2 * Authorization routines for the CUPS scheduler.
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7 * This file contains Kerberos support code, copyright 2006 by
10 * Licensed under Apache License v2.0. See the file "LICENSE" for more
15 * Include necessary headers...
22 #endif /* HAVE_SHADOW_H */
25 #endif /* HAVE_CRYPT_H */
27 # ifdef HAVE_PAM_PAM_APPL_H
28 # include <pam/pam_appl.h>
30 # include <security/pam_appl.h>
31 # endif /* HAVE_PAM_PAM_APPL_H */
32 #endif /* HAVE_LIBPAM */
33 #ifdef HAVE_MEMBERSHIP_H
34 # include <membership.h>
35 #endif /* HAVE_MEMBERSHIP_H */
36 #ifdef HAVE_AUTHORIZATION_H
37 # include <Security/AuthorizationTags.h>
38 # ifdef HAVE_SECBASEPRIV_H
39 # include <Security/SecBasePriv.h>
41 extern const char *cssmErrorString(int error
);
42 # endif /* HAVE_SECBASEPRIV_H */
43 #endif /* HAVE_AUTHORIZATION_H */
44 #ifdef HAVE_SYS_PARAM_H
45 # include <sys/param.h>
46 #endif /* HAVE_SYS_PARAM_H */
47 #ifdef HAVE_SYS_UCRED_H
48 # include <sys/ucred.h>
49 typedef struct xucred cupsd_ucred_t
;
50 # define CUPSD_UCRED_UID(c) (c).cr_uid
53 typedef struct ucred cupsd_ucred_t
;
55 typedef struct sockpeercred cupsd_ucred_t
;
57 # define CUPSD_UCRED_UID(c) (c).uid
58 #endif /* HAVE_SYS_UCRED_H */
65 #ifdef HAVE_AUTHORIZATION_H
66 static int check_authref(cupsd_client_t
*con
, const char *right
);
67 #endif /* HAVE_AUTHORIZATION_H */
68 static int compare_locations(cupsd_location_t
*a
,
70 static cupsd_authmask_t
*copy_authmask(cupsd_authmask_t
*am
, void *data
);
71 static void free_authmask(cupsd_authmask_t
*am
, void *data
);
73 static int pam_func(int, const struct pam_message
**,
74 struct pam_response
**, void *);
76 static void to64(char *s
, unsigned long v
, int n
);
77 #endif /* HAVE_LIBPAM */
85 typedef struct cupsd_authdata_s
/**** Authentication data ****/
87 char username
[HTTP_MAX_VALUE
], /* Username string */
88 password
[HTTP_MAX_VALUE
]; /* Password string */
90 #endif /* HAVE_LIBPAM */
94 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
97 int /* O - 1 on success, 0 on failure */
99 cups_array_t
**masks
, /* IO - Masks array (created as needed) */
100 const unsigned address
[4], /* I - IP address */
101 const unsigned netmask
[4]) /* I - IP netmask */
103 cupsd_authmask_t temp
; /* New host/domain mask */
106 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", masks
, *masks
, address
[0], address
[1], address
[2], address
[3], netmask
[0], netmask
[1], netmask
[2], netmask
[3]);
108 temp
.type
= CUPSD_AUTH_IP
;
109 memcpy(temp
.mask
.ip
.address
, address
, sizeof(temp
.mask
.ip
.address
));
110 memcpy(temp
.mask
.ip
.netmask
, netmask
, sizeof(temp
.mask
.ip
.netmask
));
113 * Create the masks array as needed and add...
117 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
118 (cups_acopy_func_t
)copy_authmask
,
119 (cups_afree_func_t
)free_authmask
);
121 return (cupsArrayAdd(*masks
, &temp
));
126 * 'cupsdAddLocation()' - Add a location for authorization.
130 cupsdAddLocation(cupsd_location_t
*loc
) /* I - Location to add */
133 * Make sure the locations array is created...
137 Locations
= cupsArrayNew3((cups_array_func_t
)compare_locations
, NULL
,
138 (cups_ahash_func_t
)NULL
, 0,
139 (cups_acopy_func_t
)NULL
,
140 (cups_afree_func_t
)cupsdFreeLocation
);
144 cupsArrayAdd(Locations
, loc
);
146 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddLocation: Added location \"%s\"", loc
->location
? loc
->location
: "(null)");
152 * 'cupsdAddName()' - Add a name to a location...
156 cupsdAddName(cupsd_location_t
*loc
, /* I - Location to add to */
157 char *name
) /* I - Name to add */
159 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddName(loc=%p, name=\"%s\")", loc
, name
);
162 loc
->names
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
163 (cups_acopy_func_t
)_cupsStrAlloc
,
164 (cups_afree_func_t
)_cupsStrFree
);
166 if (!cupsArrayAdd(loc
->names
, name
))
168 cupsdLogMessage(CUPSD_LOG_ERROR
,
169 "Unable to duplicate name for location %s: %s",
170 loc
->location
? loc
->location
: "nil", strerror(errno
));
177 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
180 int /* O - 1 on success, 0 on failure */
181 cupsdAddNameMask(cups_array_t
**masks
, /* IO - Masks array (created as needed) */
182 char *name
) /* I - Host or interface name */
184 cupsd_authmask_t temp
; /* New host/domain mask */
185 char ifname
[32], /* Interface name */
186 *ifptr
; /* Pointer to end of name */
189 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks
, *masks
, name
);
191 if (!_cups_strcasecmp(name
, "@LOCAL"))
194 * Deny *interface*...
197 temp
.type
= CUPSD_AUTH_INTERFACE
;
198 temp
.mask
.name
.name
= (char *)"*";
200 else if (!_cups_strncasecmp(name
, "@IF(", 4))
203 * Deny *interface*...
206 strlcpy(ifname
, name
+ 4, sizeof(ifname
));
208 ifptr
= ifname
+ strlen(ifname
) - 1;
210 if (ifptr
>= ifname
&& *ifptr
== ')')
216 temp
.type
= CUPSD_AUTH_INTERFACE
;
217 temp
.mask
.name
.name
= ifname
;
228 temp
.type
= CUPSD_AUTH_NAME
;
229 temp
.mask
.name
.name
= (char *)name
;
233 * Set the name length...
236 temp
.mask
.name
.length
= strlen(temp
.mask
.name
.name
);
239 * Create the masks array as needed and add...
243 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
244 (cups_acopy_func_t
)copy_authmask
,
245 (cups_afree_func_t
)free_authmask
);
247 return (cupsArrayAdd(*masks
, &temp
));
252 * 'cupsdAuthorize()' - Validate any authorization credentials.
256 cupsdAuthorize(cupsd_client_t
*con
) /* I - Client connection */
258 int type
; /* Authentication type */
259 const char *authorization
; /* Pointer into Authorization string */
260 char *ptr
, /* Pointer into string */
261 username
[HTTP_MAX_VALUE
],
262 /* Username string */
263 password
[HTTP_MAX_VALUE
];
264 /* Password string */
265 cupsd_cert_t
*localuser
; /* Certificate username */
269 * Locate the best matching location so we know what kind of
270 * authentication to expect...
273 con
->best
= cupsdFindBest(con
->uri
, httpGetState(con
->http
));
274 con
->type
= CUPSD_AUTH_NONE
;
276 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "con->uri=\"%s\", con->best=%p(%s)", con
->uri
, con
->best
, con
->best
? con
->best
->location
: "");
278 if (con
->best
&& con
->best
->type
!= CUPSD_AUTH_NONE
)
280 if (con
->best
->type
== CUPSD_AUTH_DEFAULT
)
281 type
= cupsdDefaultAuthType();
283 type
= con
->best
->type
;
286 type
= cupsdDefaultAuthType();
289 * Decode the Authorization string...
292 authorization
= httpGetField(con
->http
, HTTP_FIELD_AUTHORIZATION
);
299 #endif /* HAVE_GSSAPI */
301 #ifdef HAVE_AUTHORIZATION_H
304 AuthorizationFree(con
->authref
, kAuthorizationFlagDefaults
);
307 #endif /* HAVE_AUTHORIZATION_H */
312 * No authorization data provided, return early...
315 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "No authentication data provided.");
318 #ifdef HAVE_AUTHORIZATION_H
319 else if (!strncmp(authorization
, "AuthRef ", 8) &&
320 httpAddrLocalhost(httpGetAddress(con
->http
)))
322 OSStatus status
; /* Status */
323 char authdata
[HTTP_MAX_VALUE
];
324 /* Nonce value from client */
325 int authlen
; /* Auth string length */
326 AuthorizationItemSet
*authinfo
; /* Authorization item set */
329 * Get the Authorization Services data...
333 while (isspace(*authorization
& 255))
336 authlen
= sizeof(authdata
);
337 httpDecode64_2(authdata
, &authlen
, authorization
);
339 if (authlen
!= kAuthorizationExternalFormLength
)
341 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "External Authorization reference size is incorrect.");
345 if ((status
= AuthorizationCreateFromExternalForm((AuthorizationExternalForm
*)authdata
, &con
->authref
)) != 0)
347 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "AuthorizationCreateFromExternalForm returned %d (%s)", (int)status
, cssmErrorString(status
));
353 if (!AuthorizationCopyInfo(con
->authref
, kAuthorizationEnvironmentUsername
,
356 if (authinfo
->count
== 1 && authinfo
->items
[0].value
&&
357 authinfo
->items
[0].valueLength
>= 2)
359 strlcpy(username
, authinfo
->items
[0].value
, sizeof(username
));
361 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef.", username
);
364 AuthorizationFreeItemSet(authinfo
);
370 * No username in AuthRef, grab username using peer credentials...
373 struct passwd
*pwd
; /* Password entry for this user */
374 cupsd_ucred_t peercred
; /* Peer credentials */
375 socklen_t peersize
; /* Size of peer credentials */
377 peersize
= sizeof(peercred
);
379 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
381 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
385 if ((pwd
= getpwuid(CUPSD_UCRED_UID(peercred
))) == NULL
)
387 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred
));
391 strlcpy(username
, pwd
->pw_name
, sizeof(username
));
393 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef + PeerCred.", username
);
396 con
->type
= CUPSD_AUTH_BASIC
;
398 #endif /* HAVE_AUTHORIZATION_H */
399 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
400 else if (!strncmp(authorization
, "PeerCred ", 9) &&
401 con
->http
->hostaddr
->addr
.sa_family
== AF_LOCAL
&& con
->best
)
404 * Use peer credentials from domain socket connection...
407 struct passwd
*pwd
; /* Password entry for this user */
408 cupsd_ucred_t peercred
; /* Peer credentials */
409 socklen_t peersize
; /* Size of peer credentials */
410 #ifdef HAVE_AUTHORIZATION_H
411 const char *name
; /* Authorizing name */
412 int no_peer
= 0; /* Don't allow peer credentials? */
415 * See if we should allow peer credentials...
418 for (name
= (char *)cupsArrayFirst(con
->best
->names
);
420 name
= (char *)cupsArrayNext(con
->best
->names
))
422 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) ||
423 !_cups_strcasecmp(name
, "@SYSTEM"))
425 /* Normally don't want peer credentials if we need an auth key... */
428 else if (!_cups_strcasecmp(name
, "@OWNER"))
430 /* but if @OWNER is present then we allow it... */
438 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
441 #endif /* HAVE_AUTHORIZATION_H */
443 if ((pwd
= getpwnam(authorization
+ 9)) == NULL
)
445 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "User \"%s\" does not exist.", authorization
+ 9);
449 peersize
= sizeof(peercred
);
452 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
454 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
, &peersize
))
455 # endif /* __APPLE__ */
457 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
461 if (pwd
->pw_uid
!= CUPSD_UCRED_UID(peercred
))
463 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization
+ 9, CUPSD_UCRED_UID(peercred
), pwd
->pw_uid
);
464 # ifdef HAVE_SYS_UCRED_H
465 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_version=%d", peercred
.cr_version
);
466 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_uid=%d", peercred
.cr_uid
);
467 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_ngroups=%d", peercred
.cr_ngroups
);
468 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_groups[0]=%d", peercred
.cr_groups
[0]);
469 # endif /* HAVE_SYS_UCRED_H */
473 strlcpy(username
, authorization
+ 9, sizeof(username
));
476 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
477 # endif /* HAVE_GSSAPI */
479 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using PeerCred.", username
);
481 con
->type
= CUPSD_AUTH_BASIC
;
483 #endif /* SO_PEERCRED && AF_LOCAL */
484 else if (!strncmp(authorization
, "Local", 5) &&
485 httpAddrLocalhost(httpGetAddress(con
->http
)))
488 * Get Local certificate authentication data...
492 while (isspace(*authorization
& 255))
495 if ((localuser
= cupsdFindCert(authorization
)) == NULL
)
497 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Local authentication certificate not found.");
501 strlcpy(username
, localuser
->username
, sizeof(username
));
502 con
->type
= localuser
->type
;
504 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using Local.", username
);
506 else if (!strncmp(authorization
, "Basic", 5))
509 * Get the Basic authentication data...
512 int userlen
; /* Username:password length */
516 while (isspace(*authorization
& 255))
519 userlen
= sizeof(username
);
520 httpDecode64_2(username
, &userlen
, authorization
);
523 * Pull the username and password out...
526 if ((ptr
= strchr(username
, ':')) == NULL
)
528 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Missing Basic password.");
537 * Username must not be empty...
540 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic username.");
547 * Password must not be empty...
550 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic password.");
554 strlcpy(password
, ptr
, sizeof(password
));
557 * Validate the username and password...
563 case CUPSD_AUTH_BASIC
:
567 * Only use PAM to do authentication. This supports MD5
568 * passwords, among other things...
571 pam_handle_t
*pamh
; /* PAM authentication handle */
572 int pamerr
; /* PAM error code */
573 struct pam_conv pamdata
;/* PAM conversation data */
574 cupsd_authdata_t data
; /* Authentication data */
577 strlcpy(data
.username
, username
, sizeof(data
.username
));
578 strlcpy(data
.password
, password
, sizeof(data
.password
));
581 pamdata
.conv
= (int (*)(int, struct pam_message
**,
582 struct pam_response
**,
585 pamdata
.conv
= pam_func
;
587 pamdata
.appdata_ptr
= &data
;
589 pamerr
= pam_start("cups", username
, &pamdata
, &pamh
);
590 if (pamerr
!= PAM_SUCCESS
)
592 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_start() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
596 # ifdef HAVE_PAM_SET_ITEM
598 pamerr
= pam_set_item(pamh
, PAM_RHOST
, con
->http
->hostname
);
599 if (pamerr
!= PAM_SUCCESS
)
600 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
601 # endif /* PAM_RHOST */
604 pamerr
= pam_set_item(pamh
, PAM_TTY
, "cups");
605 if (pamerr
!= PAM_SUCCESS
)
606 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
607 # endif /* PAM_TTY */
608 # endif /* HAVE_PAM_SET_ITEM */
610 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
611 if (pamerr
!= PAM_SUCCESS
)
613 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_authenticate() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
618 # ifdef HAVE_PAM_SETCRED
619 pamerr
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
| PAM_SILENT
);
620 if (pamerr
!= PAM_SUCCESS
)
621 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_setcred() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
622 # endif /* HAVE_PAM_SETCRED */
624 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
625 if (pamerr
!= PAM_SUCCESS
)
627 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_acct_mgmt() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
632 pam_end(pamh
, PAM_SUCCESS
);
636 * Use normal UNIX password file-based authentication...
639 char *pass
; /* Encrypted password */
640 struct passwd
*pw
; /* User password data */
641 # ifdef HAVE_SHADOW_H
642 struct spwd
*spw
; /* Shadow password data */
643 # endif /* HAVE_SHADOW_H */
646 pw
= getpwnam(username
); /* Get the current password */
647 endpwent(); /* Close the password file */
655 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unknown username \"%s\".", username
);
659 # ifdef HAVE_SHADOW_H
660 spw
= getspnam(username
);
663 if (!spw
&& !strcmp(pw
->pw_passwd
, "x"))
666 * Don't allow blank passwords!
669 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no shadow password.", username
);
673 if (spw
&& !spw
->sp_pwdp
[0] && !pw
->pw_passwd
[0])
675 if (!pw
->pw_passwd
[0])
676 # endif /* HAVE_SHADOW_H */
679 * Don't allow blank passwords!
682 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no password.", username
);
687 * OK, the password isn't blank, so compare with what came from the
691 pass
= crypt(password
, pw
->pw_passwd
);
693 if (!pass
|| strcmp(pw
->pw_passwd
, pass
))
695 # ifdef HAVE_SHADOW_H
698 pass
= crypt(password
, spw
->sp_pwdp
);
700 if (pass
== NULL
|| strcmp(spw
->sp_pwdp
, pass
))
702 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
707 # endif /* HAVE_SHADOW_H */
709 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
713 #endif /* HAVE_LIBPAM */
716 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Basic.", username
);
723 else if (!strncmp(authorization
, "Negotiate", 9))
725 int len
; /* Length of authorization string */
726 gss_ctx_id_t context
; /* Authorization context */
727 OM_uint32 major_status
, /* Major status code */
728 minor_status
; /* Minor status code */
729 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
,
730 /* Input token from string */
731 output_token
= GSS_C_EMPTY_BUFFER
;
732 /* Output token for username */
733 gss_name_t client_name
; /* Client name */
738 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
742 if (&gss_init_sec_context
== NULL
)
744 cupsdLogClient(con
, CUPSD_LOG_WARN
, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
747 # endif /* __APPLE__ */
750 * Find the start of the Kerberos input token...
754 while (isspace(*authorization
& 255))
759 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "No authentication data specified.");
764 * Decode the authorization string to get the input token...
767 len
= (int)strlen(authorization
);
768 input_token
.value
= malloc((size_t)len
);
769 input_token
.value
= httpDecode64_2(input_token
.value
, &len
,
771 input_token
.length
= (size_t)len
;
774 * Accept the input token to get the authorization info...
777 context
= GSS_C_NO_CONTEXT
;
778 client_name
= GSS_C_NO_NAME
;
779 major_status
= gss_accept_sec_context(&minor_status
,
783 GSS_C_NO_CHANNEL_BINDINGS
,
791 if (output_token
.length
> 0)
792 gss_release_buffer(&minor_status
, &output_token
);
794 if (GSS_ERROR(major_status
))
796 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error accepting GSSAPI security context.", con
->number
);
798 if (context
!= GSS_C_NO_CONTEXT
)
799 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
806 * Get the username associated with the client's credentials...
809 if (major_status
== GSS_S_CONTINUE_NEEDED
)
810 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Credentials not complete.", con
->number
);
811 else if (major_status
== GSS_S_COMPLETE
)
813 major_status
= gss_display_name(&minor_status
, client_name
,
814 &output_token
, NULL
);
816 if (GSS_ERROR(major_status
))
818 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error getting username.", con
->number
);
819 gss_release_name(&minor_status
, &client_name
);
820 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
824 strlcpy(username
, output_token
.value
, sizeof(username
));
826 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Negotiate.", username
);
828 gss_release_name(&minor_status
, &client_name
);
829 gss_release_buffer(&minor_status
, &output_token
);
831 con
->type
= CUPSD_AUTH_NEGOTIATE
;
834 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
836 # if defined(SO_PEERCRED) && defined(AF_LOCAL)
838 * Get the client's UID if we are printing locally - that allows a backend
839 * to run as the correct user to get Kerberos credentials of its own.
842 if (httpAddrFamily(con
->http
->hostaddr
) == AF_LOCAL
)
844 cupsd_ucred_t peercred
; /* Peer credentials */
845 socklen_t peersize
; /* Size of peer credentials */
847 peersize
= sizeof(peercred
);
850 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
852 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
,
854 # endif /* __APPLE__ */
856 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
860 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred
));
861 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
864 # endif /* SO_PEERCRED && AF_LOCAL */
866 #endif /* HAVE_GSSAPI */
869 char scheme
[256]; /* Auth scheme... */
872 if (sscanf(authorization
, "%255s", scheme
) != 1)
873 strlcpy(scheme
, "UNKNOWN", sizeof(scheme
));
875 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Bad authentication data \"%s ...\".", scheme
);
880 * If we get here, then we were able to validate the username and
881 * password - copy the validated username and password to the client
885 strlcpy(con
->username
, username
, sizeof(con
->username
));
886 strlcpy(con
->password
, password
, sizeof(con
->password
));
891 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
895 int /* O - 1 if allowed, 0 otherwise */
897 unsigned ip
[4], /* I - Client address */
898 const char *name
, /* I - Client hostname */
899 size_t namelen
, /* I - Length of hostname */
900 cupsd_location_t
*loc
) /* I - Location to check */
902 int allow
; /* 1 if allowed, 0 otherwise */
905 if (!_cups_strcasecmp(name
, "localhost"))
908 * Access from localhost (127.0.0.1 or ::1) is always allowed...
916 * Do authorization checks on the domain/address...
919 switch (loc
->order_type
)
922 allow
= 0; /* anti-compiler-warning-code */
925 case CUPSD_AUTH_ALLOW
: /* Order Deny,Allow */
928 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
931 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
935 case CUPSD_AUTH_DENY
: /* Order Allow,Deny */
938 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
941 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
952 * 'cupsdCheckAuth()' - Check authorization masks.
955 int /* O - 1 if mask matches, 0 otherwise */
956 cupsdCheckAuth(unsigned ip
[4], /* I - Client address */
957 const char *name
, /* I - Client hostname */
958 size_t name_len
, /* I - Length of hostname */
959 cups_array_t
*masks
) /* I - Masks */
961 int i
; /* Looping var */
962 cupsd_authmask_t
*mask
; /* Current mask */
963 cupsd_netif_t
*iface
; /* Network interface */
964 unsigned netip4
; /* IPv4 network address */
966 unsigned netip6
[4]; /* IPv6 network address */
967 #endif /* AF_INET6 */
970 for (mask
= (cupsd_authmask_t
*)cupsArrayFirst(masks
);
972 mask
= (cupsd_authmask_t
*)cupsArrayNext(masks
))
976 case CUPSD_AUTH_INTERFACE
:
978 * Check for a match with a network interface...
981 netip4
= htonl(ip
[3]);
984 netip6
[0] = htonl(ip
[0]);
985 netip6
[1] = htonl(ip
[1]);
986 netip6
[2] = htonl(ip
[2]);
987 netip6
[3] = htonl(ip
[3]);
988 #endif /* AF_INET6 */
992 if (!strcmp(mask
->mask
.name
.name
, "*"))
996 * Allow Back-to-My-Mac addresses...
999 if ((ip
[0] & 0xff000000) == 0xfd000000)
1001 #endif /* __APPLE__ */
1004 * Check against all local interfaces...
1007 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1009 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1012 * Only check local interfaces...
1015 if (!iface
->is_local
)
1018 if (iface
->address
.addr
.sa_family
== AF_INET
)
1021 * Check IPv4 address...
1024 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1025 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1026 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1033 * Check IPv6 address...
1036 for (i
= 0; i
< 4; i
++)
1037 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1038 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1039 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1045 #endif /* AF_INET6 */
1051 * Check the named interface...
1054 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1056 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1058 if (strcmp(mask
->mask
.name
.name
, iface
->name
))
1061 if (iface
->address
.addr
.sa_family
== AF_INET
)
1064 * Check IPv4 address...
1067 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1068 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1069 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1076 * Check IPv6 address...
1079 for (i
= 0; i
< 4; i
++)
1080 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1081 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1082 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1088 #endif /* AF_INET6 */
1093 case CUPSD_AUTH_NAME
:
1095 * Check for exact name match...
1098 if (!_cups_strcasecmp(name
, mask
->mask
.name
.name
))
1102 * Check for domain match...
1105 if (name_len
>= mask
->mask
.name
.length
&&
1106 mask
->mask
.name
.name
[0] == '.' &&
1107 !_cups_strcasecmp(name
+ name_len
- mask
->mask
.name
.length
,
1108 mask
->mask
.name
.name
))
1112 case CUPSD_AUTH_IP
:
1114 * Check for IP/network address match...
1117 for (i
= 0; i
< 4; i
++)
1118 if ((ip
[i
] & mask
->mask
.ip
.netmask
[i
]) !=
1119 mask
->mask
.ip
.address
[i
])
1133 * 'cupsdCheckGroup()' - Check for a user's group membership.
1136 int /* O - 1 if user is a member, 0 otherwise */
1138 const char *username
, /* I - User name */
1139 struct passwd
*user
, /* I - System user info */
1140 const char *groupname
) /* I - Group name */
1142 int i
; /* Looping var */
1143 struct group
*group
; /* Group info */
1144 gid_t groupid
; /* ID of named group */
1145 #ifdef HAVE_MBR_UID_TO_UUID
1146 uuid_t useruuid
, /* UUID for username */
1147 groupuuid
; /* UUID for groupname */
1148 int is_member
; /* True if user is a member of group */
1149 #endif /* HAVE_MBR_UID_TO_UUID */
1152 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username
, user
, groupname
);
1158 if (!username
|| !groupname
)
1162 * Check to see if the user is a member of the named group...
1165 group
= getgrnam(groupname
);
1171 * Group exists, check it...
1174 groupid
= group
->gr_gid
;
1176 #ifdef HAVE_GETGROUPLIST
1179 int ngroups
; /* Number of groups */
1181 int groups
[2048]; /* Groups that user belongs to */
1183 gid_t groups
[2048]; /* Groups that user belongs to */
1184 # endif /* __APPLE__ */
1186 ngroups
= (int)(sizeof(groups
) / sizeof(groups
[0]));
1188 getgrouplist(username
, (int)user
->pw_gid
, groups
, &ngroups
);
1190 getgrouplist(username
, user
->pw_gid
, groups
, &ngroups
);
1191 #endif /* __APPLE__ */
1193 for (i
= 0; i
< ngroups
; i
++)
1194 if ((int)groupid
== (int)groups
[i
])
1199 for (i
= 0; group
->gr_mem
[i
]; i
++)
1201 if (!_cups_strcasecmp(username
, group
->gr_mem
[i
]))
1204 #endif /* HAVE_GETGROUPLIST */
1207 groupid
= (gid_t
)-1;
1210 * Group doesn't exist or user not in group list, check the group ID
1211 * against the user's group ID...
1214 if (user
&& groupid
== user
->pw_gid
)
1217 #ifdef HAVE_MBR_UID_TO_UUID
1219 * Check group membership through macOS membership API...
1222 if (user
&& !mbr_uid_to_uuid(user
->pw_uid
, useruuid
))
1224 if (groupid
!= (gid_t
)-1)
1227 * Map group name to UUID and check membership...
1230 if (!mbr_gid_to_uuid(groupid
, groupuuid
))
1231 if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1235 else if (groupname
[0] == '#')
1238 * Use UUID directly and check for equality (user UUID) and
1239 * membership (group UUID)...
1242 if (!uuid_parse((char *)groupname
+ 1, groupuuid
))
1244 if (!uuid_compare(useruuid
, groupuuid
))
1246 else if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1254 else if (groupname
[0] == '#')
1256 #endif /* HAVE_MBR_UID_TO_UUID */
1259 * If we get this far, then the user isn't part of the named group...
1267 * 'cupsdCopyLocation()' - Make a copy of a location...
1270 cupsd_location_t
* /* O - New location */
1272 cupsd_location_t
*loc
) /* I - Original location */
1274 cupsd_location_t
*temp
; /* New location */
1278 * Make a copy of the original location...
1281 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1285 * Copy the information from the original location to the new one.
1292 temp
->location
= _cupsStrAlloc(loc
->location
);
1294 temp
->length
= loc
->length
;
1295 temp
->limit
= loc
->limit
;
1296 temp
->order_type
= loc
->order_type
;
1297 temp
->type
= loc
->type
;
1298 temp
->level
= loc
->level
;
1299 temp
->satisfy
= loc
->satisfy
;
1300 temp
->encryption
= loc
->encryption
;
1304 if ((temp
->names
= cupsArrayDup(loc
->names
)) == NULL
)
1306 cupsdLogMessage(CUPSD_LOG_ERROR
,
1307 "Unable to allocate memory for %d names: %s",
1308 cupsArrayCount(loc
->names
), strerror(errno
));
1310 cupsdFreeLocation(temp
);
1318 * Copy allow rules...
1321 if ((temp
->allow
= cupsArrayDup(loc
->allow
)) == NULL
)
1323 cupsdLogMessage(CUPSD_LOG_ERROR
,
1324 "Unable to allocate memory for %d allow rules: %s",
1325 cupsArrayCount(loc
->allow
), strerror(errno
));
1326 cupsdFreeLocation(temp
);
1334 * Copy deny rules...
1337 if ((temp
->deny
= cupsArrayDup(loc
->deny
)) == NULL
)
1339 cupsdLogMessage(CUPSD_LOG_ERROR
,
1340 "Unable to allocate memory for %d deny rules: %s",
1341 cupsArrayCount(loc
->deny
), strerror(errno
));
1342 cupsdFreeLocation(temp
);
1352 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1356 cupsdDeleteAllLocations(void)
1359 * Free the location array, which will free all of the locations...
1362 cupsArrayDelete(Locations
);
1368 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1371 cupsd_location_t
* /* O - Location that matches */
1372 cupsdFindBest(const char *path
, /* I - Resource path */
1373 http_state_t state
) /* I - HTTP state/request */
1375 char uri
[HTTP_MAX_URI
],
1376 /* URI in request... */
1377 *uriptr
; /* Pointer into URI */
1378 cupsd_location_t
*loc
, /* Current location */
1379 *best
; /* Best match for location so far */
1380 size_t bestlen
; /* Length of best match */
1381 int limit
; /* Limit field */
1382 static const int limits
[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1384 CUPSD_AUTH_LIMIT_ALL
,
1385 CUPSD_AUTH_LIMIT_OPTIONS
,
1386 CUPSD_AUTH_LIMIT_GET
,
1387 CUPSD_AUTH_LIMIT_GET
,
1388 CUPSD_AUTH_LIMIT_HEAD
,
1389 CUPSD_AUTH_LIMIT_POST
,
1390 CUPSD_AUTH_LIMIT_POST
,
1391 CUPSD_AUTH_LIMIT_POST
,
1392 CUPSD_AUTH_LIMIT_PUT
,
1393 CUPSD_AUTH_LIMIT_PUT
,
1394 CUPSD_AUTH_LIMIT_DELETE
,
1395 CUPSD_AUTH_LIMIT_TRACE
,
1396 CUPSD_AUTH_LIMIT_ALL
,
1397 CUPSD_AUTH_LIMIT_ALL
,
1398 CUPSD_AUTH_LIMIT_ALL
,
1399 CUPSD_AUTH_LIMIT_ALL
1404 * First copy the connection URI to a local string so we have drop
1405 * any .ppd extension from the pathname in /printers or /classes
1409 strlcpy(uri
, path
, sizeof(uri
));
1411 if ((uriptr
= strchr(uri
, '?')) != NULL
)
1412 *uriptr
= '\0'; /* Drop trailing query string */
1414 if ((uriptr
= uri
+ strlen(uri
) - 1) > uri
&& *uriptr
== '/')
1415 *uriptr
= '\0'; /* Remove trailing '/' */
1417 if (!strncmp(uri
, "/printers/", 10) ||
1418 !strncmp(uri
, "/classes/", 9))
1421 * Check if the URI has .ppd on the end...
1424 uriptr
= uri
+ strlen(uri
) - 4; /* len > 4 if we get here... */
1426 if (!strcmp(uriptr
, ".ppd"))
1431 * Loop through the list of locations to find a match...
1434 limit
= limits
[state
];
1438 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: uri=\"%s\", limit=%x...", uri
, limit
);
1441 for (loc
= (cupsd_location_t
*)cupsArrayFirst(Locations
);
1443 loc
= (cupsd_location_t
*)cupsArrayNext(Locations
))
1445 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: Location %s(%d) Limit %x", loc
->location
? loc
->location
: "(null)", (int)loc
->length
, loc
->limit
);
1447 if (!strncmp(uri
, "/printers/", 10) || !strncmp(uri
, "/classes/", 9))
1450 * Use case-insensitive comparison for queue names...
1453 if (loc
->length
> bestlen
&& loc
->location
&&
1454 !_cups_strncasecmp(uri
, loc
->location
, loc
->length
) &&
1455 loc
->location
[0] == '/' &&
1456 (limit
& loc
->limit
) != 0)
1459 bestlen
= loc
->length
;
1465 * Use case-sensitive comparison for other URIs...
1468 if (loc
->length
> bestlen
&& loc
->location
&&
1469 !strncmp(uri
, loc
->location
, loc
->length
) &&
1470 loc
->location
[0] == '/' &&
1471 (limit
& loc
->limit
) != 0)
1474 bestlen
= loc
->length
;
1480 * Return the match, if any...
1483 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: best=%s", best
? best
->location
: "NONE");
1490 * 'cupsdFindLocation()' - Find the named location.
1493 cupsd_location_t
* /* O - Location that matches */
1494 cupsdFindLocation(const char *location
) /* I - Connection */
1496 cupsd_location_t key
; /* Search key */
1499 key
.location
= (char *)location
;
1501 return ((cupsd_location_t
*)cupsArrayFind(Locations
, &key
));
1506 * 'cupsdFreeLocation()' - Free all memory used by a location.
1510 cupsdFreeLocation(cupsd_location_t
*loc
)/* I - Location to free */
1512 cupsArrayDelete(loc
->names
);
1513 cupsArrayDelete(loc
->allow
);
1514 cupsArrayDelete(loc
->deny
);
1516 _cupsStrFree(loc
->location
);
1522 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1525 http_status_t
/* O - HTTP_OK if authorized or error code */
1526 cupsdIsAuthorized(cupsd_client_t
*con
, /* I - Connection */
1527 const char *owner
)/* I - Owner of object */
1529 int i
, /* Looping vars */
1530 auth
, /* Authorization status */
1531 type
; /* Type of authentication */
1532 http_addr_t
*hostaddr
= httpGetAddress(con
->http
);
1533 /* Client address */
1534 const char *hostname
= httpGetHostname(con
->http
, NULL
, 0);
1535 /* Client hostname */
1536 unsigned address
[4]; /* Authorization address */
1537 cupsd_location_t
*best
; /* Best match for location so far */
1538 size_t hostlen
; /* Length of hostname */
1539 char *name
, /* Current username */
1540 username
[256], /* Username to authorize */
1541 ownername
[256], /* Owner name to authorize */
1542 *ptr
; /* Pointer into username */
1543 struct passwd
*pw
; /* User password data */
1544 static const char * const levels
[] = /* Auth levels */
1550 static const char * const types
[] = /* Auth types */
1558 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con
->uri
, con
->best
, con
->best
? con
->best
->location
? con
->best
->location
: "(null)" : "");
1560 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: owner=\"%s\"", owner
);
1563 * If there is no "best" authentication rule for this request, then
1564 * access is allowed from the local system and denied from other
1570 if (httpAddrLocalhost(httpGetAddress(con
->http
)) ||
1571 !strcmp(hostname
, ServerName
) ||
1572 cupsArrayFind(ServerAlias
, (void *)hostname
))
1575 return (HTTP_FORBIDDEN
);
1580 if ((type
= best
->type
) == CUPSD_AUTH_DEFAULT
)
1581 type
= cupsdDefaultAuthType();
1583 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d", levels
[best
->level
], types
[type
], best
->satisfy
? "ANY" : "ALL", cupsArrayCount(best
->names
));
1585 if (best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1586 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: op=%x(%s)", best
->op
, ippOpString(best
->op
));
1589 * Check host/ip-based accesses...
1593 if (httpAddrFamily(hostaddr
) == AF_INET6
)
1596 * Copy IPv6 address...
1599 address
[0] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[0]);
1600 address
[1] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[1]);
1601 address
[2] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[2]);
1602 address
[3] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[3]);
1605 #endif /* AF_INET6 */
1606 if (con
->http
->hostaddr
->addr
.sa_family
== AF_INET
)
1609 * Copy IPv4 address...
1615 address
[3] = ntohl(hostaddr
->ipv4
.sin_addr
.s_addr
);
1618 memset(address
, 0, sizeof(address
));
1620 hostlen
= strlen(hostname
);
1622 auth
= cupsdCheckAccess(address
, hostname
, hostlen
, best
)
1623 ? CUPSD_AUTH_ALLOW
: CUPSD_AUTH_DENY
;
1625 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth
? "DENY" : "ALLOW");
1627 if (auth
== CUPSD_AUTH_DENY
&& best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
)
1628 return (HTTP_FORBIDDEN
);
1632 * See if encryption is required...
1635 if ((best
->encryption
>= HTTP_ENCRYPT_REQUIRED
&& !con
->http
->tls
&&
1636 _cups_strcasecmp(hostname
, "localhost") &&
1637 !httpAddrLocalhost(hostaddr
) &&
1638 best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
) &&
1639 !(type
== CUPSD_AUTH_NEGOTIATE
||
1640 (type
== CUPSD_AUTH_NONE
&&
1641 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE
)))
1643 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1644 "cupsdIsAuthorized: Need upgrade to TLS...");
1645 return (HTTP_UPGRADE_REQUIRED
);
1647 #endif /* HAVE_SSL */
1650 * Now see what access level is required...
1653 if (best
->level
== CUPSD_AUTH_ANON
|| /* Anonymous access - allow it */
1654 (type
== CUPSD_AUTH_NONE
&& cupsArrayCount(best
->names
) == 0))
1657 if (!con
->username
[0] && type
== CUPSD_AUTH_NONE
&&
1658 best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1661 * Check for unauthenticated username...
1664 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
1667 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1670 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1671 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1672 attr
->values
[0].string
.text
);
1673 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
1675 else if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1676 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1678 return (HTTP_OK
); /* unless overridden with Satisfy */
1682 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: username=\"%s\"",
1685 #ifdef HAVE_AUTHORIZATION_H
1686 if (!con
->username
[0] && !con
->authref
)
1688 if (!con
->username
[0])
1689 #endif /* HAVE_AUTHORIZATION_H */
1691 if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1692 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1694 return (HTTP_OK
); /* unless overridden with Satisfy */
1698 if (con
->type
!= type
&& type
!= CUPSD_AUTH_NONE
&&
1700 (type
!= CUPSD_AUTH_NEGOTIATE
|| con
->gss_uid
<= 0) &&
1701 #endif /* HAVE_GSSAPI */
1702 con
->type
!= CUPSD_AUTH_BASIC
)
1704 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorized using %s, expected %s.",
1705 types
[con
->type
], types
[type
]);
1707 return (HTTP_UNAUTHORIZED
);
1710 strlcpy(username
, con
->username
, sizeof(username
));
1714 * OK, got a username. See if we need normal user access, or group
1715 * access... (root always matches)
1718 if (!strcmp(username
, "root"))
1722 * Strip any @domain or @KDC from the username and owner...
1725 if ((ptr
= strchr(username
, '@')) != NULL
)
1730 strlcpy(ownername
, owner
, sizeof(ownername
));
1732 if ((ptr
= strchr(ownername
, '@')) != NULL
)
1736 ownername
[0] = '\0';
1739 * Get the user info...
1744 pw
= getpwnam(username
);
1750 if (best
->level
== CUPSD_AUTH_USER
)
1753 * If there are no names associated with this location, then
1754 * any valid user is OK...
1757 if (cupsArrayCount(best
->names
) == 0)
1761 * Otherwise check the user list and return OK if this user is
1765 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking user membership...");
1767 #ifdef HAVE_AUTHORIZATION_H
1769 * If an authorization reference was supplied it must match a right name...
1774 for (name
= (char *)cupsArrayFirst(best
->names
);
1776 name
= (char *)cupsArrayNext(best
->names
))
1778 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) && check_authref(con
, name
+ 9))
1780 else if (!_cups_strcasecmp(name
, "@SYSTEM") && SystemGroupAuthKey
&&
1781 check_authref(con
, SystemGroupAuthKey
))
1785 return (HTTP_FORBIDDEN
);
1787 #endif /* HAVE_AUTHORIZATION_H */
1789 for (name
= (char *)cupsArrayFirst(best
->names
);
1791 name
= (char *)cupsArrayNext(best
->names
))
1793 if (!_cups_strcasecmp(name
, "@OWNER") && owner
&&
1794 !_cups_strcasecmp(username
, ownername
))
1796 else if (!_cups_strcasecmp(name
, "@SYSTEM"))
1798 for (i
= 0; i
< NumSystemGroups
; i
++)
1799 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1802 else if (name
[0] == '@')
1804 if (cupsdCheckGroup(username
, pw
, name
+ 1))
1807 else if (!_cups_strcasecmp(username
, name
))
1811 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1815 * Check to see if this user is in any of the named groups...
1818 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group membership...");
1821 * Check to see if this user is in any of the named groups...
1824 for (name
= (char *)cupsArrayFirst(best
->names
);
1826 name
= (char *)cupsArrayNext(best
->names
))
1828 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership...", name
);
1830 if (!_cups_strcasecmp(name
, "@SYSTEM"))
1832 for (i
= 0; i
< NumSystemGroups
; i
++)
1833 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1836 else if (cupsdCheckGroup(username
, pw
, name
))
1841 * The user isn't part of the specified group, so deny access...
1844 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: User not in group(s).");
1846 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1851 * 'cupsdNewLocation()' - Create a new location for authorization.
1853 * Note: Still need to call cupsdAddLocation() to add it to the list of global
1857 cupsd_location_t
* /* O - Pointer to new location record */
1858 cupsdNewLocation(const char *location
) /* I - Location path */
1860 cupsd_location_t
*temp
; /* New location */
1864 * Try to allocate memory for the new location.
1867 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1871 * Initialize the record and copy the name over...
1874 if ((temp
->location
= _cupsStrAlloc(location
)) == NULL
)
1880 temp
->length
= strlen(temp
->location
);
1883 * Return the new record...
1890 #ifdef HAVE_AUTHORIZATION_H
1892 * 'check_authref()' - Check if an authorization services reference has the
1896 static int /* O - 1 if right is valid, 0 otherwise */
1897 check_authref(cupsd_client_t
*con
, /* I - Connection */
1898 const char *right
) /* I - Right name */
1900 OSStatus status
; /* OS Status */
1901 AuthorizationItem authright
; /* Authorization right */
1902 AuthorizationRights authrights
; /* Authorization rights */
1903 AuthorizationFlags authflags
; /* Authorization flags */
1907 * Check to see if the user is allowed to perform the task...
1913 authright
.name
= right
;
1914 authright
.valueLength
= 0;
1915 authright
.value
= NULL
;
1916 authright
.flags
= 0;
1918 authrights
.count
= 1;
1919 authrights
.items
= &authright
;
1921 authflags
= kAuthorizationFlagDefaults
|
1922 kAuthorizationFlagExtendRights
;
1924 if ((status
= AuthorizationCopyRights(con
->authref
, &authrights
,
1925 kAuthorizationEmptyEnvironment
,
1926 authflags
, NULL
)) != 0)
1928 cupsdLogMessage(CUPSD_LOG_ERROR
,
1929 "AuthorizationCopyRights(\"%s\") returned %d (%s)",
1930 authright
.name
, (int)status
, cssmErrorString(status
));
1934 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "AuthorizationCopyRights(\"%s\") succeeded.", authright
.name
);
1938 #endif /* HAVE_AUTHORIZATION_H */
1942 * 'compare_locations()' - Compare two locations.
1945 static int /* O - Result of comparison */
1946 compare_locations(cupsd_location_t
*a
, /* I - First location */
1947 cupsd_location_t
*b
) /* I - Second location */
1949 return (strcmp(b
->location
, a
->location
));
1954 * 'copy_authmask()' - Copy function for auth masks.
1957 static cupsd_authmask_t
* /* O - New auth mask */
1958 copy_authmask(cupsd_authmask_t
*mask
, /* I - Existing auth mask */
1959 void *data
) /* I - User data (unused) */
1961 cupsd_authmask_t
*temp
; /* New auth mask */
1966 if ((temp
= malloc(sizeof(cupsd_authmask_t
))) != NULL
)
1968 memcpy(temp
, mask
, sizeof(cupsd_authmask_t
));
1970 if (temp
->type
== CUPSD_AUTH_NAME
|| temp
->type
== CUPSD_AUTH_INTERFACE
)
1973 * Make a copy of the name...
1976 if ((temp
->mask
.name
.name
= _cupsStrAlloc(temp
->mask
.name
.name
)) == NULL
)
1979 * Failed to make copy...
1993 * 'free_authmask()' - Free function for auth masks.
1997 free_authmask(cupsd_authmask_t
*mask
, /* I - Auth mask to free */
1998 void *data
) /* I - User data (unused) */
2002 if (mask
->type
== CUPSD_AUTH_NAME
|| mask
->type
== CUPSD_AUTH_INTERFACE
)
2003 _cupsStrFree(mask
->mask
.name
.name
);
2011 * 'pam_func()' - PAM conversation function.
2014 static int /* O - Success or failure */
2016 int num_msg
, /* I - Number of messages */
2017 const struct pam_message
**msg
, /* I - Messages */
2018 struct pam_response
**resp
, /* O - Responses */
2020 /* I - Pointer to connection */
2022 int i
; /* Looping var */
2023 struct pam_response
*replies
; /* Replies */
2024 cupsd_authdata_t
*data
; /* Pointer to auth data */
2028 * Allocate memory for the responses...
2031 if ((replies
= malloc(sizeof(struct pam_response
) * (size_t)num_msg
)) == NULL
)
2032 return (PAM_CONV_ERR
);
2035 * Answer all of the messages...
2038 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr
));
2040 data
= (cupsd_authdata_t
*)appdata_ptr
;
2042 for (i
= 0; i
< num_msg
; i
++)
2044 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg
[i
]->msg
));
2046 switch (msg
[i
]->msg_style
)
2048 case PAM_PROMPT_ECHO_ON
:
2049 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2051 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2052 replies
[i
].resp
= strdup(data
->username
);
2055 case PAM_PROMPT_ECHO_OFF
:
2056 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2058 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2059 replies
[i
].resp
= strdup(data
->password
);
2063 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2064 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2065 replies
[i
].resp
= NULL
;
2069 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2070 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2071 replies
[i
].resp
= NULL
;
2075 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2076 msg
[i
]->msg_style
));
2078 return (PAM_CONV_ERR
);
2083 * Return the responses back to PAM...
2088 return (PAM_SUCCESS
);
2094 * 'to64()' - Base64-encode an integer value...
2098 to64(char *s
, /* O - Output string */
2099 unsigned long v
, /* I - Value to encode */
2100 int n
) /* I - Number of digits */
2102 const char *itoa64
= "./0123456789"
2103 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2104 "abcdefghijklmnopqrstuvwxyz";
2107 for (; n
> 0; n
--, v
>>= 6)
2108 *s
++ = itoa64
[v
& 0x3f];
2110 #endif /* HAVE_LIBPAM */