]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/client.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / scheduler / client.c
index bd45262cf19ea5e80bfcaba224ec55b1eb563933..a4e249790881b47cc6fd94ba438e0c1066136161 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: client.c 6999 2007-09-28 19:46:53Z mike $"
+ * "$Id: client.c 7673 2008-06-18 22:31:26Z mike $"
  *
  *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -29,6 +29,7 @@
  *   cupsdWriteClient()      - Write data to a client as needed.
  *   check_if_modified()     - Decode an "If-Modified-Since" line.
  *   compare_clients()       - Compare two client connections.
+ *   data_ready()            - Check whether data is available from a client.
  *   encrypt_client()        - Enable encryption for the client...
  *   get_cdsa_certificate()  - Convert a keychain name into the CFArrayRef
  *                            required by SSLSetCertificate.
@@ -76,6 +77,10 @@ extern const char *cssmErrorString(int error);
 #  include <gnutls/x509.h>
 #endif /* HAVE_GNUTLS */
 
+#ifdef HAVE_TCPD_H
+#  include <tcpd.h>
+#endif /* HAVE_TCPD_H */
+
 
 /*
  * Local functions...
@@ -85,6 +90,7 @@ static int            check_if_modified(cupsd_client_t *con,
                                          struct stat *filestats);
 static int             compare_clients(cupsd_client_t *a, cupsd_client_t *b,
                                        void *data);
+static int             data_ready(cupsd_client_t *con);
 #ifdef HAVE_SSL
 static int             encrypt_client(cupsd_client_t *con);
 #endif /* HAVE_SSL */
@@ -125,6 +131,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   char                 *hostname;      /* Hostname for address */
   http_addr_t          temp;           /* Temporary address variable */
   static time_t                last_dos = 0;   /* Time of last DoS attack */
+#ifdef HAVE_TCPD_H
+  struct request_info  wrap_req;       /* TCP wrappers request information */
+#endif /* HAVE_TCPD_H */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -240,7 +249,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
       cupsdLogMessage(CUPSD_LOG_WARN,
                       "Possible DoS attack - more than %d clients connecting "
                      "from %s!",
-                     MaxClientsPerHost, tempcon->http.hostname);
+                     MaxClientsPerHost,
+                     httpAddrString(con->http.hostaddr, con->http.hostname,
+                                    sizeof(con->http.hostname)));
     }
 
 #ifdef WIN32
@@ -322,7 +333,8 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     * Do double lookups as needed...
     */
 
-    if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) != NULL)
+    if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL))
+            != NULL)
     {
      /*
       * See if the hostname maps to the same IP address...
@@ -362,6 +374,34 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     }
   }
 
+#ifdef HAVE_TCPD_H
+ /*
+  * See if the connection is denied by TCP wrappers...
+  */
+
+  request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL);
+  fromhost(&wrap_req);
+
+  if (!hosts_access(&wrap_req))
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAcceptClient: Closing connection %d...",
+                    con->http.fd);
+
+#ifdef WIN32
+    closesocket(con->http.fd);
+#else
+    close(con->http.fd);
+#endif /* WIN32 */
+
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Connection from %s refused by /etc/hosts.allow and "
+                   "/etc/hosts.deny rules.", con->http.hostname);
+    free(con);
+    return;
+  }
+#endif /* HAVE_TCPD_H */
+
 #ifdef AF_INET6
   if (con->http.hostaddr->addr.sa_family == AF_INET6)
     cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv6)",
@@ -536,15 +576,15 @@ cupsdCloseClient(cupsd_client_t *con)     /* I - Client to close */
     switch (SSL_shutdown(conn))
     {
       case 1 :
-          cupsdLogMessage(CUPSD_LOG_INFO,
-                         "cupsdCloseClient: SSL shutdown successful!");
+          cupsdLogMessage(CUPSD_LOG_DEBUG,
+                         "SSL shutdown successful!");
          break;
       case -1 :
           cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "cupsdCloseClient: Fatal error during SSL shutdown!");
+                         "Fatal error during SSL shutdown!");
       default :
          while ((error = ERR_get_error()) != 0)
-           cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdCloseClient: %s",
+           cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s",
                            ERR_error_string(error, NULL));
           break;
     }
@@ -560,12 +600,12 @@ cupsdCloseClient(cupsd_client_t *con)     /* I - Client to close */
     switch (error)
     {
       case GNUTLS_E_SUCCESS:
-       cupsdLogMessage(CUPSD_LOG_INFO,
-                       "cupsdCloseClient: SSL shutdown successful!");
+       cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "SSL shutdown successful!");
        break;
       default:
        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdCloseClient: %s", gnutls_strerror(error));
+                       "SSL shutdown failed: %s", gnutls_strerror(error));
        break;
     }
 
@@ -657,6 +697,7 @@ cupsdCloseClient(cupsd_client_t *con)       /* I - Client to close */
       free(con->http.input_set);
 
     httpClearCookie(HTTP(con));
+    httpClearFields(HTTP(con));
 
     cupsdClearString(&con->filename);
     cupsdClearString(&con->command);
