]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/client.c
Merge changes from CUPS 1.5svn-r9400
[thirdparty/cups.git] / scheduler / client.c
index 4823a0c85c9e5b49b757e76ca04f548f23b387a8..1d0dcf12eb60cd6933e97e5680b465b3a56741af 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: client.c 7950 2008-09-17 00:21:59Z mike $"
  *
- *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
+ *   Client routines for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   This file contains Kerberos support code, copyright 2006 by
 
 #include "cupsd.h"
 
-#ifdef HAVE_CDSASSL
-#  include <Security/Security.h>
-#  ifdef HAVE_SECIDENTITYSEARCHPRIV_H
-#    include <Security/SecIdentitySearchPriv.h>
-#  else /* Declare prototype for function in that header... */
-extern OSStatus SecIdentitySearchCreateWithPolicy(SecPolicyRef policy, 
-                               CFStringRef idString, CSSM_KEYUSE keyUsage, 
-                               CFTypeRef keychainOrArray, 
-                               Boolean returnOnlyValidIdentities, 
-                               SecIdentitySearchRef* searchRef);
-#  endif /* HAVE_SECIDENTITYSEARCHPRIV_H */
-#  ifdef HAVE_SECPOLICYPRIV_H
-#    include <Security/SecPolicyPriv.h>
-#  else /* Declare prototype for function in that header... */
-extern OSStatus SecPolicySetValue(SecPolicyRef policyRef, 
-                                  const CSSM_DATA *value);
-#  endif /* HAVE_SECPOLICYPRIV_H */
-#  ifdef HAVE_SECBASEPRIV_H
-#    include <Security/SecBasePriv.h>
-#  else /* Declare prototype for function in that header... */
-extern const char *cssmErrorString(int error);
-#  endif /* HAVE_SECBASEPRIV_H */
-#endif /* HAVE_CDSASSL */
-
-#ifdef HAVE_GNUTLS
-#  include <gnutls/x509.h>
-#endif /* HAVE_GNUTLS */
-
 #ifdef HAVE_TCPD_H
 #  include <tcpd.h>
 #endif /* HAVE_TCPD_H */
@@ -532,15 +504,12 @@ cupsdCloseClient(cupsd_client_t *con)     /* I - Client to close */
   int          partial;                /* Do partial close for SSL? */
 #ifdef 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 */
 #  elif defined(HAVE_CDSASSL)
-  http_tls_t   *conn;                  /* CDSA connection information */
 #endif /* HAVE_LIBSSL */
 
 
@@ -564,10 +533,9 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
     partial = 1;
 
 #  ifdef HAVE_LIBSSL
-    conn    = (SSL *)(con->http.tls);
-    context = SSL_get_SSL_CTX(conn);
+    context = SSL_get_SSL_CTX(con->http.tls);
 
-    switch (SSL_shutdown(conn))
+    switch (SSL_shutdown(con->http.tls))
     {
       case 1 :
           cupsdLogMessage(CUPSD_LOG_DEBUG,
@@ -584,13 +552,12 @@ cupsdCloseClient(cupsd_client_t *con)     /* I - Client to close */
     }
 
     SSL_CTX_free(context);
-    SSL_free(conn);
+    SSL_free(con->http.tls);
 
 #  elif defined(HAVE_GNUTLS)
-    conn        = (http_tls_t *)(con->http.tls);
-    credentials = (gnutls_certificate_server_credentials *)(conn->credentials);
+    credentials = (gnutls_certificate_server_credentials *)(con->http.tls_credentials);
 
-    error = gnutls_bye(conn->session, GNUTLS_SHUT_WR);
+    error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
     switch (error)
     {
       case GNUTLS_E_SUCCESS:
@@ -603,23 +570,19 @@ cupsdCloseClient(cupsd_client_t *con)     /* I - Client to close */
        break;
     }
 
-    gnutls_deinit(conn->session);
+    gnutls_deinit(con->http.tls);
     gnutls_certificate_free_credentials(*credentials);
     free(credentials);
-    free(conn);
 
 #  elif defined(HAVE_CDSASSL)
-    conn = (http_tls_t *)(con->http.tls);
-
-    while (SSLClose(conn->session) == errSSLWouldBlock)
+    while (SSLClose(con->http.tls) == errSSLWouldBlock)
       usleep(1000);
 
-    SSLDisposeContext(conn->session);
+    SSLDisposeContext(con->http.tls);
 
-    if (conn->certsArray)
-      CFRelease(conn->certsArray);
+    if (con->http.tls_credentials)
+      CFRelease(con->http.tls_credentials);
 
-    free(conn);
 #  endif /* HAVE_LIBSSL */
 
     con->http.tls = NULL;
@@ -895,6 +858,9 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        }
 
 #ifdef HAVE_GSSAPI
