/*
- * "$Id: client.c 7950 2008-09-17 00:21:59Z mike $"
+ * "$Id$"
*
* Client routines for the CUPS scheduler.
*
- * Copyright 2007-2012 by Apple Inc.
+ * Copyright 2007-2013 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 __APPLE__
+# include <libproc.h>
+#endif /* __APPLE__ */
#ifdef HAVE_TCPD_H
# include <tcpd.h>
#endif /* HAVE_TCPD_H */
#ifdef AF_LOCAL
if (con->http.hostaddr->addr.sa_family == AF_LOCAL)
+ {
+# ifdef __APPLE__
+ socklen_t peersize; /* Size of peer credentials */
+ pid_t peerpid; /* Peer process ID */
+ char name[256]; /* Name of process */
+
+ peersize = sizeof(peerpid);
+ if (!getsockopt(con->http.fd, SOL_LOCAL, LOCAL_PEERPID, &peerpid,
+ &peersize))
+ {
+ if (!proc_name(peerpid, name, sizeof(name)))
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[Client %d] Accepted from %s (Domain ???[%d])",
+ con->http.fd, con->http.hostname, (int)peerpid);
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[Client %d] Accepted from %s (Domain %s[%d])",
+ con->http.fd, con->http.hostname, name, (int)peerpid);
+ }
+ else
+# endif /* __APPLE__ */
+
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s (Domain)",
con->http.fd, con->http.hostname);
+ }
else
#endif /* AF_LOCAL */
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s:%d (IPv%d)",
{
if (httpAddrLocalhost(&temp))
strlcpy(con->servername, "localhost", sizeof(con->servername));
- else if (HostNameLookups || RemotePort)
+ else if (HostNameLookups)
httpAddrLookup(&temp, con->servername, sizeof(con->servername));
else
httpAddrString(&temp, con->servername, sizeof(con->servername));
{
int bytes = httpFlushWrite(HTTP(con));
- con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_encoding = HTTP_ENCODING_LENGTH;
return (bytes);
}
"file=%d",
con->http.fd, con->http.error, con->http.used,
http_states[con->http.state + 1],
- con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
+ con->http.data_encoding == HTTP_ENCODING_CHUNKED ?
"CHUNKED" : "LENGTH",
CUPS_LLCAST con->http.data_remaining,
con->request,
switch (con->http.state)
{
- case HTTP_WAITING :
+ case HTTP_STATE_WAITING :
/*
* See if we've received a request line...
*/
{
if (con->http.error && con->http.error != EPIPE)
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_WAITING Closing for error %d "
+ "[Client %d] HTTP_STATE_WAITING Closing for error %d "
"(%s)", con->http.fd, con->http.error,
strerror(con->http.error));
else
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_WAITING Closing on EOF",
+ "[Client %d] HTTP_STATE_WAITING Closing on EOF",
con->http.fd);
cupsdCloseClient(con);
con->http.activity = time(NULL);
con->http.version = HTTP_1_0;
con->http.keep_alive = HTTP_KEEPALIVE_OFF;
- con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_encoding = HTTP_ENCODING_LENGTH;
con->http.data_remaining = 0;
con->http._data_remaining = 0;
- con->operation = HTTP_WAITING;
+ con->operation = HTTP_STATE_WAITING;
con->bytes = 0;
con->file = -1;
con->file_ready = 0;
*/
if (!strcmp(operation, "GET"))
- con->http.state = HTTP_GET;
+ con->http.state = HTTP_STATE_GET;
else if (!strcmp(operation, "PUT"))
- con->http.state = HTTP_PUT;
+ con->http.state = HTTP_STATE_PUT;
else if (!strcmp(operation, "POST"))
- con->http.state = HTTP_POST;
+ con->http.state = HTTP_STATE_POST;
else if (!strcmp(operation, "DELETE"))
- con->http.state = HTTP_DELETE;
+ con->http.state = HTTP_STATE_DELETE;
else if (!strcmp(operation, "TRACE"))
- con->http.state = HTTP_TRACE;
+ con->http.state = HTTP_STATE_TRACE;
else if (!strcmp(operation, "OPTIONS"))
- con->http.state = HTTP_OPTIONS;
+ con->http.state = HTTP_STATE_OPTIONS;
else if (!strcmp(operation, "HEAD"))
- con->http.state = HTTP_HEAD;
+ con->http.state = HTTP_STATE_HEAD;
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
cupsdSetBusyState();
}
- case HTTP_OPTIONS :
- case HTTP_DELETE :
- case HTTP_GET :
- case HTTP_HEAD :
- case HTTP_POST :
- case HTTP_PUT :
- case HTTP_TRACE :
+ case HTTP_STATE_OPTIONS :
+ case HTTP_STATE_DELETE :
+ case HTTP_STATE_GET :
+ case HTTP_STATE_HEAD :
+ case HTTP_STATE_POST :
+ case HTTP_STATE_PUT :
+ case HTTP_STATE_TRACE :
/*
* Parse incoming parameters until the status changes...
*/
return;
}
}
- else if (con->operation == HTTP_OPTIONS)
+ else if (con->operation == HTTP_STATE_OPTIONS)
{
/*
* Do OPTIONS command...
}
if (con->http.expect &&
- (con->operation == HTTP_POST || con->operation == HTTP_PUT))
+ (con->operation == HTTP_STATE_POST || con->operation == HTTP_STATE_PUT))
{
if (con->http.expect == HTTP_CONTINUE)
{
switch (con->http.state)
{
- case HTTP_GET_SEND :
- if (!strncmp(con->uri, "/printers/", 10) &&
+ case HTTP_STATE_GET_SEND :
+ if ((!strncmp(con->uri, "/ppd/", 5) ||
+ !strncmp(con->uri, "/printers/", 10) ||
+ !strncmp(con->uri, "/classes/", 9)) &&
!strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
{
/*
con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
- if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+ if (!strncmp(con->uri, "/ppd/", 5))
+ p = cupsdFindPrinter(con->uri + 5);
+ else if (!strncmp(con->uri, "/printers/", 10))
+ p = cupsdFindPrinter(con->uri + 10);
+ else
+ {
+ p = cupsdFindClass(con->uri + 9);
+
+ if (p)
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < p->num_printers; i ++)
+ {
+ if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
+ {
+ char ppdname[1024];/* PPD filename */
+
+ snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd",
+ ServerRoot, p->printers[i]->name);
+ if (!access(ppdname, 0))
+ {
+ p = p->printers[i];
+ break;
+ }
+ }
+ }
+
+ if (i >= p->num_printers)
+ p = NULL;
+ }
+ }
+
+ if (p)
+ {
snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+ }
else
{
if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
break;
}
}
- else if ((!strncmp(con->uri, "/printers/", 10) ||
+ else if ((!strncmp(con->uri, "/icons/", 7) ||
+ !strncmp(con->uri, "/printers/", 10) ||
!strncmp(con->uri, "/classes/", 9)) &&
!strcmp(con->uri + strlen(con->uri) - 4, ".png"))
{
con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".png" */
- if (!strncmp(con->uri, "/printers/", 10))
+ if (!strncmp(con->uri, "/icons/", 7))
+ p = cupsdFindPrinter(con->uri + 7);
+ else if (!strncmp(con->uri, "/printers/", 10))
p = cupsdFindPrinter(con->uri + 10);
else
- p = cupsdFindClass(con->uri + 9);
+ {
+ p = cupsdFindClass(con->uri + 9);
+
+ if (p)
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < p->num_printers; i ++)
+ {
+ if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
+ {
+ char ppdname[1024];/* PPD filename */
+
+ snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd",
+ ServerRoot, p->printers[i]->name);
+ if (!access(ppdname, 0))
+ {
+ p = p->printers[i];
+ break;
+ }
+ }
+ }
+
+ if (i >= p->num_printers)
+ p = NULL;
+ }
+ }
if (p)
snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
}
break;
- case HTTP_POST_RECV :
+ case HTTP_STATE_POST_RECV :
/*
* See if the POST request includes a Content-Length field, and if
* so check the length against any limits that are set...
}
else if (con->http.data_remaining < 0 ||
(!con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
- con->http.data_encoding == HTTP_ENCODE_LENGTH))
+ con->http.data_encoding == HTTP_ENCODING_LENGTH))
{
/*
* Negative content lengths are invalid!
}
break;
- case HTTP_PUT_RECV :
+ case HTTP_STATE_PUT_RECV :
/*
* Validate the resource name...
*/
fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
break;
- case HTTP_DELETE :
- case HTTP_TRACE :
+ case HTTP_STATE_DELETE :
+ case HTTP_STATE_TRACE :
cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
- case HTTP_HEAD :
+ case HTTP_STATE_HEAD :
if (!strncmp(con->uri, "/printers/", 10) &&
!strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
{
switch (con->http.state)
{
- case HTTP_PUT_RECV :
+ case HTTP_STATE_PUT_RECV :
do
{
if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
{
if (con->http.error && con->http.error != EPIPE)
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_PUT_RECV Closing for error "
+ "[Client %d] HTTP_STATE_PUT_RECV Closing for error "
"%d (%s)", con->http.fd, con->http.error,
strerror(con->http.error));
else
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_PUT_RECV Closing on EOF",
+ "[Client %d] HTTP_STATE_PUT_RECV Closing on EOF",
con->http.fd);
cupsdCloseClient(con);
}
}
}
- while (con->http.state == HTTP_PUT_RECV && data_ready(con));
+ while (con->http.state == HTTP_STATE_PUT_RECV && data_ready(con));
- if (con->http.state == HTTP_WAITING)
+ if (con->http.state == HTTP_STATE_STATUS)
{
/*
* End of file, see how big it is...
}
break;
- case HTTP_POST_RECV :
+ case HTTP_STATE_POST_RECV :
do
{
if (con->request && con->file < 0)
}
else if (ipp_state != IPP_DATA)
{
- if (con->http.state == HTTP_POST_SEND)
+ if (con->http.state == HTTP_STATE_POST_SEND)
{
cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
}
+ if (data_ready(con))
+ continue;
break;
}
else
}
}
- if (con->file < 0 && con->http.state != HTTP_POST_SEND)
+ if (con->file < 0 && con->http.state != HTTP_STATE_POST_SEND)
{
/*
* Create a file as needed for the request data...
fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
}
- if (con->http.state != HTTP_POST_SEND)
+ if (con->http.state != HTTP_STATE_POST_SEND)
{
- if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+ if (!httpWait(HTTP(con), 0))
+ return;
+ else if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
{
if (con->http.error && con->http.error != EPIPE)
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_POST_SEND Closing for "
+ "[Client %d] HTTP_STATE_POST_SEND Closing for "
"error %d (%s)", con->http.fd, con->http.error,
strerror(con->http.error));
else
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Client %d] HTTP_POST_SEND Closing on EOF",
+ "[Client %d] HTTP_STATE_POST_SEND Closing on EOF",
con->http.fd);
cupsdCloseClient(con);
}
}
}
- else if (con->http.state == HTTP_POST_RECV)
+ else if (con->http.state == HTTP_STATE_POST_RECV)
return;
- else if (con->http.state != HTTP_POST_SEND)
+ else if (con->http.state != HTTP_STATE_POST_SEND)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"[Client %d] Closing on unexpected state %s.",
}
}
}
- while (con->http.state == HTTP_POST_RECV && data_ready(con));
+ while (con->http.state == HTTP_STATE_POST_RECV && data_ready(con));
- if (con->http.state == HTTP_POST_SEND)
+ if (con->http.state == HTTP_STATE_POST_SEND)
{
if (con->file >= 0)
{
break; /* Anti-compiler-warning-code */
}
- if (con->http.state == HTTP_WAITING)
+ if (con->http.state == HTTP_STATE_WAITING)
{
if (!con->http.keep_alive)
{
httpFlushWrite(HTTP(con));
- con->http.data_encoding = HTTP_ENCODE_FIELDS;
+ con->http.data_encoding = HTTP_ENCODING_FIELDS;
if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
con->http.version % 100, code, httpStatus(code)) < 0)
con->http.hostname);
#ifdef HAVE_GSSAPI
else if (auth_type == CUPSD_AUTH_NEGOTIATE)
+ {
+# ifdef AF_LOCAL
+ if (_httpAddrFamily(con->http.hostaddr) == AF_LOCAL)
+ strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
+ else
+# endif /* AF_LOCAL */
strlcpy(auth_str, "Negotiate", sizeof(auth_str));
+ }
#endif /* HAVE_GSSAPI */
if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE &&
ipp_state_t ipp_state; /* IPP state value */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
"[Client %d] cupsdWriteClient "
"error=%d, "
"used=%d, "
"state=%s, "
- "data_encoding=HTTP_ENCODE_%s, "
+ "data_encoding=HTTP_ENCODING_%s, "
"data_remaining=" CUPS_LLFMT ", "
"response=%p(%s), "
"pipe_pid=%d, "
"file=%d",
con->http.fd, con->http.error, con->http.used,
http_states[con->http.state + 1],
- con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
+ con->http.data_encoding == HTTP_ENCODING_CHUNKED ?
"CHUNKED" : "LENGTH",
CUPS_LLCAST con->http.data_remaining,
con->response,
con->response ? ipp_states[con->response->state] : "",
con->pipe_pid, con->file);
- if (con->http.state != HTTP_GET_SEND &&
- con->http.state != HTTP_POST_SEND)
+ if (con->http.state != HTTP_STATE_GET_SEND &&
+ con->http.state != HTTP_STATE_POST_SEND)
{
/*
* If we get called in the wrong state, then something went wrong with the
if (con->response && con->response->state != IPP_DATA)
{
- ipp_state = ippWrite(HTTP(con), con->response);
- bytes = ipp_state != IPP_ERROR &&
- (con->file >= 0 || ipp_state != IPP_DATA);
+ int wused = con->http.wused; /* Previous write buffer use */
+
+ do
+ {
+ /*
+ * Write a single attribute or the IPP message header...
+ */
+
+// ipp_state = ippWrite(HTTP(con), con->response);
+ ipp_state = ippWriteIO(HTTP(con), (ipp_iocb_t)httpWrite2, 1, NULL,
+ con->response);
+
+ /*
+ * If the write buffer has been flushed, stop buffering up attributes...
+ */
+
+ if (con->http.wused <= wused)
+ break;
+ }
+ while (ipp_state != IPP_STATE_DATA && ipp_state != IPP_STATE_ERROR);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[Client %d] Writing IPP response, ipp_state=%d, old "
+ "wused=%d, new wused=%d", con->http.fd, ipp_state, wused,
+ con->http.wused);
+
+ if (con->http.wused > 0)
+ httpFlushWrite(HTTP(con));
+
+ bytes = ipp_state != IPP_STATE_ERROR &&
+ (con->file >= 0 || ipp_state != IPP_STATE_DATA);
}
else if ((bytes = read(con->file, con->header + con->header_used,
sizeof(con->header) - con->header_used)) > 0)
}
if (con->http.version == HTTP_1_1)
- con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+ con->http.data_encoding = HTTP_ENCODING_CHUNKED;
}
else
field_col = 0;
return;
}
- if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
+ if (con->http.data_encoding == HTTP_ENCODING_CHUNKED)
httpFlushWrite(HTTP(con));
con->bytes += con->header_used;
- if (con->http.state == HTTP_WAITING)
+ if (con->http.state == HTTP_STATE_WAITING)
bytes = 0;
else
bytes = con->header_used;
}
if (bytes <= 0 ||
- (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND))
+ (con->http.state != HTTP_STATE_GET_SEND && con->http.state != HTTP_STATE_POST_SEND))
{
if (!con->sent_header && con->pipe_pid)
cupsdSendError(con, HTTP_SERVER_ERROR, CUPSD_AUTH_NONE);
httpFlushWrite(HTTP(con));
- if (con->http.data_encoding == HTTP_ENCODE_CHUNKED && con->sent_header == 1)
+ if (con->http.data_encoding == HTTP_ENCODING_CHUNKED && con->sent_header == 1)
{
if (httpWrite2(HTTP(con), "", 0) < 0)
{
}
}
- con->http.state = HTTP_WAITING;
+ con->http.state = HTTP_STATE_WAITING;
cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
* Open the new config file...
*/
- snprintf(filename, sizeof(filename), "%s/cupsd.conf", ServerRoot);
- if ((out = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
+ if ((out = cupsdCreateConfFile(ConfigurationFile, ConfigFilePerm)) == NULL)
{
cupsFileClose(in);
return (HTTP_SERVER_ERROR);
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", filename);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...",
+ ConfigurationFile);
/*
* Copy from the request to the new config file...
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to copy to config file \"%s\": %s",
- filename, strerror(errno));
+ ConfigurationFile, strerror(errno));
cupsFileClose(in);
cupsFileClose(out);
- snprintf(filename, sizeof(filename), "%s%s.N", ServerRoot, con->uri + 11);
- cupsdRemoveFile(filename);
+ snprintf(filename, sizeof(filename), "%s.N", ConfigurationFile);
+ cupsdUnlinkOrRemoveFile(filename);
return (HTTP_SERVER_ERROR);
}
cupsFileClose(in);
- if (cupsdCloseCreatedConfFile(out, filename))
+ if (cupsdCloseCreatedConfFile(out, ConfigurationFile))
return (HTTP_SERVER_ERROR);
/*
* Remove the request file...
*/
- cupsdRemoveFile(con->filename);
+ cupsdUnlinkOrRemoveFile(con->filename);
cupsdClearString(&con->filename);
/*
commptr ++;
}
- if (*commptr == '?' && con->operation == HTTP_GET && !con->query_string)
+ if (*commptr == '?' && con->operation == HTTP_STATE_GET && !con->query_string)
{
commptr ++;
cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", commptr);
envp[envc ++] = http_referer;
}
- if (con->operation == HTTP_GET)
+ if (con->operation == HTTP_STATE_GET)
{
envp[envc ++] = "REQUEST_METHOD=GET";
if (cupsdFlushHeader(con) < 0)
return (0);
- con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_encoding = HTTP_ENCODING_LENGTH;
con->http.data_remaining = filestats->st_size;
if (con->http.data_remaining <= INT_MAX)
/*
- * End of "$Id: client.c 7950 2008-09-17 00:21:59Z mike $".
+ * End of "$Id$".
*/