]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/client.c
Merge changes from CUPS 1.4svn-r7282.
[thirdparty/cups.git] / scheduler / client.c
index f8316a79e696c4c8bd436f7d02ab9c746b4877d6..706c315418ec95c5af46ccb98cafc607b6727a63 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: client.c 6758 2007-08-02 00:13:44Z mike $"
+ * "$Id: client.c 6999 2007-09-28 19:46:53Z mike $"
  *
  *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2008 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   This file contains Kerberos support code, copyright 2006 by
@@ -144,9 +144,19 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     Clients = cupsArrayNew(NULL, NULL);
 
   if (!Clients)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "Unable to allocate memory for client array!");
+    cupsdPauseListening();
     return;
+  }
 
-  con = calloc(1, sizeof(cupsd_client_t));
+  if ((con = calloc(1, sizeof(cupsd_client_t))) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for client!");
+    cupsdPauseListening();
+    return;
+  }
 
   con->http.activity = time(NULL);
   con->file          = -1;
@@ -843,7 +853,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
              cupsdLogMessage(CUPSD_LOG_ERROR,
                              "Bad request line \"%s\" from %s!", line,
                              con->http.hostname);
-             cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+             cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
              cupsdCloseClient(con);
              return;
          case 2 :
@@ -855,7 +865,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                cupsdLogMessage(CUPSD_LOG_ERROR,
                                "Bad request line \"%s\" from %s!", line,
                                con->http.hostname);
-               cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+               cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
                cupsdCloseClient(con);
                return;
              }
@@ -870,7 +880,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
              }
              else
              {
-               cupsdSendError(con, HTTP_NOT_SUPPORTED, AUTH_NONE);
+               cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE);
                cupsdCloseClient(con);
                return;
              }
@@ -916,7 +926,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
 
            cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!",
                            con->uri);
-           cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, AUTH_NONE);
+           cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE);
            cupsdCloseClient(con);
            return;
          }
@@ -950,7 +960,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        else
        {
          cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation);
-         cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+         cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
          cupsdCloseClient(con);
          return;
        }
@@ -982,7 +992,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
 
        if (status != HTTP_OK && status != HTTP_CONTINUE)
        {
-         cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+         cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
          cupsdCloseClient(con);
          return;
        }
@@ -1050,7 +1060,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
       * HTTP/1.1 and higher require the "Host:" field...
       */
 
-      if (!cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE))
+      if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
       {
        cupsdCloseClient(con);
        return;
@@ -1062,9 +1072,9 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
       * Do OPTIONS command...
       */
 
-      if (con->best && con->best->type != AUTH_NONE)
+      if (con->best && con->best->type != CUPSD_AUTH_NONE)
       {
-       if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL, AUTH_NONE))
+       if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE))
        {
          cupsdCloseClient(con);
          return;
@@ -1079,7 +1089,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         * Do encryption stuff...
        */
 
-       if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, AUTH_NONE))
+       if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
        {
          cupsdCloseClient(con);
          return;
@@ -1102,7 +1112,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          return;
        }
 #else
-       if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE))
+       if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
        {
          cupsdCloseClient(con);
          return;
@@ -1110,7 +1120,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 #endif /* HAVE_SSL */
       }
 
-      if (!cupsdSendHeader(con, HTTP_OK, NULL, AUTH_NONE))
+      if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
       {
        cupsdCloseClient(con);
        return;
@@ -1132,7 +1142,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
       * Protect against malicious users!
       */
 
-      if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+      if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
       {
        cupsdCloseClient(con);
        return;
@@ -1148,7 +1158,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         * Do encryption stuff...
        */
 
-       if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, AUTH_NONE))
+       if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
        {
          cupsdCloseClient(con);
          return;
@@ -1171,7 +1181,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          return;
        }
 #else
-       if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE))
+       if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
        {
          cupsdCloseClient(con);
          return;
@@ -1184,7 +1194,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         cupsdLogMessage(CUPSD_LOG_DEBUG2,
                        "cupsdReadClient: Unauthorized request for %s...\n",
                        con->uri);
-       cupsdSendError(con, status, AUTH_NONE);
+       cupsdSendError(con, status, CUPSD_AUTH_NONE);
        cupsdCloseClient(con);
        return;
       }
@@ -1198,7 +1208,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          * Send 100-continue header...
          */
 
-         if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, AUTH_NONE))
+         if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, CUPSD_AUTH_NONE))
          {
            cupsdCloseClient(con);
            return;
@@ -1210,7 +1220,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          * Send 417-expectation-failed header...
          */
 
-         if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL, AUTH_NONE))
+         if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL, CUPSD_AUTH_NONE))
          {
            cupsdCloseClient(con);
            return;
@@ -1244,7 +1254,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
              else
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1316,7 +1326,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 
               if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1340,7 +1350,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * /admin/conf...
              */
 
-             if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+             if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1357,7 +1367,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
               if ((filename = get_file(con, &filestats, buf,
                                       sizeof(buf))) == NULL)
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1377,7 +1387,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 
                if (!cupsdSendCommand(con, con->command, con->options, 0))
                {
-                 if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                  {
                    cupsdCloseClient(con);
                    return;
@@ -1393,7 +1403,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 
              if (!check_if_modified(con, &filestats))
               {
-               if (!cupsdSendError(con, HTTP_NOT_MODIFIED, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1433,7 +1443,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * Request too large...
              */
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1447,7 +1457,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * Negative content lengths are invalid!
              */
 
-              if (!cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1542,7 +1552,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
               if ((filename = get_file(con, &filestats, buf,
                                       sizeof(buf))) == NULL)
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1559,7 +1569,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                * Only POST to CGI's...
                */
 
-               if (!cupsdSendError(con, HTTP_UNAUTHORIZED, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_UNAUTHORIZED, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1582,7 +1592,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * /admin/conf...
              */
 
-             if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+             if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1608,7 +1618,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * Request too large...
              */
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1622,7 +1632,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * Negative content lengths are invalid!
              */
 
-              if (!cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1639,19 +1649,23 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                            request_id ++);
            con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
 
-            cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
-                           con->filename, con->file);
-
            if (con->file < 0)
            {
-             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+             cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "Unable to create request file %s: %s",
+                             con->filename, strerror(errno));
+
+             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
              }
            }
 
+            cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                           "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
+                           con->filename, con->file);
+
            fchmod(con->file, 0640);
            fchown(con->file, RunUser, Group);
            fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
@@ -1659,7 +1673,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 
        case HTTP_DELETE :
        case HTTP_TRACE :
-            cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE);
+            cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
            cupsdCloseClient(con);
            return;
 
@@ -1678,7 +1692,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
              else
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -1700,7 +1714,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * CGI output...
              */
 
-              if (!cupsdSendHeader(con, HTTP_OK, "text/html", AUTH_NONE))
+              if (!cupsdSendHeader(con, HTTP_OK, "text/html", CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1732,7 +1746,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              * /admin/conf...
              */
 
-             if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+             if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1743,7 +1757,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            else if ((filename = get_file(con, &filestats, buf,
                                          sizeof(buf))) == NULL)
            {
-             if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html", AUTH_NONE))
+             if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html", CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1753,7 +1767,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
            else if (!check_if_modified(con, &filestats))
             {
-              if (!cupsdSendError(con, HTTP_NOT_MODIFIED, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1773,7 +1787,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              else
                snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
-              if (!cupsdSendHeader(con, HTTP_OK, line, AUTH_NONE))
+              if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1862,7 +1876,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              unlink(con->filename);
              cupsdClearString(&con->filename);
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -1902,7 +1916,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            unlink(con->filename);
            cupsdClearString(&con->filename);
 
-            if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+            if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
            {
              cupsdCloseClient(con);
              return;
@@ -1919,7 +1933,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          * Return the status to the client...
          */
 
-          if (!cupsdSendError(con, status, AUTH_NONE))
+          if (!cupsdSendError(con, status, CUPSD_AUTH_NONE))
          {
            cupsdCloseClient(con);
            return;
@@ -1950,7 +1964,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                              "cupsdReadClient: %d IPP Read Error!",
                              con->http.fd);
 
-             cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+             cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
              cupsdCloseClient(con);
              return;
            }
@@ -1958,7 +1972,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            {
               if (con->http.state == HTTP_POST_SEND)
              {
-               cupsdSendError(con, HTTP_BAD_REQUEST, AUTH_NONE);
+               cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
                cupsdCloseClient(con);
                return;
              }
@@ -1978,18 +1992,22 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
             cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
            con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
 
-            cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
-                           con->filename, con->file);
-
            if (con->file < 0)
            {
-             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+             cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "Unable to create request file %s: %s",
+                             con->filename, strerror(errno));
+
+             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
              }
            }
 
+            cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
+                           con->filename, con->file);
+
            fchmod(con->file, 0640);
            fchown(con->file, RunUser, Group);
             fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
@@ -2025,7 +2043,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                unlink(con->filename);
                cupsdClearString(&con->filename);
 
-               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -2081,7 +2099,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                con->request = NULL;
               }
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE))
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
              {
                cupsdCloseClient(con);
                return;
@@ -2092,7 +2110,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            {
              if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
-               if (!cupsdSendError(con, HTTP_NOT_FOUND, AUTH_NONE))
+               if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
                {
                  cupsdCloseClient(con);
                  return;
@@ -2232,7 +2250,7 @@ cupsdSendError(cupsd_client_t *con,       /* I - Connection */
   * never disable it in that case.
   */
 
-  if (code >= HTTP_BAD_REQUEST && con->http.auth_type != AUTH_NEGOTIATE)
+  if (code >= HTTP_BAD_REQUEST && con->http.auth_type != CUPSD_AUTH_NEGOTIATE)
     con->http.keep_alive = HTTP_KEEPALIVE_OFF;
 
  /*
@@ -2351,7 +2369,11 @@ cupsdSendHeader(
     char           *type,              /* I - MIME type of document */
     int            auth_type)          /* I - Type of authentication */
 {
-  char auth_str[1024];                 /* Authorization string */
+  char         auth_str[1024];         /* Authorization string */
+#ifdef HAVE_GSSAPI
+  static char  *gss_buf = NULL;        /* Kerberos auth data buffer */
+  static int   gss_bufsize = 0;        /* Size of Kerberos auth data buffer */
+#endif /* HAVE_GSSAPI */
 
 
  /*
@@ -2394,9 +2416,9 @@ cupsdSendHeader(
 
   if (code == HTTP_UNAUTHORIZED)
   {
-    if (auth_type == AUTH_NONE)
+    if (auth_type == CUPSD_AUTH_NONE)
     {
-      if (!con->best || con->best->type <= AUTH_NONE)
+      if (!con->best || con->best->type <= CUPSD_AUTH_NONE)
        auth_type = DefaultAuthType;
       else
        auth_type = con->best->type;
@@ -2404,18 +2426,18 @@ cupsdSendHeader(
 
     auth_str[0] = '\0';
 
-    if (auth_type == AUTH_BASIC || auth_type == AUTH_BASICDIGEST)
+    if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
       strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
-    else if (auth_type == AUTH_DIGEST)
+    else if (auth_type == CUPSD_AUTH_DIGEST)
       snprintf(auth_str, sizeof(auth_str), "Digest realm=\"CUPS\", nonce=\"%s\"",
               con->http.hostname);
 #ifdef HAVE_GSSAPI
-    else if (auth_type == AUTH_NEGOTIATE && con->gss_output_token.length == 0)
+    else if (auth_type == CUPSD_AUTH_NEGOTIATE && con->gss_output_token.length == 0)
       strlcpy(auth_str, "Negotiate", sizeof(auth_str));
 #endif /* HAVE_GSSAPI */
 
 #ifdef HAVE_AUTHORIZATION_H
-    if (con->best && auth_type != AUTH_NEGOTIATE)
+    if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE)
     {
       int       i;                     /* Looping var */
       char     *auth_key;              /* Auth key buffer */
@@ -2460,23 +2482,57 @@ cupsdSendHeader(
   * non-401 replies...
   */
 
-  if (con->gss_output_token.length > 0)
+  if (con->gss_output_token.length > 0 && con->gss_output_token.length <= 65536)
   {
-    char       buf[2048];              /* Output token buffer */
     OM_uint32  minor_status;           /* Minor status code */
+    int                bufsize;                /* Size of output token buffer */
+
+
+    bufsize = con->gss_output_token.length * 4 / 3 + 2;
+
+    if (bufsize > gss_bufsize)
+    {
+      char     *buf;                   /* New buffer */
+
 
+      bufsize = (bufsize + 1023) & 1023;/* Round up */
 
-    httpEncode64_2(buf, sizeof(buf),
-                  con->gss_output_token.value,
+      if (gss_buf)
+        buf = realloc(gss_buf, bufsize);
+      else
+        buf = malloc(bufsize);
+
+      if (!buf)
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to allocate %d bytes for Kerberos credentials!",
+                       bufsize);
+       return (0);
+      }
+
+      gss_buf     = buf;
+      gss_bufsize = bufsize;
+    }
+
+    httpEncode64_2(gss_buf, gss_bufsize,
+                  con->gss_output_token.value,
                   con->gss_output_token.length);
     gss_release_buffer(&minor_status, &con->gss_output_token);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdSendHeader: WWW-Authenticate: Negotiate %s", buf);
+                   "cupsdSendHeader: WWW-Authenticate: Negotiate %s", gss_buf);
 
-    if (httpPrintf(HTTP(con), "WWW-Authenticate: Negotiate %s\r\n", buf) < 0)
+    if (httpPrintf(HTTP(con), "WWW-Authenticate: Negotiate %s\r\n",
+                   gss_buf) < 0)
       return (0);
   }
+  else if (con->gss_output_token.length > 65536)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "Kerberos credentials larger than 64k (%d)!",
+                   con->gss_output_token.length);
+    return (0);
+  }
 #endif /* HAVE_GSSAPI */
 
   if (con->language && strcmp(con->language->language, "C"))
@@ -2619,7 +2675,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
 
             if (!strncasecmp(buf, "Location:", 9))
            {
-             cupsdSendHeader(con, HTTP_SEE_OTHER, NULL, AUTH_NONE);
+             cupsdSendHeader(con, HTTP_SEE_OTHER, NULL, CUPSD_AUTH_NONE);
              con->sent_header = 2;
 
              if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0)
@@ -2627,12 +2683,12 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
            }
            else if (!strncasecmp(buf, "Status:", 7))
            {
-             cupsdSendError(con, (http_status_t)atoi(buf + 7), AUTH_NONE);
+             cupsdSendError(con, (http_status_t)atoi(buf + 7), CUPSD_AUTH_NONE);
              con->sent_header = 2;
            }
            else
            {
-             cupsdSendHeader(con, HTTP_OK, NULL, AUTH_NONE);
+             cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE);
              con->sent_header = 1;
 
              if (con->http.version == HTTP_1_1)
@@ -3228,12 +3284,15 @@ get_file(cupsd_client_t *con,           /* I  - Client connection */
   int          status;                 /* Status of filesystem calls */
   char         *ptr;                   /* Pointer info filename */
   int          plen;                   /* Remaining length after pointer */
+  char         language[7];            /* Language subdirectory, if any */
 
 
  /*
   * Figure out the real filename...
   */
 
+  language[0] = '\0';
+
   if (!strncmp(con->uri, "/ppd/", 5))
     snprintf(filename, len, "%s%s", ServerRoot, con->uri);
   else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
@@ -3242,18 +3301,20 @@ get_file(cupsd_client_t *con,           /* I  - Client connection */
     snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
   else if (!strncmp(con->uri, "/admin/log/", 11))
   {
-    if (!strcmp(con->uri + 11, "access_log") && AccessLog[0] == '/')
+    if (!strncmp(con->uri + 11, "access_log", 10) && AccessLog[0] == '/')
       strlcpy(filename, AccessLog, len);
-    else if (!strcmp(con->uri + 11, "error_log") && ErrorLog[0] == '/')
+    else if (!strncmp(con->uri + 11, "error_log", 9) && ErrorLog[0] == '/')
       strlcpy(filename, ErrorLog, len);
-    else if (!strcmp(con->uri + 11, "page_log") && PageLog[0] == '/')
+    else if (!strncmp(con->uri + 11, "page_log", 8) && PageLog[0] == '/')
       strlcpy(filename, PageLog, len);
     else
       return (NULL);
   }
   else if (con->language)
-    snprintf(filename, len, "%s/%s%s", DocumentRoot, con->language->language,
-             con->uri);
+  {
+    snprintf(language, sizeof(language), "/%s", con->language->language);
+    snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
+  }
   else
     snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
 
@@ -3265,7 +3326,7 @@ get_file(cupsd_client_t *con,             /* I  - Client connection */
   * then fallback to the default one...
   */
 
-  if ((status = stat(filename, filestats)) != 0 && con->language &&
+  if ((status = stat(filename, filestats)) != 0 && language[0] &&
       strncmp(con->uri, "/ppd/", 5) &&
       strncmp(con->uri, "/admin/conf/", 12) &&
       strncmp(con->uri, "/admin/log/", 11))
@@ -3274,11 +3335,8 @@ get_file(cupsd_client_t *con,            /* I  - Client connection */
     * Drop the country code...
     */
 
-    char       ll[3];                  /* Short language name */
-
-
-    strlcpy(ll, con->language->language, sizeof(ll));
-    snprintf(filename, len, "%s/%s%s", DocumentRoot, ll, con->uri);
+    language[3] = '\0';
+    snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
 
     if ((ptr = strchr(filename, '?')) != NULL)
       *ptr = '\0';
@@ -3289,6 +3347,7 @@ get_file(cupsd_client_t *con,             /* I  - Client connection */
       * Drop the language prefix and try the root directory...
       */
 
+      language[0] = '\0';
       snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
 
       if ((ptr = strchr(filename, '?')) != NULL)
@@ -3304,52 +3363,86 @@ get_file(cupsd_client_t *con,           /* I  - Client connection */
 
   if (!status && S_ISDIR(filestats->st_mode))
   {
-    if (filename[strlen(filename) - 1] != '/')
-      strlcat(filename, "/", len);
+   /*
+    * Make sure the URI ends with a slash...
+    */
 
-    ptr  = filename + strlen(filename);
-    plen = len - (ptr - filename);
+    if (con->uri[strlen(con->uri) - 1] != '/')
+      strlcat(con->uri, "/", sizeof(con->uri));
 
-    strlcpy(ptr, "index.html", plen);
-    status = stat(filename, filestats);
+   /*
+    * Find the directory index file, trying every language...
+    */
 
-#ifdef HAVE_JAVA
-    if (status)
+    do
     {
-      strlcpy(ptr, "index.class", plen);
+      if (status && language[0])
+      {
+       /*
+        * Try a different language subset...
+       */
+
+       if (language[3])
+         language[0] = '\0';           /* Strip country code */
+       else
+         language[0] = '\0';           /* Strip language */
+      }
+
+     /*
+      * Look for the index file...
+      */
+
+      snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
+
+      if ((ptr = strchr(filename, '?')) != NULL)
+       *ptr = '\0';
+
+      ptr  = filename + strlen(filename);
+      plen = len - (ptr - filename);
+
+      strlcpy(ptr, "index.html", plen);
       status = stat(filename, filestats);
-    }
+
+#ifdef HAVE_JAVA
+      if (status)
+      {
+       strlcpy(ptr, "index.class", plen);
+       status = stat(filename, filestats);
+      }
 #endif /* HAVE_JAVA */
 
 #ifdef HAVE_PERL
-    if (status)
-    {
-      strlcpy(ptr, "index.pl", plen);
-      status = stat(filename, filestats);
-    }
+      if (status)
+      {
+       strlcpy(ptr, "index.pl", plen);
+       status = stat(filename, filestats);
+      }
 #endif /* HAVE_PERL */
 
 #ifdef HAVE_PHP
-    if (status)
-    {
-      strlcpy(ptr, "index.php", plen);
-      status = stat(filename, filestats);
-    }
+      if (status)
+      {
+       strlcpy(ptr, "index.php", plen);
+       status = stat(filename, filestats);
+      }
 #endif /* HAVE_PHP */
 
 #ifdef HAVE_PYTHON
-    if (status)
-    {
-      strlcpy(ptr, "index.pyc", plen);
-      status = stat(filename, filestats);
-    }
+      if (status)
+      {
+       strlcpy(ptr, "index.pyc", plen);
+       status = stat(filename, filestats);
+      }
 
-    if (status)
-    {
-      strlcpy(ptr, "index.py", plen);
-      status = stat(filename, filestats);
-    }
+      if (status)
+      {
+       strlcpy(ptr, "index.py", plen);
+       status = stat(filename, filestats);
+      }
 #endif /* HAVE_PYTHON */
+
+    }
+    while (status && language[0]);
   }
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_file: %d filename=%s size=%d",
@@ -3802,7 +3895,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     envp[envc++] = home;
     envp[envc]   = NULL;
 
-    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, &pid))
+    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
+                           &pid))
     {
       unlink(seedfile);
       return (0);
@@ -3879,7 +3973,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+                         &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -4112,7 +4207,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+                         &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -4183,7 +4279,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],         /* AUTH_TYPE environment variable */
+  char         auth_type[256],         /* CUPSD_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 */
@@ -4198,6 +4294,11 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
                script_name[1024],      /* SCRIPT_NAME environment variable */
                server_name[1024],      /* SERVER_NAME environment variable */
                server_port[1024];      /* SERVER_PORT environment variable */
+  ipp_attribute_t *attr;               /* attributes-natural-language attribute */
+#ifdef HAVE_GSSAPI
+  krb5_ccache  ccache = NULL;          /* Kerberos credentials */
+  char         krb5ccname[1024];       /* KRB5CCNAME environment variable */
+#endif /* HAVE_GSSAPI */
 
 
  /*
@@ -4324,7 +4425,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
 
   if (con->username[0])
   {
-    snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
+    snprintf(auth_type, sizeof(auth_type), "CUPSD_AUTH_TYPE=%s",
              httpGetField(HTTP(con), HTTP_FIELD_AUTHORIZATION));
 
     if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)
@@ -4333,8 +4434,45 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
   else
     auth_type[0] = '\0';
 
-  if (con->language)
-    snprintf(lang, sizeof(lang), "LANG=%s.UTF-8", con->language->language);
+  if (con->request &&
+      (attr = ippFindAttribute(con->request, "attributes-natural-language",
+                               IPP_TAG_LANGUAGE)) != NULL)
+  {
+    switch (strlen(attr->values[0].string.text))
+    {
+      default :
+        /*
+         * This is an unknown or badly formatted language code; use
+         * the POSIX locale...
+         */
+
+         strcpy(lang, "LANG=C");
+         break;
+
+      case 2 :
+        /*
+         * Just the language code (ll)...
+         */
+
+         snprintf(lang, sizeof(lang), "LANG=%s.UTF8",
+                  attr->values[0].string.text);
+         break;
+
+      case 5 :
+        /*
+         * Language and country code (ll-cc)...
+         */
+
+         snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF8",
+                  attr->values[0].string.text[0],
+                  attr->values[0].string.text[1],
+                  toupper(attr->values[0].string.text[3] & 255),
+                  toupper(attr->values[0].string.text[4] & 255));
+         break;
+    }
+  }
+  else if (con->language)
+    snprintf(lang, sizeof(lang), "LANG=%s.UTF8", con->language->language);
   else
     strcpy(lang, "LANG=C");
 
@@ -4380,6 +4518,120 @@ pipe_command(cupsd_client_t *con,       /* I - Client connection */
     snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
 
     envp[envc ++] = remote_user;
+
+   /*
+    * Save Kerberos credentials, if any...
+    */
+
+#ifdef HAVE_GSSAPI
+    if (con->gss_have_creds)
+    {
+#  if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL)
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                     "Sorry, your version of Kerberos does not support "
+                     "delegated credentials!");
+
+#  else
+      krb5_error_code  error;          /* Kerberos error code */
+      OM_uint32                major_status,   /* Major status code */
+                       minor_status;   /* Minor status code */
+      krb5_principal   principal;      /* Kerberos principal */
+
+
+#   ifdef __APPLE__
+     /*
+      * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+      * to use it...
+      */
+
+      if (krb5_init_context != NULL)
+      {
+#    endif /* __APPLE__ */
+
+     /*
+      * We MUST create a file-based cache because memory-based caches are
+      * only valid for the current process/address space.
+      *
+      * Due to various bugs/features in different versions of Kerberos, we
+      * need either the krb5_cc_new_unique() function or Heimdal's version
+      * of krb5_cc_gen_new() to create a new FILE: credential cache that
+      * can be passed to the backend.  These functions create a temporary
+      * file (typically in /tmp) containing the cached credentials, which
+      * are removed when we have successfully printed a job.
+      */
+
+#    ifdef HAVE_KRB5_CC_NEW_UNIQUE
+      if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL,
+                                     &ccache)) != 0)
+#    else /* HAVE_HEIMDAL */
+      if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops,
+                                  &ccache)) != 0)
+#    endif /* HAVE_KRB5_CC_NEW_UNIQUE */
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to create new credentials cache (%d/%s)",
+                       error, strerror(errno));
+       ccache = NULL;
+      }
+      else if ((error = krb5_parse_name(KerberosContext, con->username,
+                                       &principal)) != 0)
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to parse kerberos username (%d/%s)", error,
+                       strerror(errno));
+       krb5_cc_destroy(KerberosContext, ccache);
+       ccache = NULL;
+      }
+      else if ((error = krb5_cc_initialize(KerberosContext, ccache,
+                                           principal)))
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to initialize credentials cache (%d/%s)", error,
+                       strerror(errno));
+       krb5_cc_destroy(KerberosContext, ccache);
+       krb5_free_principal(KerberosContext, principal);
+       ccache = NULL;
+      }
+      else
+      {
+       krb5_free_principal(KerberosContext, principal);
+
+       /*
+       * Copy the user's credentials to the new cache file...
+       */
+
+       major_status = gss_krb5_copy_ccache(&minor_status,
+                                           con->gss_delegated_cred, ccache);
+
+       if (GSS_ERROR(major_status))
+       {
+         cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status,
+                            "Unable to import client credentials cache");
+         krb5_cc_destroy(KerberosContext, ccache);
+         ccache = NULL;
+       }
+       else
+       {
+        /*
+         * Add the KRB5CCNAME environment variable to the job so that the
+         * backend can use the credentials when printing.
+         */
+
+         snprintf(krb5ccname, sizeof(krb5ccname), "KRB5CCNAME=FILE:%s",
+                  krb5_cc_get_name(KerberosContext, ccache));
+          envp[envc++] = krb5ccname;
+
+         if (!RunUser)
+           chown(krb5_cc_get_name(KerberosContext, ccache), User, Group);
+        }
+     }
+#    ifdef __APPLE__
+     }
+#    endif /* __APPLE__ */
+#  endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */
+    }
+#endif /* HAVE_GSSAPI */
+
   }
 
   if (con->http.version == HTTP_1_1)
@@ -4474,7 +4726,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   */
 
   if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
-                       -1, -1, root, &pid) < 0)
+                       -1, -1, root, DefaultProfile, &pid) < 0)
   {
    /*
     * Error - can't fork!
@@ -4493,7 +4745,11 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
     */
 
     if (con->username[0])
-      cupsdAddCert(pid, con->username);
+#ifdef HAVE_GSSAPI
+      cupsdAddCert(pid, con->username, ccache);
+#else
+      cupsdAddCert(pid, con->username, NULL);
+#endif /* HAVE_GSSAPI */
 
     cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] %s started - PID = %d",
                     command, pid);
@@ -4529,7 +4785,7 @@ write_file(cupsd_client_t *con,           /* I - Client connection */
 
   con->pipe_pid = 0;
 
-  if (!cupsdSendHeader(con, code, type, AUTH_NONE))
+  if (!cupsdSendHeader(con, code, type, CUPSD_AUTH_NONE))
     return (0);
 
   if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
@@ -4577,5 +4833,5 @@ write_pipe(cupsd_client_t *con)           /* I - Client connection */
 
 
 /*
- * End of "$Id: client.c 6758 2007-08-02 00:13:44Z mike $".
+ * End of "$Id: client.c 6999 2007-09-28 19:46:53Z mike $".
  */