diff options
author | jlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2007-03-14 16:55:44 +0000 |
---|---|---|
committer | jlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2007-03-14 16:55:44 +0000 |
commit | f7deaa1a21758ec90bf23314af018481ea8aea7f (patch) | |
tree | 28c1e9c935060b27e10b2e9daa788f69508f3726 /scheduler | |
parent | b86bc4cf571c35972a94a634ea884baff9799fa9 (diff) | |
download | cups-f7deaa1a21758ec90bf23314af018481ea8aea7f.tar.gz |
Load cups into easysw/current.
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@279 a1ca3aef-8c08-0410-bb20-df032aa958be
Diffstat (limited to 'scheduler')
41 files changed, 4047 insertions, 1436 deletions
diff --git a/scheduler/Dependencies b/scheduler/Dependencies index e90107a76..46199952f 100644 --- a/scheduler/Dependencies +++ b/scheduler/Dependencies @@ -178,11 +178,11 @@ mime.o: ../cups/array.h ../cups/ipp.h ../cups/file.h type.o: ../cups/string.h ../config.h mime.h ../cups/array.h ../cups/ipp.h type.o: ../cups/file.h ../cups/debug.h cups-deviced.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -cups-deviced.o: ../cups/md5.h ../cups/ppd.h ../cups/array.h ../cups/file.h +cups-deviced.o: ../cups/ppd.h ../cups/array.h ../cups/file.h cups-deviced.o: ../cups/language.h ../cups/file.h ../cups/string.h cups-deviced.o: ../config.h ../cups/array.h ../cups/dir.h cups-driverd.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -cups-driverd.o: ../cups/md5.h ../cups/ppd.h ../cups/array.h ../cups/file.h +cups-driverd.o: ../cups/ppd.h ../cups/array.h ../cups/file.h cups-driverd.o: ../cups/language.h ../cups/file.h ../cups/string.h cups-driverd.o: ../config.h ../cups/dir.h ../cups/transcode.h cups-lpd.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h @@ -193,20 +193,20 @@ cups-polld.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h cups-polld.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h cups-polld.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h cups-polld.o: ../cups/language.h ../cups/string.h -testdirsvc.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h -testdirsvc.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +testdirsvc.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h +testdirsvc.o: ../cups/array.h ../cups/file.h ../cups/language.h testdirsvc.o: ../cups/string.h ../config.h -testlpd.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h -testlpd.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -testlpd.o: ../cups/string.h ../config.h +testlpd.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h +testlpd.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/string.h +testlpd.o: ../config.h testmime.o: ../cups/string.h ../config.h mime.h ../cups/array.h ../cups/ipp.h testmime.o: ../cups/file.h ../cups/dir.h -testspeed.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h -testspeed.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +testspeed.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h +testspeed.o: ../cups/array.h ../cups/file.h ../cups/language.h testspeed.o: ../cups/language.h ../cups/debug.h -testsub.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h -testsub.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -testsub.o: ../cups/debug.h ../cups/string.h ../config.h -util.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h -util.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -util.o: ../cups/file.h ../cups/string.h ../config.h +testsub.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h +testsub.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h +testsub.o: ../cups/string.h ../config.h +util.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h +util.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/file.h +util.o: ../cups/string.h ../config.h diff --git a/scheduler/Makefile b/scheduler/Makefile index 2eb297051..c76690e06 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -1,9 +1,9 @@ # -# "$Id: Makefile 5940 2006-09-11 18:30:09Z mike $" +# "$Id: Makefile 6291 2007-02-19 21:54:27Z mike $" # # Scheduler Makefile for the Common UNIX Printing System (CUPS). # -# Copyright 1997-2006 by Easy Software Products, all rights reserved. +# Copyright 1997-2007 by Easy Software Products, all rights reserved. # # These coded instructions, statements, and computer programs are the # property of Easy Software Products and are protected by Federal @@ -43,6 +43,7 @@ CUPSDOBJS = \ printers.o \ process.o \ quotas.o \ + select.o \ server.o \ statbuf.o \ subscriptions.o \ @@ -188,14 +189,15 @@ cupsd: $(CUPSDOBJS) libmime.a ../cups/$(LIBCUPS) echo Linking $@... $(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) libmime.a \ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \ - $(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(LIBS) + $(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBS) \ + $(LIBGSSAPI) cupsd-static: $(CUPSDOBJS) libmime.a ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libmime.a \ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \ ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \ - $(LIBMALLOC) $(CUPSDLIBS) + $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI) # @@ -261,7 +263,7 @@ testdirsvc: testdirsvc.o testlpd: testlpd.o ../cups/libcups.a cups-lpd echo Linking $@... $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/libcups.a \ - $(COMMONLIBS) $(LIBZ) $(SSLLIBS) + $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(LIBGSSAPI) # @@ -271,7 +273,7 @@ testlpd: testlpd.o ../cups/libcups.a cups-lpd testmime: testmime.o libmime.a ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ testmime.o libmime.a ../cups/libcups.a \ - $(COMMONLIBS) $(LIBZ) $(SSLLIBS) + $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(LIBGSSAPI) # @@ -281,7 +283,7 @@ testmime: testmime.o libmime.a ../cups/libcups.a testspeed: testspeed.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/libcups.a \ - $(COMMONLIBS) $(LIBZ) $(SSLLIBS) + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI) # @@ -291,7 +293,7 @@ testspeed: testspeed.o ../cups/libcups.a testsub: testsub.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/libcups.a \ - $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI) # @@ -302,5 +304,5 @@ include Dependencies # -# End of "$Id: Makefile 5940 2006-09-11 18:30:09Z mike $". +# End of "$Id: Makefile 6291 2007-02-19 21:54:27Z mike $". # diff --git a/scheduler/auth.c b/scheduler/auth.c index 41fd65f87..8baf94511 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -1,9 +1,12 @@ /* - * "$Id: auth.c 5948 2006-09-12 13:58:39Z mike $" + * "$Id: auth.c 6314 2007-03-01 19:11:54Z mike $" * * Authorization routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -49,9 +52,11 @@ * compare_locations() - Compare two locations. * cups_crypt() - Encrypt the password using the DES or MD5 * algorithms, as needed. + * get_gss_creds() - Obtain GSS credentials. * get_md5_password() - Get an MD5 password. * pam_func() - PAM conversation function. * to64() - Base64-encode an integer value... + * check_authref() - Check an authorization services reference. */ /* @@ -79,6 +84,14 @@ #ifdef HAVE_MEMBERSHIP_H # include <membership.h> #endif /* HAVE_MEMBERSHIP_H */ +#ifdef HAVE_AUTHORIZATION_H +# include <Security/AuthorizationTags.h> +# ifdef HAVE_SECBASEPRIV_H +# include <Security/SecBasePriv.h> +# else +extern const char *cssmErrorString(int error); +# endif /* HAVE_SECBASEPRIV_H */ +#endif /* HAVE_AUTHORIZATION_H */ /* @@ -87,17 +100,23 @@ 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); #if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H) static char *cups_crypt(const char *pw, const char *salt); #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ +#ifdef HAVE_GSSAPI +static gss_cred_id_t get_gss_creds(const char *service_name); +#endif /* HAVE_GSSAPI */ static char *get_md5_password(const char *username, const char *group, char passwd[33]); #if HAVE_LIBPAM static int pam_func(int, const struct pam_message **, struct pam_response **, void *); -#else +#elif !defined(HAVE_USERSEC_H) static void to64(char *s, unsigned long v, int n); #endif /* HAVE_LIBPAM */ @@ -309,8 +328,8 @@ void cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ { int type; /* Authentication type */ - char *authorization, /* Pointer into Authorization string */ - *ptr, /* Pointer into string */ + const char *authorization; /* Pointer into Authorization string */ + char *ptr, /* Pointer into string */ username[65], /* Username string */ password[33]; /* Password string */ const char *localuser; /* Certificate username */ @@ -356,7 +375,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * Decode the Authorization string... */ - authorization = con->http.fields[HTTP_FIELD_AUTHORIZATION]; + authorization = httpGetField(&con->http, HTTP_FIELD_AUTHORIZATION); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAuthorize: Authorization=\"%s\"", authorization); @@ -364,6 +383,14 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ username[0] = '\0'; password[0] = '\0'; +#ifdef HAVE_AUTHORIZATION_H + if (con->authref) + { + AuthorizationFree(con->authref, kAuthorizationFlagDefaults); + con->authref = NULL; + } +#endif /* HAVE_AUTHORIZATION_H */ + if (type == AUTH_NONE) { /* @@ -384,6 +411,59 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ "cupsdAuthorize: No authentication data provided."); return; } +#ifdef HAVE_AUTHORIZATION_H + else if (!strncmp(authorization, "AuthRef", 6) && + !strcasecmp(con->http.hostname, "localhost")) + { + OSStatus status; /* Status */ + int authlen; /* Auth string length */ + AuthorizationItemSet *authinfo; /* Authorization item set */ + + /* + * Get the Authorization Services data... + */ + + authorization += 7; + while (isspace(*authorization & 255)) + authorization ++; + + authlen = sizeof(nonce); + httpDecode64_2(nonce, &authlen, authorization); + + if (authlen != kAuthorizationExternalFormLength) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: External Authorization reference size" + "is incorrect!"); + return; + } + + if ((status = AuthorizationCreateFromExternalForm( + (AuthorizationExternalForm *)nonce, &con->authref)) != 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: AuthorizationCreateFromExternalForm " + "returned %d (%s)", + (int)status, cssmErrorString(status)); + return; + } + + if ((status = AuthorizationCopyInfo(con->authref, + kAuthorizationEnvironmentUsername, + &authinfo)) != 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: AuthorizationCopyInfo returned %d (%s)", + (int)status, cssmErrorString(status)); + return; + } + + if (authinfo->count == 1) + strlcpy(username, authinfo->items[0].value, sizeof(username)); + + AuthorizationFreeItemSet(authinfo); + } +#endif /* HAVE_AUTHORIZATION_H */ else if (!strncmp(authorization, "Local", 5) && !strcasecmp(con->http.hostname, "localhost")) { @@ -754,6 +834,118 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ return; } } +#ifdef HAVE_GSSAPI + else if (!strncmp(authorization, "Negotiate", 9) && type == AUTH_KERBEROS) + { + int len; /* Length of authorization string */ + gss_cred_id_t server_creds; /* Server credentials */ + gss_ctx_id_t context; /* Authorization context */ + OM_uint32 major_status, /* Major status code */ + minor_status; /* Minor status code */ + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER, + /* Input token from string */ + output_token = GSS_C_EMPTY_BUFFER; + /* Output token for username */ + gss_name_t client_name; /* Client name */ + + + con->gss_output_token.length = 0; + + /* + * Find the start of the Kerberos input token... + */ + + authorization += 9; + while (isspace(*authorization & 255)) + authorization ++; + + if (!*authorization) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAuthorize: No authentication data specified."); + return; + } + + /* + * Get the server credentials... + */ + + if ((server_creds = get_gss_creds(GSSServiceName)) == NULL) + { + con->no_negotiate = 1; + return; + } + + /* + * Decode the authorization string to get the input token... + */ + + len = strlen(authorization); + input_token.value = malloc(len); + input_token.value = httpDecode64_2(input_token.value, &len, + authorization); + input_token.length = len; + + /* + * Accept the input token to get the authorization info... + */ + + context = GSS_C_NO_CONTEXT; + client_name = GSS_C_NO_NAME; + major_status = gss_accept_sec_context(&minor_status, + &context, + server_creds, + &input_token, + GSS_C_NO_CHANNEL_BINDINGS, + &client_name, + NULL, + &con->gss_output_token, + NULL, + NULL, + &con->gss_delegated_cred); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, + "cupsdAuthorize: Error accepting GSSAPI security " + "context"); + + if (context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER); + + con->no_negotiate = 1; + return; + } + + /* + * Get the username associated with the credentials... + */ + + if (major_status == GSS_S_COMPLETE) + { + major_status = gss_display_name(&minor_status, client_name, + &output_token, NULL); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, + "cupsdAuthorize: Error getting username"); + gss_release_name(&minor_status, &client_name); + gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER); + con->no_negotiate = 1; + return; + } + + gss_release_name(&minor_status, &client_name); + strlcpy(username, output_token.value, sizeof(username)); + + gss_release_buffer(&minor_status, &output_token); + gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER); + } + else + gss_release_name(&minor_status, &client_name); + } +#endif /* HAVE_GSSAPI */ else { cupsdLogMessage(CUPSD_LOG_DEBUG, @@ -1493,7 +1685,8 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ "NONE", "BASIC", "DIGEST", - "BASICDIGEST" + "BASICDIGEST", + "KERBEROS" }; @@ -1623,9 +1816,11 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ * See if encryption is required... */ - if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls && + if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls && strcasecmp(con->http.hostname, "localhost") && - best->satisfy == AUTH_SATISFY_ALL) + best->satisfy == AUTH_SATISFY_ALL) && + !(best->type == AUTH_KERBEROS || + (best->type == AUTH_NONE && DefaultAuthType == AUTH_KERBEROS))) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Need upgrade to TLS..."); @@ -1669,7 +1864,11 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"", con->username); +#ifdef HAVE_AUTHORIZATION_H + if (!con->username[0] && !con->authref) +#else if (!con->username[0]) +#endif /* HAVE_AUTHORIZATION_H */ { if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY) return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */ @@ -1692,8 +1891,13 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ * Get the user info... */ - pw = getpwnam(username); - endpwent(); + if (username[0]) + { + pw = getpwnam(username); + endpwent(); + } + else + pw = NULL; if (best->level == AUTH_USER) { @@ -1713,6 +1917,28 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership..."); +#ifdef HAVE_AUTHORIZATION_H + /* + * If an authorization reference was supplied it must match a right name... + */ + + if (con->authref) + { + for (i = 0; i < best->num_names; i ++) + { + if (!strncasecmp(best->names[i], "@AUTHKEY(", 9) && + check_authref(con, best->names[i] + 9)) + return (HTTP_OK); + else if (!strcasecmp(best->names[i], "@SYSTEM") && + SystemGroupAuthKey && + check_authref(con, SystemGroupAuthKey)) + return (HTTP_OK); + } + + return (HTTP_UNAUTHORIZED); + } +#endif /* HAVE_AUTHORIZATION_H */ + for (i = 0; i < best->num_names; i ++) { if (!strcasecmp(best->names[i], "@OWNER") && owner && @@ -1858,6 +2084,59 @@ add_deny(cupsd_location_t *loc) /* I - Location to add to */ } +#ifdef HAVE_AUTHORIZATION_H +/* + * 'check_authref()' - Check if an authorization services reference has the + * supplied right. + */ + +static int /* O - 1 if right is valid, 0 otherwise */ +check_authref(cupsd_client_t *con, /* I - Connection */ + const char *right) /* I - Right name */ +{ + OSStatus status; /* OS Status */ + AuthorizationItem authright; /* Authorization right */ + AuthorizationRights authrights; /* Authorization rights */ + AuthorizationFlags authflags; /* Authorization flags */ + + + /* + * Check to see if the user is allowed to perform the task... + */ + + if (!con->authref) + return (0); + + authright.name = right; + authright.valueLength = 0; + authright.value = NULL; + authright.flags = 0; + + authrights.count = 1; + authrights.items = &authright; + + authflags = kAuthorizationFlagDefaults | + kAuthorizationFlagExtendRights; + + if ((status = AuthorizationCopyRights(con->authref, &authrights, + kAuthorizationEmptyEnvironment, + authflags, NULL)) != 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "AuthorizationCopyRights(\"%s\") returned %d (%s)", + authright.name, (int)status, cssmErrorString(status)); + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "AuthorizationCopyRights(\"%s\") succeeded!", + authright.name); + + return (1); +} +#endif /* HAVE_AUTHORIZATION_H */ + + /* * 'compare_locations()' - Compare two locations. */ @@ -1993,6 +2272,79 @@ cups_crypt(const char *pw, /* I - Password string */ #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ +#ifdef HAVE_GSSAPI +/* + * 'get_gss_creds()' - Obtain GSS credentials. + */ + +static gss_cred_id_t /* O - Server credentials */ +get_gss_creds(const char *service_name) /* I - Service name */ +{ + OM_uint32 major_status, /* Major status code */ + minor_status; /* Minor status code */ + gss_name_t server_name; /* Server name */ + gss_cred_id_t server_creds; /* Server credentials */ + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + /* Service name token */ + char buf[1024], /* Service name buffer */ + fqdn[HTTP_MAX_URI]; /* Hostname of server */ + + + snprintf(buf, sizeof(buf), "%s@%s", service_name, + httpGetHostname(NULL, fqdn, sizeof(fqdn))); + + token.value = buf; + token.length = strlen(buf); + server_name = GSS_C_NO_NAME; + major_status = gss_import_name(&minor_status, &token, + GSS_C_NT_HOSTBASED_SERVICE, + &server_name); + + memset(&token, 0, sizeof(token)); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status, + "gss_import_name() failed"); + return (NULL); + } + + major_status = gss_display_name(&minor_status, server_name, &token, NULL); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status, + "gss_display_name() failed"); + return (NULL); + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Attempting to acquire credentials for %s...", + (char *)token.value); + + server_creds = GSS_C_NO_CREDENTIAL; + major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, + &server_creds, NULL, NULL); + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status, + "gss_acquire_cred() failed"); + gss_release_name(&minor_status, &server_name); + gss_release_buffer(&minor_status, &token); + return (NULL); + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Credentials acquired successfully for %s.", + (char *)token.value); + + gss_release_name(&minor_status, &server_name); + gss_release_buffer(&minor_status, &token); + + return (server_creds); +} +#endif /* HAVE_GSSAPI */ + + /* * 'get_md5_password()' - Get an MD5 password. */ @@ -2146,7 +2498,7 @@ pam_func( return (PAM_SUCCESS); } -#else +#elif !defined(HAVE_USERSEC_H) /* @@ -2170,5 +2522,5 @@ to64(char *s, /* O - Output string */ /* - * End of "$Id: auth.c 5948 2006-09-12 13:58:39Z mike $". + * End of "$Id: auth.c 6314 2007-03-01 19:11:54Z mike $". */ diff --git a/scheduler/auth.h b/scheduler/auth.h index 87bd72cd9..61c7ae993 100644 --- a/scheduler/auth.h +++ b/scheduler/auth.h @@ -1,5 +1,5 @@ /* - * "$Id: auth.h 5305 2006-03-18 03:05:12Z mike $" + * "$Id: auth.h 5919 2006-08-31 04:20:45Z mike $" * * Authorization definitions for the Common UNIX Printing System (CUPS) * scheduler. @@ -38,6 +38,7 @@ #define AUTH_BASIC 1 /* Basic authentication */ #define AUTH_DIGEST 2 /* Digest authentication */ #define AUTH_BASICDIGEST 3 /* Basic authentication w/passwd.md5 */ +#define AUTH_KERBEROS 4 /* Kerberos authentication */ #define AUTH_ANON 0 /* Anonymous access */ #define AUTH_USER 1 /* Must have a valid username/password */ @@ -158,5 +159,5 @@ extern http_status_t cupsdIsAuthorized(cupsd_client_t *con, const char *owner); /* - * End of "$Id: auth.h 5305 2006-03-18 03:05:12Z mike $". + * End of "$Id: auth.h 5919 2006-08-31 04:20:45Z mike $". */ diff --git a/scheduler/banners.c b/scheduler/banners.c index f78a1077d..31847ad2f 100644 --- a/scheduler/banners.c +++ b/scheduler/banners.c @@ -1,5 +1,5 @@ /* - * "$Id: banners.c 5948 2006-09-12 13:58:39Z mike $" + * "$Id: banners.c 5947 2006-09-12 13:58:22Z mike $" * * Banner routines for the Common UNIX Printing System (CUPS). * @@ -215,5 +215,5 @@ free_banners(void) /* - * End of "$Id: banners.c 5948 2006-09-12 13:58:39Z mike $". + * End of "$Id: banners.c 5947 2006-09-12 13:58:22Z mike $". */ diff --git a/scheduler/classes.c b/scheduler/classes.c index 749a1bda0..63a818bfd 100644 --- a/scheduler/classes.c +++ b/scheduler/classes.c @@ -1,9 +1,9 @@ /* - * "$Id: classes.c 5151 2006-02-22 22:43:17Z mike $" + * "$Id: classes.c 6318 2007-03-06 04:36:55Z mike $" * * Printer class routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -366,7 +366,21 @@ cupsdLoadAllClasses(void) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value); - p = cupsdAddClass(value); + /* + * Since prior classes may have implicitly defined this class, + * see if it already exists... + */ + + if ((p = cupsdFindDest(value)) != NULL) + { + p->type = CUPS_PRINTER_CLASS; + cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName, + LocalPort, value); + cupsdSetString(&p->error_policy, "retry-job"); + } + else + p = cupsdAddClass(value); + p->accepting = 1; p->state = IPP_PRINTER_IDLE; @@ -400,6 +414,13 @@ cupsdLoadAllClasses(void) "Syntax error on line %d of classes.conf.", linenum); return; } + else if (!strcasecmp(line, "AuthInfoRequired")) + { + if (!cupsdSetAuthInfoRequired(p, value, NULL)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad AuthInfoRequired on line %d of classes.conf.", + linenum); + } else if (!strcasecmp(line, "Info")) { if (value) @@ -703,6 +724,7 @@ cupsdSaveAllClasses(void) time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ cups_option_t *option; /* Current option */ + const char *ptr; /* Pointer into info/location */ /* @@ -776,11 +798,49 @@ cupsdSaveAllClasses(void) else cupsFilePrintf(fp, "<Class %s>\n", pclass->name); + if (pclass->num_auth_info_required > 0) + { + cupsFilePrintf(fp, "AuthInfoRequired %s", pclass->auth_info_required[0]); + for (i = 1; i < pclass->num_auth_info_required; i ++) + cupsFilePrintf(fp, ",%s", pclass->auth_info_required[i]); + cupsFilePutChar(fp, '\n'); + } + if (pclass->info) - cupsFilePrintf(fp, "Info %s\n", pclass->info); + { + if ((ptr = strchr(pclass->info, '#')) != NULL) + { + /* + * Need to quote the first # in the info string... + */ + + cupsFilePuts(fp, "Info "); + cupsFileWrite(fp, pclass->info, ptr - pclass->info); + cupsFilePutChar(fp, '\\'); + cupsFilePuts(fp, ptr); + cupsFilePutChar(fp, '\n'); + } + else + cupsFilePrintf(fp, "Info %s\n", pclass->info); + } if (pclass->location) - cupsFilePrintf(fp, "Location %s\n", pclass->location); + { + if ((ptr = strchr(pclass->info, '#')) != NULL) + { + /* + * Need to quote the first # in the location string... + */ + + cupsFilePuts(fp, "Location "); + cupsFileWrite(fp, pclass->location, ptr - pclass->location); + cupsFilePutChar(fp, '\\'); + cupsFilePuts(fp, ptr); + cupsFilePutChar(fp, '\n'); + } + else + cupsFilePrintf(fp, "Location %s\n", pclass->location); + } if (pclass->state == IPP_PRINTER_STOPPED) { @@ -864,5 +924,5 @@ cupsdUpdateImplicitClasses(void) /* - * End of "$Id: classes.c 5151 2006-02-22 22:43:17Z mike $". + * End of "$Id: classes.c 6318 2007-03-06 04:36:55Z mike $". */ diff --git a/scheduler/client.c b/scheduler/client.c index 44a76f49e..9c0a17dc6 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,9 +1,12 @@ /* - * "$Id: client.c 6247 2007-02-07 20:54:37Z mike $" + * "$Id: client.c 6329 2007-03-12 14:48:28Z mike $" * * Client routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -33,6 +36,7 @@ * cupsdSendHeader() - Send an HTTP request. * cupsdUpdateCGI() - Read status messages from CGI scripts and programs. * cupsdWriteClient() - Write data to a client as needed. + * cupsdWritePipe() - Flag that data is available on the CGI pipe. * check_if_modified() - Decode an "If-Modified-Since" line. * encrypt_client() - Enable encryption for the client... * get_cdsa_certificate() - Convert a keychain name into the CFArrayRef @@ -94,7 +98,7 @@ static int encrypt_client(cupsd_client_t *con); #ifdef HAVE_CDSASSL static CFArrayRef get_cdsa_certificate(cupsd_client_t *con); #endif /* HAVE_CDSASSL */ -static char *get_file(cupsd_client_t *con, struct stat *filestats, +static char *get_file(cupsd_client_t *con, struct stat *filestats, char *filename, int len); static http_status_t install_conf_file(cupsd_client_t *con); static int is_cgi(cupsd_client_t *con, const char *filename, @@ -405,7 +409,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ */ val = 1; - setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); /* * Close this file on all execs... @@ -417,10 +421,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Add the socket to the select() input mask. */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAcceptClient: Adding fd %d to InputSet...", - con->http.fd); - FD_SET(con->http.fd, InputSet); + cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con); /* * Temporarily suspend accept()'s until we lose a client... @@ -587,13 +588,7 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ if (con->file >= 0) { - if (FD_ISSET(con->file, InputSet)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdCloseClient: %d Removing fd %d from InputSet...", - con->http.fd, con->file); - FD_CLR(con->file, InputSet); - } + cupsdRemoveSelect(con->file); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseClient: %d Closing data file %d.", @@ -615,11 +610,8 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Only do a partial close so that the encrypted client gets everything. */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdCloseClient: Removing fd %d from OutputSet...", - con->http.fd); shutdown(con->http.fd, 0); - FD_CLR(con->http.fd, OutputSet); + cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con); } else { @@ -627,12 +619,8 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Shut the socket down fully... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdCloseClient: Removing fd %d from InputSet and OutputSet...", - con->http.fd); + cupsdRemoveSelect(con->http.fd); close(con->http.fd); - FD_CLR(con->http.fd, InputSet); - FD_CLR(con->http.fd, OutputSet); con->http.fd = -1; } } @@ -671,6 +659,14 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ con->language = NULL; } +#ifdef HAVE_AUTHORIZATION_H + if (con->authref) + { + AuthorizationFree(con->authref, kAuthorizationFlagDefaults); + con->authref = NULL; + } +#endif /* HAVE_AUTHORIZATION_H */ + /* * Re-enable new client connections if we are going back under the * limit... @@ -711,7 +707,7 @@ cupsdFlushHeader(cupsd_client_t *con) /* I - Client to flush to */ * 'cupsdReadClient()' - Read data from a client. */ -int /* O - 1 on success, 0 on error */ +void cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { char line[32768], /* Line from client... */ @@ -740,7 +736,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->http.error) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: http error seen..."); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } #ifdef HAVE_SSL @@ -764,9 +761,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ buf[0] & 255); if (!encrypt_client(con)) - return (cupsdCloseClient(con)); + cupsdCloseClient(con); - return (1); + return; } } #endif /* HAVE_SSL */ @@ -782,7 +779,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: httpGets returned EOF..."); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } /* @@ -846,7 +844,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ "Bad request line \"%s\" from %s!", line, con->http.hostname); cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; case 2 : con->http.version = HTTP_0_9; break; @@ -857,7 +856,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ "Bad request line \"%s\" from %s!", line, con->http.hostname); cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } if (major < 2) @@ -871,7 +871,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else { cupsdSendError(con, HTTP_NOT_SUPPORTED); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } break; } @@ -916,7 +917,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!", con->uri); cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } /* @@ -949,7 +951,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation); cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } con->start = time(NULL); @@ -972,12 +975,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Parse incoming parameters until the status changes... */ - status = httpUpdate(HTTP(con)); + while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE) + if (con->http.used == 0 || + !memchr(con->http.buffer, '\n', con->http.used)) + break; if (status != HTTP_OK && status != HTTP_CONTINUE) { cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } break; @@ -1044,7 +1051,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_BAD_REQUEST)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else if (con->operation == HTTP_OPTIONS) { @@ -1055,7 +1065,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->best && con->best->type != AUTH_NONE) { if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } if (!strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") && @@ -1067,7 +1080,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } httpPrintf(HTTP(con), "Connection: Upgrade\r\n"); httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n"); @@ -1075,25 +1091,40 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ httpPrintf(HTTP(con), "\r\n"); if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (!encrypt_client(con)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } #else if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } #endif /* HAVE_SSL */ } if (!cupsdSendHeader(con, HTTP_OK, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n"); httpPrintf(HTTP(con), "Content-Length: 0\r\n"); httpPrintf(HTTP(con), "\r\n"); if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else if (!is_path_absolute(con->uri)) { @@ -1102,7 +1133,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_FORBIDDEN)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else { @@ -1115,7 +1149,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } httpPrintf(HTTP(con), "Connection: Upgrade\r\n"); httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n"); @@ -1123,13 +1160,22 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ httpPrintf(HTTP(con), "\r\n"); if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (!encrypt_client(con)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } #else if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } #endif /* HAVE_SSL */ } @@ -1139,7 +1185,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ "cupsdReadClient: Unauthorized request for %s...\n", con->uri); cupsdSendError(con, status); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } if (con->http.expect && @@ -1152,7 +1199,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else { @@ -1161,13 +1211,19 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } httpPrintf(HTTP(con), "Content-Length: 0\r\n"); httpPrintf(HTTP(con), "\r\n"); if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } } @@ -1189,7 +1245,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1258,7 +1317,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendCommand(con, con->command, con->options, 0)) { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else cupsdLogRequest(con, HTTP_OK); @@ -1279,7 +1341,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_FORBIDDEN)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1293,7 +1358,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ sizeof(buf))) == NULL) { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1310,7 +1378,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendCommand(con, con->command, con->options, 0)) { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else cupsdLogRequest(con, HTTP_OK); @@ -1323,7 +1394,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!check_if_modified(con, &filestats)) { if (!cupsdSendError(con, HTTP_NOT_MODIFIED)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else { @@ -1333,7 +1407,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ snprintf(line, sizeof(line), "%s/%s", type->super, type->type); if (!write_file(con, HTTP_OK, filename, line, &filestats)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } } break; @@ -1357,7 +1434,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1368,7 +1448,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_BAD_REQUEST)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1460,7 +1543,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ sizeof(buf))) == NULL) { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1474,7 +1560,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_UNAUTHORIZED)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } } break; @@ -1494,7 +1583,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_FORBIDDEN)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1517,7 +1609,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1528,7 +1623,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_BAD_REQUEST)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1548,7 +1646,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->file < 0) { if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } fchmod(con->file, 0640); @@ -1559,7 +1660,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ case HTTP_DELETE : case HTTP_TRACE : cupsdSendError(con, HTTP_NOT_IMPLEMENTED); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; case HTTP_HEAD : if (!strncmp(con->uri, "/printers/", 10) && @@ -1577,7 +1679,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1596,13 +1701,22 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendHeader(con, HTTP_OK, "text/html")) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (httpPrintf(HTTP(con), "\r\n") < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } cupsdLogRequest(con, HTTP_OK); } @@ -1619,7 +1733,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, HTTP_FORBIDDEN)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } break; } @@ -1627,14 +1744,20 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ sizeof(buf))) == NULL) { if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html")) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } cupsdLogRequest(con, HTTP_NOT_FOUND); } else if (!check_if_modified(con, &filestats)) { if (!cupsdSendError(con, HTTP_NOT_MODIFIED)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } cupsdLogRequest(con, HTTP_NOT_MODIFIED); } @@ -1651,24 +1774,39 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ snprintf(line, sizeof(line), "%s/%s", type->super, type->type); if (!cupsdSendHeader(con, HTTP_OK, line)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats.st_mtime)) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n", (unsigned long)filestats.st_size) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } cupsdLogRequest(con, HTTP_OK); } if (httpPrintf(HTTP(con), "\r\n") < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } if (cupsdFlushHeader(con) < 0) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } con->http.state = HTTP_WAITING; break; @@ -1694,35 +1832,45 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ "CHUNKED" : "LENGTH", CUPS_LLCAST con->http.data_remaining, con->file); - if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) - return (cupsdCloseClient(con)); - else if (bytes > 0) + do { - con->bytes += bytes; + if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) + { + cupsdCloseClient(con); + return; + } + else if (bytes > 0) + { + con->bytes += bytes; - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: %d writing %d bytes to %d", - con->http.fd, bytes, con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d writing %d bytes to %d", + con->http.fd, bytes, con->file); - if (write(con->file, line, bytes) < bytes) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: Unable to write %d bytes to %s: %s", - bytes, con->filename, strerror(errno)); + if (write(con->file, line, bytes) < bytes) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: Unable to write %d bytes to %s: %s", + bytes, con->filename, strerror(errno)); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: Closing data file %d...", - con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Closing data file %d...", + con->file); - close(con->file); - con->file = -1; - unlink(con->filename); - cupsdClearString(&con->filename); + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + { + cupsdCloseClient(con); + return; + } + } } - } + } + while (con->http.state == HTTP_PUT_RECV && con->http.used > 0); if (con->http.state == HTTP_WAITING) { @@ -1755,7 +1903,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdClearString(&con->filename); if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } /* @@ -1769,7 +1920,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ if (!cupsdSendError(con, status)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } break; @@ -1782,94 +1936,112 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ "CHUNKED" : "LENGTH", CUPS_LLCAST con->http.data_remaining, con->file); - if (con->request) + do { - /* - * Grab any request data from the connection... - */ - - if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR) + if (con->request) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: %d IPP Read Error!", - con->http.fd); + /* + * Grab any request data from the connection... + */ - cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); - } - else if (ipp_state != IPP_DATA) - { - if (con->http.state == HTTP_POST_SEND) + if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR) { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: %d IPP Read Error!", + con->http.fd); + cupsdSendError(con, HTTP_BAD_REQUEST); - return (cupsdCloseClient(con)); + cupsdCloseClient(con); + return; } + else if (ipp_state != IPP_DATA) + { + if (con->http.state == HTTP_POST_SEND) + { + cupsdSendError(con, HTTP_BAD_REQUEST); + cupsdCloseClient(con); + return; + } - break; - } - else - con->bytes += ippLength(con->request); - } + break; + } + else + con->bytes += ippLength(con->request); + } - if (con->file < 0 && con->http.state != HTTP_POST_SEND) - { - /* - * Create a file as needed for the request data... - */ + if (con->file < 0 && con->http.state != HTTP_POST_SEND) + { + /* + * Create a file as needed for the request data... + */ - cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++); - con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640); + 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); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, + con->filename, con->file); - if (con->file < 0) - { - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); - } + if (con->file < 0) + { + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + { + cupsdCloseClient(con); + return; + } + } - fchmod(con->file, 0640); - fchown(con->file, RunUser, Group); - fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); - } + fchmod(con->file, 0640); + fchown(con->file, RunUser, Group); + fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); + } - if (con->http.state != HTTP_POST_SEND) - { - if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) - return (cupsdCloseClient(con)); - else if (bytes > 0) + if (con->http.state != HTTP_POST_SEND) { - con->bytes += bytes; + if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) + { + cupsdCloseClient(con); + return; + } + else if (bytes > 0) + { + con->bytes += bytes; - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: %d writing %d bytes to %d", - con->http.fd, bytes, con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d writing %d bytes to %d", + con->http.fd, bytes, con->file); - if (write(con->file, line, bytes) < bytes) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: Unable to write %d bytes to %s: %s", - bytes, con->filename, strerror(errno)); + if (write(con->file, line, bytes) < bytes) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: Unable to write %d bytes to %s: %s", + bytes, con->filename, strerror(errno)); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: Closing file %d...", - con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Closing file %d...", + con->file); - close(con->file); - con->file = -1; - unlink(con->filename); - cupsdClearString(&con->filename); + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + { + cupsdCloseClient(con); + return; + } + } + } + else if (con->http.state == HTTP_POST_RECV) + return; + else if (con->http.state != HTTP_POST_SEND) + { + cupsdCloseClient(con); + return; } } - else if (con->http.state == HTTP_POST_RECV) - return (1); /* ??? */ - else if (con->http.state != HTTP_POST_SEND) - return (cupsdCloseClient(con)); - } + } + while (con->http.state == HTTP_POST_RECV && con->http.used > 0); if (con->http.state == HTTP_POST_SEND) { @@ -1910,7 +2082,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } if (con->command) @@ -1918,7 +2093,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendCommand(con, con->command, con->options, 0)) { if (!cupsdSendError(con, HTTP_NOT_FOUND)) - return (cupsdCloseClient(con)); + { + cupsdCloseClient(con); + return; + } } else cupsdLogRequest(con, HTTP_OK); @@ -1926,7 +2104,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } if (con->request) - return (cupsdProcessIPPRequest(con)); + { + cupsdProcessIPPRequest(con); + return; + } } break; @@ -1935,9 +2116,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } if (!con->http.keep_alive && con->http.state == HTTP_WAITING) - return (cupsdCloseClient(con)); - else - return (1); + cupsdCloseClient(con); } @@ -1989,14 +2168,7 @@ cupsdSendCommand( fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendCommand: Adding fd %d to InputSet...", con->file); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendCommand: Adding fd %d to OutputSet...", - con->http.fd); - - FD_SET(con->file, InputSet); - FD_SET(con->http.fd, OutputSet); + cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con); con->sent_header = 0; con->file_ready = 0; @@ -2044,9 +2216,12 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ /* * To work around bugs in some proxies, don't use Keep-Alive for some * error messages... + * + * Kerberos authentication doesn't work without Keep-Alive, so + * never disable it in that case. */ - if (code >= HTTP_BAD_REQUEST) + if (code >= HTTP_BAD_REQUEST && con->http.auth_type != AUTH_KERBEROS) con->http.keep_alive = HTTP_KEEPALIVE_OFF; /* @@ -2066,8 +2241,8 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ return (0); #endif /* HAVE_SSL */ - if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) || - (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED)) + if (con->http.version >= HTTP_1_1 && + con->http.keep_alive == HTTP_KEEPALIVE_OFF) { if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0) return (0); @@ -2091,7 +2266,8 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ text = _cupsLangString(con->language, _("Enter your username and password or the " "root username and password to access this " - "page.")); + "page. If you are using Kerberos authentication, " + "make sure you have a valid Kerberos ticket.")); else if (code == HTTP_UPGRADE_REQUIRED) { text = urltext; @@ -2162,6 +2338,9 @@ cupsdSendHeader(cupsd_client_t *con, /* I - Client to send to */ http_status_t code, /* I - HTTP status code */ char *type) /* I - MIME type of document */ { + char auth_str[1024]; /* Authorization string */ + + /* * Send the HTTP status header... */ @@ -2209,22 +2388,77 @@ cupsdSendHeader(cupsd_client_t *con, /* I - Client to send to */ auth_type = DefaultAuthType; else auth_type = con->best->type; - - if (auth_type != AUTH_DIGEST) - { - if (httpPrintf(HTTP(con), - "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0) - return (0); - } - else + + auth_str[0] = '\0'; + + if (auth_type == AUTH_BASIC || auth_type == AUTH_BASICDIGEST) + strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str)); + else if (auth_type == AUTH_DIGEST) + snprintf(auth_str, sizeof(auth_str), "Digest realm=\"CUPS\", nonce=\"%s\"", + con->http.hostname); +#ifdef HAVE_GSSAPI + else if (auth_type == AUTH_KERBEROS && !con->no_negotiate && + con->gss_output_token.length == 0) + strlcpy(auth_str, "Negotiate", sizeof(auth_str)); +#endif /* HAVE_GSSAPI */ + +#ifdef HAVE_AUTHORIZATION_H + if (con->best) { - if (httpPrintf(HTTP(con), - "WWW-Authenticate: Digest realm=\"CUPS\", nonce=\"%s\"\r\n", - con->http.hostname) < 0) - return (0); + int i; /* Looping var */ + char *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 ++) + { + if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9)) + { + snprintf(auth_key, auth_size, ", authkey=\"%s\"", + con->best->names[i] + 9); + /* end parenthesis is stripped in conf.c */ + break; + } + else if (!strcasecmp(con->best->names[i], "@SYSTEM") && + SystemGroupAuthKey) + { + snprintf(auth_key, auth_size, ", authkey=\"%s\"", SystemGroupAuthKey); + break; + } + } } +#endif /* HAVE_AUTHORIZATION_H */ + + if (auth_str[0] && + httpPrintf(HTTP(con), "WWW-Authenticate: %s\r\n", auth_str) < 0) + return (0); } +#ifdef HAVE_GSSAPI + /* + * WWW-Authenticate: Negotiate can be included even for + * non-401 replies... + */ + + if (con->gss_output_token.length > 0) + { + char buf[2048]; /* Output token buffer */ + OM_uint32 minor_status; /* Minor status code */ + + + httpEncode64_2(buf, sizeof(buf), + con->gss_output_token.value, + con->gss_output_token.length); + gss_release_buffer(&minor_status, &con->gss_output_token); + + if (httpPrintf(HTTP(con), "WWW-Authenticate: Negotiate %s\r\n", buf) < 0) + return (0); + } +#endif /* HAVE_GSSAPI */ + if (con->language && strcmp(con->language->language, "C")) { if (httpPrintf(HTTP(con), "Content-Language: %s\r\n", @@ -2282,7 +2516,7 @@ cupsdUpdateCGI(void) * 'cupsdWriteClient()' - Write data to a client as needed. */ -int /* O - 1 if success, 0 if fail */ +void cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ { int bytes; /* Number of bytes written */ @@ -2301,7 +2535,28 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND) - return (1); + return; + + if (con->pipe_pid) + { + /* + * Make sure we select on the CGI output... + */ + + cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con); + + if (!con->file_ready) + { + /* + * Try again later when there is CGI output available... + */ + + cupsdRemoveSelect(con->http.fd); + return; + } + + con->file_ready = 0; + } if (con->response) { @@ -2347,7 +2602,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ con->sent_header = 2; if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0) - return (0); + return; } else if (!strncasecmp(buf, "Status:", 7)) { @@ -2362,7 +2617,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (con->http.version == HTTP_1_1) { if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0) - return (0); + return; } } } @@ -2392,7 +2647,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (cupsdFlushHeader(con) < 0) { cupsdCloseClient(con); - return (0); + return; } if (con->http.version == HTTP_1_1) @@ -2417,7 +2672,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ httpPrintf(HTTP(con), "%s", buf); con->http.activity = time(NULL); - return (1); + return; } else if (bytes == 0) con->http.activity = time(NULL); @@ -2432,7 +2687,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ con->http.fd, bytes); cupsdCloseClient(con); - return (0); + return; } con->bytes += bytes; @@ -2456,27 +2711,17 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (httpWrite2(HTTP(con), "", 0) < 0) { cupsdCloseClient(con); - return (0); + return; } } con->http.state = HTTP_WAITING; - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdWriteClient: Removing fd %d from OutputSet...", - con->http.fd); - - FD_CLR(con->http.fd, OutputSet); + cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con); if (con->file >= 0) { - if (FD_ISSET(con->file, InputSet)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdWriteClient: Removing fd %d from InputSet...", - con->file); - FD_CLR(con->file, InputSet); - } + cupsdRemoveSelect(con->file); if (con->pipe_pid) cupsdEndProcess(con->pipe_pid, 0); @@ -2518,25 +2763,28 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (!con->http.keep_alive) { cupsdCloseClient(con); - return (0); - } - } - else - { - con->file_ready = 0; - - if (con->pipe_pid && !FD_ISSET(con->file, InputSet)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdWriteClient: Adding fd %d to InputSet...", - con->file); - FD_SET(con->file, InputSet); + return; } } con->http.activity = time(NULL); +} - return (1); + +/* + * 'cupsdWritePipe()' - Flag that data is available on the CGI pipe. + */ + +void +cupsdWritePipe(cupsd_client_t *con) /* I - Client connection */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdWritePipe: CGI output on fd %d...", + con->file); + + con->file_ready = 1; + + cupsdRemoveSelect(con->file); + cupsdAddSelect(con->http.fd, NULL, (cupsd_selfunc_t)cupsdWriteClient, con); } @@ -2667,7 +2915,7 @@ encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */ con->http.tls = conn; return (1); - + # elif defined(HAVE_GNUTLS) http_tls_t *conn; /* TLS session object */ int error; /* Error code */ @@ -2712,7 +2960,7 @@ encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */ } gnutls_certificate_allocate_credentials(credentials); - gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, + gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, ServerKey, GNUTLS_X509_FMT_PEM); gnutls_init(&(conn->session), GNUTLS_SERVER); @@ -2979,11 +3227,13 @@ get_file(cupsd_client_t *con, /* I - Client connection */ /* - * Need to add DocumentRoot global... + * Figure out the real filename... */ if (!strncmp(con->uri, "/ppd/", 5)) snprintf(filename, len, "%s%s", ServerRoot, con->uri); + else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/')) + snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5); else if (!strncmp(con->uri, "/admin/conf/", 12)) snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11); else if (!strncmp(con->uri, "/admin/log/", 11)) @@ -3472,7 +3722,7 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ int pid, /* Process ID of command */ status; /* Status of command */ char command[1024], /* Command */ - *argv[11], /* Command-line arguments */ + *argv[12], /* Command-line arguments */ *envp[MAX_ENV + 1], /* Environment variables */ home[1024], /* HOME environment variable */ infofile[1024], /* Type-in information for cert */ @@ -3548,7 +3798,7 @@ 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, &pid)) + if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, &pid)) { unlink(seedfile); return (0); @@ -3625,7 +3875,7 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ infofd = open(infofile, O_RDONLY); - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, 1, &pid)) + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid)) { close(infofd); unlink(infofile); @@ -3858,7 +4108,7 @@ make_certificate(cupsd_client_t *con) /* I - Client connection */ infofd = open(infofile, O_RDONLY); - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, 1, &pid)) + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid)) { close(infofd); unlink(infofile); @@ -3928,10 +4178,11 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ int envc; /* Number of environment variables */ char argbuf[10240], /* Argument buffer */ *argv[100], /* Argument strings */ - *envp[MAX_ENV + 17]; /* Environment variables */ + *envp[MAX_ENV + 18]; /* Environment variables */ char content_length[1024], /* CONTENT_LENGTH environment variable */ content_type[1024], /* CONTENT_TYPE environment variable */ http_cookie[32768], /* HTTP_COOKIE environment variable */ + http_referer[1024], /* HTTP_REFERER environment variable */ http_user_agent[1024], /* HTTP_USER_AGENT environment variable */ lang[1024], /* LANG environment variable */ path_info[1024], /* PATH_INFO environment variable */ @@ -4126,6 +4377,13 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ envp[envc ++] = http_user_agent; } + if (con->http.fields[HTTP_FIELD_REFERER][0]) + { + snprintf(http_referer, sizeof(http_referer), "HTTP_REFERER=%s", + con->http.fields[HTTP_FIELD_REFERER]); + envp[envc ++] = http_referer; + } + if (con->operation == HTTP_GET) { envp[envc ++] = "REQUEST_METHOD=GET"; @@ -4190,7 +4448,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ */ if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1], - -1, root, &pid) < 0) + -1, -1, root, &pid) < 0) { /* * Error - can't fork! @@ -4267,15 +4525,13 @@ write_file(cupsd_client_t *con, /* I - Client connection */ else con->http._data_remaining = INT_MAX; - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "write_file: Adding fd %d to OutputSet...", con->http.fd); - - FD_SET(con->http.fd, OutputSet); + cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, + (cupsd_selfunc_t)cupsdWriteClient, con); return (1); } /* - * End of "$Id: client.c 6247 2007-02-07 20:54:37Z mike $". + * End of "$Id: client.c 6329 2007-03-12 14:48:28Z mike $". */ diff --git a/scheduler/client.h b/scheduler/client.h index d11feb836..50f095abf 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -1,5 +1,5 @@ /* - * "$Id: client.h 6205 2007-01-22 22:04:43Z mike $" + * "$Id: client.h 6253 2007-02-10 18:48:40Z mike $" * * Client definitions for the Common UNIX Printing System (CUPS) scheduler. * @@ -22,6 +22,10 @@ * WWW: http://www.cups.org */ +#ifdef HAVE_AUTHORIZATION_H +# include <Security/Authorization.h> +#endif /* HAVE_AUTHORIZATION_H */ + /* * HTTP client structure... */ @@ -56,6 +60,16 @@ struct cupsd_client_s http_addr_t clientaddr; /* Client address */ char servername[256];/* Server name for connection */ int serverport; /* Server port for connection */ +#ifdef HAVE_GSSAPI + int no_negotiate; /* Don't offer WWW-Authenticate: Negotiate */ + gss_buffer_desc gss_output_token; + /* Output token for Negotiate header */ + gss_cred_id_t gss_delegated_cred; + /* Credentials from client header */ +#endif /* HAVE_GSSAPI */ +#ifdef HAVE_AUTHORIZATION_H + AuthorizationRef authref; /* Authorization ref */ +#endif /* HAVE_AUTHORIZATION_H */ }; #define HTTP(con) &((con)->http) @@ -108,7 +122,7 @@ extern void cupsdDeleteAllListeners(void); extern int cupsdFlushHeader(cupsd_client_t *con); extern void cupsdPauseListening(void); extern int cupsdProcessIPPRequest(cupsd_client_t *con); -extern int cupsdReadClient(cupsd_client_t *con); +extern void cupsdReadClient(cupsd_client_t *con); extern void cupsdResumeListening(void); extern int cupsdSendCommand(cupsd_client_t *con, char *command, char *options, int root); @@ -119,9 +133,10 @@ extern void cupsdShutdownClient(cupsd_client_t *con); extern void cupsdStartListening(void); extern void cupsdStopListening(void); extern void cupsdUpdateCGI(void); -extern int cupsdWriteClient(cupsd_client_t *con); +extern void cupsdWriteClient(cupsd_client_t *con); +extern void cupsdWritePipe(cupsd_client_t *con); /* - * End of "$Id: client.h 6205 2007-01-22 22:04:43Z mike $". + * End of "$Id: client.h 6253 2007-02-10 18:48:40Z mike $". */ diff --git a/scheduler/conf.c b/scheduler/conf.c index c8a3afa43..d033627ad 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1,5 +1,5 @@ /* - * "$Id: conf.c 6205 2007-01-22 22:04:43Z mike $" + * "$Id: conf.c 6253 2007-02-10 18:48:40Z mike $" * * Configuration routines for the Common UNIX Printing System (CUPS). * @@ -117,13 +117,19 @@ static cupsd_var_t variables[] = { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER }, { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER }, { "FontPath", &FontPath, CUPSD_VARTYPE_STRING }, - { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN }, +#ifdef HAVE_GSSAPI + { "GSSServiceName", &GSSServiceName, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_GSSAPI */ { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN }, { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN }, { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER }, { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER }, { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER }, { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN }, +#ifdef HAVE_LAUNCHD + { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER }, + { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_LAUNCHD */ { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER }, { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER }, @@ -161,13 +167,12 @@ static cupsd_var_t variables[] = { "ServerKey", &ServerKey, CUPSD_VARTYPE_STRING }, # endif /* HAVE_LIBSSL || HAVE_GNUTLS */ #endif /* HAVE_SSL */ -#ifdef HAVE_LAUNCHD - { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER }, - { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING }, -#endif /* HAVE_LAUNCHD */ { "ServerName", &ServerName, CUPSD_VARTYPE_STRING }, { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_STRING }, { "StateDir", &StateDir, CUPSD_VARTYPE_STRING }, +#ifdef HAVE_AUTHORIZATION_H + { "SystemGroupAuthKey", &SystemGroupAuthKey, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_AUTHORIZATION_H */ { "TempDir", &TempDir, CUPSD_VARTYPE_STRING }, { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER }, { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN } @@ -288,6 +293,9 @@ cupsdReadConfiguration(void) cupsdSetString(&RemoteRoot, "remroot"); cupsdSetString(&ServerHeader, "CUPS/1.2"); cupsdSetString(&StateDir, CUPS_STATEDIR); +#ifdef HAVE_GSSAPI + cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME); +#endif /* HAVE_GSSAPI */ if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf")) PrintcapFormat = PRINTCAP_SOLARIS; @@ -434,11 +442,15 @@ cupsdReadConfiguration(void) MaxActiveJobs = 0; MaxJobsPerUser = 0; MaxJobsPerPrinter = 0; - MaxCopies = 100; + MaxCopies = CUPS_DEFAULT_MAX_COPIES; cupsdDeleteAllPolicies(); cupsdClearString(&DefaultPolicy); +#ifdef HAVE_AUTHORIZATION_H + cupsdClearString(&SystemGroupAuthKey); +#endif /* HAVE_AUTHORIZATION_H */ + MaxSubscriptions = 100; MaxSubscriptionsPerJob = 0; MaxSubscriptionsPerPrinter = 0; @@ -1705,6 +1717,16 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ if (loc->level == AUTH_ANON) loc->level = AUTH_USER; } +#ifdef HAVE_GSSAPI + else if (!strcasecmp(value, "kerberos") || + !strcasecmp(value, "gssapi")) + { + loc->type = AUTH_KERBEROS; + + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } +#endif /* HAVE_GSSAPI */ else { cupsdLogMessage(CUPSD_LOG_WARN, @@ -1813,6 +1835,20 @@ parse_aaa(cupsd_location_t *loc, /* I - Location */ while (isspace(*value & 255)) value ++; +#ifdef HAVE_AUTHORIZATION_H + if (!strncmp(value, "@AUTHKEY(", 9)) + { + /* + * Grab "@AUTHKEY(name)" value... + */ + + for (valptr = value + 9; *valptr != ')' && *valptr; valptr ++); + + if (*valptr) + *valptr++ = '\0'; + } + else +#endif /* HAVE_AUTHORIZATION_H */ if (*value == '\"' || *value == '\'') { /* @@ -2700,6 +2736,10 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ DefaultAuthType = AUTH_DIGEST; else if (!strcasecmp(value, "basicdigest")) DefaultAuthType = AUTH_BASICDIGEST; +#ifdef HAVE_GSSAPI + else if (!strcasecmp(value, "kerberos")) + DefaultAuthType = AUTH_KERBEROS; +#endif /* HAVE_GSSAPI */ else { cupsdLogMessage(CUPSD_LOG_WARN, @@ -2730,6 +2770,19 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ } } #endif /* HAVE_SSL */ +#ifdef HAVE_GSSAPI + else if (!strcasecmp(line, "Krb5Keytab")) + { + cupsdSetStringf(&Krb5Keytab, "KRB5_KTNAME=%s", value); + putenv(Krb5Keytab); + +# ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY + gsskrb5_register_acceptor_identity(value); +# else + cupsdSetEnv("KRB5_KTNAME", value); +# endif /* HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY */ + } +#endif /* HAVE_GSSAPI */ else if (!strcasecmp(line, "User")) { /* @@ -3289,5 +3342,5 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ /* - * End of "$Id: conf.c 6205 2007-01-22 22:04:43Z mike $". + * End of "$Id: conf.c 6253 2007-02-10 18:48:40Z mike $". */ diff --git a/scheduler/conf.h b/scheduler/conf.h index 6320f9d19..cfb71fc4e 100644 --- a/scheduler/conf.h +++ b/scheduler/conf.h @@ -1,5 +1,5 @@ /* - * "$Id: conf.h 5696 2006-06-26 18:34:20Z mike $" + * "$Id: conf.h 6291 2007-02-19 21:54:27Z mike $" * * Configuration file definitions for the Common UNIX Printing System (CUPS) * scheduler. @@ -30,19 +30,19 @@ typedef enum { - CUPSD_LOG_ATTR = -3, /* Used internally for attributes */ - CUPSD_LOG_STATE, /* Used internally for state-reasons */ - CUPSD_LOG_PAGE, /* Used internally for page logging */ + CUPSD_LOG_ATTR = -3, /* Used internally for attributes */ + CUPSD_LOG_STATE, /* Used internally for state-reasons */ + CUPSD_LOG_PAGE, /* Used internally for page logging */ CUPSD_LOG_NONE, - CUPSD_LOG_EMERG, /* Emergency issues */ - CUPSD_LOG_ALERT, /* Something bad happened that needs attention */ - CUPSD_LOG_CRIT, /* Critical error but server continues */ - CUPSD_LOG_ERROR, /* Error condition */ - CUPSD_LOG_WARN, /* Warning */ - CUPSD_LOG_NOTICE, /* Normal condition that needs logging */ - CUPSD_LOG_INFO, /* General information */ - CUPSD_LOG_DEBUG, /* General debugging */ - CUPSD_LOG_DEBUG2 /* Detailed debugging */ + CUPSD_LOG_EMERG, /* Emergency issues */ + CUPSD_LOG_ALERT, /* Something bad happened that needs attention */ + CUPSD_LOG_CRIT, /* Critical error but server continues */ + CUPSD_LOG_ERROR, /* Error condition */ + CUPSD_LOG_WARN, /* Warning */ + CUPSD_LOG_NOTICE, /* Normal condition that needs logging */ + CUPSD_LOG_INFO, /* General information */ + CUPSD_LOG_DEBUG, /* General debugging */ + CUPSD_LOG_DEBUG2 /* Detailed debugging */ } cupsd_loglevel_t; @@ -50,8 +50,8 @@ typedef enum * Printcap formats... */ -#define PRINTCAP_BSD 0 /* Berkeley LPD format */ -#define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */ +#define PRINTCAP_BSD 0 /* Berkeley LPD format */ +#define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */ /* @@ -111,6 +111,12 @@ VAR char *AccessLog VALUE(NULL), /* Remote root user */ *Classification VALUE(NULL); /* Classification of system */ +#ifdef HAVE_GSSAPI +VAR char *GSSServiceName VALUE(NULL); + /* GSS service name */ +VAR char *Krb5Keytab VALUE(NULL); + /* Kerberos Keytab */ +#endif /* HAVE_GSSAPI */ VAR uid_t User VALUE(1); /* User ID for server */ VAR gid_t Group VALUE(0); @@ -127,7 +133,7 @@ VAR int ClassifyOverride VALUE(0), /* Maximum number of clients */ MaxClientsPerHost VALUE(0), /* Maximum number of clients per host */ - MaxCopies VALUE(100), + MaxCopies VALUE(CUPS_DEFAULT_MAX_COPIES), /* Maximum number of copies per job */ MaxLogSize VALUE(1024 * 1024), /* Maximum size of log files */ @@ -195,21 +201,32 @@ VAR char *LaunchdConf VALUE(NULL); /* launchd(8) configuration file */ #endif /* HAVE_LAUNCHD */ +#ifdef HAVE_AUTHORIZATION_H +VAR char *SystemGroupAuthKey VALUE(NULL); + /* System group auth key */ +#endif /* HAVE_AUTHORIZATION_H */ + + /* * Prototypes... */ extern char *cupsdGetDateTime(time_t t); extern int cupsdReadConfiguration(void); -extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code); +#ifdef HAVE_GSSAPI +extern int cupsdLogGSSMessage(int level, int major_status, + int minor_status, + const char *message, ...); +#endif /* HAVE_GSSAPI */ extern int cupsdLogMessage(int level, const char *message, ...) #ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 2, 3))) #endif /* __GNUC__ */ ; extern int cupsdLogPage(cupsd_job_t *job, const char *page); +extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code); /* - * End of "$Id: conf.h 5696 2006-06-26 18:34:20Z mike $". + * End of "$Id: conf.h 6291 2007-02-19 21:54:27Z mike $". */ diff --git a/scheduler/cups-driverd.c b/scheduler/cups-driverd.c index a51e4a934..39892bc71 100644 --- a/scheduler/cups-driverd.c +++ b/scheduler/cups-driverd.c @@ -1,5 +1,5 @@ /* - * "$Id: cups-driverd.c 6214 2007-01-23 17:01:48Z mike $" + * "$Id: cups-driverd.c 6211 2007-01-23 15:44:34Z mike $" * * PPD/driver support for the Common UNIX Printing System (CUPS). * @@ -1122,5 +1122,5 @@ load_drivers(void) /* - * End of "$Id: cups-driverd.c 6214 2007-01-23 17:01:48Z mike $". + * End of "$Id: cups-driverd.c 6211 2007-01-23 15:44:34Z mike $". */ diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c index e771c9eff..a2b0f9003 100644 --- a/scheduler/cups-lpd.c +++ b/scheduler/cups-lpd.c @@ -1,5 +1,5 @@ /* - * "$Id: cups-lpd.c 6022 2006-10-10 19:47:03Z mike $" + * "$Id: cups-lpd.c 6327 2007-03-12 14:32:10Z mike $" * * Line Printer Daemon interface for the Common UNIX Printing System (CUPS). * @@ -96,7 +96,8 @@ static int get_printer(http_t *http, const char *name, char *dest, int destsize, cups_option_t **options, int *accepting, int *shared, ipp_pstate_t *state); static int print_file(http_t *http, int id, const char *filename, - const char *docname, const char *user, int last); + const char *docname, const char *user, + const char *format, int last); static int recv_print_job(const char *name, int num_defaults, cups_option_t *defaults); static int remove_jobs(const char *name, const char *agent, @@ -824,6 +825,7 @@ print_file(http_t *http, /* I - HTTP connection */ const char *filename, /* I - File to print */ const char *docname, /* I - document-name */ const char *user, /* I - requesting-user-name */ + const char *format, /* I - document-format */ int last) /* I - 1 = last file in job */ { ipp_t *request; /* IPP request */ @@ -846,6 +848,10 @@ print_file(http_t *http, /* I - HTTP connection */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", NULL, docname); + if (format) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, + "document-format", NULL, format); + if (last) ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); @@ -1278,6 +1284,8 @@ recv_print_job( docnumber ++; if (print_file(http, id, temp[i], docname, user, + cupsGetOption("document-format", num_options, + options), docnumber == doccount)) status = 1; else @@ -1717,5 +1725,5 @@ smart_gets(char *s, /* I - Pointer to line buffer */ /* - * End of "$Id: cups-lpd.c 6022 2006-10-10 19:47:03Z mike $". + * End of "$Id: cups-lpd.c 6327 2007-03-12 14:32:10Z mike $". */ diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c index be6bbb5e6..2d21f1a0c 100644 --- a/scheduler/cups-polld.c +++ b/scheduler/cups-polld.c @@ -1,5 +1,5 @@ /* - * "$Id: cups-polld.c 5871 2006-08-23 20:55:33Z mike $" + * "$Id: cups-polld.c 5870 2006-08-23 20:30:51Z mike $" * * Polling daemon for the Common UNIX Printing System (CUPS). * @@ -478,5 +478,5 @@ sighup_handler(int sig) /* I - Signal number */ /* - * End of "$Id: cups-polld.c 5871 2006-08-23 20:55:33Z mike $". + * End of "$Id: cups-polld.c 5870 2006-08-23 20:30:51Z mike $". */ diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index dbdca8bef..81b5b3588 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -1,5 +1,5 @@ /* - * "$Id: cupsd.h 5305 2006-03-18 03:05:12Z mike $" + * "$Id: cupsd.h 6170 2007-01-02 17:26:41Z mike $" * * Main header file for the Common UNIX Printing System (CUPS) scheduler. * @@ -151,13 +151,17 @@ extern const char *cups_hstrerror(int); /* + * Select callback function type... + */ + +typedef void (*cupsd_selfunc_t)(void *data); + + +/* * Globals... */ -VAR int MaxFDs, /* Maximum number of files */ - SetSize; /* The size of the input/output sets */ -VAR fd_set *InputSet, /* Input files for select() */ - *OutputSet; /* Output files for select() */ +VAR int MaxFDs; /* Maximum number of files */ VAR time_t ReloadTime VALUE(0); /* Time of reload request... */ @@ -200,9 +204,18 @@ 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 root, int *pid); + int errfd, int backfd, int sidefd, + int root, int *pid); + +extern int cupsdAddSelect(int fd, cupsd_selfunc_t read_cb, + cupsd_selfunc_t write_cb, void *data); +extern int cupsdDoSelect(long timeout); +extern int cupsdIsSelecting(int fd); +extern void cupsdRemoveSelect(int fd); +extern void cupsdStartSelect(void); +extern void cupsdStopSelect(void); /* - * End of "$Id: cupsd.h 5305 2006-03-18 03:05:12Z mike $". + * End of "$Id: cupsd.h 6170 2007-01-02 17:26:41Z mike $". */ diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index bc5b3a466..73abd7bfc 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -1,5 +1,5 @@ /* - * "$Id: dirsvc.c 6205 2007-01-22 22:04:43Z mike $" + * "$Id: dirsvc.c 6309 2007-02-24 03:11:56Z mike $" * * Directory services routines for the Common UNIX Printing System (CUPS). * @@ -23,10 +23,13 @@ * * Contents: * + * cupsdDeregisterPrinter() - Stop sending broadcast information for a + * local printer and remove any pending + * references to remote printers. * cupsdLoadRemoteCache() - Load the remote printer cache. + * cupsdRegisterPrinter() - Start sending broadcast information for a + * printer update the broadcast contents. * cupsdSaveRemoteCache() - Save the remote printer cache. - * cupsdSendBrowseDelete() - Send a "browse delete" message for a - * printer. * cupsdSendBrowseList() - Send new browsing information as necessary. * cupsdStartBrowsing() - Start sending and receiving broadcast * information. @@ -36,9 +39,18 @@ * cupsdStopPolling() - Stop polling servers as needed. * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS * protocol. + * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries. * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP... * cupsdUpdatePolling() - Read status messages from the poll daemons. * cupsdUpdateSLPBrowse() - Get browsing information via SLP. + * dnssdBuildTxtRecord() - Build a TXT record from printer info. + * dnssdDeregisterPrinter() - Stop sending broadcast information for a + * printer. + * dnssdPackTxtRecord() - Pack an array of key/value pairs into the + * TXT record format. + * dnssdRegisterCallback() - DNSServiceRegister callback. + * dnssdRegisterPrinter() - Start sending broadcast information for a + * printer or update the broadcast contents. * dequote() - Remote quotes from a string. * process_browse_data() - Process new browse data. * process_implicit_classes() - Create/update implicit classes as needed. @@ -60,6 +72,18 @@ #include "cupsd.h" #include <grp.h> +#ifdef HAVE_DNSSD +# include <dns_sd.h> +# include <nameser.h> +# include <nameser.h> +# ifdef HAVE_COREFOUNDATION +# include <CoreFoundation/CoreFoundation.h> +# endif /* HAVE_COREFOUNDATION */ +# ifdef HAVE_SYSTEMCONFIGURATION +# include <SystemConfiguration/SystemConfiguration.h> +# endif /* HAVE_SYSTEMCONFIGURATION */ +#endif /* HAVE_DNSSD */ + /* * Local functions... @@ -135,6 +159,72 @@ static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl, SLPError errcode, void *cookie); #endif /* HAVE_LIBSLP */ +#ifdef HAVE_DNSSD +/* + * For IPP register using a subtype of 'cups' so that shared printer browsing + * only finds other CUPS servers (not all IPP based printers). + */ +static char dnssdIPPRegType[] = "_ipp._tcp,_cups"; +static char dnssdIPPFaxRegType[] = "_fax-ipp._tcp"; + +static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p); +static void dnssdDeregisterPrinter(cupsd_printer_t *p); +static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2], + int count); +static void dnssdRegisterCallback(DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, const char *regtype, + const char *domain, void *context); +static void dnssdRegisterPrinter(cupsd_printer_t *p); +#endif /* HAVE_DNSSD */ + + +/* + * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a + * local printer and remove any pending + * references to remote printers. + */ + +void +cupsdDeregisterPrinter( + cupsd_printer_t *p, /* I - Printer to register */ + int removeit) /* I - Printer being permanently removed */ +{ + /* + * Only deregister if browsing is enabled and it's a local printers... + */ + + if (!Browsing || !p->shared || + (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + return; + + /* + * Announce the deletion... + */ + + if ((BrowseLocalProtocols & BROWSE_CUPS)) + { + cups_ptype_t savedtype = p->type; /* Saved printer type */ + + p->type |= CUPS_PRINTER_DELETE; + + send_cups_browse(p); + + p->type = savedtype; + } + +#ifdef HAVE_LIBSLP + if (BrowseLocalProtocols & BROWSE_SLP) + slp_dereg_printer(p); +#endif /* HAVE_LIBSLP */ + +#ifdef HAVE_DNSSD + if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD)) + dnssdDeregisterPrinter(p); +#endif /* HAVE_DNSSD */ +} + /* * 'cupsdLoadRemoteCache()' - Load the remote printer cache. @@ -525,6 +615,30 @@ cupsdLoadRemoteCache(void) /* + * 'cupsdRegisterPrinter()' - Start sending broadcast information for a + * printer or update the broadcast contents. + */ + +void +cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ +{ + if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers || + (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + return; + +#ifdef HAVE_LIBSLP +/* if (BrowseLocalProtocols & BROWSE_SLP) + slpRegisterPrinter(p); */ +#endif /* HAVE_LIBSLP */ + +#ifdef HAVE_DNSSD + if (BrowseLocalProtocols & BROWSE_DNSSD) + dnssdRegisterPrinter(p); +#endif /* HAVE_DNSSD */ +} + + +/* * 'cupsdRestartPolling()' - Restart polling servers as needed. */ @@ -570,7 +684,7 @@ cupsdSaveRemoteCache(void) return; } else - cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache..."); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache..."); /* * Restrict access to the file... @@ -671,41 +785,6 @@ cupsdSaveRemoteCache(void) /* - * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer. - */ - -void -cupsdSendBrowseDelete( - cupsd_printer_t *p) /* I - Printer to delete */ -{ - /* - * Only announce if browsing is enabled and this is a local queue... - */ - - if (!Browsing || !p->shared || - (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) - return; - - /* - * First mark the printer for deletion... - */ - - p->type |= CUPS_PRINTER_DELETE; - - /* - * Announce the deletion... - */ - - if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0) - send_cups_browse(p); -#ifdef HAVE_LIBSLP - if ((BrowseLocalProtocols & BROWSE_SLP) && BrowseSLPHandle) - slp_dereg_printer(p); -#endif /* HAVE_LIBSLP */ -} - - -/* * 'cupsdSendBrowseList()' - Send new browsing information as necessary. */ @@ -853,6 +932,7 @@ cupsdStartBrowsing(void) { int val; /* Socket option value */ struct sockaddr_in addr; /* Broadcast address */ + cupsd_printer_t *p; /* Current printer */ BrowseNext = NULL; @@ -945,11 +1025,8 @@ cupsdStartBrowsing(void) * We only listen if we want remote printers... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartBrowsing: Adding fd %d to InputSet...", - BrowseSocket); - - FD_SET(BrowseSocket, InputSet); + cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)cupsdUpdateCUPSBrowse, + NULL, NULL); } } else @@ -1048,6 +1125,16 @@ cupsdStartBrowsing(void) BrowseLDAPRefresh = 0; } #endif /* HAVE_OPENLDAP */ + + /* + * Register the individual printers + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + cupsdRegisterPrinter(p); } @@ -1129,7 +1216,7 @@ cupsdStartPolling(void) argv[1] = pollp->hostname; - if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, + if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1, 0, &(pollp->pid)) < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, @@ -1150,10 +1237,7 @@ cupsdStartPolling(void) * Finally, add the pipe to the input selection set... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe); - - FD_SET(PollPipe, InputSet); + cupsdAddSelect(PollPipe, (cupsd_selfunc_t)cupsdUpdatePolling, NULL, NULL); } @@ -1164,9 +1248,26 @@ cupsdStartPolling(void) void cupsdStopBrowsing(void) { + cupsd_printer_t *p; /* Current printer */ + + if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols)) return; + /* + * De-register the individual printers + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + cupsdDeregisterPrinter(p, 1); + + /* + * Shut down browsing sockets... + */ + if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) && BrowseSocket >= 0) { @@ -1180,11 +1281,7 @@ cupsdStopBrowsing(void) close(BrowseSocket); #endif /* WIN32 */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopBrowsing: Removing fd %d from InputSet...", - BrowseSocket); - - FD_CLR(BrowseSocket, InputSet); + cupsdRemoveSelect(BrowseSocket); BrowseSocket = -1; } @@ -1228,9 +1325,7 @@ cupsdStopPolling(void) cupsdStatBufDelete(PollStatusBuffer); close(PollPipe); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopPolling: removing fd %d from InputSet.", PollPipe); - FD_CLR(PollPipe, InputSet); + cupsdRemoveSelect(PollPipe); PollPipe = -1; PollStatusBuffer = NULL; @@ -1515,6 +1610,34 @@ cupsdUpdateCUPSBrowse(void) } +#ifdef HAVE_DNSSD +/* + * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries. + */ + +void +cupsdUpdateDNSSDBrowse( + cupsd_printer_t *p) /* I - Printer being queried */ +{ + DNSServiceErrorType sdErr; /* Service discovery error */ + + + if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref)) + != kDNSServiceErr_NoError) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "DNS Service Discovery registration error %d for \"%s\"!", + sdErr, p->name); + cupsdRemoveSelect(p->dnssd_ipp_fd); + DNSServiceRefDeallocate(p->dnssd_ipp_ref); + + p->dnssd_ipp_ref = NULL; + p->dnssd_ipp_fd = -1; + } +} +#endif /* HAVE_DNSSD */ + + #ifdef HAVE_OPENLDAP /* * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP... @@ -2315,6 +2438,465 @@ process_browse_data( } +#ifdef HAVE_DNSSD +/* + * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. + */ + +static char * /* O - TXT record */ +dnssdBuildTxtRecord( + int *txt_len, /* O - TXT record length */ + cupsd_printer_t *p) /* I - Printer information */ +{ + int i; /* Looping var */ + char type_str[32], /* Type to string buffer */ + state_str[32], /* State to string buffer */ + rp_str[1024], /* Queue name string buffer */ + *keyvalue[32][2]; /* Table of key/value pairs */ + + + /* + * Load up the key value pairs... + */ + + i = 0; + + keyvalue[i ][0] = "txtvers"; + keyvalue[i++][1] = "1"; + + keyvalue[i ][0] = "qtotal"; + keyvalue[i++][1] = "1"; + + keyvalue[i ][0] = "rp"; + keyvalue[i++][1] = rp_str; + snprintf(rp_str, sizeof(rp_str), "%s/%s", + (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); + + keyvalue[i ][0] = "ty"; + keyvalue[i++][1] = p->make_model; + + if (p->location && *p->location != '\0') + { + keyvalue[i ][0] = "note"; + keyvalue[i++][1] = p->location; + } + + keyvalue[i ][0] = "product"; + keyvalue[i++][1] = p->product ? p->product : "Unknown"; + + snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); + snprintf(state_str, sizeof(state_str), "%d", p->state); + + keyvalue[i ][0] = "printer-state"; + keyvalue[i++][1] = state_str; + + keyvalue[i ][0] = "printer-type"; + keyvalue[i++][1] = type_str; + + keyvalue[i ][0] = "Transparent"; + keyvalue[i++][1] = "T"; + + keyvalue[i ][0] = "Binary"; + keyvalue[i++][1] = "T"; + + if ((p->type & CUPS_PRINTER_FAX)) + { + keyvalue[i ][0] = "Fax"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_COLOR)) + { + keyvalue[i ][0] = "Color"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_DUPLEX)) + { + keyvalue[i ][0] = "Duplex"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_STAPLE)) + { + keyvalue[i ][0] = "Staple"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_COPIES)) + { + keyvalue[i ][0] = "Copies"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_COLLATE)) + { + keyvalue[i ][0] = "Collate"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_PUNCH)) + { + keyvalue[i ][0] = "Punch"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_BIND)) + { + keyvalue[i ][0] = "Bind"; + keyvalue[i++][1] = "T"; + } + + if ((p->type & CUPS_PRINTER_SORT)) + { + keyvalue[i ][0] = "Sort"; + keyvalue[i++][1] = "T"; + } + + keyvalue[i ][0] = "pdl"; + keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript"; + + /* + * Then pack them into a proper txt record... + */ + + return (dnssdPackTxtRecord(txt_len, keyvalue, i)); +} + + +/* + * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a + * printer. + */ + +static void +dnssdDeregisterPrinter( + cupsd_printer_t *p) /* I - Printer */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name); + + /* + * Closing the socket deregisters the service + */ + + if (p->dnssd_ipp_ref) + { + cupsdRemoveSelect(p->dnssd_ipp_fd); + DNSServiceRefDeallocate(p->dnssd_ipp_ref); + p->dnssd_ipp_ref = NULL; + p->dnssd_ipp_fd = -1; + } + + cupsdClearString(&p->reg_name); + + if (p->txt_record) + { + /* + * p->txt_record is malloc'd, not _cupsStrAlloc'd... + */ + + free(p->txt_record); + p->txt_record = NULL; + } +} + + +/* + * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the + * TXT record format. + */ + +static char * /* O - TXT record */ +dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ + char *keyvalue[][2], /* I - Table of key value pairs */ + int count) /* I - Items in table */ +{ + int i; /* Looping var */ + int length; /* Length of TXT record */ + int length2; /* Length of value */ + char *txtRecord; /* TXT record buffer */ + char *cursor; /* Looping pointer */ + + + /* + * Calculate the buffer size + */ + + for (length = i = 0; i < count; i++) + length += 1 + strlen(keyvalue[i][0]) + + (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); + + /* + * Allocate and fill it + */ + + txtRecord = malloc(length); + if (txtRecord) + { + *txt_len = length; + + for (cursor = txtRecord, i = 0; i < count; i++) + { + /* + * Drop in the p-string style length byte followed by the data + */ + + length = strlen(keyvalue[i][0]); + length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0; + + *cursor++ = (unsigned char)(length + length2); + + memcpy(cursor, keyvalue[i][0], length); + cursor += length; + + if (length2) + { + length2 --; + *cursor++ = '='; + memcpy(cursor, keyvalue[i][1], length2); + cursor += length2; + } + } + } + + return (txtRecord); +} + + +/* + * 'dnssdRegisterCallback()' - DNSServiceRegister callback. + */ + +static void +dnssdRegisterCallback( + DNSServiceRef sdRef, /* I - DNS Service reference */ + DNSServiceFlags flags, /* I - Reserved for future use */ + DNSServiceErrorType errorCode, /* I - Error code */ + const char *name, /* I - Service name */ + const char *regtype, /* I - Service type */ + const char *domain, /* I - Domain. ".local" for now */ + void *context) /* I - User-defined context */ +{ + (void)context; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "dnssdRegisterCallback(%s, %s)", name, regtype); + + if (errorCode) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "DNSServiceRegister failed with error %d", (int)errorCode); + return; + } +} + + +/* + * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer + * or update the broadcast contents. + */ + +static void +dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ +{ + DNSServiceErrorType se; /* dnssd errors */ + cupsd_listener_t *lis; /* Current listening socket */ + char *txt_record, /* TXT record buffer */ + *name; /* Service name */ + int txt_len, /* TXT record length */ + port; /* IPP port number */ + char str_buffer[1024]; + /* C-string buffer */ + const char *computerName; /* Computer name c-string ptr */ + const char *regtype; /* Registration type */ +#ifdef HAVE_COREFOUNDATION_H + CFStringRef computerNameRef;/* Computer name CFString */ + CFStringEncoding nameEncoding; /* Computer name encoding */ + CFMutableStringRef shortNameRef; /* Mutable name string */ + CFIndex nameLength; /* Name string length */ +#else + int nameLength; /* Name string length */ +#endif /* HAVE_COREFOUNDATION_H */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, + !p->dnssd_ipp_ref ? "new" : "update"); + + /* + * If per-printer sharing was just disabled make sure we're not + * registered before returning. + */ + + if (!p->shared) + { + dnssdDeregisterPrinter(p); + return; + } + + /* + * Get the computer name as a c-string... + */ + +#ifdef HAVE_COREFOUNDATION_H + computerName = NULL; + if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding))) + if ((computerName = CFStringGetCStringPtr(computerNameRef, + kCFStringEncodingUTF8)) == NULL) + if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer), + kCFStringEncodingUTF8)) + computerName = str_buffer; +#else + computerName = ServerName; +#endif /* HAVE_COREFOUNDATION_H */ + + /* + * The registered name takes the form of "<printer-info> @ <computer name>"... + */ + + name = NULL; + if (computerName) + cupsdSetStringf(&name, "%s @ %s", + (p->info && strlen(p->info)) ? p->info : p->name, + computerName); + else + cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name); + +#ifdef HAVE_COREFOUNDATION_H + if (computerNameRef) + CFRelease(computerNameRef); +#endif /* HAVE_COREFOUNDATION_H */ + + /* + * If an existing printer was renamed, unregister it and start over... + */ + + if (p->reg_name && strcmp(p->reg_name, name)) + dnssdDeregisterPrinter(p); + + txt_len = 0; /* anti-compiler-warning-code */ + txt_record = dnssdBuildTxtRecord(&txt_len, p); + + if (!p->dnssd_ipp_ref) + { + /* + * Initial registration... + */ + + cupsdSetString(&p->reg_name, name); + + port = ippPort(); + + for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); + lis; + lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) + { + if (lis->address.addr.sa_family == AF_INET) + { + port = ntohs(lis->address.ipv4.sin_port); + break; + } + else if (lis->address.addr.sa_family == AF_INET6) + { + port = ntohs(lis->address.ipv6.sin6_port); + break; + } + } + + /* + * Use the _fax subtype for fax queues... + */ + + regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType : + dnssdIPPRegType; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) type is \"%s\"", + p->name, regtype); + + se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype, + NULL, NULL, htons(port), txt_len, txt_record, + dnssdRegisterCallback, p); + + /* + * In case the name is too long, try shortening the string one character + * at a time... + */ + + if (se == kDNSServiceErr_BadParam) + { +#ifdef HAVE_COREFOUNDATION_H + if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL) + { + CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8); + nameLength = CFStringGetLength(shortNameRef); + + while (se == kDNSServiceErr_BadParam && nameLength > 1) + { + CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1)); + if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer), + kCFStringEncodingUTF8)) + { + se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, + regtype, NULL, NULL, htons(port), + txt_len, txt_record, + dnssdRegisterCallback, p); + } + } + + CFRelease(shortNameRef); + } +#else + nameLength = strlen(name); + while (se == kDNSServiceErr_BadParam && nameLength > 1) + { + name[--nameLength] = '\0'; + se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype, + NULL, NULL, htons(port), txt_len, txt_record, + dnssdRegisterCallback, p); + } +#endif /* HAVE_COREFOUNDATION_H */ + } + + if (se == kDNSServiceErr_NoError) + { + p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref); + p->txt_record = txt_record; + p->txt_len = txt_len; + txt_record = NULL; + + cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse, + NULL, (void *)p); + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "DNS-SD registration of \"%s\" failed with %d", + p->name, se); + } + else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len)) + { + /* + * Update the existing registration... + */ + + /* A TTL of 0 means use record's original value (Radar 3176248) */ + se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0, + txt_len, txt_record, 0); + + if (p->txt_record) + free(p->txt_record); + + p->txt_record = txt_record; + p->txt_len = txt_len; + txt_record = NULL; + } + + if (txt_record) + free(txt_record); + + cupsdClearString(&name); +} +#endif /* HAVE_DNSSD */ + + /* * 'process_implicit_classes()' - Create/update implicit classes as needed. */ @@ -3192,5 +3774,5 @@ slp_url_callback( /* - * End of "$Id: dirsvc.c 6205 2007-01-22 22:04:43Z mike $". + * End of "$Id: dirsvc.c 6309 2007-02-24 03:11:56Z mike $". */ diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h index 2e3a05988..f9d0c025c 100644 --- a/scheduler/dirsvc.h +++ b/scheduler/dirsvc.h @@ -1,10 +1,10 @@ /* - * "$Id: dirsvc.h 5833 2006-08-16 20:05:58Z mike $" + * "$Id: dirsvc.h 6291 2007-02-19 21:54:27Z mike $" * * Directory services definitions for the Common UNIX Printing System * (CUPS) scheduler. * - * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -45,7 +45,7 @@ #define BROWSE_CUPS 1 /* CUPS */ #define BROWSE_SLP 2 /* SLPv2 */ #define BROWSE_LDAP 4 /* LDAP */ -#define BROWSE_DNSSD 8 /* DNS Service Discovery aka Bonjour */ +#define BROWSE_DNSSD 8 /* DNS Service Discovery (aka Bonjour) */ #define BROWSE_ALL 15 /* All protocols */ @@ -163,16 +163,20 @@ VAR char *BrowseLDAPBindDN VALUE(NULL), * Prototypes... */ +extern void cupsdDeregisterPrinter(cupsd_printer_t *p, int removeit); extern void cupsdLoadRemoteCache(void); +extern void cupsdRegisterPrinter(cupsd_printer_t *p); extern void cupsdRestartPolling(void); extern void cupsdSaveRemoteCache(void); -extern void cupsdSendBrowseDelete(cupsd_printer_t *p); extern void cupsdSendBrowseList(void); extern void cupsdStartBrowsing(void); extern void cupsdStartPolling(void); extern void cupsdStopBrowsing(void); extern void cupsdStopPolling(void); extern void cupsdUpdateCUPSBrowse(void); +#ifdef HAVE_DNSSD +extern void cupsdUpdateDNSSDBrowse(cupsd_printer_t *p); +#endif /* HAVE_DNSSD */ #ifdef HAVE_LDAP extern void cupsdUpdateLDAPBrowse(void); #endif /* HAVE_LDAP */ @@ -181,5 +185,5 @@ extern void cupsdUpdateSLPBrowse(void); /* - * End of "$Id: dirsvc.h 5833 2006-08-16 20:05:58Z mike $". + * End of "$Id: dirsvc.h 6291 2007-02-19 21:54:27Z mike $". */ diff --git a/scheduler/filter.c b/scheduler/filter.c index 25d3b651e..e6ca1b518 100644 --- a/scheduler/filter.c +++ b/scheduler/filter.c @@ -1,9 +1,9 @@ /* - * "$Id: filter.c 5606 2006-05-30 19:40:34Z mike $" + * "$Id: filter.c 6252 2007-02-10 15:34:18Z mike $" * * File type conversion routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -23,12 +23,12 @@ * * Contents: * - * mimeAddFilter() - Add a filter to the current MIME database. - * mimeFilter() - Find the fastest way to convert from one type to - * another. - * compare_filters() - Compare two filters... - * find_filters() - Find the filters to convert from one type to another. - * lookup() - Lookup a filter... + * mimeAddFilter() - Add a filter to the current MIME database. + * mimeFilter() - Find the fastest way to convert from one type to + * another. + * mimeFilterLookup() - Lookup a filter... + * compare_filters() - Compare two filters... + * find_filters() - Find the filters to convert from one type to another. */ /* @@ -64,7 +64,6 @@ static int compare_srcs(mime_filter_t *, mime_filter_t *); static cups_array_t *find_filters(mime_t *mime, mime_type_t *src, mime_type_t *dst, int *cost, _mime_typelist_t *visited); -static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *); /* @@ -93,7 +92,7 @@ mimeAddFilter(mime_t *mime, /* I - MIME database */ * destination... */ - if ((temp = lookup(mime, src, dst)) != NULL) + if ((temp = mimeFilterLookup(mime, src, dst)) != NULL) { /* * Yup, does the existing filter have a higher cost? If so, copy the @@ -194,6 +193,25 @@ mimeFilter(mime_t *mime, /* I - MIME database */ /* + * 'mimeFilterLookup()' - Lookup a filter... + */ + +mime_filter_t * /* O - Filter for src->dst */ +mimeFilterLookup(mime_t *mime, /* I - MIME database */ + mime_type_t *src, /* I - Source type */ + mime_type_t *dst) /* I - Destination type */ +{ + mime_filter_t key; /* Key record for filter search */ + + + key.src = src; + key.dst = dst; + + return ((mime_filter_t *)cupsArrayFind(mime->filters, &key)); +} + + +/* * 'compare_filters()' - Compare two filters... */ @@ -260,7 +278,7 @@ find_filters(mime_t *mime, /* I - MIME database */ * See if there is a filter that can convert the files directly... */ - if ((current = lookup(mime, src, dst)) != NULL) + if ((current = mimeFilterLookup(mime, src, dst)) != NULL) { /* * Got a direct filter! @@ -392,24 +410,5 @@ find_filters(mime_t *mime, /* I - MIME database */ /* - * 'lookup()' - Lookup a filter... - */ - -static mime_filter_t * /* O - Filter for src->dst */ -lookup(mime_t *mime, /* I - MIME database */ - mime_type_t *src, /* I - Source type */ - mime_type_t *dst) /* I - Destination type */ -{ - mime_filter_t key; /* Key record for filter search */ - - - key.src = src; - key.dst = dst; - - return ((mime_filter_t *)cupsArrayFind(mime->filters, &key)); -} - - -/* - * End of "$Id: filter.c 5606 2006-05-30 19:40:34Z mike $". + * End of "$Id: filter.c 6252 2007-02-10 15:34:18Z mike $". */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index f96d2bf13..78edc3cc8 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,9 +1,12 @@ /* - * "$Id: ipp.c 6145 2006-12-06 20:10:16Z mike $" + * "$Id: ipp.c 6318 2007-03-06 04:36:55Z mike $" * * IPP routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -79,6 +82,7 @@ * release_job() - Release a held print job. * restart_job() - Restart an old print job. * save_auth_info() - Save authentication information for a job. + * save_krb5_creds() - Save Kerberos credentials for a job. * send_document() - Send a file to a printer or class. * send_http_error() - Send a HTTP error back to the IPP client. * send_ipp_status() - Send a status back to the IPP client. @@ -101,6 +105,10 @@ #include "cupsd.h" +#ifdef HAVE_KRB5_H +# include <krb5.h> +#endif /* HAVE_KRB5_H */ + #ifdef HAVE_LIBPAPER # include <paper.h> #endif /* HAVE_LIBPAPER */ @@ -114,8 +122,7 @@ static void accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri); static void add_class(cupsd_client_t *con, ipp_attribute_t *uri); static int add_file(cupsd_client_t *con, cupsd_job_t *job, mime_type_t *filetype, int compression); -static cupsd_job_t *add_job(cupsd_client_t *con, ipp_attribute_t *uri, - cupsd_printer_t **dprinter, +static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer, mime_type_t *filetype); static void add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job); static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job); @@ -174,7 +181,11 @@ static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri); static void release_job(cupsd_client_t *con, ipp_attribute_t *uri); static void renew_subscription(cupsd_client_t *con, int sub_id); static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri); -static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job); +static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job, + ipp_attribute_t *auth_info); +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) +static void save_krb5_creds(cupsd_client_t *con, cupsd_job_t *job); +#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ static void send_document(cupsd_client_t *con, ipp_attribute_t *uri); static void send_http_error(cupsd_client_t *con, http_status_t status); static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, @@ -233,7 +244,7 @@ cupsdProcessIPPRequest( /* * Then validate the request header and required attributes... */ - + if (con->request->request.any.version[0] != 1) { /* @@ -250,7 +261,7 @@ cupsdProcessIPPRequest( _("Bad request version number %d.%d!"), con->request->request.any.version[0], con->request->request.any.version[1]); - } + } else if (!con->request->attrs) { cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, @@ -384,7 +395,7 @@ cupsdProcessIPPRequest( cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow..."); for (attr = con->request->attrs; attr; attr = attr->next) - cupsdLogMessage(CUPSD_LOG_DEBUG, + cupsdLogMessage(CUPSD_LOG_DEBUG, "attr \"%s\": group_tag = %x, value_tag = %x", attr->name ? attr->name : "(null)", attr->group_tag, attr->value_tag); @@ -651,11 +662,8 @@ cupsdProcessIPPRequest( con->http.data_remaining = length; } - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdProcessIPPRequest: Adding fd %d to OutputSet...", - con->http.fd); - - FD_SET(con->http.fd, OutputSet); + cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, + (cupsd_selfunc_t)cupsdWriteClient, con); /* * Tell the caller the response header was sent successfully... @@ -694,12 +702,6 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], /* Method 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 */ - const char *name; /* Printer name */ cupsd_printer_t *printer; /* Printer data */ @@ -710,11 +712,7 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -745,12 +743,19 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdAddPrinterHistory(printer); if (dtype & CUPS_PRINTER_CLASS) + { cupsdSaveAllClasses(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").", + printer->name, get_username(con)); + } else + { cupsdSaveAllPrinters(); - cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").", name, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").", + printer->name, get_username(con)); + } /* * Everything was ok, so return OK status... @@ -932,7 +937,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_BOOLEAN)) != NULL) { if (pclass->shared && !attr->values[0].boolean) - cupsdSendBrowseDelete(pclass); + cupsdDeregisterPrinter(pclass, 1); cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-shared to %d (was %d.)", @@ -996,11 +1001,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ * Search for the printer or class URI... */ - httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if (!cupsdValidateDest(host, resource, &dtype, &member)) + if (!cupsdValidateDest(attr->values[i].string.text, &dtype, &member)) { /* * Bad URI... @@ -1137,54 +1138,25 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ static cupsd_job_t * /* O - Job object */ add_job(cupsd_client_t *con, /* I - Client connection */ - ipp_attribute_t *uri, /* I - printer-uri */ - cupsd_printer_t **dprinter, /* I - Destination printer */ + cupsd_printer_t *printer, /* I - Destination printer */ mime_type_t *filetype) /* I - First print file type, if any */ { http_status_t status; /* Policy status */ - ipp_attribute_t *attr; /* Current attribute */ - const char *dest; /* Destination */ - cups_ptype_t dtype; /* Destination type (printer or class) */ + ipp_attribute_t *attr, /* Current attribute */ + *auth_info; /* auth-info attribute */ const char *val; /* Default option value */ int priority; /* Job priority */ char *title; /* Job name/title */ cupsd_job_t *job; /* Current job */ - char job_uri[HTTP_MAX_URI], /* Job URI */ - method[HTTP_MAX_URI], /* Method 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 */ - cupsd_printer_t *printer; /* Printer data */ + char job_uri[HTTP_MAX_URI]; /* Job URI */ int kbytes; /* Size of print file */ int i; /* Looping var */ int lowerpagerange; /* Page range bound */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); - - /* - * Is the destination valid? - */ - - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) - { - /* - * Bad URI... - */ - - send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); - return (NULL); - } - - if (dprinter) - *dprinter = printer; + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))", + con, con->http.fd, printer, printer->name, + filetype, filetype->super, filetype->type); /* * Check remote printing to non-shared printer... @@ -1222,13 +1194,13 @@ add_job(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_NOT_ACCEPTING, _("Destination \"%s\" is not accepting jobs."), - dest); + printer->name); return (NULL); } /* * Validate job template attributes; for now just document-format, - * copies, and page-ranges... + * copies, number-up, and page-ranges... */ if (filetype && printer->filetypes && @@ -1263,12 +1235,30 @@ add_job(cupsd_client_t *con, /* I - Client connection */ } } + if ((attr = ippFindAttribute(con->request, "number-up", + IPP_TAG_INTEGER)) != NULL) + { + if (attr->values[0].integer != 1 && + attr->values[0].integer != 2 && + attr->values[0].integer != 4 && + attr->values[0].integer != 6 && + attr->values[0].integer != 9 && + attr->values[0].integer != 16) + { + send_ipp_status(con, IPP_ATTRIBUTES, _("Bad number-up value %d."), + attr->values[0].integer); + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, + "number-up", attr->values[0].integer); + return (NULL); + } + } + if ((attr = ippFindAttribute(con->request, "page-ranges", IPP_TAG_RANGE)) != NULL) { for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++) { - if (attr->values[i].range.lower < lowerpagerange || + if (attr->values[i].range.lower < lowerpagerange || attr->values[i].range.lower > attr->values[i].range.upper) { send_ipp_status(con, IPP_BAD_REQUEST, @@ -1289,7 +1279,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs) cupsdCleanJobs(); - if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs) + if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("Too many active jobs.")); @@ -1331,11 +1321,13 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if ((job = cupsdAddJob(priority, printer->name)) == NULL) { send_ipp_status(con, IPP_INTERNAL_ERROR, - _("Unable to add job for destination \"%s\"!"), dest); + _("Unable to add job for destination \"%s\"!"), + printer->name); return (NULL); } - job->dtype = dtype; + job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_REMOTE); job->attrs = con->request; con->request = ippNewRequest(job->attrs->request.op.operation_id); @@ -1350,8 +1342,6 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (attr) cupsdSetString(&attr->values[0].string.text, con->username); - - save_auth_info(con, job); } else if (attr) { @@ -1374,6 +1364,30 @@ add_job(cupsd_client_t *con, /* I - Client connection */ attr->name = _cupsStrAlloc("job-originating-user-name"); } + auth_info = ippFindAttribute(job->attrs, "auth-info", IPP_TAG_TEXT); + + if (con->username[0] || auth_info) + { + save_auth_info(con, job, auth_info); + + /* + * Remove the auth-info attribute from the attribute data... + */ + + if (auth_info) + { + if (job->attrs->prev) + job->attrs->prev->next = auth_info->next; + else + job->attrs->attrs = auth_info->next; + + if (job->attrs->last == auth_info) + job->attrs->last = job->attrs->prev; + + _ippFreeAttr(auth_info); + } + } + if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", IPP_TAG_ZERO)) != NULL) { @@ -1440,7 +1454,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * the connection... */ - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname); } @@ -2266,7 +2280,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_BOOLEAN)) != NULL) { if (printer->shared && !attr->values[0].boolean) - cupsdSendBrowseDelete(printer); + cupsdDeregisterPrinter(printer, 1); cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-shared to %d (was %d.)", @@ -2566,7 +2580,7 @@ apply_printer_defaults( int i, /* Looping var */ num_options; /* Number of default options */ cups_option_t *options, /* Default options */ - *option; /* Current option */ + *option; /* Current option */ /* @@ -2600,7 +2614,8 @@ static void authenticate_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Job URI */ { - ipp_attribute_t *attr; /* Job-id attribute */ + ipp_attribute_t *attr, /* job-id attribute */ + *auth_info; /* auth-info attribute */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ char method[HTTP_MAX_URI], @@ -2652,7 +2667,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, sizeof(method), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); - + if (strncmp(resource, "/jobs/", 6)) { /* @@ -2702,7 +2717,9 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ * See if we have already authenticated... */ - if (!con->username[0]) + auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT); + + if (!con->username[0] && !auth_info) { send_ipp_status(con, IPP_NOT_AUTHORIZED, _("No authentication information provided!")); @@ -2723,7 +2740,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ * Save the authentication information for this job... */ - save_auth_info(con, job); + save_auth_info(con, job, auth_info); /* * Reset the job-hold-until value to "no-hold"... @@ -2759,11 +2776,10 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Job or Printer URI */ { http_status_t status; /* Policy status */ - const char *dest; /* Destination */ cups_ptype_t dtype; /* Destination type */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Scheme portion of URI */ userpass[HTTP_MAX_URI], /* Username portion of URI */ - host[HTTP_MAX_URI], /* Host portion of URI */ + hostname[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ ipp_attribute_t *attr; /* Attribute in request */ @@ -2822,16 +2838,17 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ * And if the destination is valid... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), userpass, sizeof(userpass), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI? */ + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, + scheme, sizeof(scheme), userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + if ((!strncmp(resource, "/printers/", 10) && resource[10]) || (!strncmp(resource, "/classes/", 9) && resource[9])) { @@ -2839,13 +2856,6 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ _("The printer or class was not found.")); return; } - else if (strcmp(resource, "/printers/")) - { - send_ipp_status(con, IPP_NOT_FOUND, - _("The printer-uri \"%s\" is not valid."), - uri->values[0].string.text); - return; - } /* * Check policy... @@ -2872,7 +2882,8 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, + NULL)) != HTTP_OK) { send_http_error(con, status); return; @@ -2882,10 +2893,11 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ * Cancel all of the jobs on the named printer... */ - cupsdCancelJobs(dest, username, purge); + cupsdCancelJobs(printer->name, username, purge); cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".", - dest, purge ? "purged" : "canceled", get_username(con)); + printer->name, purge ? "purged" : "canceled", + get_username(con)); } con->response->request.status.status_code = IPP_OK; @@ -2902,13 +2914,12 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + 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 */ cupsd_job_t *job; /* Job information */ - const char *dest; /* Destination */ cups_ptype_t dtype; /* Destination type (printer or class) */ cupsd_printer_t *printer; /* Printer data */ @@ -2940,11 +2951,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ * Find the current job on the specified printer... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -2966,12 +2973,12 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ /* * No, see if there are any pending jobs... */ - + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) if (job->state_value <= IPP_JOB_PROCESSING && - !strcasecmp(job->dest, dest)) + !strcasecmp(job->dest, printer->name)) break; if (job) @@ -2979,7 +2986,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ else { send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"), - dest); + printer->name); return; } } @@ -2991,10 +2998,10 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); - + if (strncmp(resource, "/jobs/", 6)) { /* @@ -3794,7 +3801,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ const char *from, /* I - Source file */ const char *to) /* I - Destination file */ { - fd_set *input; /* select() input set */ + fd_set input; /* select() input set */ struct timeval timeout; /* select() timeout */ int maxfd; /* Maximum file descriptor for select() */ char tempfile[1024]; /* Temporary PPD file */ @@ -3847,24 +3854,12 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ cupsdOpenPipe(temppipe); - if ((input = calloc(1, SetSize)) == NULL) - { - close(tempfd); - unlink(tempfile); - - cupsdLogMessage(CUPSD_LOG_ERROR, - "copy_model: Unable to allocate %d bytes for select()...", - SetSize); - return (-1); - } - cupsdLogMessage(CUPSD_LOG_DEBUG, "copy_model: Running \"cups-driverd cat %s\"...", from); if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1], - -1, 0, &temppid)) + -1, -1, 0, &temppid)) { - free(input); close(tempfd); unlink(tempfile); return (-1); @@ -3891,13 +3886,14 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ bytes = 0; - FD_SET(temppipe[0], input); - FD_SET(CGIPipes[0], input); + FD_ZERO(&input); + FD_SET(temppipe[0], &input); + FD_SET(CGIPipes[0], &input); timeout.tv_sec = 30; timeout.tv_usec = 0; - if ((i = select(maxfd, input, NULL, NULL, &timeout)) < 0) + if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0) { if (errno == EINTR) continue; @@ -3913,7 +3909,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ break; } - if (FD_ISSET(temppipe[0], input)) + if (FD_ISSET(temppipe[0], &input)) { /* * Read the PPD file from the pipe, and write it to the PPD file. @@ -3930,15 +3926,13 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ break; } - if (FD_ISSET(CGIPipes[0], input)) + if (FD_ISSET(CGIPipes[0], &input)) cupsdUpdateCGI(); } close(temppipe[0]); close(tempfd); - free(input); - if (!total) { /* @@ -4020,13 +4014,13 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ if ((!strcmp(system_paper, "Letter") && have_letter) || (!strcmp(system_paper, "A4") && have_a4)) { - num_defaults = cupsAddOption("PageSize", system_paper, + num_defaults = cupsAddOption("PageSize", system_paper, num_defaults, &defaults); - num_defaults = cupsAddOption("PageRegion", system_paper, + num_defaults = cupsAddOption("PageRegion", system_paper, num_defaults, &defaults); - num_defaults = cupsAddOption("PaperDimension", system_paper, + num_defaults = cupsAddOption("PaperDimension", system_paper, num_defaults, &defaults); - num_defaults = cupsAddOption("ImageableArea", system_paper, + num_defaults = cupsAddOption("ImageableArea", system_paper, num_defaults, &defaults); } } @@ -4261,7 +4255,7 @@ copy_printer_attrs( if (!ra || cupsArrayFind(ra, "printer-state-change-time")) ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", printer->state_time); - + if (MaxPrinterHistory > 0 && printer->num_history > 0 && cupsArrayFind(ra, "printer-state-history")) { @@ -4446,23 +4440,39 @@ static void create_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { - cupsd_job_t *job; /* New job */ + cupsd_printer_t *printer; /* Printer */ + cupsd_job_t *job; /* New job */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, con->http.fd, uri->values[0].string.text); /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* * Create the job object... */ - if ((job = add_job(con, uri, NULL, NULL)) == NULL) + if ((job = add_job(con, printer, NULL)) == NULL) return; /* * Save and log the job... */ - + cupsdSaveJob(job); cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on \"%s\" by \"%s\".", @@ -4630,6 +4640,16 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "uri-authentication-supported"); cupsArrayAdd(ra, "uri-security-supported"); } + else if (!strcmp(value, "printer-defaults")) + { + char *name; /* Option name */ + + + for (name = (char *)cupsArrayFirst(CommonDefaults); + name; + name = (char *)cupsArrayNext(CommonDefaults)) + cupsArrayAdd(ra, name); + } else if (!strcmp(value, "subscription-template")) { cupsArrayAdd(ra, "notify-attributes"); @@ -4683,6 +4703,8 @@ create_subscription( int interval, /* notify-time-interval */ lease; /* notify-lease-duration */ unsigned mask; /* notify-events */ + ipp_attribute_t *notify_events,/* notify-events(-default) */ + *notify_lease; /* notify-lease-duration(-default) */ #ifdef DEBUG @@ -4723,7 +4745,7 @@ create_subscription( dtype = CUPS_PRINTER_CLASS; printer = NULL; } - else if (!cupsdValidateDest(host, resource, &dtype, &printer)) + else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -4740,7 +4762,8 @@ create_subscription( if (printer) { - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, + NULL)) != HTTP_OK) { send_http_error(con, status); return; @@ -4790,6 +4813,23 @@ create_subscription( jobid = 0; mask = CUPSD_EVENT_NONE; + if (printer) + { + notify_events = ippFindAttribute(printer->attrs, "notify-events-default", + IPP_TAG_KEYWORD); + notify_lease = ippFindAttribute(printer->attrs, + "notify-lease-duration-default", + IPP_TAG_INTEGER); + + if (notify_lease) + lease = notify_lease->values[0].integer; + } + else + { + notify_events = NULL; + notify_lease = NULL; + } + while (attr && attr->group_tag != IPP_TAG_ZERO) { if (!strcmp(attr->name, "notify-recipient") && @@ -4878,10 +4918,7 @@ create_subscription( } else if (!strcmp(attr->name, "notify-events") && attr->value_tag == IPP_TAG_KEYWORD) - { - for (i = 0; i < attr->num_values; i ++) - mask |= cupsdEventValue(attr->values[i].string.text); - } + notify_events = attr; else if (!strcmp(attr->name, "notify-lease-duration") && attr->value_tag == IPP_TAG_INTEGER) lease = attr->values[0].integer; @@ -4895,6 +4932,12 @@ create_subscription( attr = attr->next; } + if (notify_events) + { + for (i = 0; i < notify_events->num_values; i ++) + mask |= cupsdEventValue(notify_events->values[i].string.text); + } + if (recipient) cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient); if (pullmethod) @@ -4989,13 +5032,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - URI of printer or class */ { http_status_t status; /* Policy status */ - const char *dest; /* Destination */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], /* Method 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 */ cupsd_printer_t *printer; /* Printer/class */ char filename[1024]; /* Script/PPD filename */ @@ -5007,11 +5044,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ * Do we have a valid URI? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -5036,7 +5069,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ * Remove old jobs... */ - cupsdCancelJobs(dest, NULL, 1); + cupsdCancelJobs(printer->name, NULL, 1); /* * Remove old subscriptions and send a "deleted printer" event... @@ -5045,32 +5078,34 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL, "%s \"%s\" deleted by \"%s\".", (dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - dest, get_username(con)); + printer->name, get_username(con)); cupsdExpireSubscriptions(printer, NULL); - + /* * Remove any old PPD or script files... */ - snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, dest); + snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, + printer->name); unlink(filename); - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest); + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, + printer->name); unlink(filename); if (dtype & CUPS_PRINTER_CLASS) { - cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".", dest, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".", + printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); cupsdSaveAllClasses(); } else { - cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", dest, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", + printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); cupsdSaveAllPrinters(); @@ -5313,7 +5348,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ const char *dest; /* Destination */ cups_ptype_t dtype; /* Destination type (printer or class) */ cups_ptype_t dmask; /* Destination type mask */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + 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 */ @@ -5335,8 +5370,8 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (!strcmp(resource, "/") || @@ -5361,7 +5396,8 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ dmask = CUPS_PRINTER_CLASS; printer = NULL; } - else if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + else if ((dest = cupsdValidateDest(uri->values[0].string.text, &dtype, + &printer)) == NULL) { /* * Bad URI... @@ -5383,7 +5419,8 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (printer) { - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, + NULL)) != HTTP_OK) { send_http_error(con, status); return; @@ -5512,7 +5549,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ int interval; /* Poll interval */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscription_attrs(con=%p[%d])", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])", con, con->http.fd); /* @@ -5720,15 +5757,6 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method 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 */ cupsd_printer_t *printer; /* Printer/class */ cups_array_t *ra; /* Requested attributes array */ @@ -5740,11 +5768,7 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if (!cupsdValidateDest(host, resource, &dtype, &printer)) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -6007,8 +6031,8 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ cups_array_t *ra; /* Requested attributes array */ ipp_attribute_t *attr; /* Attribute */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method portion of URI */ + char scheme[HTTP_MAX_URI], + /* Scheme portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], @@ -6028,8 +6052,8 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (!strcmp(resource, "/") || @@ -6052,7 +6076,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ return; } } - else if (!cupsdValidateDest(host, resource, &dtype, &printer)) + else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -6316,7 +6340,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ const char *src; /* Source printer/class */ cups_ptype_t stype, /* Source type (printer or class) */ dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + 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 */ @@ -6343,12 +6367,8 @@ move_job(cupsd_client_t *con, /* I - Client connection */ _("job-printer-uri attribute missing!")); return; } - - httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - if (!cupsdValidateDest(host, resource, &dtype, &dprinter)) + if (!cupsdValidateDest(attr->values[0].string.text, &dtype, &dprinter)) { /* * Bad URI... @@ -6363,7 +6383,8 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con, + NULL)) != HTTP_OK) { send_http_error(con, status); return; @@ -6373,8 +6394,8 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * See if we have a job URI or a printer URI... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (!strcmp(uri->name, "printer-uri")) @@ -6390,7 +6411,8 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * Move all jobs... */ - if ((src = cupsdValidateDest(host, resource, &stype, &sprinter)) == NULL) + if ((src = cupsdValidateDest(uri->values[0].string.text, &stype, + &sprinter)) == NULL) { /* * Bad URI... @@ -6638,6 +6660,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *format; /* Document-format attribute */ + const char *default_format; /* document-format-default value */ cupsd_job_t *job; /* New job */ char filename[1024]; /* Job filename */ mime_type_t *filetype; /* Type of file */ @@ -6695,6 +6718,21 @@ print_job(cupsd_client_t *con, /* I - Client connection */ } /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* * Is it a format we support? */ @@ -6705,7 +6743,8 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Grab format from client... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) + if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, + type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Could not scan type \"%s\"!"), @@ -6713,10 +6752,26 @@ print_job(cupsd_client_t *con, /* I - Client connection */ return; } } + else if ((default_format = cupsGetOption("document-format", + printer->num_options, + printer->options)) != NULL) + { + /* + * Use default document format... + */ + + if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Could not scan type \"%s\"!"), + default_format); + return; + } + } else { /* - * No document format attribute? Auto-type it! + * Auto-type it! */ strcpy(super, "application"); @@ -6739,32 +6794,35 @@ print_job(cupsd_client_t *con, /* I - Client connection */ doc_name ? doc_name->values[0].string.text : NULL, &compression); - if (filetype) - { - /* - * Replace the document-format attribute value with the auto-typed one. - */ + if (!filetype) + filetype = mimeType(MimeDatabase, super, type); + } + else + filetype = mimeType(MimeDatabase, super, type); - snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, - filetype->type); + if (filetype && + (!format || + (!strcmp(super, "application") && !strcmp(type, "octet-stream")))) + { + /* + * Replace the document-format attribute value with the auto-typed or + * default one. + */ - if (format) - { - _cupsStrFree(format->values[0].string.text); + snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, + filetype->type); - format->values[0].string.text = _cupsStrAlloc(mimetype); - } - else - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, - "document-format", NULL, mimetype); + if (format) + { + _cupsStrFree(format->values[0].string.text); + + format->values[0].string.text = _cupsStrAlloc(mimetype); } else - filetype = mimeType(MimeDatabase, super, type); + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, + "document-format", NULL, mimetype); } - else - filetype = mimeType(MimeDatabase, super, type); - - if (!filetype) + else if (!filetype) { send_ipp_status(con, IPP_DOCUMENT_FORMAT, _("Unsupported format \'%s/%s\'!"), super, type); @@ -6793,7 +6851,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Create the job object... */ - if ((job = add_job(con, uri, &printer, filetype)) == NULL) + if ((job = add_job(con, printer, filetype)) == NULL) return; /* @@ -7058,12 +7116,6 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], /* Method 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 */ - const char *name; /* Printer name */ cupsd_printer_t *printer; /* Printer data */ ipp_attribute_t *attr; /* printer-state-message text */ @@ -7075,11 +7127,7 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -7120,14 +7168,14 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdSaveAllClasses(); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").", - name, get_username(con)); + printer->name, get_username(con)); } else { cupsdSaveAllPrinters(); cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").", - name, get_username(con)); + printer->name, get_username(con)); } /* @@ -7499,22 +7547,24 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ */ static void -save_auth_info(cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Job */ +save_auth_info( + cupsd_client_t *con, /* I - Client connection */ + cupsd_job_t *job, /* I - Job */ + ipp_attribute_t *auth_info) /* I - auth-info attribute, if any */ { int i; /* Looping var */ char filename[1024]; /* Job authentication filename */ cups_file_t *fp; /* Job authentication file */ - char line[1024]; /* Line for file */ + char line[2048]; /* Line for file */ /* * This function saves the in-memory authentication information for * a job so that it can be used to authenticate with a remote host. * The information is stored in a file that is readable only by the - * root user. The username and password are Base-64 encoded, each - * on a separate line, followed by random number (up to 1024) of - * newlines to limit the amount of information that is exposed. + * root user. The fields are Base-64 encoded, each on a separate line, + * followed by random number (up to 1024) of newlines to limit the + * amount of information that is exposed. * * Because of the potential for exposing of authentication information, * this functionality is only enabled when running cupsd as root. @@ -7550,19 +7600,35 @@ save_auth_info(cupsd_client_t *con, /* I - Client connection */ fchown(cupsFileNumber(fp), 0, 0); fchmod(cupsFileNumber(fp), 0400); - /* - * Write the authenticated username... - */ + if (auth_info) + { + /* + * Write 1 to 4 auth values... + */ - httpEncode64_2(line, sizeof(line), con->username, strlen(con->username)); - cupsFilePrintf(fp, "%s\n", line); + for (i = 0; i < auth_info->num_values; i ++) + { + httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, + strlen(auth_info->values[i].string.text)); + cupsFilePrintf(fp, "%s\n", line); + } + } + else + { + /* + * Write the authenticated username... + */ - /* - * Write the authenticated password... - */ + httpEncode64_2(line, sizeof(line), con->username, strlen(con->username)); + cupsFilePrintf(fp, "%s\n", line); - httpEncode64_2(line, sizeof(line), con->password, strlen(con->password)); - cupsFilePrintf(fp, "%s\n", line); + /* + * Write the authenticated password... + */ + + httpEncode64_2(line, sizeof(line), con->password, strlen(con->password)); + cupsFilePrintf(fp, "%s\n", line); + } /* * Write a random number of newlines to the end of the file... @@ -7576,7 +7642,66 @@ save_auth_info(cupsd_client_t *con, /* I - Client connection */ */ cupsFileClose(fp); + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) + save_krb5_creds(con, job); +#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ +} + + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) +/* + * 'save_krb5_creds()' - Save Kerberos credentials for the job. + */ + +static void +save_krb5_creds(cupsd_client_t *con, /* I - Client connection */ + cupsd_job_t *job) /* I - Job */ +{ +# ifndef __APPLE__ + krb5_context krb_context; /* Kerberos context */ + krb5_ccache ccache; /* Credentials cache */ + OM_uint32 major_status, /* Major status code */ + minor_status; /* Minor status code */ + + + /* + * Setup a cached context for the job filters to use... + */ + + if (krb5_init_context(&krb_context)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context"); + return; + } + +# ifdef HAVE_HEIMDAL + if (krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache)) +# else + if (krb5_cc_gen_new(krb_context, &ccache)) +# endif /* HAVE_HEIMDAL */ + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create new credentials"); + return; + } + + major_status = gss_krb5_copy_ccache(&minor_status, con->gss_delegated_cred, + ccache); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status, + "Unable to import client credentials cache"); + krb5_cc_destroy(krb_context, ccache); + return; + } + + cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s", + krb5_cc_get_name(krb_context, ccache)); + krb5_cc_close(krb_context, ccache); +# endif /* !__APPLE__ */ } +#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ /* @@ -7589,6 +7714,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *format; /* Document-format attribute */ + const char *default_format;/* document-format-default value */ int jobid; /* Job ID number */ cupsd_job_t *job; /* Current job */ char job_uri[HTTP_MAX_URI], @@ -7747,6 +7873,22 @@ send_document(cupsd_client_t *con, /* I - Client connection */ return; } } + else if ((default_format = cupsGetOption("document-format", + printer->num_options, + printer->options)) != NULL) + { + /* + * Use default document format... + */ + + if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Could not scan type \"%s\"!"), + default_format); + return; + } + } else { /* @@ -7773,31 +7915,35 @@ send_document(cupsd_client_t *con, /* I - Client connection */ doc_name ? doc_name->values[0].string.text : NULL, &compression); - if (filetype) - { - /* - * Replace the document-format attribute value with the auto-typed one. - */ - - snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, - filetype->type); - - if (format) - { - _cupsStrFree(format->values[0].string.text); - format->values[0].string.text = _cupsStrAlloc(mimetype); - } - else - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, - "document-format", NULL, mimetype); - } - else + if (!filetype) filetype = mimeType(MimeDatabase, super, type); } else filetype = mimeType(MimeDatabase, super, type); - if (!filetype) + if (filetype && + (!format || + (!strcmp(super, "application") && !strcmp(type, "octet-stream")))) + { + /* + * Replace the document-format attribute value with the auto-typed or + * default one. + */ + + snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, + filetype->type); + + if (format) + { + _cupsStrFree(format->values[0].string.text); + + format->values[0].string.text = _cupsStrAlloc(mimetype); + } + else + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, + "document-format", NULL, mimetype); + } + else if (!filetype) { send_ipp_status(con, IPP_DOCUMENT_FORMAT, _("Unsupported format \'%s/%s\'!"), super, type); @@ -8035,16 +8181,6 @@ set_default(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method 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 */ - const char *name; /* Printer name */ cupsd_printer_t *printer; /* Printer */ @@ -8055,11 +8191,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -8092,8 +8224,8 @@ set_default(cupsd_client_t *con, /* I - Client connection */ cupsdWritePrintcap(); cupsdLogMessage(CUPSD_LOG_INFO, - "Default destination set to \"%s\" by \"%s\".", name, - get_username(con)); + "Default destination set to \"%s\" by \"%s\".", + printer->name, get_username(con)); /* * Everything was ok, so return OK status... @@ -8613,10 +8745,6 @@ set_printer_defaults( attr->values[0].string.text); cupsdSetString(&printer->error_policy, attr->values[0].string.text); } - else if (!strcmp(attr->name, "document-format-default") || - !strcmp(attr->name, "notify-lease-duration-default") || - !strcmp(attr->name, "notify-events-default")) - continue; /* * Skip any other non-default attributes... @@ -8717,16 +8845,6 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method 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 */ - const char *name; /* Printer name */ cupsd_printer_t *printer; /* Printer data */ @@ -8737,11 +8855,7 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -8771,11 +8885,11 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ cupsdStartPrinter(printer, 1); if (dtype & CUPS_PRINTER_CLASS) - cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".", name, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".", + printer->name, get_username(con)); else - cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".", name, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".", + printer->name, get_username(con)); cupsdCheckJobs(); @@ -8797,16 +8911,6 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method 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 */ - const char *name; /* Printer name */ cupsd_printer_t *printer; /* Printer data */ ipp_attribute_t *attr; /* printer-state-message attribute */ @@ -8818,11 +8922,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -8859,11 +8959,11 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ cupsdStopPrinter(printer, 1); if (dtype & CUPS_PRINTER_CLASS) - cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".", name, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".", + printer->name, get_username(con)); else - cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".", name, - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".", + printer->name, get_username(con)); /* * Everything was ok, so return OK status... @@ -8989,15 +9089,6 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *format; /* Document-format attribute */ cups_ptype_t dtype; /* Destination type (printer or class) */ - char method[HTTP_MAX_URI], - /* Method 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 */ char super[MIME_MAX_SUPER], /* Supertype of file */ type[MIME_MAX_TYPE]; @@ -9057,11 +9148,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if (cupsdValidateDest(host, resource, &dtype, &printer) == NULL) + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) { /* * Bad URI... @@ -9105,7 +9192,7 @@ validate_name(const char *name) /* I - Name to check */ */ for (ptr = name; *ptr; ptr ++) - if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') + if ((*ptr > 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') return (0); /* @@ -9161,5 +9248,5 @@ validate_user(cupsd_job_t *job, /* I - Job */ /* - * End of "$Id: ipp.c 6145 2006-12-06 20:10:16Z mike $". + * End of "$Id: ipp.c 6318 2007-03-06 04:36:55Z mike $". */ diff --git a/scheduler/job.c b/scheduler/job.c index f219c6980..3c876a649 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,9 +1,9 @@ /* - * "$Id: job.c 6234 2007-02-05 20:25:50Z mike $" + * "$Id: job.c 6318 2007-03-06 04:36:55Z mike $" * * Job management routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -127,6 +127,8 @@ cupsdAddJob(int priority, /* I - Job priority */ job->back_pipes[1] = -1; job->print_pipes[0] = -1; job->print_pipes[1] = -1; + job->side_pipes[0] = -1; + job->side_pipes[1] = -1; job->status_pipes[0] = -1; job->status_pipes[1] = -1; @@ -461,7 +463,6 @@ cupsdCleanJobs(void) void cupsdFinishJob(cupsd_job_t *job) /* I - Job */ { - int job_history; /* Did cupsdCancelJob() keep the job? */ cupsd_printer_t *printer; /* Current printer */ @@ -478,11 +479,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ * Close the pipe and clear the input bit. */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdFinishJob: Removing fd %d from InputSet...", - job->status_buffer->fd); - - FD_CLR(job->status_buffer->fd, InputSet); + cupsdRemoveSelect(job->status_buffer->fd); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: Closing status pipes [ %d %d ]...", @@ -711,8 +708,6 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ * Close out this job... */ - job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); - cupsdCancelJob(job, 0, IPP_JOB_COMPLETED); cupsdCheckJobs(); } @@ -921,13 +916,6 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ cups_file_t *fp; /* Job file */ int fileid; /* Current file ID */ ipp_attribute_t *attr; /* Job attribute */ - char scheme[32], /* Scheme portion of URI */ - username[64], /* Username portion of URI */ - host[HTTP_MAX_HOST], - /* Host portion of URI */ - resource[HTTP_MAX_URI]; - /* Resource portion of URI */ - int port; /* Port portion of URI */ const char *dest; /* Destination */ mime_type_t **filetypes; /* New filetypes array */ int *compressions; /* New compressions array */ @@ -1011,11 +999,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ return; } - httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, scheme, - sizeof(scheme), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if ((dest = cupsdValidateDest(host, resource, &(job->dtype), + if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype), NULL)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, @@ -1427,7 +1411,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ job->hold_until = curtime + ((17 - curdate->tm_hour) * 60 + 59 - curdate->tm_min) * 60 + 60 - curdate->tm_sec; - } + } else if (!strcmp(when, "second-shift")) { /* @@ -1443,7 +1427,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ job->hold_until = curtime + ((15 - curdate->tm_hour) * 60 + 59 - curdate->tm_min) * 60 + 60 - curdate->tm_sec; - } + } else if (!strcmp(when, "third-shift")) { /* @@ -1459,7 +1443,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ job->hold_until = curtime + ((23 - curdate->tm_hour) * 60 + 59 - curdate->tm_min) * 60 + 60 - curdate->tm_sec; - } + } else if (!strcmp(when, "weekend")) { /* @@ -1622,17 +1606,19 @@ cupsdStopJob(cupsd_job_t *job, /* I - Job */ cupsdClosePipe(job->back_pipes); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopJob: Closing side pipes [ %d %d ]...", + job->side_pipes[0], job->side_pipes[1]); + + cupsdClosePipe(job->side_pipes); + if (job->status_buffer) { /* * Close the pipe and clear the input bit. */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopJob: Removing fd %d from InputSet...", - job->status_buffer->fd); - - FD_CLR(job->status_buffer->fd, InputSet); + cupsdRemoveSelect(job->status_buffer->fd); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopJob: Closing status pipes [ %d %d ]...", @@ -1710,7 +1696,7 @@ cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */ } else if (!sscanf(message, "%*d%d", &copies)) copies = 1; - + job->sheets->values[0].integer += copies; if (job->printer->page_limit) @@ -1734,7 +1720,18 @@ cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */ * Set attribute(s)... */ - /**** TODO ****/ + int num_attrs; /* Number of attributes */ + cups_option_t *attrs; /* Attributes */ + const char *attr; /* Attribute */ + + + num_attrs = cupsParseOptions(message, 0, &attrs); + + if ((attr = cupsGetOption("auth-info-required", num_attrs, + attrs)) != NULL) + cupsdSetAuthInfoRequired(job->printer, attr, NULL); + + cupsFreeOptions(num_attrs, attrs); } #ifdef __APPLE__ else if (!strncmp(message, "recoverable:", 12)) @@ -1853,6 +1850,9 @@ free_job(cupsd_job_t *job) /* I - Job */ { cupsdClearString(&job->username); cupsdClearString(&job->dest); +#ifdef HAVE_GSSAPI + cupsdClearString(&job->ccname); +#endif /* HAVE_GSSAPI */ if (job->num_files > 0) { @@ -1867,7 +1867,7 @@ free_job(cupsd_job_t *job) /* I - Job */ /* - * 'ipp_length()' - Compute the size of the buffer needed to hold + * 'ipp_length()' - Compute the size of the buffer needed to hold * the textual IPP attributes. */ @@ -2082,6 +2082,8 @@ load_job_cache(const char *filename) /* I - job.cache filename */ job->back_pipes[1] = -1; job->print_pipes[0] = -1; job->print_pipes[1] = -1; + job->side_pipes[0] = -1; + job->side_pipes[1] = -1; job->status_pipes[0] = -1; job->status_pipes[1] = -1; @@ -2337,6 +2339,8 @@ load_request_root(void) job->back_pipes[1] = -1; job->print_pipes[0] = -1; job->print_pipes[1] = -1; + job->side_pipes[0] = -1; + job->side_pipes[1] = -1; job->status_pipes[0] = -1; job->status_pipes[1] = -1; @@ -2388,7 +2392,7 @@ set_time(cupsd_job_t *job, /* I - Job to update */ * 'set_hold_until()' - Set the hold time and update job-hold-until attribute... */ -static void +static void set_hold_until(cupsd_job_t *job, /* I - Job to update */ time_t holdtime) /* I - Hold until time */ { @@ -2414,7 +2418,7 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ */ holddate = gmtime(&holdtime); - snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour, + snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour, holddate->tm_min, holddate->tm_sec); if ((attr = ippFindAttribute(job->attrs, "job-hold-until", @@ -2445,8 +2449,10 @@ start_job(cupsd_job_t *job, /* I - Job ID */ { int i; /* Looping var */ int slot; /* Pipe slot */ - cups_array_t *filters; /* Filters for job */ + cups_array_t *filters, /* Filters for job */ + *prefilters; /* Filters with prefilters */ mime_filter_t *filter, /* Current filter */ + *prefilter, /* Prefilter */ port_monitor; /* Port monitor filter */ char method[255], /* Method for output */ *optptr, /* Pointer to options */ @@ -2466,7 +2472,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ title[IPP_MAX_NAME], /* Job title string */ copies[255], /* # copies string */ - *envp[MAX_ENV + 11], + *envp[MAX_ENV + 12], /* Environment variables */ charset[255], /* CHARSET env variable */ class_name[255],/* CLASS env variable */ @@ -2579,6 +2585,33 @@ start_job(cupsd_job_t *job, /* I - Job ID */ cupsArrayDelete(filters); filters = NULL; } + + /* + * If this printer has any pre-filters, insert the required pre-filter + * in the filters array... + */ + + if (printer->prefiltertype && filters) + { + prefilters = cupsArrayNew(NULL, NULL); + + for (filter = (mime_filter_t *)cupsArrayFirst(filters); + filter; + filter = (mime_filter_t *)cupsArrayNext(filters)) + { + if ((prefilter = mimeFilterLookup(MimeDatabase, filter->src, + printer->prefiltertype))) + { + cupsArrayAdd(prefilters, prefilter); + job->cost += prefilter->cost; + } + + cupsArrayAdd(prefilters, filter); + } + + cupsArrayDelete(filters); + filters = prefilters; + } } /* @@ -2707,6 +2740,18 @@ start_job(cupsd_job_t *job, /* I - Job ID */ fcntl(job->back_pipes[1], F_SETFL, fcntl(job->back_pipes[1], F_GETFL) | O_NONBLOCK); + + /* + * Create the side-channel pipes and make them non-blocking... + */ + + socketpair(AF_LOCAL, SOCK_STREAM, 0, job->side_pipes); + + fcntl(job->side_pipes[0], F_SETFL, + fcntl(job->side_pipes[0], F_GETFL) | O_NONBLOCK); + + fcntl(job->side_pipes[1], F_SETFL, + fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK); } /* @@ -3083,6 +3128,11 @@ start_job(cupsd_job_t *job, /* I - Job ID */ envp[envc ++] = class_name; } +#ifdef HAVE_GSSAPI + if (job->ccname) + envp[envc ++] = job->ccname; +#endif /* HAVE_GSSAPI */ + envp[envc] = NULL; for (i = 0; i < envc; i ++) @@ -3115,19 +3165,19 @@ start_job(cupsd_job_t *job, /* I - Job ID */ strerror(errno)); snprintf(printer->state_message, sizeof(printer->state_message), "Unable to create status pipes - %s.", strerror(errno)); - + cupsdAddPrinterHistory(printer); - + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, "Job canceled because the server could not create the job " "status pipes."); - + goto abort_job; } - + cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: status_pipes = [ %d %d ]", job->status_pipes[0], job->status_pipes[1]); - + job->status_buffer = cupsdStatBufNew(job->status_pipes[0], "[Job %d]", job->id); } @@ -3244,7 +3294,8 @@ 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], 0, job->filters + i); + job->back_pipes[0], job->side_pipes[0], 0, + job->filters + i); cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: Closing filter pipes for slot %d " @@ -3314,8 +3365,8 @@ 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], backroot, - &(job->backend)); + job->back_pipes[1], job->side_pipes[1], + backroot, &(job->backend)); if (pid == 0) { @@ -3354,6 +3405,12 @@ start_job(cupsd_job_t *job, /* I - Job ID */ cupsdClosePipe(job->back_pipes); cupsdLogMessage(CUPSD_LOG_DEBUG2, + "start_job: Closing side pipes [ %d %d ]...", + job->side_pipes[0], job->side_pipes[1]); + + cupsdClosePipe(job->side_pipes); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: Closing status output pipe %d...", job->status_pipes[1]); @@ -3397,11 +3454,8 @@ start_job(cupsd_job_t *job, /* I - Job ID */ free(argv); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "start_job: Adding fd %d to InputSet...", - job->status_buffer->fd); - - FD_SET(job->status_buffer->fd, InputSet); + cupsdAddSelect(job->status_buffer->fd, (cupsd_selfunc_t)cupsdUpdateJob, NULL, + job); cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.", job->id); @@ -3467,5 +3521,5 @@ unload_job(cupsd_job_t *job) /* I - Job */ /* - * End of "$Id: job.c 6234 2007-02-05 20:25:50Z mike $". + * End of "$Id: job.c 6318 2007-03-06 04:36:55Z mike $". */ diff --git a/scheduler/job.h b/scheduler/job.h index 5c1b540eb..4b8e399f1 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -1,5 +1,5 @@ /* - * "$Id: job.h 5970 2006-09-19 20:11:08Z mike $" + * "$Id: job.h 6170 2007-01-02 17:26:41Z mike $" * * Print job definitions for the Common UNIX Printing System (CUPS) scheduler. * @@ -46,6 +46,7 @@ typedef struct cupsd_job_s ipp_t *attrs; /* Job attributes */ int print_pipes[2], /* Print data pipes */ back_pipes[2], /* Backchannel pipes */ + side_pipes[2], /* Sidechannel pipes */ status_pipes[2];/* Status pipes */ cupsd_statbuf_t *status_buffer; /* Status buffer for this job */ int cost; /* Filtering cost */ @@ -55,6 +56,9 @@ typedef struct cupsd_job_s int status; /* Status code from filters */ cupsd_printer_t *printer; /* Printer this job is assigned to */ int tries; /* Number of tries for this job */ +#ifdef HAVE_GSSAPI + char *ccname; /* KRB5CCNAME environment variable */ +#endif /* HAVE_GSSAPI */ } cupsd_job_t; @@ -122,5 +126,5 @@ extern void cupsdUpdateJob(cupsd_job_t *job); /* - * End of "$Id: job.h 5970 2006-09-19 20:11:08Z mike $". + * End of "$Id: job.h 6170 2007-01-02 17:26:41Z mike $". */ diff --git a/scheduler/listen.c b/scheduler/listen.c index 2c5ad2bd7..258e292f7 100644 --- a/scheduler/listen.c +++ b/scheduler/listen.c @@ -1,5 +1,5 @@ /* - * "$Id: listen.c 5970 2006-09-19 20:11:08Z mike $" + * "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $" * * Server listening routines for the Common UNIX Printing System (CUPS) * scheduler. @@ -90,14 +90,7 @@ cupsdPauseListening(void) for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) - if (lis->fd >= 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdPauseListening: Removing fd %d from InputSet...", - lis->fd); - - FD_CLR(lis->fd, InputSet); - } + cupsdRemoveSelect(lis->fd); } @@ -123,13 +116,7 @@ cupsdResumeListening(void) for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) - if (lis->fd >= 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdResumeListening: Adding fd %d to InputSet...", - lis->fd); - FD_SET(lis->fd, InputSet); - } + cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis); } @@ -444,5 +431,5 @@ cupsdStopListening(void) /* - * End of "$Id: listen.c 5970 2006-09-19 20:11:08Z mike $". + * End of "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $". */ diff --git a/scheduler/log.c b/scheduler/log.c index 3839dc878..11c3cbcfe 100644 --- a/scheduler/log.c +++ b/scheduler/log.c @@ -1,5 +1,5 @@ /* - * "$Id: log.c 6027 2006-10-11 21:04:58Z mike $" + * "$Id: log.c 6328 2007-03-12 14:45:42Z mike $" * * Log file routines for the Common UNIX Printing System (CUPS). * @@ -23,11 +23,12 @@ * * Contents: * - * cupsdGetDateTime() - Returns a pointer to a date/time string. - * cupsdLogMessage() - Log a message to the error log file. - * cupsdLogPage() - Log a page to the page log file. - * cupsdLogRequest() - Log an HTTP request in Common Log Format. - * check_log_file() - Open/rotate a log file if it needs it. + * cupsdGetDateTime() - Returns a pointer to a date/time string. + * cupsdLogGSSMessage() - Log a GSSAPI error... + * cupsdLogMessage() - Log a message to the error log file. + * cupsdLogPage() - Log a page to the page log file. + * cupsdLogRequest() - Log an HTTP request in Common Log Format. + * check_log_file() - Open/rotate a log file if it needs it. */ /* @@ -107,6 +108,56 @@ cupsdGetDateTime(time_t t) /* I - Time value */ } +#ifdef HAVE_GSSAPI +/* + * 'cupsdLogGSSMessage()' - Log a GSSAPI error... + */ + +int /* O - 1 on success, 0 on error */ +cupsdLogGSSMessage( + int level, /* I - Log level */ + int major_status, /* I - Major GSSAPI status */ + int minor_status, /* I - Minor GSSAPI status */ + const char *message, /* I - printf-style message string */ + ...) /* I - Additional args as needed */ +{ + OM_uint32 err_major_status, /* Major status code for display */ + err_minor_status; /* Minor status code for display */ + OM_uint32 msg_ctx; /* Message context */ + gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER, + /* Major status message */ + minor_status_string = GSS_C_EMPTY_BUFFER; + /* Minor status message */ + int ret; /* Return value */ + + + msg_ctx = 0; + err_major_status = gss_display_status(&err_minor_status, + major_status, + GSS_C_GSS_CODE, + GSS_C_NO_OID, + &msg_ctx, + &major_status_string); + + if (!GSS_ERROR(err_major_status)) + err_major_status = gss_display_status(&err_minor_status, + minor_status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &minor_status_string); + + ret = cupsdLogMessage(level, "%s: %s, %s", message, + (char *)major_status_string.value, + (char *)minor_status_string.value); + gss_release_buffer(&err_minor_status, &major_status_string); + gss_release_buffer(&err_minor_status, &minor_status_string); + + return (ret); +} +#endif /* HAVE_GSSAPI */ + + /* * 'cupsdLogMessage()' - Log a message to the error log file. */ @@ -414,9 +465,10 @@ static int /* O - 1 if log file open */ check_log_file(cups_file_t **lf, /* IO - Log file */ const char *logname) /* I - Log filename */ { - char backname[1024], /* Backup log filename */ - filename[1024], /* Formatted log filename */ - *ptr; /* Pointer into filename */ + char backname[1024], /* Backup log filename */ + filename[1024], /* Formatted log filename */ + *ptr; /* Pointer into filename */ + const char *logptr; /* Pointer into log filename */ /* @@ -448,17 +500,17 @@ check_log_file(cups_file_t **lf, /* IO - Log file */ else filename[0] = '\0'; - for (ptr = filename + strlen(filename); - *logname && ptr < (filename + sizeof(filename) - 1); - logname ++) - if (*logname == '%') + for (logptr = logname, ptr = filename + strlen(filename); + *logptr && ptr < (filename + sizeof(filename) - 1); + logptr ++) + if (*logptr == '%') { /* * Format spec... */ - logname ++; - if (*logname == 's') + logptr ++; + if (*logptr == 's') { /* * Insert the server name... @@ -473,11 +525,11 @@ check_log_file(cups_file_t **lf, /* IO - Log file */ * Otherwise just insert the character... */ - *ptr++ = *logname; + *ptr++ = *logptr; } } else - *ptr++ = *logname; + *ptr++ = *logptr; *ptr = '\0'; } @@ -551,5 +603,5 @@ check_log_file(cups_file_t **lf, /* IO - Log file */ /* - * End of "$Id: log.c 6027 2006-10-11 21:04:58Z mike $". + * End of "$Id: log.c 6328 2007-03-12 14:45:42Z mike $". */ diff --git a/scheduler/main.c b/scheduler/main.c index 434cacf89..8591cc0f3 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -1,9 +1,9 @@ /* - * "$Id: main.c 6090 2006-11-14 16:35:27Z mike $" + * "$Id: main.c 6326 2007-03-11 17:50:18Z mike $" * * Scheduler main loop for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -32,10 +32,9 @@ * cupsdSetStringf() - Set a formatted string value. * launchd_checkin() - Check-in with launchd and collect the * listening fds. + * launchd_checkout() - Check-out with launchd. * launchd_create_dict() - Create a dictionary representing the launchd * config file org.cups.cupsd.plist. - * launchd_reload() - Tell launchd to reload the configuration - * file to pick up the new listening directives. * launchd_sync_conf() - Re-write the launchd config file * org.cups.cupsd.plist based on cupsd.conf. * parent_handler() - Catch USR1/CHLD signals... @@ -62,6 +61,17 @@ #ifdef HAVE_LAUNCH_H # include <launch.h> # include <libgen.h> +# define CUPS_KEEPALIVE CUPS_STATEDIR "/org.cups.cupsd" + /* Name of the launchd KeepAlive file */ +# ifndef LAUNCH_JOBKEY_KEEPALIVE +# define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive" +# endif /* !LAUNCH_JOBKEY_KEEPALIVE */ +# ifndef LAUNCH_JOBKEY_PATHSTATE +# define LAUNCH_JOBKEY_PATHSTATE "PathState" +# endif /* !LAUNCH_JOBKEY_PATHSTATE */ +# ifndef LAUNCH_JOBKEY_SERVICEIPC +# define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC" +# endif /* !LAUNCH_JOBKEY_SERVICEIPC */ #endif /* HAVE_LAUNCH_H */ #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) @@ -78,8 +88,8 @@ #ifdef HAVE_LAUNCHD static void launchd_checkin(void); +static void launchd_checkout(void); static CFDictionaryRef launchd_create_dict(void); -static void launchd_reload(void); static int launchd_sync_conf(void); #endif /* HAVE_LAUNCHD */ static void parent_handler(int sig); @@ -126,8 +136,6 @@ main(int argc, /* I - Number of command-line args */ char *opt; /* Option character */ int fg; /* Run in the foreground */ int fds; /* Number of ready descriptors */ - fd_set *input, /* Input set for select() */ - *output; /* Output set for select() */ cupsd_client_t *con; /* Current client */ cupsd_job_t *job; /* Current job */ cupsd_listener_t *lis; /* Current listener */ @@ -136,14 +144,11 @@ main(int argc, /* I - Number of command-line args */ browse_time, /* Next browse send time */ senddoc_time, /* Send-Document time */ expire_time, /* Subscription expire time */ -#ifndef __APPLE__ - netif_time, /* Network interface poll time */ -#endif /* !__APPLE__ */ mallinfo_time; /* Malloc information time */ size_t string_count, /* String count */ alloc_bytes, /* Allocated string bytes */ total_bytes; /* Total string bytes */ - struct timeval timeout; /* select() timeout */ + long timeout; /* Timeout for cupsdDoSelect() */ struct rlimit limit; /* Runtime limit */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ @@ -372,33 +377,23 @@ main(int argc, /* I - Number of command-line args */ getrlimit(RLIMIT_NOFILE, &limit); +#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE) if (limit.rlim_max > FD_SETSIZE) MaxFDs = FD_SETSIZE; else +#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */ +#ifdef RLIM_INFINITY + if (limit.rlim_max == RLIM_INFINITY) + MaxFDs = 16384; + else +#endif /* RLIM_INFINITY */ MaxFDs = limit.rlim_max; limit.rlim_cur = MaxFDs; setrlimit(RLIMIT_NOFILE, &limit); - /* - * Allocate memory for the input and output sets... - */ - - SetSize = (MaxFDs + 31) / 8 + 4; - if (SetSize < sizeof(fd_set)) - SetSize = sizeof(fd_set); - - InputSet = (fd_set *)calloc(1, SetSize); - OutputSet = (fd_set *)calloc(1, SetSize); - input = (fd_set *)calloc(1, SetSize); - output = (fd_set *)calloc(1, SetSize); - - if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL) - { - syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!"); - return (1); - } + cupsdStartSelect(); /* * Read configuration... @@ -415,22 +410,15 @@ main(int argc, /* I - Number of command-line args */ if (Launchd) { /* - * If we were started by launchd make sure the cupsd plist file contains the - * same listeners as cupsd.conf; If it didn't then reload it before getting - * the list of listening file descriptors... + * If we were started by launchd, make sure the cupsd plist file contains + * the same listeners as cupsd.conf. */ - if (launchd_sync_conf()) - { - launchd_reload(); - - /* - * Until rdar://3854821 is fixed we have to exit after the reload... - */ + launchd_sync_conf(); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "Exiting on launchd_reload"); - exit(0); - } + /* + * Then get the file descriptors from launchd... + */ launchd_checkin(); } @@ -551,9 +539,6 @@ main(int argc, /* I - Number of command-line args */ senddoc_time = time(NULL); expire_time = time(NULL); fds = 1; -#ifndef __APPLE__ - netif_time = 0; -#endif /* !__APPLE__ */ while (!stop_scheduler) { @@ -632,19 +617,7 @@ main(int argc, /* I - Number of command-line args */ #if HAVE_LAUNCHD if (Launchd) { - if (launchd_sync_conf()) - { - launchd_reload(); - - /* - * Until rdar://3854821 is fixed we have to exit after the reload... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "Exiting on launchd_reload"); - stop_scheduler = 1; - break; - } - + launchd_sync_conf(); launchd_checkin(); } #endif /* HAVE_LAUNCHD */ @@ -658,18 +631,15 @@ main(int argc, /* I - Number of command-line args */ } /* - * Check for available input or ready output. If select() returns - * 0 or -1, something bad happened and we should exit immediately. + * Check for available input or ready output. If cupsdDoSelect() + * returns 0 or -1, something bad happened and we should exit + * immediately. * * Note that we at least have one listening socket open at all * times. */ - memcpy(input, InputSet, SetSize); - memcpy(output, OutputSet, SetSize); - - timeout.tv_sec = select_timeout(fds); - timeout.tv_usec = 0; + timeout = select_timeout(fds); #if HAVE_LAUNCHD /* @@ -678,71 +648,40 @@ main(int argc, /* I - Number of command-line args */ * inactivity... */ - if (timeout.tv_sec == 86400 && Launchd && LaunchdTimeout && !NumPolled && - (!Browsing || !(BrowseLocalProtocols & BROWSE_DNSSD) || - cupsArrayCount(Printers) == 0)) + if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled && + (!Browsing || + (!BrowseRemoteProtocols && + (!NumBrowsers || !BrowseLocalProtocols || + cupsArrayCount(Printers) == 0)))) { - timeout.tv_sec = LaunchdTimeout; + timeout = LaunchdTimeout; launchd_idle_exit = 1; } else launchd_idle_exit = 0; #endif /* HAVE_LAUNCHD */ - if (timeout.tv_sec < 86400) /* Only use timeout for < 1 day */ - fds = select(MaxFDs, input, output, NULL, &timeout); - else - fds = select(MaxFDs, input, output, NULL, NULL); - - if (fds < 0) + if ((fds = cupsdDoSelect(timeout)) < 0) { - char s[16384], /* String buffer */ - *sptr; /* Pointer into buffer */ - int slen; /* Length of string buffer */ - - /* * Got an error from select! */ - if (errno == EINTR) /* Just interrupted by a signal */ +#ifdef HAVE_DNSSD + cupsd_printer_t *p; /* Current printer */ +#endif /* HAVE_DNSSD */ + + + if (errno == EINTR) /* Just interrupted by a signal */ continue; /* * Log all sorts of debug info to help track down the problem. */ - cupsdLogMessage(CUPSD_LOG_EMERG, "select() failed - %s!", + cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!", strerror(errno)); - strcpy(s, "InputSet ="); - slen = 10; - sptr = s + 10; - - for (i = 0; i < MaxFDs; i ++) - if (FD_ISSET(i, InputSet)) - { - snprintf(sptr, sizeof(s) - slen, " %d", i); - slen += strlen(sptr); - sptr += strlen(sptr); - } - - cupsdLogMessage(CUPSD_LOG_EMERG, "%s", s); - - strcpy(s, "OutputSet ="); - slen = 11; - sptr = s + 11; - - for (i = 0; i < MaxFDs; i ++) - if (FD_ISSET(i, OutputSet)) - { - snprintf(sptr, sizeof(s) - slen, " %d", i); - slen += strlen(sptr); - sptr += strlen(sptr); - } - - cupsdLogMessage(CUPSD_LOG_EMERG, "%s", s); - for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients); con; i ++, con = (cupsd_client_t *)cupsArrayNext(Clients)) @@ -772,6 +711,15 @@ main(int argc, /* I - Number of command-line args */ job->status_buffer ? job->status_buffer->fd : -1, job->print_pipes[0], job->print_pipes[1], job->back_pipes[0], job->back_pipes[1]); + +#ifdef HAVE_DNSSD + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] %d", p->name, + p->dnssd_ipp_fd); +#endif /* HAVE_DNSSD */ + break; } @@ -794,67 +742,6 @@ main(int argc, /* I - Number of command-line args */ #endif /* HAVE_LAUNCHD */ /* - * Check for status info from job filters... - */ - - for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); - job; - job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (job->status_buffer && FD_ISSET(job->status_buffer->fd, input)) - { - /* - * Clear the input bit to avoid updating the next job - * using the same status pipe file descriptor... - */ - - FD_CLR(job->status_buffer->fd, input); - - /* - * Read any status messages from the filters... - */ - - cupsdUpdateJob(job); - } - - /* - * Update CGI messages as needed... - */ - - if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input)) - cupsdUpdateCGI(); - - /* - * Handle system management events as needed... - */ - -#ifdef __APPLE__ - /* - * Mac OS X provides the SystemConfiguration framework for system - * configuration change events... - */ - - if (SysEventPipes[0] >= 0 && FD_ISSET(SysEventPipes[0], input)) - cupsdUpdateSystemMonitor(); -#else - /* - * All other operating systems need to poll for changes... - */ - - if ((current_time - netif_time) >= 60) - { - NetIFUpdate = 1; - netif_time = current_time; - } -#endif /* __APPLE__ */ - - /* - * Update notifier messages as needed... - */ - - if (NotifierPipes[0] >= 0 && FD_ISSET(NotifierPipes[0], input)) - cupsdUpdateNotifierStatus(); - - /* * Expire subscriptions and unload completed jobs as needed... */ @@ -872,14 +759,8 @@ main(int argc, /* I - Number of command-line args */ * Update the browse list as needed... */ - if (Browsing && BrowseRemoteProtocols) + if (Browsing) { - if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input)) - cupsdUpdateCUPSBrowse(); - - if (PollPipe >= 0 && FD_ISSET(PollPipe, input)) - cupsdUpdatePolling(); - #ifdef HAVE_LIBSLP if ((BrowseRemoteProtocols & BROWSE_SLP) && BrowseSLPRefresh <= current_time) @@ -900,17 +781,20 @@ main(int argc, /* I - Number of command-line args */ } /* - * Check for new connections on the "listen" sockets... + * Update the root certificate once every 5 minutes if we have client + * connections... */ - for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); - lis; - lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) - if (lis->fd >= 0 && FD_ISSET(lis->fd, input)) - { - FD_CLR(lis->fd, input); - cupsdAcceptClient(lis); - } + if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration && + !RunUser && cupsArrayCount(Clients)) + { + /* + * Update the root certificate... + */ + + cupsdDeleteCert(0); + cupsdAddCert(0, "root"); + } /* * Check for new data on the client sockets... @@ -921,61 +805,13 @@ main(int argc, /* I - Number of command-line args */ con = (cupsd_client_t *)cupsArrayNext(Clients)) { /* - * Process the input buffer... - */ - - if (FD_ISSET(con->http.fd, input) || con->http.used) - { - int fd = con->file; - - - FD_CLR(con->http.fd, input); - - if (!cupsdReadClient(con)) - { - if (fd >= 0) - FD_CLR(fd, input); - - continue; - } - } - - /* - * Write data as needed... + * Process pending data in the input buffer... */ - if (con->pipe_pid && FD_ISSET(con->file, input)) - { - /* - * Keep track of pending input from the file/pipe separately - * so that we don't needlessly spin on select() when the web - * client is not ready to receive data... - */ - - FD_CLR(con->file, input); - con->file_ready = 1; - -#ifdef DEBUG - cupsdLogMessage(CUPSD_LOG_DEBUG2, "main: Data ready file %d!", - con->file); -#endif /* DEBUG */ - - if (!FD_ISSET(con->http.fd, output)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "main: Removing fd %d from InputSet...", con->file); - FD_CLR(con->file, input); - FD_CLR(con->file, InputSet); - } - } - - if (FD_ISSET(con->http.fd, output)) + if (con->http.used) { - FD_CLR(con->http.fd, output); - - if (!con->pipe_pid || con->file_ready) - if (!cupsdWriteClient(con)) - continue; + cupsdReadClient(con); + continue; } /* @@ -1032,22 +868,6 @@ main(int argc, /* I - Number of command-line args */ } /* - * Update the root certificate once every 5 minutes if we have client - * connections... - */ - - if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration && - !RunUser && cupsArrayCount(Clients)) - { - /* - * Update the root certificate... - */ - - cupsdDeleteCert(0); - cupsdAddCert(0, "root"); - } - - /* * Handle OS-specific event notification for any events that have * accumulated. Don't send these more than once a second... */ @@ -1114,13 +934,17 @@ main(int argc, /* I - Number of command-line args */ * Update the launchd config file as needed... */ - launchd_sync_conf(); + if (Launchd) + { + launchd_checkout(); + launchd_sync_conf(); - if (launchd_conf_url) - CFRelease(launchd_conf_url); + if (launchd_conf_url) + CFRelease(launchd_conf_url); - if (launchd_conf_dict) - CFRelease(launchd_conf_dict); + if (launchd_conf_dict) + CFRelease(launchd_conf_dict); + } #endif /* HAVE_LAUNCHD */ #ifdef __sgi @@ -1135,14 +959,7 @@ main(int argc, /* I - Number of command-line args */ unlink("/var/spool/lp/SCHEDLOCK"); #endif /* __sgi */ - /* - * Free memory used by FD sets and return... - */ - - free(InputSet); - free(OutputSet); - free(input); - free(output); + cupsdStopSelect(); return (!stop_scheduler); } @@ -1364,6 +1181,8 @@ launchd_checkin(void) cupsd_listener_t *lis; /* Listeners array */ http_addr_t addr; /* Address variable */ socklen_t addrlen; /* Length of address */ + int fd; /* File descriptor */ + char s[256]; /* String addresss */ cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid()); @@ -1417,56 +1236,77 @@ launchd_checkin(void) if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY) { - /* - * Free the listeners array built from cupsd.conf... - */ - - cupsdDeleteAllListeners(); - - /* - * Create a new array of listeners from the launchd data... - */ - - Listeners = cupsArrayNew(NULL, NULL); - count = launch_data_array_get_count(ld_array); + count = launch_data_array_get_count(ld_array); for (i = 0; i < count; i ++) { /* - * Copy the current address and log it... + * Get the launchd file descriptor and address... */ - if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL) + tmp = launch_data_array_get_index(ld_array, i); + fd = launch_data_get_fd(tmp); + addrlen = sizeof(addr); + + if (getsockname(fd, (struct sockaddr *)&addr, &addrlen)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "launchd_checkin: Unable to allocate listener - %s.", - strerror(errno)); - exit(EXIT_FAILURE); + "launchd_checkin: Unable to get local address - %s", + strerror(errno)); + continue; } - cupsArrayAdd(Listeners, lis); + /* + * Try to match the launchd socket address to one of the listeners... + */ - tmp = launch_data_array_get_index(ld_array, i); - lis->fd = launch_data_get_fd(tmp); - addrlen = sizeof(lis->address); + for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); + lis; + lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) + if (httpAddrEqual(&lis->address, &addr)) + break; + + /* + * Add a new listener If there's no match... + */ - if (getsockname(lis->fd, (struct sockaddr *)&(lis->address), &addrlen)) + if (lis) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "launchd_checkin: Unable to get local address - %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "launchd_checkin: Matched existing listener %s with fd %d...", + httpAddrString(&(lis->address), s, sizeof(s)), fd); + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "launchd_checkin: Adding new listener %s with fd %d...", + httpAddrString(&addr, s, sizeof(s)), fd); + + if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "launchd_checkin: Unable to allocate listener - %s.", + strerror(errno)); + exit(EXIT_FAILURE); + } + + cupsArrayAdd(Listeners, lis); + + memcpy(&lis->address, &addr, sizeof(lis->address)); } + lis->fd = fd; + # ifdef HAVE_SSL portnum = 0; # ifdef AF_INET6 - if (addr.addr.sa_family == AF_INET6) - portnum = ntohs(addr.ipv6.sin6_port); + if (lis->address.addr.sa_family == AF_INET6) + portnum = ntohs(lis->address.ipv6.sin6_port); else # endif /* AF_INET6 */ - if (addr.addr.sa_family == AF_INET) - portnum = ntohs(addr.ipv4.sin_port); + if (lis->address.addr.sa_family == AF_INET) + portnum = ntohs(lis->address.ipv4.sin_port); if (portnum == 443) lis->encryption = HTTP_ENCRYPT_ALWAYS; @@ -1512,6 +1352,43 @@ launchd_checkin(void) /* + * 'launchd_checkout()' - Update the launchd KeepAlive file as needed. + */ + +static void +launchd_checkout(void) +{ + int fd; /* File descriptor */ + + + /* + * Create or remove the launchd KeepAlive file based on whether + * there are active jobs, polling, browsing for remote printers or + * shared printers to advertise... + */ + + if ((cupsArrayCount(ActiveJobs) || NumPolled || + (Browsing && + (BrowseRemoteProtocols || + (BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers)))))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"..."); + + if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0) + close(fd); + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"..."); + + unlink(CUPS_KEEPALIVE); + } +} + + +/* * 'launchd_create_dict()' - Create a dictionary representing the launchd * config file org.cups.cupsd.plist. */ @@ -1519,24 +1396,26 @@ launchd_checkin(void) static CFDictionaryRef /* O - CFDictionary */ launchd_create_dict(void) { - int portnum; /* Port number */ - bool runatload; /* Run at load? */ - CFMutableDictionaryRef cupsd_dict, /* org.cups.cupsd.plist dictionary */ - sockets, /* Sockets dictionary */ - listener; /* Listener dictionary */ - CFMutableArrayRef array; /* Array */ - CFNumberRef socket_mode; /* Domain socket mode bits */ - CFStringRef socket_path; /* Domain socket path */ - CFTypeRef value; /* CF values */ - cupsd_listener_t *lis; /* Current listening socket */ - struct servent *service; /* Services data base entry */ - char temp[1024]; /* Temporary buffer for value */ + int portnum; /* Port number */ + bool runatload; /* Run at load? */ + CFMutableDictionaryRef cupsd_dict, /* org.cups.cupsd.plist dictionary */ + keepalive, /* KeepAlive dictionary */ + pathstate, /* PathState dictionary */ + sockets, /* Sockets dictionary */ + listener; /* Listener dictionary */ + CFMutableArrayRef array; /* Array */ + CFNumberRef socket_mode; /* Domain socket mode bits */ + CFStringRef socket_path; /* Domain socket path */ + CFTypeRef value; /* CF values */ + cupsd_listener_t *lis; /* Current listening socket */ + struct servent *service; /* Services data base entry */ + char temp[1024]; /* Temporary buffer for value */ if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL) - return NULL; + return (NULL); CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL), CFSTR("org.cups.cupsd")); @@ -1544,20 +1423,35 @@ launchd_create_dict(void) kCFBooleanTrue); /* - * Run-at-load if there are active jobs, polling or shared printers - * to advertise... + * Use run-at-load and/or KeepAlive if there are active jobs, polling or + * shared printers to advertise... */ - + + if ((keepalive = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)) != NULL) + { + if ((pathstate = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)) != NULL) + { + CFDictionaryAddValue(pathstate, CFSTR(CUPS_KEEPALIVE), kCFBooleanTrue); + CFDictionaryAddValue(keepalive, CFSTR(LAUNCH_JOBKEY_PATHSTATE), + pathstate); + } + + CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_KEEPALIVE), + keepalive); + } + runatload = (cupsArrayCount(ActiveJobs) || NumPolled || (Browsing && BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))) ? true : false; CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD), runatload ? kCFBooleanTrue : kCFBooleanFalse); -# ifdef LAUNCH_JOBKEY_SERVICEIPC CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC), kCFBooleanTrue); -# endif /* LAUNCH_JOBKEY_SERVICEIPC */ if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks)) != NULL) @@ -1728,106 +1622,6 @@ launchd_create_dict(void) /* - * 'launchd_reload()' - Tell launchd to reload the configuration file to pick - * up the new listening directives. - */ - -static void -launchd_reload(void) -{ - int child_status; /* Exit status of child process */ - pid_t child_pid, /* Child PID */ - waitpid_status; /* Child process exit status */ - char *argv[4]; /* Argument strings */ - - - /* - * The current launchd doesn't support a reload option (rdar://3854821). - * Until this is fixed we need to reload the config file by execing launchctl - * twice (to unload then load). NOTE: This will cause us to exit on SIGTERM - * which will cancel all client & job activity. - * - * After this is fixed we'll be able to tell launchd to reload the file - * and pick up the new listening descriptors without disrupting current - * activity. - */ - - /* - * Unloading the current configuration will cause launchd to send us a SIGTERM; - * block it for now so we can get our work done... - */ - - cupsdHoldSignals(); - - /* - * Set up the unload arguments to launchctl... - */ - - argv[0] = "/bin/launchctl"; - argv[1] = "unload"; - argv[2] = LaunchdConf; - argv[3] = NULL; - - if (cupsdStartProcess(argv[0], argv, NULL, -1, -1, -1, -1, 1, &child_pid) < 0) - cupsdLogMessage(CUPSD_LOG_ERROR, - "launchd_reload: Unable to execute %s - %s", argv[0], - strerror(errno)); - else - { - do - { - waitpid_status = waitpid(child_pid, &child_status, 0); - } - while (waitpid_status == (pid_t)-1 && errno == EINTR); - - if (WIFSIGNALED(child_status)) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_reload: %s pid %d crashed on signal %d!", - basename(argv[0]), child_pid, WTERMSIG(child_status)); - else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_reload: %s pid %d stopped with status %d!", - basename(argv[0]), child_pid, WEXITSTATUS(child_status)); - - /* - * Do it again with the load command... - */ - - argv[1] = "load"; - - if (cupsdStartProcess(argv[0], argv, NULL, -1, -1, -1, -1, 1, - &child_pid) < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "launchd_reload: Unable to fork for %s - %s", argv[0], - strerror(errno)); - } - else - { - do - { - waitpid_status = waitpid(child_pid, &child_status, 0); - } while (waitpid_status == (pid_t)-1 && errno == EINTR); - - if (WIFSIGNALED(child_status)) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_reload: %s pid %d crashed on signal %d!", - basename(argv[0]), child_pid, WTERMSIG(child_status)); - else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_reload: %s pid %d stopped with status %d", - basename(argv[0]), child_pid, - WEXITSTATUS(child_status)); - } - } - - /* - * Leave signals blocked since exit() will be called momentarily anyways... - */ -} - - -/* * 'launchd_sync_conf()' - Rewrite the launchd config file * org.cups.cupsd.plist based on cupsd.conf. */ @@ -1890,7 +1684,7 @@ launchd_sync_conf(void) if (!CFEqual(cupsd_dict, launchd_conf_dict)) { if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, - cupsd_dict))) + cupsd_dict))) { if (CFURLWriteDataAndPropertiesToResource(launchd_conf_url, resourceData, NULL, &errorCode)) @@ -2174,12 +1968,12 @@ select_timeout(int fds) /* I - Number of descriptors returned */ return (0); /* - * If select has been active in the last second (fds != 0) or we have + * If select has been active in the last second (fds > 0) or we have * many resources in use then don't bother trying to optimize the * timeout, just make it 1 second. */ - if (fds || cupsArrayCount(Clients) > 50) + if (fds > 0 || cupsArrayCount(Clients) > 50) return (1); /* @@ -2225,7 +2019,7 @@ select_timeout(int fds) /* I - Number of descriptors returned */ } #endif /* HAVE_LDAP */ - if (BrowseLocalProtocols & BROWSE_CUPS) + if ((BrowseLocalProtocols & BROWSE_CUPS) && NumBrowsers) { for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; @@ -2239,7 +2033,7 @@ select_timeout(int fds) /* I - Number of descriptors returned */ why = "browse timeout a printer"; } } - else if (!(p->type & CUPS_PRINTER_IMPLICIT)) + else if (p->shared && !(p->type & CUPS_PRINTER_IMPLICIT)) { if (BrowseInterval && (p->browse_time + BrowseInterval) < timeout) { @@ -2313,8 +2107,8 @@ select_timeout(int fds) /* I - Number of descriptors returned */ * Log and return the timeout value... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: %ld seconds to %s", - timeout, why); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s", + fds, timeout, why); return (timeout); } @@ -2340,5 +2134,5 @@ usage(int status) /* O - Exit status */ /* - * End of "$Id: main.c 6090 2006-11-14 16:35:27Z mike $". + * End of "$Id: main.c 6326 2007-03-11 17:50:18Z mike $". */ diff --git a/scheduler/mime.c b/scheduler/mime.c index 2e98d0b3f..052b42922 100644 --- a/scheduler/mime.c +++ b/scheduler/mime.c @@ -1,5 +1,5 @@ /* - * "$Id: mime.c 5606 2006-05-30 19:40:34Z mike $" + * "$Id: mime.c 5605 2006-05-30 19:38:02Z mike $" * * MIME database file routines for the Common UNIX Printing System (CUPS). * @@ -738,5 +738,5 @@ load_types(mime_t *mime, /* I - MIME database */ /* - * End of "$Id: mime.c 5606 2006-05-30 19:40:34Z mike $". + * End of "$Id: mime.c 5605 2006-05-30 19:38:02Z mike $". */ diff --git a/scheduler/mime.h b/scheduler/mime.h index 2b44bf121..16e9a3d7c 100644 --- a/scheduler/mime.h +++ b/scheduler/mime.h @@ -1,9 +1,9 @@ /* - * "$Id: mime.h 5771 2006-07-20 18:06:20Z mike $" + * "$Id: mime.h 6252 2007-02-10 15:34:18Z mike $" * * MIME type/conversion database definitions for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -143,6 +143,8 @@ extern mime_filter_t *mimeAddFilter(mime_t *mime, mime_type_t *src, extern void mimeDeleteFilter(mime_t *mime, mime_filter_t *filter); extern cups_array_t *mimeFilter(mime_t *mime, mime_type_t *src, mime_type_t *dst, int *cost); +extern mime_filter_t *mimeFilterLookup(mime_t *mime, mime_type_t *src, + mime_type_t *dst); extern mime_filter_t *mimeFirstFilter(mime_t *mime); extern mime_filter_t *mimeNextFilter(mime_t *mime); extern int mimeNumFilters(mime_t *mime); @@ -153,5 +155,5 @@ extern int mimeNumFilters(mime_t *mime); #endif /* !_CUPS_MIME_H_ */ /* - * End of "$Id: mime.h 5771 2006-07-20 18:06:20Z mike $". + * End of "$Id: mime.h 6252 2007-02-10 15:34:18Z mike $". */ diff --git a/scheduler/network.c b/scheduler/network.c index e63d4f44e..b7057d7b4 100644 --- a/scheduler/network.c +++ b/scheduler/network.c @@ -1,5 +1,5 @@ /* - * "$Id: network.c 6090 2006-11-14 16:35:27Z mike $" + * "$Id: network.c 6086 2006-11-14 15:43:55Z mike $" * * Network interface functions for the Common UNIX Printing System * (CUPS) scheduler. @@ -314,5 +314,5 @@ compare_netif(cupsd_netif_t *a, /* I - First network interface */ /* - * End of "$Id: network.c 6090 2006-11-14 16:35:27Z mike $". + * End of "$Id: network.c 6086 2006-11-14 15:43:55Z mike $". */ diff --git a/scheduler/network.h b/scheduler/network.h index 5d8c83f8a..c26e8dbb2 100644 --- a/scheduler/network.h +++ b/scheduler/network.h @@ -1,5 +1,5 @@ /* - * "$Id: network.h 6090 2006-11-14 16:35:27Z mike $" + * "$Id: network.h 6086 2006-11-14 15:43:55Z mike $" * * Network interface definitions for the Common UNIX Printing System * (CUPS) scheduler. @@ -57,5 +57,5 @@ extern void cupsdNetIFUpdate(void); /* - * End of "$Id: network.h 6090 2006-11-14 16:35:27Z mike $". + * End of "$Id: network.h 6086 2006-11-14 15:43:55Z mike $". */ diff --git a/scheduler/policy.c b/scheduler/policy.c index 606978e3e..668bbff6f 100644 --- a/scheduler/policy.c +++ b/scheduler/policy.c @@ -1,5 +1,5 @@ /* - * "$Id: policy.c 5838 2006-08-17 14:41:42Z mike $" + * "$Id: policy.c 5837 2006-08-17 14:37:40Z mike $" * * Policy routines for the Common UNIX Printing System (CUPS). * @@ -330,5 +330,5 @@ cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */ /* - * End of "$Id: policy.c 5838 2006-08-17 14:41:42Z mike $". + * End of "$Id: policy.c 5837 2006-08-17 14:37:40Z mike $". */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 936c9d0be..9a33a2221 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,9 +1,9 @@ /* - * "$Id: printers.c 5970 2006-09-19 20:11:08Z mike $" + * "$Id: printers.c 6318 2007-03-06 04:36:55Z mike $" * * Printer routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -70,7 +70,8 @@ */ static void add_printer_defaults(cupsd_printer_t *p); -static void add_printer_filter(cupsd_printer_t *p, const char *filter); +static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type, + const char *filter); static void add_printer_formats(cupsd_printer_t *p); static int compare_printers(void *first, void *second, void *data); static void delete_printer_filters(cupsd_printer_t *p); @@ -412,10 +413,6 @@ cupsdCreateCommonData(void) /* copies-supported */ ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies); - /* document-format-default */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, - "document-format-default", NULL, "application/octet-stream"); - /* generated-natural-language-supported */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "generated-natural-language-supported", NULL, DefaultLanguage); @@ -495,10 +492,6 @@ cupsdCreateCommonData(void) (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])), NULL, notify_attrs); - /* notify-lease-duration-default */ - ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "notify-lease-duration-default", DefaultLeaseDuration); - /* notify-lease-duration-supported */ ippAddRange(CommonData, IPP_TAG_PRINTER, "notify-lease-duration-supported", 0, @@ -508,10 +501,6 @@ cupsdCreateCommonData(void) ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "notify-max-events-supported", MaxEvents); - /* notify-events-default */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "notify-events-default", NULL, "job-completed"); - /* notify-events-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "notify-events-supported", @@ -703,13 +692,18 @@ cupsdDeletePrinter( } /* - * Remove this printer from any classes and send a browse delete message... + * Remove this printer from any classes... */ if (!(p->type & CUPS_PRINTER_IMPLICIT)) { cupsdDeletePrinterFromClasses(p); - cupsdSendBrowseDelete(p); + + /* + * Deregister from any browse protocols... + */ + + cupsdDeregisterPrinter(p, 1); } /* @@ -735,6 +729,7 @@ cupsdDeletePrinter( delete_printer_filters(p); mimeDeleteType(MimeDatabase, p->filetype); + mimeDeleteType(MimeDatabase, p->prefiltertype); cupsdFreePrinterUsers(p); cupsdFreeQuotas(p); @@ -752,6 +747,11 @@ cupsdDeletePrinter( cupsdClearString(&p->op_policy); cupsdClearString(&p->error_policy); +#ifdef HAVE_DNSSD + cupsdClearString(&p->product); + cupsdClearString(&p->pdl); +#endif /* HAVE_DNSSD */ + cupsArrayDelete(p->filetypes); if (p->browse_attrs) @@ -954,6 +954,13 @@ cupsdLoadAllPrinters(void) "Syntax error on line %d of printers.conf.", linenum); return; } + else if (!strcasecmp(line, "AuthInfoRequired")) + { + if (!cupsdSetAuthInfoRequired(p, value, NULL)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad AuthInfoRequired on line %d of printers.conf.", + linenum); + } else if (!strcasecmp(line, "Info")) { if (value) @@ -1247,6 +1254,9 @@ cupsdRenamePrinter( mimeDeleteType(MimeDatabase, p->filetype); p->filetype = mimeAddType(MimeDatabase, "printer", name); + mimeDeleteType(MimeDatabase, p->prefiltertype); + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name); + /* * Rename the printer... */ @@ -1286,6 +1296,7 @@ cupsdSaveAllPrinters(void) time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ cups_option_t *option; /* Current option */ + const char *ptr; /* Pointer into info/location */ /* @@ -1359,12 +1370,49 @@ cupsdSaveAllPrinters(void) else cupsFilePrintf(fp, "<Printer %s>\n", printer->name); + if (printer->num_auth_info_required > 0) + { + cupsFilePrintf(fp, "AuthInfoRequired %s", printer->auth_info_required[0]); + for (i = 1; i < printer->num_auth_info_required; i ++) + cupsFilePrintf(fp, ",%s", printer->auth_info_required[i]); + cupsFilePutChar(fp, '\n'); + } + if (printer->info) - cupsFilePrintf(fp, "Info %s\n", printer->info); + { + if ((ptr = strchr(printer->info, '#')) != NULL) + { + /* + * Need to quote the first # in the info string... + */ + + cupsFilePuts(fp, "Info "); + cupsFileWrite(fp, printer->info, ptr - printer->info); + cupsFilePutChar(fp, '\\'); + cupsFilePuts(fp, ptr); + cupsFilePutChar(fp, '\n'); + } + else + cupsFilePrintf(fp, "Info %s\n", printer->info); + } if (printer->location) - cupsFilePrintf(fp, "Location %s\n", printer->location); + { + if ((ptr = strchr(printer->info, '#')) != NULL) + { + /* + * Need to quote the first # in the location string... + */ + cupsFilePuts(fp, "Location "); + cupsFileWrite(fp, printer->location, ptr - printer->location); + cupsFilePutChar(fp, '\\'); + cupsFilePuts(fp, ptr); + cupsFilePutChar(fp, '\n'); + } + else + cupsFilePrintf(fp, "Location %s\n", printer->location); + } if (printer->device_uri) cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri); @@ -1428,6 +1476,119 @@ cupsdSaveAllPrinters(void) /* + * 'cupsdSetAuthInfoRequired()' - Set the required authentication info. + */ + +int /* O - 1 if value OK, 0 otherwise */ +cupsdSetAuthInfoRequired( + cupsd_printer_t *p, /* I - Printer */ + const char *values, /* I - Plain text value (or NULL) */ + ipp_attribute_t *attr) /* I - IPP attribute value (or NULL) */ +{ + int i; /* Looping var */ + + + p->num_auth_info_required = 0; + + /* + * Do we have a plain text value? + */ + + if (values) + { + /* + * Yes, grab the keywords... + */ + + const char *end; /* End of current value */ + + + while (*values && p->num_auth_info_required < 4) + { + if ((end = strchr(values, ',')) == NULL) + end = values + strlen(values); + + if (!strncmp(values, "none", end - values)) + { + if (p->num_auth_info_required != 0 || *end) + return (0); + + p->auth_info_required[p->num_auth_info_required] = "none"; + p->num_auth_info_required ++; + + return (1); + } + else if (!strncmp(values, "domain", end - values)) + { + p->auth_info_required[p->num_auth_info_required] = "domain"; + p->num_auth_info_required ++; + } + else if (!strncmp(values, "password", end - values)) + { + p->auth_info_required[p->num_auth_info_required] = "password"; + p->num_auth_info_required ++; + } + else if (!strncmp(values, "username", end - values)) + { + p->auth_info_required[p->num_auth_info_required] = "username"; + p->num_auth_info_required ++; + } + else + return (0); + } + + if (p->num_auth_info_required == 0) + { + p->auth_info_required[0] = "none"; + p->num_auth_info_required = 1; + } + + return (1); + } + + /* + * Grab values from an attribute instead... + */ + + if (!attr || attr->num_values > 4) + return (0); + + for (i = 0; i < attr->num_values; i ++) + { + if (!strcmp(attr->values[i].string.text, "none")) + { + if (p->num_auth_info_required != 0 || attr->num_values != 1) + return (0); + + p->auth_info_required[p->num_auth_info_required] = "none"; + p->num_auth_info_required ++; + + return (1); + } + else if (!strcmp(attr->values[i].string.text, "domain")) + { + p->auth_info_required[p->num_auth_info_required] = "domain"; + p->num_auth_info_required ++; + } + else if (!strcmp(attr->values[i].string.text, "password")) + { + p->auth_info_required[p->num_auth_info_required] = "password"; + p->num_auth_info_required ++; + } + else if (!strcmp(attr->values[i].string.text, "username")) + { + p->auth_info_required[p->num_auth_info_required] = "username"; + p->num_auth_info_required ++; + } + else + return (0); + } + + return (1); +} + + +/* * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file. */ @@ -1552,6 +1713,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ "job-k-limit", p->k_limit); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-page-limit", p->page_limit); + if (p->num_auth_info_required) + ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "auth-info-required", p->num_auth_info_required, + NULL, p->auth_info_required); + else + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "auth-info-required", NULL, "none"); if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_REMOTE)) { @@ -1880,7 +2048,20 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ * handle "raw" printing by users. */ - add_printer_filter(p, "application/vnd.cups-raw 0 -"); + add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); + + /* + * Add any pre-filters in the PPD file... + */ + + if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) + { + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); + + for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) + if (ppdattr->value) + add_printer_filter(p, p->prefiltertype, ppdattr->value); + } /* * Add any filters in the PPD file... @@ -1890,7 +2071,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ for (i = 0; i < ppd->num_filters; i ++) { DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i])); - add_printer_filter(p, ppd->filters[i]); + add_printer_filter(p, p->filetype, ppd->filters[i]); } if (ppd->num_filters == 0) @@ -1899,7 +2080,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ * If there are no filters, add a PostScript printing filter. */ - add_printer_filter(p, "application/vnd.cups-postscript 0 -"); + add_printer_filter(p, p->filetype, + "application/vnd.cups-postscript 0 -"); } /* @@ -1940,6 +2122,10 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ attr->values[i].string.text = _cupsStrAlloc("bcp"); } +#ifdef HAVE_DNSSD + cupsdSetString(&p->product, ppd->product); +#endif /* HAVE_DNSSD */ + /* * Close the PPD and set the type... */ @@ -1974,13 +2160,14 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ * handle "raw" printing by users. */ - add_printer_filter(p, "application/vnd.cups-raw 0 -"); + add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); /* * Add a PostScript filter, since this is still possibly PS printer. */ - add_printer_filter(p, "application/vnd.cups-postscript 0 -"); + add_printer_filter(p, p->filetype, + "application/vnd.cups-postscript 0 -"); } else { @@ -1997,11 +2184,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ */ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, "Local System V Printer"); + "printer-make-and-model", NULL, + "Local System V Printer"); snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s", ServerRoot, p->name); - add_printer_filter(p, filename); + add_printer_filter(p, p->filetype, filename); } else if (p->device_uri && !strncmp(p->device_uri, "ipp://", 6) && @@ -2098,12 +2286,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]); length += 32; if (BrowseLocalOptions) - length += 12 + strlen(BrowseLocalOptions); + length += 12 + strlen(BrowseLocalOptions); /* * Allocate the new string... */ - + if ((p->browse_attrs = calloc(1, length)) == NULL) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate %d bytes for browse data!", @@ -2173,6 +2361,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ write_irix_config(p); write_irix_state(p); #endif /* __sgi */ + + /* + * Let the browse protocols reflect the change + */ + + cupsdRegisterPrinter(p); } @@ -2328,6 +2522,12 @@ cupsdSetPrinterState( cupsdAddPrinterHistory(p); /* + * Let the browse protocols reflect the change... + */ + + cupsdRegisterPrinter(p); + + /* * Save the printer configuration if a printer goes from idle or processing * to stopped (or visa-versa)... */ @@ -2452,18 +2652,25 @@ cupsdUpdatePrinters(void) const char * /* O - Printer or class name */ cupsdValidateDest( - const char *hostname, /* I - Host name */ - const char *resource, /* I - Resource name */ + const char *uri, /* I - Printer URI */ cups_ptype_t *dtype, /* O - Type (printer or class) */ cupsd_printer_t **printer) /* O - Printer pointer */ { cupsd_printer_t *p; /* Current printer */ char localname[1024],/* Localized hostname */ *lptr, /* Pointer into localized hostname */ - *sptr; /* Pointer into server name */ - - - DEBUG_printf(("cupsdValidateDest(\"%s\", \"%s\", %p, %p)\n", hostname, resource, + *sptr, /* Pointer into server name */ + *rptr, /* Pointer into resource */ + scheme[32], /* Scheme portion of URI */ + username[64], /* Username portion of URI */ + hostname[HTTP_MAX_HOST], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ + + + DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri, dtype, printer)); /* @@ -2473,7 +2680,16 @@ cupsdValidateDest( if (printer) *printer = NULL; - *dtype = (cups_ptype_t)0; + if (dtype) + *dtype = (cups_ptype_t)0; + + /* + * Pull the hostname and resource from the URI... + */ + + httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), + username, sizeof(username), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); /* * See if the resource is a class or printer... @@ -2485,7 +2701,7 @@ cupsdValidateDest( * Class... */ - resource += 9; + rptr = resource + 9; } else if (!strncmp(resource, "/printers/", 10)) { @@ -2493,7 +2709,7 @@ cupsdValidateDest( * Printer... */ - resource += 10; + rptr = resource + 10; } else { @@ -2508,17 +2724,19 @@ cupsdValidateDest( * See if the printer or class name exists... */ - p = cupsdFindDest(resource); + p = cupsdFindDest(rptr); - if (p == NULL && strchr(resource, '@') == NULL) + if (p == NULL && strchr(rptr, '@') == NULL) return (NULL); else if (p != NULL) { if (printer) *printer = p; - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE); + if (dtype) + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_REMOTE); + return (p->name); } @@ -2527,7 +2745,7 @@ cupsdValidateDest( */ if (!strcasecmp(hostname, "localhost")) - hostname = ServerName; + strlcpy(hostname, ServerName, sizeof(hostname)); strlcpy(localname, hostname, sizeof(localname)); @@ -2569,13 +2787,15 @@ cupsdValidateDest( p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) if (!strcasecmp(p->hostname, localname) && - !strcasecmp(p->name, resource)) + !strcasecmp(p->name, rptr)) { if (printer) *printer = p; - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE); + if (dtype) + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_REMOTE); + return (p->name); } @@ -2793,6 +3013,27 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ /* + * Maintain a common array of default attribute names... + */ + + if (!CommonDefaults) + { + CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL); + + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default")); + cupsArrayAdd(CommonDefaults, + _cupsStrAlloc("orientation-requested-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default")); + } + + /* * Add all of the default options from the .conf files... */ @@ -2806,6 +3047,9 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ { snprintf(name, sizeof(name), "%s-default", option->name); num_options = cupsAddOption(name, option->value, num_options, &options); + + if (!cupsArrayFind(CommonDefaults, name)) + cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name)); } } @@ -2824,6 +3068,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1); + if (!cupsGetOption("document-format", p->num_options, p->options)) + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, + "document-format-default", NULL, "application/octet-stream"); + if (!cupsGetOption("job-hold-until", p->num_options, p->options)) ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "job-hold-until-default", NULL, "no-hold"); @@ -2839,6 +3087,14 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ if (!cupsGetOption("orientation-requested", p->num_options, p->options)) ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-default", IPP_PORTRAIT); + + if (!cupsGetOption("notify-lease-duration", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "notify-lease-duration-default", DefaultLeaseDuration); + + if (!cupsGetOption("notify-events", p->num_options, p->options)) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-events-default", NULL, "job-completed"); } @@ -2849,6 +3105,7 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ static void add_printer_filter( cupsd_printer_t *p, /* I - Printer to add to */ + mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ const char *filter) /* I - Filter to add */ { char super[MIME_MAX_SUPER], /* Super-type for filter */ @@ -2919,9 +3176,9 @@ add_printer_filter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s", p->name, temptype->super, temptype->type, - p->filetype->super, p->filetype->type, + filtertype->super, filtertype->type, cost, program); - mimeAddFilter(MimeDatabase, temptype, p->filetype, cost, program); + mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program); } } @@ -3017,6 +3274,54 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ attr->values[i].string.text = _cupsStrAlloc(mimetype); } + +#ifdef HAVE_DNSSD + { + char pdl[1024]; /* Buffer to build pdl list */ + mime_filter_t *filter; /* MIME filter looping var */ + + + pdl[0] = '\0'; + + if (mimeType(MimeDatabase, "application", "pdf")) + strlcat(pdl, "application/pdf,", sizeof(pdl)); + + if (mimeType(MimeDatabase, "application", "postscript")) + strlcat(pdl, "application/postscript,", sizeof(pdl)); + + if (mimeType(MimeDatabase, "application", "vnd.cups-raster")) + strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl)); + + /* + * Determine if this is a Tioga PrintJobMgr based queue... + */ + + for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); + filter; + filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) + { + if (filter->dst == p->filetype && filter->filter && + strstr(filter->filter, "PrintJobMgr")) + break; + } + + /* + * We only support raw printing if this is not a Tioga PrintJobMgr based + * queue and if application/octet-stream is a known conversion... + */ + + if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) + strlcat(pdl, "application/octet-stream,", sizeof(pdl)); + + if (mimeType(MimeDatabase, "image", "png")) + strlcat(pdl, "image/png,", sizeof(pdl)); + + if (pdl[0]) + pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ + + cupsdSetString(&p->pdl, pdl); + } +#endif /* HAVE_DNSSD */ } @@ -3327,5 +3632,5 @@ write_irix_state(cupsd_printer_t *p) /* I - Printer to update */ /* - * End of "$Id: printers.c 5970 2006-09-19 20:11:08Z mike $". + * End of "$Id: printers.c 6318 2007-03-06 04:36:55Z mike $". */ diff --git a/scheduler/printers.h b/scheduler/printers.h index acbc73800..77782359d 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -1,9 +1,9 @@ /* - * "$Id: printers.h 5828 2006-08-15 21:21:45Z mike $" + * "$Id: printers.h 6318 2007-03-06 04:36:55Z mike $" * * Printer definitions for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -22,6 +22,10 @@ * WWW: http://www.cups.org */ +#ifdef HAVE_DNSSD +# include <dns_sd.h> +#endif /* HAVE_DNSSD */ + /* * Quota data... */ @@ -67,7 +71,8 @@ typedef struct cupsd_printer_s char *port_monitor; /* Port monitor */ int raw; /* Raw queue? */ int remote; /* Remote queue? */ - mime_type_t *filetype; /* Pseudo-filetype for printer */ + mime_type_t *filetype, /* Pseudo-filetype for printer */ + *prefiltertype; /* Pseudo-filetype for pre-filters */ cups_array_t *filetypes; /* Supported file types */ void *job; /* Current job in queue */ ipp_t *attrs; /* Attributes supported by this printer */ @@ -86,9 +91,21 @@ typedef struct cupsd_printer_s int sequence_number; /* Increasing sequence number */ int num_options; /* Number of default options */ cups_option_t *options; /* Default options */ + int num_auth_info_required; /* Number of required auth fields */ + const char *auth_info_required[4]; /* Required authentication fields */ #ifdef __APPLE__ char *recoverable; /* com.apple.print.recoverable-message */ #endif /* __APPLE__ */ + +#ifdef HAVE_DNSSD + char *reg_name, /* Name used for service registration */ + *product, /* PPD Product string */ + *pdl, /* pdl value for TXT record */ + *txt_record; /* TXT record contents */ + int txt_len; /* TXT record length */ + DNSServiceRef dnssd_ipp_ref; /* DNSServiceRegister ref for _ipp */ + int dnssd_ipp_fd; /* File descriptor for DNSServiceRegister reference */ +#endif /* HAVE_DNSSD */ } cupsd_printer_t; @@ -98,6 +115,8 @@ typedef struct cupsd_printer_s VAR ipp_t *CommonData VALUE(NULL); /* Common printer object attrs */ +VAR cups_array_t *CommonDefaults VALUE(NULL); + /* Common -default option names */ VAR cups_array_t *Printers VALUE(NULL), /* Printer list */ *ImplicitPrinters VALUE(NULL); @@ -117,7 +136,8 @@ 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 cupsdAddPrinterUser(cupsd_printer_t *p, + const char *username); extern void cupsdCreateCommonData(void); extern void cupsdDeleteAllPrinters(void); extern void cupsdDeletePrinter(cupsd_printer_t *p, int update); @@ -126,26 +146,31 @@ extern cupsd_printer_t *cupsdFindPrinter(const char *name); 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, const char *name); +extern void cupsdRenamePrinter(cupsd_printer_t *p, + const char *name); +extern char *cupsdSanitizeURI(const char *uri, char *buffer, + int buflen); extern void cupsdSaveAllPrinters(void); +extern int cupsdSetAuthInfoRequired(cupsd_printer_t *p, + const char *values, + ipp_attribute_t *attr); extern void cupsdSetPrinterAttrs(cupsd_printer_t *p); -extern void cupsdSetPrinterReasons(cupsd_printer_t *p, const char *s); -extern void cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s, int update); +extern void cupsdSetPrinterReasons(cupsd_printer_t *p, + const char *s); +extern void cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s, + int update); #define cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PRINTER_IDLE, (u)) extern void cupsdStopPrinter(cupsd_printer_t *p, int update); extern void cupsdUpdatePrinters(void); -extern cupsd_quota_t *cupsdUpdateQuota(cupsd_printer_t *p, const char *username, - int pages, int k); -extern const char *cupsdValidateDest(const char *hostname, - const char *resource, +extern cupsd_quota_t *cupsdUpdateQuota(cupsd_printer_t *p, + const char *username, int pages, + int k); +extern const char *cupsdValidateDest(const char *uri, cups_ptype_t *dtype, cupsd_printer_t **printer); extern void cupsdWritePrintcap(void); -extern char *cupsdSanitizeURI(const char *uri, char *buffer, - int buflen); - /* - * End of "$Id: printers.h 5828 2006-08-15 21:21:45Z mike $". + * End of "$Id: printers.h 6318 2007-03-06 04:36:55Z mike $". */ diff --git a/scheduler/process.c b/scheduler/process.c index 5af7e5eef..7462472a6 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -1,9 +1,9 @@ /* - * "$Id: process.c 5376 2006-04-06 20:32:07Z mike $" + * "$Id: process.c 6326 2007-03-11 17:50:18Z mike $" * * Process management routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -121,6 +121,7 @@ cupsdStartProcess( int outfd, /* I - Standard output file descriptor */ int errfd, /* I - Standard error file descriptor */ int backfd, /* I - Backchannel file descriptor */ + int sidefd, /* I - Sidechannel file descriptor */ int root, /* I - Run as root? */ int *pid) /* O - Process ID */ { @@ -161,7 +162,7 @@ cupsdStartProcess( linkpath); else snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s", - dirname(command), linkpath); + dirname((char *)command), linkpath); } else snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command); @@ -217,6 +218,12 @@ cupsdStartProcess( open("/dev/null", O_RDWR); fcntl(3, F_SETFL, O_NDELAY); } + if (sidefd != 4 && sidefd > 0) + { + close(4); + dup(sidefd); + fcntl(4, F_SETFL, O_NDELAY); + } /* * Change the priority of the process based on the FilterNice setting. @@ -344,5 +351,5 @@ compare_procs(cupsd_proc_t *a, /* I - First process */ /* - * End of "$Id: process.c 5376 2006-04-06 20:32:07Z mike $". + * End of "$Id: process.c 6326 2007-03-11 17:50:18Z mike $". */ diff --git a/scheduler/quotas.c b/scheduler/quotas.c index 7d3e4e3eb..a51f7f08d 100644 --- a/scheduler/quotas.c +++ b/scheduler/quotas.c @@ -1,5 +1,5 @@ /* - * "$Id: quotas.c 5970 2006-09-19 20:11:08Z mike $" + * "$Id: quotas.c 5969 2006-09-19 20:09:24Z mike $" * * Quota routines for the Common UNIX Printing System (CUPS). * @@ -230,5 +230,5 @@ find_quota(cupsd_printer_t *p, /* I - Printer */ /* - * End of "$Id: quotas.c 5970 2006-09-19 20:11:08Z mike $". + * End of "$Id: quotas.c 5969 2006-09-19 20:09:24Z mike $". */ diff --git a/scheduler/select.c b/scheduler/select.c new file mode 100644 index 000000000..c72adbdc9 --- /dev/null +++ b/scheduler/select.c @@ -0,0 +1,946 @@ +/* + * "$Id: select.c 6166 2006-12-29 20:35:18Z mike $" + * + * Select abstraction functions for the Common UNIX Printing System (CUPS). + * + * Copyright 2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddSelect() - Add a file descriptor to the list. + * cupsdDoSelect() - Do a select-like operation. + * cupsdIsSelecting() - Determine whether we are monitoring a file + * descriptor. + * cupsdRemoveSelect() - Remove a file descriptor from the list. + * cupsdStartSelect() - Initialize the file polling engine. + * cupsdStopSelect() - Shutdown the file polling engine. + * compare_fds() - Compare file descriptors. + * find_fd() - Find an existing file descriptor record. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + +#ifdef HAVE_EPOLL +# include <sys/epoll.h> +#elif defined(HAVE_KQUEUE) +# include <sys/event.h> +# include <sys/time.h> +#elif defined(HAVE_POLL) +# include <sys/poll.h> +#elif defined(__hpux) +# include <sys/time.h> +#else +# include <sys/select.h> +#endif /* HAVE_EPOLL */ + + +/* + * Design Notes for Poll/Select API in CUPSD + * ----------------------------------------- + * + * SUPPORTED APIS + * + * OS select poll epoll kqueue /dev/poll + * -------------- ------ ------ ------ ------ --------- + * AIX YES YES NO NO NO + * FreeBSD YES YES NO YES NO + * HP-UX YES YES NO NO NO + * IRIX YES YES NO NO NO + * Linux YES YES YES NO NO + * MacOS X YES YES NO YES NO + * NetBSD YES YES NO YES NO + * OpenBSD YES YES NO YES NO + * Solaris YES YES NO NO YES + * Tru64 YES YES NO NO NO + * Windows YES NO NO NO NO + * + * + * HIGH-LEVEL API + * + * typedef void (*cupsd_selfunc_t)(void *data); + * + * void cupsdStartSelect(void); + * void cupsdStopSelect(void); + * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb, + * cupsd_selfunc_t write_cb, void *data); + * void cupsdRemoveSelect(int fd); + * int cupsdDoSelect(int timeout); + * + * + * IMPLEMENTATION STRATEGY + * + * 0. Common Stuff + * a. CUPS array of file descriptor to callback functions + * and data. + * b. cupsdStartSelect() creates the array + * c. cupsdStopSelect() destroys the array and all elements. + * d. cupsdAddSelect() adds to the array and allocates a + * new callback element. + * e. cupsdRemoveSelect() removes from the array and frees + * the callback element. + * f. _cupsd_fd_t provides a reference-counted structure for + * tracking file descriptors that are monitored. + * + * 1. select() O(n) + * a. Input/Output fd_set variables, copied to working + * copies and then used with select(). + * b. Loop through CUPS array, using FD_ISSET and calling + * the read/write callbacks as needed. + * c. cupsdRemoveSelect() clears fd_set bit from main and + * working sets. + * d. cupsdStopSelect() frees all of the memory used by the + * CUPS array and fd_set's. + * + * 2. poll() - O(n log n) + * a. Regular array of pollfd, sorted the same as the CUPS + * array. + * b. Loop through pollfd array, call the corresponding + * read/write callbacks as needed. + * c. cupsdAddSelect() adds first to CUPS array and flags the + * pollfd array as invalid. + * d. cupsdDoSelect() rebuilds pollfd array as needed, calls + * poll(), then loops through the pollfd array looking up + * as needed. + * e. cupsdRemoveSelect() flags the pollfd array as invalid. + * f. cupsdStopSelect() frees all of the memory used by the + * CUPS array and pollfd array. + * + * 3. epoll() - O(n) + * a. cupsdStartSelect() creates epoll file descriptor using + * epoll_create() with the maximum fd count, and + * allocates an events buffer for the maximum fd count. + * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add + * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single + * event using the level-triggered semantics. The event + * user data field is a pointer to the new callback array + * element. + * c. cupsdDoSelect() uses epoll_wait() with the global event + * buffer allocated in cupsdStartSelect() and then loops + * through the events, using the user data field to find + * the callback record. + * d. cupsdStopSelect() closes the epoll file descriptor and + * frees all of the memory used by the event buffer. + * + * 4. kqueue() - O(n) + * b. cupsdStartSelect() creates kqueue file descriptor + * using kqyeue() function and allocates a global event + * buffer. + * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to + * register the changes. The event user data field is a + * pointer to the new callback array element. + * d. cupsdDoSelect() uses kevent() to poll for events and + * loops through the events, using the user data field to + * find the callback record. + * e. cupsdStopSelect() closes the kqyeye() file descriptor + * and frees all of the memory used by the event buffer. + * + * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED + * a. cupsdStartSelect() opens /dev/poll and allocates an + * array of pollfd structs; on failure to open /dev/poll, + * revert to poll() system call. + * b. cupsdAddSelect() writes a single pollfd struct to + * /dev/poll with the new file descriptor and the + * POLLIN/POLLOUT flags. + * c. cupsdRemoveSelect() writes a single pollfd struct to + * /dev/poll with the file descriptor and the POLLREMOVE + * flag. + * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve + * events from /dev/poll and then loops through the + * returned pollfd array, looking up the file descriptors + * as needed. + * e. cupsdStopSelect() closes /dev/poll and frees the + * pollfd array. + * + * PERFORMANCE + * + * In tests using the "make test" target with option 0 (keep cupsd + * running) and the "testspeed" program with "-c 50 -r 1000", epoll() + * performed 5.5% slower select(), followed by kqueue() at 16% slower + * than select() and poll() at 18% slower than select(). Similar + * results were seen with twice the number of client connections. + * + * The epoll() and kqueue() performance is likely limited by the + * number of system calls used to add/modify/remove file + * descriptors dynamically. Further optimizations may be possible + * in the area of limiting use of cupsdAddSelect() and + * cupsdRemoveSelect(), however extreme care will be needed to avoid + * excess CPU usage and deadlock conditions. + * + * We may be able to improve the poll() implementation simply by + * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that + * will eliminate the rebuilding of the array whenever there is a + * change and eliminate the fd array lookups in the inner loop of + * cupsdDoSelect(). + * + * Since /dev/poll will never be able to use a shadow array, it may + * not make sense to implement support for it. ioctl() overhead will + * impact performance as well, so my guess would be that, for CUPS, + * /dev/poll will yield a net performance loss. + */ + +/* + * Local structures... + */ + +typedef struct _cupsd_fd_s +{ + int fd, /* File descriptor */ + use; /* Use count */ + cupsd_selfunc_t read_cb, /* Read callback */ + write_cb; /* Write callback */ + void *data; /* Data pointer for callbacks */ +} _cupsd_fd_t; + + +/* + * Local globals... + */ + +static cups_array_t *cupsd_fds = NULL; + +#ifdef HAVE_EPOLL +static int cupsd_epoll_fd = -1; +static struct epoll_event *cupsd_epoll_events = NULL; +#elif defined(HAVE_KQUEUE) +static int cupsd_kqueue_fd = -1, + cupsd_kqueue_changes = 0; +static struct kevent *cupsd_kqueue_events = NULL; +#elif defined(HAVE_POLL) +static int cupsd_alloc_pollfds = 0, + cupsd_update_pollfds = 0; +static struct pollfd *cupsd_pollfds = NULL; +#else /* select() */ +static fd_set cupsd_global_input, + cupsd_global_output, + cupsd_current_input, + cupsd_current_output; +#endif /* HAVE_EPOLL */ + + +/* + * Local functions... + */ + +static int compare_fds(_cupsd_fd_t *a, _cupsd_fd_t *b); +static _cupsd_fd_t *find_fd(int fd); +#define release_fd(f) { \ + (f)->use --; \ + if (!(f)->use) free((f));\ + } +#define retain_fd(f) (f)->use++ + + +/* + * 'cupsdAddSelect()' - Add a file descriptor to the list. + */ + +int /* O - 1 on success, 0 on error */ +cupsdAddSelect(int fd, /* I - File descriptor */ + cupsd_selfunc_t read_cb, /* I - Read callback */ + cupsd_selfunc_t write_cb,/* I - Write callback */ + void *data) /* I - Data to pass to callback */ +{ + _cupsd_fd_t *fdptr; /* File descriptor record */ + int added; /* 1 if added, 0 if modified */ + + + /* + * Range check input... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: fd=%d, read_cb=%p, write_cb=%p, data=%p", + fd, read_cb, write_cb, data); + + if (fd < 0) + return (0); + + /* + * See if this FD has already been added... + */ + + if ((fdptr = find_fd(fd)) == NULL) + { + /* + * No, add a new entry... + */ + + if ((fdptr = calloc(1, sizeof(_cupsd_fd_t))) == NULL) + return (0); + + fdptr->fd = fd; + fdptr->use = 1; + + if (!cupsArrayAdd(cupsd_fds, fdptr)) + { + cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to add fd %d to array!", fd); + free(fdptr); + return (0); + } + + added = 1; + } + else + added = 0; + +#ifdef HAVE_EPOLL + { + struct epoll_event event; /* Event data */ + + + event.events = 0; + + if (read_cb) + event.events |= EPOLLIN; + + if (write_cb) + event.events |= EPOLLOUT; + + event.data.ptr = fdptr; + + epoll_ctl(cupsd_epoll_fd, added ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, + &event); + } + +#elif defined(HAVE_KQUEUE) + { + struct kevent event; /* Event data */ + struct timespec timeout; /* Timeout value */ + + + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + if (fdptr->read_cb != read_cb) + { + if (read_cb) + EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, fdptr); + else + EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr); + + if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: kevent() returned %s", + strerror(errno)); + return (0); + } + } + + if (fdptr->write_cb != write_cb) + { + if (write_cb) + EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, fdptr); + else + EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr); + + if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: kevent() returned %s", + strerror(errno)); + return (0); + } + } + } + +#elif defined(HAVE_POLL) + cupsd_update_pollfds = 1; + +#else /* select() */ + /* + * Add or remove the file descriptor in the input and output sets + * for select()... + */ + + if (read_cb) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: Adding fd %d to input set...", fd); + FD_SET(fd, &cupsd_global_input); + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: Removing fd %d from input set...", fd); + FD_CLR(fd, &cupsd_global_input); + FD_CLR(fd, &cupsd_current_input); + } + + if (write_cb) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: Adding fd %d to output set...", fd); + FD_SET(fd, &cupsd_global_output); + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddSelect: Removing fd %d from output set...", fd); + FD_CLR(fd, &cupsd_global_output); + FD_CLR(fd, &cupsd_current_output); + } +#endif /* HAVE_EPOLL */ + + /* + * Save the (new) read and write callbacks... + */ + + fdptr->read_cb = read_cb; + fdptr->write_cb = write_cb; + fdptr->data = data; + + return (1); +} + + +/* + * 'cupsdDoSelect()' - Do a select-like operation. + */ + +int /* O - Number of files or -1 on error */ +cupsdDoSelect(long timeout) /* I - Timeout in seconds */ +{ + int nfds; /* Number of file descriptors */ + _cupsd_fd_t *fdptr; /* Current file descriptor */ +#ifdef HAVE_EPOLL + int i; /* Looping var */ + struct epoll_event *event; /* Current event */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: polling %d fds for %ld seconds...", + cupsArrayCount(cupsd_fds), timeout); + + if (timeout >= 0 && timeout < 86400) + nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, + timeout * 1000); + else + nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, -1); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: epoll() returned %d...", + nfds); + + for (i = nfds, event = cupsd_epoll_events; i > 0; i --, event ++) + { + fdptr = (_cupsd_fd_t *)event->data.ptr; + + retain_fd(fdptr); + + if (fdptr->read_cb && (event->events & (EPOLLIN | EPOLLERR | EPOLLHUP))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...", + fdptr->fd); + (*(fdptr->read_cb))(fdptr->data); + } + + if (fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", + fdptr->fd); + (*(fdptr->write_cb))(fdptr->data); + } + + release_fd(fdptr); + } + +#elif defined(HAVE_KQUEUE) + int i; /* Looping var */ + struct kevent *event; /* Current event */ + struct timespec ktimeout; /* kevent() timeout */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: polling %d fds for %ld seconds...", + cupsArrayCount(cupsd_fds), timeout); + + if (timeout >= 0 && timeout < 86400) + { + ktimeout.tv_sec = timeout; + ktimeout.tv_nsec = 0; + + nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs, + &ktimeout); + } + else + nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs, NULL); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...", + cupsd_kqueue_fd, MaxFDs, nfds); + + cupsd_kqueue_changes = 0; + + for (i = nfds, event = cupsd_kqueue_events; i > 0; i --, event ++) + { + fdptr = (_cupsd_fd_t *)event->udata; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "event->filter=%d, event->ident=%d", + event->filter, (int)event->ident); + + retain_fd(fdptr); + + if (fdptr->read_cb && event->filter == EVFILT_READ) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...", + fdptr->fd); + (*(fdptr->read_cb))(fdptr->data); + } + + if (fdptr->write_cb && event->filter == EVFILT_WRITE) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", + fdptr->fd); + (*(fdptr->write_cb))(fdptr->data); + } + + release_fd(fdptr); + } + +#elif defined(HAVE_POLL) + struct pollfd *pfd; /* Current pollfd structure */ + int count; /* Number of file descriptors */ + + + count = cupsArrayCount(cupsd_fds); + + if (cupsd_update_pollfds) + { + /* + * Update the cupsd_pollfds array to match the current FD array... + */ + + cupsd_update_pollfds = 0; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Updating pollfd array..."); + + /* + * (Re)allocate memory as needed... + */ + + if (count > cupsd_alloc_pollfds) + { + int allocfds = count + 16; + + + if (cupsd_pollfds) + pfd = realloc(cupsd_pollfds, allocfds * sizeof(struct pollfd)); + else + pfd = malloc(allocfds * sizeof(struct pollfd)); + + if (!pfd) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "Unable to allocate %d bytes for polling!", + (int)(allocfds * sizeof(struct pollfd))); + + return (-1); + } + + cupsd_pollfds = pfd; + cupsd_alloc_pollfds = allocfds; + } + + /* + * Rebuild the array... + */ + + for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds), pfd = cupsd_pollfds; + fdptr; + fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds), pfd ++) + { + pfd->fd = fdptr->fd; + pfd->events = 0; + + if (fdptr->read_cb) + pfd->events |= POLLIN; + + if (fdptr->write_cb) + pfd->events |= POLLOUT; + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: polling %d fds for %ld seconds...", + count, timeout); + + if (timeout >= 0 && timeout < 86400) + nfds = poll(cupsd_pollfds, count, timeout * 1000); + else + nfds = poll(cupsd_pollfds, count, -1); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: poll() returned %d...", + nfds); + + if (nfds > 0) + { + /* + * Do callbacks for each file descriptor... + */ + + for (pfd = cupsd_pollfds; count > 0; pfd ++, count --) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}", + pfd - cupsd_pollfds, pfd->fd, pfd->revents); + + if (!pfd->revents) + continue; + + if ((fdptr = find_fd(pfd->fd)) == NULL) + continue; + + retain_fd(fdptr); + + if (fdptr->read_cb && (pfd->revents & (POLLIN | POLLERR | POLLHUP))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...", + fdptr->fd); + (*(fdptr->read_cb))(fdptr->data); + } + + if (fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", + fdptr->fd); + (*(fdptr->write_cb))(fdptr->data); + } + + release_fd(fdptr); + } + } + +#else /* select() */ + struct timeval stimeout; /* Timeout for select() */ + int maxfd; /* Maximum file descriptor */ + + + /* + * Figure out the highest file descriptor number... + */ + + if ((fdptr = (_cupsd_fd_t *)cupsArrayLast(cupsd_fds)) == NULL) + maxfd = 1; + else + maxfd = fdptr->fd + 1; + + /* + * Do the select()... + */ + + cupsd_current_input = cupsd_global_input; + cupsd_current_output = cupsd_global_output; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDoSelect: selecting %d fds for %ld seconds...", + maxfd, timeout); + + if (timeout >= 0 && timeout < 86400) + { + stimeout.tv_sec = timeout; + stimeout.tv_usec = 0; + + nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL, + &stimeout); + } + else + nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL, + NULL); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: select() returned %d...", + nfds); + + if (nfds > 0) + { + /* + * Do callbacks for each file descriptor... + */ + + for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds); + fdptr; + fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds)) + { + retain_fd(fdptr); + + if (fdptr->read_cb && FD_ISSET(fdptr->fd, &cupsd_current_input)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...", + fdptr->fd); + (*(fdptr->read_cb))(fdptr->data); + } + + if (fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", + fdptr->fd); + (*(fdptr->write_cb))(fdptr->data); + } + + release_fd(fdptr); + } + } + +#endif /* HAVE_EPOLL */ + + /* + * Return the number of file descriptors handled... + */ + + return (nfds); +} + + +/* + * 'cupsdIsSelecting()' - Determine whether we are monitoring a file + * descriptor. + */ + +int /* O - 1 if selecting, 0 otherwise */ +cupsdIsSelecting(int fd) /* I - File descriptor */ +{ + return (find_fd(fd) != NULL); +} + + +/* + * 'cupsdRemoveSelect()' - Remove a file descriptor from the list. + */ + +void +cupsdRemoveSelect(int fd) /* I - File descriptor */ +{ + _cupsd_fd_t *fdptr; /* File descriptor record */ +#ifdef HAVE_EPOLL + struct epoll_event event; /* Event data */ +#elif defined(HAVE_KQUEUE) + struct kevent event; /* Event data */ + struct timespec timeout; /* Timeout value */ +#elif defined(HAVE_POLL) + /* No variables for poll() */ +#endif /* HAVE_EPOLL */ + + + /* + * Range check input... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRemoveSelect: fd=%d", fd); + + if (fd < 0) + return; + + /* + * Find the file descriptor... + */ + + if ((fdptr = find_fd(fd)) == NULL) + return; + +#ifdef HAVE_EPOLL + epoll_ctl(cupsd_epoll_fd, EPOLL_CTL_DEL, fd, &event); + +#elif defined(HAVE_KQUEUE) + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + if (fdptr->read_cb) + { + EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr); + + if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdRemoveSelect: kevent() returned %s", + strerror(errno)); + return; + } + } + + if (fdptr->write_cb) + { + EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr); + + if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdRemoveSelect: kevent() returned %s", + strerror(errno)); + return; + } + } + + +#elif defined(HAVE_POLL) + /* + * Update the pollfds array... + */ + + cupsd_update_pollfds = 1; + +#else /* select() */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdRemoveSelect: Removing fd %d from input and output " + "sets...", fd); + FD_CLR(fd, &cupsd_global_input); + FD_CLR(fd, &cupsd_global_output); + FD_CLR(fd, &cupsd_current_input); + FD_CLR(fd, &cupsd_current_output); +#endif /* HAVE_EPOLL */ + + /* + * Remove the file descriptor for from the FD array... + */ + + cupsArrayRemove(cupsd_fds, fdptr); + release_fd(fdptr); +} + + +/* + * 'cupsdStartSelect()' - Initialize the file polling engine. + */ + +void +cupsdStartSelect(void) +{ + cupsd_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL); + +#ifdef HAVE_EPOLL + cupsd_epoll_fd = epoll_create(MaxFDs); + cupsd_epoll_events = calloc(MaxFDs, sizeof(struct epoll_event)); + +#elif defined(HAVE_KQUEUE) + cupsd_kqueue_fd = kqueue(); + cupsd_kqueue_changes = 0; + cupsd_kqueue_events = calloc(MaxFDs, sizeof(struct kevent)); + +#elif defined(HAVE_POLL) + cupsd_update_pollfds = 0; + +#else /* select() */ + FD_ZERO(&cupsd_global_input); + FD_ZERO(&cupsd_global_output); +#endif /* HAVE_EPOLL */ +} + + +/* + * 'cupsdStopSelect()' - Shutdown the file polling engine. + */ + +void +cupsdStopSelect(void) +{ + _cupsd_fd_t *fdptr; /* Current file descriptor */ + + + for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds); + fdptr; + fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds)) + free(fdptr); + + cupsArrayDelete(cupsd_fds); + cupsd_fds = NULL; + +#ifdef HAVE_EPOLL + if (cupsd_epoll_events) + { + free(cupsd_epoll_events); + cupsd_epoll_events = NULL; + } + + if (cupsd_epoll_fd >= 0) + { + close(cupsd_epoll_fd); + cupsd_epoll_fd = -1; + } + +#elif defined(HAVE_KQUEUE) + if (cupsd_kqueue_events) + { + free(cupsd_kqueue_events); + cupsd_kqueue_events = NULL; + } + + if (cupsd_kqueue_fd >= 0) + { + close(cupsd_kqueue_fd); + cupsd_kqueue_fd = -1; + } + + cupsd_kqueue_changes = 0; + +#elif defined(HAVE_POLL) + if (cupsd_pollfds) + { + free(cupsd_pollfds); + cupsd_pollfds = NULL; + cupsd_alloc_pollfds = 0; + } + + cupsd_update_pollfds = 0; + +#else /* select() */ + FD_ZERO(&cupsd_global_input); + FD_ZERO(&cupsd_global_output); +#endif /* HAVE_EPOLL */ +} + + +/* + * 'compare_fds()' - Compare file descriptors. + */ + +static int /* O - Result of comparison */ +compare_fds(_cupsd_fd_t *a, /* I - First file descriptor */ + _cupsd_fd_t *b) /* I - Second file descriptor */ +{ + return (a->fd - b->fd); +} + + +/* + * 'find_fd()' - Find an existing file descriptor record. + */ + +static _cupsd_fd_t * /* O - FD record pointer or NULL */ +find_fd(int fd) /* I - File descriptor */ +{ + _cupsd_fd_t *fdptr, /* Matching record (if any) */ + key; /* Search key */ + + + cupsArraySave(cupsd_fds); + + key.fd = fd; + fdptr = (_cupsd_fd_t *)cupsArrayFind(cupsd_fds, &key); + + cupsArrayRestore(cupsd_fds); + + return (fdptr); +} + + +/* + * End of "$Id: select.c 6166 2006-12-29 20:35:18Z mike $". + */ diff --git a/scheduler/server.c b/scheduler/server.c index bcc3c71e6..7efbbcd71 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -1,5 +1,5 @@ /* - * "$Id: server.c 5493 2006-05-05 16:33:57Z mike $" + * "$Id: server.c 6123 2006-11-21 15:36:04Z mike $" * * Server start/stop routines for the Common UNIX Printing System (CUPS). * @@ -107,10 +107,7 @@ cupsdStartServer(void) { CGIStatusBuffer = cupsdStatBufNew(CGIPipes[0], "[CGI]"); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartServer: Adding fd %d to InputSet...", - CGIPipes[0]); - FD_SET(CGIPipes[0], InputSet); + cupsdAddSelect(CGIPipes[0], (cupsd_selfunc_t)cupsdUpdateCGI, NULL, NULL); } /* @@ -158,11 +155,7 @@ cupsdStopServer(void) if (CGIPipes[0] >= 0) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopServer: Removing fd %d from InputSet...", - CGIPipes[0]); - - FD_CLR(CGIPipes[0], InputSet); + cupsdRemoveSelect(CGIPipes[0]); cupsdStatBufDelete(CGIStatusBuffer); close(CGIPipes[1]); @@ -211,5 +204,5 @@ cupsdStopServer(void) /* - * End of "$Id: server.c 5493 2006-05-05 16:33:57Z mike $". + * End of "$Id: server.c 6123 2006-11-21 15:36:04Z mike $". */ diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c index b10f63ebc..0450fa14a 100644 --- a/scheduler/statbuf.c +++ b/scheduler/statbuf.c @@ -1,5 +1,5 @@ /* - * "$Id: statbuf.c 5889 2006-08-24 21:44:35Z mike $" + * "$Id: statbuf.c 5888 2006-08-24 21:42:47Z mike $" * * Status buffer routines for the Common UNIX Printing System (CUPS) * scheduler. @@ -330,5 +330,5 @@ cupsdStatBufUpdate(cupsd_statbuf_t *sb, /* I - Status buffer */ /* - * End of "$Id: statbuf.c 5889 2006-08-24 21:44:35Z mike $". + * End of "$Id: statbuf.c 5888 2006-08-24 21:42:47Z mike $". */ diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index d0e05d9be..c077bcdeb 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -1,9 +1,9 @@ /* - * "$Id: subscriptions.c 5991 2006-09-29 02:26:29Z mike $" + * "$Id: subscriptions.c 6176 2007-01-03 15:28:30Z mike $" * * Subscription routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -52,8 +52,8 @@ # include <dbus/dbus.h> # ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND # define dbus_message_append_iter_init dbus_message_iter_init_append -# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, v) -# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, v) +# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &(v)) +# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &(v)) # endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */ #endif /* HAVE_DBUS */ @@ -1226,10 +1226,7 @@ cupsdStopAllNotifiers(void) if (NotifierPipes[0] >= 0) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopAllNotifiers: Removing fd %d from InputSet...", - NotifierPipes[0]); - FD_CLR(NotifierPipes[0], InputSet); + cupsdRemoveSelect(NotifierPipes[0]); cupsdStatBufDelete(NotifierStatusBuffer); @@ -1362,11 +1359,11 @@ cupsd_send_dbus(cupsd_eventmask_t event,/* I - Event to send */ dbus_message_append_iter_init(message, &iter); if (dest) - dbus_message_iter_append_string(&iter, &(dest->name)); + dbus_message_iter_append_string(&iter, dest->name); if (job) { - dbus_message_iter_append_uint32(&iter, &(job->id)); - dbus_message_iter_append_string(&iter, &(job->username)); + dbus_message_iter_append_uint32(&iter, job->id); + dbus_message_iter_append_string(&iter, job->username); } dbus_connection_send(con, message, NULL); @@ -1571,11 +1568,8 @@ cupsd_start_notifier( NotifierStatusBuffer = cupsdStatBufNew(NotifierPipes[0], "[Notifier]"); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "start_notifier: Adding fd %d to InputSet...", - NotifierPipes[0]); - - FD_SET(NotifierPipes[0], InputSet); + cupsdAddSelect(NotifierPipes[0], (cupsd_selfunc_t)cupsdUpdateNotifierStatus, + NULL, NULL); } if (cupsdOpenPipe(fds)) @@ -1597,7 +1591,7 @@ cupsd_start_notifier( */ if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1], - -1, 0, &pid) < 0) + -1, -1, 0, &pid) < 0) { /* * Error - can't fork! @@ -1627,5 +1621,5 @@ cupsd_start_notifier( /* - * End of "$Id: subscriptions.c 5991 2006-09-29 02:26:29Z mike $". + * End of "$Id: subscriptions.c 6176 2007-01-03 15:28:30Z mike $". */ diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h index 9671d937f..6cdd3a063 100644 --- a/scheduler/subscriptions.h +++ b/scheduler/subscriptions.h @@ -1,5 +1,5 @@ /* - * "$Id: subscriptions.h 5673 2006-06-16 21:04:45Z mike $" + * "$Id: subscriptions.h 5672 2006-06-16 21:04:07Z mike $" * * Subscription definitions for the Common UNIX Printing System (CUPS) scheduler. * @@ -168,5 +168,5 @@ extern void cupsdUpdateNotifierStatus(void); /* - * End of "$Id: subscriptions.h 5673 2006-06-16 21:04:45Z mike $". + * End of "$Id: subscriptions.h 5672 2006-06-16 21:04:07Z mike $". */ diff --git a/scheduler/sysman.c b/scheduler/sysman.c index 61f342dcb..6267b665b 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -1,5 +1,5 @@ /* - * "$Id: sysman.c 6090 2006-11-14 16:35:27Z mike $" + * "$Id: sysman.c 6291 2007-02-19 21:54:27Z mike $" * * System management definitions for the Common UNIX Printing System (CUPS). * @@ -160,10 +160,8 @@ cupsdStartSystemMonitor(void) return; } - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartSystemMonitor: Adding fd %d to InputSet...", - SysEventPipes[0]); - FD_SET(SysEventPipes[0], InputSet); + cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)cupsdUpdateSystemMonitor, + NULL, NULL); /* * Set non-blocking mode on the descriptor we will be receiving notification @@ -220,12 +218,7 @@ cupsdStopSystemMonitor(void) if (SysEventPipes[0] >= 0) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStopSystemMonitor: Removing fd %d from InputSet...", - SysEventPipes[0]); - - FD_CLR(SysEventPipes[0], InputSet); - + cupsdRemoveSelect(SysEventPipes[0]); cupsdClosePipe(SysEventPipes); } } @@ -314,7 +307,7 @@ cupsdUpdateSystemMonitor(void) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Deregistering local printer \"%s\"", p->name); - cupsdSendBrowseDelete(p); + cupsdDeregisterPrinter(p, 0); } } @@ -370,18 +363,19 @@ cupsdUpdateSystemMonitor(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - cupsdSendBrowseDelete(p); + cupsdDeregisterPrinter(p, 1); /* * Now re-register them... - * - * TODO: This might need updating for MDNS. */ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { p->browse_time = 0; + cupsdRegisterPrinter(p); + } } else cupsdLogMessage(CUPSD_LOG_DEBUG, @@ -757,5 +751,5 @@ sysEventTimerNotifier( /* - * End of "$Id: sysman.c 6090 2006-11-14 16:35:27Z mike $". + * End of "$Id: sysman.c 6291 2007-02-19 21:54:27Z mike $". */ diff --git a/scheduler/testlpd.c b/scheduler/testlpd.c index a49950391..65b827c25 100644 --- a/scheduler/testlpd.c +++ b/scheduler/testlpd.c @@ -1,5 +1,5 @@ /* - * "$Id: testlpd.c 5868 2006-08-23 19:39:39Z mike $" + * "$Id: testlpd.c 6331 2007-03-12 16:07:31Z mike $" * * cups-lpd test program for the Common UNIX Printing System (CUPS). * @@ -184,6 +184,11 @@ main(int argc, /* I - Number of command-line arguments */ status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); else if (!strcmp(op, "status-short")) status = status_short(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); + else + { + printf("Unknown operation \"%s\"!\n", op); + status = 1; + } /* * Kill the test program... @@ -296,8 +301,8 @@ print_job(int outfd, /* I - Command file descriptor */ "Hlocalhost\n" "P%s\n" "J%s\n" - "ldfA%03.3dlocalhost\n" - "UdfA%03.3dlocalhost\n" + "ldfA%03dlocalhost\n" + "UdfA%03dlocalhost\n" "N%s\n", cupsUser(), jobname, sequence, sequence, jobname); @@ -307,7 +312,7 @@ print_job(int outfd, /* I - Command file descriptor */ bytes = strlen(control); - snprintf(command, sizeof(command), "\002%d cfA%03.3dlocalhost\n", + snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n", bytes, sequence); if ((status = do_command(outfd, infd, command)) != 0) @@ -344,7 +349,7 @@ print_job(int outfd, /* I - Command file descriptor */ * Send the data file... */ - snprintf(command, sizeof(command), "\003%d dfA%03.3dlocalhost\n", + snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n", (int)fileinfo.st_size, sequence); if ((status = do_command(outfd, infd, command)) != 0) @@ -546,5 +551,5 @@ usage(void) /* - * End of "$Id: testlpd.c 5868 2006-08-23 19:39:39Z mike $". + * End of "$Id: testlpd.c 6331 2007-03-12 16:07:31Z mike $". */ diff --git a/scheduler/testmime.c b/scheduler/testmime.c index 460e1d587..6246b64b6 100644 --- a/scheduler/testmime.c +++ b/scheduler/testmime.c @@ -1,5 +1,5 @@ /* - * "$Id: testmime.c 5606 2006-05-30 19:40:34Z mike $" + * "$Id: testmime.c 5605 2006-05-30 19:38:02Z mike $" * * MIME test program for the Common UNIX Printing System (CUPS). * @@ -331,5 +331,5 @@ type_dir(mime_t *mime, /* I - MIME database */ /* - * End of "$Id: testmime.c 5606 2006-05-30 19:40:34Z mike $". + * End of "$Id: testmime.c 5605 2006-05-30 19:38:02Z mike $". */ diff --git a/scheduler/testsub.c b/scheduler/testsub.c index 62156bd17..4c70e7839 100644 --- a/scheduler/testsub.c +++ b/scheduler/testsub.c @@ -1,5 +1,5 @@ /* - * "$Id: testsub.c 5940 2006-09-11 18:30:09Z mike $" + * "$Id: testsub.c 5938 2006-09-11 18:23:46Z mike $" * * Scheduler notification tester for the Common UNIX Printing System (CUPS). * @@ -527,5 +527,5 @@ usage(void) /* - * End of "$Id: testsub.c 5940 2006-09-11 18:30:09Z mike $". + * End of "$Id: testsub.c 5938 2006-09-11 18:23:46Z mike $". */ |