+        con->have_gss = 0;
+
+       if (con->gss_creds)
        {
          OM_uint32 minor_status;
          gss_release_cred(&minor_status, &con->gss_creds);
@@ -1128,8 +1094,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          *ptr = '\0';
       }
       else
-        snprintf(locale, sizeof(locale), "%s.%s",
-                con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], DefaultCharset);
+        snprintf(locale, sizeof(locale), "%s.UTF-8",
+                con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
 
       con->language = cupsLangGet(locale);
     }
@@ -1373,14 +1339,57 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                break;
              }
            }
+            else if ((!strncmp(con->uri, "/printers/", 10) ||
+                     !strncmp(con->uri, "/classes/", 9)) &&
+                    !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
+           {
+            /*
+             * Send icon file - get the real queue name since queue names are
+             * not case sensitive but filenames can be...
+             */
 
-           if ((!strncmp(con->uri, "/admin", 6) &&
-                strncmp(con->uri, "/admin/conf/", 12) &&
-                strncmp(con->uri, "/admin/log/", 11)) ||
-               !strncmp(con->uri, "/printers", 9) ||
-               !strncmp(con->uri, "/classes", 8) ||
-               !strncmp(con->uri, "/help", 5) ||
-               !strncmp(con->uri, "/jobs", 5))
+             con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".png" */
+
+              if (!strncmp(con->uri, "/printers/", 10))
+                p = cupsdFindPrinter(con->uri + 10);
+              else
+                p = cupsdFindClass(con->uri + 9);
+
+              if (p)
+               snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
+             else
+             {
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
+
+               break;
+             }
+           }
+
+            if (!WebInterface)
+           {
+            /*
+             * Web interface is disabled. Show an appropriate message...
+             */
+
+             if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+
+             break;
+           }
+           else if ((!strncmp(con->uri, "/admin", 6) &&
+                     strncmp(con->uri, "/admin/conf/", 12) &&
+                     strncmp(con->uri, "/admin/log/", 11)) ||
+                    !strncmp(con->uri, "/printers", 9) ||
+                    !strncmp(con->uri, "/classes", 8) ||
+                    !strncmp(con->uri, "/help", 5) ||
+                    !strncmp(con->uri, "/jobs", 5))
            {
             /*
              * Send CGI output...
@@ -1585,6 +1594,20 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
            if (!strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
                        "application/ipp"))
               con->request = ippNew();
+            else if (!WebInterface)
+           {
+            /*
+             * Web interface is disabled. Show an appropriate message...
+             */
+
+             if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+
+             break;
+           }
            else if ((!strncmp(con->uri, "/admin", 6) &&
                      strncmp(con->uri, "/admin/conf/", 12) &&
                      strncmp(con->uri, "/admin/log/", 11)) ||
@@ -1801,6 +1824,52 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                break;
              }
            }
