/*
- * "$Id$"
+ * "$Id: ipp.c 6508 2007-05-03 20:07:14Z mike $"
*
* IPP routines for the Common UNIX Printing System (CUPS) scheduler.
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
*
* These coded instructions, statements, and computer programs are the
* property of Easy Software Products and are protected by Federal
* get_job_attrs() - Get job attributes.
* get_jobs() - Get a list of jobs for the specified printer.
* get_notifications() - Get events for a subscription.
+ * get_ppd() - Get a named PPD from the local system.
* get_ppds() - Get the list of PPD files on the local
* system.
* get_printer_attrs() - Get printer attributes.
* get_username() - Get the username associated with a request.
* hold_job() - Hold a print job.
* move_job() - Move a job to a new destination.
- * ppd_add_default() - Add a PPD default choice.
* ppd_parse_line() - Parse a PPD default line.
* print_job() - Print a file to a printer or class.
* read_ps_line() - Read a line from a PS file...
* release_job() - Release a held print job.
* restart_job() - Restart an old print job.
* save_auth_info() - Save authentication information for a job.
+ * save_krb5_creds() - Save Kerberos credentials for a job.
* send_document() - Send a file to a printer or class.
* send_http_error() - Send a HTTP error back to the IPP client.
* send_ipp_status() - Send a status back to the IPP client.
* start_printer() - Start a printer.
* stop_printer() - Stop a printer.
* url_encode_attr() - URL-encode a string attribute.
+ * url_encode_string() - URL-encode a string.
* user_allowed() - See if a user is allowed to print to a queue.
* validate_job() - Validate printer options and destination.
* validate_name() - Make sure the printer name only contains
#include "cupsd.h"
+#ifdef HAVE_KRB5_H
+# include <krb5.h>
+#endif /* HAVE_KRB5_H */
+
#ifdef HAVE_LIBPAPER
# include <paper.h>
#endif /* HAVE_LIBPAPER */
-
-/*
- * PPD default choice structure...
- */
-
-typedef struct
-{
- char option[PPD_MAX_NAME]; /* Main keyword (option name) */
- char choice[PPD_MAX_NAME]; /* Option keyword (choice name) */
-} ppd_default_t;
+#ifdef __APPLE__
+# ifdef HAVE_MEMBERSHIP_H
+# include <membership.h>
+# endif /* HAVE_MEMBERSHIP_H */
+# ifdef HAVE_MEMBERSHIPPRIV_H
+# include <membershipPriv.h>
+# else
+extern int mbr_user_name_to_uuid(const char* name, uuid_t uu);
+extern int mbr_group_name_to_uuid(const char* name, uuid_t uu);
+extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
+# endif /* HAVE_MEMBERSHIPPRIV_H */
+#endif /* __APPLE__ */
/*
static void get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_notifications(cupsd_client_t *con);
+static void get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_ppds(cupsd_client_t *con);
static void get_printers(cupsd_client_t *con, int type);
static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static const char *get_username(cupsd_client_t *con);
static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void move_job(cupsd_client_t *con, ipp_attribute_t *uri);
-static int ppd_add_default(const char *option, const char *choice,
- int num_defaults, ppd_default_t **defaults);
static int ppd_parse_line(const char *line, char *option, int olen,
char *choice, int clen);
static void print_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void release_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void renew_subscription(cupsd_client_t *con, int sub_id);
static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
-static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job);
+static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job,
+ ipp_attribute_t *auth_info);
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
+static void save_krb5_creds(cupsd_client_t *con, cupsd_job_t *job);
+#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
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);
+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, ...)
# ifdef __GNUC__
static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
static void url_encode_attr(ipp_attribute_t *attr, char *buffer,
int bufsize);
+static char *url_encode_string(const char *s, char *buffer, int bufsize);
static int user_allowed(cupsd_printer_t *p, const char *username);
static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
static int validate_name(const char *name);
/*
* Then validate the request header and required attributes...
*/
-
+
if (con->request->request.any.version[0] != 1)
{
/*
_("Bad request version number %d.%d!"),
con->request->request.any.version[0],
con->request->request.any.version[1]);
- }
+ }
else if (!con->request->attrs)
{
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, 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);
else
uri = NULL;
if (!uri)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing printer-uri or job-uri attribute!");
+ "Missing printer-uri, job-uri, or ppd-name "
+ "attribute!");
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
- "%04X %s Missing printer-uri or job-uri attribute",
- IPP_BAD_REQUEST, con->http.hostname);
+ "%04X %s Missing printer-uri, job-uri, or ppd-name "
+ "attribute", IPP_BAD_REQUEST, con->http.hostname);
}
cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
for (attr = con->request->attrs; attr; attr = attr->next)
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
"attr \"%s\": group_tag = %x, value_tag = %x",
attr->name ? attr->name : "(null)", attr->group_tag,
attr->value_tag);
get_devices(con);
break;
+ case CUPS_GET_PPD :
+ get_ppd(con, uri);
+ break;
+
case CUPS_GET_PPDS :
get_ppds(con);
break;
con->http.fd, con->response->request.status.status_code,
ippErrorString(con->response->request.status.status_code));
- if (cupsdSendHeader(con, HTTP_OK, "application/ipp"))
+ if (cupsdSendHeader(con, HTTP_OK, "application/ipp", AUTH_NONE))
{
#ifdef CUPSD_USE_CHUNKING
/*
* Because older versions of CUPS (1.1.17 and older) and some IPP
- * clients do not implement chunking properly, we should not use
+ * clients do not implement chunking properly, we cannot use
* chunking by default. This may become the default in future
* CUPS releases, or we might add a configuration directive for
* it.
if (con->http.version == HTTP_1_1)
{
- con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+ if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n") < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
- httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n");
+ con->http.data_encoding = HTTP_ENCODE_CHUNKED;
}
else
#endif /* CUPSD_USE_CHUNKING */
{
+ size_t length; /* Length of response */
+
+
+ length = ippLength(con->response);
+
+ if (con->file >= 0 && !con->pipe_pid)
+ {
+ struct stat fileinfo; /* File information */
+
+
+ if (!fstat(con->file, &fileinfo))
+ length += fileinfo.st_size;
+ }
+
+ if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
+ CUPS_LLCAST length) < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
+
con->http.data_encoding = HTTP_ENCODE_LENGTH;
- con->http.data_remaining = ippLength(con->response);
+ con->http.data_remaining = length;
- if (con->http.data_remaining < INT_MAX)
+ if (con->http.data_remaining <= INT_MAX)
con->http._data_remaining = con->http.data_remaining;
else
con->http._data_remaining = INT_MAX;
-
- httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
- CUPS_LLCAST con->http.data_remaining);
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdProcessIPPRequest: Adding fd %d to OutputSet...",
- con->http.fd);
-
- FD_SET(con->http.fd, OutputSet);
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+ (cupsd_selfunc_t)cupsdWriteClient, con);
/*
* Tell the caller the response header was sent successfully...
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
IPP_TAG_BOOLEAN)) != NULL)
{
if (pclass->shared && !attr->values[0].boolean)
- cupsdSendBrowseDelete(pclass);
+ cupsdDeregisterPrinter(pclass, 1);
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-shared to %d (was %d.)",
if (!compressions || !filetypes)
{
- cupsdCancelJob(job, 1);
+ cupsdCancelJob(job, 1, IPP_JOB_ABORTED);
send_ipp_status(con, IPP_INTERNAL_ERROR,
_("Unable to allocate memory for file types!"));
mime_type_t *filetype) /* I - First print file type, if any */
{
http_status_t status; /* Policy status */
- ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *attr, /* Current attribute */
+ *auth_info; /* auth-info attribute */
const char *val; /* Default option value */
int priority; /* Job priority */
char *title; /* Job name/title */
* Check policy...
*/
+ auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
+
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return (NULL);
}
- else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && !con->username[0])
+ else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) &&
+ !con->username[0] && !auth_info)
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, printer);
return (NULL);
}
+#ifdef HAVE_SSL
+ else if (auth_info && !con->http.tls &&
+ !httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Require encryption of auth-info over non-local connections...
+ */
+
+ send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
+ return (NULL);
+ }
+#endif /* HAVE_SSL */
/*
* See if the printer is accepting jobs...
/*
* Validate job template attributes; for now just document-format,
- * copies, and page-ranges...
+ * copies, number-up, and page-ranges...
*/
if (filetype && printer->filetypes &&
}
}
+ if ((attr = ippFindAttribute(con->request, "number-up",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (attr->values[0].integer != 1 &&
+ attr->values[0].integer != 2 &&
+ attr->values[0].integer != 4 &&
+ attr->values[0].integer != 6 &&
+ attr->values[0].integer != 9 &&
+ attr->values[0].integer != 16)
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Bad number-up value %d."),
+ attr->values[0].integer);
+ ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
+ "number-up", attr->values[0].integer);
+ return (NULL);
+ }
+ }
+
if ((attr = ippFindAttribute(con->request, "page-ranges",
IPP_TAG_RANGE)) != NULL)
{
for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
{
- if (attr->values[i].range.lower < lowerpagerange ||
+ if (attr->values[i].range.lower < lowerpagerange ||
attr->values[i].range.lower > attr->values[i].range.upper)
{
send_ipp_status(con, IPP_BAD_REQUEST,
job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
CUPS_PRINTER_REMOTE);
job->attrs = con->request;
- con->request = NULL;
+ con->request = ippNewRequest(job->attrs->request.op.operation_id);
add_job_uuid(con, job);
apply_printer_defaults(printer, job);
if (attr)
cupsdSetString(&attr->values[0].string.text, con->username);
-
- save_auth_info(con, job);
}
else if (attr)
{
attr->name = _cupsStrAlloc("job-originating-user-name");
}
+ if (con->username[0] || auth_info)
+ {
+ save_auth_info(con, job, auth_info);
+
+ /*
+ * Remove the auth-info attribute from the attribute data...
+ */
+
+ if (auth_info)
+ {
+ if (job->attrs->prev)
+ job->attrs->prev->next = auth_info->next;
+ else
+ job->attrs->attrs = auth_info->next;
+
+ if (job->attrs->last == auth_info)
+ job->attrs->last = job->attrs->prev;
+
+ _ippFreeAttr(auth_info);
+ }
+ }
+
if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
IPP_TAG_ZERO)) != NULL)
{
* the connection...
*/
- ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
"job-originating-host-name", NULL, con->http.hostname);
}
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
"job-state", IPP_JOB_STOPPED);
- job->state_value = job->state->values[0].integer;
+ job->state_value = (ipp_jstate_t)job->state->values[0].integer;
job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
"job-media-sheets-completed", 0);
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)",
con, con->http.fd, job ? job->id : 0);
- switch (job ? job->state_value : IPP_JOB_CANCELLED)
+ switch (job ? job->state_value : IPP_JOB_CANCELED)
{
case IPP_JOB_PENDING :
dest = cupsdFindDest(job->dest);
"job-state-reasons", NULL, "job-stopped");
break;
- case IPP_JOB_CANCELLED :
+ case IPP_JOB_CANCELED :
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-state-reasons", NULL, "job-canceled-by-user");
break;
while (attr && attr->group_tag != IPP_TAG_ZERO)
{
- if (!strcmp(attr->name, "notify-recipient") &&
+ if (!strcmp(attr->name, "notify-recipient-uri") &&
attr->value_tag == IPP_TAG_URI)
recipient = attr->values[0].string.text;
else if (!strcmp(attr->name, "notify-pull-method") &&
cupsd_job_t *job) /* I - Job */
{
char uuid[1024]; /* job-uuid string */
- ipp_attribute_t *attr; /* job-uuid attribute */
_cups_md5_state_t md5state; /* MD5 state */
unsigned char md5sum[16]; /* MD5 digest/sum */
* First see if the job already has a job-uuid attribute; if so, return...
*/
- if ((attr = ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI)) != NULL)
+ if (ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI))
return;
/*
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
IPP_TAG_BOOLEAN)) != NULL)
{
if (printer->shared && !attr->values[0].boolean)
- cupsdSendBrowseDelete(printer);
+ cupsdDeregisterPrinter(printer, 1);
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-shared to %d (was %d.)",
int i, /* Looping var */
num_options; /* Number of default options */
cups_option_t *options, /* Default options */
- *option; /* Current option */
+ *option; /* Current option */
/*
authenticate_job(cupsd_client_t *con, /* I - Client connection */
ipp_attribute_t *uri) /* I - Job URI */
{
- ipp_attribute_t *attr; /* Job-id attribute */
+ ipp_attribute_t *attr, /* job-id attribute */
+ *auth_info; /* auth-info attribute */
int jobid; /* Job ID */
cupsd_job_t *job; /* Current job */
char method[HTTP_MAX_URI],
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
sizeof(method), username, sizeof(username), host,
sizeof(host), &port, resource, sizeof(resource));
-
+
if (strncmp(resource, "/jobs/", 6))
{
/*
* See if we have already authenticated...
*/
- if (!con->username[0])
+ auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
+
+ if (!con->username[0] && !auth_info)
{
send_ipp_status(con, IPP_NOT_AUTHORIZED,
_("No authentication information provided!"));
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
* Save the authentication information for this job...
*/
- save_auth_info(con, job);
+ save_auth_info(con, job, auth_info);
/*
* Reset the job-hold-until value to "no-hold"...
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
cupsdCancelJobs(NULL, username, purge);
cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
- purge ? "purged" : "cancelled", get_username(con));
+ purge ? "purged" : "canceled", get_username(con));
}
else
{
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
cupsdCancelJobs(printer->name, username, purge);
cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
- printer->name, purge ? "purged" : "cancelled",
+ printer->name, purge ? "purged" : "canceled",
get_username(con));
}
/*
* No, see if there are any pending jobs...
*/
-
+
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
job;
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
sizeof(scheme), username, sizeof(username), host,
sizeof(host), &port, resource, sizeof(resource));
-
+
if (strncmp(resource, "/jobs/", 6))
{
/*
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
/*
- * See if the job is already completed, cancelled, or aborted; if so,
+ * See if the job is already completed, canceled, or aborted; if so,
* we can't cancel...
*/
- if (job->state_value >= IPP_JOB_CANCELLED)
+ if (job->state_value >= IPP_JOB_CANCELED)
{
switch (job->state_value)
{
- case IPP_JOB_CANCELLED :
+ case IPP_JOB_CANCELED :
send_ipp_status(con, IPP_NOT_POSSIBLE,
- _("Job #%d is already cancelled - can\'t cancel."),
+ _("Job #%d is already canceled - can\'t cancel."),
jobid);
break;
* Cancel the job and return...
*/
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job cancelled by \"%s\".", username);
-
- cupsdCancelJob(job, 0);
+ cupsdCancelJob(job, 0, IPP_JOB_CANCELED);
cupsdCheckJobs();
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was cancelled by \"%s\".", jobid,
+ cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was canceled by \"%s\".", jobid,
username);
con->response->request.status.status_code = IPP_OK;
DefaultPolicyPtr,
con, sub->owner)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, sub->dest);
return;
}
int i; /* Looping var */
char username[33]; /* Username */
cupsd_quota_t *q; /* Quota data */
+#ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * Use Apple membership APIs which require that all names represent
+ * valid user account or group records accessible by the server.
+ */
+
+ uuid_t usr_uuid; /* UUID for job requesting user */
+ uuid_t usr2_uuid; /* UUID for ACL user name entry */
+ uuid_t grp_uuid; /* UUID for ACL group name entry */
+ int mbr_err; /* Error from membership function */
+ int is_member; /* Is this user a member? */
+#else
+ /*
+ * Use standard POSIX APIs for checking users and groups...
+ */
+
struct passwd *pw; /* User password data */
+#endif /* HAVE_MBR_UID_TO_UUID */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])",
if (p->num_users)
{
+#ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * Get UUID for job requesting user...
+ */
+
+ if (mbr_user_name_to_uuid((char *)username, usr_uuid))
+ {
+ /*
+ * Unknown user...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for user \"%s\"",
+ username);
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Denying user \"%s\" access to printer \"%s\" "
+ "(unknown user)...",
+ username, p->name);
+ return (0);
+ }
+#else
+ /*
+ * Get UID and GID of requesting user...
+ */
+
pw = getpwnam(username);
endpwent();
+#endif /* HAVE_MBR_UID_TO_UUID */
for (i = 0; i < p->num_users; i ++)
if (p->users[i][0] == '@')
* Check group membership...
*/
+#ifdef HAVE_MBR_UID_TO_UUID
+ if ((mbr_err = mbr_group_name_to_uuid((char *)p->users[i] + 1,
+ grp_uuid)) != 0)
+ {
+ /*
+ * Invalid ACL entries are ignored for matching; just record a
+ * warning in the log...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for ACL entry "
+ "\"%s\" (err=%d)", p->users[i], mbr_err);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Access control entry \"%s\" not a valid group name; "
+ "entry ignored", p->users[i]);
+ }
+ else
+ {
+ if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid,
+ &is_member)) != 0)
+ {
+ /*
+ * At this point, there should be no errors, but check anyways...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: group \"%s\" membership check "
+ "failed (err=%d)", p->users[i] + 1, mbr_err);
+ is_member = 0;
+ }
+
+ /*
+ * Stop if we found a match...
+ */
+
+ if (is_member)
+ break;
+ }
+#else
if (cupsdCheckGroup(username, pw, p->users[i] + 1))
break;
+#endif /* HAVE_MBR_UID_TO_UUID */
+ }
+#ifdef HAVE_MBR_UID_TO_UUID
+ else
+ {
+ if ((mbr_err = mbr_user_name_to_uuid((char *)p->users[i],
+ usr2_uuid)) != 0)
+ {
+ /*
+ * Invalid ACL entries are ignored for matching; just record a
+ * warning in the log...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for ACL entry "
+ "\"%s\" (err=%d)", p->users[i], mbr_err);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Access control entry \"%s\" not a valid user name; "
+ "entry ignored", p->users[i]);
+ }
+ else
+ {
+ if ((mbr_err = mbr_check_membership(usr_uuid, usr2_uuid,
+ &is_member)) != 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: User \"%s\" identity check failed "
+ "(err=%d)", p->users[i], mbr_err);
+ is_member = 0;
+ }
+
+ if (is_member)
+ break;
+ }
}
+#else
else if (!strcasecmp(username, p->users[i]))
break;
+#endif /* HAVE_MBR_UID_TO_UUID */
if ((i < p->num_users) == p->deny_users)
{
* Check quotas...
*/
+#ifdef __APPLE__
+ if (AppleQuotas)
+ {
+ /*
+ * TODO: Define these special page count values as constants!
+ */
+
+ if (q->page_count == -4) /* special case: unlimited user */
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "User \"%s\" request approved for printer %s (%s): "
+ "unlimited quota.",
+ username, p->name, p->info);
+ q->page_count = 0; /* allow user to print */
+ return (1);
+ }
+ else if (q->page_count == -3) /* quota exceeded */
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "User \"%s\" request denied for printer %s (%s): "
+ "quota limit exceeded.",
+ username, p->name, p->info);
+ q->page_count = 2; /* force quota exceeded failure */
+ return (0);
+ }
+ else if (q->page_count == -2) /* quota disabled for user */
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "User \"%s\" request denied for printer %s (%s): "
+ "printing disabled for user.",
+ username, p->name, p->info);
+ q->page_count = 2; /* force quota exceeded failure */
+ return (0);
+ }
+ else if (q->page_count == -1) /* quota access error */
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "User \"%s\" request denied for printer %s (%s): "
+ "unable to determine quota limit.",
+ username, p->name, p->info);
+ q->page_count = 2; /* force quota exceeded failure */
+ return (0);
+ }
+ else if (q->page_count < 0) /* user not found or other error */
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "User \"%s\" request denied for printer %s (%s): "
+ "user disabled / missing quota.",
+ username, p->name, p->info);
+ q->page_count = 2; /* force quota exceeded failure */
+ return (0);
+ }
+ else /* page within user limits */
+ {
+ q->page_count = 0; /* allow user to print */
+ return (1);
+ }
+ }
+ else
+#endif /* __APPLE__ */
if (p->k_limit || p->page_limit)
{
if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL)
* Filter attributes as needed...
*/
- if (group != IPP_TAG_ZERO && fromattr->group_tag != group &&
- fromattr->group_tag != IPP_TAG_ZERO && !fromattr->name)
+ if ((group != IPP_TAG_ZERO && fromattr->group_tag != group &&
+ fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
continue;
if (!ra || cupsArrayFind(ra, fromattr->name))
const char *from, /* I - Source file */
const char *to) /* I - Destination file */
{
- fd_set *input; /* select() input set */
+ fd_set input; /* select() input set */
struct timeval timeout; /* select() timeout */
int maxfd; /* Maximum file descriptor for select() */
char tempfile[1024]; /* Temporary PPD file */
*envp[MAX_ENV]; /* Environment */
cups_file_t *src, /* Source file */
*dst; /* Destination file */
+ ppd_file_t *ppd; /* PPD file */
int bytes, /* Bytes from pipe */
total; /* Total bytes from pipe */
- char buffer[2048], /* Copy buffer */
- *ptr; /* Pointer into buffer */
+ char buffer[2048]; /* Copy buffer */
int i; /* Looping var */
char option[PPD_MAX_NAME], /* Option name */
choice[PPD_MAX_NAME]; /* Choice name */
int num_defaults; /* Number of default options */
- ppd_default_t *defaults; /* Default options */
+ cups_option_t *defaults; /* Default options */
char cups_protocol[PPD_MAX_LINE];
/* cupsProtocol attribute */
int have_letter, /* Have Letter size */
cupsdOpenPipe(temppipe);
- if ((input = calloc(1, SetSize)) == NULL)
- {
- close(tempfd);
- unlink(tempfile);
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "copy_model: Unable to allocate %d bytes for select()...",
- SetSize);
- return (-1);
- }
-
cupsdLogMessage(CUPSD_LOG_DEBUG,
"copy_model: Running \"cups-driverd cat %s\"...", from);
if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
- -1, 0, &temppid))
+ -1, -1, 0, &temppid))
{
- free(input);
close(tempfd);
unlink(tempfile);
return (-1);
bytes = 0;
- FD_SET(temppipe[0], input);
- FD_SET(CGIPipes[0], input);
+ FD_ZERO(&input);
+ FD_SET(temppipe[0], &input);
+ FD_SET(CGIPipes[0], &input);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
- if ((i = select(maxfd, input, NULL, NULL, &timeout)) < 0)
+ if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
{
if (errno == EINTR)
continue;
break;
}
- if (FD_ISSET(temppipe[0], input))
+ if (FD_ISSET(temppipe[0], &input))
{
/*
* Read the PPD file from the pipe, and write it to the PPD file.
break;
}
- if (FD_ISSET(CGIPipes[0], input))
+ if (FD_ISSET(CGIPipes[0], &input))
cupsdUpdateCGI();
}
close(temppipe[0]);
close(tempfd);
- free(input);
-
if (!total)
{
/*
* Read the source file and see what page sizes are supported...
*/
- if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
+ if ((ppd = ppdOpenFile(tempfile)) == NULL)
{
unlink(tempfile);
return (-1);
}
- have_letter = 0;
- have_a4 = 0;
-
- while (cupsFileGets(src, buffer, sizeof(buffer)))
- if (!strncmp(buffer, "*PageSize ", 10))
- {
- /*
- * Strip UI text and command data from the end of the line...
- */
-
- if ((ptr = strchr(buffer + 10, '/')) != NULL)
- *ptr = '\0';
- if ((ptr = strchr(buffer + 10, ':')) != NULL)
- *ptr = '\0';
-
- for (ptr = buffer + 10; isspace(*ptr); ptr ++);
-
- /*
- * Look for Letter and A4 page sizes...
- */
-
- if (!strcmp(ptr, "Letter"))
- have_letter = 1;
-
- if (!strcmp(ptr, "A4"))
- have_a4 = 1;
- }
-
- cupsFileRewind(src);
+ have_letter = ppdPageSize(ppd, "Letter") != NULL;
+ have_a4 = ppdPageSize(ppd, "A4") != NULL;
/*
* Open the destination (if possible) and set the default options...
if (!ppd_parse_line(buffer, option, sizeof(option),
choice, sizeof(choice)))
- num_defaults = ppd_add_default(option, choice, num_defaults,
+ {
+ ppd_option_t *ppdo; /* PPD option */
+
+
+ /*
+ * Only add the default if the default hasn't already been
+ * set and the choice exists in the new PPD...
+ */
+
+ if (!cupsGetOption(option, num_defaults, defaults) &&
+ (ppdo = ppdFindOption(ppd, option)) != NULL &&
+ ppdFindChoice(ppdo, choice))
+ num_defaults = cupsAddOption(option, choice, num_defaults,
&defaults);
+ }
}
else if (!strncmp(buffer, "*cupsProtocol:", 14))
strlcpy(cups_protocol, buffer, sizeof(cups_protocol));
if ((!strcmp(system_paper, "Letter") && have_letter) ||
(!strcmp(system_paper, "A4") && have_a4))
{
- num_defaults = ppd_add_default("PageSize", system_paper,
- num_defaults, &defaults);
- num_defaults = ppd_add_default("PageRegion", system_paper,
- num_defaults, &defaults);
- num_defaults = ppd_add_default("PaperDimension", system_paper,
- num_defaults, &defaults);
- num_defaults = ppd_add_default("ImageableArea", system_paper,
- num_defaults, &defaults);
+ num_defaults = cupsAddOption("PageSize", system_paper,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("PageRegion", system_paper,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("PaperDimension", system_paper,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("ImageableArea", system_paper,
+ num_defaults, &defaults);
}
}
#endif /* HAVE_LIBPAPER */
!strcasecmp(DefaultLanguage, "C") ||
!strcasecmp(DefaultLanguage, "POSIX") ||
!strcasecmp(DefaultLanguage, "en") ||
+ !strncasecmp(DefaultLanguage, "en.", 3) ||
!strncasecmp(DefaultLanguage, "en_US", 5) ||
!strncasecmp(DefaultLanguage, "en_CA", 5) ||
!strncasecmp(DefaultLanguage, "fr_CA", 5))
if (have_letter)
{
- num_defaults = ppd_add_default("PageSize", "Letter", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("PageRegion", "Letter", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("PaperDimension", "Letter", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("ImageableArea", "Letter", num_defaults,
- &defaults);
+ num_defaults = cupsAddOption("PageSize", "Letter", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("PageRegion", "Letter", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("PaperDimension", "Letter", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("ImageableArea", "Letter", num_defaults,
+ &defaults);
}
}
else if (have_a4)
* The rest default to "a4" size...
*/
- num_defaults = ppd_add_default("PageSize", "A4", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("PageRegion", "A4", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("PaperDimension", "A4", num_defaults,
- &defaults);
- num_defaults = ppd_add_default("ImageableArea", "A4", num_defaults,
- &defaults);
+ num_defaults = cupsAddOption("PageSize", "A4", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("PageRegion", "A4", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("PaperDimension", "A4", num_defaults,
+ &defaults);
+ num_defaults = cupsAddOption("ImageableArea", "A4", num_defaults,
+ &defaults);
}
}
+ ppdClose(ppd);
+
+ /*
+ * Open the source file for a copy...
+ */
+
+ if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
+ {
+ cupsFreeOptions(num_defaults, defaults);
+ unlink(tempfile);
+ return (-1);
+ }
+
/*
* Open the destination file for a copy...
*/
if ((dst = cupsFileOpen(to, "wb")) == NULL)
{
- if (num_defaults > 0)
- free(defaults);
-
+ cupsFreeOptions(num_defaults, defaults);
cupsFileClose(src);
unlink(tempfile);
return (-1);
if (!ppd_parse_line(buffer, option, sizeof(option),
choice, sizeof(choice)))
{
- for (i = 0; i < num_defaults; i ++)
- if (!strcmp(option, defaults[i].option))
- {
- /*
- * Substitute the previous choice...
- */
+ const char *val; /* Default option value */
- snprintf(buffer, sizeof(buffer), "*Default%s: %s", option,
- defaults[i].choice);
- break;
- }
+
+ if ((val = cupsGetOption(option, num_defaults, defaults)) != NULL)
+ {
+ /*
+ * Substitute the previous choice...
+ */
+
+ snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, val);
+ }
}
}
if (cups_protocol[0])
cupsFilePrintf(dst, "%s\n", cups_protocol);
- if (num_defaults > 0)
- free(defaults);
+ cupsFreeOptions(num_defaults, defaults);
/*
* Close both files and return...
printer->recoverable);
#endif /* __APPLE__ */
+ if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert")))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING,
+ "printer-alert", NULL, printer->alert);
+
+ if (printer->alert_description &&
+ (!ra || cupsArrayFind(ra, "printer-alert-description")))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-alert-description", NULL,
+ printer->alert_description);
+
if (!ra || cupsArrayFind(ra, "printer-current-time"))
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
ippTimeToDate(curtime));
if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"printer-state-change-time", printer->state_time);
-
+
if (MaxPrinterHistory > 0 && printer->num_history > 0 &&
cupsArrayFind(ra, "printer-state-history"))
{
{
httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
"ipp", NULL, con->servername, con->serverport,
- "/printers/%s", printer->name);
+ (printer->type & CUPS_PRINTER_CLASS) ?
+ "/classes/%s" : "/printers/%s", printer->name);
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-uri-supported", NULL, printer_uri);
cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"",
*/
ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
- IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
"notify-events", NULL, name);
}
else
count ++;
attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
- IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
"notify-events", count, NULL, NULL);
for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
/*
* Save and log the job...
*/
-
+
cupsdSaveJob(job);
cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on \"%s\" by \"%s\".",
cupsArrayAdd(ra, "pages-per-minute");
cupsArrayAdd(ra, "pages-per-minute-color");
cupsArrayAdd(ra, "pdl-override-supported");
+ cupsArrayAdd(ra, "printer-alert");
+ cupsArrayAdd(ra, "printer-alert-description");
cupsArrayAdd(ra, "printer-current-time");
cupsArrayAdd(ra, "printer-driver-installer");
cupsArrayAdd(ra, "printer-info");
cupsArrayAdd(ra, "uri-authentication-supported");
cupsArrayAdd(ra, "uri-security-supported");
}
+ else if (!strcmp(value, "printer-defaults"))
+ {
+ char *name; /* Option name */
+
+
+ for (name = (char *)cupsArrayFirst(CommonDefaults);
+ name;
+ name = (char *)cupsArrayNext(CommonDefaults))
+ cupsArrayAdd(ra, name);
+ }
else if (!strcmp(value, "subscription-template"))
{
cupsArrayAdd(ra, "notify-attributes");
http_status_t status; /* Policy status */
int i; /* Looping var */
ipp_attribute_t *attr; /* Current attribute */
- const char *dest; /* Destination */
cups_ptype_t dtype; /* Destination type (printer or class) */
char scheme[HTTP_MAX_URI],
/* Scheme portion of URI */
int interval, /* notify-time-interval */
lease; /* notify-lease-duration */
unsigned mask; /* notify-events */
+ ipp_attribute_t *notify_events,/* notify-events(-default) */
+ *notify_lease; /* notify-lease-duration(-default) */
#ifdef DEBUG
if (!strcmp(resource, "/"))
{
- dest = NULL;
dtype = (cups_ptype_t)0;
printer = NULL;
}
else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
{
- dest = NULL;
dtype = (cups_ptype_t)0;
printer = NULL;
}
else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
{
- dest = NULL;
dtype = CUPS_PRINTER_CLASS;
printer = NULL;
}
- else if ((dest = cupsdValidateDest(uri->values[0].string.text, &dtype,
- &printer)) == NULL)
+ else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
{
/*
* Bad URI...
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
}
else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
jobid = 0;
mask = CUPSD_EVENT_NONE;
+ if (printer)
+ {
+ notify_events = ippFindAttribute(printer->attrs, "notify-events-default",
+ IPP_TAG_KEYWORD);
+ notify_lease = ippFindAttribute(printer->attrs,
+ "notify-lease-duration-default",
+ IPP_TAG_INTEGER);
+
+ if (notify_lease)
+ lease = notify_lease->values[0].integer;
+ }
+ else
+ {
+ notify_events = NULL;
+ notify_lease = NULL;
+ }
+
while (attr && attr->group_tag != IPP_TAG_ZERO)
{
- if (!strcmp(attr->name, "notify-recipient") &&
+ if (!strcmp(attr->name, "notify-recipient-uri") &&
attr->value_tag == IPP_TAG_URI)
{
/*
recipient = attr->values[0].string.text;
- if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient, scheme,
- sizeof(scheme), userpass, sizeof(userpass), host,
- sizeof(host), &port, resource, sizeof(resource)))
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
+ 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-recipient URI \"%s\"!"), recipient);
+ _("Bad notify-recipient-uri URI \"%s\"!"), recipient);
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
"notify-status-code", IPP_URI_SCHEME);
return;
if (access(notifier, X_OK))
{
send_ipp_status(con, IPP_NOT_POSSIBLE,
- _("notify-recipient URI \"%s\" uses unknown scheme!"),
+ _("notify-recipient-uri URI \"%s\" uses unknown scheme!"),
recipient);
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
"notify-status-code", IPP_URI_SCHEME);
}
else if (!strcmp(attr->name, "notify-events") &&
attr->value_tag == IPP_TAG_KEYWORD)
- {
- for (i = 0; i < attr->num_values; i ++)
- mask |= cupsdEventValue(attr->values[i].string.text);
- }
+ notify_events = attr;
else if (!strcmp(attr->name, "notify-lease-duration") &&
attr->value_tag == IPP_TAG_INTEGER)
lease = attr->values[0].integer;
attr = attr->next;
}
+ if (notify_events)
+ {
+ for (i = 0; i < notify_events->num_values; i ++)
+ mask |= cupsdEventValue(notify_events->values[i].string.text);
+ }
+
if (recipient)
cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient);
if (pullmethod)
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
printer->name, get_username(con));
cupsdExpireSubscriptions(printer, NULL);
-
+
/*
* Remove any old PPD or script files...
*/
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
return;
}
else
+ {
+ dtype &= CUPS_PRINTER_CLASS;
dmask = CUPS_PRINTER_CLASS;
+ }
/*
* Check policy...
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
}
else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
if ((job->dtype & dmask) != dtype &&
(!job->printer || (job->printer->type & dmask) != dtype))
continue;
- if (username[0] && strcasecmp(username, job->username))
- continue;
-
if (completed && job->state_value <= IPP_JOB_STOPPED)
continue;
if (!job->attrs)
continue;
+ if (username[0] && strcasecmp(username, job->username))
+ continue;
+
if (count > 0)
ippAddSeparator(con->response);
int interval; /* Poll interval */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscription_attrs(con=%p[%d])",
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])",
con, con->http.fd);
/*
DefaultPolicyPtr,
con, sub->owner)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, sub->dest);
return;
}
}
+/*
+ * 'get_ppd()' - Get a named PPD from the local system.
+ */
+
+static void
+get_ppd(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI or PPD name */
+{
+ http_status_t status; /* Policy status */
+ cupsd_printer_t *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
+ con->http.fd, uri, uri->name, uri->values[0].string.text);
+
+ if (!strcmp(uri->name, "ppd-name"))
+ {
+ /*
+ * Return a PPD file from cups-driverd...
+ */
+
+ char command[1024], /* cups-driverd command */
+ options[1024], /* Options to pass to command */
+ ppd_name[1024]; /* ppd-name */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Run cups-driverd command with the given options...
+ */
+
+ snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
+ url_encode_string(uri->values[0].string.text, ppd_name, sizeof(ppd_name));
+ snprintf(options, sizeof(options), "get+%d+%s",
+ con->request->request.op.request_id, ppd_name);
+
+ if (cupsdSendCommand(con, command, options, 0))
+ {
+ /*
+ * Command started successfully, don't send an IPP response here...
+ */
+
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+ else
+ {
+ /*
+ * Command failed, return "internal error" so the user knows something
+ * went wrong...
+ */
+
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("cups-driverd failed to execute."));
+ }
+ }
+ else if (!strcmp(uri->name, "printer-uri") &&
+ cupsdValidateDest(uri->values[0].string.text, &dtype, &dest))
+ {
+ int i; /* Looping var */
+ char filename[1024]; /* PPD filename */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * See if we need the PPD for a class or remote printer...
+ */
+
+ if (dtype & CUPS_PRINTER_REMOTE)
+ {
+ send_ipp_status(con, CUPS_SEE_OTHER, NULL);
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->uri);
+ return;
+ }
+ else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ for (i = 0; i < dest->num_printers; i ++)
+ if (!(dest->printers[i]->type &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_REMOTE)))
+ break;
+
+ if (i < dest->num_printers)
+ dest = dest->printers[i];
+ else
+ {
+ send_ipp_status(con, CUPS_SEE_OTHER, NULL);
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->printers[0]->uri);
+ return;
+ }
+ }
+
+ /*
+ * Found the printer with the PPD file, now see if there is one...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ dest->name);
+
+ if ((con->file = open(filename, O_RDONLY)) < 0)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be opened: %s"),
+ uri->values[i].string.text, strerror(errno));
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ con->pipe_pid = 0;
+
+ send_ipp_status(con, IPP_OK, NULL);
+ }
+ else
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be found."),
+ uri->values[0].string.text);
+}
+
+
/*
* 'get_ppds()' - Get the list of PPD files on the local system.
*/
{
http_status_t status; /* Policy status */
ipp_attribute_t *limit, /* Limit attribute */
+ *device, /* ppd-device-id attribute */
+ *language, /* ppd-natural-language attribute */
*make, /* ppd-make attribute */
+ *model, /* ppd-make-and-model attribute */
+ *product, /* ppd-product attribute */
+ *psversion, /* ppd-psverion attribute */
*requested; /* requested-attributes attribute */
- char command[1024], /* cups-deviced command */
+ char command[1024], /* cups-driverd command */
options[1024], /* Options to pass to command */
- requested_str[256],
+ device_str[256],/* Escaped ppd-device-id string */
+ language_str[256],
+ /* Escaped ppd-natural-language string */
+ make_str[256], /* Escaped ppd-make string */
+ model_str[256], /* Escaped ppd-make-and-model string */
+ product_str[256],
+ /* Escaped ppd-product string */
+ psversion_str[256],
+ /* Escaped ppd-psversion string */
+ requested_str[256];
/* String for requested attributes */
- make_str[256]; /* Escaped ppd-make string */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd);
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
*/
limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ device = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
+ language = ippFindAttribute(con->request, "ppd-natural-language",
+ IPP_TAG_LANGUAGE);
make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
+ model = ippFindAttribute(con->request, "ppd-make-and-model",
+ IPP_TAG_TEXT);
+ product = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
+ psversion = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
requested = ippFindAttribute(con->request, "requested-attributes",
IPP_TAG_KEYWORD);
else
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+ if (device)
+ url_encode_attr(device, device_str, sizeof(device_str));
+ else
+ device_str[0] = '\0';
+
+ if (language)
+ url_encode_attr(language, language_str, sizeof(language_str));
+ else
+ language_str[0] = '\0';
+
if (make)
url_encode_attr(make, make_str, sizeof(make_str));
else
make_str[0] = '\0';
+ if (model)
+ url_encode_attr(model, model_str, sizeof(model_str));
+ else
+ model_str[0] = '\0';
+
+ if (product)
+ url_encode_attr(product, product_str, sizeof(product_str));
+ else
+ product_str[0] = '\0';
+
+ if (psversion)
+ url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
+ else
+ psversion_str[0] = '\0';
+
snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
- snprintf(options, sizeof(options), "list+%d+%d+%s%s%s",
+ snprintf(options, sizeof(options), "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s",
con->request->request.op.request_id,
limit ? limit->values[0].integer : 0,
- requested_str, make ? "%20" : "", make_str);
+ requested_str,
+ device ? "%20" : "", device_str,
+ language ? "%20" : "", language_str,
+ make ? "%20" : "", make_str,
+ model ? "%20" : "", model_str,
+ product ? "%20" : "", product_str,
+ psversion ? "%20" : "", psversion_str);
if (cupsdSendCommand(con, command, options, 0))
{
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
DefaultPolicyPtr,
con, sub->owner)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, sub->dest);
return;
}
DefaultPolicyPtr,
con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
cupsdHoldJob(job);
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
+ "Job held by user.");
+
if ((newattr = ippFindAttribute(con->request, "job-hold-until",
IPP_TAG_KEYWORD)) == NULL)
newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
*/
cupsdSetJobHoldUntil(job, attr->values[0].string.text);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
+ "Job job-hold-until value changed by user.");
}
cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was held by \"%s\".", jobid,
ipp_attribute_t *attr; /* Current attribute */
int jobid; /* Job ID */
cupsd_job_t *job; /* Current job */
- const char *src, /* Source printer/class */
- *dest; /* Destination */
+ const char *src; /* Source printer/class */
cups_ptype_t stype, /* Source type (printer or class) */
dtype; /* Destination type (printer or class) */
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
_("job-printer-uri attribute missing!"));
return;
}
-
- if ((dest = cupsdValidateDest(attr->values[0].string.text, &dtype,
- &dprinter)) == NULL)
+
+ if (!cupsdValidateDest(attr->values[0].string.text, &dtype, &dprinter))
{
/*
* Bad URI...
if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con,
NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, dprinter);
return;
}
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
}
-/*
- * 'ppd_add_default()' - Add a PPD default choice.
- */
-
-static int /* O - Number of defaults */
-ppd_add_default(
- const char *option, /* I - Option name */
- const char *choice, /* I - Choice name */
- int num_defaults, /* I - Number of defaults */
- ppd_default_t **defaults) /* IO - Defaults */
-{
- int i; /* Looping var */
- ppd_default_t *temp; /* Temporary defaults array */
-
-
- /*
- * First check if the option already has a default value; the PPD spec
- * says that the first one is used...
- */
-
- for (i = 0, temp = *defaults; i < num_defaults; i ++)
- if (!strcmp(option, temp[i].option))
- return (num_defaults);
-
- /*
- * Now add the option...
- */
-
- if (num_defaults == 0)
- temp = malloc(sizeof(ppd_default_t));
- else
- temp = realloc(*defaults, (num_defaults + 1) * sizeof(ppd_default_t));
-
- if (!temp)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "ppd_add_default: Unable to add default value for \"%s\" - %s",
- option, strerror(errno));
- return (num_defaults);
- }
-
- *defaults = temp;
- temp += num_defaults;
-
- strlcpy(temp->option, option, sizeof(temp->option));
- strlcpy(temp->choice, choice, sizeof(temp->choice));
-
- return (num_defaults + 1);
-}
-
-
/*
* 'ppd_parse_line()' - Parse a PPD default line.
*/
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
attr->value_tag = IPP_TAG_KEYWORD;
attr->values[0].string.text = _cupsStrAlloc("no-hold");
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
+ "Job job-hold-until value changed by user.");
}
/*
cupsdReleaseJob(job);
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
+ "Job released by user.");
+
cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was released by \"%s\".", jobid,
username);
DefaultPolicyPtr,
con, sub->owner)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, sub->dest);
return;
}
cupsdSaveAllSubscriptions();
con->response->request.status.status_code = IPP_OK;
+
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-lease-duration", sub->lease);
}
cupsdLoadJob(job);
- if (!job->attrs ||job->num_files == 0)
+ if (!job->attrs || job->num_files == 0)
{
/*
* Nope - return a "not possible" error...
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
*/
static void
-save_auth_info(cupsd_client_t *con, /* I - Client connection */
- cupsd_job_t *job) /* I - Job */
+save_auth_info(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job, /* I - Job */
+ ipp_attribute_t *auth_info) /* I - auth-info attribute, if any */
{
int i; /* Looping var */
char filename[1024]; /* Job authentication filename */
cups_file_t *fp; /* Job authentication file */
- char line[1024]; /* Line for file */
+ char line[2048]; /* Line for file */
/*
* This function saves the in-memory authentication information for
* a job so that it can be used to authenticate with a remote host.
* The information is stored in a file that is readable only by the
- * root user. The username and password are Base-64 encoded, each
- * on a separate line, followed by random number (up to 1024) of
- * newlines to limit the amount of information that is exposed.
+ * root user. The fields are Base-64 encoded, each on a separate line,
+ * followed by random number (up to 1024) of newlines to limit the
+ * amount of information that is exposed.
*
* Because of the potential for exposing of authentication information,
* this functionality is only enabled when running cupsd as root.
fchown(cupsFileNumber(fp), 0, 0);
fchmod(cupsFileNumber(fp), 0400);
- /*
- * Write the authenticated username...
- */
+ if (auth_info)
+ {
+ /*
+ * Write 1 to 4 auth values...
+ */
- httpEncode64_2(line, sizeof(line), con->username, strlen(con->username));
- cupsFilePrintf(fp, "%s\n", line);
+ for (i = 0; i < auth_info->num_values; i ++)
+ {
+ httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text,
+ strlen(auth_info->values[i].string.text));
+ cupsFilePrintf(fp, "%s\n", line);
+ }
+ }
+ else
+ {
+ /*
+ * Write the authenticated username...
+ */
- /*
- * Write the authenticated password...
- */
+ httpEncode64_2(line, sizeof(line), con->username, strlen(con->username));
+ cupsFilePrintf(fp, "%s\n", line);
+
+ /*
+ * Write the authenticated password...
+ */
- httpEncode64_2(line, sizeof(line), con->password, strlen(con->password));
- cupsFilePrintf(fp, "%s\n", line);
+ httpEncode64_2(line, sizeof(line), con->password, strlen(con->password));
+ cupsFilePrintf(fp, "%s\n", line);
+ }
/*
* Write a random number of newlines to the end of the file...
*/
cupsFileClose(fp);
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
+ save_krb5_creds(con, job);
+#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
+}
+
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
+/*
+ * 'save_krb5_creds()' - Save Kerberos credentials for the job.
+ */
+
+static void
+save_krb5_creds(cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job) /* I - Job */
+{
+ krb5_context krb_context; /* Kerberos context */
+ krb5_ccache ccache; /* Credentials cache */
+ OM_uint32 major_status, /* Major status code */
+ minor_status; /* Minor status code */
+
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (krb5_init_context == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "save_krb5_creds: GSSAPI/Kerberos framework is not "
+ "present");
+ return;
+ }
+# endif /* __APPLE__ */
+
+ /*
+ * Setup a cached context for the job filters to use...
+ */
+
+ if (krb5_init_context(&krb_context))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
+ return;
+ }
+
+# ifdef HAVE_HEIMDAL
+ if (krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))
+# else
+ if (krb5_cc_gen_new(krb_context, &ccache))
+# endif /* HAVE_HEIMDAL */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create new credentials");
+ return;
+ }
+
+ 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(krb_context, ccache);
+ return;
+ }
+
+ cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s",
+ krb5_cc_get_name(krb_context, ccache));
+ krb5_cc_close(krb_context, ccache);
}
+#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
/*
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", jobid);
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
- job ? job->state_value : IPP_JOB_CANCELLED);
+ job ? job->state_value : IPP_JOB_CANCELED);
add_job_state_reasons(con, job);
con->response->request.status.status_code = IPP_OK;
*/
static void
-send_http_error(cupsd_client_t *con, /* I - Client connection */
- http_status_t status) /* I - HTTP status code */
+send_http_error(
+ cupsd_client_t *con, /* I - Client connection */
+ http_status_t status, /* I - HTTP status code */
+ cupsd_printer_t *printer) /* I - Printer, if any */
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s",
ippOpString(con->request->request.op.operation_id),
httpStatus(status));
- cupsdSendError(con, status);
+ if (status == HTTP_UNAUTHORIZED &&
+ printer && printer->num_auth_info_required > 0 &&
+ !strcmp(printer->auth_info_required[0], "negotiate"))
+ cupsdSendError(con, status, AUTH_NEGOTIATE);
+ else
+ cupsdSendError(con, status, AUTH_NONE);
ippDelete(con->response);
con->response = NULL;
_cupsLangString(con->language, message), ap);
va_end(ap);
- cupsdLogMessage(status >= IPP_BAD_REQUEST ? CUPSD_LOG_ERROR : CUPSD_LOG_INFO,
- "%s %s: %s",
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
ippOpString(con->request->request.op.operation_id),
ippErrorString(status), formatted);
}
else
- cupsdLogMessage(status >= IPP_BAD_REQUEST ? CUPSD_LOG_ERROR : CUPSD_LOG_INFO,
- "%s %s",
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s",
ippOpString(con->request->request.op.operation_id),
ippErrorString(status));
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, NULL);
return;
}
resource[HTTP_MAX_URI];
/* Resource portion of URI */
int port; /* Port portion of URI */
+ int event; /* Events? */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED);
+ send_http_error(con, HTTP_UNAUTHORIZED, NULL);
return;
}
cupsdLoadJob(job);
+ event = 0;
+
for (attr = con->request->attrs; attr; attr = attr->next)
{
if (attr->group_tag != IPP_TAG_JOB || !attr->name)
return;
}
else if (con->response->request.status.status_code == IPP_OK)
+ {
cupsdSetJobPriority(job, attr->values[0].integer);
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
+ }
}
else if (!strcmp(attr->name, "job-state"))
{
else if (con->response->request.status.status_code == IPP_OK)
{
job->state->values[0].integer = attr->values[0].integer;
- job->state_value = attr->values[0].integer;
+ job->state_value = (ipp_jstate_t)attr->values[0].integer;
+
+ event |= CUPSD_EVENT_JOB_STATE;
}
break;
}
break;
- case IPP_JOB_CANCELLED :
+ case IPP_JOB_CANCELED :
case IPP_JOB_ABORTED :
case IPP_JOB_COMPLETED :
if (job->state_value > IPP_JOB_PROCESSING)
return;
}
else if (con->response->request.status.status_code == IPP_OK)
- {
- cupsdCancelJob(job, 0);
-
- if (JobHistory)
- {
- job->state->values[0].integer = attr->values[0].integer;
- job->state_value = attr->values[0].integer;
- cupsdSaveJob(job);
- }
- }
+ cupsdCancelJob(job, 0, (ipp_jstate_t)attr->values[0].integer);
break;
}
}
cupsdReleaseJob(job);
else
cupsdHoldJob(job);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
}
}
else if (attr->value_tag == IPP_TAG_DELETEATTR)
job->attrs->last = job->attrs->prev;
_ippFreeAttr(attr2);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
}
}
else
*/
copy_attribute(job->attrs, attr, 0);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
}
}
cupsdSaveJob(job);
+ /*
+ * Send events as needed...
+ */
+
+ if (event & CUPSD_EVENT_JOB_STATE)
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
+ job->state_value == IPP_JOB_HELD ?
+ "Job held by user." : "Job restarted by user.");
+
+ if (event & CUPSD_EVENT_JOB_CONFIG_CHANGED)
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
+ "Job options changed by user.");
+
/*
* Start jobs if possible...
*/
attr->values[0].string.text);
cupsdSetString(&printer->error_policy, attr->values[0].string.text);
}
- else if (!strcmp(attr->name, "notify-lease-duration-default") ||
- !strcmp(attr->name, "notify-events-default"))
- continue;
/*
* Skip any other non-default attributes...
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
cupsdStartPrinter(printer, 1);
if (dtype & CUPS_PRINTER_CLASS)
- {
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".",
printer->name, get_username(con));
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
- "Class \"%s\" started by \"%s\".", printer->name,
- get_username(con));
- }
else
- {
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".",
printer->name, get_username(con));
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
- "Printer \"%s\" started by \"%s\".", printer->name,
- get_username(con));
- }
cupsdCheckJobs();
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
cupsdStopPrinter(printer, 1);
if (dtype & CUPS_PRINTER_CLASS)
- {
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".",
printer->name, get_username(con));
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
- "Class \"%s\" stopped by \"%s\".", printer->name,
- get_username(con));
- }
else
- {
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".",
printer->name, get_username(con));
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
- "Printer \"%s\" stopped by \"%s\".", printer->name,
- get_username(con));
- }
/*
* Everything was ok, so return OK status...
{
int i; /* Looping var */
char *bufptr, /* Pointer into buffer */
- *bufend, /* End of buffer */
- *valptr; /* Pointer into value */
+ *bufend; /* End of buffer */
strlcpy(buffer, attr->name, bufsize);
*bufptr++ = '\'';
- for (valptr = attr->values[i].string.text;
- *valptr && bufptr < bufend;
- valptr ++)
- if (*valptr == ' ')
- {
- if (bufptr >= (bufend - 2))
- break;
-
- *bufptr++ = '%';
- *bufptr++ = '2';
- *bufptr++ = '0';
- }
- else if (*valptr == '\'' || *valptr == '\\')
- {
- *bufptr++ = '\\';
- *bufptr++ = *valptr;
- }
- else
- *bufptr++ = *valptr;
+ bufptr = url_encode_string(attr->values[i].string.text,
+ bufptr, bufend - bufptr + 1);
if (bufptr >= bufend)
break;
}
+/*
+ * 'url_encode_string()' - URL-encode a string.
+ */
+
+static char * /* O - End of string */
+url_encode_string(const char *s, /* I - String */
+ char *buffer, /* I - String buffer */
+ int bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ static const char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+
+ while (*s && bufptr < bufend)
+ {
+ if (*s == ' ' || *s == '%')
+ {
+ if (bufptr >= (bufend - 2))
+ break;
+
+ *bufptr++ = '%';
+ *bufptr++ = hex[(*s >> 4) & 15];
+ *bufptr++ = hex[*s & 15];
+
+ s ++;
+ }
+ else if (*s == '\'' || *s == '\\')
+ {
+ if (bufptr >= (bufend - 1))
+ break;
+
+ *bufptr++ = '\\';
+ *bufptr++ = *s++;
+ }
+ else
+ *bufptr++ = *s++;
+ }
+
+ *bufptr = '\0';
+
+ return (bufptr);
+}
+
+
/*
* 'user_allowed()' - See if a user is allowed to print to a queue.
*/
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
- send_http_error(con, status);
+ send_http_error(con, status, printer);
return;
}
*/
for (ptr = name; *ptr; ptr ++)
- if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
+ if ((*ptr > 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
return (0);
/*
/*
- * End of "$Id$".
+ * End of "$Id: ipp.c 6508 2007-05-03 20:07:14Z mike $".
*/