diff options
Diffstat (limited to 'scheduler')
-rw-r--r-- | scheduler/auth.c | 134 | ||||
-rw-r--r-- | scheduler/client.c | 26 | ||||
-rw-r--r-- | scheduler/client.h | 5 | ||||
-rw-r--r-- | scheduler/conf.c | 237 | ||||
-rw-r--r-- | scheduler/ipp.c | 787 | ||||
-rw-r--r-- | scheduler/job.c | 14 | ||||
-rw-r--r-- | scheduler/org.cups.cupsd.service.in | 2 | ||||
-rw-r--r-- | scheduler/process.c | 18 | ||||
-rw-r--r-- | scheduler/server.c | 22 |
9 files changed, 603 insertions, 642 deletions
diff --git a/scheduler/auth.c b/scheduler/auth.c index 8b134b5..fa4e271 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -1,8 +1,8 @@ /* * Authorization routines for the CUPS scheduler. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. @@ -71,9 +71,6 @@ static int check_authref(cupsd_client_t *con, const char *right); static int compare_locations(cupsd_location_t *a, cupsd_location_t *b); static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data); -#if !HAVE_LIBPAM -static char *cups_crypt(const char *pw, const char *salt); -#endif /* !HAVE_LIBPAM */ static void free_authmask(cupsd_authmask_t *am, void *data); #if HAVE_LIBPAM static int pam_func(int, const struct pam_message **, @@ -694,14 +691,14 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * client... */ - pass = cups_crypt(password, pw->pw_passwd); + pass = crypt(password, pw->pw_passwd); if (!pass || strcmp(pw->pw_passwd, pass)) { # ifdef HAVE_SHADOW_H if (spw) { - pass = cups_crypt(password, spw->sp_pwdp); + pass = crypt(password, spw->sp_pwdp); if (pass == NULL || strcmp(spw->sp_pwdp, pass)) { @@ -1995,129 +1992,6 @@ copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */ } -#if !HAVE_LIBPAM -/* - * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms, - * as needed. - */ - -static char * /* O - Encrypted password */ -cups_crypt(const char *pw, /* I - Password string */ - const char *salt) /* I - Salt (key) string */ -{ - if (!strncmp(salt, "$1$", 3)) - { - /* - * Use MD5 passwords without the benefit of PAM; this is for - * Slackware Linux, and the algorithm was taken from the - * old shadow-19990827/lib/md5crypt.c source code... :( - */ - - int i; /* Looping var */ - unsigned long n; /* Output number */ - int pwlen; /* Length of password string */ - const char *salt_end; /* End of "salt" data for MD5 */ - char *ptr; /* Pointer into result string */ - _cups_md5_state_t state; /* Primary MD5 state info */ - _cups_md5_state_t state2; /* Secondary MD5 state info */ - unsigned char digest[16]; /* MD5 digest result */ - static char result[120]; /* Final password string */ - - - /* - * Get the salt data between dollar signs, e.g. $1$saltdata$md5. - * Get a maximum of 8 characters of salt data after $1$... - */ - - for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++) - if (*salt_end == '$') - break; - - /* - * Compute the MD5 sum we need... - */ - - pwlen = strlen(pw); - - _cupsMD5Init(&state); - _cupsMD5Append(&state, (unsigned char *)pw, pwlen); - _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt); - - _cupsMD5Init(&state2); - _cupsMD5Append(&state2, (unsigned char *)pw, pwlen); - _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3); - _cupsMD5Append(&state2, (unsigned char *)pw, pwlen); - _cupsMD5Finish(&state2, digest); - - for (i = pwlen; i > 0; i -= 16) - _cupsMD5Append(&state, digest, i > 16 ? 16 : i); - - for (i = pwlen; i > 0; i >>= 1) - _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1); - - _cupsMD5Finish(&state, digest); - - for (i = 0; i < 1000; i ++) - { - _cupsMD5Init(&state); - - if (i & 1) - _cupsMD5Append(&state, (unsigned char *)pw, pwlen); - else - _cupsMD5Append(&state, digest, 16); - - if (i % 3) - _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3); - - if (i % 7) - _cupsMD5Append(&state, (unsigned char *)pw, pwlen); - - if (i & 1) - _cupsMD5Append(&state, digest, 16); - else - _cupsMD5Append(&state, (unsigned char *)pw, pwlen); - - _cupsMD5Finish(&state, digest); - } - - /* - * Copy the final sum to the result string and return... - */ - - memcpy(result, salt, (size_t)(salt_end - salt)); - ptr = result + (salt_end - salt); - *ptr++ = '$'; - - for (i = 0; i < 5; i ++, ptr += 4) - { - n = ((((unsigned)digest[i] << 8) | (unsigned)digest[i + 6]) << 8); - - if (i < 4) - n |= (unsigned)digest[i + 12]; - else - n |= (unsigned)digest[5]; - - to64(ptr, n, 4); - } - - to64(ptr, (unsigned)digest[11], 2); - ptr += 2; - *ptr = '\0'; - - return (result); - } - else - { - /* - * Use the standard crypt() function... - */ - - return (crypt(pw, salt)); - } -} -#endif /* !HAVE_LIBPAM */ - - /* * 'free_authmask()' - Free function for auth masks. */ diff --git a/scheduler/client.c b/scheduler/client.c index c36c1d2..0719700 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,8 +1,8 @@ /* * Client routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. @@ -818,6 +818,18 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (status == HTTP_STATUS_OK) { + /* + * Record whether the client is a web browser. "Mozilla" was the original + * and it seems that every web browser in existence now uses that as the + * prefix with additional information identifying *which* browser. + * + * Chrome (at least) has problems with multiple WWW-Authenticate values in + * a single header, so we only report Basic or Negotiate to web browsers and + * leave the multiple choices to the native CUPS client... + */ + + con->is_browser = !strncmp(httpGetField(con->http, HTTP_FIELD_USER_AGENT), "Mozilla/", 8); + if (httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE)[0]) { /* @@ -2350,18 +2362,20 @@ cupsdSendHeader( auth_str[0] = '\0'; if (auth_type == CUPSD_AUTH_BASIC) + { strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str)); + } else if (auth_type == CUPSD_AUTH_NEGOTIATE) { -#ifdef AF_LOCAL +#if defined(SO_PEERCRED) && defined(AF_LOCAL) if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) - strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str)); + strlcpy(auth_str, "PeerCred", sizeof(auth_str)); else -#endif /* AF_LOCAL */ +#endif /* SO_PEERCRED && AF_LOCAL */ strlcpy(auth_str, "Negotiate", sizeof(auth_str)); } - if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE && + if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE && !con->is_browser && !_cups_strcasecmp(httpGetHostname(con->http, NULL, 0), "localhost")) { /* diff --git a/scheduler/client.h b/scheduler/client.h index b26d04c..beddab0 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -1,8 +1,8 @@ /* * Client definitions for the CUPS scheduler. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -30,6 +30,7 @@ struct cupsd_client_s struct timeval start; /* Request start time */ http_state_t operation; /* Request operation */ off_t bytes; /* Bytes transferred for this request */ + int is_browser; /* Is the client a web browser? */ int type; /* AuthType for username */ char username[HTTP_MAX_VALUE], /* Username from Authorization: line */ diff --git a/scheduler/conf.c b/scheduler/conf.c index 8c2694f..9c1be70 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1,8 +1,8 @@ /* * Configuration routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -1481,13 +1481,25 @@ cupsdReadConfiguration(void) } } - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d", - cupsArrayCount(Policies)); - for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies); - p; - i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies)) - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadConfiguration: Policies[%d]=\"%s\"", i, p->name); + if (LogLevel >= CUPSD_LOG_DEBUG2) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d", + cupsArrayCount(Policies)); + for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies); + p; + i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies)) + { + int j; /* Looping var */ + cupsd_location_t *loc; /* Current location */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: Policies[%d]=\"%s\"", i, p->name); + + for (j = 0, loc = (cupsd_location_t *)cupsArrayFirst(p->ops); loc; j ++, loc = (cupsd_location_t *)cupsArrayNext(p->ops)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: ops[%d]=%s", j, ippOpString(loc->op)); + } + } + } /* * If we are doing a full reload or the server root has changed, flush @@ -2916,13 +2928,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ /* Line from file */ temp[HTTP_MAX_BUFFER], /* Temporary buffer for value */ - *value, /* Pointer to value */ - *valueptr; /* Pointer into value */ + *value; /* Pointer to value */ int valuelen; /* Length of value */ http_addrlist_t *addrlist, /* Address list */ *addr; /* Current address */ - cups_file_t *incfile; /* Include file */ - char incname[1024]; /* Include filename */ /* @@ -2937,28 +2946,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ * Decode the directive... */ - if (!_cups_strcasecmp(line, "Include") && value) - { - /* - * Include filename - */ - - if (value[0] == '/') - strlcpy(incname, value, sizeof(incname)); - else - snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value); - - if ((incfile = cupsFileOpen(incname, "rb")) == NULL) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to include config file \"%s\" - %s", - incname, strerror(errno)); - else - { - read_cupsd_conf(incfile); - cupsFileClose(incfile); - } - } - else if (!_cups_strcasecmp(line, "<Location") && value) + if (!_cups_strcasecmp(line, "<Location") && value) { /* * <Location path> @@ -3354,31 +3342,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d of %s.", value, linenum, ConfigurationFile); } - else if (!_cups_strcasecmp(line, "PassEnv") && value) - { - /* - * PassEnv variable [... variable] - */ - - for (; *value;) - { - for (valuelen = 0; value[valuelen]; valuelen ++) - if (_cups_isspace(value[valuelen]) || value[valuelen] == ',') - break; - - if (value[valuelen]) - { - value[valuelen] = '\0'; - valuelen ++; - } - - cupsdSetEnv(value, NULL); - - for (value += valuelen; *value; value ++) - if (!_cups_isspace(*value) || *value != ',') - break; - } - } else if (!_cups_strcasecmp(line, "ServerAlias") && value) { /* @@ -3407,30 +3370,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ break; } } - else if (!_cups_strcasecmp(line, "SetEnv") && value) - { - /* - * SetEnv variable value - */ - - for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); - - if (*valueptr) - { - /* - * Found a value... - */ - - while (isspace(*valueptr & 255)) - *valueptr++ = '\0'; - - cupsdSetEnv(value, valueptr); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing value for SetEnv directive on line %d of %s.", - linenum, ConfigurationFile); - } else if (!_cups_strcasecmp(line, "AccessLog") || !_cups_strcasecmp(line, "CacheDir") || !_cups_strcasecmp(line, "ConfigFilePerm") || @@ -3444,6 +3383,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ !_cups_strcasecmp(line, "LogFilePerm") || !_cups_strcasecmp(line, "LPDConfigFile") || !_cups_strcasecmp(line, "PageLog") || + !_cups_strcasecmp(line, "PassEnv") || !_cups_strcasecmp(line, "Printcap") || !_cups_strcasecmp(line, "PrintcapFormat") || !_cups_strcasecmp(line, "RemoteRoot") || @@ -3453,6 +3393,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ !_cups_strcasecmp(line, "ServerKey") || !_cups_strcasecmp(line, "ServerKeychain") || !_cups_strcasecmp(line, "ServerRoot") || + !_cups_strcasecmp(line, "SetEnv") || !_cups_strcasecmp(line, "SMBConfigFile") || !_cups_strcasecmp(line, "StateDir") || !_cups_strcasecmp(line, "SystemGroup") || @@ -3482,10 +3423,49 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ static int /* O - 1 on success, 0 on failure */ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */ { - int linenum; /* Current line number */ + int i, /* Looping var */ + linenum; /* Current line number */ char line[HTTP_MAX_BUFFER], /* Line from file */ *value; /* Value from line */ struct group *group; /* Group */ + static const char * const prohibited_env[] = + { /* Prohibited environment variables */ + "APPLE_LANGUAGE", + "AUTH_DOMAIN", + "AUTH_INFO_REQUIRED", + "AUTH_NEGOTIATE", + "AUTH_PASSWORD", + "AUTH_UID", + "AUTH_USERNAME", + "CHARSET", + "CLASS", + "CLASSIFICATION", + "CONTENT_TYPE", + "CUPS_CACHEDIR", + "CUPS_DATADIR", + "CUPS_DOCROOT", + "CUPS_FILETYPE", + "CUPS_FONTPATH", + "CUPS_MAX_MESSAGE", + "CUPS_REQUESTROOT", + "CUPS_SERVERBIN", + "CUPS_SERVERROOT", + "CUPS_STATEDIR", + "DEVICE_URI", + "FINAL_CONTENT_TYPE", + "HOME", + "LANG", + "PPD", + "PRINTER", + "PRINTER_INFO", + "PRINTER_LOCATION", + "PRINTER_STATE_REASONS", + "RIP_CACHE", + "SERVER_ADMIN", + "SOFTWARE", + "TMPDIR", + "USER" + }; /* @@ -3523,6 +3503,47 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */ } } } + else if (!_cups_strcasecmp(line, "PassEnv") && value) + { + /* + * PassEnv variable [... variable] + */ + + int valuelen; /* Length of variable name */ + + for (; *value;) + { + for (valuelen = 0; value[valuelen]; valuelen ++) + if (_cups_isspace(value[valuelen]) || value[valuelen] == ',') + break; + + if (value[valuelen]) + { + value[valuelen] = '\0'; + valuelen ++; + } + + for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++) + { + if (!strcmp(value, prohibited_env[i])) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be passed through on line %d of %s.", value, linenum, CupsFilesFile); + + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + else + break; + } + } + + if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0]))) + cupsdSetEnv(value, NULL); + + for (value += valuelen; *value; value ++) + if (!_cups_isspace(*value) || *value != ',') + break; + } + } else if (!_cups_strcasecmp(line, "PrintcapFormat") && value) { /* @@ -3568,6 +3589,46 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */ return (0); } } + else if (!_cups_strcasecmp(line, "SetEnv") && value) + { + /* + * SetEnv variable value + */ + + char *valueptr; /* Pointer to environment variable value */ + + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + { + /* + * Found a value... + */ + + while (isspace(*valueptr & 255)) + *valueptr++ = '\0'; + + for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++) + { + if (!strcmp(value, prohibited_env[i])) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be set on line %d of %s.", value, linenum, CupsFilesFile); + + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + else + break; + } + } + + if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0]))) + cupsdSetEnv(value, valueptr); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing value for SetEnv directive on line %d of %s.", + linenum, ConfigurationFile); + } else if (!_cups_strcasecmp(line, "SystemGroup") && value) { /* @@ -3853,11 +3914,9 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ if (num_ops < (int)(sizeof(ops) / sizeof(ops[0]))) { if (!_cups_strcasecmp(value, "All")) - ops[num_ops] = IPP_ANY_OPERATION; + ops[num_ops ++] = IPP_ANY_OPERATION; else if ((ops[num_ops] = ippOpValue(value)) == IPP_BAD_OPERATION) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Bad IPP operation name \"%s\" on line %d of %s.", - value, linenum, ConfigurationFile); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad IPP operation name \"%s\" on line %d of %s.", value, linenum, ConfigurationFile); else num_ops ++; } diff --git a/scheduler/ipp.c b/scheduler/ipp.c index ad8f1f0..d1c6a89 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,8 +1,8 @@ /* * IPP routines for the CUPS scheduler. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. @@ -150,6 +150,7 @@ cupsdProcessIPPRequest( ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */ ipp_attribute_t *username; /* requesting-user-name attr */ int sub_id; /* Subscription ID */ + int valid = 1; /* Valid request? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); @@ -183,34 +184,23 @@ cupsdProcessIPPRequest( con->response = ippNew(); - con->response->request.status.version[0] = - con->request->request.op.version[0]; - con->response->request.status.version[1] = - con->request->request.op.version[1]; - con->response->request.status.request_id = - con->request->request.op.request_id; + con->response->request.status.version[0] = con->request->request.op.version[0]; + con->response->request.status.version[1] = con->request->request.op.version[1]; + con->response->request.status.request_id = con->request->request.op.request_id; /* * Then validate the request header and required attributes... */ - if (con->request->request.any.version[0] != 1 && - con->request->request.any.version[0] != 2) + if (con->request->request.any.version[0] != 1 && con->request->request.any.version[0] != 2) { /* * Return an error, since we only support IPP 1.x and 2.x. */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Bad request version number %d.%d", - IPP_VERSION_NOT_SUPPORTED, con->http->hostname, - con->request->request.any.version[0], - con->request->request.any.version[1]); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request version number %d.%d.", IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, con->http->hostname, con->request->request.any.version[0], con->request->request.any.version[1]); - send_ipp_status(con, IPP_VERSION_NOT_SUPPORTED, - _("Bad request version number %d.%d."), - con->request->request.any.version[0], - con->request->request.any.version[1]); + send_ipp_status(con, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, _("Bad request version number %d.%d."), con->request->request.any.version[0], con->request->request.any.version[1]); } else if (con->request->request.any.request_id < 1) { @@ -218,21 +208,15 @@ cupsdProcessIPPRequest( * Return an error, since request IDs must be between 1 and 2^31-1 */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Bad request ID %d", - IPP_BAD_REQUEST, con->http->hostname, - con->request->request.any.request_id); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request ID %d.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname, con->request->request.any.request_id); - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad request ID %d."), - con->request->request.any.request_id); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Bad request ID %d."), con->request->request.any.request_id); } else if (!con->request->attrs) { - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s No attributes in request", - IPP_BAD_REQUEST, con->http->hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s No attributes in request.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); - send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request.")); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("No attributes in request.")); } else { @@ -250,13 +234,9 @@ cupsdProcessIPPRequest( * Out of order; return an error... */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Attribute groups are out of order", - IPP_BAD_REQUEST, con->http->hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Attribute groups are out of order", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); - send_ipp_status(con, IPP_BAD_REQUEST, - _("Attribute groups are out of order (%x < %x)."), - attr->group_tag, group); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute groups are out of order (%x < %x)."), attr->group_tag, group); break; } else @@ -273,9 +253,7 @@ cupsdProcessIPPRequest( */ attr = con->request->attrs; - if (attr && attr->name && - !strcmp(attr->name, "attributes-charset") && - (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET) + if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET) charset = attr; else charset = NULL; @@ -283,9 +261,7 @@ cupsdProcessIPPRequest( if (attr) attr = attr->next; - if (attr && attr->name && - !strcmp(attr->name, "attributes-natural-language") && - (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE) + if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE) { language = attr; @@ -303,11 +279,9 @@ cupsdProcessIPPRequest( else language = NULL; - if ((attr = ippFindAttribute(con->request, "printer-uri", - IPP_TAG_URI)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) != NULL) uri = attr; - else if ((attr = ippFindAttribute(con->request, "job-uri", - IPP_TAG_URI)) != NULL) + else if ((attr = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) != NULL) uri = attr; else if (con->request->request.op.operation_id == CUPS_GET_PPD) uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME); @@ -315,24 +289,16 @@ cupsdProcessIPPRequest( uri = NULL; if (charset) - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, - charset->values[0].string.text); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, charset->values[0].string.text); else - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, "utf-8"); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); if (language) - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, - language->values[0].string.text); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->values[0].string.text); else - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, DefaultLanguage); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, DefaultLanguage); - if (charset && - _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && - _cups_strcasecmp(charset->values[0].string.text, "utf-8")) + if (charset && _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && _cups_strcasecmp(charset->values[0].string.text, "utf-8")) { /* * Bad character set... @@ -340,13 +306,8 @@ cupsdProcessIPPRequest( cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"", charset->values[0].string.text); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Unsupported attributes-charset value \"%s\"", - IPP_CHARSET, con->http->hostname, - charset->values[0].string.text); - send_ipp_status(con, IPP_BAD_REQUEST, - _("Unsupported character set \"%s\"."), - charset->values[0].string.text); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Unsupported attributes-charset value \"%s\".", IPP_STATUS_ERROR_CHARSET, con->http->hostname, charset->values[0].string.text); + send_ipp_status(con, IPP_STATUS_ERROR_CHARSET, _("Unsupported character set \"%s\"."), charset->values[0].string.text); } else if (!charset || !language || (!uri && @@ -364,33 +325,24 @@ cupsdProcessIPPRequest( if (!charset) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing attributes-charset attribute"); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing attributes-charset attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing attributes-charset attribute", - IPP_BAD_REQUEST, con->http->hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-charset attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } if (!language) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing attributes-natural-language attribute"); + "Missing attributes-natural-language attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing attributes-natural-language attribute", - IPP_BAD_REQUEST, con->http->hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-natural-language attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } if (!uri) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing printer-uri, job-uri, or ppd-name " - "attribute"); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing printer-uri, job-uri, or ppd-name attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing printer-uri, job-uri, or ppd-name " - "attribute", IPP_BAD_REQUEST, con->http->hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing printer-uri, job-uri, or ppd-name attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow..."); @@ -409,20 +361,55 @@ cupsdProcessIPPRequest( else { /* - * OK, all the checks pass so far; make sure requesting-user-name is - * not "root" from a remote host... + * OK, all the checks pass so far; validate "requesting-user-name" + * attribute value... */ - if ((username = ippFindAttribute(con->request, "requesting-user-name", - IPP_TAG_NAME)) != NULL) - { - /* - * Check for root user... - */ - - if (!strcmp(username->values[0].string.text, "root") && - _cups_strcasecmp(con->http->hostname, "localhost") && - strcmp(con->username, "root")) + if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_ZERO)) != NULL) + { + /* + * Validate "requesting-user-name"... + */ + + if (username->group_tag != IPP_TAG_OPERATION && StrictConformance) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute in wrong group.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("\"requesting-user-name\" attribute in wrong group.")); + valid = 0; + } + else if (username->value_tag != IPP_TAG_NAME && username->value_tag != IPP_TAG_NAMELANG) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with wrong syntax.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname); + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax.")); + if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + valid = 0; + } + else if (!ippValidateAttribute(username)) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with bad value.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname); + + if (StrictConformance) + { + /* + * Throw an error... + */ + + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax.")); + if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + valid = 0; + } + else + { + /* + * Map bad "requesting-user-name" to 'anonymous'... + */ + + ippSetString(con->request, &username, 0, "anonymous"); + } + } + else if (!strcmp(username->values[0].string.text, "root") && _cups_strcasecmp(con->http->hostname, "localhost") && strcmp(con->username, "root")) { /* * Remote unauthenticated user masquerading as local root... @@ -432,215 +419,207 @@ cupsdProcessIPPRequest( } } - if ((attr = ippFindAttribute(con->request, "notify-subscription-id", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL) sub_id = attr->values[0].integer; else sub_id = 0; - /* - * Then try processing the operation... - */ - - if (uri) - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", - ippOpString(con->request->request.op.operation_id), - uri->values[0].string.text); - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", - ippOpString(con->request->request.op.operation_id)); - - switch (con->request->request.op.operation_id) - { - case IPP_OP_PRINT_JOB : - print_job(con, uri); - break; - - case IPP_OP_VALIDATE_JOB : - validate_job(con, uri); - break; - - case IPP_OP_CREATE_JOB : - create_job(con, uri); - break; - - case IPP_OP_SEND_DOCUMENT : - send_document(con, uri); - break; - - case IPP_OP_CANCEL_JOB : - cancel_job(con, uri); - break; - - case IPP_OP_GET_JOB_ATTRIBUTES : - get_job_attrs(con, uri); - break; - - case IPP_OP_GET_JOBS : - get_jobs(con, uri); - break; - - case IPP_OP_GET_PRINTER_ATTRIBUTES : - get_printer_attrs(con, uri); - break; - - case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : - get_printer_supported(con, uri); - break; - - case IPP_OP_HOLD_JOB : - hold_job(con, uri); - break; - - case IPP_OP_RELEASE_JOB : - release_job(con, uri); - break; - - case IPP_OP_RESTART_JOB : - restart_job(con, uri); - break; - - case IPP_OP_PAUSE_PRINTER : - stop_printer(con, uri); - break; - - case IPP_OP_RESUME_PRINTER : - start_printer(con, uri); - break; - - case IPP_OP_PURGE_JOBS : - case IPP_OP_CANCEL_JOBS : - case IPP_OP_CANCEL_MY_JOBS : - cancel_all_jobs(con, uri); - break; - - case IPP_OP_SET_JOB_ATTRIBUTES : - set_job_attrs(con, uri); - break; - - case IPP_OP_SET_PRINTER_ATTRIBUTES : - set_printer_attrs(con, uri); - break; - - case IPP_OP_HOLD_NEW_JOBS : - hold_new_jobs(con, uri); - break; - - case IPP_OP_RELEASE_HELD_NEW_JOBS : - release_held_new_jobs(con, uri); - break; - - case IPP_OP_CLOSE_JOB : - close_job(con, uri); - break; - - case IPP_OP_CUPS_GET_DEFAULT : - get_default(con); - break; - - case IPP_OP_CUPS_GET_PRINTERS : - get_printers(con, 0); - break; - - case IPP_OP_CUPS_GET_CLASSES : - get_printers(con, CUPS_PRINTER_CLASS); - break; - - case IPP_OP_CUPS_ADD_MODIFY_PRINTER : - add_printer(con, uri); - break; - - case IPP_OP_CUPS_DELETE_PRINTER : - delete_printer(con, uri); - break; - - case IPP_OP_CUPS_ADD_MODIFY_CLASS : - add_class(con, uri); - break; - - case IPP_OP_CUPS_DELETE_CLASS : - delete_printer(con, uri); - break; + if (valid) + { + /* + * Try processing the operation... + */ - case IPP_OP_CUPS_ACCEPT_JOBS : - case IPP_OP_ENABLE_PRINTER : - accept_jobs(con, uri); - break; + if (uri) + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", ippOpString(con->request->request.op.operation_id), uri->values[0].string.text); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", ippOpString(con->request->request.op.operation_id)); - case IPP_OP_CUPS_REJECT_JOBS : - case IPP_OP_DISABLE_PRINTER : - reject_jobs(con, uri); - break; + switch (con->request->request.op.operation_id) + { + case IPP_OP_PRINT_JOB : + print_job(con, uri); + break; + + case IPP_OP_VALIDATE_JOB : + validate_job(con, uri); + break; + + case IPP_OP_CREATE_JOB : + create_job(con, uri); + break; + + case IPP_OP_SEND_DOCUMENT : + send_document(con, uri); + break; + + case IPP_OP_CANCEL_JOB : + cancel_job(con, uri); + break; + + case IPP_OP_GET_JOB_ATTRIBUTES : + get_job_attrs(con, uri); + break; + + case IPP_OP_GET_JOBS : + get_jobs(con, uri); + break; + + case IPP_OP_GET_PRINTER_ATTRIBUTES : + get_printer_attrs(con, uri); + break; + + case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : + get_printer_supported(con, uri); + break; + + case IPP_OP_HOLD_JOB : + hold_job(con, uri); + break; + + case IPP_OP_RELEASE_JOB : + release_job(con, uri); + break; + + case IPP_OP_RESTART_JOB : + restart_job(con, uri); + break; + + case IPP_OP_PAUSE_PRINTER : + stop_printer(con, uri); + break; + + case IPP_OP_RESUME_PRINTER : + start_printer(con, uri); + break; + + case IPP_OP_PURGE_JOBS : + case IPP_OP_CANCEL_JOBS : + case IPP_OP_CANCEL_MY_JOBS : + cancel_all_jobs(con, uri); + break; + + case IPP_OP_SET_JOB_ATTRIBUTES : + set_job_attrs(con, uri); + break; + + case IPP_OP_SET_PRINTER_ATTRIBUTES : + set_printer_attrs(con, uri); + break; + + case IPP_OP_HOLD_NEW_JOBS : + hold_new_jobs(con, uri); + break; + + case IPP_OP_RELEASE_HELD_NEW_JOBS : + release_held_new_jobs(con, uri); + break; + + case IPP_OP_CLOSE_JOB : + close_job(con, uri); + break; + + case IPP_OP_CUPS_GET_DEFAULT : + get_default(con); + break; + + case IPP_OP_CUPS_GET_PRINTERS : + get_printers(con, 0); + break; + + case IPP_OP_CUPS_GET_CLASSES : + get_printers(con, CUPS_PRINTER_CLASS); + break; + + case IPP_OP_CUPS_ADD_MODIFY_PRINTER : + add_printer(con, uri); + break; + + case IPP_OP_CUPS_DELETE_PRINTER : + delete_printer(con, uri); + break; + + case IPP_OP_CUPS_ADD_MODIFY_CLASS : + add_class(con, uri); + break; + + case IPP_OP_CUPS_DELETE_CLASS : + delete_printer(con, uri); + break; + + case IPP_OP_CUPS_ACCEPT_JOBS : + case IPP_OP_ENABLE_PRINTER : + accept_jobs(con, uri); + break; + + case IPP_OP_CUPS_REJECT_JOBS : + case IPP_OP_DISABLE_PRINTER : + reject_jobs(con, uri); + break; - case IPP_OP_CUPS_SET_DEFAULT : - set_default(con, uri); - break; + case IPP_OP_CUPS_SET_DEFAULT : + set_default(con, uri); + break; - case IPP_OP_CUPS_GET_DEVICES : - get_devices(con); - break; + case IPP_OP_CUPS_GET_DEVICES : + get_devices(con); + break; - case IPP_OP_CUPS_GET_DOCUMENT : - get_document(con, uri); - break; + case IPP_OP_CUPS_GET_DOCUMENT : + get_document(con, uri); + break; - case IPP_OP_CUPS_GET_PPD : - get_ppd(con, uri); - break; + case IPP_OP_CUPS_GET_PPD : + get_ppd(con, uri); + break; - case IPP_OP_CUPS_GET_PPDS : - get_ppds(con); - break; + case IPP_OP_CUPS_GET_PPDS : + get_ppds(con); + break; - case IPP_OP_CUPS_MOVE_JOB : - move_job(con, uri); - break; + case IPP_OP_CUPS_MOVE_JOB : + move_job(con, uri); + break; - case IPP_OP_CUPS_AUTHENTICATE_JOB : - authenticate_job(con, uri); - break; + case IPP_OP_CUPS_AUTHENTICATE_JOB : + authenticate_job(con, uri); + break; - case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : - case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : - create_subscriptions(con, uri); - break; + case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : + case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : + create_subscriptions(con, uri); + break; + + case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : + get_subscription_attrs(con, sub_id); + break; + + case IPP_OP_GET_SUBSCRIPTIONS : + get_subscriptions(con, uri); + break; - case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : - get_subscription_attrs(con, sub_id); - break; + case IPP_OP_RENEW_SUBSCRIPTION : + renew_subscription(con, sub_id); + break; - case IPP_OP_GET_SUBSCRIPTIONS : - get_subscriptions(con, uri); - break; + case IPP_OP_CANCEL_SUBSCRIPTION : + cancel_subscription(con, sub_id); + break; - case IPP_OP_RENEW_SUBSCRIPTION : - renew_subscription(con, sub_id); - break; + case IPP_OP_GET_NOTIFICATIONS : + get_notifications(con); + break; - case IPP_OP_CANCEL_SUBSCRIPTION : - cancel_subscription(con, sub_id); - break; + case IPP_OP_CUPS_CREATE_LOCAL_PRINTER : + create_local_printer(con); + break; - case IPP_OP_GET_NOTIFICATIONS : - get_notifications(con); - break; + default : + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Operation %04X (%s) not supported.", IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, con->http->hostname, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); - case IPP_OP_CUPS_CREATE_LOCAL_PRINTER : - create_local_printer(con); - break; - - default : - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Operation %04X (%s) not supported", - IPP_OPERATION_NOT_SUPPORTED, con->http->hostname, - con->request->request.op.operation_id, - ippOpString(con->request->request.op.operation_id)); - - send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED, - _("%s not supported."), - ippOpString( - con->request->request.op.operation_id)); - break; + send_ipp_status(con, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, _("%s not supported."), ippOpString(con->request->request.op.operation_id)); + break; + } } } } @@ -652,16 +631,7 @@ cupsdProcessIPPRequest( * Sending data from the scheduler... */ - cupsdLogMessage(con->response->request.status.status_code - >= IPP_BAD_REQUEST && - con->response->request.status.status_code - != IPP_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, - "[Client %d] Returning IPP %s for %s (%s) from %s", - con->number, - ippErrorString(con->response->request.status.status_code), - ippOpString(con->request->request.op.operation_id), - uri ? uri->values[0].string.text : "no URI", - con->http->hostname); + cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname); httpClearFields(con->http); @@ -676,10 +646,7 @@ cupsdProcessIPPRequest( if (con->http->version == HTTP_1_1) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Transfer-Encoding: chunked", - con->number); - + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked"); cupsdSetLength(con->http, 0); } else @@ -698,9 +665,7 @@ cupsdProcessIPPRequest( length += (size_t)fileinfo.st_size; } - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Content-Length: " CUPS_LLFMT, - con->number, CUPS_LLCAST length); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length); httpSetLength(con->http, length); } @@ -710,8 +675,7 @@ cupsdProcessIPPRequest( * Tell the caller the response header was sent successfully... */ - cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, - (cupsd_selfunc_t)cupsdWriteClient, con); + cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con); return (1); } @@ -1586,27 +1550,34 @@ add_job(cupsd_client_t *con, /* I - Client connection */ _("Bad job-name value: Wrong type or count.")); if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; - return (NULL); + + if (StrictConformance) + return (NULL); + + /* Don't use invalid attribute */ + ippDeleteAttribute(con->request, attr); + + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); } else if (!ippValidateAttribute(attr)) { send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"), cupsLastErrorString()); + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; - return (NULL); - } - attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME); + if (StrictConformance) + return (NULL); - if (attr && !ippValidateAttribute(attr)) - { - send_ipp_status(con, IPP_ATTRIBUTES, _("Bad requesting-user-name value: %s"), cupsLastErrorString()); - if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) - attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; - return (NULL); + /* Don't use invalid attribute */ + ippDeleteAttribute(con->request, attr); + + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); } + attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME); + if ((job = cupsdAddJob(priority, printer->name)) == NULL) { send_ipp_status(con, IPP_INTERNAL_ERROR, @@ -2062,7 +2033,7 @@ add_job_subscriptions( snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme); - if (access(notifier, X_OK)) + if (access(notifier, X_OK) || !strcmp(scheme, ".") || !strcmp(scheme, "..")) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("notify-recipient-uri URI \"%s\" uses unknown " @@ -5317,6 +5288,7 @@ create_local_bg_thread( ipp_t *request, /* Request to printer */ *response; /* Response from printer */ ipp_attribute_t *attr; /* Attribute in response */ + ipp_status_t status; /* Status code */ /* @@ -5349,12 +5321,35 @@ create_local_bg_thread( cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port); request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, 2, 0); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all"); response = cupsDoRequest(http, request, resource); + status = cupsLastError(); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString()); + + if (status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) + { + /* + * Try request using IPP/1.1, in case we are talking to an old CUPS server or + * printer... + */ + + ippDelete(response); - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s", printer->name, ippErrorString(cupsLastError())); + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Re-sending Get-Printer-Attributes request using IPP/1.1...", printer->name); + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, 1, 1); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all"); + + response = cupsDoRequest(http, request, resource); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: IPP/1.1 Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString()); + } // TODO: Grab printer icon file... httpClose(http); @@ -5365,6 +5360,8 @@ create_local_bg_thread( if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response)) { + _cupsRWLockWrite(&printer->lock); + if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL) cupsdSetString(&printer->info, ippGetString(attr, 0, NULL)); @@ -5374,6 +5371,8 @@ create_local_bg_thread( if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL) cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL)); + _cupsRWUnlock(&printer->lock); + if ((from = cupsFileOpen(fromppd, "r")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno)); @@ -5874,7 +5873,26 @@ create_subscriptions( } if (recipient) + { cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient); + + + if (!strncmp(recipient, "mailto:", 7) && user_data) + { + char temp[64]; /* Temporary string */ + + memcpy(temp, user_data->values[0].unknown.data, user_data->values[0].unknown.length); + temp[user_data->values[0].unknown.length] = '\0'; + + if (httpSeparateURI(HTTP_URI_CODING_ALL, temp, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_OK) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad notify-user-data \"%s\"."), temp); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES); + return; + } + } + } + if (pullmethod) cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod); cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease); @@ -7970,13 +7988,16 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ * Hold the job and return... */ - if ((attr = ippFindAttribute(con->request, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); - - if (attr) + if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) { - when = attr->values[0].string.text; + if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr)) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + when = ippGetString(attr, 0, NULL); cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, "Job job-hold-until value changed by user."); @@ -10340,7 +10361,39 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ continue; } - if (!strcmp(attr->name, "job-priority")) + if (!ippValidateAttribute(attr)) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad '%s' value."), attr->name); + ippCopyAttribute(con->response, attr, 0); + return; + } + + if (!strcmp(attr->name, "job-hold-until")) + { + const char *when = ippGetString(attr, 0, NULL); + /* job-hold-until value */ + + if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", when); + cupsdSetJobHoldUntil(job, when, 0); + + if (!strcmp(when, "no-hold")) + { + cupsdReleaseJob(job); + check_jobs = 1; + } + else + cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", username); + + event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; + } + else if (!strcmp(attr->name, "job-priority")) { /* * Change the job priority... @@ -10460,28 +10513,6 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ */ ippCopyAttribute(job->attrs, attr, 0); - - /* - * See if the job-name or job-hold-until is being changed. - */ - - if (!strcmp(attr->name, "job-hold-until")) - { - cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", - attr->values[0].string.text); - cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0); - - if (!strcmp(attr->values[0].string.text, "no-hold")) - { - cupsdReleaseJob(job); - check_jobs = 1; - } - else - cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, - "Job held by \"%s\".", username); - - event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; - } } else if (attr->value_tag == IPP_TAG_DELETEATTR) { @@ -11300,80 +11331,34 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ } /* + * Is the job-hold-until value valid? + */ + + if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL && ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr))) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + /* * Is the job-name valid? */ if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL) { - int bad_name = 0; /* Is the job-name value bad? */ - if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) || - name->num_values != 1) - { - bad_name = 1; - } - else - { - /* - * Validate that job-name conforms to RFC 5198 (Network Unicode) and - * IPP Everywhere requirements for "name" values... - */ - - const unsigned char *nameptr; /* Pointer into "job-name" attribute */ - - for (nameptr = (unsigned char *)name->values[0].string.text; - *nameptr; - nameptr ++) - { - if (*nameptr < ' ' && *nameptr != '\t') - break; - else if (*nameptr == 0x7f) - break; - else if ((*nameptr & 0xe0) == 0xc0) - { - if ((nameptr[1] & 0xc0) != 0x80) - break; - - nameptr ++; - } - else if ((*nameptr & 0xf0) == 0xe0) - { - if ((nameptr[1] & 0xc0) != 0x80 || - (nameptr[2] & 0xc0) != 0x80) - break; - - nameptr += 2; - } - else if ((*nameptr & 0xf8) == 0xf0) - { - if ((nameptr[1] & 0xc0) != 0x80 || - (nameptr[2] & 0xc0) != 0x80 || - (nameptr[3] & 0xc0) != 0x80) - break; - - nameptr += 3; - } - else if (*nameptr & 0x80) - break; - } - - if (*nameptr) - bad_name = 1; - } - - if (bad_name) + name->num_values != 1 || !ippValidateAttribute(name)) { if (StrictConformance) { - send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported 'job-name' value.")); + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-name' value.")); ippCopyAttribute(con->response, name, 0); return; } else { - cupsdLogMessage(CUPSD_LOG_WARN, - "Unsupported 'job-name' value, deleting from request."); + cupsdLogMessage(CUPSD_LOG_WARN, "Unsupported 'job-name' value, deleting from request."); ippDeleteAttribute(con->request, name); } } diff --git a/scheduler/job.c b/scheduler/job.c index 86e75e6..ed8267d 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,7 +1,7 @@ /* * Job management routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -4774,6 +4774,18 @@ start_job(cupsd_job_t *job, /* I - Job ID */ job->profile = cupsdCreateProfile(job->id, 0); job->bprofile = cupsdCreateProfile(job->id, 1); +#ifdef HAVE_SANDBOX_H + if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF) + { + /* + * Failure to create the sandbox profile means something really bad has + * happened and we need to shutdown immediately. + */ + + return; + } +#endif /* HAVE_SANDBOX_H */ + /* * Create the status pipes and buffer... */ diff --git a/scheduler/org.cups.cupsd.service.in b/scheduler/org.cups.cupsd.service.in index 50faa39..f2afa11 100644 --- a/scheduler/org.cups.cupsd.service.in +++ b/scheduler/org.cups.cupsd.service.in @@ -5,7 +5,7 @@ Documentation=man:cupsd(8) [Service] ExecStart=@sbindir@/cupsd -l Type=simple -Restart=always +Restart=on-failure [Install] Also=org.cups.cupsd.socket org.cups.cupsd.path diff --git a/scheduler/process.c b/scheduler/process.c index 5c01b4b..a09d498 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -1,7 +1,7 @@ /* * Process management routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -102,9 +102,13 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */ if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL) { + /* + * This should never happen, and is fatal when sandboxing is enabled. + */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking); - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to create security profile: %s", strerror(errno)); + kill(getpid(), SIGTERM); return (NULL); } @@ -201,10 +205,8 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */ " #\"^%s/\"" /* TempDir/... */ " #\"^%s$\"" /* CacheDir */ " #\"^%s/\"" /* CacheDir/... */ - " #\"^%s$\"" /* StateDir */ - " #\"^%s/\"" /* StateDir/... */ "))\n", - temp, temp, cache, cache, state, state); + temp, temp, cache, cache); /* Read common folders */ cupsFilePrintf(fp, "(allow file-read-data file-read-metadata\n" @@ -246,8 +248,10 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */ " #\"^%s/\"" /* ServerBin/... */ " #\"^%s$\"" /* ServerRoot */ " #\"^%s/\"" /* ServerRoot/... */ + " #\"^%s$\"" /* StateDir */ + " #\"^%s/\"" /* StateDir/... */ "))\n", - request, request, bin, bin, root, root); + request, request, bin, bin, root, root, state, state); if (Sandboxing == CUPSD_SANDBOXING_RELAXED) { /* Limited write access to /Library/Printers/... */ diff --git a/scheduler/server.c b/scheduler/server.c index d28cd4a..63fcf90 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -1,7 +1,7 @@ /* * Server start/stop routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -38,16 +38,28 @@ void cupsdStartServer(void) { /* - * Start color management (as needed)... + * Create the default security profile... */ - cupsdStartColor(); + DefaultProfile = cupsdCreateProfile(0, 1); + +#ifdef HAVE_SANDBOX_H + if (!DefaultProfile && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF) + { + /* + * Failure to create the sandbox profile means something really bad has + * happened and we need to shutdown immediately. + */ + + return; + } +#endif /* HAVE_SANDBOX_H */ /* - * Create the default security profile... + * Start color management (as needed)... */ - DefaultProfile = cupsdCreateProfile(0, 1); + cupsdStartColor(); /* * Startup all the networking stuff... |