+            else if (!strncmp(con->uri, "/printers/", 10) &&
+                    !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
+           {
+            /*
+             * Send PNG file - get the real printer name since printer
+             * names are not case sensitive but filenames can be...
+             */
+
+              con->uri[strlen(con->uri) - 4] = '\0';   /* Drop ".ppd" */
+
+              if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+               snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
+             else
+             {
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
+
+               break;
+             }
+           }
+           else if (!WebInterface)
+           {
+              if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+
+             if (httpPrintf(HTTP(con), "\r\n") < 0)
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+
+             if (cupsdFlushHeader(con) < 0)
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+
+             con->http.state = HTTP_WAITING;
+             break;
+           }
 
            if ((!strncmp(con->uri, "/admin", 6) &&
                 strncmp(con->uri, "/admin/conf/", 12) &&
@@ -2189,6 +2258,15 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                return;
              }
            }
+           else if (filestats.st_size == 0)
+           {
+            /*
+             * Don't allow empty file...
+             */
+
+             unlink(con->filename);
+             cupsdClearString(&con->filename);
+           }
 
            if (con->command)
            {
@@ -2407,6 +2485,10 @@ cupsdSendError(cupsd_client_t *con,      /* I - Connection */
               "CONTENT=\"3;URL=https://%s:%d%s\">\n",
               con->servername, con->serverport, con->uri);
     }
+    else if (code == HTTP_WEBIF_DISABLED)
+      text = _cupsLangString(con->language,
+                             _("The web interface is currently disabled. Run "
+                              "\"cupsctl WebInterface=yes\" to enable it."));
     else
       text = "";
 
@@ -2417,17 +2499,17 @@ cupsdSendError(cupsd_client_t *con,     /* I - Connection */
             "<HEAD>\n"
              "\t<META HTTP-EQUIV=\"Content-Type\" "
             "CONTENT=\"text/html; charset=utf-8\">\n"
-            "\t<TITLE>%d %s</TITLE>\n"
+            "\t<TITLE>%s - " CUPS_SVERSION "</TITLE>\n"
             "\t<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" "
             "HREF=\"/cups.css\">\n"
             "%s"
             "</HEAD>\n"
              "<BODY>\n"
-            "<H1>%d %s</H1>\n"
+            "<H1>%s</H1>\n"
             "<P>%s</P>\n"
             "</BODY>\n"
             "</HTML>\n",
-            code, httpStatus(code), redirect, code, httpStatus(code), text);
+            httpStatus(code), redirect, httpStatus(code), text);
 
     if (httpPrintf(HTTP(con), "Content-Type: text/html; charset=utf-8\r\n") < 0)
       return (0);
@@ -2482,6 +2564,15 @@ cupsdSendHeader(
     return (httpPrintf(HTTP(con), "HTTP/%d.%d 100 Continue\r\n\r\n",
                       con->http.version / 100, con->http.version % 100) > 0);
   }
+  else if (code == HTTP_WEBIF_DISABLED)
+  {
+   /*
+    * Treat our special "web interface is disabled" status as "200 OK" for web
+    * browsers.
+    */
+
+    code = HTTP_OK;
+  }
 
   httpFlushWrite(HTTP(con));
 
@@ -2541,26 +2632,27 @@ cupsdSendHeader(
       * parameter as needed...
       */
 
-      int      i;                      /* Looping var */
-      char     *auth_key;              /* Auth key buffer */
+      char     *name,                  /* Current user name */
+               *auth_key;              /* Auth key buffer */
       size_t   auth_size;              /* Size of remaining buffer */
 
       auth_key  = auth_str + strlen(auth_str);
       auth_size = sizeof(auth_str) - (auth_key - auth_str);
 
-      for (i = 0; i < con->best->num_names; i ++)
+      for (name = (char *)cupsArrayFirst(con->best->names);
+           name;
+          name = (char *)cupsArrayNext(con->best->names))
       {
 #ifdef HAVE_AUTHORIZATION_H
-       if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9))
+       if (!strncasecmp(name, "@AUTHKEY(", 9))
        {
-         snprintf(auth_key, auth_size, ", authkey=\"%s\"",
-                  con->best->names[i] + 9);
+         snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9);
          /* end parenthesis is stripped in conf.c */
          break;
         }
        else
 #endif /* HAVE_AUTHORIZATION_H */
-       if (!strcasecmp(con->best->names[i], "@SYSTEM"))
+       if (!strcasecmp(name, "@SYSTEM"))
        {
 #ifdef HAVE_AUTHORIZATION_H
          if (SystemGroupAuthKey)
@@ -3073,13 +3165,12 @@ data_ready(cupsd_client_t *con)         /* I - Client */
     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))
+    if (gnutls_record_check_pending(con->http.tls))
       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)
+    if (!SSLGetBufferedReadSize(con->http.tls, &bytes) && bytes > 0)
       return (1);
 #  endif /* HAVE_LIBSSL */
   }
