/*
- * "$Id: auth.c 6361 2007-03-19 16:01:28Z mike $"
+ * "$Id: auth.c 6947 2007-09-12 21:09:49Z mike $"
*
* Authorization routines for the Common UNIX Printing System (CUPS).
*
+ * Copyright 2007 by Apple Inc.
* 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
- * 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
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
extern const char *cssmErrorString(int error);
# endif /* HAVE_SECBASEPRIV_H */
#endif /* HAVE_AUTHORIZATION_H */
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+#ifdef HAVE_SYS_UCRED_H
+# include <sys/ucred.h>
+typedef struct xucred cupsd_ucred_t;
+# define CUPSD_UCRED_UID(c) (c).cr_uid
+#else
+typedef struct ucred cupsd_ucred_t;
+# define CUPSD_UCRED_UID(c) (c).uid
+#endif /* HAVE_SYS_UCRED_H */
/*
int type; /* Authentication type */
const char *authorization; /* Pointer into Authorization string */
char *ptr, /* Pointer into string */
- username[65], /* Username string */
+ username[256], /* Username string */
password[33]; /* Password string */
const char *localuser; /* Certificate username */
char nonce[HTTP_MAX_VALUE], /* Nonce value from client */
con->uri, con->best, con->best ? con->best->location : "");
if (con->best && con->best->type != AUTH_NONE)
- type = con->best->type;
+ {
+ if (con->best->type == AUTH_DEFAULT)
+ type = DefaultAuthType;
+ else
+ type = con->best->type;
+ }
else
type = DefaultAuthType;
if (authlen != kAuthorizationExternalFormLength)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdAuthorize: External Authorization reference size"
- "is incorrect!");
+ "External Authorization reference size is incorrect!");
return;
}
(AuthorizationExternalForm *)nonce, &con->authref)) != 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdAuthorize: AuthorizationCreateFromExternalForm "
- "returned %d (%s)",
+ "AuthorizationCreateFromExternalForm returned %d (%s)",
(int)status, cssmErrorString(status));
return;
}
&authinfo)) != 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdAuthorize: AuthorizationCopyInfo returned %d (%s)",
+ "AuthorizationCopyInfo returned %d (%s)",
(int)status, cssmErrorString(status));
return;
}
if (authinfo->count == 1)
strlcpy(username, authinfo->items[0].value, sizeof(username));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using AuthRef",
+ username);
+
AuthorizationFreeItemSet(authinfo);
}
#endif /* HAVE_AUTHORIZATION_H */
+#if defined(SO_PEERCRED) && defined(AF_LOCAL)
+ else if (!strncmp(authorization, "PeerCred ", 9) &&
+ con->http.hostaddr->addr.sa_family == AF_LOCAL)
+ {
+ /*
+ * Use peer credentials from domain socket connection...
+ */
+
+ struct passwd *pwd; /* Password entry for this user */
+ cupsd_ucred_t peercred; /* Peer credentials */
+ socklen_t peersize; /* Size of peer credentials */
+
+
+ if ((pwd = getpwnam(authorization + 9)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "User \"%s\" does not exist!",
+ authorization + 9);
+ return;
+ }
+
+ peersize = sizeof(peercred);
+
+ if (getsockopt(con->http.fd, SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s",
+ strerror(errno));
+ return;
+ }
+
+ if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Invalid peer credentials for \"%s\" - got %d, "
+ "expected %d!", authorization + 9,
+ CUPSD_UCRED_UID(peercred), pwd->pw_uid);
+# ifdef HAVE_SYS_UCRED_H
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_version=%d",
+ peercred.cr_version);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_uid=%d",
+ peercred.cr_uid);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_ngroups=%d",
+ peercred.cr_ngroups);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_groups[0]=%d",
+ peercred.cr_groups[0]);
+# endif /* HAVE_SYS_UCRED_H */
+ return;
+ }
+
+ strlcpy(username, authorization + 9, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using PeerCred",
+ username);
+ }
+#endif /* SO_PEERCRED && AF_LOCAL */
else if (!strncmp(authorization, "Local", 5) &&
!strcasecmp(con->http.hostname, "localhost"))
{
authorization ++;
if ((localuser = cupsdFindCert(authorization)) != NULL)
+ {
strlcpy(username, localuser, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Local",
+ username);
+ }
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
}
#endif /* HAVE_LIBPAM */
}
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Basic",
+ username);
break;
case AUTH_BASICDIGEST :
username);
return;
}
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using BasicDigest",
+ username);
break;
}
}
username);
return;
}
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Digest",
+ username);
}
#ifdef HAVE_GSSAPI
- else if (!strncmp(authorization, "Negotiate", 9) && type == AUTH_NEGOTIATE)
+ else if (!strncmp(authorization, "Negotiate", 9))
{
int len; /* Length of authorization string */
gss_cred_id_t server_creds; /* Server credentials */
output_token = GSS_C_EMPTY_BUFFER;
/* Output token for username */
gss_name_t client_name; /* Client name */
+ unsigned int ret_flags; /* Credential flags */
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (gss_init_sec_context == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "GSSAPI/Kerberos authentication failed because the "
+ "Kerberos framework is not present.");
+ return;
+ }
+# endif /* __APPLE__ */
con->gss_output_token.length = 0;
*/
if ((server_creds = get_gss_creds(GSSServiceName)) == NULL)
- {
- con->no_negotiate = 1;
return;
- }
/*
* Decode the authorization string to get the input token...
&client_name,
NULL,
&con->gss_output_token,
- NULL,
+ &ret_flags,
NULL,
&con->gss_delegated_cred);
if (context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
- con->no_negotiate = 1;
+ gss_release_cred(&minor_status, &server_creds);
return;
}
/*
- * Get the username associated with the credentials...
+ * Release our credentials...
+ */
+
+ gss_release_cred(&minor_status, &server_creds);
+
+ /*
+ * Get the username associated with the client's credentials...
*/
- if (major_status == GSS_S_COMPLETE)
+ if (!con->gss_delegated_cred)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: No delegated credentials!");
+
+ if (major_status == GSS_S_CONTINUE_NEEDED)
+ cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
+ "cupsdAuthorize: Credentials not complete");
+ else if (major_status == GSS_S_COMPLETE)
{
major_status = gss_display_name(&minor_status, client_name,
&output_token, NULL);
"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));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Negotiate",
+ username);
+
gss_release_buffer(&minor_status, &output_token);
gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+
+ con->gss_have_creds = 1;
}
else
gss_release_name(&minor_status, &client_name);
}
#endif /* HAVE_GSSAPI */
- else
+ else if (type != AUTH_NONE)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdAuthorize: Bad authentication data.");
+ char scheme[256]; /* Auth scheme... */
+ static const char * const types[] = /* Auth types */
+ {
+ "None",
+ "Basic",
+ "Digest",
+ "BasicDigest",
+ "Negotiate"
+ };
+
+
+ if (sscanf(authorization, "%255s", scheme) != 1)
+ strcpy(scheme, "UNKNOWN");
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad authentication data \"%s ...\", expected \"%s ...\"",
+ scheme, types[type]);
return;
}
strlcpy(con->username, username, sizeof(con->username));
strlcpy(con->password, password, sizeof(con->password));
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: username=\"%s\"",
- con->username);
}
unsigned address[4]; /* Authorization address */
cupsd_location_t *best; /* Best match for location so far */
int hostlen; /* Length of hostname */
- const char *username; /* Username to authorize */
+ char username[256], /* Username to authorize */
+ ownername[256], /* Owner name to authorize */
+ *ptr; /* Pointer into username */
struct passwd *pw; /* User password data */
static const char * const levels[] = /* Auth levels */
{
!(best->type == AUTH_NEGOTIATE ||
(best->type == AUTH_NONE && DefaultAuthType == AUTH_NEGOTIATE)))
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdIsAuthorized: Need upgrade to TLS...");
return (HTTP_UPGRADE_REQUIRED);
}
attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
if (attr)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdIsAuthorized: requesting-user-name=\"%s\"",
attr->values[0].string.text);
- username = attr->values[0].string.text;
+ strlcpy(username, attr->values[0].string.text, sizeof(username));
}
else if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
}
else
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"",
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
con->username);
#ifdef HAVE_AUTHORIZATION_H
return (HTTP_OK); /* unless overridden with Satisfy */
}
- username = con->username;
+ strlcpy(username, con->username, sizeof(username));
}
/*
if (!strcmp(username, "root"))
return (HTTP_OK);
+ /*
+ * Strip any @domain or @KDC from the username and owner...
+ */
+
+ if ((ptr = strchr(username, '@')) != NULL)
+ *ptr = '\0';
+
+ if (owner)
+ {
+ strlcpy(ownername, owner, sizeof(ownername));
+
+ if ((ptr = strchr(ownername, '@')) != NULL)
+ *ptr = '\0';
+ }
+ else
+ ownername[0] = '\0';
+
/*
* Get the user info...
*/
for (i = 0; i < best->num_names; i ++)
{
if (!strcasecmp(best->names[i], "@OWNER") && owner &&
- !strcasecmp(username, owner))
+ !strcasecmp(username, ownername))
return (HTTP_OK);
else if (!strcasecmp(best->names[i], "@SYSTEM"))
{
* The user isn't part of the specified group, so deny access...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdIsAuthorized: User not in group(s)!");
return (HTTP_UNAUTHORIZED);
return (NULL);
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Attempting to acquire credentials for %s...",
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_gss_creds: Attempting to acquire credentials for %s...",
(char *)token.value);
server_creds = GSS_C_NO_CREDENTIAL;
return (NULL);
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Credentials acquired successfully for %s.",
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_gss_creds: Credentials acquired successfully for %s.",
(char *)token.value);
gss_release_name(&minor_status, &server_name);
/*
- * End of "$Id: auth.c 6361 2007-03-19 16:01:28Z mike $".
+ * End of "$Id: auth.c 6947 2007-09-12 21:09:49Z mike $".
*/