static void send_document(cupsd_client_t *con, ipp_attribute_t *uri);
static void send_http_error(cupsd_client_t *con, http_status_t status,
cupsd_printer_t *printer);
-static void send_ipp_status(cupsd_client_t *con, ipp_status_t status,
- const char *message, ...)
- __attribute__((__format__(__printf__, 3, 4)));
+static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4);
static void set_default(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
*/
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 && attr->group_tag == IPP_TAG_OPERATION)
charset = attr;
else
charset = NULL;
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 && attr->group_tag == IPP_TAG_OPERATION)
{
language = attr;
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 && attr->group_tag == IPP_TAG_OPERATION)
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 && attr->group_tag == IPP_TAG_OPERATION)
uri = attr;
- else if (con->request->request.op.operation_id == CUPS_GET_PPD)
- uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME);
+ else if (con->request->request.op.operation_id == CUPS_GET_PPD && (attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
+ uri = attr;
else
uri = NULL;
host[HTTP_MAX_URI], /* Host portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
-
+ struct stat info; /* File information */
recipient = attr->values[0].string.text;
return;
}
- snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
- scheme);
- if (access(notifier, X_OK))
+ snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme);
+ if (access(notifier, X_OK) || stat(notifier, &info) || !S_ISREG(info.st_mode))
{
send_ipp_status(con, IPP_NOT_POSSIBLE,
_("notify-recipient-uri URI \"%s\" uses unknown "
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets);
if (job->name && (!ra || cupsArrayFind(ra, "job-name")))
- ippAddString(con->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_NAME), "job-name", NULL, job->name);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, job->name);
if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name")))
- ippAddString(con->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_NAME), "job-originating-user-name", NULL, job->username);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username);
if (!ra || cupsArrayFind(ra, "job-state"))
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
* and document-format attributes that may be provided by the client.
*/
+ _cupsRWLockRead(&printer->lock);
+
curtime = time(NULL);
if (!ra || cupsArrayFind(ra, "marker-change-time"))
};
if (printer->type & CUPS_PRINTER_CLASS)
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", NULL, "retry-current-job");
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", NULL, "retry-current-job");
else
- ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors);
+ ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors);
}
if (!ra || cupsArrayFind(ra, "printer-icons"))
if (printer->ppd_attrs)
copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
+
+ _cupsRWUnlock(&printer->lock);
}
* Simple event list...
*/
- ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
- (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
- "notify-events", NULL, name);
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", NULL, name);
}
else
{
if (sub->mask & mask)
count ++;
- attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
- (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
- "notify-events", count, NULL, NULL);
+ attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", count, NULL, NULL);
for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
if (sub->mask & mask)
{
- attr->values[count].string.text =
- (char *)cupsdEventName((cupsd_eventmask_t)mask);
+ attr->values[count].string.text = (char *)cupsdEventName((cupsd_eventmask_t)mask);
count ++;
}
ipp_t *request, /* Request to printer */
*response; /* Response from printer */
ipp_attribute_t *attr; /* Attribute in response */
+ ipp_status_t status; /* Status code */
/*
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: 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");
- cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s", printer->name, ippErrorString(cupsLastError()));
+ 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);
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));
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));
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 "
}
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, (size_t)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);
* 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.");
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...
*/
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)
{
}
}
+ /*
+ * 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);
}
}