@@ -3099,7 +3190,6 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
 {
 #  ifdef HAVE_LIBSSL
   SSL_CTX      *context;               /* Context for encryption */
-  SSL          *conn;                  /* Connection for encryption */
   BIO          *bio;                   /* BIO data */
   unsigned long        error;                  /* Error code */
 
@@ -3136,10 +3226,10 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
   bio = BIO_new(_httpBIOMethods());
   BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
 
-  conn = SSL_new(context);
-  SSL_set_bio(conn, bio, bio);
+  con->http.tls = SSL_new(context);
+  SSL_set_bio(con->http.tls, bio, bio);
 
-  if (SSL_accept(conn) != 1)
+  if (SSL_accept(con->http.tls) != 1)
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s!",
                     con->http.hostname);
@@ -3148,18 +3238,17 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
       cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL));
 
     SSL_CTX_free(context);
-    SSL_free(conn);
+    SSL_free(con->http.tls);
+    con->http.tls = NULL;
     return (0);
   }
 
   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
                   con->http.hostname);
 
-  con->http.tls = conn;
   return (1);
 
 #  elif defined(HAVE_GNUTLS)
-  http_tls_t   *conn;                  /* TLS session object */
   int          error;                  /* Error code */
   gnutls_certificate_server_credentials *credentials;
                                        /* TLS credentials */
@@ -3186,11 +3275,6 @@ encrypt_client(cupsd_client_t *con)      /* I - Client to encrypt */
   * Create the SSL object and perform the SSL handshake...
   */
 
-  conn = (http_tls_t *)malloc(sizeof(http_tls_t));
-
-  if (conn == NULL)
-    return (0);
-
   credentials = (gnutls_certificate_server_credentials *)
                     malloc(sizeof(gnutls_certificate_server_credentials));
   if (credentials == NULL)
@@ -3199,7 +3283,6 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
                     "Unable to encrypt connection from %s - %s",
                     con->http.hostname, strerror(errno));
 
-    free(conn);
     return (0);
   }
 
@@ -3207,14 +3290,14 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
   gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
                                       ServerKey, GNUTLS_X509_FMT_PEM);
 
-  gnutls_init(&(conn->session), GNUTLS_SERVER);
-  gnutls_set_default_priority(conn->session);
-  gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
-  gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr)HTTP(con));
-  gnutls_transport_set_pull_function(conn->session, _httpReadGNUTLS);
-  gnutls_transport_set_push_function(conn->session, _httpWriteGNUTLS);
+  gnutls_init(&con->http.tls), GNUTLS_SERVER);
+  gnutls_set_default_priority(con->http.tls);
+  gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
+  gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con));
+  gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS);
+  gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS);
 
-  error = gnutls_handshake(conn->session);
+  error = gnutls_handshake(con->http.tls);
 
   if (error != GNUTLS_E_SUCCESS)
   {
@@ -3222,9 +3305,9 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
                     "Unable to encrypt connection from %s - %s",
                     con->http.hostname, gnutls_strerror(error));
 
-    gnutls_deinit(conn->session);
+    gnutls_deinit(con->http.tls);
     gnutls_certificate_free_credentials(*credentials);
-    free(conn);
+    con->http.tls = NULL;
     free(credentials);
     return (0);
   }
@@ -3232,36 +3315,30 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
                   con->http.hostname);
 
-  conn->credentials = credentials;
-  con->http.tls = conn;
+  con->http.tls_credentials = credentials;
   return (1);
 
 #  elif defined(HAVE_CDSASSL)
   OSStatus     error;                  /* Error code */
-  http_tls_t   *conn;                  /* CDSA connection information */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
                   con->http.fd);
 
-  if ((conn = (http_tls_t *)malloc(sizeof(http_tls_t))) == NULL)
-    return (0);
-
-  error            = 0;
-  conn->session    = NULL;
-  conn->certsArray = get_cdsa_certificate(con);
+  error                     = 0;
+  con->http.tls_credentials = get_cdsa_certificate(con);
 
-  if (!conn->certsArray)
+  if (!con->http.tls_credentials)
   {
    /*
     * No keychain (yet), make a self-signed certificate...
     */
 
     if (make_certificate(con))
-      conn->certsArray = get_cdsa_certificate(con);
+      con->http.tls_credentials = get_cdsa_certificate(con);
   }
 
-  if (!conn->certsArray)
+  if (!con->http.tls_credentials)
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Could not find signing key in keychain \"%s\"",
@@ -3270,25 +3347,25 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
   }
 
   if (!error)
-    error = SSLNewContext(true, &conn->session);
+    error = SSLNewContext(true, &con->http.tls);
 
   if (!error)
-    error = SSLSetIOFuncs(conn->session, _httpReadCDSA, _httpWriteCDSA);
+    error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA);
 
   if (!error)
-    error = SSLSetProtocolVersionEnabled(conn->session, kSSLProtocol2, false);
+    error = SSLSetProtocolVersionEnabled(con->http.tls, kSSLProtocol2, false);
 
   if (!error)
-    error = SSLSetConnection(conn->session, HTTP(con));
+    error = SSLSetConnection(con->http.tls, HTTP(con));
 
   if (!error)
-    error = SSLSetAllowsExpiredCerts(conn->session, true);
+    error = SSLSetAllowsExpiredCerts(con->http.tls, true);
 
   if (!error)
-    error = SSLSetAllowsAnyRoot(conn->session, true);
+    error = SSLSetAllowsAnyRoot(con->http.tls, true);
 
   if (!error)
-    error = SSLSetCertificate(conn->session, conn->certsArray);
+    error = SSLSetCertificate(con->http.tls, con->http.tls_credentials);
 
   if (!error)
   {
@@ -3296,7 +3373,7 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
     * Perform SSL/TLS handshake
     */
 
-    while ((error = SSLHandshake(conn->session)) == errSSLWouldBlock)
+    while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock)
       usleep(1000);
   }
 
@@ -3309,13 +3386,17 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
     con->http.error  = error;
     con->http.status = HTTP_ERROR;
 
-    if (conn->session)
-      SSLDisposeContext(conn->session);
-
-    if (conn->certsArray)
-      CFRelease(conn->certsArray);
+    if (con->http.tls)
+    {
+      SSLDisposeContext(con->http.tls);
+      con->http.tls = NULL;
+    }
 
-    free(conn);
+    if (con->http.tls_credentials)
+    {
+      CFRelease(con->http.tls_credentials);
+      con->http.tls_credentials = NULL;
+    }
 
     return (0);
   }
@@ -3323,7 +3404,16 @@ encrypt_client(cupsd_client_t *con)      /* I - Client to encrypt */
   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
                   con->http.hostname);
 
-  con->http.tls = conn;
+  CFArrayRef           peerCerts;      /* Peer certificates */
+
+  if (!(error = SSLCopyPeerCertificates(con->http.tls, &peerCerts)) && peerCerts)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!",
+                   (int)CFArrayGetCount(peerCerts));
+  }
+  else
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates!");
+
   return (1);
 
 #  endif /* HAVE_LIBSSL */
@@ -3337,51 +3427,129 @@ encrypt_client(cupsd_client_t *con)    /* I - Client to encrypt */
  */
 
 static CFArrayRef                              /* O - Array of certificates */
-get_cdsa_certificate(cupsd_client_t *con)      /* I - Client connection */
+get_cdsa_certificate(
+    cupsd_client_t *con)                       /* I - Client connection */
 {
   OSStatus             err;            /* Error info */
-  SecKeychainRef       keychain;       /* Keychain reference */
-  SecIdentitySearchRef search;         /* Search reference */
-  SecIdentityRef       identity;       /* Identity */
+  SecKeychainRef       keychain = NULL;/* Keychain reference */
+  SecIdentitySearchRef search = NULL;  /* Search reference */
+  SecIdentityRef       identity = NULL;/* Identity */
   CFArrayRef           certificates = NULL;
                                        /* Certificate array */
+#  if HAVE_SECPOLICYCREATESSL
+  SecPolicyRef         policy = NULL;  /* Policy ref */
+  CFStringRef          servername = NULL;
+                                       /* Server name */
+  CFMutableDictionaryRef query = NULL; /* Query qualifiers */
+  char                 localname[1024];/* Local hostname */
+#  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+  SecPolicyRef         policy = NULL;  /* Policy ref */
+  SecPolicySearchRef   policy_search = NULL;
+                                       /* Policy search ref */
+  CSSM_DATA            options;        /* Policy options */
+  CSSM_APPLE_TP_SSL_OPTIONS
+                       ssl_options;    /* SSL Option for hostname */
+  char                 localname[1024];/* Local hostname */
+#  endif /* HAVE_SECPOLICYCREATESSL */
 
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
+                  "get_cdsa_certificate: Looking for certs for \"%s\"...",
+                 con->servername);
+
   if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
                    ServerCertificate, cssmErrorString(err), (int)err);
-    return (NULL);
+    goto cleanup;
+  }
+
+#  if HAVE_SECPOLICYCREATESSL
+  servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
+                                        kCFStringEncodingUTF8);
+
+  if ((policy = SecPolicyCreateSSL(1, servername)) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
+    goto cleanup;
+  }
+
+  if (servername)
+    CFRelease(servername);
+
+  if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                         &kCFTypeDictionaryKeyCallBacks,
+                                         &kCFTypeDictionaryValueCallBacks)))
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
+    goto cleanup;
+  }
+
+  CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
+  CFDictionaryAddValue(query, kSecMatchPolicy, policy);
+  CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
+  CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
+
+  err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
+
+  if (err && DNSSDHostName)
+  {
+   /*
+    * Search for the connection server name failed; try the DNS-SD .local
+    * hostname instead...
+    */
+
+    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "get_cdsa_certificate: Looking for certs for \"%s\"...",
+                   localname);
+
+    servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
+                                          kCFStringEncodingUTF8);
+  
+    CFRelease(policy);
+
+    if ((policy = SecPolicyCreateSSL(1, servername)) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
+      goto cleanup;
+    }
+
+    if (servername)
+      CFRelease(servername);
+
+    CFDictionarySetValue(query, kSecMatchPolicy, policy);
+
+    err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
+  }
+
+  if (err)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "Cannot find signing key in keychain \"%s\": %s (%d)",
+                   ServerCertificate, cssmErrorString(err), (int)err);
+    goto cleanup;
   }
 
-#  if HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY
+#  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
  /*
-  * Use a policy to search for valid certificates who's common name matches the
+  * Use a policy to search for valid certificates whose common name matches the
   * servername...
   */
 
-  SecPolicySearchRef   policy_search;  /* Policy search ref */
-  SecPolicyRef         policy;         /* Policy ref */
-  CSSM_DATA            options;        /* Policy options */
-  CSSM_APPLE_TP_SSL_OPTIONS
-                       ssl_options;    /* SSL Option for hostname */
-
-
-  if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, 
+  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);
+    goto cleanup;
   }
 
   if (SecPolicySearchCopyNext(policy_search, &policy))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Cannot find a policy to use for searching");
-    CFRelease(keychain);
-    CFRelease(policy_search);
-    return (NULL);
+    goto cleanup;
   }
 
   memset(&ssl_options, 0, sizeof(ssl_options));
@@ -3389,10 +3557,6 @@ get_cdsa_certificate(cupsd_client_t *con)        /* I - Client connection */
   ssl_options.ServerName = con->servername;
   ssl_options.ServerNameLen = strlen(con->servername);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
-                  "get_cdsa_certificate: Looking for certs for \"%s\"...",
-                 con->servername);
-
   options.Data = (uint8 *)&ssl_options;
   options.Length = sizeof(ssl_options);
 
