📄 client.c
字号:
/* * "$Id: client.c,v 1.197 2005/01/03 19:29:59 mike Exp $" * * Client routines for the Common UNIX Printing System (CUPS) scheduler. * * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal * copyright law. Distribution and use rights are outlined in the file * "LICENSE.txt" which should have been included with this file. If this * file is missing or damaged please contact Easy Software Products * at: * * Attn: CUPS Licensing Information * Easy Software Products * 44141 Airport View Drive, Suite 204 * Hollywood, Maryland 20636 USA * * Voice: (301) 373-9600 * EMail: cups-info@cups.org * WWW: http://www.cups.org * * Contents: * * AcceptClient() - Accept a new client. * CloseAllClients() - Close all remote clients immediately. * CloseClient() - Close a remote client. * EncryptClient() - Enable encryption for the client... * IsCGI() - Is the resource a CGI script/program? * ReadClient() - Read data from a client. * SendCommand() - Send output from a command via HTTP. * SendError() - Send an error message via HTTP. * SendFile() - Send a file via HTTP. * SendHeader() - Send an HTTP request. * UpdateCGI() - Read status messages from CGI scripts and programs. * WriteClient() - Write data to a client as needed. * check_if_modified() - Decode an "If-Modified-Since" line. * decode_auth() - Decode an authorization string. * get_file() - Get a filename and state info. * install_conf_file() - Install a configuration file. * is_path_absolute() - Is a path absolute and free of relative elements. * pipe_command() - Pipe the output of a command to the remote client. * CDSAReadFunc() - Read function for CDSA decryption code. * CDSAWriteFunc() - Write function for CDSA encryption code. *//* * Include necessary headers... */#if 0#include <cups/http-private.h>#endif#include "cupsd.h"#include <grp.h>/* * Local functions... */#if 0static int check_if_modified(client_t *con, struct stat *filestats);static void decode_auth(client_t *con);static char *get_file(client_t *con, struct stat *filestats, char *filename, int len);static http_status_t install_conf_file(client_t *con);static int is_path_absolute(const char *path);static int pipe_command(client_t *con, int infile, int *outfile, char *command, char *options);#ifdef HAVE_CDSASSLstatic OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);static OSStatus CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);#endif /* HAVE_CDSASSL */#endifint SFD = -1;static int printer_get(client_t* con, char* dev);/* * 'AcceptClient()' - Accept a new client. */voidAcceptClient(listener_t *lis) /* I - Listener socket */{ int i; /* Looping var */ int count; /* Count of connections on a host */ int val; /* Parameter value */ client_t *con; /* New client pointer */ unsigned address;/* Address of client */ struct hostent *host; /* Host entry for address */ static time_t last_dos = 0; /* Time of last DoS attack */ DEBUG_printf(("\nFunction AcceptClient() START...... \n")); LogMessage(L_DEBUG2, "AcceptClient(lis=%p) %d NumClients = %d", lis, lis->fd, NumClients); /* * Make sure we don't have a full set of clients already... */ if (NumClients == MaxClients) return; /* * Get a pointer to the next available client... */ con = Clients + NumClients; memset(con, 0, sizeof(client_t)); con->http.activity = time(NULL); con->file = -1; /* * Accept the client and get the remote address... */ val = sizeof(struct sockaddr_in); if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr), &val)) < 0) { DEBUG_printf(("Unable to accept client connection - %s.", strerror(errno))); LogMessage(L_ERROR, "Unable to accept client connection - %s.", strerror(errno)); return; } con->http.hostaddr.sin_port = lis->address.sin_port; /* * Check the number of clients on the same address... */ for (i = 0, count = 0; i < NumClients; i ++) if (memcmp(&(Clients[i].http.hostaddr), &(con->http.hostaddr), sizeof(con->http.hostaddr)) == 0) { count ++; if (count >= MaxClientsPerHost) break; } if (count >= MaxClientsPerHost) { if ((time(NULL) - last_dos) >= 60) { last_dos = time(NULL); LogMessage(L_WARN, "Possible DoS attack - more than %d clients connecting from %s!", MaxClientsPerHost, Clients[i].http.hostname); }#ifdef WIN32 closesocket(con->http.fd);#else close(con->http.fd);#endif /* WIN32 */ return; } /* * Get the hostname or format the IP address as needed... */ address = ntohl(con->http.hostaddr.sin_addr.s_addr); if (HostNameLookups)#ifndef __sgi host = gethostbyaddr((char *)&(con->http.hostaddr.sin_addr), sizeof(struct in_addr), AF_INET);#else host = gethostbyaddr(&(con->http.hostaddr.sin_addr), sizeof(struct in_addr), AF_INET);#endif /* !__sgi */ else host = NULL; if (address == 0x7f000001) { /* * Map accesses from the loopback interface to "localhost"... */ strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname)); } else if (con->http.hostaddr.sin_addr.s_addr == ServerAddr.sin_addr.s_addr) { /* * Map accesses from the same host to the server name. */ strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname)); } else if (host == NULL) { sprintf(con->http.hostname, "%d.%d.%d.%d", (address >> 24) & 255, (address >> 16) & 255, (address >> 8) & 255, address & 255); if (HostNameLookups == 2) { /* * Can't have an unresolved IP address with double-lookups enabled... */#ifdef WIN32 closesocket(con->http.fd);#else close(con->http.fd);#endif /* WIN32 */ LogMessage(L_WARN, "Name lookup failed - connection from %s closed!", con->http.hostname); return; } } else strlcpy(con->http.hostname, host->h_name, sizeof(con->http.hostname)); if (HostNameLookups == 2) { /* * Do double lookups as needed... */ if ((host = httpGetHostByName(con->http.hostname)) != NULL) { /* * See if the hostname maps to the IP address... */ if (host->h_length != 4 || host->h_addrtype != AF_INET) { /* * Not an IPv4 address... */ host = NULL; } else { /* * Compare all of the addresses against this one... */ for (i = 0; host->h_addr_list[i]; i ++) if (memcmp(&(con->http.hostaddr.sin_addr), host->h_addr_list[i], 4) == 0) break; if (!host->h_addr_list[i]) host = NULL; } } if (host == NULL) { /* * Can't have a hostname that doesn't resolve to the same IP address * with double-lookups enabled... */#ifdef WIN32 closesocket(con->http.fd);#else close(con->http.fd);#endif /* WIN32 */ LogMessage(L_WARN, "IP lookup failed - connection from %s closed!", con->http.hostname); return; } } LogMessage(L_DEBUG, "AcceptClient: %d from %s:%d.", con->http.fd, con->http.hostname, ntohs(con->http.hostaddr.sin_port)); /* * Using TCP_NODELAY improves responsiveness, especially on systems * with a slow loopback interface... Since we write large buffers * when sending print files and requests, there shouldn't be any * performance penalty for this... */ val = 1; setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); /* * Close this file on all execs... */ fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC); /* * Add the socket to the select() input mask. */ LogMessage(L_DEBUG2, "AcceptClient: Adding fd %d to InputSet...", con->http.fd); FD_SET(con->http.fd, InputSet); NumClients ++; /* * Temporarily suspend accept()'s until we lose a client... */ if (NumClients == MaxClients) PauseListening();#if 0#ifdef HAVE_SSL /* * See if we are connecting on a secure port... */ if (lis->encryption == HTTP_ENCRYPT_ALWAYS) { /* * https connection; go secure... */ con->http.encryption = HTTP_ENCRYPT_ALWAYS; EncryptClient(con); }#endif /* HAVE_SSL */#endif DEBUG_printf(("Function AcceptClient()\n\n")); }/* * 'CloseAllClients()' - Close all remote clients immediately. */voidCloseAllClients(void){ while (NumClients > 0) CloseClient(Clients);}/* * 'CloseClient()' - Close a remote client. */int /* O - 1 if partial close, 0 if fully closed */CloseClient(client_t *con) /* I - Client to close */{ int partial; /* Do partial close for SSL? */#if defined(HAVE_LIBSSL) SSL_CTX *context; /* Context for encryption */ SSL *conn; /* Connection for encryption */ unsigned long error; /* Error code */#elif defined(HAVE_GNUTLS) http_tls_t *conn; /* TLS connection information */ int error; /* Error code */ gnutls_certificate_server_credentials *credentials; /* TLS credentials */#endif /* HAVE_GNUTLS */ LogMessage(L_DEBUG, "CloseClient: %d", con->http.fd); partial = 0;#if 0#ifdef HAVE_SSL /* * Shutdown encryption as needed... */ if (con->http.tls) { partial = 1;# ifdef HAVE_LIBSSL conn = (SSL *)(con->http.tls); context = SSL_get_SSL_CTX(conn); switch (SSL_shutdown(conn)) { case 1 : LogMessage(L_INFO, "CloseClient: SSL shutdown successful!"); break; case -1 : LogMessage(L_ERROR, "CloseClient: Fatal error during SSL shutdown!"); default : while ((error = ERR_get_error()) != 0) LogMessage(L_ERROR, "CloseClient: %s", ERR_error_string(error, NULL)); break; } SSL_CTX_free(context); SSL_free(conn);# elif defined(HAVE_GNUTLS) conn = (http_tls_t *)(con->http.tls); credentials = (gnutls_certificate_server_credentials *)(conn->credentials); error = gnutls_bye(conn->session, GNUTLS_SHUT_WR); switch (error) { case GNUTLS_E_SUCCESS: LogMessage(L_INFO, "CloseClient: SSL shutdown successful!"); break; default: LogMessage(L_ERROR, "CloseClient: %s", gnutls_strerror(error)); break; } gnutls_deinit(conn->session); gnutls_certificate_free_credentials(*credentials); free(credentials); free(conn);# elif defined(HAVE_CDSASSL) status = SSLClose((SSLContextRef)con->http.tls); SSLDisposeContext((SSLContextRef)con->http.tls);# endif /* HAVE_LIBSSL */ con->http.tls = NULL; }#endif /* HAVE_SSL */#endif /* * Close the socket and clear the file from the input set for select()... */ if (con->http.fd > 0) { if (partial) { /* * Only do a partial close so that the encrypted client gets everything. */ LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from OutputSet...", con->http.fd); shutdown(con->http.fd, 0); FD_CLR(con->http.fd, OutputSet); } else { /* * Shut the socket down fully... */ LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet and OutputSet...", con->http.fd); close(con->http.fd); FD_CLR(con->http.fd, InputSet); FD_CLR(con->http.fd, OutputSet); con->http.fd = 0; } } if (con->pipe_pid != 0) { /* * Stop any CGI process... */ LogMessage(L_DEBUG2, "CloseClient: %d Killing process ID %d...", con->http.fd, con->pipe_pid); kill(con->pipe_pid, SIGKILL); } if (con->file >= 0) { if (FD_ISSET(con->file, InputSet)) { LogMessage(L_DEBUG2, "CloseClient: %d Removing fd %d from InputSet...", con->http.fd, con->file); FD_CLR(con->file, InputSet); } LogMessage(L_DEBUG2, "CloseClient: %d Closing data file %d.", con->http.fd, con->file); close(con->file); con->file = -1; } if (!partial) { /* * Free memory... */ if (con->http.input_set) free(con->http.input_set); httpClearCookie(HTTP(con)); ClearString(&con->filename); ClearString(&con->command); ClearString(&con->options); if (con->request) { ippDelete(con->request); con->request = NULL; } if (con->response) { ippDelete(con->response); con->response = NULL; } if (con->language) { cupsLangFree(con->language); con->language = NULL; } /* * Re-enable new client connections if we are going back under the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -