/*
- * "$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
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;
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 :
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;
}
}
else
{
- cupsdSendError(con, HTTP_NOT_SUPPORTED, AUTH_NONE);
+ cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
}
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;
}
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;
}
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;
}
* 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;
* 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;
* 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;
return;
}
#else
- if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
#endif /* HAVE_SSL */
}
- if (!cupsdSendHeader(con, HTTP_OK, NULL, AUTH_NONE))
+ if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* Protect against malicious users!
*/
- if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* 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;
return;
}
#else
- if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
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;
}
* Send 100-continue header...
*/
- if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, AUTH_NONE))
+ if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* 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;
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;
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;
* /admin/conf...
*/
- if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
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;
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;
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;
* 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;
* 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;
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;
* Only POST to CGI's...
*/
- if (!cupsdSendError(con, HTTP_UNAUTHORIZED, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_UNAUTHORIZED, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* /admin/conf...
*/
- if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* 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;
* 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;
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);
case HTTP_DELETE :
case HTTP_TRACE :
- cupsdSendError(con, HTTP_NOT_IMPLEMENTED, AUTH_NONE);
+ cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
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;
* CGI output...
*/
- if (!cupsdSendHeader(con, HTTP_OK, "text/html", AUTH_NONE))
+ if (!cupsdSendHeader(con, HTTP_OK, "text/html", CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
* /admin/conf...
*/
- if (!cupsdSendError(con, HTTP_FORBIDDEN, AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
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;
}
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;
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;
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;
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;
* Return the status to the client...
*/
- if (!cupsdSendError(con, status, AUTH_NONE))
+ if (!cupsdSendError(con, status, CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
"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;
}
{
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;
}
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);
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;
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;
{
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;
* 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;
/*
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 */
/*
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;
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 */
* 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"))
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)
}
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)
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, '/'))
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);
* 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))
* 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';
* 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)
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",
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);
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);
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);
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 */
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 */
/*
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)
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");
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)
*/
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!
*/
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);
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",
/*
- * 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 $".
*/