@@ -3400,55 +3564,120 @@ get_cdsa_certificate(cupsd_client_t *con)      /* I - Client connection */
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Cannot set policy value to use for searching");
-    CFRelease(keychain);
-    CFRelease(policy_search);
-    return (NULL);
+    goto cleanup;
+  }
+
+  if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
+                                              keychain, FALSE, &search)))
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                   "Cannot create identity search reference: %s (%d)",
+                   cssmErrorString(err), (int)err);
+    goto cleanup;
+  }
+
+  err = SecIdentitySearchCopyNext(search, &identity);
+
+  if (err && DNSSDHostName)
+  {
+   /*
+    * Search for the connection server name failed; try the DNS-SD .local
+    * hostname instead...
+    */
+
+    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+
+    ssl_options.ServerName    = localname;
+    ssl_options.ServerNameLen = strlen(localname);
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "get_cdsa_certificate: Looking for certs for \"%s\"...",
+                   localname);
+
+    if (SecPolicySetValue(policy, &options))
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                     "Cannot set policy value to use for searching");
+      goto cleanup;
+    }
+
+    CFRelease(search);
+    search = NULL;
+    if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
+                                              keychain, FALSE, &search)))
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                     "Cannot create identity search reference: %s (%d)",
+                     cssmErrorString(err), (int)err);
+      goto cleanup;
+    }
+
+    err = SecIdentitySearchCopyNext(search, &identity);
+
+  }
+
+  if (err)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "Cannot find signing key in keychain \"%s\": %s (%d)",
+                   ServerCertificate, cssmErrorString(err), (int)err);
+    goto cleanup;
   }
 
-  err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
-                                         keychain, FALSE, &search);
 #  else
  /*
   * Assume there is exactly one SecIdentity in the keychain...
   */
 
-  err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search);
-#  endif /* HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */
-
-  if (err)
+  if ((err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search)))
+  {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                   "Cannot create keychain search reference: %s (%d)", 
-                   cssmErrorString(err), (int)err);
-  else
+                   "Cannot create identity search reference (%d)", (int)err);
+    goto cleanup;
+  }
+
+  if ((err = SecIdentitySearchCopyNext(search, &identity)))
   {
-    if ((err = SecIdentitySearchCopyNext(search, &identity)))
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG,
-                     "Cannot find signing key in keychain \"%s\": %s (%d)",
-                     ServerCertificate, cssmErrorString(err), (int)err);
-    }
-    else
-    {
-      if (CFGetTypeID(identity) != SecIdentityGetTypeID())
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "SecIdentitySearchCopyNext CFTypeID failure!");
-      else
-      {
-      if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 
-                                     1, &kCFTypeArrayCallBacks)) == NULL)
-       cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
-      }
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "Cannot find signing key in keychain \"%s\": %s (%d)",
+                   ServerCertificate, cssmErrorString(err), (int)err);
+    goto cleanup;
+  }
+#  endif /* HAVE_SECPOLICYCREATESSL */
 
-      CFRelease(identity);
-    }
+  if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure!");
+    goto cleanup;
+  }
 
-    CFRelease(search);
+  if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
+                                 1, &kCFTypeArrayCallBacks)) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
+    goto cleanup;
   }
 
-#  if HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY
-  CFRelease(policy);
-  CFRelease(policy_search);
-#  endif /* HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */
+  cleanup :
+
+  if (keychain)
+    CFRelease(keychain);
+  if (search)
+    CFRelease(search);
+  if (identity)
+    CFRelease(identity);
+
+#  if HAVE_SECPOLICYCREATESSL
+  if (policy)
+    CFRelease(policy);
+  if (query)
+    CFRelease(query);
+#  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+  if (policy)
+    CFRelease(policy);
+  if (policy_search)
+    CFRelease(policy_search);
+#  endif /* HAVE_SECPOLICYCREATESSL */
 
   return (certificates);
 }
