From 10d09e334a4892cd5ed4e2a2a0f5bbe3c8c171ed Mon Sep 17 00:00:00 2001 From: msweet Date: Sat, 6 Nov 2010 05:13:04 +0000 Subject: [PATCH] Merge changes from CUPS 1.5svn-r9352. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@2848 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES.txt | 6 +- IPPTOOL.txt | 36 +- conf/cupsd.conf.in | 20 +- cups/api-array.shtml | 29 +- cups/array.c | 114 +- cups/array.h | 12 +- cups/http-addrlist.c | 12 +- cups/http-private.h | 11 +- cups/http.c | 138 ++- cups/libcups2.def | 1 + cups/pwg-ppd.c | 28 +- cups/request.c | 14 + cups/usersys.c | 132 +-- doc/cups-printable.css | 2 + doc/cups.css | 3 + doc/help/api-array.html | 88 +- doc/help/api-cgi.html | 2 + doc/help/api-cups.html | 96 +- doc/help/api-driver.html | 2 + doc/help/api-filedir.html | 2 + doc/help/api-filter.html | 4 +- doc/help/api-httpipp.html | 140 ++- doc/help/api-mime.html | 2 + doc/help/api-overview.html | 2 + doc/help/api-ppd.html | 5 +- doc/help/api-ppdc.html | 2 + doc/help/api-raster.html | 93 +- doc/help/postscript-driver.html | 17 + doc/help/ppd-compiler.html | 17 + doc/help/raster-driver.html | 17 + doc/help/ref-cupsd-conf.html.in | 85 ++ doc/help/spec-ppd.html | 869 +++++++++----- filter/Makefile | 12 + filter/api-raster.header | 4 +- filter/postscript-driver.header | 15 + filter/ppd-compiler.header | 15 + filter/raster-driver.header | 15 + filter/spec-ppd.header | 32 + filter/spec-ppd.shtml | 1851 ++++++++++++++++++++++++++++++ man/cupsd.conf.man.in | 45 +- man/ipptool.man | 11 +- scheduler/auth.c | 724 +++++------- scheduler/auth.h | 35 +- scheduler/banners.c | 4 +- scheduler/banners.h | 4 +- scheduler/cert.c | 2 +- scheduler/cert.h | 5 +- scheduler/classes.c | 16 +- scheduler/classes.h | 2 +- scheduler/client.c | 43 +- scheduler/client.h | 4 +- scheduler/conf.c | 600 ++++++---- scheduler/conf.h | 2 +- scheduler/cups-deviced.c | 4 +- scheduler/cupsd.h | 2 + scheduler/cupsfilter.c | 2 +- scheduler/dirsvc.c | 30 +- scheduler/dirsvc.h | 7 +- scheduler/env.c | 4 +- scheduler/ipp.c | 394 ++++--- scheduler/job.c | 11 +- scheduler/job.h | 6 +- scheduler/listen.c | 5 +- scheduler/log.c | 2 +- scheduler/main.c | 167 +-- scheduler/mime.h | 4 +- scheduler/network.h | 5 +- scheduler/policy.c | 313 +++-- scheduler/policy.h | 17 +- scheduler/printers.c | 95 +- scheduler/printers.h | 16 +- scheduler/quotas.c | 2 +- scheduler/removefile.c | 10 +- scheduler/select.c | 2 +- scheduler/statbuf.c | 5 +- scheduler/statbuf.h | 7 +- scheduler/subscriptions.c | 31 +- scheduler/subscriptions.h | 9 +- scheduler/sysman.c | 6 +- scheduler/sysman.h | 4 +- scheduler/util.c | 30 +- scheduler/util.h | 4 +- test/4.4-subscription-ops.test | 5 + test/get-printer-attributes.test | 9 +- test/ipp-1.1.test | 2 +- test/ipptool.c | 123 +- test/print-job-media-col.test | 1 + test/run-stp-tests.sh | 6 +- 88 files changed, 5065 insertions(+), 1717 deletions(-) create mode 100644 filter/spec-ppd.header create mode 100644 filter/spec-ppd.shtml diff --git a/CHANGES.txt b/CHANGES.txt index 067dc958e..008b91b37 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,12 @@ -CHANGES.txt - 2010-06-16 +CHANGES.txt - 2010-11-05 ------------------------ CHANGES IN CUPS V1.5b1 + - The scheduler now provides privacy controls for jobs and subscriptions + (STR #2969) + - Added new cupsArrayNew3 API which offers memory management of array + elements. - Added several new color spaces to the CUPS raster format (STR #3419) - The Validate-Job operation now uses the same policy as Print-Job by default. diff --git a/IPPTOOL.txt b/IPPTOOL.txt index c96822017..c13da01ae 100644 --- a/IPPTOOL.txt +++ b/IPPTOOL.txt @@ -1,24 +1,23 @@ -IPPTOOL.txt - 2010-04-07 +IPPTOOL.txt - 2010-10-17 ------------------------ INTRODUCTION - Starting with CUPS 1.5, CUPS now installs a user program called - ipptool that can be used to send arbitrary IPP requests to a CUPS - server or IPP printer. This tool started life as part of the CUPS - automated test suite and has grown to support complex conformance - tests and a simple way to query printer, job, and subscription - attributes. + Starting with CUPS 1.5, CUPS now installs a user program called ipptool that + can be used to send arbitrary IPP requests to a CUPS server or IPP printer. + This tool started life as part of the CUPS automated test suite and has + grown to support complex conformance tests and a simple way to query + printer, job, and subscription attributes. BASIC USAGE - The ipptool command requires a printer URI and one or more "test" - files that describe the operations, attributes to display, and - expected status and attribute values. Several standard files are - included with CUPS, for example to show a list of pending print jobs - on a CUPS printer called "myprinter" you'd run: + The ipptool command requires a printer URI and one or more "test" files that + describe the operations, attributes to display, and expected status and + attribute values. Several standard files are included with CUPS, for example + to show a list of pending print jobs on a CUPS printer called "myprinter" + you'd run: ipptool ipp://localhost/printers/myprinter get-jobs.test @@ -31,8 +30,8 @@ BASIC USAGE 74 pending-held testfile.jpg msweet 75 pending-held testfile.txt msweet - To get output suitable for import into a spreadsheet, use the "-c" - (CSV) option: + To get output suitable for import into a spreadsheet, use the "-c" (CSV) + option: ipptool -c ipp://localhost/printers/myprinter get-jobs.test @@ -47,9 +46,8 @@ BASIC USAGE CONFORMANCE TESTS - We provide basic IPP conformance tests for IPP/1.1, IPP/2.0, and - IPP/2.1. For a given printer URI, the following commands perform - tests at each level: + We provide basic IPP conformance tests for IPP/1.1, IPP/2.0, and IPP/2.1. + For a given printer URI, the following commands perform tests at each level: ipptool -t printer-uri ipp-1.1.test ipptool -t -V 2.0 printer-uri ipp-2.0.test @@ -58,8 +56,8 @@ CONFORMANCE TESTS READING THE DOCUMENTATION - The command usage is described in the ipptest(1) man page, while the - file format is described in the ipptestfile(5) man page. + The command usage is described in the ipptest(1) man page, while the file + format is described in the ipptestfile(5) man page. GETTING SUPPORT AND OTHER RESOURCES diff --git a/conf/cupsd.conf.in b/conf/cupsd.conf.in index a7143b7dc..1a2037cfa 100644 --- a/conf/cupsd.conf.in +++ b/conf/cupsd.conf.in @@ -45,6 +45,12 @@ DefaultAuthType Basic # Set the default printer/job policies... + # Job/subscription privacy... + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateAccess default + # Job-related operations must be done by the owner or an administrator... Order deny,allow @@ -63,14 +69,14 @@ DefaultAuthType Basic # All printer operations require a printer operator to authenticate... - + AuthType Default Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@ Order deny,allow # Only the owner or an administrator can cancel or authenticate a job... - + Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@ Order deny,allow @@ -82,6 +88,12 @@ DefaultAuthType Basic # Set the authenticated printer/job policies... + # Job/subscription privacy... + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateAccess default + # Job-related operations must be done by the owner or an administrator... AuthType Default @@ -102,14 +114,14 @@ DefaultAuthType Basic # All printer operations require a printer operator to authenticate... - + AuthType Default Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@ Order deny,allow # Only the owner or an administrator can cancel or authenticate a job... - + AuthType Default Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@ Order deny,allow diff --git a/cups/api-array.shtml b/cups/api-array.shtml index bacf48307..0872d51e7 100644 --- a/cups/api-array.shtml +++ b/cups/api-array.shtml @@ -31,8 +31,9 @@ data.

Managing Arrays

Arrays are created using either the -cupsArrayNew or -cupsArrayNew2 functions. The +cupsArrayNew, +cupsArrayNew2, or +cupsArrayNew3 functions. The first function creates a new array with the specified callback function and user data pointer:

@@ -69,7 +70,7 @@ static int compare_func(void *first, void *second, void *user_data); static int hash_func(void *element, void *user_data); void *user_data; -cups_array_t *array = cupsArrayNew2(compare_func, user_data, hash_func, HASH_SIZE); +cups_array_t *hash_array = cupsArrayNew2(compare_func, user_data, hash_func, HASH_SIZE);

The hash function (type @@ -80,6 +81,25 @@ element and is called whenever you look up an element in the array with only limited by available memory, but generally should not be larger than 16384 to realize any performance improvement.

+

The cupsArrayNew3 function adds +copy and free callbacks to support basic memory management of elements:

+ +
+#include <cups/array.h>
+
+#define HASH_SIZE 512 /* Size of hash table */
+
+static int compare_func(void *first, void *second, void *user_data);
+static void *copy_func(void *element, void *user_data);
+static void free_func(void *element, void *user_data);
+static int hash_func(void *element, void *user_data);
+
+void *user_data;
+cups_array_t *array = cupsArrayNew3(compare_func, user_data, NULL, 0, copy_func, free_func);
+
+cups_array_t *hash_array = cupsArrayNew3(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func);
+
+

Once you have created the array, you add elements using the cupsArrayAdd cupsArrayInsert functions. @@ -128,8 +148,7 @@ example:

Finally, you free the memory used by the array using the cupsArrayDelete function. All of the memory for the array and hash table (if any) is freed, however CUPS -does not free the elements - if necessary, you must allocate and free the -elements yourself.

+does not free the elements unless you provide copy and free functions.

Finding and Enumerating Elements

diff --git a/cups/array.c b/cups/array.c index 5b9a8ce37..5448472b3 100644 --- a/cups/array.c +++ b/cups/array.c @@ -30,12 +30,15 @@ * cupsArrayInsert() - Insert an element in the array. * cupsArrayLast() - Get the last element in the array. * cupsArrayNew() - Create a new array. + * cupsArrayNew2() - Create a new array with hash. + * cupsArrayNew3() - Create a new array with hash and/or free function. * cupsArrayNext() - Get the next element in the array. * cupsArrayPrev() - Get the previous element in the array. * cupsArrayRemove() - Remove an element from the array. - * cupsArrayRestore() - Reset the current element to the last cupsArraySave. - * cupsArraySave() - Mark the current element for a later - * cupsArrayRestore. + * cupsArrayRestore() - Reset the current element to the last @link + * cupsArraySave@. + * cupsArraySave() - Mark the current element for a later @link + * cupsArrayRestore@. * cupsArrayUserData() - Return the user data for an array. * cups_array_add() - Insert or append an element to the array... * cups_array_find() - Find an element in the array... @@ -84,6 +87,8 @@ struct _cups_array_s /**** CUPS array structure ****/ cups_ahash_func_t hashfunc; /* Hash function */ int hashsize, /* Size of hash */ *hash; /* Hash array */ + cups_acopy_func_t copyfunc; /* Copy function */ + cups_afree_func_t freefunc; /* Free function */ }; @@ -149,6 +154,19 @@ cupsArrayClear(cups_array_t *a) /* I - Array */ if (!a) return; + /* + * Free the existing elements as needed.. + */ + + if (a->freefunc) + { + int i; /* Looping var */ + void **e; /* Current element */ + + for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) + (a->freefunc)(*e, a->data); + } + /* * Set the number of elements to 0; we don't actually free the memory * here - that is done in cupsArrayDelete()... @@ -236,8 +254,21 @@ cupsArrayDelete(cups_array_t *a) /* I - Array */ return; /* - * Free the array of element pointers - the caller is responsible - * for freeing the elements themselves... + * Free the elements if we have a free function (otherwise the caller is + * responsible for doing the dirty work...) + */ + + if (a->freefunc) + { + int i; /* Looping var */ + void **e; /* Current element */ + + for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) + (a->freefunc)(*e, a->data); + } + + /* + * Free the array of element pointers... */ if (a->alloc_elements) @@ -303,7 +334,26 @@ cupsArrayDup(cups_array_t *a) /* I - Array */ * Copy the element pointers... */ - memcpy(da->elements, a->elements, a->num_elements * sizeof(void *)); + if (a->copyfunc) + { + /* + * Use the copy function to make a copy of each element... + */ + + int i; /* Looping var */ + + for (i = 0; i < a->num_elements; i ++) + da->elements[i] = (a->copyfunc)(a->elements[i], a->data); + } + else + { + /* + * Just copy raw pointers... + */ + + memcpy(da->elements, a->elements, a->num_elements * sizeof(void *)); + } + da->num_elements = a->num_elements; da->alloc_elements = a->num_elements; } @@ -566,7 +616,7 @@ cups_array_t * /* O - Array */ cupsArrayNew(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d) /* I - User data pointer or @code NULL@ */ { - return (cupsArrayNew2(f, d, 0, 0)); + return (cupsArrayNew3(f, d, 0, 0, 0, 0)); } @@ -589,6 +639,38 @@ cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ fo void *d, /* I - User data or @code NULL@ */ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ int hsize) /* I - Hash size (>= 0) */ +{ + return (cupsArrayNew3(f, d, h, hsize, 0, 0)); +} + + +/* + * 'cupsArrayNew3()' - Create a new array with hash and/or free function. + * + * The comparison function ("f") is used to create a sorted array. The function + * receives pointers to two elements and the user data pointer ("d") - the user + * data pointer argument can safely be omitted when not required so functions + * like @code strcmp@ can be used for sorted string arrays. + * + * The hash function ("h") is used to implement cached lookups with the + * specified hash size ("hsize"). + * + * The copy function ("cf") is used to automatically copy/retain elements when + * added or the array is copied. + * + * The free function ("cf") is used to automatically free/release elements when + * removed or the array is deleted. + * + * @since CUPS 1.5@ + */ + +cups_array_t * /* O - Array */ +cupsArrayNew3(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ + void *d, /* I - User data or @code NULL@ */ + cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ + int hsize, /* I - Hash size (>= 0) */ + cups_acopy_func_t cf, /* I - Copy function */ + cups_afree_func_t ff) /* I - Free function */ { cups_array_t *a; /* Array */ @@ -623,6 +705,9 @@ cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ fo memset(a->hash, -1, hsize * sizeof(int)); } + a->copyfunc = cf; + a->freefunc = ff; + return (a); } @@ -738,6 +823,9 @@ cupsArrayRemove(cups_array_t *a, /* I - Array */ a->num_elements --; + if (a->freefunc) + (a->freefunc)(a->elements[current], a->data); + if (current < a->num_elements) memmove(a->elements + current, a->elements + current + 1, (a->num_elements - current) * sizeof(void *)); @@ -985,7 +1073,17 @@ cups_array_add(cups_array_t *a, /* I - Array */ DEBUG_printf(("9cups_array_add: append element at %d...", current)); #endif /* DEBUG */ - a->elements[current] = e; + if (a->copyfunc) + { + if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL) + { + DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0"); + return (0); + } + } + else + a->elements[current] = e; + a->num_elements ++; a->insert = current; diff --git a/cups/array.h b/cups/array.h index 029e2e996..466a2721f 100644 --- a/cups/array.h +++ b/cups/array.h @@ -1,9 +1,9 @@ /* * "$Id: array.h 7266 2008-01-29 02:15:29Z mike $" * - * Sorted array definitions for the Common UNIX Printing System (CUPS). + * Sorted array definitions for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -45,6 +45,10 @@ typedef int (*cups_array_func_t)(void *first, void *second, void *data); /**** Array comparison function ****/ typedef int (*cups_ahash_func_t)(void *element, void *data); /**** Array hash function ****/ +typedef void *(*cups_acopy_func_t)(void *element, void *data); + /**** Array element copy function ****/ +typedef void (*cups_afree_func_t)(void *element, void *data); + /**** Array element free function ****/ /* @@ -67,6 +71,10 @@ extern void *cupsArrayLast(cups_array_t *a) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew2(cups_array_func_t f, void *d, cups_ahash_func_t h, int hsize) _CUPS_API_1_3; +extern cups_array_t *cupsArrayNew3(cups_array_func_t f, void *d, + cups_ahash_func_t h, int hsize, + cups_acopy_func_t cf, + cups_afree_func_t ff) _CUPS_API_1_5; extern void *cupsArrayNext(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayPrev(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayRemove(cups_array_t *a, void *e) _CUPS_API_1_2; diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c index 14406427d..7c11d1b1a 100644 --- a/cups/http-addrlist.c +++ b/cups/http-addrlist.c @@ -40,9 +40,12 @@ httpAddrConnect( http_addrlist_t *addrlist, /* I - List of potential addresses */ int *sock) /* O - Socket */ { - int val; /* Socket option value */ + int val; /* Socket option value */ +#ifdef __APPLE__ + struct timeval timeout; /* Socket timeout value */ +#endif /* __APPLE__ */ #ifdef DEBUG - char temp[256]; /* Temporary address string */ + char temp[256]; /* Temporary address string */ #endif /* DEBUG */ @@ -108,8 +111,9 @@ httpAddrConnect( * we block... */ - val = 30; - setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val)); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); #endif /* __APPLE__ */ /* diff --git a/cups/http-private.h b/cups/http-private.h index 0700530bd..483592f51 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -169,6 +169,8 @@ typedef void *http_tls_t; # endif /* HAVE_LIBSSL */ +typedef int (*_http_timeout_cb_t)(http_t *http, void *user_data); + struct _http_s /**** HTTP connection structure. ****/ { int fd; /* File descriptor for this socket */ @@ -224,11 +226,14 @@ struct _http_s /**** HTTP connection structure. ****/ gss_name_t gssname; /* Authentication server name @since CUPS 1.3@ */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H - AuthorizationRef auth_ref; /* Authorization ref */ + AuthorizationRef auth_ref; /* Authorization ref @since CUPS 1.3@ */ # endif /* HAVE_AUTHORIZATION_H */ /**** New in CUPS 1.5 ****/ http_tls_credentials_t tls_credentials; - /* TLS credentials */ + /* TLS credentials @since CUPS 1.5@ */ + _http_timeout_cb_t timeout_cb; /* Timeout callback @since CUPS 1.5@ */ + void *timeout_data; /* User data pointer @since CUPS 1.5@ */ + struct timeval timeout_value; /* Timeout in seconds */ }; @@ -314,6 +319,8 @@ extern void _httpFreeCredentials(http_tls_credentials_t credentials); extern ssize_t _httpPeek(http_t *http, char *buffer, size_t length); extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int log); +extern void _httpSetTimeout(http_t *http, double timeout, + _http_timeout_cb_t cb, void *user_data); extern int _httpWait(http_t *http, int msec, int usessl); diff --git a/cups/http.c b/cups/http.c index defa38859..06ceb0212 100644 --- a/cups/http.c +++ b/cups/http.c @@ -80,6 +80,8 @@ * httpSetExpect() - Set the Expect: header in a request. * httpSetField() - Set the value of an HTTP header. * httpSetLength() - Set the content-length and content-encoding. + * _httpSetTimeout() - Set read/write timeouts and an optional + * callback. * httpTrace() - Send an TRACE request to the server. * httpUpdate() - Update the current HTTP state for incoming * data. @@ -1347,8 +1349,15 @@ httpGets(char *line, /* I - Line to read into */ #ifdef WIN32 DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError())); - if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) + if (WSAGetLastError() == WSAEINTR) continue; + else if (WSAGetLastError() == WSAEWOULDBLOCK) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + + http->error = WSAGetLastError(); + } else if (WSAGetLastError() != http->error) { http->error = WSAGetLastError(); @@ -1358,8 +1367,17 @@ httpGets(char *line, /* I - Line to read into */ #else DEBUG_printf(("3httpGets: recv() error %d!", errno)); - if (errno == EINTR || errno == EAGAIN) + if (errno == EINTR) continue; + else if (errno == EWOULDBLOCK || errno == EAGAIN) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + else if (!http->timeout_cb && errno == EAGAIN) + continue; + + http->error = errno; + } else if (errno != http->error) { http->error = errno; @@ -1925,13 +1943,34 @@ httpRead2(http_t *http, /* I - Connection to server */ else if (bytes < 0) { #ifdef WIN32 - if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK) + if (WSAGetLastError() != WSAEINTR) { http->error = WSAGetLastError(); return (-1); } + else if (WSAGetLastError() == WSAEWOULDBLOCK) + { + if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) + { + http->error = WSAEWOULDBLOCK; + return (-1); + } + } #else - if (errno != EINTR && errno != EAGAIN) + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) + { + http->error = errno; + return (-1); + } + else if (!http->timeout_cb && errno != EAGAIN) + { + http->error = errno; + return (-1); + } + } + else if (errno != EINTR) { http->error = errno; return (-1); @@ -1979,13 +2018,29 @@ httpRead2(http_t *http, /* I - Connection to server */ CUPS_LLCAST length)); #ifdef WIN32 - while ((bytes = (ssize_t) recv(http->fd, buffer, (int)length, 0)) < 0) - if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK) + while ((bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0)) < 0) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) + { + if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) + break; + } + else if (WSAGetLastError() != WSAEINTR) break; + } #else while ((bytes = recv(http->fd, buffer, length, 0)) < 0) - if (errno != EINTR && errno != EAGAIN) + { + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) + break; + else if (!http->timeout_cb && errno != EAGAIN) + break; + } + else if (errno != EINTR) break; + } #endif /* WIN32 */ DEBUG_printf(("2httpRead2: read " CUPS_LLFMT " bytes from socket...", @@ -2004,12 +2059,12 @@ httpRead2(http_t *http, /* I - Connection to server */ else if (bytes < 0) { #ifdef WIN32 - if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) + if (WSAGetLastError() == WSAEINTR) bytes = 0; else http->error = WSAGetLastError(); #else - if (errno == EINTR || errno == EAGAIN) + if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb)) bytes = 0; else http->error = errno; @@ -2216,6 +2271,14 @@ httpReconnect(http_t *http) /* I - Connection to server */ DEBUG_printf(("2httpReconnect: New socket=%d", http->fd)); + if (http->timeout_value.tv_sec > 0) + { + setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value), + sizeof(http->timeout_value)); + setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value), + sizeof(http->timeout_value)); + } + http->hostaddr = &(addr->addr); http->error = 0; http->status = HTTP_CONTINUE; @@ -2470,6 +2533,39 @@ httpSetLength(http_t *http, /* I - Connection to server */ } +/* + * '_httpSetTimeout()' - Set read/write timeouts and an optional callback. + * + * The optional timeout callback receives both the HTTP connection and a user + * data pointer and must return 1 to continue or 0 to error out. + */ + +void +_httpSetTimeout( + http_t *http, /* I - Connection to server */ + double timeout, /* I - Number of seconds for timeout, + must be greater than 0 */ + _http_timeout_cb_t cb, /* I - Callback function or NULL */ + void *user_data) /* I - User data pointer */ +{ + if (!http || timeout <= 0.0) + return; + + http->timeout_cb = cb; + http->timeout_data = user_data; + http->timeout_value.tv_sec = (int)timeout; + http->timeout_value.tv_usec = (int)(timeout * 1000000) % 1000000; + + if (http->fd >= 0) + { + setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value), + sizeof(http->timeout_value)); + setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value), + sizeof(http->timeout_value)); + } +} + + /* * 'httpTrace()' - Send an TRACE request to the server. */ @@ -4175,16 +4271,34 @@ http_write(http_t *http, /* I - Connection to server */ if (bytes < 0) { #ifdef WIN32 - if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) + if (WSAGetLastError() == WSAEINTR) continue; - else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET) + else if (WSAGetLastError() == WSAEWOULDBLOCK) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + + http->error = WSAGetLastError(); + } + else if (WSAGetLastError() != http->error && + WSAGetLastError() != WSAECONNRESET) { http->error = WSAGetLastError(); continue; } + #else - if (errno == EINTR || errno == EAGAIN) + if (errno == EINTR) continue; + else if (errno == EWOULDBLOCK || errno == EAGAIN) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + else if (!http->timeout_cb && errno == EAGAIN) + continue; + + http->error = errno; + } else if (errno != http->error && errno != ECONNRESET) { http->error = errno; diff --git a/cups/libcups2.def b/cups/libcups2.def index a34c70032..798c82f65 100644 --- a/cups/libcups2.def +++ b/cups/libcups2.def @@ -24,6 +24,7 @@ _cups_strcpy _cups_strlcat _cups_strlcpy _httpResolveURI +_httpSetTimeout _ippAddAttr _ippAttrString _ippFindOption diff --git a/cups/pwg-ppd.c b/cups/pwg-ppd.c index 5307019c7..1bfd26d9e 100644 --- a/cups/pwg-ppd.c +++ b/cups/pwg-ppd.c @@ -95,7 +95,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ int similar; /* Are the old and new size similar? */ _pwg_size_t *old_size; /* Current old size */ int old_imageable, /* Old imageable length in 2540ths */ - old_borderless; /* Old borderless state */ + old_borderless, /* Old borderless state */ + old_known_pwg; /* Old PWG name is well-known */ int new_width, /* New width in 2540ths */ new_length, /* New length in 2540ths */ new_left, /* New left margin in 2540ths */ @@ -103,7 +104,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ new_right, /* New right margin in 2540ths */ new_top, /* New top margin in 2540ths */ new_imageable, /* New imageable length in 2540ths */ - new_borderless; /* New borderless state */ + new_borderless, /* New borderless state */ + new_known_pwg; /* New PWG name is well-known */ _pwg_size_t *new_size; /* New size to add, if any */ @@ -178,7 +180,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * Standard name and no conflicts, use it! */ - pwg_name = pwg_media->pwg; + pwg_name = pwg_media->pwg; + new_known_pwg = 1; } else { @@ -188,7 +191,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * pp_lowerppd_WIDTHxHEIGHTuu */ - pwg_name = pwg_keyword; + pwg_name = pwg_keyword; + new_known_pwg = 0; pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name)); _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name, @@ -208,8 +212,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ new_right = _PWG_FROMPTS(ppd_size->width - ppd_size->right); new_top = _PWG_FROMPTS(ppd_size->length - ppd_size->top); new_imageable = new_length - new_top - new_bottom; - new_borderless = (new_bottom == 0 && new_top == 0) || - (new_left == 0 && new_right == 0); + new_borderless = new_bottom == 0 && new_top == 0 && + new_left == 0 && new_right == 0; for (k = pwg->num_sizes, similar = 0, old_size = pwg->sizes, new_size = NULL; k > 0 && !similar; @@ -218,16 +222,20 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ old_imageable = old_size->length - old_size->top - old_size->bottom; old_borderless = old_size->left == 0 && old_size->bottom == 0 && old_size->right == 0 && old_size->top == 0; - + old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) && + strncmp(old_size->map.pwg, "om_", 3); + similar = old_borderless == new_borderless && _PWG_EQUIVALENT(old_size->width, new_width) && _PWG_EQUIVALENT(old_size->length, new_length); - if (similar && new_imageable > old_imageable) + if (similar && + (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable))) { /* - * The new paper has a larger imageable area so it will replace - * the older paper. + * The new paper has a larger imageable area so it could replace + * the older paper. Regardless of the imageable area, we always + * prefer the size with a well-known PWG name. */ new_size = old_size; diff --git a/cups/request.c b/cups/request.c index 8b7a32941..df2c0137c 100644 --- a/cups/request.c +++ b/cups/request.c @@ -803,6 +803,7 @@ cupsWriteRequestData( if ((http = cg->http) == NULL) { _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1); + DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR."); return (HTTP_ERROR); } } @@ -814,7 +815,11 @@ cupsWriteRequestData( wused = http->wused; if (httpWrite2(http, buffer, length) < 0) + { + DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR."); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0); return (HTTP_ERROR); + } /* * Finally, check if we have any pending data from the server... @@ -833,12 +838,17 @@ cupsWriteRequestData( http_status_t status; /* Status from httpUpdate */ if ((status = httpUpdate(http)) >= HTTP_BAD_REQUEST) + { + _cupsSetHTTPError(status); httpFlush(http); + } + DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status)); return (status); } } + DEBUG_puts("1cupsWriteRequestData: Returning HTTP_CONTINUE."); return (HTTP_CONTINUE); } @@ -1004,6 +1014,10 @@ _cupsSetHTTPError(http_status_t status) /* I - HTTP status code */ _cupsSetError(IPP_PKI_ERROR, httpStatus(status), 0); break; + case HTTP_ERROR : + _cupsSetError(IPP_INTERNAL_ERROR, httpStatus(status), 0); + break; + default : DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to " "IPP_SERVICE_UNAVAILABLE!", status)); diff --git a/cups/usersys.c b/cups/usersys.c index abee546c3..20a38db2d 100644 --- a/cups/usersys.c +++ b/cups/usersys.c @@ -539,91 +539,45 @@ _cupsSetDefaults(void) cups_expiredcerts = getenv("CUPS_EXPIREDCERTS"); /* - * Then, if needed, the .cups/client.conf or .cupsrc file in the home - * directory... + * Then, if needed, read the ~/.cups/client.conf or /etc/cups/client.conf + * files to get the default values... */ - if ((cg->encryption == (http_encryption_t)-1 || !cg->server[0] || - !cg->ipp_port) && (home = getenv("HOME")) != NULL) - { - /* - * Look for ~/.cups/client.conf... - */ - - snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home); - if ((fp = cupsFileOpen(filename, "r")) != NULL) - { - cups_read_client_conf(fp, cg, cups_encryption, cups_server, - cups_anyroot, cups_expiredroot, - cups_expiredcerts); - - cupsFileClose(fp); - } - } - if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] || !cg->ipp_port) { - /* - * Look for CUPS_SERVERROOT/client.conf... - */ - - snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot); - if ((fp = cupsFileOpen(filename, "r")) != NULL) + if ((home = getenv("HOME")) != NULL) { - cups_read_client_conf(fp, cg, cups_encryption, cups_server, - cups_anyroot, cups_expiredroot, - cups_expiredcerts); - cupsFileClose(fp); - } - } - - /* - * If we still have things that aren't set, use the compiled in defaults... - */ + /* + * Look for ~/.cups/client.conf... + */ - if (cg->encryption == (http_encryption_t)-1) - cg->encryption = HTTP_ENCRYPT_IF_REQUESTED; + snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home); + fp = cupsFileOpen(filename, "r"); + } + else + fp = NULL; - if (!cg->server[0]) - { - if (!cups_server) + if (!fp) { -#ifdef CUPS_DEFAULT_DOMAINSOCKET /* - * If we are compiled with domain socket support, only use the - * domain socket if it exists and has the right permissions... + * Look for CUPS_SERVERROOT/client.conf... */ - struct stat sockinfo; /* Domain socket information */ - - if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) && - (sockinfo.st_mode & S_IRWXO) == S_IRWXO) - cups_server = CUPS_DEFAULT_DOMAINSOCKET; - else -#endif /* CUPS_DEFAULT_DOMAINSOCKET */ - cups_server = "localhost"; + snprintf(filename, sizeof(filename), "%s/client.conf", + cg->cups_serverroot); + fp = cupsFileOpen(filename, "r"); } - cupsSetServer(cups_server); - } - - if (!cg->ipp_port) - { - const char *ipp_port; /* IPP_PORT environment variable */ - struct servent *service; /* Port number info */ - + /* + * Read the configuration file and apply any environment variables; both + * functions handle NULL cups_file_t pointers... + */ - if ((ipp_port = getenv("IPP_PORT")) != NULL) - { - if ((cg->ipp_port = atoi(ipp_port)) <= 0) - cg->ipp_port = CUPS_DEFAULT_IPP_PORT; - } - else if ((service = getservbyname("ipp", NULL)) == NULL || - service->s_port <= 0) - cg->ipp_port = CUPS_DEFAULT_IPP_PORT; - else - cg->ipp_port = ntohs(service->s_port); + cups_read_client_conf(fp, cg, cups_encryption, cups_server, + cups_anyroot, cups_expiredroot, + cups_expiredcerts); + cupsFileClose(fp); } } @@ -738,6 +692,44 @@ cups_read_client_conf( cg->ipp_port = atoi(value); } + if (!cg->server[0]) + { +#ifdef CUPS_DEFAULT_DOMAINSOCKET + /* + * If we are compiled with domain socket support, only use the + * domain socket if it exists and has the right permissions... + */ + + struct stat sockinfo; /* Domain socket information */ + + if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) && + (sockinfo.st_mode & S_IRWXO) == S_IRWXO) + cups_server = CUPS_DEFAULT_DOMAINSOCKET; + else +#endif /* CUPS_DEFAULT_DOMAINSOCKET */ + cups_server = "localhost"; + + cupsSetServer(cups_server); + } + + if (!cg->ipp_port) + { + const char *ipp_port; /* IPP_PORT environment variable */ + struct servent *service; /* Port number info */ + + + if ((ipp_port = getenv("IPP_PORT")) != NULL) + { + if ((cg->ipp_port = atoi(ipp_port)) <= 0) + cg->ipp_port = CUPS_DEFAULT_IPP_PORT; + } + else if ((service = getservbyname("ipp", NULL)) == NULL || + service->s_port <= 0) + cg->ipp_port = CUPS_DEFAULT_IPP_PORT; + else + cg->ipp_port = ntohs(service->s_port); + } + if (cups_anyroot) cg->any_root = !strcasecmp(cups_anyroot, "yes") || !strcasecmp(cups_anyroot, "on") || diff --git a/doc/cups-printable.css b/doc/cups-printable.css index cc11262fd..42ea2bee1 100644 --- a/doc/cups-printable.css +++ b/doc/cups-printable.css @@ -16,7 +16,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/cups.css b/doc/cups.css index 8ec40856f..4d76d6332 100644 --- a/doc/cups.css +++ b/doc/cups.css @@ -19,8 +19,11 @@ PRE { } PRE.command { + background: #f0f0f0; + border: dotted thin #7f7f7f; color: #7f0000; margin-left: 36pt; + padding: 10px; } P.example { diff --git a/doc/help/api-array.html b/doc/help/api-array.html index fec426de9..2b47b3e13 100644 --- a/doc/help/api-array.html +++ b/doc/help/api-array.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -394,6 +396,7 @@ div.contents ul.subcontents li {
  • cupsArrayLast
  • cupsArrayNew
  • cupsArrayNew2
  • +
  • cupsArrayNew3
  • cupsArrayNext
  • cupsArrayPrev
  • cupsArrayRemove
  • @@ -402,6 +405,8 @@ div.contents ul.subcontents li {
  • cupsArrayUserData
  • Data Types
      +
    • cups_acopy_func_t
    • +
    • cups_afree_func_t
    • cups_ahash_func_t
    • cups_array_func_t
    • cups_array_t
    • @@ -439,8 +444,9 @@ data.

      Managing Arrays

      Arrays are created using either the -cupsArrayNew or -cupsArrayNew2 functions. The +cupsArrayNew, +cupsArrayNew2, or +cupsArrayNew3 functions. The first function creates a new array with the specified callback function and user data pointer:

      @@ -477,7 +483,7 @@ static int compare_func(void *first, void *second, void *user_data); static int hash_func(void *element, void *user_data); void *user_data; -cups_array_t *array = cupsArrayNew2(compare_func, user_data, hash_func, HASH_SIZE); +cups_array_t *hash_array = cupsArrayNew2(compare_func, user_data, hash_func, HASH_SIZE);

      The hash function (type @@ -488,6 +494,25 @@ element and is called whenever you look up an element in the array with only limited by available memory, but generally should not be larger than 16384 to realize any performance improvement.

      +

      The cupsArrayNew3 function adds +copy and free callbacks to support basic memory management of elements:

      + +
      +#include <cups/array.h>
      +
      +#define HASH_SIZE 512 /* Size of hash table */
      +
      +static int compare_func(void *first, void *second, void *user_data);
      +static void *copy_func(void *element, void *user_data);
      +static void free_func(void *element, void *user_data);
      +static int hash_func(void *element, void *user_data);
      +
      +void *user_data;
      +cups_array_t *array = cupsArrayNew3(compare_func, user_data, NULL, 0, copy_func, free_func);
      +
      +cups_array_t *hash_array = cupsArrayNew3(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func);
      +
      +

      Once you have created the array, you add elements using the cupsArrayAdd cupsArrayInsert functions. @@ -536,8 +561,7 @@ example:

      Finally, you free the memory used by the array using the cupsArrayDelete function. All of the memory for the array and hash table (if any) is freed, however CUPS -does not free the elements - if necessary, you must allocate and free the -elements yourself.

      +does not free the elements unless you provide copy and free functions.

      Finding and Enumerating Elements

      @@ -848,6 +872,50 @@ like strcmp can be used for sorted string arrays.
      The hash function ("h") is used to implement cached lookups with the specified hash size ("hsize"). +

      +

       CUPS 1.5 cupsArrayNew3

      +

      Create a new array with hash and/or free function.

      +

      +cups_array_t *cupsArrayNew3 (
      +    cups_array_func_t f,
      +    void *d,
      +    cups_ahash_func_t h,
      +    int hsize,
      +    cups_acopy_func_t cf,
      +    cups_afree_func_t ff
      +);

      +

      Parameters

      +
      +
      f
      +
      Comparison function or NULL for an unsorted array
      +
      d
      +
      User data or NULL
      +
      h
      +
      Hash function or NULL for unhashed lookups
      +
      hsize
      +
      Hash size (>= 0)
      +
      cf
      +
      Copy function
      +
      ff
      +
      Free function
      +
      +

      Return Value

      +

      Array

      +

      Discussion

      +

      The comparison function ("f") is used to create a sorted array. The function +receives pointers to two elements and the user data pointer ("d") - the user +data pointer argument can safely be omitted when not required so functions +like strcmp can be used for sorted string arrays.
      +
      +The hash function ("h") is used to implement cached lookups with the +specified hash size ("hsize").
      +
      +The copy function ("cf") is used to automatically copy/retain elements when +added or the array is copied.
      +
      +The free function ("cf") is used to automatically free/release elements when +removed or the array is deleted. +

       CUPS 1.2/Mac OS X 10.5 cupsArrayNext

      Get the next element in the array.

      @@ -963,6 +1031,16 @@ void *cupsArrayUserData (

      Return Value

      User data

      Data Types

      +

      cups_acopy_func_t

      +

      Array element copy function

      +

      +typedef void *(*cups_acopy_func_t)(void *element, void *data); +

      +

      cups_afree_func_t

      +

      Array element free function

      +

      +typedef void (*cups_afree_func_t)(void *element, void *data); +

      cups_ahash_func_t

      Array hash function

      diff --git a/doc/help/api-cgi.html b/doc/help/api-cgi.html index bdcd5c21f..a1b75197f 100644 --- a/doc/help/api-cgi.html +++ b/doc/help/api-cgi.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-cups.html b/doc/help/api-cups.html index d53d09f0f..796248bba 100644 --- a/doc/help/api-cups.html +++ b/doc/help/api-cups.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -428,8 +430,6 @@ for the given language.">cupsLangEncoding

    • cupsLangFlush
    • cupsLangFree
    • cupsLangGet
    • -
    • cupsLastError
    • -
    • cupsLastErrorString
    • cupsNotifySubject
    • cupsNotifyText
    • cupsParseOptions
    • @@ -443,6 +443,9 @@ specified server.">cupsPrintFiles2
    • cupsRemoveDest
    • cupsRemoveOption
    • cupsServer
    • +
    • cupsSetClientCertCB
    • +
    • cupsSetCredentials
    • cupsSetDefaultDest
    • cupsSetDests
    • cupsSetDests2
    • @@ -450,6 +453,7 @@ specified server.">cupsPrintFiles2
    • cupsSetPasswordCB
    • cupsSetPasswordCB2
    • cupsSetServer
    • +
    • cupsSetServerCertCB
    • cupsSetUser
    • cupsStartDocument
    • cupsTempFd
    • @@ -458,6 +462,7 @@ specified server.">cupsPrintFiles2
    • cupsUser
  • Data Types
  • Structures
    • cups_dest_s
    • @@ -1716,18 +1722,6 @@ cups_lang_t *cupsLangGet (

      Return Value

      Language data

      -

      cupsLastError

      -

      Return the last IPP status code.

      -

      -ipp_status_t cupsLastError (void);

      -

      Return Value

      -

      IPP status code from last request

      -

       CUPS 1.2/Mac OS X 10.5 cupsLastErrorString

      -

      Return the last IPP status-message.

      -

      -const char *cupsLastErrorString (void);

      -

      Return Value

      -

      status-message text from last request

       CUPS 1.2/Mac OS X 10.5 cupsNotifySubject

      Return the subject for the given notification message.

      @@ -1975,6 +1969,48 @@ Note: The current server is tracked separately for each thread in a program. Multi-threaded programs that override the server via the cupsSetServer function need to do so in each thread for the same server to be used.

      +

       CUPS 1.5 cupsSetClientCertCB

      +

      Set the client certificate callback.

      +

      +void cupsSetClientCertCB (
      +    cups_client_cert_cb_t cb,
      +    void *user_data
      +);

      +

      Parameters

      +
      +
      cb
      +
      Callback function
      +
      user_data
      +
      User data pointer
      +
      +

      Discussion

      +

      Pass NULL to restore the default callback.
      +
      +Note: The current certificate callback is tracked separately for each thread +in a program. Multi-threaded programs that override the callback need to do +so in each thread for the same callback to be used. + +

      +

       CUPS 1.5 cupsSetCredentials

      +

      Set the default credentials to be used for SSL/TLS +connections.

      +

      +int cupsSetCredentials (
      +    cups_array_t *credentials
      +);

      +

      Parameters

      +
      +
      credentials
      +
      Array of credentials
      +
      +

      Return Value

      +

      Status of call (0 = success)

      +

      Discussion

      +

      Note: The default credentials are tracked separately for each thread in a +program. Multi-threaded programs that override the setting need to do so in +each thread for the same setting to be used. + +

       CUPS 1.3/Mac OS X 10.5 cupsSetDefaultDest

      Set the default destination.

      @@ -2122,6 +2158,28 @@ default server name and port.
      Note: The current server is tracked separately for each thread in a program. Multi-threaded programs that override the server need to do so in each thread for the same server to be used.

      +

       CUPS 1.5 cupsSetServerCertCB

      +

      Set the server certificate callback.

      +

      +void cupsSetServerCertCB (
      +    cups_server_cert_cb_t cb,
      +    void *user_data
      +);

      +

      Parameters

      +
      +
      cb
      +
      Callback function
      +
      user_data
      +
      User data pointer
      +
      +

      Discussion

      +

      Pass NULL to restore the default callback.
      +
      +Note: The current credentials callback is tracked separately for each thread +in a program. Multi-threaded programs that override the callback need to do +so in each thread for the same callback to be used. + +

      cupsSetUser

      Set the default user name.

      @@ -2251,6 +2309,11 @@ program. Multi-threaded programs that override the user name with the cupsSetUser function need to do so in each thread for the same user name to be used.

      Data Types

      +

       CUPS 1.5 cups_client_cert_cb_t

      +

      Client credentials callback

      +

      +typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls, cups_array_t *distinguished_names, void *user_data); +

      cups_dest_t

      Destination

      @@ -2286,6 +2349,11 @@ typedef const char *(*cups_password_cb_t)(const char *prompt);

      typedef unsigned cups_ptype_t;

      +

       CUPS 1.5 cups_server_cert_cb_t

      +

      Server credentials callback

      +

      +typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls, cups_array_t *certs, void *user_data); +

      Structures

      cups_dest_s

      Destination

      diff --git a/doc/help/api-driver.html b/doc/help/api-driver.html index 4f221310b..2f456ea0c 100644 --- a/doc/help/api-driver.html +++ b/doc/help/api-driver.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-filedir.html b/doc/help/api-filedir.html index 7f4dd9473..d79857834 100644 --- a/doc/help/api-filedir.html +++ b/doc/help/api-filedir.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-filter.html b/doc/help/api-filter.html index 568aa07b8..48ed8dcb4 100644 --- a/doc/help/api-filter.html +++ b/doc/help/api-filter.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -375,7 +377,7 @@ div.contents ul.subcontents li { Programming: Raster API
      Programming: Developing PostScript Printer Drivers
      Programming: Developing Raster Printer Drivers
      - Specifications: CUPS Design Description + Specifications: CUPS Design Description diff --git a/doc/help/api-httpipp.html b/doc/help/api-httpipp.html index 6753a8d92..98878ddab 100644 --- a/doc/help/api-httpipp.html +++ b/doc/help/api-httpipp.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -393,11 +395,14 @@ div.contents ul.subcontents li {
    • cupsGetFd
    • cupsGetFile
    • cupsGetResponse
    • +
    • cupsLastError
    • +
    • cupsLastErrorString
    • cupsPutFd
    • cupsPutFile
    • cupsReadResponseData
    • cupsSendRequest
    • cupsWriteRequestData
    • +
    • httpAddCredential
    • httpAddrAny
    • httpAddrEqual
    • httpAddrLength
    • @@ -412,9 +417,11 @@ components with a formatted resource.">httpAssembleURIf
    • httpCheck
    • httpClearCookie
    • httpClearFields
    • -
    • httpClose
    • +
    • httpClose
    • httpConnect
    • httpConnectEncrypt
    • +
    • httpCopyCredentials
    • httpDecode64
    • httpDecode64_2
    • httpDelete
    • @@ -424,6 +431,7 @@ components with a formatted resource.">httpAssembleURIf
    • httpError
    • httpFlush
    • httpFlushWrite
    • +
    • httpFreeCredentials
    • httpGet
    • httpGetAuthString
    • httpGetBlocking
    • @@ -465,7 +473,9 @@ components.">httpSeparate2
    • httpSeparateURI
    • httpSetAuthString
    • -
    • httpSetCookie
    • +
    • httpSetCookie
    • +
    • httpSetCredentials
    • httpSetExpect
    • httpSetField
    • httpSetLength
    • @@ -525,6 +535,7 @@ used to enumerate all of the addresses that are associated with a hostname. ">http_addrlist_t
    • http_auth_t
    • +
    • http_credential_t
    • http_encoding_t
    • http_encryption_t
    • http_field_t
    • @@ -557,6 +568,7 @@ are server-oriented...">http_state_t used to enumerate all of the addresses that are associated with a hostname. ">http_addrlist_s +
    • http_credential_s
    • ipp_attribute_s
    • ipp_s
  • @@ -1172,6 +1184,18 @@ cupsSendDocument() or cupsSendRequest(). For requests that return additional data, use httpRead() after getting a successful response.

    +

    cupsLastError

    +

    Return the last IPP status code.

    +

    +ipp_status_t cupsLastError (void);

    +

    Return Value

    +

    IPP status code from last request

    +

     CUPS 1.2/Mac OS X 10.5 cupsLastErrorString

    +

    Return the last IPP status-message.

    +

    +const char *cupsLastErrorString (void);

    +

    Return Value

    +

    status-message text from last request

     CUPS 1.1.20/Mac OS X 10.4 cupsPutFd

    Put a file on the server.

    @@ -1269,7 +1293,7 @@ files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.

    Discussion

    Use httpWrite() to write any additional data (document, PPD file, etc.) for the request, cupsGetResponse() to get the IPP response, and httpRead() -to read any additional data following the response. Only one request can be +to read any additional data following the response. Only one request can be sent/queued at a time.

    Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the @@ -1299,6 +1323,29 @@ request is not freed.

    This function is used after cupsSendRequest to provide a PPD and after cupsStartDocument to provide a document file. +

    +

     CUPS 1.5 httpAddCredential

    +

    Allocates and adds a single credential to an array.

    +

    +int httpAddCredential (
    +    cups_array_t *credentials,
    +    const void *data,
    +    size_t datalen
    +);

    +

    Parameters

    +
    +
    credentials
    +
    Credentials array
    +
    data
    +
    PEM-encoded X.509 data
    +
    datalen
    +
    Length of data
    +
    +

    Return Value

    +

    0 on success, -1 on error

    +

    Discussion

    +

    Use cupsArrayNew(NULL, NULL) to create a credentials array. +

     CUPS 1.2/Mac OS X 10.5 httpAddrAny

    Check for the "any" address.

    @@ -1531,7 +1578,7 @@ void httpClearFields (
    Connection to server

    httpClose

    -

    Close an HTTP connection...

    +

    Close an HTTP connection.

    void httpClose (
        http_t *http
    @@ -1580,6 +1627,23 @@ void httpClose (

    Return Value

    New HTTP connection

    +

     CUPS 1.5 httpCopyCredentials

    +

    Copy the credentials associated with an encrypted +connection.

    +

    +int httpCopyCredentials (
    +    http_t *http,
    +    cups_array_t **credentials
    +);

    +

    Parameters

    +
    +
    http
    +
    Connection to server
    +
    credentials
    +
    Array of credentials
    +
    +

    Return Value

    +

    Status of call (0 = success)

     DEPRECATED httpDecode64

    Base64-decode a string.

    @@ -1732,6 +1796,17 @@ int httpFlushWrite (

    Return Value

    Bytes written or -1 on error

    +

    httpFreeCredentials

    +

    Free an array of credentials.

    +

    +void httpFreeCredentials (
    +    cups_array_t *credentials
    +);

    +

    Parameters

    +
    +
    credentials
    +
    Array of credentials
    +

    httpGet

    Send a GET request to the server.

    @@ -2356,7 +2431,7 @@ httpHead(), httpOptions(), httpPost, or httpPut().

     CUPS 1.1.19/Mac OS X 10.3 httpSetCookie

    -

    Set the cookie value(s)...

    +

    Set the cookie value(s).

    void httpSetCookie (
        http_t *http,
    @@ -2369,6 +2444,23 @@ void httpSetCookie (

    cookie
    Cookie string
    +

     CUPS 1.5 httpSetCredentials

    +

    Set the credentials associated with an encrypted +connection.

    +

    +int httpSetCredentials (
    +    http_t *http,
    +    cups_array_t *credentials
    +);

    +

    Parameters

    +
    +
    http
    +
    Connection to server
    +
    credentials
    +
    Array of credentials
    +
    +

    Return Value

    +

    Status of call (0 = success)

     CUPS 1.2/Mac OS X 10.5 httpSetExpect

    Set the Expect: header in a request.

    @@ -3267,6 +3359,11 @@ typedef struct http_addrlist_s / http_addrlist_t;

    typedef enum http_auth_e http_auth_t;

    +

     CUPS 1.5 http_credential_t

    +

    Credential data

    +

    +typedef struct http_credential_s http_credential_t; +

    http_encoding_t

    HTTP transfer encoding values

    @@ -3308,7 +3405,7 @@ typedef struct _http_s http_t;

    typedef enum http_uri_coding_e http_uri_coding_t;

    -

     CUPS1.2 http_uri_status_t

    +

     CUPS 1.2 http_uri_status_t

    URI separation status

    typedef enum http_uri_status_e http_uri_status_t; @@ -3410,6 +3507,19 @@ with a hostname.

    next
    Pointer to next address in list
    +

     CUPS 1.5 http_credential_s

    +

    Credential data

    +

    struct http_credential_s {
    +    void *data;
    +    size_t datalen;
    +};

    +

    Members

    +
    +
    data
    +
    Pointer to credential data
    +
    datalen
    +
    Credential length
    +

    ipp_attribute_s

    Attribute

    struct ipp_attribute_s {
    @@ -3460,8 +3570,8 @@ with a hostname.

    Request header
    state
    State of request
    -
    use
    -
    Use count
    +
    use  CUPS 1.4.4/Mac OS X 10.6.? 
    +
    Use count

    Unions

    ipp_request_u

    @@ -3646,8 +3756,8 @@ are server-oriented...

    HTTP_ACCEPTED
    DELETE command was successful
    -
    HTTP_AUTHORIZATION_CANCELED
    -
    User cancelled authorization
    +
    HTTP_AUTHORIZATION_CANCELED  CUPS 1.4 
    +
    User canceled authorization
    HTTP_BAD_GATEWAY
    Bad gateway
    HTTP_BAD_REQUEST
    @@ -3698,6 +3808,8 @@ are server-oriented...

    Only a partial file was recieved/sent
    HTTP_PAYMENT_REQUIRED
    Payment required
    +
    HTTP_PKI_ERROR  CUPS 1.5 
    +
    Error negotiating a secure connection
    HTTP_PRECONDITION
    Precondition failed
    HTTP_PROXY_AUTHENTICATION
    @@ -3748,7 +3860,7 @@ are server-oriented...

    HTTP_URI_CODING_USERNAME
    En/decode the username portion
    -

     CUPS1.2 http_uri_status_e

    +

     CUPS 1.2 http_uri_status_e

    URI separation status

    Constants

    @@ -4032,6 +4144,8 @@ are server-oriented...

    client-error-attributes-or-values-not-supported
    IPP_ATTRIBUTES_NOT_SETTABLE
    client-error-attributes-not-settable
    +
    IPP_AUTHENTICATION_CANCELED  CUPS 1.5 
    +
    Authentication canceled by user
    IPP_BAD_REQUEST
    client-error-bad-request
    IPP_CHARSET
    @@ -4092,6 +4206,8 @@ are server-oriented...

    successful-ok-too-many-events
    IPP_OPERATION_NOT_SUPPORTED
    server-error-operation-not-supported
    +
    IPP_PKI_ERROR  CUPS 1.5 
    +
    Error negotiating a secure connection
    IPP_PRINTER_BUSY
    server-error-busy
    IPP_PRINTER_IS_DEACTIVATED
    @@ -4110,6 +4226,8 @@ are server-oriented...

    client-error-timeout
    IPP_TOO_MANY_SUBSCRIPTIONS
    client-error-too-many-subscriptions
    +
    IPP_UPGRADE_REQUIRED
    +
    TLS upgrade required
    IPP_URI_SCHEME
    client-error-uri-scheme-not-supported
    IPP_VERSION_NOT_SUPPORTED
    diff --git a/doc/help/api-mime.html b/doc/help/api-mime.html index 7b428490e..e904ddbd5 100644 --- a/doc/help/api-mime.html +++ b/doc/help/api-mime.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-overview.html b/doc/help/api-overview.html index a5eb498a2..bdd3f612b 100644 --- a/doc/help/api-overview.html +++ b/doc/help/api-overview.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-ppd.html b/doc/help/api-ppd.html index 6ac61beec..c6d6077ca 100644 --- a/doc/help/api-ppd.html +++ b/doc/help/api-ppd.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -1805,7 +1807,6 @@ typedef enum ppd_ui_e ppd_ui_t;     char *product;
        ppd_profile_t *profiles;
        char *protocols;
    -    void *pwg;
        char *shortnickname;
        ppd_size_t *sizes;
        int throughput;
    @@ -1888,8 +1889,6 @@ typedef enum ppd_ui_e ppd_ui_t;
    sRGB color profiles
    protocols  CUPS 1.1.19/Mac OS X 10.3 
    Protocols (BCP, TBCP) string
    -
    pwg
    -
    PWG to/from PPD mappings
    shortnickname
    Short version of nickname
    sizes
    diff --git a/doc/help/api-ppdc.html b/doc/help/api-ppdc.html index d8bef72bb..e02f71d05 100644 --- a/doc/help/api-ppdc.html +++ b/doc/help/api-ppdc.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { diff --git a/doc/help/api-raster.html b/doc/help/api-raster.html index 93c816b88..3d7875cdc 100644 --- a/doc/help/api-raster.html +++ b/doc/help/api-raster.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -340,9 +342,9 @@ div.contents ul.subcontents li { +

    Developing PostScript Printer Drivers

    This document describes how to develop printer drivers for PostScript printers. Topics include: printer driver basics, creating new PPD files, importing existing PPD files, using custom filters, implementing color management, and adding Mac OS X features.

    diff --git a/doc/help/ppd-compiler.html b/doc/help/ppd-compiler.html index c00d4dbdd..9a40ca88e 100644 --- a/doc/help/ppd-compiler.html +++ b/doc/help/ppd-compiler.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -337,6 +339,21 @@ div.contents ul.subcontents li {
    + +

    Introduction to the PPD Compiler

    This document describes how to use the CUPS PostScript Printer Description diff --git a/doc/help/raster-driver.html b/doc/help/raster-driver.html index fc85337c4..40346a66a 100644 --- a/doc/help/raster-driver.html +++ b/doc/help/raster-driver.html @@ -24,7 +24,9 @@ PRE { } PRE.command { + border: dotted thin #7f7f7f; margin-left: 36pt; + padding: 10px; } P.compact { @@ -337,6 +339,21 @@ div.contents ul.subcontents li {

    + +

    Developing Raster Printer Drivers

    This document describes how to develop printer drivers for raster printers. Topics include: printer driver basics, creating new PPD files, using filters, implementing color management, and adding Mac OS X features.

    diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in index a35ca4af6..d3610cb84 100644 --- a/doc/help/ref-cupsd-conf.html.in +++ b/doc/help/ref-cupsd-conf.html.in @@ -1479,6 +1479,48 @@ the file is assumed to be relative to the ServerRoot directory.

    +

    CUPS 1.5JobPrivateAccess

    + +

    Examples

    + +
    +JobPrivateAccess all
    +JobPrivateAccess default
    +JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
    +
    + +

    Description

    + +

    The JobPrivateAccess directive specifies the access list for a +job's private values. The "default" access list is "@OWNER @SYSTEM". "@ACL" maps +to the printer's requesting-user-name-allowed or requesting-user-name-denied +values.

    + +

    The JobPrivateAccess directive must appear inside a Policy section.

    + + +

    CUPS 1.5JobPrivateValues

    + +

    Examples

    + +
    +JobPrivateValues all
    +JobPrivateValues default
    +JobPrivateValues none
    +JobPrivateValues attribute-name-1 [ ... attribute-name-N ]
    +
    + +

    Description

    + +

    The JobPrivateValues directive specifies the list of job values +to make private. The "default" values are "job-name", +"job-originating-host-name", and "job-originating-user-name".

    + +

    The JobPrivateValues directive must appear inside a Policy section.

    + +

    CUPS 1.2/Mac OS X 10.5JobRetryInterval

    Examples

    @@ -2985,6 +3027,49 @@ on for secure connections. Multiple SSLPort lines can be specified to listen on multiple ports.

    +

    CUPS 1.5SubscriptionPrivateAccess

    + +

    Examples

    + +
    +SubscriptionPrivateAccess all
    +SubscriptionPrivateAccess default
    +SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
    +
    + +

    Description

    + +

    The SubscriptionPrivateAccess directive specifies the access list for a +subscription's private values. The "default" access list is "@OWNER @SYSTEM". +"@ACL" maps to the printer's requesting-user-name-allowed or +requesting-user-name-denied values.

    + +

    The SubscriptionPrivateAccess directive must appear inside a Policy section.

    + + +

    CUPS 1.5SubscriptionPrivateValues

    + +

    Examples

    + +
    +SubscriptionPrivateValues all
    +SubscriptionPrivateValues default
    +SubscriptionPrivateValues none
    +SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ]
    +
    + +

    Description

    + +

    The SubscriptionPrivateValues directive specifies the list of +subscription values to make private. The "default" values are "notify-events", +"notify-pull-method", "notify-recipient-uri", "notify-subscriber-user-name", and +"notify-user-data".

    + +

    The SubscriptionPrivateValues directive must appear inside a Policy section.

    + +

    SystemGroup

    Examples

    diff --git a/doc/help/spec-ppd.html b/doc/help/spec-ppd.html index 3c81a763c..1343d71f2 100644 --- a/doc/help/spec-ppd.html +++ b/doc/help/spec-ppd.html @@ -2,15 +2,347 @@ - CUPS PPD Extensions - - +CUPS PPD Extensions + + + +
    +

    Developing PostScript Printer Drivers

    This document describes how to develop printer drivers for PostScript printers. Topics include: printer driver basics, creating new PPD files, importing existing PPD files, using custom filters, implementing color management, and adding Mac OS X features.

    diff --git a/filter/ppd-compiler.header b/filter/ppd-compiler.header index 6afe1b4f0..4af7865f8 100644 --- a/filter/ppd-compiler.header +++ b/filter/ppd-compiler.header @@ -1,3 +1,18 @@ + +

    Introduction to the PPD Compiler

    This document describes how to use the CUPS PostScript Printer Description diff --git a/filter/raster-driver.header b/filter/raster-driver.header index 5ba1fb614..31fc60722 100644 --- a/filter/raster-driver.header +++ b/filter/raster-driver.header @@ -1,3 +1,18 @@ + +

    Developing Raster Printer Drivers

    This document describes how to develop printer drivers for raster printers. Topics include: printer driver basics, creating new PPD files, using filters, implementing color management, and adding Mac OS X features.

    diff --git a/filter/spec-ppd.header b/filter/spec-ppd.header new file mode 100644 index 000000000..8292be8a7 --- /dev/null +++ b/filter/spec-ppd.header @@ -0,0 +1,32 @@ + + +

    CUPS PPD Extensions

    + +

    This specification describes the attributes and extensions that CUPS adds to Adobe TechNote #5003: PostScript Printer Description File Format Specification Version 4.3. PostScript Printer Description ("PPD") files describe the capabilities of each printer and are used by CUPS to support printer-specific features and intelligent filtering.

    + + diff --git a/filter/spec-ppd.shtml b/filter/spec-ppd.shtml new file mode 100644 index 000000000..96fb88133 --- /dev/null +++ b/filter/spec-ppd.shtml @@ -0,0 +1,1851 @@ +

    PPD File Syntax

    + +

    The PPD format is text-based and uses lines of up to 255 characters terminated by a carriage return, linefeed, or combination of carriage return and line feed. The following ABNF definition [RFC5234] defines the general format of lines in a PPD file:

    + +
    +PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
    +
    +HEADER   = "*PPD-Adobe:" *WSP DQUOTE VERSION DQUOTE LINE-END
    +
    +VERSION  = "4.0" / "4.1" / "4.2" / "4.3"
    +
    +COMMENT  = "*%" *TCHAR LINE-END
    +
    +DATA     = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
    +           1*(*WSP VALUE) LINE-END
    +
    +VALUE    = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
    +
    +KCHAR    = ALPHA / DIGIT / "_" / "." / "-"
    +
    +SCHAR    = LINE-END / WSP / %x21.23-7E.A0-FF
    +
    +TCHAR    = %x20-7E.A0-FF
    +
    +LINE-END = CR / LF / CR LF
    +
    + + +

    Auto-Configuration

    + +

    CUPS supports several methods of auto-configuration via PPD keywords.

    + +

    DeprecatedAPAutoSetupTool

    + +

    *APAutoSetupTool: "/LibraryPrinters/vendor/filename"

    + +

    This deprecated keyword defines a program that sets the default option choices. It is run when a printer is added from the Add Printer window or the Nearby Printers list in the Print dialog.

    + +

    The program is provided with two arguments: the printer's device URI and the PPD file to be used for the printer. The program must write an updated PPD file to stdout.

    + +
    Note: + +

    This keyword is deprecated. New printer drivers SHOULD provide a CUPS command filter and support the "AutoConfigure" command. Alternately, drivers MAY use the SNMP OID keywords to configure network printers or PostScript query keywords to configure PostScript printers.

    + +
    +

    Examples:

    + +
    +*% Use our setup tool when adding a printer
    +*APAutoSetupTool: "/Library/Printers/vendor/Tools/autosetuptool"
    +
    + +

    Mac OS X 10.2/CUPS 1.4?MainKeyword

    + +

    *?MainKeyword: "
    + PostScript query code that writes a message using the = operator...
    +"
    +*End

    + +

    The ?MainKeyword keyword defines PostScript code that determines the currently selected/enabled option keyword (choice) for the main keyword (option). It is typically used when communicating with USB, serial, Appletalk, and AppSocket (port 9100) printers.

    + +

    The PostScript code typically sends its response back using the = operator.

    + +

    Example:

    + +
    +*OpenUI OptionDuplex/Duplexer Installed: Boolean
    +*DuplexOptionDuplex: False
    +*OptionDuplex False/Not Installed: ""
    +*OptionDuplex True/Installed: ""
    +
    +*% Query the printer for the presence of the duplexer option...
    +*?OptionDuplex: "
    +  currentpagedevice /Duplex known
    +  {(True)} {(False)} ifelse
    +  = flush
    +"
    +*End
    +*CloseUI: OptionDuplex
    +
    + +

    Mac OS X 10.4/CUPS 1.5OIDMainKeyword

    + +

    *?OIDMainKeyword: ".n.n.n..."
    +*OIDMainKeyword OptionKeyword1: "value"
    +...
    +*OIDMainKeyword OptionKeywordN: "value"

    + +

    The OIDMainKeyword keyword is used to define SNMP OIDs that map to installable options. The first (query) line defines the OID to lookup on the network device. The second and subsequent keywords define a mapping from OID value to option keyword. Since SNMP is an IP-based network protocol, this method is typically only used to configure AppSocket, IPP, and LPD network printers.

    + +

    Examples:

    + +
    +*% Get the installed memory on the printer...
    +*?OIDInstalledMemory: ".1.3.6.1.2.1.25.2.2.0"
    +*OIDInstalledMemory 16MB: "16384 KBytes"
    +*OIDInstalledMemory 32MB: "32768 KBytes"
    +*OIDInstalledMemory 48MB: "49152 KBytes"
    +*OIDInstalledMemory 72MB: "73728 KBytes"
    +
    + + +

    Color Profiles

    + +

    CUPS supports three types of color profiles. The first type is based on sRGB and is used by the standard CUPS raster filters and GPL Ghostscript. The second type is based on ICC profiles and is used by the Quartz-based filters on MacOS X. The final type is based on well-known colorspaces such as sRGB and Adobe RGB.

    + +
    Note: + +

    At this time, none of the CUPS raster filters support ICC profiles. This will be addressed as time and resources permit.

    + +
    + +

    DeprecatedcupsColorProfile

    + +

    *cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"

    + +

    This string keyword specifies an sRGB-based color profile consisting of gamma and density controls and a 3x3 CMY color transform matrix. This keyword is not supported on Mac OS X.

    + +

    The Resolution and MediaType values may be "-" to act as a wildcard. Otherwise they must match one of the Resolution or MediaType option keywords defined in the PPD file.

    + +

    The density and gamma values define gamma and +density adjustment function such that:

    + +
    +f(x) = density * x gamma
    +
    + +

    The m00 through m22 values define a 3x3 transformation matrix for the CMY color values. The density function is applied after the CMY transformation:

    + +
    +| m00 m01 m02 |
    +| m10 m11 m12 |
    +| m20 m21 m22 |
    +
    + +

    Examples:

    + +
    +*% Specify a profile for printing at 360dpi on all media types 
    +*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    +*% Specify a profile for printing at 720dpi on Glossy media 
    +*cupsColorProfile 720dpi/Glossy: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    +*% Specify a default profile for printing at all other resolutions and media types 
    +*cupsColorProfile -/-: "0.9 2.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    + + +

    Mac OS X 10.3/CUPS 1.2cupsICCProfile

    + +

    *cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"

    + +

    This keyword specifies an ICC color profile that is used to convert the document colors to the device colorspace. The ColorModel, MediaType, and Resolution option keywords specify a selector for color profiles. If omitted, the color profile will match any option keyword for the corresponding main keyword.

    + +

    The Description specifies human-readable text that is associated with the color profile. The filename portion specifies the ICC color profile to use; if the filename is not absolute, it is loaded relative to the /usr/share/cups/profiles directory.

    + +

    Examples:

    + +
    +*% Specify a profile for CMYK printing at 360dpi on all media types 
    +*cupsICCProfile CMYK..360dpi/360dpi CMYK: "/Library/Printers/vendor/Profiles/foo-360-cmyk.icc"
    +
    +*% Specify a profile for RGB printing at 720dpi on Glossy media 
    +*cupsColorProfile RGB.Glossy.720dpi/720dpi Glossy: "/Library/Printers/vendor/Profiles/foo-720-glossy-rgb.icc"
    +
    +*% Specify a default profile for printing at all other resolutions and media types 
    +*cupsICCProfile ../Default: "/Library/Printers/vendor/Profiles/foo-default.icc"
    +
    + +

    Customizing the Profile Selection Keywords

    + +

    The MediaType and Resolution main keywords can be reassigned to different main keywords, allowing drivers to do color profile selection based on different parameters. The cupsICCQualifier2 and cupsICCQualifier3 keywords define the mapping from selector to main keyword:

    + +
    +*cupsICCQualifier2: MainKeyword2
    +*cupsICCQualifier3: MainKeyword3
    +
    + +

    The default mapping is as follows:

    + +
    +*cupsICCQualifier2: MediaType
    +*cupsICCQualifier3: Resolution
    +
    + +

    Mac OS X 10.4Custom Color Matching Support

    + +

    *APSupportsCustomColorMatching: true
    +*APCustomColorMatchingName name/text: ""
    +*APCustomColorMatchingProfile: profile
    +*APDefaultCustomColorMatchingProfile: profile

    + +

    These keywords tell the Mac OS X raster filters that the printer driver provides its own custom color matching and that generic color profiles should be used when generating 1-, 3-, and 4-component raster data as requested by the driver. The APCustomColorMatchingProfile and APDefaultColorMatchingProfile keywords specify alternate color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.

    + +
    Note: + +

    Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB". The new default in Mac OS X 10.6 and later is "sRGB". For more information, see "Mac OS X v10.6: About gamma 2.2" on Apple's support site.

    + +
    + +

    Mac OS X 10.5APCustomColorMatchingName

    + +

    *APCustomColorMatchingName name/text: ""

    + +

    This keyword defines an alternate name for the color matching provided by a driver in the Color Matching print panel. The default is to use the name "Vendor Matching" or its localized equivalent.

    + +

    Examples:

    + +
    +*% Define the names for our color matching...
    +*APCustomColorMatchingName name/AcmeColor(tm): ""
    +*fr.APCustomColorMatchingName name/La AcmeColor(tm): ""
    +
    + +

    Mac OS X 10.5APCustomColorMatchingProfile

    + +

    *APCustomColorMatchingProfile: name

    + +

    This keyword defines a supported RGB color profile that can be used when doing custom color matching. Currently only sRGB, AdobeRGB, and GenericRGB are supported. If not specified, RGB data will use the GenericRGB colorspace.

    + +
    Note: + +

    If you provide multiple APCustomColorMatchingProfile keywords, you are responsible for providing the necessary user interface controls to select the profile in a print dialog pane. Add the named profile to the print settings using the key kPMCustomColorMatchingProfileKey.

    + +
    + +

    Examples:

    + +
    +*% Use sRGB for RGB color by default, but support both sRGB and AdobeRGB
    +*APSupportsCustomColorMatching: true
    +*APDefaultCustomColorMatchingProfile: sRGB
    +*APCustomColorMatchingProfile: sRGB
    +*APCustomColorMatchingProfile: AdobeRGB
    +
    + +

    Mac OS X 10.5APDefaultCustomColorMatchingProfile

    + +

    *APDefaultCustomColorMatchingProfile: name

    + +

    This keyword defines the default RGB color profile that will be used when doing custom color matching. Currently only sRGB, AdobeRGB, and GenericRGB are supported.

    + +

    Examples:

    + +
    +*% Use sRGB for RGB color by default
    +*APSupportsCustomColorMatching: true
    +*APDefaultCustomColorMatchingProfile: sRGB
    +
    + +

    Mac OS X 10.4APSupportsCustomColorMatching

    + +

    *APSupportsCustomColorMatching: boolean

    + +

    This keyword specifies that the driver provides its own custom color matching. When true, the default hand-off colorspace will be GenericGray, GenericRGB, or GenericCMYK depending on the number of components the driver requests. The APDefaultCustomColorMatchingProfile keyword can be used to override the default 3-component (RGB) colorspace.

    + +

    The default for APSupportsCustomColorMatching is false.

    + +

    Examples:

    + +
    +*APSupportsCustomColorMatching: true
    +*APDefaultCustomColorMatchingProfile: sRGB
    +
    + + +

    Constraints

    + +

    Constraints are option choices that are not allowed by the driver or device, for example printing 2-sided transparencies. All versions of CUPS support constraints defined by the legacy Adobe UIConstraints and NonUIConstraints keywords which support conflicts between any two option choices, for example:

    + +
    +*% Do not allow 2-sided printing on transparency media
    +*UIConstraints: "*Duplex *MediaType Transparency"
    +*UIConstraints: "*MediaType Transparency *Duplex"
    +
    + +

    While nearly all constraints can be expressed using these keywords, there are valid scenarios requiring constraints between more than two option choices. In addition, resolution of constraints is problematic since users and software have to guess how a particular constraint is best resolved.

    + +

    CUPS 1.4 and higher define two new keywords for constraints, cupsUIConstraints and cupsUIResolver. Each cupsUIConstraints keyword points to a cupsUIResolver keyword which specifies alternate options that resolve the conflict condition. The same cupsUIResolver can be used by multiple cupsUIConstraints.

    + +
    Note: + +

    When developing PPD files that contain constraints, it is very important to use the cupstestppd(1) program to verify that your constraints are accurate and cannot result in unresolvable option selections.

    + +
    + +

    CUPS 1.4/Mac OS X 10.6cupsUIConstraints

    + +

    *cupsUIConstraints resolver: "*Keyword1 *Keyword2 ..."
    +*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 ..."
    +*cupsUIConstraints resolver: "*Keyword1 *Keyword2 OptionKeyword2 ..."
    +*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."
    +*cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."

    + +

    Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the constraint exists. When no resolver is provided, CUPS first tries the default choice followed by testing each option choice to resolve the conflict.

    + +

    Examples:

    + +
    +*% Specify that 2-sided printing cannot happen on transparencies 
    +*cupsUIConstraints transparency: "*Duplex *MediaType Transparency"
    +
    +*% Specify that envelope printing cannot happen from the paper trays 
    +*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
    +*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
    +*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
    +*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
    +
    +*% Specify an installable option constraint for the envelope feeder
    +*cupsUIConstraints: "*InputSlot EnvFeeder *InstalledEnvFeeder"
    +
    +*% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi 
    +*cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi"
    +*cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi"
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsUIResolver

    + +

    *cupsUIResolution resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."

    + +

    Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more cupsUIConstraints. The same action can be used for multiple constraints. The option keyword pairs are treated as an ordered list of option selections to try - only the first N selections will be used, where N is the minimum number of selections required. Because cupsResolveConflicts() will not change the most recent option selection passed to it, at least two options from the constraints must be listed to avoid situations where conflicts cannot be resolved.

    + +

    Examples:

    + +
    +*% Specify the options to change for the 2-sided transparency constraint 
    +*cupsUIResolver transparency: "*Duplex None *MediaType Plain"
    +
    +*% Specify the options to change for the envelope printing constraints.  Notice
    +*% that we try to change the InputSlot to either the envelope feeder or the
    +*% manual feed first, then we change the page size...
    +*cupsUIResolver envelope: "*InputSlot EnvFeeder *InputSlot ManualFeed *PageSize Letter"
    +
    +*% Specify the options to change for the photo printing constraints 
    +*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
    +
    + + +

    Globalized PPD Support

    + +

    CUPS 1.2 and higher adds support for PPD files containing multiple languages by following the following additional rules:

    + +
      + +
    1. The LanguageVersion MUST be English
    2. + +
    3. The LanguageEncoding MUST be ISOLatin1
    4. + +
    5. The cupsLanguages keyword MUST be provided and list each of the supported locales in the PPD file
    6. + +
    7. Main and option keywords MUST NOT exceed 34 (instead of 40) characters to allow room for the locale prefixes in translation keywords
    8. + +
    9. The main keyword "Translation" MUST NOT be used
    10. + +
    11. Translation strings included with the main and option keywords MUST NOT contain characters outside the ASCII subset of ISOLatin1 and UTF-8; developers wishing to use characters outside ASCII MUST provide a separate set of English localization keywords for the affected keywords.
    12. + +
    13. Localizations are specified using a locale prefix of the form "ll" or "ll_CC." where "ll" is the 2-letter ISO language code and "CC" is the 2-letter ISO country code
        +
      • A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed
      • +
      • For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese
      • +
    14. + +
    15. Locale-specific translation strings MUST be encoded using UTF-8.
    16. + +
    17. Main keywords MUST be localized using one of the following forms: +

      *ll.Translation MainKeyword/translation text: ""
      + *ll_CC.Translation MainKeyword/translation text: ""

    18. + +
    19. Option keywords MUST be localized using one of the following forms: +

      *ll.MainKeyword OptionKeyword/translation text: ""
      + *ll_CC.MainKeyword OptionKeyword/translation text: ""

    20. + +
    21. Localization keywords MAY appear anywhere after the first line of the PPD file
    22. + +
    + +
    Note: + +

    We use a LanguageEncoding value of ISOLatin1 and limit the allowed base translation strings to ASCII to avoid character coding issues that would otherwise occur. In addition, requiring the base translation strings to be in English allows for easier fallback translation when no localization is provided in the PPD file for a given locale.

    + +
    + +

    Examples:

    + +
    +*LanguageVersion: English
    +*LanguageEncoding: ISOLatin1
    +*cupsLanguages: "de fr_CA"
    +*ModelName: "Foobar Laser 9999"
    +
    +*% Localize ModelName for French and German
    +*fr_CA.Translation ModelName/La Foobar Laser 9999: ""
    +*de.Translation ModelName/Foobar LaserDrucken 9999: ""
    +
    +*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
    +*% Localize printer-state-reason for French and German
    +*fr_CA.cupsIPPReason com.vendor-error/Une erreur sèrieuse s'est produite: "/help/com.vendor/error.html"
    +*de.cupsIPPReason com.vendor-error/Eine ernste Störung trat: "/help/com.vendor/error.html"
    +
    +...
    +
    +*OpenUI *InputSlot/Paper Source: PickOne
    +*OrderDependency: 10 AnySetup *InputSlot
    +*DefaultInputSlot: Auto
    +*% Localize InputSlot for French and German
    +*fr_CA.Translation InputSlot/Papier source: ""
    +*de.Translation InputSlot/Papiereinzug: ""
    +*InputSlot Auto/Default: "<</ManualFeed false>>setpagedevice"
    +*% Localize InputSlot=Auto for French and German
    +*fr_CA.InputSlot Auto/Par Defaut: ""
    +*de.InputSlot Auto/Standard: ""
    +*InputSlot Manual/Manual Feed: "<</ManualFeed true>>setpagedevice"
    +*% Localize InputSlot=Manual for French and German
    +*fr_CA.InputSlot Manual/Manuel mecanisme de alimentation: ""
    +*de.InputSlot Manual/Manueller Einzug: ""
    +*CloseUI: *InputSlot
    +
    + + +

    CUPS 1.3/Mac OS X 10.6Custom Options

    + +

    CUPS supports custom options using an extension of the CustomPageSize and ParamCustomPageSize syntax:

    + +
    +*CustomFoo True: "command"
    +*ParamCustomFoo Name1/Text 1: order type minimum maximum
    +*ParamCustomFoo Name2/Text 2: order type minimum maximum
    +...
    +*ParamCustomFoo NameN/Text N: order type minimum maximum
    +
    + +

    When the base option is part of the JCLSetup section, the "command" string contains JCL commands with "\order" placeholders for each numbered parameter. The CUPS API handles any necessary value quoting for HP-PJL commands. For example, if the JCL command string is "@PJL SET PASSCODE=\1" and the first +option value is "1234" then CUPS will output the string "@PJL SET PASSCODE=1234".

    + +

    For non-JCLSetup options, the "order" value is a number from 1 to N and specifies the order of values as they are placed on the stack before the command. For example, if the PostScript command string is "<</cupsReal1 2 1 roll>>setpagedevice" and the option value is "2.0" then CUPS will output the string "2.0 <</cupsReal1 2 1 roll>>setpagedevice".

    + +

    The "type" is one of the following keywords:

    + +
      + +
    • curve - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x value
    • + +
    • int - an integer value from "minimum" to "maximum"
    • + +
    • invcurve - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x 1 / value
    • + +
    • passcode - a string of numbers value with a minimum of "minimum" numbers and a maximum of "maximum" numbers ("minimum" and "maximum" are numbers and passcode strings are not displayed in the user interface)
    • + +
    • password - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers and password strings are not displayed in the user interface)
    • + +
    • points - a measurement value in points from "minimum" to "maximum"
    • + +
    • real - a real value from "minimum" to "maximum"
    • + +
    • string - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers)
    • + +
    + +

    Examples:

    + +
    +*% Base JCL key code option 
    +*JCLOpenUI JCLPasscode/Key Code: PickOne
    +*OrderDependency: 10 JCLSetup *JCLPasscode
    +*DefaultJCLPasscode: None
    +*JCLPasscode None/No Code: ""
    +*JCLPasscode 1111: "@PJL SET PASSCODE = 1111<0A>"
    +*JCLPasscode 2222: "@PJL SET PASSCODE = 2222<0A>"
    +*JCLPasscode 3333: "@PJL SET PASSCODE = 3333<0A>"
    +*JCLCloseUI: *JCLPasscode
    +
    +*% Custom JCL key code option 
    +*CustomJCLPasscode True: "@PJL SET PASSCODE = \1<0A>"
    +*ParamCustomJCLPasscode Code/Key Code: 1 passcode 4 4
    +
    +
    +*% Base PostScript watermark option
    +*OpenUI WatermarkText/Watermark Text: PickOne
    +*OrderDependency: 10 AnySetup *WatermarkText
    +*DefaultWatermarkText: None
    +*WatermarkText None: ""
    +*WatermarkText Draft: "<</cupsString1(Draft)>>setpagedevice"
    +*CloseUI: *WatermarkText
    +
    +*% Custom PostScript watermark option
    +*CustomWatermarkText True: "<</cupsString1 3 -1 roll>>setpagedevice"
    +*ParamCustomWatermarkText Text: 1 string 0 32
    +
    +
    +*% Base PostScript gamma/density option 
    +*OpenUI GammaDensity/Gamma and Density: PickOne
    +*OrderDependency: 10 AnySetup *GammaDensity
    +*DefaultGammaDensity: Normal
    +*GammaDensity Normal/Normal: "<</cupsReal1 1.0/cupsReal2 1.0>>setpagedevice"
    +*GammaDensity Light/Lighter: "<</cupsReal1 0.9/cupsReal2 0.67>>setpagedevice"
    +*GammaDensity Dark/Darker: "<</cupsReal1 1.1/cupsReal2 1.5>>setpagedevice"
    +*CloseUI: *GammaDensity
    +
    +*% Custom PostScript gamma/density option 
    +*CustomGammaDensity True: "<</cupsReal1 3 -1 roll/cupsReal2 5 -1>>setpagedevice"
    +*ParamCustomGammaDensity Gamma: 1 curve 0.1 10
    +*ParamCustomGammaDensity Density: 2 real 0 2
    +
    + + +

    Writing PostScript Option Commands for Raster Drivers

    + +

    PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device keywords such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:

    + +
    +*PageSize A4: "<</PageSize[595 842]>>setpagedevice"
    +
    + +

    Custom options typically use other operators to organize the values into a key/value dictionary for setpagedevice. For example, our previous CustomWatermarkText option code uses the roll operator to move the custom string value into the dictionary for setpagedevice:

    + +
    +*CustomWatermarkText True: "<</cupsString1 3 -1 roll>>setpagedevice"
    +
    + +

    For a custom string value of "My Watermark", CUPS will produce the following PostScript code for the option:

    + +
    +(My Watermark)
    +<</cupsString1 3 -1 roll>>setpagedevice
    +
    + +

    The code moves the string value ("My Watermark") from the bottom of the stack to the top, creating a dictionary that looks like:

    + +
    +<</cupsString1(My Watermark)>>setpagedevice
    +
    + +

    The resulting dictionary sets the page device attributes that are sent to your raster driver in the page header.

    + +

    Custom Page Size Code

    + +

    There are many possible implementations of the CustomPageSize code. For CUPS raster drivers, the following code is recommended:

    + +
    +*ParamCustomPageSize Width:        1 points min-width max-width
    +*ParamCustomPageSize Height:       2 points min-height max-height
    +*ParamCustomPageSize WidthOffset:  3 points 0 0
    +*ParamCustomPageSize HeightOffset: 4 points 0 0
    +*ParamCustomPageSize Orientation:  5 int 0 0
    +*CustomPageSize True: "pop pop pop <</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice"
    +
    + +

    Supported PostScript Operators

    + +

    CUPS supports the following PostScript operators in addition to the usual PostScript number, string (literal and hex-encoded), boolean, null, and name values:

    + +
      + +
    • << - Start a dictionary.
    • + +
    • >> - End a dictionary.
    • + +
    • [ - Start an array.
    • + +
    • ] - End an array.
    • + +
    • copy - Copy the top N objects on the stack.
    • + +
    • dup - Copy the top object on the stack.
    • + +
    • index - Copy the Nth from the top object on the stack.
    • + +
    • pop - Pop the top object on the stack.
    • + +
    • roll - Shift the top N objects on the stack.
    • + +
    • setpagedevice - Set the page header values according to the key/value dictionary on the stack.
    • + +
    + +
    Note: + +

    Never use the unsupported dict or put +operators in your option code. These operators are typically used in +option code dating back to Level 1 PostScript printers, which did not +support the simpler << or >> operators. +If you have old option code using dict or put, you can +rewrite it very easily to use the newer << and +>> operators instead. For example, the following code +to set the page size:

    + + + +
    +1 dict dup /PageSize [612 792] put setpagedevice
    +
    + +

    can be rewritten as:

    + +
    +<< /PageSize [612 792] >> setpagedevice
    +
    + +
    + +

    Supported Page Device Attributes

    + +

    Table 2 shows the supported page device attributes along with PostScript code examples.

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 2: Supported Page Device Attributes
    Name(s)TypeDescriptionExample(s)
    AdvanceDistanceIntegerSpecifies the number of points to advance roll media after printing.<</AdvanceDistance 18>>setpagedevice
    AdvanceMediaIntegerSpecifies when to advance the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.<</AdvanceMedia 4>>setpagedevice
    CollateBooleanSpecifies whether collated copies are required.<</Collate true>>setpagedevice
    CutMediaIntegerSpecifies when to cut the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.<</CutMedia 1>>setpagedevice
    DuplexBooleanSpecifies whether 2-sided printing is required.<</Duplex true>>setpagedevice
    HWResolutionInteger ArraySpecifies the resolution of the page image in pixels per inch.<</HWResolution[1200 1200]>>setpagedevice
    InsertSheetBooleanSpecifies whether to insert a blank sheet before the job.<</InsertSheet true>>setpagedevice
    JogIntegerSpecifies when to shift the media in the output bin: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.<</Jog 2>>setpagedevice
    LeadingEdgeIntegerSpecifies the leading edge of the media: 0 = top, 1 = right, 2 = bottom, 3 = left.<</LeadingEdge 0>>setpagedevice
    ManualFeedBooleanSpecifies whether media should be drawn from the manual feed tray. Note: The MediaPosition attribute is preferred over the ManualFeed attribute.<</ManualFeed true>>setpagedevice
    MediaClassStringSpecifies a named media.<</MediaClass (Invoices)>>setpagedevice
    MediaColorStringSpecifies the color of the media.<</MediaColor >>setpagedevice
    MediaPositionIntegerSpecifies the tray or source of the media.<</MediaPosition 12>>setpagedevice
    MediaTypeStringSpecifies the general media type.<</MediaType (Glossy)>>setpagedevice
    MediaWeightIntegerSpecifies the media weight in grams per meter2.<</MediaWeight 100>>setpagedevice
    MirrorPrintBooleanSpecifies whether to flip the output image horizontally.<</MirrorPrint true>>setpagedevice
    NegativePrintBooleanSpecifies whether to invert the output image.<</NegativePrint true>>setpagedevice
    NumCopiesIntegerSpecifies the number of copies to produce of each page.<</NumCopies 100>>setpagedevice
    OrientationIntegerSpecifies the orientation of the output: 0 = portrait, 1 = landscape rotated counter-clockwise, 2 = upside-down, 3 = landscape rotated clockwise.<</Orientation 3>>setpagedevice
    OutputFaceUpBooleanSpecifies whether to place the media face-up in the output bin/tray.<</OutputFaceUp true>>setpagedevice
    OutputTypeStringSpecifies the output type name.<</OutputType (Photo)>>setpagedevice
    PageSizeInteger/Real ArraySpecifies the width and length/height of the page in points.<</PageSize[595 842]>>setpagedevice
    SeparationsBooleanSpecifies whether to produce color separations.<</Separations true>>setpagedevice
    TraySwitchBooleanSpecifies whether to switch trays automatically.<</TraySwitch true>>setpagedevice
    TumbleBooleanSpecifies whether the back sides of pages are rotated 180 degrees.<</Tumble true>>setpagedevice
    cupsBorderlessScalingFactorRealSpecifies the amount to scale the page image dimensions.<</cupsBorderlessScalingFactor 1.01>>setpagedevice
    cupsColorOrderIntegerSpecifies the order of colors: 0 = chunked, 1 = banded, 2 = planar.<</cupsColorOrder 0>>setpagedevice
    cupsColorSpaceIntegerSpecifies the page image colorspace: 0 = W, 1 = RGB, 2 = RGBA, 3 = K, 4 = CMY, 5 = YMC, 6 = CMYK, 7 = YMCK, 8 = KCMY, 9 = KCMYcm, 10 = GMCK, 11 = GMCS, 12 = White, 13 = Gold, 14 = Silver, 15 = CIE XYZ, 16 = CIE Lab, 17 = RGBW, 32 to 46 = CIE Lab (1 to 15 inks)<</cupsColorSpace 1 >>setpagedevice
    cupsCompressionIntegerSpecifies a driver compression type/mode.<</cupsCompression 2>>setpagedevice
    cupsInteger0
    + ...
    + cupsInteger15
    IntegerSpecifies driver integer values.<</cupsInteger11 1234>>setpagedevice
    cupsMarkerTypeStringSpecifies the type of ink/toner to use.<</cupsMarkerType (Black+Color)>>setpagedevice
    cupsMediaTypeIntegerSpecifies a numeric media type.<</cupsMediaType 999>>setpagedevice
    cupsPageSizeNameStringSpecifies the name of the page size.<</cupsPageSizeName (A4.Full)>>setpagedevice
    cupsPreferredBitsPerColorIntegerSpecifies the preferred number of bits per color, typically 8 or 16.<</cupsPreferredBitsPerColor 16>>setpagedevice
    cupsReal0
    + ...
    + cupsReal15
    RealSpecifies driver real number values.<</cupsReal15 1.234>>setpagedevice
    cupsRenderingIntentStringSpecifies the color rendering intent.<</cupsRenderingIntent (AbsoluteColorimetric)>>setpagedevice
    cupsRowCountIntegerSpecifies the number of rows of raster data to print on each line for some drivers.<</cupsRowCount 24>>setpagedevice
    cupsRowFeedIntegerSpecifies the number of rows to feed between passes for some drivers.<</cupsRowFeed 17>>setpagedevice
    cupsRowStepIntegerSpecifies the number of lines between columns/rows on the print head for some drivers.<</cupsRowStep 2>>setpagedevice
    cupsString0
    + ...
    + cupsString15
    StringSpecifies driver string values.<</cupsString0(String Value)>>setpagedevice
    + + +

    Media Keywords

    + +

    The CUPS media keywords allow drivers to specify alternate custom page +size limits based on up to two options.

    + +

    CUPS 1.4/Mac OS X 10.6cupsMediaQualifier2

    + +

    *cupsMediaQualifier2: MainKeyword

    + +

    This keyword specifies the second option to use for overriding the +custom page size limits.

    + +

    Example:

    + +
    +*% Specify alternate custom page size limits based on InputSlot and Quality
    +*cupsMediaQualifier2: InputSlot
    +*cupsMediaQualifier3: Quality
    +*cupsMaxSize .Manual.: "1000 1000"
    +*cupsMinSize .Manual.: "100 100"
    +*cupsMinSize .Manual.Photo: "200 200"
    +*cupsMinSize ..Photo: "300 300"
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsMediaQualifier3

    + +

    *cupsMediaQualifier3: MainKeyword

    + +

    This keyword specifies the third option to use for overriding the +custom page size limits.

    + +

    Example:

    + +
    +*% Specify alternate custom page size limits based on InputSlot and Quality
    +*cupsMediaQualifier2: InputSlot
    +*cupsMediaQualifier3: Quality
    +*cupsMaxSize .Manual.: "1000 1000"
    +*cupsMinSize .Manual.: "100 100"
    +*cupsMinSize .Manual.Photo: "200 200"
    +*cupsMinSize ..Photo: "300 300"
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsMinSize

    + +

    *cupsMinSize .Qualifier2.Qualifier3: "width length"
    +*cupsMinSize .Qualifier2.: "width length"
    +*cupsMinSize ..Qualifier3: "width length"

    + +

    This keyword specifies alternate minimum custom page sizes in points. +The cupsMediaQualifier2 and +cupsMediaQualifier3 keywords +are used to identify options to use for matching.

    + +

    Example:

    + +
    +*% Specify alternate custom page size limits based on InputSlot and Quality
    +*cupsMediaQualifier2: InputSlot
    +*cupsMediaQualifier3: Quality
    +*cupsMaxSize .Manual.: "1000 1000"
    +*cupsMinSize .Manual.: "100 100"
    +*cupsMinSize .Manual.Photo: "200 200"
    +*cupsMinSize ..Photo: "300 300"
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsMaxSize

    + +

    *cupsMaxSize .Qualifier2.Qualifier3: "width length"
    +*cupsMaxSize .Qualifier2.: "width length"
    +*cupsMaxSize ..Qualifier3: "width length"

    + +

    This keyword specifies alternate maximum custom page sizes in points. +The cupsMediaQualifier2 and +cupsMediaQualifier3 keywords +are used to identify options to use for matching.

    + +

    Example:

    + +
    +*% Specify alternate custom page size limits based on InputSlot and Quality
    +*cupsMediaQualifier2: InputSlot
    +*cupsMediaQualifier3: Quality
    +*cupsMaxSize .Manual.: "1000 1000"
    +*cupsMinSize .Manual.: "100 100"
    +*cupsMinSize .Manual.Photo: "200 200"
    +*cupsMinSize ..Photo: "300 300"
    +
    + + +

    General Attributes

    + +

    CUPS 1.3/Mac OS X 10.5cupsBackSide

    + +

    *cupsBackSide: keyword

    + +

    This keyword requests special handling of the back side of pages +when doing duplexed (2-sided) output. Table 1 +shows the supported keyword values for this keyword and their effect +on the raster data sent to your driver. For example, when cupsBackSide +is Rotated and Tumble is false, your driver +will receive print data starting at the bottom right corner of the page, with +each line going right-to-left instead of left-to-right. The default value is +Normal.

    + +
    Note: + +

    cupsBackSide replaces the older cupsFlipDuplex +keyword - if cupsBackSide is specified, cupsFlipDuplex +will be ignored.

    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 1: Back Side Raster Coordinate System
    cupsBackSideTumble ValueImage Presentation
    NormalfalseLeft-to-right, top-to-bottom
    NormaltrueLeft-to-right, top-to-bottom
    ManualTumblefalseLeft-to-right, top-to-bottom
    ManualTumbletrueRight-to-left, bottom-to-top
    RotatedfalseRight-to-left, bottom-to-top
    RotatedtrueRight-to-left, top-to-bottom
    Flipped *falseLeft-to-right, bottom-to-top
    Flipped *trueRight-to-left, top-to-bottom
    +
    + +

    * - Not supported in Mac OS X 10.5.x and earlier

    + +
    + + +
    Figure 1: Back side images
    Back side images
    + +

    Examples:

    + +
    +*% Flip the page image for the back side of duplexed output 
    +*cupsBackSide: Flipped
    +
    +*% Rotate the page image for the back side of duplexed output 
    +*cupsBackSide: Rotated
    +
    + +

    Also see the related APDuplexRequiresFlippedMargin +keyword.

    + +

    CUPS 1.4/Mac OS X 10.6cupsCommands

    + +

    *cupsCommands: "name name2 ... nameN"

    + +

    This string keyword specifies the commands that are supported by the +CUPS command file filter for this device. The command names are separated +by whitespace.

    + +

    Example:

    + +
    +*% Specify the list of commands we support 
    +*cupsCommands: "AutoConfigure Clean PrintSelfTestPage ReportLevels com.vendor.foo"
    +
    + + +

    CUPS 1.3/Mac OS X 10.5cupsEvenDuplex

    + +

    *cupsEvenDuplex: boolean

    + +

    This boolean keyword notifies the RIP filters that the +destination printer requires an even number of pages when 2-sided +printing is selected. The default value is false.

    + +

    Example:

    + +
    +*% Always send an even number of pages when duplexing 
    +*cupsEvenDuplex: true
    +
    + +

    cupsFax

    + +

    *cupsFax: boolean

    + +

    This boolean keyword specifies whether the PPD defines a facsimile device. The default is false.

    + +

    Examples:

    + +
    +*cupsFax: true
    +
    + +

    cupsFilter

    + +

    *cupsFilter: "source/type cost program"

    + +

    This string keyword provides a conversion rule from the +given source type to the printer's native format using the +filter "program". If a printer supports the source type directly, +the special filter program "-" may be specified.

    + +

    Examples:

    + +
    +*% Standard raster printer driver filter 
    +*cupsFilter: "application/vnd.cups-raster 100 rastertofoo"
    +
    +*% Plain text filter 
    +*cupsFilter: "text/plain 10 texttofoo"
    +
    +*% Pass-through filter for PostScript printers 
    +*cupsFilter: "application/vnd.cups-postscript 0 -"
    +
    + +

    DeprecatedcupsFlipDuplex

    + +

    *cupsFlipDuplex: boolean

    + +

    Due to implementation differences between Mac OS X and Ghostscript, +the cupsFlipDuplex keyword is deprecated. Instead, use +the cupsBackSide keyword to specify +the coordinate system (pixel layout) of the page data on the back side of +duplex pages.

    + +

    The value true maps to a cupsBackSide value +of Rotated on Mac OS X and Flipped with +Ghostscript.

    + +

    The default value is false.

    + +
    Note: + +

    Mac OS X drivers that previously used +cupsFlipDuplex may wish to provide both the old and +new keywords for maximum compatibility, for example:

    + +
    +*cupsBackSide: Rotated
    +*cupsFlipDuplex: true
    +
    + +

    Similarly, drivers written for other operating systems using +Ghostscript can use:

    + +
    +*cupsBackSide: Flipped
    +*cupsFlipDuplex: true
    +
    + +

    CUPS 1.3/Mac OS X 10.5cupsIPPFinishings

    + +

    *cupsIPPFinishings number/text: "*Option Choice ..."

    + +

    This keyword defines a mapping from IPP finishings +values to PPD options and choices.

    + +

    Examples:

    + +
    +*cupsIPPFinishings 4/staple: "*StapleLocation SinglePortrait"
    +*cupsIPPFinishings 5/punch: "*PunchMedia Yes *PunchLocation LeftSide"
    +*cupsIPPFinishings 20/staple-top-left: "*StapleLocation SinglePortrait"
    +*cupsIPPFinishings 21/staple-bottom-left: "*StapleLocation SingleLandscape"
    +
    + +

    CUPS 1.3/Mac OS X 10.5cupsIPPReason

    + +

    *cupsIPPReason reason/Reason Text: "optional URIs"

    + +

    This optional keyword maps custom +printer-state-reasons keywords that are generated by +the driver to human readable text. The optional URIs string +contains zero or more URIs separated by a newline. Each URI can +be a CUPS server absolute path to a help file under the +scheduler's DocumentRoot directory, a full HTTP URL +("http://www.domain.com/path/to/help/page.html"), or any other +valid URI which directs the user at additional information +concerning the condition that is being reported.

    + +

    Since the reason text is limited to 80 characters by the PPD specification, +longer text strings can be included by URI-encoding the text with the "text" +scheme, for example "text:some%20text". Multiple text URIs are +combined (with spaces between each URI) by the ppdLocalizeIPPReason +into a single string that can be displayed to the user.

    + +

    Examples:

    + +
    +*% Map com.vendor-error to text but no page
    +*cupsIPPReason com.vendor-error/A serious error occurred: ""
    +
    +*% Map com.vendor-error to more than 80 characters of text but no page
    +*cupsIPPReason com.vendor-error/A serious error occurred: "text:Now%20is%20the%20time
    +text:for%20all%20good%20men%20to%20come%20to%20the%20aid%20of%20their%20country."
    +
    +*% Map com.vendor-error to text and a local page
    +*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
    +
    +*% Map com.vendor-error to text and a remote page
    +*cupsIPPReason com.vendor-error/A serious error occurred: "http://www.vendor.com/help"
    +
    +*% Map com.vendor-error to text and a local, Apple help book, and remote page
    +*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
    +*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html
    +help:anchor='com.vendor-error'%20bookID=Vendor%20Help
    +http://www.vendor.com/help"
    +*End
    +
    + +

    CUPS 1.2/Mac OS X 10.5cupsLanguages

    + +

    *cupsLanguages: "locale list"

    + +

    This keyword describes which language localizations are +included in the PPD. The "locale list" string is a space-delimited +list of locale names ("en", "en_US", "fr_CA", etc.)

    + +

    Example:

    + +
    +*% Specify Canadian, UK, and US English, and Candian and French French 
    +*cupsLanguages: "en_CA en_UK en_US fr_CA fr_FR"
    +
    + +

    cupsManualCopies

    + +

    *cupsManualCopies: boolean

    + +

    This boolean keyword notifies the RIP filters that the +destination printer does not support copy generation in +hardware. The default value is false.

    + +

    Example:

    + +
    +*% Tell the RIP filters to generate the copies for us 
    +*cupsManualCopies: true
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsMarkerName

    + +

    *cupsMarkerName/Name Text: ""

    + +

    This optional keyword maps marker-names strings that are +generated by the driver to human readable text.

    + +

    Examples:

    + +
    +*% Map cyanToner to "Cyan Toner"
    +*cupsMarkerName cyanToner/Cyan Toner: ""
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsMarkerNotice

    + +

    *cupsMarkerNotice: "disclaimer text"

    + +

    This optional keyword provides disclaimer text for the supply level +information provided by the driver, typically something like "supply levels +are approximate".

    + +

    Examples:

    + +
    +*cupsMarkerNotice: "Supply levels are approximate."
    +
    + +

    cupsModelNumber

    + +

    *cupsModelNumber: number

    + +

    This integer keyword specifies a printer-specific model +number. This number can be used by a filter program to adjust +the output for a specific model of printer.

    + +

    Example:

    + +
    +*% Specify an integer for a driver-specific model number 
    +*cupsModelNumber: 1234
    +
    + +

    CUPS 1.3/Mac OS X 10.5cupsPJLCharset

    + +

    *cupsPJLCharset: "ISO character set name"

    + +

    This string keyword specifies the character set that is used +for strings in PJL commands. If not specified, US-ASCII is +assumed.

    + +

    Example:

    + +
    +*% Specify UTF-8 is used in PJL strings
    +*cupsPJLCharset: "UTF-8"
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsPJLDisplay

    + +

    *cupsPJLDisplay: "what"

    + +

    This optional keyword specifies which command is used to display the +job ID, name, and user on the printer's control panel. "What" is either "none" +to disable this functionality, "job" to use "@PJL JOB DISPLAY", or "rdymsg" +to use "@PJL RDYMSG DISPLAY". The default is "job".

    + +

    Examples:

    + +
    +*% Display job information using @PJL SET RDYMSG DISPLAY="foo"
    +*cupsPJLDisplay: "rdymsg"
    +
    +*% Display job information display
    +*cupsPJLDisplay: "none"
    +
    + +

    CUPS 1.2/Mac OS X 10.5cupsPortMonitor

    + +

    *cupsPortMonitor urischeme/Descriptive Text: "port monitor"

    + +

    This string keyword specifies printer-specific "port +monitor" filters that may be used with the printer. The CUPS +scheduler also looks for the Protocols keyword to see +if the BCP or TBCP protocols are supported. If +so, the corresponding port monitor ("bcp" and "tbcp", +respectively) is listed in the printer's +port-monitor-supported keyword.

    + +

    The "urischeme" portion of the keyword specifies the URI scheme +that this port monitor should be used for. Typically this is used to +pre-select a particular port monitor for each type of connection that +is supported by the printer. The "port monitor" string can be "none" +to disable the port monitor for the given URI scheme.

    + +

    Examples:

    + +
    +*% Specify a PostScript printer that supports the TBCP protocol
    +*Protocols: TBCP PJL
    +
    +*% Specify that TBCP should be used for socket connections but not USB
    +*cupsPortMonitor socket/AppSocket Printing: "tbcp"
    +*cupsPortMonitor usb/USB Printing: "none"
    +
    +*% Specify a printer-specific port monitor for an Epson USB printer 
    +*cupsPortMonitor usb/USB Status Monitor: "epson-usb"
    +
    + +

    CUPS 1.3/Mac OS X 10.5cupsPreFilter

    + +

    *cupsPreFilter: "source/type cost program"

    + +

    This string keyword provides a pre-filter rule. The pre-filter +program will be inserted in the conversion chain immediately +before the filter that accepts the given MIME type.

    + +

    Examples:

    + +
    +*% PDF pre-filter
    +*cupsPreFilter: "application/pdf 100 mypdfprefilter"
    +
    +*% PNG pre-filter
    +*cupsPreFilter: "image/png 0 mypngprefilter"
    +
    + + +

    CUPS 1.5cupsPrintQuality

    + +

    *cupsPrintQuality keyword/text: "code"

    + +

    This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template keyword. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each cupsPrintQuality option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.

    + +
    Note: + +

    Unlike all of the other keywords defined in this document, cupsPrintQuality is a UI keyword that MUST be enclosed inside the PPD OpenUI and CloseUI keywords.

    + +
    + +

    Examples:

    + +
    +*OpenUI *cupsPrintQuality/Print Quality: PickOne
    +*OrderDependency: 10 AnySetup *cupsPrintQuality
    +*DefaultcupsPrintQuality: Normal
    +*cupsPrintQuality Draft/Draft: "code"
    +*cupsPrintQuality Normal/Normal: "code"
    +*cupsPrintQuality High/Photo: "code"
    +*CloseUI: *cupsPrintQuality
    +
    + +

    CUPS 1.4/Mac OS X 10.6cupsSNMPSupplies

    + +

    *cupsSNMPSupplies: boolean

    + +

    This keyword tells the standard network backends whether they should query +the standard SNMP Printer MIB OIDs for supply levels. The default value is +True. + +

    Example:

    + +
    +*% Do not use SNMP queries to report supply levels
    +*cupsSNMPSupplies: False
    +
    + +

    cupsVersion

    + +

    *cupsVersion: major.minor

    + +

    This required keyword describes which version of the CUPS +PPD file extensions was used. Currently it must be the string +"1.0", "1.1", "1.2", or "1.3".

    + +

    Example:

    + +
    +*% Specify a CUPS 1.2 driver 
    +*cupsVersion: "1.2"
    +
    + + +

    Mac OS X Attributes

    + +

    Mac OS X 10.3APDialogExtension

    + +

    *APDialogExtension: "/Library/Printers/vendor/filename.plugin"

    + +

    This keyword defines additional option panes that are displayed in the +print dialog. Each keyword adds one or more option panes. See the "OutputBinsPDE" +example and Apple +Technical Q&A QA1352 for information on writing your own print dialog +plug-ins.

    + +
    Note: + +

    Starting with Mac OS X 10.5, each plug-in must be compiled "4-way fat" +(32-bit and 64-bit for both PowerPC and Intel) with garbage collection enabled +in order to be usable with all applications.

    + +
    + +

    Examples:

    + +
    +*% Add two panes for finishing and driver options
    +*APDialogExtension: "/Library/Printers/vendor/finishing.plugin"
    +*APDialogExtension: "/Library/Printers/vendor/options.plugin"
    +
    + +

    Mac OS X 10.4APDuplexRequiresFlippedMargin

    + +

    *APDuplexRequiresFlippedMargin: boolean

    + +

    This boolean keyword notifies the RIP filters that the +destination printer requires the top and bottom margins of the +ImageableArea to be swapped for the back page. The +default is true when cupsBackSide is Flipped +and false otherwise. Table 2 shows how +APDuplexRequiresFlippedMargin interacts with cupsBackSide +and the Tumble page attribute.

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 2: Margin Flipping Modes
    APDuplexRequiresFlippedMargincupsBackSideTumble ValueMargins
    falseanyanyNormal
    anyNormalanyNormal
    trueManualDuplexfalseNormal
    trueManualDuplextrueFlipped
    trueRotatedfalseFlipped
    trueRotatedtrueNormal
    true or unspecifiedFlippedanyFlipped
    + +

    Example:

    + +
    +*% Rotate the back side images
    +*cupsBackSide: Rotated
    +
    +*% Don't swap the top and bottom margins for the back side 
    +*APDuplexRequiresFlippedMargin: false
    +
    + +

    Also see the related cupsBackSide +keyword.

    + +

    APHelpBook

    + +

    *APHelpBook: "bundle URL"

    + +

    This string keyword specifies the Apple help book bundle to use when +looking up IPP reason codes for this printer driver. The +cupsIPPReason keyword maps +"help" URIs to this file.

    + +

    Example:

    + +
    +*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
    +
    + +

    Mac OS X 10.6APICADriver

    + +

    *APICADriver: boolean

    + +

    This keyword specifies whether the device has a matching Image Capture +Architecture (ICA) driver for scanning. The default is False.

    + +

    Examples:

    + +
    +*APICADriver: True
    +*APScanAppBundleID: "com.apple.ImageCaptureApp"
    +
    + +

    Mac OS X 10.3APPrinterIconPath

    + +

    *APPrinterIconPath: "/Library/Printers/vendor/filename.icns"

    + +

    This keyword defines the location of a printer icon file to use when +displaying the printer. The file must be in the Apple icon format.

    + +

    Examples:

    + +
    +*% Apple icon file
    +*APPrinterIconPath: "/Library/Printers/vendor/Icons/filename.icns"
    +
    + +

    Mac OS X 10.4APPrinterLowInkTool

    + +

    *APPrinterLowInkTool: "/Library/Printers/vendor/program"

    + +

    This keyword defines an program that checks the ink/toner/marker levels +on a printer, returning an XML document with those levels. See the "InkTool" +example and +Apple +Technical Note TN2144 for more information.

    + +

    Examples:

    + +
    +*% Use a vendor monitoring program
    +*APPrinterLowInkTool: "/Library/Printers/vendor/Tools/lowinktool"
    +
    + +

    Mac OS X 10.5APPrinterPreset

    + +

    *APPrinterPreset name/text: "*Option Choice ..."

    + +

    This keyword defines presets for multiple options that show up +in the print dialog of applications (such as iPhoto) that set the job +style hint to NSPrintPhotoJobStyleHint. Each preset maps to one or +more pairs of PPD options and choices as well as providing key/value data for +the application. The following standard preset names are currently defined:

    + +
      + +
    • General_with_Paper_Auto-Detect; Normal quality general printing with auto-detected media.
    • + +
    • General_with_Paper_Auto-Detect_-_Draft; Draft quality general printing with auto-detected media.
    • + +
    • General_on_Plain_Paper; Normal quality general printing on plain paper.
    • + +
    • General_on_Plain_Paper_-_Draft; Draft quality general printing on plain paper.
    • + +
    • Photo_with_Paper_Auto-Detect; Normal quality photo printing with auto-detected media.
    • + +
    • Photo_with_Paper_Auto-Detect_-_Fine; High quality photo printing with auto-detected media.
    • + +
    • Photo_on_Plain_Paper; Normal quality photo printing on plain paper.
    • + +
    • Photo_on_Plain_Paper_-_Fine; High quality photo printing on plain paper.
    • + +
    • Photo_on_Photo_Paper; Normal quality photo printing on glossy photo paper.
    • + +
    • Photo_on_Photo_Paper_-_Fine; High quality photo printing on glossy photo paper.
    • + +
    • Photo_on_Matte_Paper; Normal quality photo printing on matte paper.
    • + +
    • Photo_on_Matte_Paper_-_Fine; High quality photo printing on matte paper.
    • + +
    + +

    The value string consists of pairs of keywords, either an option name and +choice (*MainKeyword OptionKeyword) or a preset identifier and value +(com.apple.print.preset.foo value). The following preset identifiers are currently used:

    + +
      + +
    • com.apple.print.preset.graphicsType; specifies the type of printing used for this printing - "General" for general purpose printing and "Photo" for photo printing.
    • + +
    • com.apple.print.preset.media-front-coating; specifies the media type selected by this preset - "none" (plain paper), "glossy", "high-gloss", "semi-gloss", "satin", "matte", and "autodetect".
    • + +
    • com.apple.print.preset.output-mode; specifies the output mode for this preset - "color" (default for color printers) or "monochrome" (grayscale, default for B&W printers).
    • + +
    • com.apple.print.preset.quality; specifies the overall print quality selected by this preset - "low" (draft), "mid" (normal), or "high".
    • + +
    + +

    Presets, like options, can also be localized in multiple languages.

    + +

    Examples:

    + +
    +*APPrinterPreset Photo_on_Photo_Paper/Photo on Photo Paper: "
    +  *MediaType Glossy
    +  *ColorModel RGB
    +  *Resolution 300dpi
    +  com.apple.print.preset.graphicsType Photo
    +  com.apple.print.preset.quality mid
    +  com.apple.print.preset.media-front-coating glossy"
    +*End
    +*fr.APPrinterPreset Photo_on_Photo_Paper/Photo sur papier photographique: ""
    +
    + +

    Mac OS X 10.3APPrinterUtilityPath

    + +

    *APPrinterPrinterUtilityPath: "/Library/Printers/vendor/filename.app"

    + +

    This keyword defines a GUI application that can be used to do printer +maintenance functions such as cleaning the print head(s). See ... for more +information.

    + +

    Examples:

    + +
    +*% Define the printer utility application
    +*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/Tools/utility.app"
    +
    + +

    Mac OS X 10.6APScannerOnly

    + +

    *APScannerOnly: boolean

    + +

    This keyword specifies whether the device has scanning but no printing +capabilities. The default is False.

    + +

    Examples:

    + +
    +*APICADriver: True
    +*APScannerOnly: True
    +
    + +

    Mac OS X 10.3APScanAppBundleID

    + +

    *APScanAppBundleID: "bundle ID"

    + +

    This keyword defines the application to use when scanning pages from +the device.

    + +

    Examples:

    + +
    +*APICADriver: True
    +*APScanAppBundleID: "com.apple.ImageCaptureApp"
    +
    + + +

    Change History

    + +

    Changes in CUPS 1.5

    + +
      + +
    • Changes all instances of PPD attributes to PPD keywords, to be consistent with the parent specification from Adobe.
    • + +
    + + +

    Changes in CUPS 1.4.5

    + + + + +

    Changes in CUPS 1.4

    + + + + +

    Changes in CUPS 1.3.1

    + +
      + +
    • Added missing Mac OS X AP keywords.
    • + +
    • Added section on auto-configuration including the + OIDMainKeyword and ?MainKeyword + keywords.
    • + +
    • Minor reorganization.
    • + +
    + + +

    Changes in CUPS 1.3

    + + + +

    Changes in CUPS 1.2.8

    + +
      + +
    • Added section on supported PostScript commands for raster + drivers
    • + +
    + +

    Changes in CUPS 1.2

    + + + +

    Changes in CUPS 1.1

    + + diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in index ad4d082b3..d32412110 100644 --- a/man/cupsd.conf.man.in +++ b/man/cupsd.conf.man.in @@ -12,7 +12,7 @@ .\" which should have been included with this file. If this file is .\" file is missing or damaged, see the license at "http://www.cups.org/". .\" -.TH cupsd.conf 5 "CUPS" "28 January 2010" "Apple Inc." +.TH cupsd.conf 5 "CUPS" "5 November 2010" "Apple Inc." .SH NAME cupsd.conf \- server configuration file for cups .SH DESCRIPTION @@ -400,6 +400,26 @@ JobKillDelay seconds Specifies the number of seconds to wait before killing the filters and backend associated with a canceled or held job. .TP 5 +JobPrivateAccess all +.TP 5 +JobPrivateAccess default +.TP 5 +JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+ +.br +Specifies an access list for a job's private values. The "default" access list +is "@OWNER @SYSTEM". "@ACL" maps to the printer's requesting-user-name-allowed +or requesting-user-name-denied values. +.TP 5 +JobPrivateValues all +.TP 5 +JobPrivateValues default +.TP 5 +JobPrivateValues none +.TP 5 +JobPrivateValues attribute-name-1 [ ... attribute-name-N ] +Specifies the list of job values to make private. The "default" values are +"job-name", "job-originating-host-name", and "job-originating-user-name". +.TP 5 JobRetryInterval seconds .br Specifies the interval between retries of jobs in seconds. @@ -686,6 +706,27 @@ SSLPort .br Listens on the specified port for encrypted connections. .TP 5 +SubscriptionPrivateAccess all +.TP 5 +SubscriptionPrivateAccess default +.TP 5 +SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+ +.br +Specifies an access list for a subscription's private values. The "default" +access list is "@OWNER @SYSTEM". "@ACL" maps to the printer's +requesting-user-name-allowed or requesting-user-name-denied values. +.TP 5 +SubscriptionPrivateValues all +.TP 5 +SubscriptionPrivateValues default +.TP 5 +SubscriptionPrivateValues none +.TP 5 +SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ] +Specifies the list of job values to make private. The "default" values are +"notify-events", "notify-pull-method", "notify-recipient-uri", +"notify-subscriber-user-name", and "notify-user-data". +.TP 5 SystemGroup group-name [group-name ...] .br Specifies the group(s) to use for System class authentication. @@ -708,7 +749,7 @@ Specifies the user name or ID that is used when running external programs. .br http://localhost:631/help .SH COPYRIGHT -Copyright 2007-2009 by Apple Inc. +Copyright 2007-2010 by Apple Inc. .\" .\" End of "$Id: cupsd.conf.man.in 7935 2008-09-11 01:54:11Z mike $". .\" diff --git a/man/ipptool.man b/man/ipptool.man index 1e9f59b3c..31bd93de6 100644 --- a/man/ipptool.man +++ b/man/ipptool.man @@ -11,12 +11,14 @@ .\" which should have been included with this file. If this file is .\" file is missing or damaged, see the license at "http://www.cups.org/". .\" -.TH ipptool 1 "CUPS" "2 August 2010" "Apple Inc." +.TH ipptool 1 "CUPS" "17 October 2010" "Apple Inc." .SH NAME ipptool - perform internet printing protocol requests .SH SYNOPSIS .B ipptool -[ -C ] [ -E ] [ -I ] [ -L ] [ -S ] [ -V +[ -C ] [ -E ] [ -I ] [ -L ] [ -S ] [ -T +.I seconds +] [ -V .I version ] [ -X ] [ -c ] [ -d .I name=value @@ -52,6 +54,9 @@ Specifies that requests should be sent using the HTTP/1.0 "Content-Length:" head -S Forces (dedicated) SSL encryption when connecting to the server. .TP 5 +-T seconds +Specifies a timeout for IPP requests in seconds. +.TP 5 -V version Specifies the default IPP version to use: 1.0, 1.1, 2.0, 2.1, or 2.2. If not specified, version 1.1 is used. .TP 5 @@ -68,7 +73,7 @@ Defines the named variable. Defines the default request filename for tests. .TP 5 -i seconds -Specifies that the (last) file should be repeated at the specified interval. This option is incompatible with the \fI-x\fR (XML plist output) option. +Specifies that the (last) file should be repeated at the specified interval. This option is incompatible with the \fI-X\fR (XML plist output) option. .TP 5 -l Specifies that plain text output is desired. diff --git a/scheduler/auth.c b/scheduler/auth.c index 497997d6f..8b3571f29 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -1,9 +1,9 @@ /* * "$Id: auth.c 7830 2008-08-04 20:38:50Z mike $" * - * Authorization routines for the Common UNIX Printing System (CUPS). + * Authorization routines for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -17,12 +17,11 @@ * * Contents: * + * cupsdAddIPMask() - Add an IP address authorization mask. * cupsdAddLocation() - Add a location for authorization. * cupsdAddName() - Add a name to a location... - * cupsdAllowHost() - Add a host name that is allowed to access the - * location. - * cupsdAllowIP() - Add an IP address or network that is allowed to - * access the location. + * cupsdAddNameMask() - Add a host or interface name authorization + * mask. * cupsdAuthorize() - Validate any authorization credentials. * cupsdCheckAccess() - Check whether the given address is allowed to * access a location. @@ -32,22 +31,19 @@ * cupsdCopyLocation() - Make a copy of a location... * cupsdDeleteAllLocations() - Free all memory used for location * authorization. - * cupsdDeleteLocation() - Free all memory used by a location. - * cupsdDenyHost() - Add a host name that is not allowed to access - * the location. - * cupsdDenyIP() - Add an IP address or network that is not - * allowed to access the location. * cupsdFindBest() - Find the location entry that best matches the * resource. * cupsdFindLocation() - Find the named location. + * cupsdFreeLocation() - Free all memory used by a location. * cupsdIsAuthorized() - Check to see if the user is authorized... - * add_allow() - Add an allow mask to the location. - * add_deny() - Add a deny mask to the location. + * cupsdNewLocation() - Create a new location for authorization. * check_authref() - Check if an authorization services reference * has the supplied right. * compare_locations() - Compare two locations. + * copy_authmask() - Copy function for auth masks. * cups_crypt() - Encrypt the password using the DES or MD5 * algorithms, as needed. + * free_authmask() - Free function for auth masks. * get_md5_password() - Get an MD5 password. * pam_func() - PAM conversation function. * to64() - Base64-encode an integer value... @@ -108,16 +104,16 @@ extern void krb5_ipc_client_clear_target(void); * Local functions... */ -static cupsd_authmask_t *add_allow(cupsd_location_t *loc); -static cupsd_authmask_t *add_deny(cupsd_location_t *loc); #ifdef HAVE_AUTHORIZATION_H static int check_authref(cupsd_client_t *con, const char *right); #endif /* HAVE_AUTHORIZATION_H */ 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 && !defined(HAVE_USERSEC_H) static char *cups_crypt(const char *pw, const char *salt); #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ +static void free_authmask(cupsd_authmask_t *am, void *data); static char *get_md5_password(const char *username, const char *group, char passwd[33]); #if HAVE_LIBPAM @@ -151,54 +147,66 @@ static cupsd_authdata_t *auth_data; /* Current client being authenticated */ /* - * 'cupsdAddLocation()' - Add a location for authorization. + * 'cupsdAddIPMask()' - Add an IP address authorization mask. */ -cupsd_location_t * /* O - Pointer to new location record */ -cupsdAddLocation(const char *location) /* I - Location path */ +int /* O - 1 on success, 0 on failure */ +cupsdAddIPMask( + cups_array_t **masks, /* IO - Masks array (created as needed) */ + const unsigned address[4], /* I - IP address */ + const unsigned netmask[4]) /* I - IP netmask */ { - cupsd_location_t *temp; /* New location */ + cupsd_authmask_t temp; /* New host/domain mask */ - /* - * Make sure the locations array is created... - */ - - if (!Locations) - Locations = cupsArrayNew((cups_array_func_t)compare_locations, NULL); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, " + "netmask=%x:%x:%x:%x)", + masks, *masks, + address[0], address[1], address[2], address[3], + netmask[0], netmask[1], netmask[2], netmask[3]); - if (!Locations) - return (NULL); + temp.type = CUPSD_AUTH_IP; + memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address)); + memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask)); /* - * Try to allocate memory for the new location. + * Create the masks array as needed and add... */ - if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL) - return (NULL); + if (!*masks) + *masks = cupsArrayNew3(NULL, NULL, NULL, 0, + (cups_acopy_func_t)copy_authmask, + (cups_afree_func_t)free_authmask); - /* - * Initialize the record and copy the name over... - */ - - if ((temp->location = strdup(location)) == NULL) - { - free(temp); - return (NULL); - } - - temp->length = strlen(temp->location); + return (cupsArrayAdd(*masks, &temp)); +} - cupsArrayAdd(Locations, temp); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: added location \'%s\'", - location); +/* + * 'cupsdAddLocation()' - Add a location for authorization. + */ +void +cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */ +{ /* - * Return the new record... + * Make sure the locations array is created... */ - return (temp); + if (!Locations) + Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)NULL, + (cups_afree_func_t)cupsdFreeLocation); + + if (Locations) + { + cupsArrayAdd(Locations, loc); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"", + loc->location ? loc->location : "(null)"); + } } @@ -210,126 +218,98 @@ void cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */ char *name) /* I - Name to add */ { - char **temp; /* Pointer to names array */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", loc, name); - if (loc->num_names == 0) - temp = malloc(sizeof(char *)); - else - temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *)); - - if (temp == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add name to location %s: %s", - loc->location ? loc->location : "nil", strerror(errno)); - return; - } - - loc->names = temp; + if (!loc->names) + loc->names = cupsArrayNew3(NULL, NULL, NULL, 0, + (cups_acopy_func_t)_cupsStrAlloc, + (cups_afree_func_t)_cupsStrFree); - if ((temp[loc->num_names] = strdup(name)) == NULL) + if (!cupsArrayAdd(loc->names, name)) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to duplicate name for location %s: %s", loc->location ? loc->location : "nil", strerror(errno)); return; } - - loc->num_names ++; } /* - * 'cupsdAllowHost()' - Add a host name that is allowed to access the location. + * 'cupsdAddNameMask()' - Add a host or interface name authorization mask. */ -void -cupsdAllowHost(cupsd_location_t *loc, /* I - Location to add to */ - char *name) /* I - Name of host or domain to add */ +int /* O - 1 on success, 0 on failure */ +cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */ + char *name) /* I - Host or interface name */ { - cupsd_authmask_t *temp; /* New host/domain mask */ + cupsd_authmask_t temp; /* New host/domain mask */ char ifname[32], /* Interface name */ *ifptr; /* Pointer to end of name */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAllowHost(loc=%p(%s), name=\"%s\")", - loc, loc->location ? loc->location : "nil", name); - - if ((temp = add_allow(loc)) == NULL) - return; + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", + masks, *masks, name); if (!strcasecmp(name, "@LOCAL")) { /* - * Allow *interface*... + * Deny *interface*... */ - temp->type = CUPSD_AUTH_INTERFACE; - temp->mask.name.name = strdup("*"); - temp->mask.name.length = 1; + temp.type = CUPSD_AUTH_INTERFACE; + temp.mask.name.name = (char *)"*"; } else if (!strncasecmp(name, "@IF(", 4)) { /* - * Allow *interface*... + * Deny *interface*... */ strlcpy(ifname, name + 4, sizeof(ifname)); - ifptr = ifname + strlen(ifname); + ifptr = ifname + strlen(ifname) - 1; - if (ifptr[-1] == ')') + if (ifptr >= ifname && *ifptr == ')') { ifptr --; *ifptr = '\0'; } - temp->type = CUPSD_AUTH_INTERFACE; - temp->mask.name.name = strdup(ifname); - temp->mask.name.length = ifptr - ifname; + temp.type = CUPSD_AUTH_INTERFACE; + temp.mask.name.name = ifname; } else { /* - * Allow name... + * Deny name... */ - temp->type = CUPSD_AUTH_NAME; - temp->mask.name.name = strdup(name); - temp->mask.name.length = strlen(name); - } -} - + if (*name == '*') + name ++; -/* - * 'cupsdAllowIP()' - Add an IP address or network that is allowed to access - * the location. - */ + temp.type = CUPSD_AUTH_NAME; + temp.mask.name.name = (char *)name; + } -void -cupsdAllowIP( - cupsd_location_t *loc, /* I - Location to add to */ - const unsigned address[4], /* I - IP address to add */ - const unsigned netmask[4]) /* I - Netmask of address */ -{ - cupsd_authmask_t *temp; /* New host/domain mask */ + /* + * Set the name length... + */ + temp.mask.name.length = strlen(temp.mask.name.name); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAllowIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", - loc, loc->location ? loc->location : "nil", - address[0], address[1], address[2], address[3], - netmask[0], netmask[1], netmask[2], netmask[3]); + /* + * Create the masks array as needed and add... + */ - if ((temp = add_allow(loc)) == NULL) - return; + if (!*masks) + *masks = cupsArrayNew3(NULL, NULL, NULL, 0, + (cups_acopy_func_t)copy_authmask, + (cups_afree_func_t)free_authmask); - temp->type = CUPSD_AUTH_IP; - memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address)); - memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask)); + return (cupsArrayAdd(*masks, &temp)); } @@ -1232,20 +1212,20 @@ cupsdCheckAccess( case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */ allow = 1; - if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny)) + if (cupsdCheckAuth(ip, name, namelen, loc->deny)) allow = 0; - if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow)) + if (cupsdCheckAuth(ip, name, namelen, loc->allow)) allow = 1; break; case CUPSD_AUTH_DENY : /* Order Allow,Deny */ allow = 0; - if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow)) + if (cupsdCheckAuth(ip, name, namelen, loc->allow)) allow = 1; - if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny)) + if (cupsdCheckAuth(ip, name, namelen, loc->deny)) allow = 0; break; } @@ -1260,24 +1240,25 @@ cupsdCheckAccess( */ int /* O - 1 if mask matches, 0 otherwise */ -cupsdCheckAuth( - unsigned ip[4], /* I - Client address */ - char *name, /* I - Client hostname */ - int name_len, /* I - Length of hostname */ - int num_masks, /* I - Number of masks */ - cupsd_authmask_t *masks) /* I - Masks */ +cupsdCheckAuth(unsigned ip[4], /* I - Client address */ + char *name, /* I - Client hostname */ + int name_len, /* I - Length of hostname */ + cups_array_t *masks) /* I - Masks */ { - int i; /* Looping var */ - cupsd_netif_t *iface; /* Network interface */ - unsigned netip4; /* IPv4 network address */ + int i; /* Looping var */ + cupsd_authmask_t *mask; /* Current mask */ + cupsd_netif_t *iface; /* Network interface */ + unsigned netip4; /* IPv4 network address */ #ifdef AF_INET6 - unsigned netip6[4]; /* IPv6 network address */ + unsigned netip6[4]; /* IPv6 network address */ #endif /* AF_INET6 */ - while (num_masks > 0) + for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks); + mask; + mask = (cupsd_authmask_t *)cupsArrayNext(masks)) { - switch (masks->type) + switch (mask->type) { case CUPSD_AUTH_INTERFACE : /* @@ -1293,7 +1274,7 @@ cupsdCheckAuth( netip6[3] = htonl(ip[3]); #endif /* AF_INET6 */ - if (!strcmp(masks->mask.name.name, "*")) + if (!strcmp(mask->mask.name.name, "*")) { #ifdef __APPLE__ /* @@ -1361,7 +1342,7 @@ cupsdCheckAuth( iface; iface = (cupsd_netif_t *)cupsArrayNext(NetIFList)) { - if (strcmp(masks->mask.name.name, iface->name)) + if (strcmp(mask->mask.name.name, iface->name)) continue; if (iface->address.addr.sa_family == AF_INET) @@ -1401,17 +1382,17 @@ cupsdCheckAuth( * Check for exact name match... */ - if (!strcasecmp(name, masks->mask.name.name)) + if (!strcasecmp(name, mask->mask.name.name)) return (1); /* * Check for domain match... */ - if (name_len >= masks->mask.name.length && - masks->mask.name.name[0] == '.' && - !strcasecmp(name + name_len - masks->mask.name.length, - masks->mask.name.name)) + if (name_len >= mask->mask.name.length && + mask->mask.name.name[0] == '.' && + !strcasecmp(name + name_len - mask->mask.name.length, + mask->mask.name.name)) return (1); break; @@ -1421,17 +1402,14 @@ cupsdCheckAuth( */ for (i = 0; i < 4; i ++) - if ((ip[i] & masks->mask.ip.netmask[i]) != - masks->mask.ip.address[i]) + if ((ip[i] & mask->mask.ip.netmask[i]) != + mask->mask.ip.address[i]) break; if (i == 4) return (1); break; } - - masks ++; - num_masks --; } return (0); @@ -1731,137 +1709,78 @@ cupsdCopyKrb5Creds(cupsd_client_t *con) /* I - Client connection */ cupsd_location_t * /* O - New location */ cupsdCopyLocation( - cupsd_location_t **loc) /* IO - Original location */ + cupsd_location_t *loc) /* I - Original location */ { - int i; /* Looping var */ cupsd_location_t *temp; /* New location */ - char location[HTTP_MAX_URI]; - /* Location of resource */ /* - * Use a local copy of location because cupsdAddLocation may cause - * this memory to be moved... + * Make a copy of the original location... */ - strlcpy(location, (*loc)->location, sizeof(location)); - - if ((temp = cupsdAddLocation(location)) == NULL) + if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL) return (NULL); /* * Copy the information from the original location to the new one. */ - temp->limit = (*loc)->limit; - temp->order_type = (*loc)->order_type; - temp->type = (*loc)->type; - temp->level = (*loc)->level; - temp->satisfy = (*loc)->satisfy; - temp->encryption = (*loc)->encryption; + if (!loc) + return (temp); - if ((temp->num_names = (*loc)->num_names) > 0) - { - /* - * Copy the names array... - */ + if (loc->location) + temp->location = _cupsStrAlloc(loc->location); + + temp->limit = loc->limit; + temp->order_type = loc->order_type; + temp->type = loc->type; + temp->level = loc->level; + temp->satisfy = loc->satisfy; + temp->encryption = loc->encryption; - if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL) + if (loc->names) + { + if ((temp->names = cupsArrayDup(loc->names)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to allocate memory for %d names: %s", - temp->num_names, strerror(errno)); + "Unable to allocate memory for %d names: %s", + cupsArrayCount(loc->names), strerror(errno)); - cupsdDeleteLocation(temp); + cupsdFreeLocation(temp); return (NULL); } - - for (i = 0; i < temp->num_names; i ++) - if ((temp->names[i] = strdup((*loc)->names[i])) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to copy name \"%s\": %s", - (*loc)->names[i], strerror(errno)); - - cupsdDeleteLocation(temp); - return (NULL); - } } - if ((temp->num_allow = (*loc)->num_allow) > 0) + if (loc->allow) { /* * Copy allow rules... */ - if ((temp->allow = calloc(temp->num_allow, sizeof(cupsd_authmask_t))) == NULL) + if ((temp->allow = cupsArrayDup(loc->allow)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s", - temp->num_allow, strerror(errno)); - cupsdDeleteLocation(temp); + "Unable to allocate memory for %d allow rules: %s", + cupsArrayCount(loc->allow), strerror(errno)); + cupsdFreeLocation(temp); return (NULL); } - - for (i = 0; i < temp->num_allow; i ++) - switch (temp->allow[i].type = (*loc)->allow[i].type) - { - case CUPSD_AUTH_NAME : - temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length; - temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name); - - if (temp->allow[i].mask.name.name == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to copy allow name \"%s\": %s", - (*loc)->allow[i].mask.name.name, strerror(errno)); - cupsdDeleteLocation(temp); - return (NULL); - } - break; - case CUPSD_AUTH_IP : - memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip), - sizeof(cupsd_ipmask_t)); - break; - } } - if ((temp->num_deny = (*loc)->num_deny) > 0) + if (loc->deny) { /* * Copy deny rules... */ - if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL) + if ((temp->deny = cupsArrayDup(loc->deny)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s", - temp->num_deny, strerror(errno)); - cupsdDeleteLocation(temp); + "Unable to allocate memory for %d deny rules: %s", + cupsArrayCount(loc->deny), strerror(errno)); + cupsdFreeLocation(temp); return (NULL); } - - for (i = 0; i < temp->num_deny; i ++) - switch (temp->deny[i].type = (*loc)->deny[i].type) - { - case CUPSD_AUTH_NAME : - temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length; - temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name); - - if (temp->deny[i].mask.name.name == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdCopyLocation: Unable to copy deny name \"%s\": %s", - (*loc)->deny[i].mask.name.name, strerror(errno)); - cupsdDeleteLocation(temp); - return (NULL); - } - break; - case CUPSD_AUTH_IP : - memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip), - sizeof(cupsd_ipmask_t)); - break; - } } return (temp); @@ -1875,20 +1794,8 @@ cupsdCopyLocation( void cupsdDeleteAllLocations(void) { - cupsd_location_t *loc; /* Current location */ - - /* - * Free all of the allow/deny records first... - */ - - for (loc = (cupsd_location_t *)cupsArrayFirst(Locations); - loc; - loc = (cupsd_location_t *)cupsArrayNext(Locations)) - cupsdDeleteLocation(loc); - - /* - * Then free the location array... + * Free the location array, which will free all of the locations... */ cupsArrayDelete(Locations); @@ -1896,136 +1803,6 @@ cupsdDeleteAllLocations(void) } -/* - * 'cupsdDeleteLocation()' - Free all memory used by a location. - */ - -void -cupsdDeleteLocation( - cupsd_location_t *loc) /* I - Location to delete */ -{ - int i; /* Looping var */ - cupsd_authmask_t *mask; /* Current mask */ - - - cupsArrayRemove(Locations, loc); - - for (i = loc->num_names - 1; i >= 0; i --) - free(loc->names[i]); - - if (loc->num_names > 0) - free(loc->names); - - for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++) - if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE) - free(mask->mask.name.name); - - if (loc->num_allow > 0) - free(loc->allow); - - for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++) - if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE) - free(mask->mask.name.name); - - if (loc->num_deny > 0) - free(loc->deny); - - free(loc->location); - free(loc); -} - - -/* - * 'cupsdDenyHost()' - Add a host name that is not allowed to access the - * location. - */ - -void -cupsdDenyHost(cupsd_location_t *loc, /* I - Location to add to */ - char *name) /* I - Name of host or domain to add */ -{ - cupsd_authmask_t *temp; /* New host/domain mask */ - char ifname[32], /* Interface name */ - *ifptr; /* Pointer to end of name */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")", - loc, loc->location ? loc->location : "nil", name); - - if ((temp = add_deny(loc)) == NULL) - return; - - if (!strcasecmp(name, "@LOCAL")) - { - /* - * Deny *interface*... - */ - - temp->type = CUPSD_AUTH_INTERFACE; - temp->mask.name.name = strdup("*"); - temp->mask.name.length = 1; - } - else if (!strncasecmp(name, "@IF(", 4)) - { - /* - * Deny *interface*... - */ - - strlcpy(ifname, name + 4, sizeof(ifname)); - - ifptr = ifname + strlen(ifname); - - if (ifptr[-1] == ')') - { - ifptr --; - *ifptr = '\0'; - } - - temp->type = CUPSD_AUTH_INTERFACE; - temp->mask.name.name = strdup(ifname); - temp->mask.name.length = ifptr - ifname; - } - else - { - /* - * Deny name... - */ - - temp->type = CUPSD_AUTH_NAME; - temp->mask.name.name = strdup(name); - temp->mask.name.length = strlen(name); - } -} - - -/* - * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to - * access the location. - */ - -void -cupsdDenyIP(cupsd_location_t *loc, /* I - Location to add to */ - const unsigned address[4],/* I - IP address to add */ - const unsigned netmask[4])/* I - Netmask of address */ -{ - cupsd_authmask_t *temp; /* New host/domain mask */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", - loc, loc->location ? loc->location : "nil", - address[0], address[1], address[2], address[3], - netmask[0], netmask[1], netmask[2], netmask[3]); - - if ((temp = add_deny(loc)) == NULL) - return; - - temp->type = CUPSD_AUTH_IP; - memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address)); - memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask)); -} - - /* * 'cupsdFindBest()' - Find the location entry that best matches the resource. */ @@ -2157,6 +1934,22 @@ cupsdFindLocation(const char *location) /* I - Connection */ } +/* + * 'cupsdFreeLocation()' - Free all memory used by a location. + */ + +void +cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */ +{ + cupsArrayDelete(loc->names); + cupsArrayDelete(loc->allow); + cupsArrayDelete(loc->deny); + + _cupsStrFree(loc->location); + free(loc); +} + + /* * 'cupsdIsAuthorized()' - Check to see if the user is authorized... */ @@ -2165,13 +1958,14 @@ http_status_t /* O - HTTP_OK if authorized or error code */ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ const char *owner)/* I - Owner of object */ { - int i, j, /* Looping vars */ + int i, /* Looping vars */ auth, /* Authorization status */ type; /* Type of authentication */ unsigned address[4]; /* Authorization address */ cupsd_location_t *best; /* Best match for location so far */ int hostlen; /* Length of hostname */ - char username[256], /* Username to authorize */ + char *name, /* Current username */ + username[256], /* Username to authorize */ ownername[256], /* Owner name to authorize */ *ptr; /* Pointer into username */ struct passwd *pw; /* User password data */ @@ -2223,7 +2017,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, " "satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d", levels[best->level], types[type], - best->satisfy ? "ANY" : "ALL", best->num_names); + best->satisfy ? "ANY" : "ALL", cupsArrayCount(best->names)); if (best->limit == CUPSD_AUTH_LIMIT_IPP) cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", @@ -2294,7 +2088,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ */ if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */ - (type == CUPSD_AUTH_NONE && best->num_names == 0)) + (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0)) return (HTTP_OK); if (!con->username[0] && type == CUPSD_AUTH_NONE && @@ -2393,7 +2187,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ * any valid user is OK... */ - if (best->num_names == 0) + if (cupsArrayCount(best->names) == 0) return (HTTP_OK); /* @@ -2411,13 +2205,13 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ if (con->authref) { - for (i = 0; i < best->num_names; i ++) + for (name = (char *)cupsArrayFirst(best->names); + name; + name = (char *)cupsArrayNext(best->names)) { - if (!strncasecmp(best->names[i], "@AUTHKEY(", 9) && - check_authref(con, best->names[i] + 9)) + if (!strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9)) return (HTTP_OK); - else if (!strcasecmp(best->names[i], "@SYSTEM") && - SystemGroupAuthKey && + else if (!strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey && check_authref(con, SystemGroupAuthKey)) return (HTTP_OK); } @@ -2426,23 +2220,25 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ } #endif /* HAVE_AUTHORIZATION_H */ - for (i = 0; i < best->num_names; i ++) + for (name = (char *)cupsArrayFirst(best->names); + name; + name = (char *)cupsArrayNext(best->names)) { - if (!strcasecmp(best->names[i], "@OWNER") && owner && + if (!strcasecmp(name, "@OWNER") && owner && !strcasecmp(username, ownername)) return (HTTP_OK); - else if (!strcasecmp(best->names[i], "@SYSTEM")) + else if (!strcasecmp(name, "@SYSTEM")) { - for (j = 0; j < NumSystemGroups; j ++) - if (cupsdCheckGroup(username, pw, SystemGroups[j])) + for (i = 0; i < NumSystemGroups; i ++) + if (cupsdCheckGroup(username, pw, SystemGroups[i])) return (HTTP_OK); } - else if (best->names[i][0] == '@') + else if (name[0] == '@') { - if (cupsdCheckGroup(username, pw, best->names[i] + 1)) + if (cupsdCheckGroup(username, pw, name + 1)) return (HTTP_OK); } - else if (!strcasecmp(username, best->names[i])) + else if (!strcasecmp(username, name)) return (HTTP_OK); } @@ -2460,19 +2256,21 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ * Check to see if this user is in any of the named groups... */ - for (i = 0; i < best->num_names; i ++) + for (name = (char *)cupsArrayFirst(best->names); + name; + name = (char *)cupsArrayNext(best->names)) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", - best->names[i]); + name); - if (!strcasecmp(best->names[i], "@SYSTEM")) + if (!strcasecmp(name, "@SYSTEM")) { - for (j = 0; j < NumSystemGroups; j ++) - if (cupsdCheckGroup(username, pw, SystemGroups[j])) + for (i = 0; i < NumSystemGroups; i ++) + if (cupsdCheckGroup(username, pw, SystemGroups[i])) return (HTTP_OK); } - else if (cupsdCheckGroup(username, pw, best->names[i])) + else if (cupsdCheckGroup(username, pw, name)) return (HTTP_OK); } @@ -2488,85 +2286,41 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ /* - * 'add_allow()' - Add an allow mask to the location. - */ - -static cupsd_authmask_t * /* O - New mask record */ -add_allow(cupsd_location_t *loc) /* I - Location to add to */ -{ - cupsd_authmask_t *temp; /* New mask record */ - - - /* - * Range-check... - */ - - if (loc == NULL) - return (NULL); - - /* - * Try to allocate memory for the record... - */ - - if (loc->num_allow == 0) - temp = malloc(sizeof(cupsd_authmask_t)); - else - temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1)); - - if (temp == NULL) - return (NULL); - - loc->allow = temp; - temp += loc->num_allow; - loc->num_allow ++; - - /* - * Clear the mask record and return... - */ - - memset(temp, 0, sizeof(cupsd_authmask_t)); - return (temp); -} - - -/* - * 'add_deny()' - Add a deny mask to the location. + * 'cupsdNewLocation()' - Create a new location for authorization. + * + * Note: Still need to call cupsdAddLocation() to add it to the list of global + * locations. */ -static cupsd_authmask_t * /* O - New mask record */ -add_deny(cupsd_location_t *loc) /* I - Location to add to */ +cupsd_location_t * /* O - Pointer to new location record */ +cupsdNewLocation(const char *location) /* I - Location path */ { - cupsd_authmask_t *temp; /* New mask record */ + cupsd_location_t *temp; /* New location */ /* - * Range-check... + * Try to allocate memory for the new location. */ - if (loc == NULL) + if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL) return (NULL); /* - * Try to allocate memory for the record... + * Initialize the record and copy the name over... */ - if (loc->num_deny == 0) - temp = malloc(sizeof(cupsd_authmask_t)); - else - temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1)); - - if (temp == NULL) + if ((temp->location = _cupsStrAlloc(location)) == NULL) + { + free(temp); return (NULL); + } - loc->deny = temp; - temp += loc->num_deny; - loc->num_deny ++; + temp->length = strlen(temp->location); /* - * Clear the mask record and return... + * Return the new record... */ - memset(temp, 0, sizeof(cupsd_authmask_t)); return (temp); } @@ -2636,6 +2390,45 @@ compare_locations(cupsd_location_t *a, /* I - First location */ } +/* + * 'copy_authmask()' - Copy function for auth masks. + */ + +static cupsd_authmask_t * /* O - New auth mask */ +copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */ + void *data) /* I - User data (unused) */ +{ + cupsd_authmask_t *temp; /* New auth mask */ + + + (void)data; + + if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL) + { + memcpy(temp, mask, sizeof(cupsd_authmask_t)); + + if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE) + { + /* + * Make a copy of the name... + */ + + if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL) + { + /* + * Failed to make copy... + */ + + free(temp); + temp = NULL; + } + } + } + + return (temp); +} + + #if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H) /* * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms, @@ -2759,6 +2552,23 @@ cups_crypt(const char *pw, /* I - Password string */ #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ +/* + * 'free_authmask()' - Free function for auth masks. + */ + +static void +free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */ + void *data) /* I - User data (unused) */ +{ + (void)data; + + if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE) + _cupsStrFree(mask->mask.name.name); + + free(mask); +} + + /* * 'get_md5_password()' - Get an MD5 password. */ diff --git a/scheduler/auth.h b/scheduler/auth.h index 189ca2997..5e7525cbc 100644 --- a/scheduler/auth.h +++ b/scheduler/auth.h @@ -1,10 +1,9 @@ /* * "$Id: auth.h 7317 2008-02-15 22:29:27Z mike $" * - * Authorization definitions for the Common UNIX Printing System (CUPS) - * scheduler. + * Authorization definitions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -98,12 +97,9 @@ typedef struct type, /* Type of authentication */ level, /* Access level required */ satisfy; /* Satisfy any or all limits? */ - int num_names; /* Number of names */ - char **names; /* User or group names */ - int num_allow; /* Number of Allow lines */ - cupsd_authmask_t *allow; /* Allow lines */ - int num_deny; /* Number of Deny lines */ - cupsd_authmask_t *deny; /* Deny lines */ + cups_array_t *names, /* User or group names */ + *allow, /* Allow lines */ + *deny; /* Deny lines */ http_encryption_t encryption; /* To encrypt or not to encrypt... */ } cupsd_location_t; @@ -128,33 +124,30 @@ VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED); * Prototypes... */ -extern cupsd_location_t *cupsdAddLocation(const char *location); +extern int cupsdAddIPMask(cups_array_t **masks, + const unsigned address[4], + const unsigned netmask[4]); +extern void cupsdAddLocation(cupsd_location_t *loc); extern void cupsdAddName(cupsd_location_t *loc, char *name); -extern void cupsdAllowHost(cupsd_location_t *loc, char *name); -extern void cupsdAllowIP(cupsd_location_t *loc, - const unsigned address[4], - const unsigned netmask[4]); +extern int cupsdAddNameMask(cups_array_t **masks, char *name); extern void cupsdAuthorize(cupsd_client_t *con); extern int cupsdCheckAccess(unsigned ip[4], char *name, int namelen, cupsd_location_t *loc); extern int cupsdCheckAuth(unsigned ip[4], char *name, int namelen, - int num_masks, cupsd_authmask_t *masks); + cups_array_t *masks); extern int cupsdCheckGroup(const char *username, struct passwd *user, const char *groupname); #ifdef HAVE_GSSAPI extern krb5_ccache cupsdCopyKrb5Creds(cupsd_client_t *con); #endif /* HAVE_GSSAPI */ -extern cupsd_location_t *cupsdCopyLocation(cupsd_location_t **loc); +extern cupsd_location_t *cupsdCopyLocation(cupsd_location_t *loc); extern void cupsdDeleteAllLocations(void); -extern void cupsdDeleteLocation(cupsd_location_t *loc); -extern void cupsdDenyHost(cupsd_location_t *loc, char *name); -extern void cupsdDenyIP(cupsd_location_t *loc, - const unsigned address[4], - const unsigned netmask[4]); extern cupsd_location_t *cupsdFindBest(const char *path, http_state_t state); extern cupsd_location_t *cupsdFindLocation(const char *location); +extern void cupsdFreeLocation(cupsd_location_t *loc); extern http_status_t cupsdIsAuthorized(cupsd_client_t *con, const char *owner); +extern cupsd_location_t *cupsdNewLocation(const char *location); /* diff --git a/scheduler/banners.c b/scheduler/banners.c index ef73d2e7c..968de4911 100644 --- a/scheduler/banners.c +++ b/scheduler/banners.c @@ -1,9 +1,9 @@ /* * "$Id: banners.c 7221 2008-01-16 22:20:08Z mike $" * - * Banner routines for the Common UNIX Printing System (CUPS). + * Banner routines for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/banners.h b/scheduler/banners.h index 6ae8baa42..b215fe6ab 100644 --- a/scheduler/banners.h +++ b/scheduler/banners.h @@ -1,9 +1,9 @@ /* * "$Id: banners.h 6649 2007-07-11 21:46:42Z mike $" * - * Banner definitions for the Common UNIX Printing System (CUPS). + * Banner definitions for the CUPS scheduler. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/cert.c b/scheduler/cert.c index c34efac0c..0e791f8c4 100644 --- a/scheduler/cert.c +++ b/scheduler/cert.c @@ -1,7 +1,7 @@ /* * "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $" * - * Authentication certificate routines for CUPS. + * Authentication certificate routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. diff --git a/scheduler/cert.h b/scheduler/cert.h index 976600146..444897ebd 100644 --- a/scheduler/cert.h +++ b/scheduler/cert.h @@ -1,10 +1,9 @@ /* * "$Id: cert.h 7383 2008-03-20 20:58:07Z mike $" * - * Authentication certificate definitions for the Common UNIX - * Printing System (CUPS). + * Authentication certificate definitions for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/classes.c b/scheduler/classes.c index 72b5dbff0..92122c068 100644 --- a/scheduler/classes.c +++ b/scheduler/classes.c @@ -1,7 +1,7 @@ /* * "$Id: classes.c 7724 2008-07-14 06:06:06Z mike $" * - * Printer class routines for the Common UNIX Printing System (CUPS). + * Printer class routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. @@ -584,7 +584,7 @@ cupsdLoadAllClasses(void) if (value) { p->deny_users = 0; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -595,7 +595,7 @@ cupsdLoadAllClasses(void) if (value) { p->deny_users = 1; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -685,7 +685,8 @@ cupsdSaveAllClasses(void) cups_file_t *fp; /* classes.conf file */ char temp[1024], /* Temporary string */ backup[1024], /* printers.conf.O file */ - value[2048]; /* Value string */ + value[2048], /* Value string */ + *name; /* Current user name */ cupsd_printer_t *pclass; /* Current printer class */ int i; /* Looping var */ time_t curtime; /* Current time */ @@ -825,9 +826,10 @@ cupsdSaveAllClasses(void) cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit); cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit); - for (i = 0; i < pclass->num_users; i ++) - cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", - pclass->users[i]); + for (name = (char *)cupsArrayFirst(pclass->users); + name; + name = (char *)cupsArrayNext(pclass->users)) + cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", name); if (pclass->op_policy) cupsFilePutConf(fp, "OpPolicy", pclass->op_policy); diff --git a/scheduler/classes.h b/scheduler/classes.h index e9940ce2b..ef415762a 100644 --- a/scheduler/classes.h +++ b/scheduler/classes.h @@ -1,7 +1,7 @@ /* * "$Id: classes.h 6649 2007-07-11 21:46:42Z mike $" * - * Printer class definitions for the Common UNIX Printing System (CUPS). + * Printer class definitions for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. diff --git a/scheduler/client.c b/scheduler/client.c index 298fdfe30..f6a446195 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,7 +1,7 @@ /* * "$Id: client.c 7950 2008-09-17 00:21:59Z mike $" * - * Client routines for the Common UNIX Printing System (CUPS) scheduler. + * Client routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. @@ -2545,26 +2545,27 @@ cupsdSendHeader( * parameter as needed... */ - int i; /* Looping var */ - char *auth_key; /* Auth key buffer */ + char *name, /* Current user name */ + *auth_key; /* Auth key buffer */ size_t auth_size; /* Size of remaining buffer */ auth_key = auth_str + strlen(auth_str); auth_size = sizeof(auth_str) - (auth_key - auth_str); - for (i = 0; i < con->best->num_names; i ++) + for (name = (char *)cupsArrayFirst(con->best->names); + name; + name = (char *)cupsArrayNext(con->best->names)) { #ifdef HAVE_AUTHORIZATION_H - if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9)) + if (!strncasecmp(name, "@AUTHKEY(", 9)) { - snprintf(auth_key, auth_size, ", authkey=\"%s\"", - con->best->names[i] + 9); + snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9); /* end parenthesis is stripped in conf.c */ break; } else #endif /* HAVE_AUTHORIZATION_H */ - if (!strcasecmp(con->best->names[i], "@SYSTEM")) + if (!strcasecmp(name, "@SYSTEM")) { #ifdef HAVE_AUTHORIZATION_H if (SystemGroupAuthKey) @@ -3513,7 +3514,19 @@ get_cdsa_certificate( goto cleanup; } + CFRelease(search); + search = NULL; + if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN, + keychain, FALSE, &search))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot create identity search reference: %s (%d)", + cssmErrorString(err), (int)err); + goto cleanup; + } + err = SecIdentitySearchCopyNext(search, &identity); + } if (err) @@ -4477,11 +4490,21 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ *argv[4], /* Command-line arguments */ *envp[MAX_ENV + 1], /* Environment variables */ keychain[1024], /* Keychain argument */ - infofile[1024]; /* Type-in information for cert */ + infofile[1024], /* Type-in information for cert */ + localname[1024], /* Local hostname */ + *servername; /* Name of server in cert */ cups_file_t *fp; /* Seed/info file */ int infofd; /* Info file descriptor */ + if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) + { + snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); + servername = localname; + } + else + servername = con->servername; + /* * Run the "certtool" command to generate a self-signed certificate... */ @@ -4509,7 +4532,7 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ } cupsFilePrintf(fp, "%s\nr\n\ny\nb\ns\ny\n%s\n\n\n\n\n%s\ny\n", - con->servername, con->servername, ServerAdmin); + servername, servername, ServerAdmin); cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_INFO, diff --git a/scheduler/client.h b/scheduler/client.h index aa2cee818..a88f9dcef 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -1,9 +1,9 @@ /* * "$Id: client.h 7935 2008-09-11 01:54:11Z mike $" * - * Client definitions for the Common UNIX Printing System (CUPS) scheduler. + * Client definitions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/conf.c b/scheduler/conf.c index a10f1cdb3..b85c79ce6 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1,7 +1,7 @@ /* - * "$Id: conf.c 7952 2008-09-17 00:56:20Z mike $" + * "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $" * - * Configuration routines for the Common UNIX Printing System (CUPS). + * Configuration routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. @@ -29,6 +29,7 @@ * read_configuration() - Read a configuration file. * read_location() - Read a definition. * read_policy() - Read a definition. + * set_policy_defaults() - Set default policy values as needed. */ /* @@ -209,6 +210,7 @@ static int parse_protocols(const char *s); static int read_configuration(cups_file_t *fp); static int read_location(cups_file_t *fp, char *name, int linenum); static int read_policy(cups_file_t *fp, char *name, int linenum); +static void set_policy_defaults(cupsd_policy_t *pol); /* @@ -462,8 +464,7 @@ cupsdReadConfiguration(void) if (NumRelays > 0) { for (i = 0; i < NumRelays; i ++) - if (Relays[i].from.type == CUPSD_AUTH_NAME) - free(Relays[i].from.mask.name.name); + cupsArrayDelete(Relays[i].from); free(Relays); @@ -1166,6 +1167,27 @@ cupsdReadConfiguration(void) DefaultPolicyPtr = p = cupsdAddPolicy("default"); cupsdLogMessage(CUPSD_LOG_INFO, ""); + + cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateAccess default"); + cupsdAddString(&(p->job_access), "@OWNER"); + cupsdAddString(&(p->job_access), "@SYSTEM"); + + cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateValues default"); + cupsdAddString(&(p->job_attrs), "job-name"); + cupsdAddString(&(p->job_attrs), "job-originating-host-name"); + cupsdAddString(&(p->job_attrs), "job-originating-user-name"); + + cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateAccess default"); + cupsdAddString(&(p->sub_access), "@OWNER"); + cupsdAddString(&(p->sub_access), "@SYSTEM"); + + cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateValues default"); + cupsdAddString(&(p->job_attrs), "notify-events"); + cupsdAddString(&(p->job_attrs), "notify-pull-method"); + cupsdAddString(&(p->job_attrs), "notify-recipient-uri"); + cupsdAddString(&(p->job_attrs), "notify-subscriber-user-name"); + cupsdAddString(&(p->job_attrs), "notify-user-data"); + cupsdLogMessage(CUPSD_LOG_INFO, ""); cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); @@ -1185,7 +1207,7 @@ cupsdReadConfiguration(void) "Set-Job-Attributes Create-Job-Subscription " "Renew-Subscription Cancel-Subscription " "Get-Notifications Reprocess-Job Cancel-Current-Job " - "Suspend-Current-Job Resume-Job Cancel-Jobs " + "Suspend-Current-Job Resume-Job " "Cancel-My-Jobs Close-Job CUPS-Move-Job " "CUPS-Authenticate-Job CUPS-Get-Document>"); cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); @@ -1213,7 +1235,6 @@ cupsdReadConfiguration(void) cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB); cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB); cupsdAddPolicyOp(p, po, IPP_RESUME_JOB); - cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS); cupsdAddPolicyOp(p, po, IPP_CANCEL_MY_JOBS); cupsdAddPolicyOp(p, po, IPP_CLOSE_JOB); cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB); @@ -1229,7 +1250,7 @@ cupsdReadConfiguration(void) "Hold-New-Jobs Release-Held-New-Jobs " "Deactivate-Printer Activate-Printer Restart-Printer " "Shutdown-Printer Startup-Printer Promote-Job " - "Schedule-Job-After CUPS-Add-Printer " + "Schedule-Job-After Cancel-Jobs CUPS-Add-Printer " "CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class " "CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>"); cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); @@ -1257,6 +1278,7 @@ cupsdReadConfiguration(void) cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER); cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB); cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER); + cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS); cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER); cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER); cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS); @@ -1888,9 +1910,9 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ */ if (!strcasecmp(line, "Allow")) - cupsdAllowIP(loc, zeros, zeros); + cupsdAddIPMask(&(loc->allow), zeros, zeros); else - cupsdDenyIP(loc, zeros, zeros); + cupsdAddIPMask(&(loc->deny), zeros, zeros); } else if (!strcasecmp(value, "none")) { @@ -1899,9 +1921,9 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ */ if (!strcasecmp(line, "Allow")) - cupsdAllowIP(loc, ones, zeros); + cupsdAddIPMask(&(loc->allow), ones, zeros); else - cupsdDenyIP(loc, ones, zeros); + cupsdAddIPMask(&(loc->deny), ones, zeros); } #ifdef AF_INET6 else if (value[0] == '*' || value[0] == '.' || @@ -1918,9 +1940,9 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ value ++; if (!strcasecmp(line, "Allow")) - cupsdAllowHost(loc, value); + cupsdAddNameMask(&(loc->allow), value); else - cupsdDenyHost(loc, value); + cupsdAddNameMask(&(loc->deny), value); } else { @@ -1936,9 +1958,9 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ } if (!strcasecmp(line, "Allow")) - cupsdAllowIP(loc, ip, mask); + cupsdAddIPMask(&(loc->allow), ip, mask); else - cupsdDenyIP(loc, ip, mask); + cupsdAddIPMask(&(loc->deny), ip, mask); } /* @@ -2407,8 +2429,6 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ /* Line from file */ temp[HTTP_MAX_BUFFER], /* Temporary buffer for value */ - temp2[HTTP_MAX_BUFFER], - /* Temporary buffer 2 for value */ *ptr, /* Pointer into line/temp */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ @@ -2704,7 +2724,8 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ */ if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); + if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL) + cupsdAddLocation(location); if (location == NULL) cupsdLogMessage(CUPSD_LOG_ERROR, @@ -2752,35 +2773,43 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ */ if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); + if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL) + cupsdAddLocation(location); + if (location == NULL) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize browse access control list!"); else { - while (*value) + if (!strncasecmp(value, "from", 4)) { - if (!strncasecmp(value, "from", 4)) - { - /* - * Strip leading "from"... - */ + /* + * Skip leading "from"... + */ - value += 4; + value += 4; + } - while (isspace(*value & 255)) - value ++; + while (*value) + { + /* + * Skip leading whitespace... + */ - if (!*value) - break; - } + while (isspace(*value & 255)) + value ++; + + if (!*value) + break; /* * Find the end of the value... */ - for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + for (valueptr = value; + *valueptr && !isspace(*valueptr & 255); + valueptr ++); while (isspace(*valueptr & 255)) *valueptr++ = '\0'; @@ -2808,9 +2837,9 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ */ if (!strcasecmp(line, "BrowseAllow")) - cupsdAllowIP(location, zeros, zeros); + cupsdAddIPMask(&(location->allow), zeros, zeros); else - cupsdDenyIP(location, zeros, zeros); + cupsdAddIPMask(&(location->deny), zeros, zeros); } else if (!strcasecmp(value, "none")) { @@ -2819,28 +2848,26 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ */ if (!strcasecmp(line, "BrowseAllow")) - cupsdAllowIP(location, ones, zeros); + cupsdAddIPMask(&(location->allow), ones, zeros); else - cupsdDenyIP(location, ones, zeros); + cupsdAddIPMask(&(location->deny), ones, zeros); } #ifdef AF_INET6 else if (value[0] == '*' || value[0] == '.' || (!isdigit(value[0] & 255) && value[0] != '[')) #else - else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255)) + else if (value[0] == '*' || value[0] == '.' || + !isdigit(value[0] & 255)) #endif /* AF_INET6 */ { /* * Host or domain name... */ - if (value[0] == '*') - value ++; - if (!strcasecmp(line, "BrowseAllow")) - cupsdAllowHost(location, value); + cupsdAddNameMask(&(location->allow), value); else - cupsdDenyHost(location, value); + cupsdAddNameMask(&(location->deny), value); } else { @@ -2856,9 +2883,9 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ } if (!strcasecmp(line, "BrowseAllow")) - cupsdAllowIP(location, ip, mask); + cupsdAddIPMask(&(location->allow), ip, mask); else - cupsdDenyIP(location, ip, mask); + cupsdAddIPMask(&(location->deny), ip, mask); } /* @@ -2896,15 +2923,30 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ if (!strncasecmp(value, "from ", 5)) { /* - * Strip leading "from"... + * Skip leading "from"... */ value += 5; + /* + * Skip leading whitespace... + */ + while (isspace(*value)) value ++; } + /* + * Find the end of the from value... + */ + + for (valueptr = value; + *valueptr && !isspace(*valueptr & 255); + valueptr ++); + + while (isspace(*valueptr & 255)) + *valueptr++ = '\0'; + /* * Figure out what form the from address takes: * @@ -2930,24 +2972,13 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ * Host or domain name... */ - if (value[0] == '*') - value ++; - - strlcpy(temp, value, sizeof(temp)); - if ((ptr = strchr(temp, ' ')) != NULL) - *ptr = '\0'; - - relay->from.type = CUPSD_AUTH_NAME; - - if ((relay->from.mask.name.name = strdup(temp)) == NULL) + if (!cupsdAddNameMask(&(relay->from), value)) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate BrowseRelay name at line %d - %s.", linenum, strerror(errno)); continue; } - - relay->from.mask.name.length = strlen(temp); } else { @@ -2962,41 +2993,32 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ break; } - relay->from.type = CUPSD_AUTH_IP; - memcpy(relay->from.mask.ip.address, ip, - sizeof(relay->from.mask.ip.address)); - memcpy(relay->from.mask.ip.netmask, mask, - sizeof(relay->from.mask.ip.netmask)); + if (!cupsdAddIPMask(&(relay->from), ip, mask)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowseRelay IP at line %d - %s.", + linenum, strerror(errno)); + continue; + } } /* - * Skip value and trailing whitespace... + * Get "to" address and port... */ - for (; *value; value ++) - if (isspace(*value)) - break; - - while (isspace(*value)) - value ++; - - if (!strncasecmp(value, "to ", 3)) + if (!strncasecmp(valueptr, "to ", 3)) { /* * Strip leading "to"... */ - value += 3; + valueptr += 3; - while (isspace(*value)) - value ++; + while (isspace(*valueptr)) + valueptr ++; } - /* - * Get "to" address and port... - */ - - if ((addrlist = get_address(value, BrowsePort)) != NULL) + if ((addrlist = get_address(valueptr, BrowsePort)) != NULL) { /* * Only IPv4 addresses are supported... @@ -3012,37 +3034,29 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ httpAddrString(&(relay->to), temp, sizeof(temp)); - if (relay->from.type == CUPSD_AUTH_IP) - snprintf(temp2, sizeof(temp2), "%u.%u.%u.%u/%u.%u.%u.%u", - relay->from.mask.ip.address[0] >> 24, - (relay->from.mask.ip.address[0] >> 16) & 255, - (relay->from.mask.ip.address[0] >> 8) & 255, - relay->from.mask.ip.address[0] & 255, - relay->from.mask.ip.netmask[0] >> 24, - (relay->from.mask.ip.netmask[0] >> 16) & 255, - (relay->from.mask.ip.netmask[0] >> 8) & 255, - relay->from.mask.ip.netmask[0] & 255); - else - strlcpy(temp2, relay->from.mask.name.name, sizeof(temp2)); - cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)", - temp2, temp, ntohs(relay->to.ipv4.sin_port)); + value, temp, ntohs(relay->to.ipv4.sin_port)); NumRelays ++; } else + { + cupsArrayDelete(relay->from); + relay->from = NULL; + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", - value, linenum); + valueptr, linenum); + } httpAddrFreeList(addrlist); } else { - if (relay->from.type == CUPSD_AUTH_NAME) - free(relay->from.mask.name.name); + cupsArrayDelete(relay->from); + relay->from = NULL; cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", - value, linenum); + valueptr, linenum); } } else if (!strcasecmp(line, "BrowsePoll") && value) @@ -3563,9 +3577,11 @@ read_location(cups_file_t *fp, /* I - Configuration file */ *valptr; /* Pointer into value */ - if ((parent = cupsdAddLocation(location)) == NULL) + if ((parent = cupsdNewLocation(location)) == NULL) return (0); + cupsdAddLocation(parent); + parent->limit = CUPSD_AUTH_LIMIT_ALL; loc = parent; @@ -3589,9 +3605,11 @@ read_location(cups_file_t *fp, /* I - Configuration file */ continue; } - if ((loc = cupsdCopyLocation(&parent)) == NULL) + if ((loc = cupsdCopyLocation(parent)) == NULL) return (0); + cupsdAddLocation(loc); + loc->limit = 0; while (*value) { @@ -3694,106 +3712,7 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ "Missing before on line %d!", linenum); - /* - * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs, - * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that - * upgrades do not introduce new security issues... - */ - - if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL || - op->op == IPP_ANY_OPERATION) - { - if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL && - op->op != IPP_ANY_OPERATION) - { - /* - * Add a new limit for Validate-Job using the Print-Job limit as a - * template... - */ - - cupsdLogMessage(CUPSD_LOG_WARN, - "No limit for Validate-Job defined in policy %s " - "- using Print-Job's policy", pol->name); - - cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB); - } - } - - if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL || - op->op == IPP_ANY_OPERATION) - { - if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOB)) != NULL && - op->op != IPP_ANY_OPERATION) - { - /* - * Add a new limit for Cancel-Jobs using the Cancel-Job limit as a - * template... - */ - - cupsdLogMessage(CUPSD_LOG_WARN, - "No limit for Cancel-Jobs defined in policy %s " - "- using Cancel-Job's policy", pol->name); - - cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS); - } - } - - if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL || - op->op == IPP_ANY_OPERATION) - { - if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && - op->op != IPP_ANY_OPERATION) - { - /* - * Add a new limit for Cancel-My-Jobs using the Send-Document limit as - * a template... - */ - - cupsdLogMessage(CUPSD_LOG_WARN, - "No limit for Cancel-My-Jobs defined in policy %s " - "- using Send-Document's policy", pol->name); - - cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS); - } - } - - if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL || - op->op == IPP_ANY_OPERATION) - { - if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && - op->op != IPP_ANY_OPERATION) - { - /* - * Add a new limit for Close-Job using the Send-Document limit as a - * template... - */ - - cupsdLogMessage(CUPSD_LOG_WARN, - "No limit for Close-Job defined in policy %s " - "- using Send-Document's policy", pol->name); - - cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB); - } - } - - if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL || - op->op == IPP_ANY_OPERATION) - { - if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && - op->op != IPP_ANY_OPERATION) - { - /* - * Add a new limit for CUPS-Get-Document using the Send-Document - * limit as a template... - */ - - cupsdLogMessage(CUPSD_LOG_WARN, - "No limit for CUPS-Get-Document defined in policy %s " - "- using Send-Document's policy", pol->name); - - cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT); - } - } + set_policy_defaults(pol); return (linenum); } @@ -3874,6 +3793,109 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ op = NULL; } + else if (!strcasecmp(line, "JobPrivateAccess") || + !strcasecmp(line, "JobPrivateValues") || + !strcasecmp(line, "SubscriptionPrivateAccess") || + !strcasecmp(line, "SubscriptionPrivateValues")) + { + if (op) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "%s directive must appear outside ... " + "on line %d.", line, linenum); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } + else + { + /* + * Pull out whitespace-delimited values... + */ + + while (*value) + { + /* + * Find the end of the current value... + */ + + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); + + if (*valptr) + *valptr++ = '\0'; + + /* + * Save it appropriately... + */ + + if (!strcasecmp(line, "JobPrivateAccess")) + { + /* + * JobPrivateAccess {all|default|user/group list|@@ACL} + */ + + if (!strcasecmp(value, "default")) + { + cupsdAddString(&(pol->job_access), "@OWNER"); + cupsdAddString(&(pol->job_access), "@SYSTEM"); + } + else + cupsdAddString(&(pol->job_access), value); + } + else if (!strcasecmp(line, "JobPrivateValues")) + { + /* + * JobPrivateValues {all|none|default|attribute list} + */ + + if (!strcasecmp(value, "default")) + { + cupsdAddString(&(pol->job_attrs), "job-name"); + cupsdAddString(&(pol->job_attrs), "job-originating-host-name"); + cupsdAddString(&(pol->job_attrs), "job-originating-user-name"); + } + else + cupsdAddString(&(pol->job_attrs), value); + } + else if (!strcasecmp(line, "SubscriptionPrivateAccess")) + { + /* + * SubscriptionPrivateAccess {all|default|user/group list|@@ACL} + */ + + if (!strcasecmp(value, "default")) + { + cupsdAddString(&(pol->sub_access), "@OWNER"); + cupsdAddString(&(pol->sub_access), "@SYSTEM"); + } + else + cupsdAddString(&(pol->sub_access), value); + } + else /* if (!strcasecmp(line, "SubscriptionPrivateValues")) */ + { + /* + * SubscriptionPrivateValues {all|none|default|attribute list} + */ + + if (!strcasecmp(value, "default")) + { + cupsdAddString(&(pol->sub_attrs), "notify-events"); + cupsdAddString(&(pol->sub_attrs), "notify-pull-method"); + cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri"); + cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name"); + cupsdAddString(&(pol->sub_attrs), "notify-user-data"); + } + else + cupsdAddString(&(pol->sub_attrs), value); + } + + /* + * Find the next string on the line... + */ + + for (value = valptr; isspace(*value & 255); value ++); + } + } + } else if (!op) { cupsdLogMessage(CUPSD_LOG_ERROR, @@ -3907,5 +3929,183 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ /* - * End of "$Id: conf.c 7952 2008-09-17 00:56:20Z mike $". + * 'set_policy_defaults()' - Set default policy values as needed. + */ + +static void +set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */ +{ + cupsd_location_t *op; /* Policy operation */ + + + /* + * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs, + * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that + * upgrades do not introduce new security issues... + */ + + if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL || + op->op == IPP_ANY_OPERATION) + { + if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL && + op->op != IPP_ANY_OPERATION) + { + /* + * Add a new limit for Validate-Job using the Print-Job limit as a + * template... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Validate-Job defined in policy %s " + "- using Print-Job's policy.", pol->name); + + cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Validate-Job defined in policy %s " + "and no suitable template found.", pol->name); + } + + if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL || + op->op == IPP_ANY_OPERATION) + { + if ((op = cupsdFindPolicyOp(pol, IPP_PAUSE_PRINTER)) != NULL && + op->op != IPP_ANY_OPERATION) + { + /* + * Add a new limit for Cancel-Jobs using the Pause-Printer limit as a + * template... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Cancel-Jobs defined in policy %s " + "- using Pause-Printer's policy.", pol->name); + + cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Cancel-Jobs defined in policy %s " + "and no suitable template found.", pol->name); + } + + if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL || + op->op == IPP_ANY_OPERATION) + { + if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && + op->op != IPP_ANY_OPERATION) + { + /* + * Add a new limit for Cancel-My-Jobs using the Send-Document limit as + * a template... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Cancel-My-Jobs defined in policy %s " + "- using Send-Document's policy.", pol->name); + + cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Cancel-My-Jobs defined in policy %s " + "and no suitable template found.", pol->name); + } + + if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL || + op->op == IPP_ANY_OPERATION) + { + if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && + op->op != IPP_ANY_OPERATION) + { + /* + * Add a new limit for Close-Job using the Send-Document limit as a + * template... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Close-Job defined in policy %s " + "- using Send-Document's policy.", pol->name); + + cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for Close-Job defined in policy %s " + "and no suitable template found.", pol->name); + } + + if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL || + op->op == IPP_ANY_OPERATION) + { + if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL && + op->op != IPP_ANY_OPERATION) + { + /* + * Add a new limit for CUPS-Get-Document using the Send-Document + * limit as a template... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for CUPS-Get-Document defined in policy %s " + "- using Send-Document's policy.", pol->name); + + cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "No limit for CUPS-Get-Document defined in policy %s " + "and no suitable template found.", pol->name); + } + + /* + * Verify we have JobPrivateAccess, JobPrivateValues, + * SubscriptionPrivateAccess, and SubscriptionPrivateValues in the policy. + */ + + if (!pol->job_access) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "No JobPrivateAccess defined in policy %s " + "- using defaults.", pol->name); + cupsdAddString(&(pol->job_access), "@OWNER"); + cupsdAddString(&(pol->job_access), "@SYSTEM"); + } + + if (!pol->job_attrs) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "No JobPrivateValues defined in policy %s " + "- using defaults.", pol->name); + cupsdAddString(&(pol->job_attrs), "job-name"); + cupsdAddString(&(pol->job_attrs), "job-originating-host-name"); + cupsdAddString(&(pol->job_attrs), "job-originating-user-name"); + } + + if (!pol->sub_access) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "No SubscriptionPrivateAccess defined in policy %s " + "- using defaults.", pol->name); + cupsdAddString(&(pol->sub_access), "@OWNER"); + cupsdAddString(&(pol->sub_access), "@SYSTEM"); + } + + if (!pol->sub_attrs) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "No SubscriptionPrivateValues defined in policy %s " + "- using defaults.", pol->name); + cupsdAddString(&(pol->sub_attrs), "notify-events"); + cupsdAddString(&(pol->sub_attrs), "notify-pull-method"); + cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri"); + cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name"); + cupsdAddString(&(pol->sub_attrs), "notify-user-data"); + } +} + + +/* + * End of "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $". */ diff --git a/scheduler/conf.h b/scheduler/conf.h index d1cab69a1..c98e89a00 100644 --- a/scheduler/conf.h +++ b/scheduler/conf.h @@ -1,7 +1,7 @@ /* * "$Id: conf.h 7935 2008-09-11 01:54:11Z mike $" * - * Configuration file definitions for CUPS. + * Configuration file definitions for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c index 547a032d0..a7195985d 100644 --- a/scheduler/cups-deviced.c +++ b/scheduler/cups-deviced.c @@ -1,9 +1,9 @@ /* * "$Id: cups-deviced.c 7816 2008-07-30 20:53:31Z mike $" * - * Device scanning mini-daemon for the Common UNIX Printing System (CUPS). + * Device scanning mini-daemon for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index 1c5ce2560..f1ba5cc7c 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -177,8 +177,10 @@ VAR int Launchd VALUE(0); * Prototypes... */ +extern int cupsdAddString(cups_array_t **a, const char *s); extern void cupsdCheckProcess(void); extern void cupsdClearString(char **s); +extern void cupsdFreeStrings(cups_array_t **a); extern void cupsdHoldSignals(void); extern void cupsdReleaseSignals(void); extern void cupsdSetString(char **s, const char *v); diff --git a/scheduler/cupsfilter.c b/scheduler/cupsfilter.c index b40cc5564..e2e7bee84 100644 --- a/scheduler/cupsfilter.c +++ b/scheduler/cupsfilter.c @@ -1,7 +1,7 @@ /* * "$Id: cupsfilter.c 7952 2008-09-17 00:56:20Z mike $" * - * CUPS filtering program for CUPS. + * Filtering program for CUPS. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index 581ab6763..2f7f0e6c4 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -1,7 +1,7 @@ /* * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $" * - * Directory services routines for the Common UNIX Printing System (CUPS). + * Directory services routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. @@ -634,7 +634,7 @@ cupsdLoadRemoteCache(void) if (value) { p->deny_users = 0; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -645,7 +645,7 @@ cupsdLoadRemoteCache(void) if (value) { p->deny_users = 1; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -728,7 +728,8 @@ cupsdSaveRemoteCache(void) int i; /* Looping var */ cups_file_t *fp; /* printers.conf file */ char temp[1024], /* Temporary string */ - value[2048]; /* Value string */ + value[2048], /* Value string */ + *name; /* Current user name */ cupsd_printer_t *printer; /* Current printer class */ time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ @@ -829,9 +830,10 @@ cupsdSaveRemoteCache(void) printer->job_sheets[1]); cupsFilePutConf(fp, "JobSheets", value); - for (i = 0; i < printer->num_users; i ++) - cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", - printer->users[i]); + for (name = (char *)cupsArrayFirst(printer->users); + name; + name = (char *)cupsArrayNext(printer->users)) + cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name); for (i = printer->num_options, option = printer->options; i > 0; @@ -5194,24 +5196,20 @@ update_cups_browse(void) case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */ auth = CUPSD_AUTH_ALLOW; - if (cupsdCheckAuth(address, srcname, len, - BrowseACL->num_deny, BrowseACL->deny)) + if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny)) auth = CUPSD_AUTH_DENY; - if (cupsdCheckAuth(address, srcname, len, - BrowseACL->num_allow, BrowseACL->allow)) + if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow)) auth = CUPSD_AUTH_ALLOW; break; case CUPSD_AUTH_DENY : /* Order Allow,Deny */ auth = CUPSD_AUTH_DENY; - if (cupsdCheckAuth(address, srcname, len, - BrowseACL->num_allow, BrowseACL->allow)) + if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow)) auth = CUPSD_AUTH_ALLOW; - if (cupsdCheckAuth(address, srcname, len, - BrowseACL->num_deny, BrowseACL->deny)) + if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny)) auth = CUPSD_AUTH_DENY; break; } @@ -5323,7 +5321,7 @@ update_cups_browse(void) */ for (i = 0; i < NumRelays; i ++) - if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from))) + if (cupsdCheckAuth(address, srcname, len, Relays[i].from)) if (sendto(BrowseSocket, packet, bytes, 0, (struct sockaddr *)&(Relays[i].to), httpAddrLength(&(Relays[i].to))) <= 0) diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h index c17a25406..cc4eb2047 100644 --- a/scheduler/dirsvc.h +++ b/scheduler/dirsvc.h @@ -1,10 +1,9 @@ /* * "$Id: dirsvc.h 7933 2008-09-11 00:44:58Z mike $" * - * Directory services definitions for the Common UNIX Printing System - * (CUPS) scheduler. + * Directory services definitions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -62,7 +61,7 @@ typedef struct typedef struct { - cupsd_authmask_t from; /* Source address/name mask */ + cups_array_t *from; /* Source address/name mask(s) */ http_addr_t to; /* Destination address */ } cupsd_dirsvc_relay_t; diff --git a/scheduler/env.c b/scheduler/env.c index 94d7c355b..9cf6ff26f 100644 --- a/scheduler/env.c +++ b/scheduler/env.c @@ -1,9 +1,9 @@ /* * "$Id: env.c 7673 2008-06-18 22:31:26Z mike $" * - * Environment management routines for the Common UNIX Printing System (CUPS). + * Environment management routines for the CUPS scheduler. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/ipp.c b/scheduler/ipp.c index b1049b1ff..207596c08 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -167,7 +167,8 @@ static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr, int quickcopy); static void close_job(cupsd_client_t *con, ipp_attribute_t *uri); static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra, - ipp_tag_t group, int quickcopy); + ipp_tag_t group, int quickcopy, + cups_array_t *exclude); static int copy_banner(cupsd_client_t *con, cupsd_job_t *job, const char *name); static int copy_file(const char *from, const char *to); @@ -175,13 +176,14 @@ static int copy_model(cupsd_client_t *con, const char *from, const char *to); static void copy_job_attrs(cupsd_client_t *con, cupsd_job_t *job, - cups_array_t *ra); + cups_array_t *ra, cups_array_t *exclude); static void copy_printer_attrs(cupsd_client_t *con, cupsd_printer_t *printer, cups_array_t *ra); static void copy_subscription_attrs(cupsd_client_t *con, cupsd_subscription_t *sub, - cups_array_t *ra); + cups_array_t *ra, + cups_array_t *exclude); static void create_job(cupsd_client_t *con, ipp_attribute_t *uri); static cups_array_t *create_requested_array(ipp_t *request); static void create_subscription(cupsd_client_t *con, ipp_attribute_t *uri); @@ -4396,8 +4398,8 @@ static int /* O - 1 if OK, 0 if forbidden, check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *p) /* I - Printer or class */ { - int i; /* Looping var */ - char username[33]; /* Username */ + char username[33], /* Username */ + *name; /* Current user name */ cupsd_quota_t *q; /* Quota data */ #ifdef HAVE_MBR_UID_TO_UUID /* @@ -4464,10 +4466,10 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ * Check against users... */ - if (p->num_users == 0 && p->k_limit == 0 && p->page_limit == 0) + if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0) return (1); - if (p->num_users) + if (cupsArrayCount(p->users)) { #ifdef HAVE_MBR_UID_TO_UUID /* @@ -4498,21 +4500,22 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ endpwent(); #endif /* HAVE_MBR_UID_TO_UUID */ - for (i = 0; i < p->num_users; i ++) - if (p->users[i][0] == '@') + for (name = (char *)cupsArrayFirst(p->users); + name; + name = (char *)cupsArrayNext(p->users)) + if (name[0] == '@') { /* * Check group membership... */ #ifdef HAVE_MBR_UID_TO_UUID - if (p->users[i][1] == '#') + if (name[1] == '#') { - if (uuid_parse((char *)p->users[i] + 2, grp_uuid)) + if (uuid_parse(name + 2, grp_uuid)) uuid_clear(grp_uuid); } - else if ((mbr_err = mbr_group_name_to_uuid((char *)p->users[i] + 1, - grp_uuid)) != 0) + else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0) { /* * Invalid ACL entries are ignored for matching; just record a @@ -4521,10 +4524,10 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: UUID lookup failed for ACL entry " - "\"%s\" (err=%d)", p->users[i], mbr_err); + "\"%s\" (err=%d)", name, mbr_err); cupsdLogMessage(CUPSD_LOG_WARN, "Access control entry \"%s\" not a valid group name; " - "entry ignored", p->users[i]); + "entry ignored", name); } if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid, @@ -4536,7 +4539,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: group \"%s\" membership check " - "failed (err=%d)", p->users[i] + 1, mbr_err); + "failed (err=%d)", name + 1, mbr_err); is_member = 0; } @@ -4548,20 +4551,19 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ break; #else - if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + if (cupsdCheckGroup(username, pw, name + 1)) break; #endif /* HAVE_MBR_UID_TO_UUID */ } #ifdef HAVE_MBR_UID_TO_UUID else { - if (p->users[i][0] == '#') + if (name[0] == '#') { - if (uuid_parse((char *)p->users[i] + 1, usr2_uuid)) + if (uuid_parse(name + 1, usr2_uuid)) uuid_clear(usr2_uuid); } - else if ((mbr_err = mbr_user_name_to_uuid((char *)p->users[i], - usr2_uuid)) != 0) + else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0) { /* * Invalid ACL entries are ignored for matching; just record a @@ -4570,21 +4572,21 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: UUID lookup failed for ACL entry " - "\"%s\" (err=%d)", p->users[i], mbr_err); + "\"%s\" (err=%d)", name, mbr_err); cupsdLogMessage(CUPSD_LOG_WARN, "Access control entry \"%s\" not a valid user name; " - "entry ignored", p->users[i]); + "entry ignored", name); } if (!uuid_compare(usr_uuid, usr2_uuid)) break; } #else - else if (!strcasecmp(username, p->users[i])) + else if (!strcasecmp(username, name)) break; #endif /* HAVE_MBR_UID_TO_UUID */ - if ((i < p->num_users) == p->deny_users) + if ((name != NULL) == p->deny_users) { cupsdLogMessage(CUPSD_LOG_INFO, "Denying user \"%s\" access to printer \"%s\"...", @@ -4940,7 +4942,8 @@ copy_attrs(ipp_t *to, /* I - Destination request */ ipp_t *from, /* I - Source request */ cups_array_t *ra, /* I - Requested attributes */ ipp_tag_t group, /* I - Group to copy */ - int quickcopy) /* I - Do a quick copy? */ + int quickcopy, /* I - Do a quick copy? */ + cups_array_t *exclude) /* I - Attributes to exclude? */ { ipp_attribute_t *fromattr; /* Source attribute */ @@ -4962,6 +4965,23 @@ copy_attrs(ipp_t *to, /* I - Destination request */ fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name) continue; + if (exclude && + (cupsArrayFind(exclude, fromattr->name) || + cupsArrayFind(exclude, "all"))) + { + /* + * We need to exclude this attribute for security reasons; we require the + * job-id and job-printer-uri attributes regardless of the security + * settings for IPP conformance. + * + * Subscription attribute security is handled by copy_subscription_attrs(). + */ + + if (strcmp(fromattr->name, "job-id") && + strcmp(fromattr->name, "job-printer-uri")) + continue; + } + if (!ra || cupsArrayFind(ra, fromattr->name)) { /* @@ -5608,7 +5628,8 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ static void copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job, /* I - Job */ - cups_array_t *ra) /* I - Requested attributes array */ + cups_array_t *ra, /* I - Requested attributes array */ + cups_array_t *exclude) /* I - Private attributes array */ { char job_uri[HTTP_MAX_URI]; /* Job URI */ @@ -5621,26 +5642,34 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ con->servername, con->serverport, "/jobs/%d", job->id); - if (!ra || cupsArrayFind(ra, "document-count")) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "document-count", job->num_files); + if (!cupsArrayFind(exclude, "all")) + { + if ((!exclude || !cupsArrayFind(exclude, "document-count")) && + (!ra || cupsArrayFind(ra, "document-count"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "document-count", job->num_files); - if (!ra || cupsArrayFind(ra, "job-media-progress")) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "job-media-progress", job->progress); + if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) && + (!ra || cupsArrayFind(ra, "job-media-progress"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "job-media-progress", job->progress); - if (!ra || cupsArrayFind(ra, "job-more-info")) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, - "job-more-info", NULL, job_uri); + if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) && + (!ra || cupsArrayFind(ra, "job-more-info"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, + "job-more-info", NULL, job_uri); - if (job->state_value > IPP_JOB_PROCESSING && - (!ra || cupsArrayFind(ra, "job-preserved"))) - ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved", - job->num_files > 0); + if (job->state_value > IPP_JOB_PROCESSING && + (!exclude || !cupsArrayFind(exclude, "job-preserved")) && + (!ra || cupsArrayFind(ra, "job-preserved"))) + ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved", + job->num_files > 0); - if (!ra || cupsArrayFind(ra, "job-printer-up-time")) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "job-printer-up-time", time(NULL)); + if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) && + (!ra || cupsArrayFind(ra, "job-printer-up-time"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "job-printer-up-time", time(NULL)); + } if (!ra || cupsArrayFind(ra, "job-state-reasons")) add_job_state_reasons(con, job); @@ -5649,7 +5678,7 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); - copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0); + copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude); } @@ -5821,7 +5850,7 @@ copy_printer_attrs( for (i = 0; i < printer->num_history; i ++) copy_attrs(history->values[i].collection = ippNew(), printer->history[i], - NULL, IPP_TAG_ZERO, 0); + NULL, IPP_TAG_ZERO, 0, NULL); } if (!ra || cupsArrayFind(ra, "printer-state-message")) @@ -5875,10 +5904,10 @@ copy_printer_attrs( if (!ra || cupsArrayFind(ra, "queued-job-count")) add_queued_job_count(con, printer); - copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0); + copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL); if (printer->ppd_attrs) - copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0); - copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY); + 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); } @@ -5890,7 +5919,8 @@ static void copy_subscription_attrs( cupsd_client_t *con, /* I - Client connection */ cupsd_subscription_t *sub, /* I - Subscription */ - cups_array_t *ra) /* I - Requested attributes array */ + cups_array_t *ra, /* I - Requested attributes array */ + cups_array_t *exclude) /* I - Private attributes array */ { ipp_attribute_t *attr; /* Current attribute */ char printer_uri[HTTP_MAX_URI]; @@ -5900,56 +5930,92 @@ copy_subscription_attrs( const char *name; /* Current event name */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)", + con, sub, ra, exclude); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. */ - if (!ra || cupsArrayFind(ra, "notify-events")) + if (!exclude || !cupsArrayFind(exclude, "all")) { - if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + if ((!exclude || !cupsArrayFind(exclude, "notify-events")) && + (!ra || cupsArrayFind(ra, "notify-events"))) { - /* - * Simple event list... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events"); - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, - (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), - "notify-events", NULL, name); - } - else - { - /* - * Complex event list... - */ + if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + { + /* + * Simple event list... + */ + + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, + (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "notify-events", NULL, name); + } + else + { + /* + * Complex event list... + */ - for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) - if (sub->mask & mask) - count ++; + for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) + 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_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "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); + 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); - count ++; - } + count ++; + } + } } + + if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) && + (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration")))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-lease-duration", sub->lease); + + if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) && + (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri")))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, + "notify-recipient-uri", NULL, sub->recipient); + else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) && + (!ra || cupsArrayFind(ra, "notify-pull-method"))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, + "notify-pull-method", NULL, "ippget"); + + if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) && + (!ra || cupsArrayFind(ra, "notify-subscriber-user-name"))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, + "notify-subscriber-user-name", NULL, sub->owner); + + if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) && + (!ra || cupsArrayFind(ra, "notify-time-interval"))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-time-interval", sub->interval); + + if (sub->user_data_len > 0 && + (!exclude || !cupsArrayFind(exclude, "notify-user-data")) && + (!ra || cupsArrayFind(ra, "notify-user-data"))) + ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data", + sub->user_data, sub->user_data_len); } if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id"))) ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-job-id", sub->job->id); - if (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))) - ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-lease-duration", sub->lease); - if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri"))) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), @@ -5959,28 +6025,9 @@ copy_subscription_attrs( "notify-printer-uri", NULL, printer_uri); } - if (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, - "notify-recipient-uri", NULL, sub->recipient); - else if (!ra || cupsArrayFind(ra, "notify-pull-method")) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, - "notify-pull-method", NULL, "ippget"); - - if (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, - "notify-subscriber-user-name", NULL, sub->owner); - if (!ra || cupsArrayFind(ra, "notify-subscription-id")) ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); - - if (!ra || cupsArrayFind(ra, "notify-time-interval")) - ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-time-interval", sub->interval); - - if (sub->user_data_len > 0 && (!ra || cupsArrayFind(ra, "notify-user-data"))) - ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data", - sub->user_data, sub->user_data_len); } @@ -7004,12 +7051,14 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ cupsd_printer_t *printer; /* Current printer */ - char scheme[HTTP_MAX_URI], /* Method portion of URI */ + cupsd_policy_t *policy; /* Current security policy */ + char scheme[HTTP_MAX_URI], /* Scheme portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - cups_array_t *ra; /* Requested attributes array */ + cups_array_t *ra, /* Requested attributes array */ + *exclude; /* Private attributes array */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con, @@ -7082,20 +7131,18 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ printer = cupsdFindDest(job->dest); if (printer) - { - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, - NULL)) != HTTP_OK) - { - send_http_error(con, status, printer); - return; - } - } - else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK) { send_http_error(con, status, NULL); return; } + exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username); + /* * Copy attributes... */ @@ -7103,7 +7150,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLoadJob(job); ra = create_requested_array(con->request); - copy_job_attrs(con, job, ra); + copy_job_attrs(con, job, ra, exclude); cupsArrayDelete(ra); con->response->request.status.status_code = IPP_OK; @@ -7137,7 +7184,9 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Current job pointer */ cupsd_printer_t *printer; /* Printer */ cups_array_t *list; /* Which job list... */ - cups_array_t *ra; /* Requested attributes array */ + cups_array_t *ra, /* Requested attributes array */ + *exclude; /* Private attributes array */ + cupsd_policy_t *policy; /* Current policy */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd, @@ -7200,15 +7249,11 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ */ if (printer) - { - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, - NULL)) != HTTP_OK) - { - send_http_error(con, status, printer); - return; - } - } - else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK) { send_http_error(con, status, NULL); return; @@ -7395,7 +7440,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (i > 0) ippAddSeparator(con->response); - copy_job_attrs(con, job, ra); + exclude = cupsdGetPrivateAttrs(job->printer ? + job->printer->op_policy_ptr : + policy, con, job->printer, + job->username); + + copy_job_attrs(con, job, ra, exclude); } } else @@ -7451,7 +7501,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ count ++; - copy_job_attrs(con, job, ra); + exclude = cupsdGetPrivateAttrs(job->printer ? + job->printer->op_policy_ptr : + policy, con, job->printer, + job->username); + + copy_job_attrs(con, job, ra, exclude); } cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count); @@ -7577,7 +7632,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ * If we don't have any new events, nothing to do here... */ - if (min_seq > (sub->first_event_id + sub->num_events)) + if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events))) continue; /* @@ -7589,12 +7644,13 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ else j = min_seq - sub->first_event_id; - for (; j < sub->num_events; j ++) + for (; j < cupsArrayCount(sub->events); j ++) { ippAddSeparator(con->response); - copy_attrs(con->response, sub->events[j]->attrs, NULL, - IPP_TAG_EVENT_NOTIFICATION, 0); + copy_attrs(con->response, + ((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL, + IPP_TAG_EVENT_NOTIFICATION, 0, NULL); } } } @@ -8162,7 +8218,8 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ * access... */ - if (printer->num_users && username && !user_allowed(printer, username)) + if (cupsArrayCount(printer->users) && username && + !user_allowed(printer, username)) continue; /* @@ -8199,7 +8256,9 @@ get_subscription_attrs( { http_status_t status; /* Policy status */ cupsd_subscription_t *sub; /* Subscription */ - cups_array_t *ra; /* Requested attributes array */ + cupsd_policy_t *policy; /* Current security policy */ + cups_array_t *ra, /* Requested attributes array */ + *exclude; /* Private attributes array */ cupsdLogMessage(CUPSD_LOG_DEBUG2, @@ -8225,14 +8284,19 @@ get_subscription_attrs( * Check policy... */ - if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr : - DefaultPolicyPtr, - con, sub->owner)) != HTTP_OK) + if (sub->dest) + policy = sub->dest->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK) { send_http_error(con, status, sub->dest); return; } + exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. @@ -8240,7 +8304,7 @@ get_subscription_attrs( ra = create_requested_array(con->request); - copy_subscription_attrs(con, sub, ra); + copy_subscription_attrs(con, sub, ra, exclude); cupsArrayDelete(ra); @@ -8274,6 +8338,8 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ int port; /* Port portion of URI */ cupsd_job_t *job; /* Job pointer */ cupsd_printer_t *printer; /* Printer */ + cupsd_policy_t *policy; /* Policy */ + cups_array_t *exclude; /* Private attributes array */ cupsdLogMessage(CUPSD_LOG_DEBUG2, @@ -8337,9 +8403,12 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(printer ? printer->op_policy_ptr : - DefaultPolicyPtr, - con, NULL)) != HTTP_OK) + if (printer) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK) { send_http_error(con, status, printer); return; @@ -8376,7 +8445,12 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ (!username[0] || !strcasecmp(username, sub->owner))) { ippAddSeparator(con->response); - copy_subscription_attrs(con, sub, ra); + + exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr : + policy, con, sub->dest, + sub->owner); + + copy_subscription_attrs(con, sub, ra, exclude); count ++; if (limit && count >= limit) @@ -11198,7 +11272,7 @@ set_printer_defaults( } else if (!strcmp(attr->name, "requesting-user-name-allowed")) { - cupsdFreePrinterUsers(printer); + cupsdFreeStrings(&(printer->users)); printer->deny_users = 0; @@ -11207,12 +11281,12 @@ set_printer_defaults( strcmp(attr->values[0].string.text, "all"))) { for (i = 0; i < attr->num_values; i ++) - cupsdAddPrinterUser(printer, attr->values[i].string.text); + cupsdAddString(&(printer->users), attr->values[i].string.text); } } else if (!strcmp(attr->name, "requesting-user-name-denied")) { - cupsdFreePrinterUsers(printer); + cupsdFreeStrings(&(printer->users)); printer->deny_users = 1; @@ -11221,7 +11295,7 @@ set_printer_defaults( strcmp(attr->values[0].string.text, "none"))) { for (i = 0; i < attr->num_values; i ++) - cupsdAddPrinterUser(printer, attr->values[i].string.text); + cupsdAddString(&(printer->users), attr->values[i].string.text); } } else if (!strcmp(attr->name, "job-quota-period")) @@ -11401,6 +11475,7 @@ static void start_printer(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { + int i; /* Temporary variable */ http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer/class) */ cupsd_printer_t *printer; /* Printer data */ @@ -11451,6 +11526,21 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ cupsdCheckJobs(); + /* + * Check quotas... + */ + + if ((i = check_quotas(con, printer)) < 0) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached.")); + return; + } + else if (i == 0) + { + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print.")); + return; + } + /* * Everything was ok, so return OK status... */ @@ -11634,13 +11724,13 @@ static int /* O - 0 if not allowed, 1 if allowed */ user_allowed(cupsd_printer_t *p, /* I - Printer or class */ const char *username) /* I - Username */ { - int i; /* Looping var */ struct passwd *pw; /* User password data */ char baseuser[256], /* Base username */ - *baseptr; /* Pointer to "@" in base username */ + *baseptr, /* Pointer to "@" in base username */ + *name; /* Current user name */ - if (p->num_users == 0) + if (cupsArrayCount(p->users) == 0) return (1); if (!strcmp(username, "root")) @@ -11663,31 +11753,33 @@ user_allowed(cupsd_printer_t *p, /* I - Printer or class */ pw = getpwnam(username); endpwent(); - for (i = 0; i < p->num_users; i ++) + for (name = (char *)cupsArrayFirst(p->users); + name; + name = (char *)cupsArrayNext(p->users)) { - if (p->users[i][0] == '@') + if (name[0] == '@') { /* * Check group membership... */ - if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + if (cupsdCheckGroup(username, pw, name + 1)) break; } - else if (p->users[i][0] == '#') + else if (name[0] == '#') { /* * Check UUID... */ - if (cupsdCheckGroup(username, pw, p->users[i])) + if (cupsdCheckGroup(username, pw, name)) break; } - else if (!strcasecmp(username, p->users[i])) + else if (!strcasecmp(username, name)) break; } - return ((i < p->num_users) != p->deny_users); + return ((name != NULL) != p->deny_users); } diff --git a/scheduler/job.c b/scheduler/job.c index cc395d311..a58ab311d 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -294,6 +294,9 @@ cupsdCheckJobs(void) if (job->kill_time && job->kill_time <= curtime) { + cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job!", + job->id); + stop_job(job, CUPSD_JOB_FORCE); continue; } @@ -2721,6 +2724,12 @@ finalize_job(cupsd_job_t *job, /* I - Job */ cupsdDestroyProfile(job->profile); job->profile = NULL; + /* + * Clear the unresponsive job watchdog timer... + */ + + job->kill_time = 0; + /* * Close pipes and status buffer... */ @@ -3068,7 +3077,7 @@ get_options(cupsd_job_t *job, /* I - Job */ output_mode = _PWG_OUTPUT_MODE_COLOR; if ((attr = ippFindAttribute(job->attrs, "print-quality", - IPP_TAG_INTEGER)) != NULL && + IPP_TAG_ENUM)) != NULL && attr->values[0].integer >= IPP_QUALITY_DRAFT && attr->values[0].integer <= IPP_QUALITY_HIGH) print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT; diff --git a/scheduler/job.h b/scheduler/job.h index 16dd09ff7..2268886b0 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -1,9 +1,9 @@ /* * "$Id: job.h 7883 2008-08-28 20:38:13Z mike $" * - * Print job definitions for the Common UNIX Printing System (CUPS) scheduler. + * Print job definitions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -40,6 +40,7 @@ struct cupsd_job_s /**** Job request ****/ char *username; /* Printing user */ char *dest; /* Destination printer or class */ cups_ptype_t dtype; /* Destination type */ + cupsd_printer_t *printer; /* Printer this job is assigned to */ int num_files; /* Number of files in job */ mime_type_t **filetypes; /* File types */ int *compressions; /* Compression status of each file */ @@ -68,7 +69,6 @@ struct cupsd_job_s /**** Job request ****/ /* Filter process IDs, 0 terminated */ int backend; /* Backend process ID */ int status; /* Status code from filters */ - cupsd_printer_t *printer; /* Printer this job is assigned to */ int tries; /* Number of tries for this job */ char *auth_username, /* AUTH_USERNAME environment variable, * if any */ diff --git a/scheduler/listen.c b/scheduler/listen.c index 85c807166..15af46f06 100644 --- a/scheduler/listen.c +++ b/scheduler/listen.c @@ -1,10 +1,9 @@ /* * "$Id: listen.c 7918 2008-09-08 22:03:01Z mike $" * - * Server listening routines for the Common UNIX Printing System (CUPS) - * scheduler. + * Server listening routines for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/log.c b/scheduler/log.c index 09bb273e9..80ee8e077 100644 --- a/scheduler/log.c +++ b/scheduler/log.c @@ -1,7 +1,7 @@ /* * "$Id: log.c 7918 2008-09-08 22:03:01Z mike $" * - * Log file routines for the Common UNIX Printing System (CUPS). + * Log file routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. diff --git a/scheduler/main.c b/scheduler/main.c index 1c0bdf4f8..cbd6732d6 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -14,26 +14,29 @@ * * Contents: * - * main() - Main entry for the CUPS scheduler. - * cupsdClosePipe() - Close a pipe as necessary. - * cupsdOpenPipe() - Create a pipe which is closed on exec. - * cupsdHoldSignals() - Hold child and termination signals. - * cupsdReleaseSignals() - Release signals for delivery. - * cupsdSetString() - Set a string value. - * cupsdSetStringf() - Set a formatted string value. - * cupsd_clean_files() - Clean out old files. - * launchd_checkin() - Check-in with launchd and collect the - * listening fds. - * launchd_checkout() - Check-out with launchd. - * parent_handler() - Catch USR1/CHLD signals... - * process_children() - Process all dead children... - * select_timeout() - Calculate the select timeout value. - * sigchld_handler() - Handle 'child' signals from old processes. - * sighup_handler() - Handle 'hangup' signals to reconfigure the - * scheduler. - * sigterm_handler() - Handle 'terminate' signals that stop the - * scheduler. - * usage() - Show scheduler usage. + * main() - Main entry for the CUPS scheduler. + * cupsdAddString() - Copy and add a string to an array. + * cupsdCheckProcess() - Tell the main loop to check for dead children. + * cupsdClearString() - Clear a string. + * cupsdClosePipe() - Close a pipe as necessary. + * cupsdFreeStrings() - Free an array of strings. + * cupsdHoldSignals() - Hold child and termination signals. + * cupsdOpenPipe() - Create a pipe which is closed on exec. + * cupsdReleaseSignals() - Release signals for delivery. + * cupsdSetString() - Set a string value. + * cupsdSetStringf() - Set a formatted string value. + * cupsd_clean_files() - Clean out old files. + * launchd_checkin() - Check-in with launchd and collect the listening + * fds. + * launchd_checkout() - Update the launchd KeepAlive file as needed. + * parent_handler() - Catch USR1/CHLD signals... + * process_children() - Process all dead children... + * select_timeout() - Calculate the select timeout value. + * sigchld_handler() - Handle 'child' signals from old processes. + * sighup_handler() - Handle 'hangup' signals to reconfigure the + * scheduler. + * sigterm_handler() - Handle 'terminate' signals that stop the scheduler. + * usage() - Show scheduler usage. */ /* @@ -1178,6 +1181,24 @@ main(int argc, /* I - Number of command-line args */ } +/* + * 'cupsdAddString()' - Copy and add a string to an array. + */ + +int /* O - 1 on success, 0 on failure */ +cupsdAddString(cups_array_t **a, /* IO - String array */ + const char *s) /* I - String to copy and add */ +{ + if (!*a) + *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)_cupsStrAlloc, + (cups_afree_func_t)_cupsStrFree); + + return (cupsArrayAdd(*a, (char *)s)); +} + + /* * 'cupsdCheckProcess()' - Tell the main loop to check for dead children. */ @@ -1193,6 +1214,21 @@ cupsdCheckProcess(void) } +/* + * 'cupsdClearString()' - Clear a string. + */ + +void +cupsdClearString(char **s) /* O - String value */ +{ + if (s && *s) + { + _cupsStrFree(*s); + *s = NULL; + } +} + + /* * 'cupsdClosePipe()' - Close a pipe as necessary. */ @@ -1218,6 +1254,49 @@ cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */ } +/* + * 'cupsdFreeStrings()' - Free an array of strings. + */ + +void +cupsdFreeStrings(cups_array_t **a) /* IO - String array */ +{ + if (*a) + { + cupsArrayDelete(*a); + *a = NULL; + } +} + + +/* + * 'cupsdHoldSignals()' - Hold child and termination signals. + */ + +void +cupsdHoldSignals(void) +{ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + sigset_t newmask; /* New POSIX signal mask */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + holdcount ++; + if (holdcount > 1) + return; + +#ifdef HAVE_SIGSET + sighold(SIGTERM); + sighold(SIGCHLD); +#elif defined(HAVE_SIGACTION) + sigemptyset(&newmask); + sigaddset(&newmask, SIGTERM); + sigaddset(&newmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &newmask, &holdmask); +#endif /* HAVE_SIGSET */ +} + + /* * 'cupsdOpenPipe()' - Create a pipe which is closed on exec. */ @@ -1271,49 +1350,6 @@ cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */ } -/* - * 'cupsdClearString()' - Clear a string. - */ - -void -cupsdClearString(char **s) /* O - String value */ -{ - if (s && *s) - { - _cupsStrFree(*s); - *s = NULL; - } -} - - -/* - * 'cupsdHoldSignals()' - Hold child and termination signals. - */ - -void -cupsdHoldSignals(void) -{ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - sigset_t newmask; /* New POSIX signal mask */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - holdcount ++; - if (holdcount > 1) - return; - -#ifdef HAVE_SIGSET - sighold(SIGTERM); - sighold(SIGCHLD); -#elif defined(HAVE_SIGACTION) - sigemptyset(&newmask); - sigaddset(&newmask, SIGTERM); - sigaddset(&newmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &newmask, &holdmask); -#endif /* HAVE_SIGSET */ -} - - /* * 'cupsdReleaseSignals()' - Release signals for delivery. */ @@ -2159,9 +2195,10 @@ usage(int status) /* O - Exit status */ "\n" "-c config-file Load alternate configuration file\n" "-f Run in the foreground\n" - "-F Run in the foreground but detach\n" + "-F Run in the foreground but detach from console\n" "-h Show this usage message\n" - "-l Run cupsd from launchd(8)\n")); + "-l Run cupsd from launchd(8)\n" + "-t Test the configuration file\n")); exit(status); } diff --git a/scheduler/mime.h b/scheduler/mime.h index a6eb515dd..630b2d763 100644 --- a/scheduler/mime.h +++ b/scheduler/mime.h @@ -1,9 +1,9 @@ /* * "$Id: mime.h 7694 2008-06-26 00:23:20Z mike $" * - * MIME type/conversion database definitions for the Common UNIX Printing System (CUPS). + * MIME type/conversion database definitions for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/network.h b/scheduler/network.h index bbb081ade..95b6badc1 100644 --- a/scheduler/network.h +++ b/scheduler/network.h @@ -1,10 +1,9 @@ /* * "$Id: network.h 6649 2007-07-11 21:46:42Z mike $" * - * Network interface definitions for the Common UNIX Printing System - * (CUPS) scheduler. + * Network interface definitions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/policy.c b/scheduler/policy.c index b7deab72a..bdca28728 100644 --- a/scheduler/policy.c +++ b/scheduler/policy.c @@ -1,9 +1,9 @@ /* * "$Id: policy.c 7673 2008-06-18 22:31:26Z mike $" * - * Policy routines for the Common UNIX Printing System (CUPS). + * Policy routines for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -14,13 +14,19 @@ * * Contents: * - * cupsdAddPolicy() - Add a policy to the system. + * AddPolicy() - Add a policy to the system. * cupsdAddPolicyOp() - Add an operation to a policy. - * cupsdCheckPolicy() - Check the IPP operation and username against - * a policy. + * cupsdCheckPolicy() - Check the IPP operation and username against a + * policy. * cupsdDeleteAllPolicies() - Delete all policies in memory. * cupsdFindPolicy() - Find a named policy. * cupsdFindPolicyOp() - Find a policy operation. + * cupsdGetPrivateAttrs() - Get the private attributes for the current + * request. + * compare_ops() - Compare two operations. + * compare_policies() - Compare two policies. + * free_policy() - Free the memory used by a policy. + * hash_op() - Generate a lookup hash for the operation. */ /* @@ -28,6 +34,7 @@ */ #include "cupsd.h" +#include /* @@ -36,6 +43,7 @@ static int compare_ops(cupsd_location_t *a, cupsd_location_t *b); static int compare_policies(cupsd_policy_t *a, cupsd_policy_t *b); +static void free_policy(cupsd_policy_t *p); static int hash_op(cupsd_location_t *op); @@ -53,7 +61,10 @@ cupsdAddPolicy(const char *policy) /* I - Name of policy */ return (NULL); if (!Policies) - Policies = cupsArrayNew((cups_array_func_t)compare_policies, NULL); + Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)NULL, + (cups_afree_func_t)free_policy); if (!Policies) return (NULL); @@ -77,9 +88,7 @@ cupsdAddPolicyOp(cupsd_policy_t *p, /* I - Policy */ cupsd_location_t *po, /* I - Policy operation to copy */ ipp_op_t op) /* I - IPP operation code */ { - int i; /* Looping var */ cupsd_location_t *temp; /* New policy operation */ - char name[1024]; /* Interface name */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))", @@ -89,72 +98,20 @@ cupsdAddPolicyOp(cupsd_policy_t *p, /* I - Policy */ return (NULL); if (!p->ops) - p->ops = cupsArrayNew2((cups_array_func_t)compare_ops, NULL, - (cups_ahash_func_t)hash_op, 128); + p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL, + (cups_ahash_func_t)hash_op, 128, + (cups_acopy_func_t)NULL, + (cups_afree_func_t)cupsdFreeLocation); if (!p->ops) return (NULL); - if ((temp = calloc(1, sizeof(cupsd_location_t))) != NULL) + if ((temp = cupsdCopyLocation(po)) != NULL) { temp->op = op; temp->limit = CUPSD_AUTH_LIMIT_IPP; cupsArrayAdd(p->ops, temp); - - if (po) - { - /* - * Copy the specified policy to the new one... - */ - - temp->order_type = po->order_type; - temp->type = po->type; - temp->level = po->level; - temp->satisfy = po->satisfy; - temp->encryption = po->encryption; - - for (i = 0; i < po->num_names; i ++) - cupsdAddName(temp, po->names[i]); - - for (i = 0; i < po->num_allow; i ++) - switch (po->allow[i].type) - { - case CUPSD_AUTH_IP : - cupsdAllowIP(temp, po->allow[i].mask.ip.address, - po->allow[i].mask.ip.netmask); - break; - - case CUPSD_AUTH_INTERFACE : - snprintf(name, sizeof(name), "@IF(%s)", - po->allow[i].mask.name.name); - cupsdAllowHost(temp, name); - break; - - default : - cupsdAllowHost(temp, po->allow[i].mask.name.name); - break; - } - - for (i = 0; i < po->num_deny; i ++) - switch (po->deny[i].type) - { - case CUPSD_AUTH_IP : - cupsdDenyIP(temp, po->deny[i].mask.ip.address, - po->deny[i].mask.ip.netmask); - break; - - case CUPSD_AUTH_INTERFACE : - snprintf(name, sizeof(name), "@IF(%s)", - po->deny[i].mask.name.name); - cupsdDenyHost(temp, name); - break; - - default : - cupsdDenyHost(temp, po->deny[i].mask.name.name); - break; - } - } } return (temp); @@ -211,8 +168,6 @@ cupsdCheckPolicy(cupsd_policy_t *p, /* I - Policy */ void cupsdDeleteAllPolicies(void) { - cupsd_policy_t *p; /* Current policy */ - cupsd_location_t *po; /* Current policy op */ cupsd_printer_t *printer; /* Current printer */ @@ -228,24 +183,12 @@ cupsdDeleteAllPolicies(void) printer = (cupsd_printer_t *)cupsArrayNext(Printers)) printer->op_policy_ptr = NULL; + DefaultPolicyPtr = NULL; + /* * Then free all of the policies... */ - for (p = (cupsd_policy_t *)cupsArrayFirst(Policies); - p; - p = (cupsd_policy_t *)cupsArrayNext(Policies)) - { - for (po = (cupsd_location_t *)cupsArrayFirst(p->ops); - po; - po = (cupsd_location_t *)cupsArrayNext(p->ops)) - cupsdDeleteLocation(po); - - cupsArrayDelete(p->ops); - cupsdClearString(&p->name); - free(p); - } - cupsArrayDelete(Policies); Policies = NULL; @@ -326,6 +269,197 @@ cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */ } +/* + * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current + * request. + */ + +cups_array_t * /* O - Array or NULL for no restrictions */ +cupsdGetPrivateAttrs( + cupsd_policy_t *policy, /* I - Policy */ + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *printer, /* I - Printer, if any */ + const char *owner) /* I - Owner of object */ +{ + char *name; /* Current name in access list */ + cups_array_t *access_ptr, /* Access array */ + *attrs_ptr; /* Attributes array */ + const char *username; /* Username associated with request */ + ipp_attribute_t *attr; /* Attribute from request */ + struct passwd *pw; /* User info */ + + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), " + "printer=%p(%s), owner=\"%s\")", policy, policy->name, con, + con->http.fd, printer, printer ? printer->name : "", owner); +#endif /* DEBUG */ + + /* + * Get the access and attributes lists that correspond to the request... + */ + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s", + ippOpString(con->request->request.op.operation_id)); +#endif /* DEBUG */ + + switch (con->request->request.op.operation_id) + { + case IPP_GET_SUBSCRIPTIONS : + case IPP_GET_SUBSCRIPTION_ATTRIBUTES : + case IPP_GET_NOTIFICATIONS : + access_ptr = policy->sub_access; + attrs_ptr = policy->sub_attrs; + break; + + default : + access_ptr = policy->job_access; + attrs_ptr = policy->job_attrs; + break; + } + + /* + * If none of the attributes are private, return NULL now... + */ + + if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL && + !strcasecmp(name, "none")) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); +#endif /* DEBUG */ + + return (NULL); + } + + /* + * Otherwise check the user against the access list... + */ + + if (con->username[0]) + username = con->username; + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + username = attr->values[0].string.text; + else + username = "anonymous"; + + if (username[0]) + { + pw = getpwnam(username); + endpwent(); + } + else + pw = NULL; + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"", + username); +#endif /* DEBUG */ + + /* + * Otherwise check the user against the access list... + */ + + for (name = (char *)cupsArrayFirst(access_ptr); + name; + name = (char *)cupsArrayNext(access_ptr)) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name); +#endif /* DEBUG */ + + if (printer && !strcasecmp(name, "@ACL")) + { + char *acl; /* Current ACL user/group */ + + for (acl = (char *)cupsArrayFirst(printer->users); + acl; + acl = (char *)cupsArrayNext(printer->users)) + { + if (acl[0] == '@') + { + /* + * Check group membership... + */ + + if (cupsdCheckGroup(username, pw, acl + 1)) + break; + } + else if (acl[0] == '#') + { + /* + * Check UUID... + */ + + if (cupsdCheckGroup(username, pw, acl)) + break; + } + else if (!strcasecmp(username, acl)) + break; + } + } + else if (owner && !strcasecmp(name, "@OWNER") && + !strcasecmp(username, owner)) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdGetPrivateAttrs: Returning NULL."); +#endif /* DEBUG */ + + return (NULL); + } + else if (!strcasecmp(name, "@SYSTEM")) + { + int i; /* Looping var */ + + for (i = 0; i < NumSystemGroups; i ++) + if (cupsdCheckGroup(username, pw, SystemGroups[i])) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdGetPrivateAttrs: Returning NULL."); +#endif /* DEBUG */ + + return (NULL); + } + } + else if (name[0] == '@') + { + if (cupsdCheckGroup(username, pw, name + 1)) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdGetPrivateAttrs: Returning NULL."); +#endif /* DEBUG */ + + return (NULL); + } + } + else if (!strcasecmp(username, name)) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); +#endif /* DEBUG */ + + return (NULL); + } + } + + /* + * No direct access, so return private attributes list... + */ + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list."); +#endif /* DEBUG */ + + return (attrs_ptr); +} + + /* * 'compare_ops()' - Compare two operations. */ @@ -350,6 +484,23 @@ compare_policies(cupsd_policy_t *a, /* I - First policy */ } +/* + * 'free_policy()' - Free the memory used by a policy. + */ + +static void +free_policy(cupsd_policy_t *p) /* I - Policy to free */ +{ + cupsArrayDelete(p->job_access); + cupsArrayDelete(p->job_attrs); + cupsArrayDelete(p->sub_access); + cupsArrayDelete(p->sub_attrs); + cupsArrayDelete(p->ops); + cupsdClearString(&p->name); + free(p); +} + + /* * 'hash_op()' - Generate a lookup hash for the operation. */ diff --git a/scheduler/policy.h b/scheduler/policy.h index d3c0c34b2..897b011f5 100644 --- a/scheduler/policy.h +++ b/scheduler/policy.h @@ -1,10 +1,9 @@ /* * "$Id: policy.h 6895 2007-08-30 00:09:27Z mike $" * - * Policy definitions for the Common UNIX Printing System (CUPS) - * scheduler. + * Policy definitions for the CUPS scheduler. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -22,9 +21,15 @@ typedef struct { char *name; /* Policy name */ - cups_array_t *ops; /* Operations */ + cups_array_t *job_access, /* Private users/groups for jobs */ + *job_attrs, /* Private attributes for jobs */ + *sub_access, /* Private users/groups for subscriptions */ + *sub_attrs, /* Private attributes for subscriptions */ + *ops; /* Operations */ } cupsd_policy_t; +typedef struct cupsd_printer_s cupsd_printer_t; + /* * Globals... @@ -47,6 +52,10 @@ extern http_status_t cupsdCheckPolicy(cupsd_policy_t *p, cupsd_client_t *con, extern void cupsdDeleteAllPolicies(void); extern cupsd_policy_t *cupsdFindPolicy(const char *policy); extern cupsd_location_t *cupsdFindPolicyOp(cupsd_policy_t *p, ipp_op_t op); +extern cups_array_t *cupsdGetPrivateAttrs(cupsd_policy_t *p, + cupsd_client_t *con, + cupsd_printer_t *printer, + const char *owner); /* diff --git a/scheduler/printers.c b/scheduler/printers.c index 537d6e4f4..8d2de325a 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -16,13 +16,11 @@ * * cupsdAddPrinter() - Add a printer to the system. * cupsdAddPrinterHistory() - Add the current printer state to the history. - * cupsdAddPrinterUser() - Add a user to the ACL. * cupsdCreateCommonData() - Create the common printer data. * cupsdDeleteAllPrinters() - Delete all printers from the system. * cupsdDeletePrinter() - Delete a printer from the system. * cupsdFindDest() - Find a destination in the list. * cupsdFindPrinter() - Find a printer in the list. - * cupsdFreePrinterUsers() - Free allow/deny users. * cupsdLoadAllPrinters() - Load printers from the printers.conf file. * cupsdRenamePrinter() - Rename a printer. * cupsdSaveAllPrinters() - Save all printer definitions to the @@ -241,37 +239,6 @@ cupsdAddPrinterHistory( } -/* - * 'cupsdAddPrinterUser()' - Add a user to the ACL. - */ - -void -cupsdAddPrinterUser( - cupsd_printer_t *p, /* I - Printer */ - const char *username) /* I - User */ -{ - const char **temp; /* Temporary array pointer */ - - - if (!p || !username) - return; - - if (p->num_users == 0) - temp = malloc(sizeof(char **)); - else - temp = realloc(p->users, sizeof(char **) * (p->num_users + 1)); - - if (!temp) - return; - - p->users = temp; - temp += p->num_users; - - if ((*temp = strdup(username)) != NULL) - p->num_users ++; -} - - /* * 'cupsdCreateCommonData()' - Create the common printer data. */ @@ -931,7 +898,7 @@ cupsdDeletePrinter( delete_string_array(&(p->filters)); delete_string_array(&(p->pre_filters)); - cupsdFreePrinterUsers(p); + cupsdFreeStrings(&(p->users)); cupsdFreeQuotas(p); cupsdClearString(&p->uri); @@ -1007,30 +974,6 @@ cupsdFindPrinter(const char *name) /* I - Name of printer to find */ } -/* - * 'cupsdFreePrinterUsers()' - Free allow/deny users. - */ - -void -cupsdFreePrinterUsers( - cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - - - if (!p || !p->num_users) - return; - - for (i = 0; i < p->num_users; i ++) - free((void *)p->users[i]); - - free(p->users); - - p->num_users = 0; - p->users = NULL; -} - - /* * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file. */ @@ -1399,7 +1342,7 @@ cupsdLoadAllPrinters(void) if (value) { p->deny_users = 0; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -1410,7 +1353,7 @@ cupsdLoadAllPrinters(void) if (value) { p->deny_users = 1; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, @@ -1583,7 +1526,8 @@ cupsdSaveAllPrinters(void) char temp[1024], /* Temporary string */ backup[1024], /* printers.conf.O file */ value[2048], /* Value string */ - *ptr; /* Pointer into value */ + *ptr, /* Pointer into value */ + *name; /* Current user/group name */ cupsd_printer_t *printer; /* Current printer class */ time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ @@ -1756,9 +1700,10 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit); cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit); - for (i = 0; i < printer->num_users; i ++) - cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", - printer->users[i]); + for (name = (char *)cupsArrayFirst(printer->users); + name; + name = (char *)cupsArrayNext(printer->users)) + cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name); if (printer->op_policy) cupsFilePutConf(fp, "OpPolicy", printer->op_policy); @@ -2263,7 +2208,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ ipp_t *oldattrs; /* Old printer attributes */ ipp_attribute_t *attr; /* Attribute data */ cups_option_t *option; /* Current printer option */ - char *filter; /* Current filter */ + char *name, /* Current user/group name */ + *filter; /* Current filter */ static const char * const air_none[] = { /* No authentication */ "none" @@ -2366,16 +2312,21 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, p->info ? p->info : ""); - if (p->num_users) + if (cupsArrayCount(p->users) > 0) { if (p->deny_users) - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "requesting-user-name-denied", p->num_users, NULL, - p->users); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "requesting-user-name-denied", + cupsArrayCount(p->users), NULL, NULL); else - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "requesting-user-name-allowed", p->num_users, NULL, - p->users); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "requesting-user-name-allowed", + cupsArrayCount(p->users), NULL, NULL); + + for (i = 0, name = (char *)cupsArrayFirst(p->users); + name; + i ++, name = (char *)cupsArrayNext(p->users)) + attr->values[i].string.text = _cupsStrRetain(name); } ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, diff --git a/scheduler/printers.h b/scheduler/printers.h index f594a2492..5a62a5da9 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -1,9 +1,9 @@ /* * "$Id: printers.h 7564 2008-05-15 00:57:43Z mike $" * - * Printer definitions for the Common UNIX Printing System (CUPS) scheduler. + * Printer definitions for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -38,7 +38,7 @@ typedef struct typedef struct cupsd_job_s cupsd_job_t; -typedef struct cupsd_printer_s +struct cupsd_printer_s { char *uri, /* Printer URI */ *hostname, /* Host printer resides on */ @@ -81,9 +81,8 @@ typedef struct cupsd_printer_s page_limit, /* Maximum number of pages */ k_limit; /* Maximum number of kilobytes */ cups_array_t *quotas; /* Quota records */ - int deny_users, /* 1 = deny, 0 = allow */ - num_users; /* Number of allowed/denied users */ - const char **users; /* Allowed/denied users */ + int deny_users; /* 1 = deny, 0 = allow */ + cups_array_t *users; /* Allowed/denied users */ int num_history; /* Number of history collections */ ipp_t **history; /* History data */ int sequence_number; /* Increasing sequence number */ @@ -109,7 +108,7 @@ typedef struct cupsd_printer_s DNSServiceRef ipp_ref, /* Reference for _ipp._tcp,_cups */ printer_ref; /* Reference for _printer._tcp */ #endif /* HAVE_DNSSD */ -} cupsd_printer_t; +}; /* @@ -139,8 +138,6 @@ VAR cupsd_policy_t *DefaultPolicyPtr extern cupsd_printer_t *cupsdAddPrinter(const char *name); extern void cupsdAddPrinterHistory(cupsd_printer_t *p); -extern void cupsdAddPrinterUser(cupsd_printer_t *p, - const char *username); extern void cupsdCreateCommonData(void); extern void cupsdDeleteAllPrinters(void); extern int cupsdDeletePrinter(cupsd_printer_t *p, int update); @@ -148,7 +145,6 @@ extern cupsd_printer_t *cupsdFindDest(const char *name); extern cupsd_printer_t *cupsdFindPrinter(const char *name); extern cupsd_quota_t *cupsdFindQuota(cupsd_printer_t *p, const char *username); -extern void cupsdFreePrinterUsers(cupsd_printer_t *p); extern void cupsdFreeQuotas(cupsd_printer_t *p); extern void cupsdLoadAllPrinters(void); extern void cupsdRenamePrinter(cupsd_printer_t *p, diff --git a/scheduler/quotas.c b/scheduler/quotas.c index eb6277102..15f1b37b3 100644 --- a/scheduler/quotas.c +++ b/scheduler/quotas.c @@ -1,7 +1,7 @@ /* * "$Id: quotas.c 6947 2007-09-12 21:09:49Z mike $" * - * Quota routines for the Common UNIX Printing System (CUPS). + * Quota routines for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. diff --git a/scheduler/removefile.c b/scheduler/removefile.c index 213d795ea..756912e99 100644 --- a/scheduler/removefile.c +++ b/scheduler/removefile.c @@ -1,9 +1,9 @@ /* * "$Id: removefile.c 7720 2008-07-11 22:46:21Z mike $" * - * "Secure" file removal function for the Common UNIX Printing System (CUPS). + * "Secure" file removal function for the CUPS scheduler. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -107,8 +107,10 @@ cupsdRemoveFile(const char *filename) /* I - File to remove */ return (-1); } + CUPS_SRAND(time(NULL)); + for (i = 0; i < sizeof(buffer); i ++) - buffer[i] = rand(); + buffer[i] = CUPS_RAND(); if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size)) { close(fd); @@ -130,7 +132,7 @@ cupsdRemoveFile(const char *filename) /* I - File to remove */ } for (i = 0; i < sizeof(buffer); i ++) - buffer[i] = rand(); + buffer[i] = CUPS_RAND(); if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size)) { close(fd); diff --git a/scheduler/select.c b/scheduler/select.c index 03e47437a..2965c6cb0 100644 --- a/scheduler/select.c +++ b/scheduler/select.c @@ -1,7 +1,7 @@ /* * "$Id: select.c 7720 2008-07-11 22:46:21Z mike $" * - * Select abstraction functions for the Common UNIX Printing System (CUPS). + * Select abstraction functions for the CUPS scheduler. * * Copyright 2007-2010 by Apple Inc. * Copyright 2006-2007 by Easy Software Products. diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c index 6da11175a..e719aebdb 100644 --- a/scheduler/statbuf.c +++ b/scheduler/statbuf.c @@ -1,10 +1,9 @@ /* * "$Id: statbuf.c 7674 2008-06-18 23:18:32Z mike $" * - * Status buffer routines for the Common UNIX Printing System (CUPS) - * scheduler. + * Status buffer routines for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/statbuf.h b/scheduler/statbuf.h index c42c6fdb7..1ca227213 100644 --- a/scheduler/statbuf.h +++ b/scheduler/statbuf.h @@ -1,10 +1,9 @@ /* * "$Id: statbuf.h 7674 2008-06-18 23:18:32Z mike $" * - * Status buffer definitions for the Common UNIX Printing System (CUPS) - * scheduler. + * Status buffer definitions for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -19,7 +18,7 @@ * Constants... */ -#define CUPSD_SB_BUFFER_SIZE 1024 /* Bytes or job status buffer */ +#define CUPSD_SB_BUFFER_SIZE 2048 /* Bytes for job status buffer */ /* diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index 4781ac147..92dffe642 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -1,9 +1,9 @@ /* * "$Id: subscriptions.c 7824 2008-08-01 21:11:55Z mike $" * - * Subscription routines for the Common UNIX Printing System (CUPS) scheduler. + * Subscription routines for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -480,9 +480,6 @@ cupsdDeleteSubscription( cupsd_subscription_t *sub, /* I - Subscription object */ int update) /* I - 1 = update subscriptions.conf */ { - int i; /* Looping var */ - - /* * Close the pipe to the notifier as needed... */ @@ -503,13 +500,7 @@ cupsdDeleteSubscription( cupsdClearString(&(sub->owner)); cupsdClearString(&(sub->recipient)); - if (sub->events) - { - for (i = 0; i < sub->num_events; i ++) - cupsd_delete_event(sub->events[i]); - - free(sub->events); - } + cupsArrayDelete(sub->events); free(sub); @@ -1426,7 +1417,10 @@ cupsd_send_notification( if (!sub->events) { - sub->events = calloc(MaxEvents, sizeof(cupsd_event_t *)); + sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)NULL, + (cups_afree_func_t)cupsd_delete_event); if (!sub->events) { @@ -1441,19 +1435,15 @@ cupsd_send_notification( * Purge an old event as needed... */ - if (sub->num_events >= MaxEvents) + if (cupsArrayCount(sub->events) >= MaxEvents) { /* * Purge the oldest event in the cache... */ - cupsd_delete_event(sub->events[0]); + cupsArrayRemove(sub->events, cupsArrayFirst(sub->events)); - sub->num_events --; sub->first_event_id ++; - - memmove(sub->events, sub->events + 1, - sub->num_events * sizeof(cupsd_event_t *)); } /* @@ -1463,8 +1453,7 @@ cupsd_send_notification( * event cache limit, we don't need to check for overflow here... */ - sub->events[sub->num_events] = event; - sub->num_events ++; + cupsArrayAdd(sub->events, event); /* * Deliver the event... diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h index b807ac215..2a2714ec1 100644 --- a/scheduler/subscriptions.h +++ b/scheduler/subscriptions.h @@ -1,9 +1,9 @@ /* * "$Id: subscriptions.h 7824 2008-08-01 21:11:55Z mike $" * - * Subscription definitions for the Common UNIX Printing System (CUPS) scheduler. + * Subscription definitions for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -100,9 +100,8 @@ typedef struct cupsd_subscription_s /**** Subscription structure ****/ time_t last; /* Time of last notification */ time_t expire; /* Lease expiration time */ int first_event_id, /* First event-id in cache */ - next_event_id, /* Next event-id to use */ - num_events; /* Number of cached events */ - cupsd_event_t **events; /* Cached events */ + next_event_id; /* Next event-id to use */ + cups_array_t *events; /* Cached events */ } cupsd_subscription_t; diff --git a/scheduler/sysman.c b/scheduler/sysman.c index 1c548b6ca..e5c138e28 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -1,9 +1,9 @@ /* * "$Id: sysman.c 7928 2008-09-10 22:14:22Z mike $" * - * System management definitions for the Common UNIX Printing System (CUPS). + * System management functions for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -52,7 +52,7 @@ * * Power management support is currently only implemented on MacOS X, but * essentially we use four functions to let the OS know when it is OK to - * put the system to idle sleep, typically when we are not in the middle of + * put the system to sleep, typically when we are not in the middle of * printing a job. * * Once put to sleep, we invalidate all remote printers since it is common diff --git a/scheduler/sysman.h b/scheduler/sysman.h index 231fc2c54..0983f109d 100644 --- a/scheduler/sysman.h +++ b/scheduler/sysman.h @@ -1,9 +1,9 @@ /* * "$Id: sysman.h 7928 2008-09-10 22:14:22Z mike $" * - * System management definitions for the Common UNIX Printing System (CUPS). + * System management definitions for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/scheduler/util.c b/scheduler/util.c index db920c225..b170f8052 100644 --- a/scheduler/util.c +++ b/scheduler/util.c @@ -1,9 +1,9 @@ /* * "$Id: util.c 7621 2008-06-06 18:55:35Z mike $" * - * Mini-daemon utility functions for the Common UNIX Printing System (CUPS). + * Mini-daemon utility functions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -163,13 +163,16 @@ cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */ cups_array_t *a; /* CUPS array */ const char *start, /* Start of string */ *end; /* End of string */ - char *ptr; /* New string */ + char buffer[8192]; /* New string */ if (!s) return (NULL); - if ((a = cupsArrayNew((cups_array_func_t)strcmp, NULL)) != NULL) + if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)_cupsStrAlloc, + (cups_afree_func_t)_cupsStrFree)) != NULL) { for (start = end = s; *end; start = end + 1) { @@ -178,17 +181,26 @@ cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */ */ if ((end = strchr(start, ',')) == NULL) - end = start + strlen(start); + { + /* + * Last delimited string... + */ + + cupsArrayAdd(a, (char *)start); + break; + } /* - * Duplicate the string and add it to the array... + * Copy the string and add it to the array... */ - if ((ptr = calloc(1, end - start + 1)) == NULL) + if ((end - start + 1) > sizeof(buffer)) break; - memcpy(ptr, start, end - start); - cupsArrayAdd(a, ptr); + memcpy(buffer, start, end - start); + buffer[end - start] = '\0'; + + cupsArrayAdd(a, buffer); } } diff --git a/scheduler/util.h b/scheduler/util.h index fab50eee5..ecf7645a4 100644 --- a/scheduler/util.h +++ b/scheduler/util.h @@ -1,9 +1,9 @@ /* * "$Id: util.h 7711 2008-07-02 04:39:27Z mike $" * - * Mini-daemon utility definitions for the Common UNIX Printing System (CUPS). + * Mini-daemon utility definitions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the diff --git a/test/4.4-subscription-ops.test b/test/4.4-subscription-ops.test index f63cfcbd2..f6cf820f1 100644 --- a/test/4.4-subscription-ops.test +++ b/test/4.4-subscription-ops.test @@ -16,6 +16,7 @@ ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1 + ATTR name requesting-user-name $user GROUP subscription ATTR uri notify-recipient-uri testnotify:// @@ -48,6 +49,7 @@ ATTR language attributes-natural-language en ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1 ATTR integer notify-subscription-id $notify-subscription-id + ATTR name requesting-user-name $user # What statuses are OK? STATUS client-error-not-found @@ -69,6 +71,7 @@ ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1 + ATTR name requesting-user-name $user GROUP subscription ATTR uri notify-recipient-uri testnotify:// @@ -102,6 +105,7 @@ ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1 + ATTR name requesting-user-name $user # What statuses are OK? STATUS successful-ok @@ -129,6 +133,7 @@ ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1 + ATTR name requesting-user-name $user GROUP subscription ATTR uri notify-recipient-uri testnotify:// diff --git a/test/get-printer-attributes.test b/test/get-printer-attributes.test index 54ce778b2..5940017a0 100644 --- a/test/get-printer-attributes.test +++ b/test/get-printer-attributes.test @@ -1,16 +1,13 @@ # Get printer attributes using get-printer-attributes { # The name of the test... - NAME "Get printer attributes using get-printer-attributes" - - # The resource to use for the POST - # RESOURCE /admin + NAME "Get printer attributes using Get-Printer-Attributes" # The operation to use - OPERATION get-printer-attributes + OPERATION Get-Printer-Attributes # Attributes, starting in the operation group... - GROUP operation + GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri diff --git a/test/ipp-1.1.test b/test/ipp-1.1.test index eb547fb01..dc3147090 100644 --- a/test/ipp-1.1.test +++ b/test/ipp-1.1.test @@ -226,7 +226,7 @@ EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1 EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1 EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job - # Not requiring 0x0004 Validate-Job since it is deprecated + EXPECT operations-supported WITH-VALUE 0x0004 # Validate-Job EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes EXPECT operations-supported WITH-VALUE 0x000a # Get-Jobs diff --git a/test/ipptool.c b/test/ipptool.c index 330c5212d..6832f9d34 100644 --- a/test/ipptool.c +++ b/test/ipptool.c @@ -36,6 +36,7 @@ * print_xml_string() - Print an XML string with escaping. * print_xml_trailer() - Print the XML trailer with success/fail value. * set_variable() - Set a variable value. + * timeout_cb() - Handle HTTP timeouts. * usage() - Show program usage. * validate_attr() - Determine whether an attribute is valid. * with_value() - Test a WITH-VALUE predicate. @@ -115,6 +116,7 @@ typedef struct _cups_vars_s /**** Set of variables ****/ resource[1024]; /* Resource path from URI */ int port; /* Port number from URI */ http_encryption_t encryption; /* Encryption for connection? */ + double timeout; /* Timeout for connection */ cups_array_t *vars; /* Array of variables */ } _cups_vars_t; @@ -191,6 +193,7 @@ static void print_xml_string(const char *element, const char *s); static void print_xml_trailer(int success, const char *message); static void set_variable(_cups_vars_t *vars, const char *name, const char *value); +static int timeout_cb(http_t *http, void *user_data); static void usage(void); static int validate_attr(ipp_attribute_t *attr, int print); static int with_value(char *value, int regex, ipp_attribute_t *attr, @@ -213,7 +216,7 @@ main(int argc, /* I - Number of command-line args */ filename[1024], /* Real filename */ testname[1024]; /* Real test filename */ const char *testfile; /* Test file to use */ - int interval, /* Test interval */ + int interval, /* Test interval in microseconds */ repeat; /* Repeat count */ _cups_vars_t vars; /* Variables */ http_uri_status_t uri_status; /* URI separation status */ @@ -282,6 +285,19 @@ main(int argc, /* I - Number of command-line args */ #endif /* HAVE_SSL */ break; + case 'T' : /* Set timeout */ + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, + _("ipptool: Missing timeout for \"-T\".\n")); + usage(); + } + + vars.timeout = _cupsStrScand(argv[i], NULL, localeconv()); + break; + case 'V' : /* Set IPP version */ i ++; @@ -378,7 +394,16 @@ main(int argc, /* I - Number of command-line args */ usage(); } else - interval = atoi(argv[i]); + { + interval = (int)(_cupsStrScand(argv[i], NULL, localeconv()) * + 1000000.0); + if (interval <= 0) + { + _cupsLangPuts(stderr, + _("ipptool: Invalid seconds for \"-i\".\n")); + usage(); + } + } if (Output == _CUPS_OUTPUT_PLIST && interval) { @@ -517,20 +542,20 @@ main(int argc, /* I - Number of command-line args */ if (Output == _CUPS_OUTPUT_PLIST) print_xml_trailer(!status, NULL); - else if (interval && repeat > 0) + else if (interval > 0 && repeat > 0) { while (repeat > 1) { - sleep(interval); + usleep(interval); do_tests(&vars, testfile); repeat --; } } - else if (interval) + else if (interval > 0) { for (;;) { - sleep(interval); + usleep(interval); do_tests(&vars, testfile); } } @@ -628,6 +653,9 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ goto test_exit; } + if (vars->timeout > 0.0) + _httpSetTimeout(http, vars->timeout, timeout_cb, NULL); + /* * Loop on tests... */ @@ -1194,7 +1222,7 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ * Delay before operation... */ - int delay; + double delay; if (!get_token(fp, token, sizeof(token), &linenum)) { @@ -1203,7 +1231,7 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ goto test_exit; } - if ((delay = atoi(token)) <= 0) + if ((delay = _cupsStrScand(token, NULL, localeconv())) <= 0.0) { print_fatal_error("Bad DELAY value \"%s\" on line %d.", token, linenum); @@ -1213,9 +1241,9 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ else { if (Output == _CUPS_OUTPUT_TEST) - printf(" [%d second delay]\n", delay); + printf(" [%g second delay]\n", delay); - sleep(delay); + usleep((int)(1000000.0 * delay)); } } else if (!strcasecmp(token, "ATTR")) @@ -3687,6 +3715,21 @@ set_variable(_cups_vars_t *vars, /* I - Variables */ } +/* + * 'timeout_cb()' - Handle HTTP timeouts. + */ + +static int /* O - 1 to continue, 0 to cancel */ +timeout_cb(http_t *http, /* I - Connection to server (unused) */ + void *user_data) /* I - User data (unused) */ +{ + (void)http; + (void)user_data; + + return (0); +} + + /* * 'usage()' - Show program usage. */ @@ -3705,6 +3748,7 @@ usage(void) "-I Ignore errors\n" "-L Send requests using content-length\n" "-S Test with SSL encryption.\n" + "-T Set the receive/send timeout in seconds.\n" "-V version Set default IPP version.\n" "-X Produce XML plist instead of plain text.\n" "-d name=value Define variable.\n" @@ -4526,6 +4570,65 @@ with_value(char *value, /* I - Value string */ } break; + case IPP_TAG_RANGE : + for (i = 0; i < attr->num_values; i ++) + { + char op, /* Comparison operator */ + *nextptr; /* Next pointer */ + int intvalue; /* Integer value */ + + + valptr = value; + if (!strncmp(valptr, "no-value,", 9)) + valptr += 9; + + while (isspace(*valptr & 255) || isdigit(*valptr & 255) || + *valptr == '-' || *valptr == ',' || *valptr == '<' || + *valptr == '=' || *valptr == '>') + { + op = '='; + while (*valptr && !isdigit(*valptr & 255) && *valptr != '-') + { + if (*valptr == '<' || *valptr == '>' || *valptr == '=') + op = *valptr; + valptr ++; + } + + if (!*valptr) + break; + + intvalue = strtol(valptr, &nextptr, 0); + if (nextptr == valptr) + break; + valptr = nextptr; + + switch (op) + { + case '=' : + if (attr->values[i].range.upper == intvalue) + return (1); + break; + case '<' : + if (attr->values[i].range.upper < intvalue) + return (1); + break; + case '>' : + if (attr->values[i].range.upper > intvalue) + return (1); + break; + } + } + } + + if (report) + { + for (i = 0; i < attr->num_values; i ++) + print_test_error("GOT: %s=%d-%d", attr->name, + attr->values[i].range.lower, + attr->values[i].range.upper); + } + break; + case IPP_TAG_BOOLEAN : for (i = 0; i < attr->num_values; i ++) { diff --git a/test/print-job-media-col.test b/test/print-job-media-col.test index ed4f73b5d..cafd291fb 100644 --- a/test/print-job-media-col.test +++ b/test/print-job-media-col.test @@ -32,6 +32,7 @@ MEMBER integer media-top-margin 0 MEMBER integer media-bottom-margin 0 } + ATTR enum print-quality 5 FILE $filename diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh index 1d0973b9d..a1a3536e5 100755 --- a/test/run-stp-tests.sh +++ b/test/run-stp-tests.sh @@ -736,10 +736,10 @@ fi # Warning log messages count=`grep '^W ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'` -if test $count != 0; then - echo "FAIL: $count warning messages, expected 0." +if test $count != 9; then + echo "FAIL: $count warning messages, expected 9." grep '^W ' /tmp/cups-$user/log/error_log - echo "

    FAIL: $count warning messages, expected 0.

    " >>$strfile + echo "

    FAIL: $count warning messages, expected 9.

    " >>$strfile echo "
    " >>$strfile
     	grep '^W ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
     	echo "
    " >>$strfile -- 2.39.2