From a4924f6c45f9a65e7c380e63c8539e86c0795d60 Mon Sep 17 00:00:00 2001 From: msweet Date: Fri, 21 Dec 2007 23:54:03 +0000 Subject: [PATCH] Import CUPS 1.4svn-r7153. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@563 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES-1.3.txt | 13 ++ CHANGES.txt | 8 +- backend/snmp.c | 26 ++- berkeley/lpr.c | 19 +- config-scripts/cups-common.m4 | 3 + config-scripts/cups-compiler.m4 | 61 +++-- config-scripts/cups-network.m4 | 18 -- config-scripts/cups-pam.m4 | 1 + config.h.in | 15 +- cups/Makefile | 2 +- cups/cups.h | 2 + cups/dest.c | 380 +++++++++++++++++++++++++------- cups/http-private.h | 6 - cups/libcups.exp | 1 + cups/testcups.c | 188 +++++++++++++++- doc/Makefile | 5 - scheduler/auth.c | 8 + scheduler/client.c | 33 ++- scheduler/cupsd.h | 6 +- scheduler/dirsvc.c | 8 +- scheduler/ipp.c | 15 +- scheduler/job.c | 12 +- scheduler/job.h | 1 + scheduler/main.c | 22 ++ scheduler/printers.c | 2 + scheduler/process.c | 149 ++++++++++++- scheduler/server.c | 25 ++- scheduler/subscriptions.c | 2 +- systemv/lp.c | 19 +- 29 files changed, 831 insertions(+), 219 deletions(-) diff --git a/CHANGES-1.3.txt b/CHANGES-1.3.txt index 21abb5955..5822d1565 100644 --- a/CHANGES-1.3.txt +++ b/CHANGES-1.3.txt @@ -1,8 +1,21 @@ CHANGES-1.3.txt --------------- +CHANGES IN CUPS V1.3.6 + + - The scheduler did not detect network interface changes + on operating systems other than Mac OS X (STR #2631) + - The scheduler now logs the UNIX error message when it + is unable to create a request file such as a print job. + - Added support for --enable-pie on Mac OS X. + + CHANGES IN CUPS V1.3.5 + - The SNMP backend did not check for negative string + lengths (STR #2589) + - The scheduler incorrectly removed auth-info attributes, + potentially leading to a loss of all options for a job. - The scheduler stopped sending CUPS browse packets on a restart when using fixed addresses (STR #2618) - Fixed PDF filter security issues (CVE-2007-4352 diff --git a/CHANGES.txt b/CHANGES.txt index ca5acc926..9d917f106 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,14 @@ -CHANGES.txt - 2007-12-07 +CHANGES.txt - 2007-12-19 ------------------------ CHANGES IN CUPS V1.4b1 + - Added a new cupsGetNamedDest() function to the CUPS + library for faster printing with lp and lpr (STR #2638) + - The scheduler now sets the PAM RHOST value on systems + that support it (STR #2637) + - The scheduler now sandboxes child processes when + possible. - The Cancel-Job operation now supports a purge-job attriibute to purge a specified job. - ppdEmit* and ppdCollect* now use the NonUIOrderDependency diff --git a/backend/snmp.c b/backend/snmp.c index 916430bd8..8969474ac 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -1064,18 +1064,38 @@ asn1_get_string( char *string, /* I - String buffer */ int strsize) /* I - String buffer size */ { - if (length < strsize) + if (length < 0) { - memcpy(string, *buffer, length); + /* + * Disallow negative lengths! + */ + + fprintf(stderr, "ERROR: Bad ASN1 string length %d!\n", length); + *string = '\0'; + } + else if (length < strsize) + { + /* + * String is smaller than the buffer... + */ + + if (length > 0) + memcpy(string, *buffer, length); + string[length] = '\0'; } else { + /* + * String is larger than the buffer... + */ + memcpy(string, buffer, strsize - 1); string[strsize - 1] = '\0'; } - (*buffer) += length; + if (length > 0) + (*buffer) += length; return (string); } diff --git a/berkeley/lpr.c b/berkeley/lpr.c index 47e0d814c..de01906bc 100644 --- a/berkeley/lpr.c +++ b/berkeley/lpr.c @@ -68,9 +68,7 @@ main(int argc, /* I - Number of command-line arguments */ int num_copies; /* Number of copies per file */ int num_files; /* Number of files to print */ const char *files[1000]; /* Files to print */ - int num_dests; /* Number of destinations */ - cups_dest_t *dests, /* Destinations */ - *dest; /* Selected destination */ + cups_dest_t *dest; /* Selected destination */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ int deletefile; /* Delete file after print? */ @@ -88,8 +86,7 @@ main(int argc, /* I - Number of command-line arguments */ deletefile = 0; printer = NULL; - num_dests = 0; - dests = NULL; + dest = NULL; num_options = 0; options = NULL; num_files = 0; @@ -258,10 +255,7 @@ main(int argc, /* I - Number of command-line arguments */ if ((instance = strrchr(printer, '/')) != NULL) *instance++ = '\0'; - if (num_dests == 0) - num_dests = cupsGetDests(&dests); - - if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL) + if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL) { for (j = 0; j < dest->num_options; j ++) if (cupsGetOption(dest->options[j].name, num_options, @@ -355,10 +349,7 @@ main(int argc, /* I - Number of command-line arguments */ if (printer == NULL) { - if (num_dests == 0) - num_dests = cupsGetDests(&dests); - - if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL) { printer = dest->name; @@ -387,7 +378,7 @@ main(int argc, /* I - Number of command-line arguments */ else val = "LPDEST"; - if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) + if (printer && !cupsGetNamedDest(NULL, printer, NULL)) _cupsLangPrintf(stderr, _("%s: Error - %s environment variable names " "non-existent destination \"%s\"!\n"), diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4 index 5e98a3933..17a9f8883 100644 --- a/config-scripts/cups-common.m4 +++ b/config-scripts/cups-common.m4 @@ -237,6 +237,9 @@ case $uname in CUPS_DEFAULT_PRINTADMIN_AUTH="@AUTHKEY(system.print.admin) @admin @lpadmin" CUPS_SYSTEM_AUTHKEY="SystemGroupAuthKey system.preferences"]) AC_CHECK_HEADER(Security/SecBasePriv.h,AC_DEFINE(HAVE_SECBASEPRIV_H)) + + dnl Check for sandbox/Seatbelt support + AC_CHECK_HEADER(sandbox.h,AC_DEFINE(HAVE_SANDBOX_H)) ;; Linux*) diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 index 5bfcd6a87..f3e369acb 100644 --- a/config-scripts/cups-compiler.m4 +++ b/config-scripts/cups-compiler.m4 @@ -56,9 +56,6 @@ AC_ARG_WITH(arch64flags, [ --with-arch64flags="flags" ARCH64FLAGS="" AC_SUBST(ARCH64FLAGS) -dnl Position-Independent Executable support on Linux... -AC_ARG_ENABLE(pie, [ --enable-pie use GCC -fPIE option, default=no]) - dnl Read-only data/program support on Linux... AC_ARG_ENABLE(relro, [ --enable-relro use GCC relro option, default=no]) @@ -98,36 +95,52 @@ if test -n "$GCC"; then fi fi + # Generate position-independent code as needed... if test $PICFLAG = 1 -a $uname != AIX; then OPTIM="-fPIC $OPTIM" fi - case $uname in - Linux*) - if test x$enable_pie = xyes; then - PIEFLAGS="-pie -fPIE" - fi - - if test x$enable_relro = xyes; then - RELROFLAGS="-Wl,-z,relro" - fi - ;; - - *) - if test x$enable_pie = xyes; then - echo "Sorry, --enable-pie is not supported on this OS!" - fi - ;; - esac + # The -fstack-protector option is available with some versions of + # GCC and adds "stack canaries" which detect when the return address + # has been overwritten, preventing many types of exploit attacks. + AC_MSG_CHECKING(if GCC supports -fstack-protector) + OLDCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fstack-protector" + AC_TRY_COMPILE(,, + OPTIM="$OPTIM -fstack-protector" + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + CFLAGS="$OLDCFLAGS" + + # The -pie option is available with some versions of GCC and adds + # randomization of addresses, which avoids another class of exploits + # that depend on a fixed address for common functions. + AC_MSG_CHECKING(if GCC supports -pie) + OLDCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pie -fPIE" + AC_TRY_COMPILE(,, + PIEFLAGS="-pie -fPIE" + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + CFLAGS="$OLDCFLAGS" if test "x$with_optim" = x; then # Add useful warning options for tracking down problems... OPTIM="-Wall -Wno-format-y2k $OPTIM" - # Additional warning options for alpha testing... + # Additional warning options for development testing... OPTIM="-Wshadow -Wunused $OPTIM" fi case "$uname" in + Darwin*) + # -D_FORTIFY_SOURCE=2 adds additional object size + # checking, basically wrapping all string functions + # with buffer-limited ones. Not strictly needed for + # CUPS since we already use buffer-limited calls, but + # this will catch any additions that are broken. + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + ;; + HP-UX*) if test "x$enable_32bit" = xyes; then # Build 32-bit libraries, 64-bit base... @@ -201,6 +214,12 @@ if test -n "$GCC"; then ;; Linux*) + # The -z relro option is provided by the Linux linker command to + # make relocatable data read-only. + if test x$enable_relro = xyes; then + RELROFLAGS="-Wl,-z,relro" + fi + if test "x$enable_32bit" = xyes; then # Build 32-bit libraries, 64-bit base... if test -z "$with_arch32flags"; then diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4 index 30e7398e7..347dc9a52 100644 --- a/config-scripts/cups-network.m4 +++ b/config-scripts/cups-network.m4 @@ -29,24 +29,6 @@ fi AC_CHECK_MEMBER(struct sockaddr.sa_len,,, [#include ]) AC_CHECK_HEADER(sys/sockio.h, AC_DEFINE(HAVE_SYS_SOCKIO_H)) -if test "$uname" = "SunOS"; then - case "$uversion" in - 55* | 56*) - maxfiles=1024 - ;; - *) - maxfiles=4096 - ;; - esac -else - maxfiles=4096 -fi - -AC_ARG_WITH(maxfiles, [ --with-maxfiles=N set maximum number of file descriptors for scheduler ], - maxfiles=$withval) - -AC_DEFINE_UNQUOTED(CUPS_MAX_FDS, $maxfiles) - CUPS_DEFAULT_DOMAINSOCKET="" dnl Domain socket support... diff --git a/config-scripts/cups-pam.m4 b/config-scripts/cups-pam.m4 index 4ceb2d4af..b100053e8 100644 --- a/config-scripts/cups-pam.m4 +++ b/config-scripts/cups-pam.m4 @@ -30,6 +30,7 @@ if test x$enable_pam != xno; then AC_CHECK_LIB(dl,dlopen) AC_CHECK_LIB(pam,pam_start) + AC_CHECK_LIB(pam,pam_set_item,AC_DEFINE(HAVE_PAM_SET_ITEM)) AC_CHECK_HEADER(security/pam_appl.h) if test x$ac_cv_header_security_pam_appl_h != xyes; then AC_CHECK_HEADER(pam/pam_appl.h, diff --git a/config.h.in b/config.h.in index 2d1c5cdb3..168ae55b4 100644 --- a/config.h.in +++ b/config.h.in @@ -84,13 +84,6 @@ #define CUPS_DEFAULT_MAX_COPIES 100 -/* - * Maximum number of file descriptors to support. - */ - -#define CUPS_MAX_FDS 4096 - - /* * Do we have domain socket support? */ @@ -138,6 +131,7 @@ #endif /* !HAVE_LIBPAM */ #undef HAVE_PAM_PAM_APPL_H +#undef HAVE_PAM_SET_ITEM /* @@ -552,6 +546,13 @@ #undef HAVE_REMOVEFILE +/* + * Do we have ? + */ + +#undef HAVE_SANDBOX_H + + #endif /* !_CUPS_CONFIG_H_ */ /* diff --git a/cups/Makefile b/cups/Makefile index 822f10f54..d290c7528 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -265,7 +265,7 @@ libcups.so.2 libcups.sl.2: $(LIBOBJS) # libcups.2.dylib # -libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) +libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) libcups.exp echo Linking $@... $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \ -install_name $(libdir)/$@ \ diff --git a/cups/cups.h b/cups/cups.h index 7e48ea3af..e938dfa94 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -249,6 +249,8 @@ extern void cupsSetDefaultDest(const char *name, cups_dest_t *dests) _CUPS_API_1_3; /**** New in CUPS 1.4 ****/ +extern cups_dest_t *cupsGetNamedDest(http_t *http, const char *name, + const char *instance) _CUPS_API_1_4; extern http_status_t cupsGetPPD3(http_t *http, const char *name, time_t *modtime, char *buffer, size_t bufsize) _CUPS_API_1_4; diff --git a/cups/dest.c b/cups/dest.c index 245f81dda..9f4fd212b 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -25,6 +25,7 @@ * server. * cupsGetDests2() - Get the list of destinations from the * specified server. + * cupsGetNamedDest() - Get options for the named destination. * cupsRemoveDest() - Remove a destination from the destination list. * cupsDestSetDefaultDest() - Set the default destination. * cupsSetDests() - Set the list of destinations for the default @@ -39,6 +40,7 @@ * Include necessary headers... */ +#include "debug.h" #include "globals.h" #include #include @@ -53,10 +55,13 @@ * Local functions... */ -static int cups_get_dests(const char *filename, int num_dests, +static const char *cups_get_default(const char *filename, char *namebuf, + size_t namesize, const char **instance); +static int cups_get_dests(const char *filename, const char *match_name, + const char *match_inst, int num_dests, cups_dest_t **dests); -static int cups_get_sdests(http_t *http, ipp_op_t op, int num_dests, - cups_dest_t **dests); +static int cups_get_sdests(http_t *http, ipp_op_t op, const char *name, + int num_dests, cups_dest_t **dests); /* @@ -261,19 +266,17 @@ int /* O - Number of destinations */ cupsGetDests(cups_dest_t **dests) /* O - Destinations */ { int num_dests; /* Number of destinations */ - http_t *http; /* HTTP connection */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Connect to the CUPS server and get the destination list and options... */ - http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + if (!cg->http) + cg->http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - num_dests = cupsGetDests2(http, dests); - - if (http) - httpClose(http); + num_dests = cupsGetDests2(cg->http, dests); return (num_dests); } @@ -328,8 +331,8 @@ cupsGetDests2(http_t *http, /* I - HTTP connection */ * Grab the printers and classes... */ - num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, num_dests, dests); - num_dests = cups_get_sdests(http, CUPS_GET_CLASSES, num_dests, dests); + num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, NULL, num_dests, dests); + num_dests = cups_get_sdests(http, CUPS_GET_CLASSES, NULL, num_dests, dests); /* * Make a copy of the "real" queues for a later sanity check... @@ -388,7 +391,7 @@ cupsGetDests2(http_t *http, /* I - HTTP connection */ */ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); - num_dests = cups_get_dests(filename, num_dests, dests); + num_dests = cups_get_dests(filename, NULL, NULL, num_dests, dests); if ((home = getenv("HOME")) != NULL) { @@ -396,7 +399,7 @@ cupsGetDests2(http_t *http, /* I - HTTP connection */ if (access(filename, 0)) snprintf(filename, sizeof(filename), "%s/.lpoptions", home); - num_dests = cups_get_dests(filename, num_dests, dests); + num_dests = cups_get_dests(filename, NULL, NULL, num_dests, dests); } /* @@ -449,6 +452,136 @@ cupsGetDests2(http_t *http, /* I - HTTP connection */ } +/* + * 'cupsGetNamedDest()' - Get options for the named destination. + * + * This function is optimized for retrieving a single destination and should + * be used instead of cupsGetDests() and cupsGetDest() when you either know + * the name of the destination or want to print to the default destination. + * If NULL is returned, the destination does not exist or there is no default + * destination. + * + * If "http" is NULL, the connection to the default print server will be used. + * + * If "name" is NULL, the default printer for the current user will be returned. + * + * The returned destination must be freed using cupsFreeDests() with a + * "num_dests" of 1. + * + * @since CUPS 1.4@ + */ + +cups_dest_t * /* O - Destination or NULL */ +cupsGetNamedDest(http_t *http, /* I - HTTP connection or NULL */ + const char *name, /* I - Destination name or NULL */ + const char *instance) /* I - Instance name or NULL */ +{ + cups_dest_t *dest; /* Destination */ + char filename[1024], /* Path to lpoptions */ + defname[256]; /* Default printer name */ + const char *home = getenv("HOME"); /* Home directory */ + ipp_op_t op = IPP_GET_PRINTER_ATTRIBUTES; + /* IPP operation to get server ops */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * Connect to the server as needed... + */ + + if (!http) + { + if (!cg->http && + (cg->http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + return (NULL); + + http = cg->http; + } + + /* + * If "name" is NULL, find the default destination... + */ + + if (!name) + { + if ((name = getenv("LPDEST")) == NULL) + if ((name = getenv("PRINTER")) != NULL && !strcmp(name, "lp")) + name = NULL; + + if (!name && home) + { + /* + * No default in the environment, try the user's lpoptions files... + */ + + snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); + + if ((name = cups_get_default(filename, defname, sizeof(defname), + &instance)) == NULL) + { + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + name = cups_get_default(filename, defname, sizeof(defname), + &instance); + } + } + + if (!name) + { + /* + * Still not there? Try the system lpoptions file... + */ + + snprintf(filename, sizeof(filename), "%s/lpoptions", + cg->cups_serverroot); + name = cups_get_default(filename, defname, sizeof(defname), &instance); + } + + if (!name) + { + /* + * No locally-set default destination, ask the server... + */ + + op = CUPS_GET_DEFAULT; + } + } + + /* + * Get the printer's attributes... + */ + + if (!cups_get_sdests(http, op, name, 0, &dest)) + return (NULL); + + if (instance) + dest->instance = _cupsStrAlloc(instance); + + /* + * Then add local options... + */ + + snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); + cups_get_dests(filename, name, instance, 1, &dest); + + if (home) + { + snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); + + if (access(filename, 0)) + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + + cups_get_dests(filename, name, instance, 1, &dest); + } + + /* + * Return the result... + */ + + return (dest); +} + + /* * 'cupsRemoveDest()' - Remove a destination from the destination list. * @@ -548,19 +681,17 @@ void cupsSetDests(int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { - http_t *http; /* HTTP connection */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Connect to the CUPS server and save the destination list and options... */ - http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - - cupsSetDests2(http, num_dests, dests); + if (!cg->http) + cg->http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - if (http) - httpClose(http); + cupsSetDests2(cg->http, num_dests, dests); } @@ -606,8 +737,8 @@ cupsSetDests2(http_t *http, /* I - HTTP connection */ * Get the server destinations... */ - num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps); - num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps); + num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, NULL, 0, &temps); + num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, NULL, num_temps, &temps); /* * Figure out which file to write to... @@ -622,7 +753,7 @@ cupsSetDests2(http_t *http, /* I - HTTP connection */ * Merge in server defaults... */ - num_temps = cups_get_dests(filename, num_temps, &temps); + num_temps = cups_get_dests(filename, NULL, NULL, num_temps, &temps); /* * Point to user defaults... @@ -788,25 +919,89 @@ cupsSetDests2(http_t *http, /* I - HTTP connection */ } +/* + * 'cups_get_default()' - Get the default destination from an lpoptions file. + */ + +static const char * /* O - Default destination or NULL */ +cups_get_default(const char *filename, /* I - File to read */ + char *namebuf, /* I - Name buffer */ + size_t namesize, /* I - Size of name buffer */ + const char **instance) /* I - Instance */ +{ + cups_file_t *fp; /* lpoptions file */ + char line[8192], /* Line from file */ + *value, /* Value for line */ + *nameptr; /* Pointer into name */ + int linenum; /* Current line */ + + + *namebuf = '\0'; + + if ((fp = cupsFileOpen(filename, "r")) != NULL) + { + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, "default") && value) + { + strlcpy(namebuf, value, namesize); + + if ((nameptr = strchr(namebuf, ' ')) != NULL) + *nameptr = '\0'; + if ((nameptr = strchr(namebuf, '\t')) != NULL) + *nameptr = '\0'; + + if ((nameptr = strchr(namebuf, '/')) != NULL) + *nameptr++ = '\0'; + + *instance = nameptr; + break; + } + } + + cupsFileClose(fp); + } + + return (*namebuf ? namebuf : NULL); +} + + /* * 'cups_get_dests()' - Get destinations from a file. */ static int /* O - Number of destinations */ cups_get_dests(const char *filename, /* I - File to read from */ + const char *match_name, /* I - Destination name we want */ + const char *match_inst, /* I - Instance name we want */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { int i; /* Looping var */ cups_dest_t *dest; /* Current destination */ - FILE *fp; /* File pointer */ + cups_file_t *fp; /* File pointer */ char line[8192], /* Line from file */ *lineptr, /* Pointer into line */ *name, /* Name of destination/option */ *instance; /* Instance of destination */ + int linenum; /* Current line number */ const char *printer; /* PRINTER or LPDEST */ + DEBUG_printf(("cups_get_dests(filename=\"%s\", match_name=\"%s\", " + "match_inst=\"%s\", num_dests=%d, dests=%p)\n", filename, + match_name ? match_name : "(null)", + match_inst ? match_inst : "(null)", num_dests, dests)); + + /* + * Try to open the file... + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + return (num_dests); + /* * Check environment variables... */ @@ -816,12 +1011,8 @@ cups_get_dests(const char *filename, /* I - File to read from */ if (strcmp(printer, "lp") == 0) printer = NULL; - /* - * Try to open the file... - */ - - if ((fp = fopen(filename, "r")) == NULL) - return (num_dests); + DEBUG_printf(("cups_get_dests: printer=\"%s\"\n", + printer ? printer : "(null)")); /* * Read each printer; each line looks like: @@ -830,28 +1021,22 @@ cups_get_dests(const char *filename, /* I - File to read from */ * Default name[/instance] options */ - while (fgets(line, sizeof(line), fp) != NULL) + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &lineptr, &linenum)) { /* * See what type of line it is... */ - if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255)) - lineptr = line + 4; - else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255)) - lineptr = line + 7; - else - continue; - - /* - * Skip leading whitespace... - */ - - while (isspace(*lineptr & 255)) - lineptr ++; + DEBUG_printf(("cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"\n", + linenum, line, lineptr ? lineptr : "(null)")); - if (!*lineptr) + if ((strcasecmp(line, "dest") && strcasecmp(line, "default")) || !lineptr) + { + DEBUG_puts("cups_get_dests: Not a dest or default line..."); continue; + } name = lineptr; @@ -862,9 +1047,6 @@ cups_get_dests(const char *filename, /* I - File to read from */ while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/') lineptr ++; - if (!*lineptr) - continue; - if (*lineptr == '/') { /* @@ -884,30 +1066,49 @@ cups_get_dests(const char *filename, /* I - File to read from */ else instance = NULL; - *lineptr++ = '\0'; + if (*lineptr) + *lineptr++ = '\0'; + + DEBUG_printf(("cups_get_dests: name=\"%s\", instance=\"%s\"\n", name, + instance)); /* * See if the primary instance of the destination exists; if not, * ignore this entry and move on... */ - if (cupsGetDest(name, NULL, num_dests, *dests) == NULL) - continue; - - /* - * Add the destination... - */ - - num_dests = cupsAddDest(name, instance, num_dests, dests); + if (match_name) + { + if (strcasecmp(name, match_name) || + (!instance && match_inst) || + (instance && !match_inst) || + (instance && strcasecmp(instance, match_inst))) + continue; - if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) + dest = *dests; + } + else if (cupsGetDest(name, NULL, num_dests, *dests) == NULL) + { + DEBUG_puts("cups_get_dests: Not found!"); + continue; + } + else { /* - * Out of memory! + * Add the destination... */ - fclose(fp); - return (num_dests); + num_dests = cupsAddDest(name, instance, num_dests, dests); + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) + { + /* + * Out of memory! + */ + + DEBUG_puts("cups_get_dests: Out of memory!"); + break; + } } /* @@ -917,12 +1118,21 @@ cups_get_dests(const char *filename, /* I - File to read from */ dest->num_options = cupsParseOptions(lineptr, dest->num_options, &(dest->options)); + /* + * If we found what we were looking for, stop now... + */ + + if (match_name) + break; + /* * Set this as default if needed... */ - if (strncasecmp(line, "default", 7) == 0 && printer == NULL) + if (!printer && !strcasecmp(line, "default")) { + DEBUG_puts("cups_get_dests: Setting as default..."); + for (i = 0; i < num_dests; i ++) (*dests)[i].is_default = 0; @@ -934,7 +1144,7 @@ cups_get_dests(const char *filename, /* I - File to read from */ * Close the file and return... */ - fclose(fp); + cupsFileClose(fp); return (num_dests); } @@ -946,7 +1156,8 @@ cups_get_dests(const char *filename, /* I - File to read from */ static int /* O - Number of destinations */ cups_get_sdests(http_t *http, /* I - HTTP connection */ - ipp_op_t op, /* I - get-printers or get-classes */ + ipp_op_t op, /* I - IPP operation */ + const char *name, /* I - Name of destination */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { @@ -963,8 +1174,9 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ const char *info, /* printer-info attribute */ *location, /* printer-location attribute */ *make_model, /* printer-make-and-model attribute */ - *name; /* printer-name attribute */ - char job_sheets[1024], /* job-sheets-default attribute */ + *printer_name; /* printer-name attribute */ + char uri[1024], /* printer-uri value */ + job_sheets[1024], /* job-sheets-default attribute */ auth_info_req[1024], /* auth-info-required attribute */ reasons[1024]; /* printer-state-reasons attribute */ int num_options; /* Number of options */ @@ -1008,6 +1220,14 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + if (name) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", ippPort(), "/printers/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + } + /* * Do the request and get back a response... */ @@ -1030,17 +1250,17 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ * Pull the needed attributes from this printer... */ - accepting = 0; - change_time = 0; - info = NULL; - location = NULL; - make_model = NULL; - name = NULL; - num_options = 0; - options = NULL; - shared = 1; - state = IPP_PRINTER_IDLE; - type = CUPS_PRINTER_LOCAL; + accepting = 0; + change_time = 0; + info = NULL; + location = NULL; + make_model = NULL; + printer_name = NULL; + num_options = 0; + options = NULL; + shared = 1; + state = IPP_PRINTER_IDLE; + type = CUPS_PRINTER_LOCAL; auth_info_req[0] = '\0'; job_sheets[0] = '\0'; @@ -1091,7 +1311,7 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ make_model = attr->values[0].string.text; else if (!strcmp(attr->name, "printer-name") && attr->value_tag == IPP_TAG_NAME) - name = attr->values[0].string.text; + printer_name = attr->values[0].string.text; else if (!strcmp(attr->name, "printer-state") && attr->value_tag == IPP_TAG_ENUM) state = attr->values[0].integer; @@ -1196,7 +1416,7 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ * See if we have everything needed... */ - if (!name) + if (!printer_name) { cupsFreeOptions(num_options, options); @@ -1206,9 +1426,9 @@ cups_get_sdests(http_t *http, /* I - HTTP connection */ continue; } - num_dests = cupsAddDest(name, NULL, num_dests, dests); + num_dests = cupsAddDest(printer_name, NULL, num_dests, dests); - if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL) + if ((dest = cupsGetDest(printer_name, NULL, num_dests, *dests)) != NULL) { dest->num_options = num_options; dest->options = options; diff --git a/cups/http-private.h b/cups/http-private.h index 30ed0a2ad..78348a4dd 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -26,12 +26,6 @@ # include # ifdef __sun -/* - * Define FD_SETSIZE to CUPS_MAX_FDS on Solaris to get the correct version of - * select() for large numbers of file descriptors. - */ - -# define FD_SETSIZE CUPS_MAX_FDS # include # endif /* __sun */ diff --git a/cups/libcups.exp b/cups/libcups.exp index 0dbb901d4..b68dedf8f 100644 --- a/cups/libcups.exp +++ b/cups/libcups.exp @@ -113,6 +113,7 @@ _cupsGetFd _cupsGetFile _cupsGetJobs _cupsGetJobs2 +_cupsGetNamedDest _cupsGetOption _cupsGetPassword _cupsGetPPD diff --git a/cups/testcups.c b/cups/testcups.c index a3187fd1c..68785d035 100644 --- a/cups/testcups.c +++ b/cups/testcups.c @@ -16,7 +16,8 @@ * * Contents: * - * main() - Main entry. + * main() - Main entry. + * dests_equal() - Determine whether two destinations are equal. */ /* @@ -28,6 +29,14 @@ #include "cups.h" +/* + * Local functions... + */ + +static int dests_equal(cups_dest_t *a, cups_dest_t *b); +static void show_diffs(cups_dest_t *a, cups_dest_t *b); + + /* * 'main()' - Main entry. */ @@ -37,9 +46,11 @@ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int status = 0, /* Exit status */ + i, /* Looping var */ num_dests; /* Number of destinations */ cups_dest_t *dests, /* Destinations */ - *dest; /* Current destination */ + *dest, /* Current destination */ + *named_dest; /* Current named destination */ const char *ppdfile; /* PPD file */ ppd_file_t *ppd; /* PPD file data */ int num_jobs; /* Number of jobs for queue */ @@ -61,7 +72,78 @@ main(int argc, /* I - Number of command-line arguments */ return (1); } else - puts("PASS"); + { + printf("PASS (%d dests)\n", num_dests); + + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + { + printf(" %s", dest->name); + + if (dest->instance) + printf(" /%s", dest->instance); + + if (dest->is_default) + puts(" ***DEFAULT***"); + else + putchar('\n'); + } + } + + /* + * cupsGetDest(NULL) + */ + + fputs("cupsGetDest(NULL): ", stdout); + fflush(stdout); + + if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) + { + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + if (dest->is_default) + break; + + if (i) + { + status = 1; + puts("FAIL"); + } + else + puts("PASS (no default)"); + + dest = NULL; + } + else + printf("PASS (%s)\n", dest->name); + + /* + * cupsGetNamedDest(NULL, NULL, NULL) + */ + + fputs("cupsGetNamedDest(NULL, NULL, NULL): ", stdout); + fflush(stdout); + + if ((named_dest = cupsGetNamedDest(NULL, NULL, NULL)) == NULL || + !dests_equal(dest, named_dest)) + { + if (!dest) + puts("PASS (no default)"); + else if (named_dest) + { + puts("FAIL (different values)"); + show_diffs(dest, named_dest); + status = 1; + } + else + { + puts("FAIL (no default)"); + status = 1; + } + } + else + printf("PASS (%s)\n", named_dest->name); + + if (named_dest) + cupsFreeDests(1, named_dest); /* * cupsGetDest(printer) @@ -80,20 +162,34 @@ main(int argc, /* I - Number of command-line arguments */ puts("PASS"); /* - * cupsGetDest(NULL) + * cupsGetNamedDest(NULL, printer, instance) */ - fputs("cupsGetDest(NULL): ", stdout); + printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name, + dest->instance ? dest->instance : "(null)"); fflush(stdout); - if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) + if ((named_dest = cupsGetNamedDest(NULL, dest->name, + dest->instance)) == NULL || + !dests_equal(dest, named_dest)) { + if (named_dest) + { + puts("FAIL (different values)"); + show_diffs(dest, named_dest); + } + else + puts("FAIL (no destination)"); + + status = 1; - puts("FAIL"); } else puts("PASS"); + if (named_dest) + cupsFreeDests(1, named_dest); + /* * cupsPrintFile() */ @@ -169,6 +265,84 @@ main(int argc, /* I - Number of command-line arguments */ } +/* + * 'dests_equal()' - Determine whether two destinations are equal. + */ + +static int /* O - 1 if equal, 0 if not equal */ +dests_equal(cups_dest_t *a, /* I - First destination */ + cups_dest_t *b) /* I - Second destination */ +{ + int i; /* Looping var */ + cups_option_t *aoption; /* Current option */ + const char *bval; /* Option value */ + + + if (a == b) + return (1); + + if ((!a && b) || (a && !b)) + return (0); + + if (strcasecmp(a->name, b->name) || + (a->instance && !b->instance) || + (!a->instance && b->instance) || + (a->instance && strcasecmp(a->instance, b->instance)) || + a->num_options != b->num_options) + return (0); + + for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) + if ((bval = cupsGetOption(aoption->name, b->num_options, + b->options)) == NULL || + strcmp(aoption->value, bval)) + return (0); + + return (1); +} + + +/* + * 'show_diffs()' - Show differences between two destinations. + */ + +static void +show_diffs(cups_dest_t *a, /* I - First destination */ + cups_dest_t *b) /* I - Second destination */ +{ + int i; /* Looping var */ + cups_option_t *aoption; /* Current option */ + const char *bval; /* Option value */ + + + if (!a || !b) + return; + + puts(" Item cupsGetDest cupsGetNamedDest"); + puts(" -------------------- -------------------- --------------------"); + + if (strcasecmp(a->name, b->name)) + printf(" name %-20.20s %-20.20s\n", a->name, b->name); + + if ((a->instance && !b->instance) || + (!a->instance && b->instance) || + (a->instance && strcasecmp(a->instance, b->instance))) + printf(" instance %-20.20s %-20.20s\n", + a->instance ? a->instance : "(null)", + b->instance ? b->instance : "(null)"); + + if (a->num_options != b->num_options) + printf(" num_options %-20d %-20d\n", a->num_options, + b->num_options); + + for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) + if ((bval = cupsGetOption(aoption->name, b->num_options, + b->options)) == NULL || + strcmp(aoption->value, bval)) + printf(" %-20.20s %-20.20s %-20.20s\n", aoption->name, + aoption->value, bval ? bval : "(null)"); +} + + /* * End of "$Id: testfile.c 6192 2007-01-10 19:26:48Z mike $". */ diff --git a/doc/Makefile b/doc/Makefile index 6ce51d17e..6e2260b3a 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -165,11 +165,6 @@ install-languages: if test -f $$lang/cups.css; then \ $(INSTALL_MAN) $$lang/cups.css $(DOCDIR)/$$lang; \ fi; \ - for file in $(WEBBUTTONS); do \ - if test -f $$lang/$$file; then \ - $(INSTALL_MAN) $$lang/$$file $(DOCDIR)/$$lang/images; \ - fi; \ - done \ done diff --git a/scheduler/auth.c b/scheduler/auth.c index 3d487ab2e..e0563a3f7 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -657,6 +657,14 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ return; } +# if defined(HAVE_PAM_SET_ITEM) && defined(PAM_RHOST) + pamerr = pam_set_item(pamh, PAM_RHOST, con->http.hostname); + if (pamerr != PAM_SUCCESS) + cupsdLogMessage(CUPSD_LOG_WARN, + "cupsdAuthorize: pam_set_item() returned %d " + "(%s)!\n", pamerr, pam_strerror(pamh, pamerr)); +# endif /* HAVE_PAM_SET_ITEM && PAM_RHOST */ + pamerr = pam_authenticate(pamh, PAM_SILENT); if (pamerr != PAM_SUCCESS) { diff --git a/scheduler/client.c b/scheduler/client.c index f6c106a78..5de5f1fc0 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1639,12 +1639,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ request_id ++); con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, - con->filename, con->file); - if (con->file < 0) { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create request file %s: %s", + con->filename, strerror(errno)); + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE)) { cupsdCloseClient(con); @@ -1652,6 +1652,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } } + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, + con->filename, con->file); + fchmod(con->file, 0640); fchown(con->file, RunUser, Group); fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); @@ -1978,11 +1982,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++); con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, - con->filename, con->file); - if (con->file < 0) { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create request file %s: %s", + con->filename, strerror(errno)); + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, AUTH_NONE)) { cupsdCloseClient(con); @@ -1990,6 +1995,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } } + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, + con->filename, con->file); + fchmod(con->file, 0640); fchown(con->file, RunUser, Group); fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); @@ -3839,7 +3847,8 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ envp[envc++] = home; envp[envc] = NULL; - if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, &pid)) + if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL, + &pid)) { unlink(seedfile); return (0); @@ -3916,7 +3925,8 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ infofd = open(infofile, O_RDONLY); - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid)) + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, + &pid)) { close(infofd); unlink(infofile); @@ -4149,7 +4159,8 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ infofd = open(infofile, O_RDONLY); - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid)) + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, + &pid)) { close(infofd); unlink(infofile); @@ -4549,7 +4560,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ */ if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1], - -1, -1, root, &pid) < 0) + -1, -1, root, DefaultProfile, &pid) < 0) { /* * Error - can't fork! diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index a6340be4c..5e80e5578 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -160,6 +160,8 @@ VAR time_t ReloadTime VALUE(0); /* Time of reload request... */ VAR int NeedReload VALUE(RELOAD_ALL); /* Need to load configuration? */ +VAR void *DefaultProfile VALUE(0); + /* Default security profile */ #ifdef HAVE_GSSAPI VAR krb5_context KerberosContext;/* Kerberos context for credentials */ @@ -208,12 +210,14 @@ __attribute__ ((__format__ (__printf__, 2, 3))) #endif /* __GNUC__ */ ; +extern void *cupsdCreateProfile(int job_id); +extern void cupsdDestroyProfile(void *profile); extern int cupsdEndProcess(int pid, int force); extern const char *cupsdFinishProcess(int pid, char *name, int namelen); extern int cupsdStartProcess(const char *command, char *argv[], char *envp[], int infd, int outfd, int errfd, int backfd, int sidefd, - int root, int *pid); + int root, void *profile, int *pid); extern int cupsdAddSelect(int fd, cupsd_selfunc_t read_cb, cupsd_selfunc_t write_cb, void *data); diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index 5303bf898..f0269e67f 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -1248,7 +1248,7 @@ cupsdStartPolling(void) argv[1] = pollp->hostname; if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1, - 0, &(pollp->pid)) < 0) + 0, DefaultProfile, &(pollp->pid)) < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdStartPolling: Unable to fork polling daemon - %s", @@ -3900,7 +3900,8 @@ update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */ argv[3] = LPDConfigFile + 10; argv[4] = NULL; - cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid); + cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, + NULL, &pid); } } @@ -4015,7 +4016,8 @@ update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */ argv[3] = SMBConfigFile + 10; argv[4] = NULL; - cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid); + cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, + NULL, &pid); } } diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 690a08732..79ec7b3f1 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1512,17 +1512,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ */ if (auth_info) - { - if (job->attrs->prev) - job->attrs->prev->next = auth_info->next; - else - job->attrs->attrs = auth_info->next; - - if (job->attrs->last == auth_info) - job->attrs->last = job->attrs->prev; - - _ippFreeAttr(auth_info); - } + ippDeleteAttribute(job->attrs, auth_info); } if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", @@ -4303,10 +4293,11 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ "copy_model: Running \"cups-driverd cat %s\"...", from); if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1], - -1, -1, 0, &temppid)) + -1, -1, 0, DefaultProfile, &temppid)) { close(tempfd); unlink(tempfile); + return (-1); } diff --git a/scheduler/job.c b/scheduler/job.c index 9169b4485..458d6bd03 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1710,6 +1710,9 @@ cupsdStopJob(cupsd_job_t *job, /* I - Job */ job->backend = 0; } + cupsdDestroyProfile(job->profile); + job->profile = NULL; + cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Job %d] Closing print pipes [ %d %d ]...", job->id, job->print_pipes[0], job->print_pipes[1]); @@ -3005,7 +3008,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ IPP_TAG_LANGUAGE); #ifdef __APPLE__ - strcpy(apple_language, "APPLE_LANGUAGE"); + strcpy(apple_language, "APPLE_LANGUAGE="); _cupsAppleLanguage(attr->values[0].string.text, apple_language + 15, sizeof(apple_language) - 15); #endif /* __APPLE__ */ @@ -3182,6 +3185,9 @@ start_job(cupsd_job_t *job, /* I - Job ID */ job->status = 0; memset(job->filters, 0, sizeof(job->filters)); + if (!job->profile) + job->profile = cupsdCreateProfile(job->id); + for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters); filter; i ++, filter = (mime_filter_t *)cupsArrayNext(filters)) @@ -3292,7 +3298,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0], filterfds[slot][1], job->status_pipes[1], job->back_pipes[0], job->side_pipes[0], 0, - job->filters + i); + job->profile, job->filters + i); cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Job %d] start_job: Closing filter pipes for slot %d " @@ -3364,7 +3370,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0], filterfds[slot][1], job->status_pipes[1], job->back_pipes[1], job->side_pipes[1], - backroot, &(job->backend)); + backroot, job->profile, &(job->backend)); if (pid == 0) { diff --git a/scheduler/job.h b/scheduler/job.h index 7aa71b3e2..704690583 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -56,6 +56,7 @@ typedef struct cupsd_job_s char *auth_username, /* AUTH_USERNAME environment variable, if any */ *auth_domain, /* AUTH_DOMAIN environment variable, if any */ *auth_password; /* AUTH_PASSWORD environment variable, if any */ + void *profile; /* Security profile */ #ifdef HAVE_GSSAPI krb5_ccache ccache; /* Kerberos credential cache */ char *ccname; /* KRB5CCNAME environment variable */ diff --git a/scheduler/main.c b/scheduler/main.c index f3836b785..5d51538b2 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -149,6 +149,8 @@ main(int argc, /* I - Number of command-line args */ #ifdef __APPLE__ int run_as_child = 0; /* Needed for Mac OS X fork/exec */ +#else + time_t netif_time = 0; /* Time since last network update */ #endif /* __APPLE__ */ #if HAVE_LAUNCHD int launchd_idle_exit; @@ -394,6 +396,14 @@ main(int argc, /* I - Number of command-line args */ for (i = 0; i < limit.rlim_cur && i < 1024; i ++) close(i); + + /* + * Redirect stdin/out/err to /dev/null... + */ + + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); #endif /* DEBUG */ } @@ -840,6 +850,18 @@ main(int argc, /* I - Number of command-line args */ current_time = time(NULL); +#ifndef __APPLE__ + /* + * Update the network interfaces once a minute... + */ + + if ((current_time - netif_time) >= 60) + { + netif_time = current_time; + NetIFUpdate = 1; + } +#endif /* !__APPLE__ */ + #if HAVE_LAUNCHD /* * If no other work was scheduled and we're being controlled by launchd diff --git a/scheduler/printers.c b/scheduler/printers.c index 3571454f5..03498bbc6 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1691,10 +1691,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ "username", "password" }; +#ifdef HAVE_GSSAPI static const char * const air_negotiate[] = { /* Kerberos authentication */ "negotiate" }; +#endif /* HAVE_GSSAPI */ static const char * const air_none[] = { /* No authentication */ "none" diff --git a/scheduler/process.c b/scheduler/process.c index 56f748566..4b83abd37 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -14,10 +14,13 @@ * * Contents: * - * cupsdEndProcess() - End a process. - * cupsdFinishProcess() - Finish a process and get its name. - * cupsdStartProcess() - Start a process. - * compare_procs() - Compare two processes. + * cupsdCreateProfile() - Create an execution profile for a subprocess. + * cupsdDestroyProfile() - Delete an execution profile. + * cupsdEndProcess() - End a process. + * cupsdFinishProcess() - Finish a process and get its name. + * cupsdStartProcess() - Start a process. + * compare_procs() - Compare two processes. + * cupsd_requote() - Make a regular-expression version of a string. */ /* @@ -26,9 +29,13 @@ #include "cupsd.h" #include -#if defined(__APPLE__) +#ifdef __APPLE__ # include #endif /* __APPLE__ */ +#ifdef HAVE_SANDBOX_H +# define __APPLE_API_PRIVATE +# include +#endif /* HAVE_SANDBOX_H */ /* @@ -54,6 +61,84 @@ static cups_array_t *process_array = NULL; */ static int compare_procs(cupsd_proc_t *a, cupsd_proc_t *b); +#ifdef HAVE_SANDBOX_H +static char *cupsd_requote(char *dst, const char *src, size_t dstsize); +#endif /* HAVE_SANDBOX_H */ + + +/* + * 'cupsdCreateProfile()' - Create an execution profile for a subprocess. + */ + +void * /* O - Profile or NULL on error */ +cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */ +{ +#ifdef HAVE_SANDBOX_H + cups_file_t *fp; /* File pointer */ + char profile[1024], /* File containing the profile */ + cache[1024], /* Quoted CacheDir */ + request[1024], /* Quoted RequestRoot */ + root[1024], /* Quoted ServerRoot */ + temp[1024]; /* Quoted TempDir */ + + + if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s", + strerror(errno)); + return (NULL); + } + + cupsd_requote(cache, CacheDir, sizeof(cache)); + cupsd_requote(request, RequestRoot, sizeof(request)); + cupsd_requote(root, ServerRoot, sizeof(root)); + cupsd_requote(temp, TempDir, sizeof(temp)); + + cupsFilePuts(fp, "(version 1)\n"); + cupsFilePuts(fp, "(debug deny)\n"); + cupsFilePuts(fp, "(allow default)\n"); + cupsFilePrintf(fp, + "(deny file-write* file-read-data file-read-metadata\n" + " (regex #\"^%s\"))\n", request); + cupsFilePrintf(fp, + "(deny file-write*\n" + " (regex #\"^%s\" #\"^/private/etc\" #\"^/usr/local/etc\" " + "#\"^/Library\" #\"^/System\"))\n", root); + cupsFilePrintf(fp, + "(allow file-write* file-read-data file-read-metadata\n" + " (regex #\"^%s$\" #\"^%s/\" #\"^%s$\" #\"^%s/\"))\n", + temp, temp, cache, cache); + if (job_id) + cupsFilePrintf(fp, + "(allow file-read-data file-read-metadata\n" + " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n", + request); + + cupsFileClose(fp); + + return ((void *)strdup(profile)); +#else + + return (NULL); +#endif /* HAVE_SANDBOX_H */ +} + + +/* + * 'cupsdDestroyProfile()' - Delete an execution profile. + */ + +void +cupsdDestroyProfile(void *profile) /* I - Profile */ +{ +#ifdef HAVE_SANDBOX_H + if (profile) + { + unlink((char *)profile); + free(profile); + } +#endif /* HAVE_SANDBOX_H */ +} /* @@ -114,6 +199,7 @@ cupsdStartProcess( int backfd, /* I - Backchannel file descriptor */ int sidefd, /* I - Sidechannel file descriptor */ int root, /* I - Run as root? */ + void *profile, /* I - Security profile to use */ int *pid) /* O - Process ID */ { cupsd_proc_t *proc; /* New process record */ @@ -289,6 +375,24 @@ cupsdStartProcess( cupsdReleaseSignals(); +#ifdef HAVE_SANDBOX_H + /* + * Run in a separate security profile... + */ + + if (profile) + { + char *error; /* Sandbox error, if any */ + + if (sandbox_init((char *)profile, SANDBOX_NAMED_EXTERNAL, &error)) + { + fprintf(stderr, "ERROR: sandbox_init failed: %s (%s)\n", error, + strerror(errno)); + sandbox_free_error(error); + } + } +#endif /* HAVE_SANDBOX_H */ + /* * Execute the command; if for some reason this doesn't work, * return the error code... @@ -349,6 +453,41 @@ compare_procs(cupsd_proc_t *a, /* I - First process */ } +#ifdef HAVE_SANDBOX_H +/* + * 'cupsd_requote()' - Make a regular-expression version of a string. + */ + +static char * /* O - Quoted string */ +cupsd_requote(char *dst, /* I - Destination buffer */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destination buffer */ +{ + int ch; /* Current character */ + char *dstptr, /* Current position in buffer */ + *dstend; /* End of destination buffer */ + + + dstptr = dst; + dstend = dst + dstsize - 2; + + while (*src && dstptr < dstend) + { + ch = *src++; + + if (strchr(".?*()[]^$\\", ch)) + *dstptr++ = '\\'; + + *dstptr++ = ch; + } + + *dstptr = '\0'; + + return (dst); +} +#endif /* HAVE_SANDBOX_H */ + + /* * End of "$Id: process.c 6987 2007-09-25 15:43:44Z mike $". */ diff --git a/scheduler/server.c b/scheduler/server.c index ce5536da2..dcff28baa 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -79,6 +79,12 @@ cupsdStartServer(void) gnutls_global_init(); #endif /* HAVE_LIBSSL */ + /* + * Create the default security profile... + */ + + DefaultProfile = cupsdCreateProfile(0); + /* * Startup all the networking stuff... */ @@ -155,6 +161,16 @@ cupsdStopServer(void) CGIPipes[1] = -1; } +#ifdef HAVE_NOTIFY_POST + /* + * Send one last notification as the server shuts down. + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "notify_post(\"com.apple.printerListChange\") last"); + notify_post("com.apple.printerListChange"); +#endif /* HAVE_NOTIFY_POST */ + /* * Close all log files... */ @@ -180,15 +196,12 @@ cupsdStopServer(void) PageFile = NULL; } -#ifdef HAVE_NOTIFY_POST /* - * Send one last notification as the server shuts down. + * Delete the default security profile... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "notify_post(\"com.apple.printerListChange\") last"); - notify_post("com.apple.printerListChange"); -#endif /* HAVE_NOTIFY_POST */ + cupsdDestroyProfile(DefaultProfile); + DefaultProfile = NULL; started = 0; } diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index 642edd17d..1c9c06770 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -1565,7 +1565,7 @@ cupsd_start_notifier( */ if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1], - -1, -1, 0, &pid) < 0) + -1, -1, 0, DefaultProfile, &pid) < 0) { /* * Error - can't fork! diff --git a/systemv/lp.c b/systemv/lp.c index f9b90836a..9c886ae3c 100644 --- a/systemv/lp.c +++ b/systemv/lp.c @@ -73,9 +73,7 @@ main(int argc, /* I - Number of command-line arguments */ int num_copies; /* Number of copies per file */ int num_files; /* Number of files to print */ const char *files[1000]; /* Files to print */ - int num_dests; /* Number of destinations */ - cups_dest_t *dests, /* Destinations */ - *dest; /* Selected destination */ + cups_dest_t *dest; /* Selected destination */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ int end_options; /* No more options? */ @@ -112,8 +110,7 @@ main(int argc, /* I - Number of command-line arguments */ silent = 0; printer = NULL; - num_dests = 0; - dests = NULL; + dest = NULL; num_options = 0; options = NULL; num_files = 0; @@ -179,10 +176,7 @@ main(int argc, /* I - Number of command-line arguments */ if ((instance = strrchr(printer, '/')) != NULL) *instance++ = '\0'; - if (num_dests == 0) - num_dests = cupsGetDests(&dests); - - if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL) + if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL) { for (j = 0; j < dest->num_options; j ++) if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) @@ -593,10 +587,7 @@ main(int argc, /* I - Number of command-line arguments */ if (printer == NULL) { - if (num_dests == 0) - num_dests = cupsGetDests(&dests); - - if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL) { printer = dest->name; @@ -625,7 +616,7 @@ main(int argc, /* I - Number of command-line arguments */ else val = "LPDEST"; - if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) + if (printer && !cupsGetNamedDest(NULL, printer, NULL)) _cupsLangPrintf(stderr, _("%s: Error - %s environment variable names " "non-existent destination \"%s\"!\n"), -- 2.39.2