Index: client.c =================================================================== --- client.c (revision 7233) +++ client.c (working copy) @@ -4257,6 +4257,10 @@ server_name[1024], /* SERVER_NAME environment variable */ server_port[1024]; /* SERVER_PORT environment variable */ ipp_attribute_t *attr; /* attributes-natural-language attribute */ +#ifdef HAVE_GSSAPI + krb5_ccache ccache = NULL; /* Kerberos credentials */ + char krb5ccname[1024]; /* KRB5CCNAME environment variable */ +#endif /* HAVE_GSSAPI */ /* @@ -4476,6 +4480,120 @@ snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username); envp[envc ++] = remote_user; + + /* + * Save Kerberos credentials, if any... + */ + +#ifdef HAVE_GSSAPI + if (con->gss_have_creds) + { +# if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL) + cupsdLogMessage(CUPSD_LOG_INFO, + "Sorry, your version of Kerberos does not support " + "delegated credentials!"); + +# else + krb5_error_code error; /* Kerberos error code */ + OM_uint32 major_status, /* Major status code */ + minor_status; /* Minor status code */ + krb5_principal principal; /* Kerberos principal */ + + +# ifdef __APPLE__ + /* + * If the weak-linked GSSAPI/Kerberos library is not present, don't try + * to use it... + */ + + if (krb5_init_context != NULL) + { +# endif /* __APPLE__ */ + + /* + * We MUST create a file-based cache because memory-based caches are + * only valid for the current process/address space. + * + * Due to various bugs/features in different versions of Kerberos, we + * need either the krb5_cc_new_unique() function or Heimdal's version + * of krb5_cc_gen_new() to create a new FILE: credential cache that + * can be passed to the backend. These functions create a temporary + * file (typically in /tmp) containing the cached credentials, which + * are removed when we have successfully printed a job. + */ + +# ifdef HAVE_KRB5_CC_NEW_UNIQUE + if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL, + &ccache)) != 0) +# else /* HAVE_HEIMDAL */ + if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops, + &ccache)) != 0) +# endif /* HAVE_KRB5_CC_NEW_UNIQUE */ + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create new credentials cache (%d/%s)", + error, strerror(errno)); + ccache = NULL; + } + else if ((error = krb5_parse_name(KerberosContext, con->username, + &principal)) != 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to parse kerberos username (%d/%s)", error, + strerror(errno)); + krb5_cc_destroy(KerberosContext, ccache); + ccache = NULL; + } + else if ((error = krb5_cc_initialize(KerberosContext, ccache, + principal))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to initialize credentials cache (%d/%s)", error, + strerror(errno)); + krb5_cc_destroy(KerberosContext, ccache); + krb5_free_principal(KerberosContext, principal); + ccache = NULL; + } + else + { + krb5_free_principal(KerberosContext, principal); + + /* + * Copy the user's credentials to the new cache file... + */ + + 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(KerberosContext, ccache); + ccache = NULL; + } + else + { + /* + * Add the KRB5CCNAME environment variable to the job so that the + * backend can use the credentials when printing. + */ + + snprintf(krb5ccname, sizeof(krb5ccname), "KRB5CCNAME=FILE:%s", + krb5_cc_get_name(KerberosContext, ccache)); + envp[envc++] = krb5ccname; + + if (!RunUser) + chown(krb5_cc_get_name(KerberosContext, ccache), User, Group); + } + } +# ifdef __APPLE__ + } +# endif /* __APPLE__ */ +# endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */ + } +#endif /* HAVE_GSSAPI */ + } if (con->http.version == HTTP_1_1) @@ -4589,7 +4707,11 @@ */ if (con->username[0]) - cupsdAddCert(pid, con->username); +#ifdef HAVE_GSSAPI + cupsdAddCert(pid, con->username, ccache); +#else + cupsdAddCert(pid, con->username, NULL); +#endif /* HAVE_GSSAPI */ cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] %s started - PID = %d", command, pid); Index: cert.c =================================================================== --- cert.c (revision 7232) +++ cert.c (working copy) @@ -4,7 +4,7 @@ * Authentication certificate routines for the Common UNIX * Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -42,7 +42,8 @@ void cupsdAddCert(int pid, /* I - Process ID */ - const char *username) /* I - Username */ + const char *username, /* I - Username */ + void *ccache) /* I - Kerberos credentials or NULL */ { int i; /* Looping var */ cupsd_cert_t *cert; /* Current certificate */ @@ -244,6 +245,16 @@ close(fd); /* + * Add Kerberos credentials as needed... + */ + +#ifdef HAVE_GSSAPI + cert->ccache = (krb5_ccache)ccache; +#else + (void)ccache; +#endif /* HAVE_GSSAPI */ + + /* * Insert the certificate at the front of the list... */ @@ -282,6 +293,15 @@ else prev->next = cert->next; +#ifdef HAVE_GSSAPI + /* + * Release Kerberos credentials as needed... + */ + + if (cert->ccache) + krb5_cc_destroy(KerberosContext, cert->ccache); +#endif /* HAVE_GSSAPI */ + free(cert); /* @@ -412,7 +432,7 @@ */ if (!RunUser) - cupsdAddCert(0, "root"); + cupsdAddCert(0, "root", NULL); } Index: cert.h =================================================================== --- cert.h (revision 7232) +++ cert.h (working copy) @@ -4,7 +4,7 @@ * Authentication certificate definitions for the Common UNIX * Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -24,6 +24,9 @@ int pid; /* Process ID (0 for root certificate) */ char certificate[33]; /* 32 hex characters, or 128 bits */ char username[33]; /* Authenticated username */ +#ifdef HAVE_GSSAPI + krb5_ccache ccache; /* Kerberos credential cache */ +#endif /* HAVE_GSSAPI */ } cupsd_cert_t; @@ -39,7 +42,8 @@ * Prototypes... */ -extern void cupsdAddCert(int pid, const char *username); +extern void cupsdAddCert(int pid, const char *username, + void *ccache); extern void cupsdDeleteCert(int pid); extern void cupsdDeleteAllCerts(void); extern const char *cupsdFindCert(const char *certificate); Index: job.c =================================================================== --- job.c (revision 7233) +++ job.c (working copy) @@ -1820,6 +1820,7 @@ cupsdClearString(&job->auth_username); cupsdClearString(&job->auth_domain); cupsdClearString(&job->auth_password); + #ifdef HAVE_GSSAPI /* * Destroy the credential cache and clear the KRB5CCNAME env var string. Index: main.c =================================================================== --- main.c (revision 7232) +++ main.c (working copy) @@ -946,7 +946,7 @@ */ cupsdDeleteCert(0); - cupsdAddCert(0, "root"); + cupsdAddCert(0, "root", NULL); } /*