@@ -866,11 +907,14 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
        {
          case 1 :
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "Bad request line \"%s\" from %s!", line,
-                             con->http.hostname);
-             cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
-             cupsdCloseClient(con);
+             if (line[0])
+             {
+               cupsdLogMessage(CUPSD_LOG_ERROR,
+                               "Bad request line \"%s\" from %s!", line,
+                               con->http.hostname);
+               cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+               cupsdCloseClient(con);
+              }
              return;
          case 2 :
              con->http.version = HTTP_0_9;
@@ -1005,8 +1049,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        */
 
         while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE)
-         if (con->http.used == 0 ||
-             !memchr(con->http.buffer, '\n', con->http.used))
+         if (!data_ready(con))
            break;
 
        if (status != HTTP_OK && status != HTTP_CONTINUE)
@@ -1211,7 +1254,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
       if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_OK)
       {
         cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                       "cupsdReadClient: Unauthorized request for %s...\n",
+                       "cupsdReadClient: Unauthorized request for %s...",
                        con->uri);
        cupsdSendError(con, status, CUPSD_AUTH_NONE);
        cupsdCloseClient(con);
@@ -1905,7 +1948,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
          }
         }
-       while (con->http.state == HTTP_PUT_RECV && con->http.used > 0);
+       while (con->http.state == HTTP_PUT_RECV && data_ready(con));
 
         if (con->http.state == HTTP_WAITING)
        {
@@ -2080,7 +2123,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
          }
         }
-       while (con->http.state == HTTP_POST_RECV && con->http.used > 0);
+       while (con->http.state == HTTP_POST_RECV && data_ready(con));
 
        if (con->http.state == HTTP_POST_SEND)
        {
@@ -2965,6 +3008,38 @@ compare_clients(cupsd_client_t *a,       /* I - First client */
 }
 
 
+/*
+ * 'data_ready()' - Check whether data is available from a client.
+ */
+
+static int                             /* O - 1 if data is ready, 0 otherwise */
+data_ready(cupsd_client_t *con)                /* I - Client */
+{
+  if (con->http.used > 0)
+    return (1);
+#ifdef HAVE_SSL
+  else if (con->http.tls)
+  {
+#  ifdef HAVE_LIBSSL
+    if (SSL_pending((SSL *)(con->http.tls)))
+      return (1);
+#  elif defined(HAVE_GNUTLS)
+    if (gnutls_record_check_pending(((http_tls_t *)(con->http.tls))->session))
+      return (1);
+#  elif defined(HAVE_CDSASSL)
+    size_t bytes;                      /* Bytes that are available */
+
+    if (!SSLGetBufferedReadSize(((http_tls_t *)(con->http.tls))->session,
+                                &bytes) && bytes > 0)
+      return (1);
+#  endif /* HAVE_LIBSSL */
+  }
+#endif /* HAVE_SSL */
+
+  return (0);
+}
+
+
 #ifdef HAVE_SSL
 /*
  * 'encrypt_client()' - Enable encryption for the client...
@@ -3002,7 +3077,8 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
 
   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
   SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
-  SSL_CTX_use_certificate_file(context, ServerCertificate, SSL_FILETYPE_PEM);
+  SSL_CTX_use_certificate_chain_file(context, ServerCertificate,
+                                     SSL_FILETYPE_PEM);
 
   bio = BIO_new(_httpBIOMethods());
   BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
@@ -3243,15 +3319,15 @@ get_cdsa_certificate(cupsd_client_t *con)       /* I - Client connection */
                        ssl_options;    /* SSL Option for hostname */
 
 
-  if ((err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, 
-                             NULL, &policy_search)))
+  if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, 
+                           NULL, &policy_search))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create a policy search reference");
     CFRelease(keychain);
     return (NULL);
   }
 
-  if ((err = SecPolicySearchCopyNext(policy_search, &policy)))
+  if (SecPolicySearchCopyNext(policy_search, &policy))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, 
                    "Cannot find a policy to use for searching");
@@ -3268,7 +3344,7 @@ get_cdsa_certificate(cupsd_client_t *con) /* I - Client connection */
   options.Data = (uint8 *)&ssl_options;
   options.Length = sizeof(ssl_options);
 
-  if ((err = SecPolicySetValue(policy, &options)))
+  if (SecPolicySetValue(policy, &options))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, 
                    "Cannot set policy value to use for searching");
@@ -3692,7 +3768,7 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "is_cgi(con=%p, filename=\"%s\", filestats=%p, type=%s/%s)\n",
+                  "is_cgi(con=%p, filename=\"%s\", filestats=%p, type=%s/%s)",
                  con, filename, filestats, type ? type->super : "unknown",
                  type ? type->type : "unknown");
 
@@ -3725,8 +3801,6 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
 
     cupsdSetString(&con->command, filename);
 
-    filename = strrchr(filename, '/') + 1; /* Filename always absolute */
-
     if (options)
       cupsdSetStringf(&con->options, " %s", options);
 
@@ -4890,5 +4964,5 @@ write_pipe(cupsd_client_t *con)           /* I - Client connection */
 
 
 /*
- * End of "$Id: client.c 6999 2007-09-28 19:46:53Z mike $".
+ * End of "$Id: client.c 7673 2008-06-18 22:31:26Z mike $".
  */