@@ -3477,8 +3706,14 @@ get_file(cupsd_client_t *con,            /* I  - Client connection */
 
   language[0] = '\0';
 
-  if (!strncmp(con->uri, "/ppd/", 5))
+  if (!strncmp(con->uri, "/ppd/", 5) && !strchr(con->uri + 5, '/'))
     snprintf(filename, len, "%s%s", ServerRoot, con->uri);
+  else if (!strncmp(con->uri, "/icons/", 7) && !strchr(con->uri + 7, '/'))
+  {
+    snprintf(filename, len, "%s/%s", CacheDir, con->uri + 7);
+    if (access(filename, F_OK) < 0)
+      snprintf(filename, len, "%s/images/generic.png", DocumentRoot);
+  }
   else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
     snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
   else if (!strncmp(con->uri, "/admin/conf/", 12))
@@ -3511,7 +3746,9 @@ get_file(cupsd_client_t *con,             /* I  - Client connection */
   */
 
   if ((status = stat(filename, filestats)) != 0 && language[0] &&
+      strncmp(con->uri, "/icons/", 7) &&
       strncmp(con->uri, "/ppd/", 5) &&
+      strncmp(con->uri, "/rss/", 5) &&
       strncmp(con->uri, "/admin/conf/", 12) &&
       strncmp(con->uri, "/admin/log/", 11))
   {
@@ -3634,9 +3871,6 @@ get_file(cupsd_client_t *con,             /* I  - Client connection */
                  "%s", con, con->http.fd, filestats, filename, len,
                  status ? "(null)" : filename);
 
-  if (!status)
-    con->http.data_remaining = (int)filestats->st_size;
-
   if (status)
     return (NULL);
   else
@@ -4010,7 +4244,6 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
   char         command[1024],          /* Command */
                *argv[12],              /* Command-line arguments */
                *envp[MAX_ENV + 1],     /* Environment variables */
-               home[1024],             /* HOME environment variable */
                infofile[1024],         /* Type-in information for cert */
                seedfile[1024];         /* Random number seed file */
   int          envc,                   /* Number of environment variables */
@@ -4051,8 +4284,6 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     cupsdLogMessage(CUPSD_LOG_INFO,
                     "Seeding the random number generator...");
 
-    snprintf(home, sizeof(home), "HOME=%s", TempDir);
-
    /*
     * Write the seed file...
     */
@@ -4081,8 +4312,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     argv[5] = NULL;
 
     envc = cupsdLoadEnv(envp, MAX_ENV);
-    envp[envc++] = home;
-    envp[envc]   = NULL;
+    envp[envc] = NULL;
 
     if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
                            NULL, &pid))
@@ -4347,11 +4577,21 @@ make_certificate(cupsd_client_t *con)   /* I - Client connection */
                *argv[4],               /* Command-line arguments */
                *envp[MAX_ENV + 1],     /* Environment variables */
                keychain[1024],         /* Keychain argument */
-               infofile[1024];         /* Type-in information for cert */
+               infofile[1024],         /* Type-in information for cert */
+               localname[1024],        /* Local hostname */
+               *servername;            /* Name of server in cert */
   cups_file_t  *fp;                    /* Seed/info file */
   int          infofd;                 /* Info file descriptor */
 
 
+  if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName)
+  {
+    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+    servername = localname;
+  }
+  else
+    servername = con->servername;
+       
  /*
   * Run the "certtool" command to generate a self-signed certificate...
   */
@@ -4378,8 +4618,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     return (0);
   }
 
-  cupsFilePrintf(fp, "%s\nr\n\ny\nb\ns\ny\n%s\n\n\n\n\n%s\ny\n", 
-                con->servername, con->servername, ServerAdmin);
+  cupsFilePrintf(fp, "%s\nr\n\ny\nb\ns\ny\n%s\n\n\n\n\n%s\ny\n",
+                servername, servername, ServerAdmin);
   cupsFileClose(fp);
 
   cupsdLogMessage(CUPSD_LOG_INFO,
@@ -4468,7 +4708,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   char         argbuf[10240],          /* Argument buffer */
                *argv[100],             /* Argument strings */
                *envp[MAX_ENV + 20];    /* Environment variables */
-  char         auth_type[256],         /* CUPSD_AUTH_TYPE environment variable */
+  char         auth_type[256],         /* AUTH_TYPE environment variable */
                content_length[1024],   /* CONTENT_LENGTH environment variable */
                content_type[1024],     /* CONTENT_TYPE environment variable */
                http_cookie[32768],     /* HTTP_COOKIE environment variable */
@@ -4514,7 +4754,12 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
   argv[0] = command;
 
   if (options)
-    strlcpy(argbuf, options, sizeof(argbuf));
+  {
+    commptr = options;
+    if (*commptr == ' ')
+      commptr ++;
+    strlcpy(argbuf, commptr, sizeof(argbuf));
+  }
   else
     argbuf[0] = '\0';
 
@@ -4613,7 +4858,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
 
   if (con->username[0])
   {
-    snprintf(auth_type, sizeof(auth_type), "CUPSD_AUTH_TYPE=%s",
+    snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
              httpGetField(HTTP(con), HTTP_FIELD_AUTHORIZATION));
 
     if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)