2 * Authorization routines for the CUPS scheduler.
4 * Copyright 2007-2016 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 information.
14 * Include necessary headers...
21 #endif /* HAVE_SHADOW_H */
24 #endif /* HAVE_CRYPT_H */
26 # ifdef HAVE_PAM_PAM_APPL_H
27 # include <pam/pam_appl.h>
29 # include <security/pam_appl.h>
30 # endif /* HAVE_PAM_PAM_APPL_H */
31 #endif /* HAVE_LIBPAM */
32 #ifdef HAVE_MEMBERSHIP_H
33 # include <membership.h>
34 #endif /* HAVE_MEMBERSHIP_H */
35 #ifdef HAVE_AUTHORIZATION_H
36 # include <Security/AuthorizationTags.h>
37 # ifdef HAVE_SECBASEPRIV_H
38 # include <Security/SecBasePriv.h>
40 extern const char *cssmErrorString(int error
);
41 # endif /* HAVE_SECBASEPRIV_H */
42 #endif /* HAVE_AUTHORIZATION_H */
43 #ifdef HAVE_SYS_PARAM_H
44 # include <sys/param.h>
45 #endif /* HAVE_SYS_PARAM_H */
46 #ifdef HAVE_SYS_UCRED_H
47 # include <sys/ucred.h>
48 typedef struct xucred cupsd_ucred_t
;
49 # define CUPSD_UCRED_UID(c) (c).cr_uid
52 typedef struct ucred cupsd_ucred_t
;
54 typedef struct sockpeercred cupsd_ucred_t
;
56 # define CUPSD_UCRED_UID(c) (c).uid
57 #endif /* HAVE_SYS_UCRED_H */
64 #ifdef HAVE_AUTHORIZATION_H
65 static int check_authref(cupsd_client_t
*con
, const char *right
);
66 #endif /* HAVE_AUTHORIZATION_H */
67 static int compare_locations(cupsd_location_t
*a
,
69 static cupsd_authmask_t
*copy_authmask(cupsd_authmask_t
*am
, void *data
);
71 static char *cups_crypt(const char *pw
, const char *salt
);
72 #endif /* !HAVE_LIBPAM */
73 static void free_authmask(cupsd_authmask_t
*am
, void *data
);
75 static int pam_func(int, const struct pam_message
**,
76 struct pam_response
**, void *);
78 static void to64(char *s
, unsigned long v
, int n
);
79 #endif /* HAVE_LIBPAM */
87 typedef struct cupsd_authdata_s
/**** Authentication data ****/
89 char username
[HTTP_MAX_VALUE
], /* Username string */
90 password
[HTTP_MAX_VALUE
]; /* Password string */
92 #endif /* HAVE_LIBPAM */
96 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
99 int /* O - 1 on success, 0 on failure */
101 cups_array_t
**masks
, /* IO - Masks array (created as needed) */
102 const unsigned address
[4], /* I - IP address */
103 const unsigned netmask
[4]) /* I - IP netmask */
105 cupsd_authmask_t temp
; /* New host/domain mask */
108 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]);
110 temp
.type
= CUPSD_AUTH_IP
;
111 memcpy(temp
.mask
.ip
.address
, address
, sizeof(temp
.mask
.ip
.address
));
112 memcpy(temp
.mask
.ip
.netmask
, netmask
, sizeof(temp
.mask
.ip
.netmask
));
115 * Create the masks array as needed and add...
119 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
120 (cups_acopy_func_t
)copy_authmask
,
121 (cups_afree_func_t
)free_authmask
);
123 return (cupsArrayAdd(*masks
, &temp
));
128 * 'cupsdAddLocation()' - Add a location for authorization.
132 cupsdAddLocation(cupsd_location_t
*loc
) /* I - Location to add */
135 * Make sure the locations array is created...
139 Locations
= cupsArrayNew3((cups_array_func_t
)compare_locations
, NULL
,
140 (cups_ahash_func_t
)NULL
, 0,
141 (cups_acopy_func_t
)NULL
,
142 (cups_afree_func_t
)cupsdFreeLocation
);
146 cupsArrayAdd(Locations
, loc
);
148 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddLocation: Added location \"%s\"", loc
->location
? loc
->location
: "(null)");
154 * 'cupsdAddName()' - Add a name to a location...
158 cupsdAddName(cupsd_location_t
*loc
, /* I - Location to add to */
159 char *name
) /* I - Name to add */
161 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddName(loc=%p, name=\"%s\")", loc
, name
);
164 loc
->names
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
165 (cups_acopy_func_t
)_cupsStrAlloc
,
166 (cups_afree_func_t
)_cupsStrFree
);
168 if (!cupsArrayAdd(loc
->names
, name
))
170 cupsdLogMessage(CUPSD_LOG_ERROR
,
171 "Unable to duplicate name for location %s: %s",
172 loc
->location
? loc
->location
: "nil", strerror(errno
));
179 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
182 int /* O - 1 on success, 0 on failure */
183 cupsdAddNameMask(cups_array_t
**masks
, /* IO - Masks array (created as needed) */
184 char *name
) /* I - Host or interface name */
186 cupsd_authmask_t temp
; /* New host/domain mask */
187 char ifname
[32], /* Interface name */
188 *ifptr
; /* Pointer to end of name */
191 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks
, *masks
, name
);
193 if (!_cups_strcasecmp(name
, "@LOCAL"))
196 * Deny *interface*...
199 temp
.type
= CUPSD_AUTH_INTERFACE
;
200 temp
.mask
.name
.name
= (char *)"*";
202 else if (!_cups_strncasecmp(name
, "@IF(", 4))
205 * Deny *interface*...
208 strlcpy(ifname
, name
+ 4, sizeof(ifname
));
210 ifptr
= ifname
+ strlen(ifname
) - 1;
212 if (ifptr
>= ifname
&& *ifptr
== ')')
218 temp
.type
= CUPSD_AUTH_INTERFACE
;
219 temp
.mask
.name
.name
= ifname
;
230 temp
.type
= CUPSD_AUTH_NAME
;
231 temp
.mask
.name
.name
= (char *)name
;
235 * Set the name length...
238 temp
.mask
.name
.length
= strlen(temp
.mask
.name
.name
);
241 * Create the masks array as needed and add...
245 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
246 (cups_acopy_func_t
)copy_authmask
,
247 (cups_afree_func_t
)free_authmask
);
249 return (cupsArrayAdd(*masks
, &temp
));
254 * 'cupsdAuthorize()' - Validate any authorization credentials.
258 cupsdAuthorize(cupsd_client_t
*con
) /* I - Client connection */
260 int type
; /* Authentication type */
261 const char *authorization
; /* Pointer into Authorization string */
262 char *ptr
, /* Pointer into string */
263 username
[HTTP_MAX_VALUE
],
264 /* Username string */
265 password
[HTTP_MAX_VALUE
];
266 /* Password string */
267 cupsd_cert_t
*localuser
; /* Certificate username */
271 * Locate the best matching location so we know what kind of
272 * authentication to expect...
275 con
->best
= cupsdFindBest(con
->uri
, httpGetState(con
->http
));
276 con
->type
= CUPSD_AUTH_NONE
;
278 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "con->uri=\"%s\", con->best=%p(%s)", con
->uri
, con
->best
, con
->best
? con
->best
->location
: "");
280 if (con
->best
&& con
->best
->type
!= CUPSD_AUTH_NONE
)
282 if (con
->best
->type
== CUPSD_AUTH_DEFAULT
)
283 type
= cupsdDefaultAuthType();
285 type
= con
->best
->type
;
288 type
= cupsdDefaultAuthType();
291 * Decode the Authorization string...
294 authorization
= httpGetField(con
->http
, HTTP_FIELD_AUTHORIZATION
);
301 #endif /* HAVE_GSSAPI */
303 #ifdef HAVE_AUTHORIZATION_H
306 AuthorizationFree(con
->authref
, kAuthorizationFlagDefaults
);
309 #endif /* HAVE_AUTHORIZATION_H */
314 * No authorization data provided, return early...
317 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "No authentication data provided.");
320 #ifdef HAVE_AUTHORIZATION_H
321 else if (!strncmp(authorization
, "AuthRef ", 8) &&
322 httpAddrLocalhost(httpGetAddress(con
->http
)))
324 OSStatus status
; /* Status */
325 char authdata
[HTTP_MAX_VALUE
];
326 /* Nonce value from client */
327 int authlen
; /* Auth string length */
328 AuthorizationItemSet
*authinfo
; /* Authorization item set */
331 * Get the Authorization Services data...
335 while (isspace(*authorization
& 255))
338 authlen
= sizeof(authdata
);
339 httpDecode64_2(authdata
, &authlen
, authorization
);
341 if (authlen
!= kAuthorizationExternalFormLength
)
343 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "External Authorization reference size is incorrect.");
347 if ((status
= AuthorizationCreateFromExternalForm((AuthorizationExternalForm
*)authdata
, &con
->authref
)) != 0)
349 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "AuthorizationCreateFromExternalForm returned %d (%s)", (int)status
, cssmErrorString(status
));
355 if (!AuthorizationCopyInfo(con
->authref
, kAuthorizationEnvironmentUsername
,
358 if (authinfo
->count
== 1 && authinfo
->items
[0].value
&&
359 authinfo
->items
[0].valueLength
>= 2)
361 strlcpy(username
, authinfo
->items
[0].value
, sizeof(username
));
363 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef.", username
);
366 AuthorizationFreeItemSet(authinfo
);
372 * No username in AuthRef, grab username using peer credentials...
375 struct passwd
*pwd
; /* Password entry for this user */
376 cupsd_ucred_t peercred
; /* Peer credentials */
377 socklen_t peersize
; /* Size of peer credentials */
379 peersize
= sizeof(peercred
);
381 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
383 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
387 if ((pwd
= getpwuid(CUPSD_UCRED_UID(peercred
))) == NULL
)
389 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred
));
393 strlcpy(username
, pwd
->pw_name
, sizeof(username
));
395 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef + PeerCred.", username
);
398 con
->type
= CUPSD_AUTH_BASIC
;
400 #endif /* HAVE_AUTHORIZATION_H */
401 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
402 else if (!strncmp(authorization
, "PeerCred ", 9) &&
403 con
->http
->hostaddr
->addr
.sa_family
== AF_LOCAL
&& con
->best
)
406 * Use peer credentials from domain socket connection...
409 struct passwd
*pwd
; /* Password entry for this user */
410 cupsd_ucred_t peercred
; /* Peer credentials */
411 socklen_t peersize
; /* Size of peer credentials */
412 #ifdef HAVE_AUTHORIZATION_H
413 const char *name
; /* Authorizing name */
414 int no_peer
= 0; /* Don't allow peer credentials? */
417 * See if we should allow peer credentials...
420 for (name
= (char *)cupsArrayFirst(con
->best
->names
);
422 name
= (char *)cupsArrayNext(con
->best
->names
))
424 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) ||
425 !_cups_strcasecmp(name
, "@SYSTEM"))
427 /* Normally don't want peer credentials if we need an auth key... */
430 else if (!_cups_strcasecmp(name
, "@OWNER"))
432 /* but if @OWNER is present then we allow it... */
440 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
443 #endif /* HAVE_AUTHORIZATION_H */
445 if ((pwd
= getpwnam(authorization
+ 9)) == NULL
)
447 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "User \"%s\" does not exist.", authorization
+ 9);
451 peersize
= sizeof(peercred
);
454 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
456 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
, &peersize
))
457 # endif /* __APPLE__ */
459 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
463 if (pwd
->pw_uid
!= CUPSD_UCRED_UID(peercred
))
465 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization
+ 9, CUPSD_UCRED_UID(peercred
), pwd
->pw_uid
);
466 # ifdef HAVE_SYS_UCRED_H
467 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_version=%d", peercred
.cr_version
);
468 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_uid=%d", peercred
.cr_uid
);
469 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_ngroups=%d", peercred
.cr_ngroups
);
470 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_groups[0]=%d", peercred
.cr_groups
[0]);
471 # endif /* HAVE_SYS_UCRED_H */
475 strlcpy(username
, authorization
+ 9, sizeof(username
));
478 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
479 # endif /* HAVE_GSSAPI */
481 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using PeerCred.", username
);
483 con
->type
= CUPSD_AUTH_BASIC
;
485 #endif /* SO_PEERCRED && AF_LOCAL */
486 else if (!strncmp(authorization
, "Local", 5) &&
487 httpAddrLocalhost(httpGetAddress(con
->http
)))
490 * Get Local certificate authentication data...
494 while (isspace(*authorization
& 255))
497 if ((localuser
= cupsdFindCert(authorization
)) == NULL
)
499 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Local authentication certificate not found.");
503 strlcpy(username
, localuser
->username
, sizeof(username
));
504 con
->type
= localuser
->type
;
506 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using Local.", username
);
508 else if (!strncmp(authorization
, "Basic", 5))
511 * Get the Basic authentication data...
514 int userlen
; /* Username:password length */
518 while (isspace(*authorization
& 255))
521 userlen
= sizeof(username
);
522 httpDecode64_2(username
, &userlen
, authorization
);
525 * Pull the username and password out...
528 if ((ptr
= strchr(username
, ':')) == NULL
)
530 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Missing Basic password.");
539 * Username must not be empty...
542 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic username.");
549 * Password must not be empty...
552 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic password.");
556 strlcpy(password
, ptr
, sizeof(password
));
559 * Validate the username and password...
565 case CUPSD_AUTH_BASIC
:
569 * Only use PAM to do authentication. This supports MD5
570 * passwords, among other things...
573 pam_handle_t
*pamh
; /* PAM authentication handle */
574 int pamerr
; /* PAM error code */
575 struct pam_conv pamdata
;/* PAM conversation data */
576 cupsd_authdata_t data
; /* Authentication data */
579 strlcpy(data
.username
, username
, sizeof(data
.username
));
580 strlcpy(data
.password
, password
, sizeof(data
.password
));
583 pamdata
.conv
= (int (*)(int, struct pam_message
**,
584 struct pam_response
**,
587 pamdata
.conv
= pam_func
;
589 pamdata
.appdata_ptr
= &data
;
591 pamerr
= pam_start("cups", username
, &pamdata
, &pamh
);
592 if (pamerr
!= PAM_SUCCESS
)
594 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_start() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
598 # ifdef HAVE_PAM_SET_ITEM
600 pamerr
= pam_set_item(pamh
, PAM_RHOST
, con
->http
->hostname
);
601 if (pamerr
!= PAM_SUCCESS
)
602 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
603 # endif /* PAM_RHOST */
606 pamerr
= pam_set_item(pamh
, PAM_TTY
, "cups");
607 if (pamerr
!= PAM_SUCCESS
)
608 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
609 # endif /* PAM_TTY */
610 # endif /* HAVE_PAM_SET_ITEM */
612 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
613 if (pamerr
!= PAM_SUCCESS
)
615 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_authenticate() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
620 # ifdef HAVE_PAM_SETCRED
621 pamerr
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
| PAM_SILENT
);
622 if (pamerr
!= PAM_SUCCESS
)
623 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_setcred() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
624 # endif /* HAVE_PAM_SETCRED */
626 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
627 if (pamerr
!= PAM_SUCCESS
)
629 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_acct_mgmt() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
634 pam_end(pamh
, PAM_SUCCESS
);
638 * Use normal UNIX password file-based authentication...
641 char *pass
; /* Encrypted password */
642 struct passwd
*pw
; /* User password data */
643 # ifdef HAVE_SHADOW_H
644 struct spwd
*spw
; /* Shadow password data */
645 # endif /* HAVE_SHADOW_H */
648 pw
= getpwnam(username
); /* Get the current password */
649 endpwent(); /* Close the password file */
657 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unknown username \"%s\".", username
);
661 # ifdef HAVE_SHADOW_H
662 spw
= getspnam(username
);
665 if (!spw
&& !strcmp(pw
->pw_passwd
, "x"))
668 * Don't allow blank passwords!
671 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no shadow password.", username
);
675 if (spw
&& !spw
->sp_pwdp
[0] && !pw
->pw_passwd
[0])
677 if (!pw
->pw_passwd
[0])
678 # endif /* HAVE_SHADOW_H */
681 * Don't allow blank passwords!
684 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no password.", username
);
689 * OK, the password isn't blank, so compare with what came from the
693 pass
= cups_crypt(password
, pw
->pw_passwd
);
695 if (!pass
|| strcmp(pw
->pw_passwd
, pass
))
697 # ifdef HAVE_SHADOW_H
700 pass
= cups_crypt(password
, spw
->sp_pwdp
);
702 if (pass
== NULL
|| strcmp(spw
->sp_pwdp
, pass
))
704 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
709 # endif /* HAVE_SHADOW_H */
711 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
715 #endif /* HAVE_LIBPAM */
718 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Basic.", username
);
725 else if (!strncmp(authorization
, "Negotiate", 9))
727 int len
; /* Length of authorization string */
728 gss_ctx_id_t context
; /* Authorization context */
729 OM_uint32 major_status
, /* Major status code */
730 minor_status
; /* Minor status code */
731 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
,
732 /* Input token from string */
733 output_token
= GSS_C_EMPTY_BUFFER
;
734 /* Output token for username */
735 gss_name_t client_name
; /* Client name */
740 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
744 if (&gss_init_sec_context
== NULL
)
746 cupsdLogClient(con
, CUPSD_LOG_WARN
, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
749 # endif /* __APPLE__ */
752 * Find the start of the Kerberos input token...
756 while (isspace(*authorization
& 255))
761 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "No authentication data specified.");
766 * Decode the authorization string to get the input token...
769 len
= (int)strlen(authorization
);
770 input_token
.value
= malloc((size_t)len
);
771 input_token
.value
= httpDecode64_2(input_token
.value
, &len
,
773 input_token
.length
= (size_t)len
;
776 * Accept the input token to get the authorization info...
779 context
= GSS_C_NO_CONTEXT
;
780 client_name
= GSS_C_NO_NAME
;
781 major_status
= gss_accept_sec_context(&minor_status
,
785 GSS_C_NO_CHANNEL_BINDINGS
,
793 if (output_token
.length
> 0)
794 gss_release_buffer(&minor_status
, &output_token
);
796 if (GSS_ERROR(major_status
))
798 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error accepting GSSAPI security context.", con
->number
);
800 if (context
!= GSS_C_NO_CONTEXT
)
801 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
808 * Get the username associated with the client's credentials...
811 if (major_status
== GSS_S_CONTINUE_NEEDED
)
812 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Credentials not complete.", con
->number
);
813 else if (major_status
== GSS_S_COMPLETE
)
815 major_status
= gss_display_name(&minor_status
, client_name
,
816 &output_token
, NULL
);
818 if (GSS_ERROR(major_status
))
820 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error getting username.", con
->number
);
821 gss_release_name(&minor_status
, &client_name
);
822 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
826 strlcpy(username
, output_token
.value
, sizeof(username
));
828 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Negotiate.", username
);
830 gss_release_name(&minor_status
, &client_name
);
831 gss_release_buffer(&minor_status
, &output_token
);
833 con
->type
= CUPSD_AUTH_NEGOTIATE
;
836 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
838 # if defined(SO_PEERCRED) && defined(AF_LOCAL)
840 * Get the client's UID if we are printing locally - that allows a backend
841 * to run as the correct user to get Kerberos credentials of its own.
844 if (httpAddrFamily(con
->http
->hostaddr
) == AF_LOCAL
)
846 cupsd_ucred_t peercred
; /* Peer credentials */
847 socklen_t peersize
; /* Size of peer credentials */
849 peersize
= sizeof(peercred
);
852 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
854 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
,
856 # endif /* __APPLE__ */
858 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
862 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred
));
863 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
866 # endif /* SO_PEERCRED && AF_LOCAL */
868 #endif /* HAVE_GSSAPI */
871 char scheme
[256]; /* Auth scheme... */
874 if (sscanf(authorization
, "%255s", scheme
) != 1)
875 strlcpy(scheme
, "UNKNOWN", sizeof(scheme
));
877 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Bad authentication data \"%s ...\".", scheme
);
882 * If we get here, then we were able to validate the username and
883 * password - copy the validated username and password to the client
887 strlcpy(con
->username
, username
, sizeof(con
->username
));
888 strlcpy(con
->password
, password
, sizeof(con
->password
));
893 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
897 int /* O - 1 if allowed, 0 otherwise */
899 unsigned ip
[4], /* I - Client address */
900 const char *name
, /* I - Client hostname */
901 size_t namelen
, /* I - Length of hostname */
902 cupsd_location_t
*loc
) /* I - Location to check */
904 int allow
; /* 1 if allowed, 0 otherwise */
907 if (!_cups_strcasecmp(name
, "localhost"))
910 * Access from localhost (127.0.0.1 or ::1) is always allowed...
918 * Do authorization checks on the domain/address...
921 switch (loc
->order_type
)
924 allow
= 0; /* anti-compiler-warning-code */
927 case CUPSD_AUTH_ALLOW
: /* Order Deny,Allow */
930 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
933 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
937 case CUPSD_AUTH_DENY
: /* Order Allow,Deny */
940 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
943 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
954 * 'cupsdCheckAuth()' - Check authorization masks.
957 int /* O - 1 if mask matches, 0 otherwise */
958 cupsdCheckAuth(unsigned ip
[4], /* I - Client address */
959 const char *name
, /* I - Client hostname */
960 size_t name_len
, /* I - Length of hostname */
961 cups_array_t
*masks
) /* I - Masks */
963 int i
; /* Looping var */
964 cupsd_authmask_t
*mask
; /* Current mask */
965 cupsd_netif_t
*iface
; /* Network interface */
966 unsigned netip4
; /* IPv4 network address */
968 unsigned netip6
[4]; /* IPv6 network address */
969 #endif /* AF_INET6 */
972 for (mask
= (cupsd_authmask_t
*)cupsArrayFirst(masks
);
974 mask
= (cupsd_authmask_t
*)cupsArrayNext(masks
))
978 case CUPSD_AUTH_INTERFACE
:
980 * Check for a match with a network interface...
983 netip4
= htonl(ip
[3]);
986 netip6
[0] = htonl(ip
[0]);
987 netip6
[1] = htonl(ip
[1]);
988 netip6
[2] = htonl(ip
[2]);
989 netip6
[3] = htonl(ip
[3]);
990 #endif /* AF_INET6 */
994 if (!strcmp(mask
->mask
.name
.name
, "*"))
998 * Allow Back-to-My-Mac addresses...
1001 if ((ip
[0] & 0xff000000) == 0xfd000000)
1003 #endif /* __APPLE__ */
1006 * Check against all local interfaces...
1009 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1011 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1014 * Only check local interfaces...
1017 if (!iface
->is_local
)
1020 if (iface
->address
.addr
.sa_family
== AF_INET
)
1023 * Check IPv4 address...
1026 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1027 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1028 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1035 * Check IPv6 address...
1038 for (i
= 0; i
< 4; i
++)
1039 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1040 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1041 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1047 #endif /* AF_INET6 */
1053 * Check the named interface...
1056 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1058 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1060 if (strcmp(mask
->mask
.name
.name
, iface
->name
))
1063 if (iface
->address
.addr
.sa_family
== AF_INET
)
1066 * Check IPv4 address...
1069 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1070 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1071 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1078 * Check IPv6 address...
1081 for (i
= 0; i
< 4; i
++)
1082 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1083 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1084 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1090 #endif /* AF_INET6 */
1095 case CUPSD_AUTH_NAME
:
1097 * Check for exact name match...
1100 if (!_cups_strcasecmp(name
, mask
->mask
.name
.name
))
1104 * Check for domain match...
1107 if (name_len
>= mask
->mask
.name
.length
&&
1108 mask
->mask
.name
.name
[0] == '.' &&
1109 !_cups_strcasecmp(name
+ name_len
- mask
->mask
.name
.length
,
1110 mask
->mask
.name
.name
))
1114 case CUPSD_AUTH_IP
:
1116 * Check for IP/network address match...
1119 for (i
= 0; i
< 4; i
++)
1120 if ((ip
[i
] & mask
->mask
.ip
.netmask
[i
]) !=
1121 mask
->mask
.ip
.address
[i
])
1135 * 'cupsdCheckGroup()' - Check for a user's group membership.
1138 int /* O - 1 if user is a member, 0 otherwise */
1140 const char *username
, /* I - User name */
1141 struct passwd
*user
, /* I - System user info */
1142 const char *groupname
) /* I - Group name */
1144 int i
; /* Looping var */
1145 struct group
*group
; /* Group info */
1146 gid_t groupid
; /* ID of named group */
1147 #ifdef HAVE_MBR_UID_TO_UUID
1148 uuid_t useruuid
, /* UUID for username */
1149 groupuuid
; /* UUID for groupname */
1150 int is_member
; /* True if user is a member of group */
1151 #endif /* HAVE_MBR_UID_TO_UUID */
1154 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username
, user
, groupname
);
1160 if (!username
|| !groupname
)
1164 * Check to see if the user is a member of the named group...
1167 group
= getgrnam(groupname
);
1173 * Group exists, check it...
1176 groupid
= group
->gr_gid
;
1178 #ifdef HAVE_GETGROUPLIST
1181 int ngroups
; /* Number of groups */
1183 int groups
[2048]; /* Groups that user belongs to */
1185 gid_t groups
[2048]; /* Groups that user belongs to */
1186 # endif /* __APPLE__ */
1188 ngroups
= (int)(sizeof(groups
) / sizeof(groups
[0]));
1190 getgrouplist(username
, (int)user
->pw_gid
, groups
, &ngroups
);
1192 getgrouplist(username
, user
->pw_gid
, groups
, &ngroups
);
1193 #endif /* __APPLE__ */
1195 for (i
= 0; i
< ngroups
; i
++)
1196 if ((int)groupid
== (int)groups
[i
])
1201 for (i
= 0; group
->gr_mem
[i
]; i
++)
1203 if (!_cups_strcasecmp(username
, group
->gr_mem
[i
]))
1206 #endif /* HAVE_GETGROUPLIST */
1209 groupid
= (gid_t
)-1;
1212 * Group doesn't exist or user not in group list, check the group ID
1213 * against the user's group ID...
1216 if (user
&& groupid
== user
->pw_gid
)
1219 #ifdef HAVE_MBR_UID_TO_UUID
1221 * Check group membership through macOS membership API...
1224 if (user
&& !mbr_uid_to_uuid(user
->pw_uid
, useruuid
))
1226 if (groupid
!= (gid_t
)-1)
1229 * Map group name to UUID and check membership...
1232 if (!mbr_gid_to_uuid(groupid
, groupuuid
))
1233 if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1237 else if (groupname
[0] == '#')
1240 * Use UUID directly and check for equality (user UUID) and
1241 * membership (group UUID)...
1244 if (!uuid_parse((char *)groupname
+ 1, groupuuid
))
1246 if (!uuid_compare(useruuid
, groupuuid
))
1248 else if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1256 else if (groupname
[0] == '#')
1258 #endif /* HAVE_MBR_UID_TO_UUID */
1261 * If we get this far, then the user isn't part of the named group...
1269 * 'cupsdCopyLocation()' - Make a copy of a location...
1272 cupsd_location_t
* /* O - New location */
1274 cupsd_location_t
*loc
) /* I - Original location */
1276 cupsd_location_t
*temp
; /* New location */
1280 * Make a copy of the original location...
1283 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1287 * Copy the information from the original location to the new one.
1294 temp
->location
= _cupsStrAlloc(loc
->location
);
1296 temp
->length
= loc
->length
;
1297 temp
->limit
= loc
->limit
;
1298 temp
->order_type
= loc
->order_type
;
1299 temp
->type
= loc
->type
;
1300 temp
->level
= loc
->level
;
1301 temp
->satisfy
= loc
->satisfy
;
1302 temp
->encryption
= loc
->encryption
;
1306 if ((temp
->names
= cupsArrayDup(loc
->names
)) == NULL
)
1308 cupsdLogMessage(CUPSD_LOG_ERROR
,
1309 "Unable to allocate memory for %d names: %s",
1310 cupsArrayCount(loc
->names
), strerror(errno
));
1312 cupsdFreeLocation(temp
);
1320 * Copy allow rules...
1323 if ((temp
->allow
= cupsArrayDup(loc
->allow
)) == NULL
)
1325 cupsdLogMessage(CUPSD_LOG_ERROR
,
1326 "Unable to allocate memory for %d allow rules: %s",
1327 cupsArrayCount(loc
->allow
), strerror(errno
));
1328 cupsdFreeLocation(temp
);
1336 * Copy deny rules...
1339 if ((temp
->deny
= cupsArrayDup(loc
->deny
)) == NULL
)
1341 cupsdLogMessage(CUPSD_LOG_ERROR
,
1342 "Unable to allocate memory for %d deny rules: %s",
1343 cupsArrayCount(loc
->deny
), strerror(errno
));
1344 cupsdFreeLocation(temp
);
1354 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1358 cupsdDeleteAllLocations(void)
1361 * Free the location array, which will free all of the locations...
1364 cupsArrayDelete(Locations
);
1370 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1373 cupsd_location_t
* /* O - Location that matches */
1374 cupsdFindBest(const char *path
, /* I - Resource path */
1375 http_state_t state
) /* I - HTTP state/request */
1377 char uri
[HTTP_MAX_URI
],
1378 /* URI in request... */
1379 *uriptr
; /* Pointer into URI */
1380 cupsd_location_t
*loc
, /* Current location */
1381 *best
; /* Best match for location so far */
1382 size_t bestlen
; /* Length of best match */
1383 int limit
; /* Limit field */
1384 static const int limits
[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1386 CUPSD_AUTH_LIMIT_ALL
,
1387 CUPSD_AUTH_LIMIT_OPTIONS
,
1388 CUPSD_AUTH_LIMIT_GET
,
1389 CUPSD_AUTH_LIMIT_GET
,
1390 CUPSD_AUTH_LIMIT_HEAD
,
1391 CUPSD_AUTH_LIMIT_POST
,
1392 CUPSD_AUTH_LIMIT_POST
,
1393 CUPSD_AUTH_LIMIT_POST
,
1394 CUPSD_AUTH_LIMIT_PUT
,
1395 CUPSD_AUTH_LIMIT_PUT
,
1396 CUPSD_AUTH_LIMIT_DELETE
,
1397 CUPSD_AUTH_LIMIT_TRACE
,
1398 CUPSD_AUTH_LIMIT_ALL
,
1399 CUPSD_AUTH_LIMIT_ALL
,
1400 CUPSD_AUTH_LIMIT_ALL
,
1401 CUPSD_AUTH_LIMIT_ALL
1406 * First copy the connection URI to a local string so we have drop
1407 * any .ppd extension from the pathname in /printers or /classes
1411 strlcpy(uri
, path
, sizeof(uri
));
1413 if ((uriptr
= strchr(uri
, '?')) != NULL
)
1414 *uriptr
= '\0'; /* Drop trailing query string */
1416 if ((uriptr
= uri
+ strlen(uri
) - 1) > uri
&& *uriptr
== '/')
1417 *uriptr
= '\0'; /* Remove trailing '/' */
1419 if (!strncmp(uri
, "/printers/", 10) ||
1420 !strncmp(uri
, "/classes/", 9))
1423 * Check if the URI has .ppd on the end...
1426 uriptr
= uri
+ strlen(uri
) - 4; /* len > 4 if we get here... */
1428 if (!strcmp(uriptr
, ".ppd"))
1433 * Loop through the list of locations to find a match...
1436 limit
= limits
[state
];
1440 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: uri=\"%s\", limit=%x...", uri
, limit
);
1443 for (loc
= (cupsd_location_t
*)cupsArrayFirst(Locations
);
1445 loc
= (cupsd_location_t
*)cupsArrayNext(Locations
))
1447 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: Location %s(%d) Limit %x", loc
->location
? loc
->location
: "(null)", (int)loc
->length
, loc
->limit
);
1449 if (!strncmp(uri
, "/printers/", 10) || !strncmp(uri
, "/classes/", 9))
1452 * Use case-insensitive comparison for queue names...
1455 if (loc
->length
> bestlen
&& loc
->location
&&
1456 !_cups_strncasecmp(uri
, loc
->location
, loc
->length
) &&
1457 loc
->location
[0] == '/' &&
1458 (limit
& loc
->limit
) != 0)
1461 bestlen
= loc
->length
;
1467 * Use case-sensitive comparison for other URIs...
1470 if (loc
->length
> bestlen
&& loc
->location
&&
1471 !strncmp(uri
, loc
->location
, loc
->length
) &&
1472 loc
->location
[0] == '/' &&
1473 (limit
& loc
->limit
) != 0)
1476 bestlen
= loc
->length
;
1482 * Return the match, if any...
1485 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: best=%s", best
? best
->location
: "NONE");
1492 * 'cupsdFindLocation()' - Find the named location.
1495 cupsd_location_t
* /* O - Location that matches */
1496 cupsdFindLocation(const char *location
) /* I - Connection */
1498 cupsd_location_t key
; /* Search key */
1501 key
.location
= (char *)location
;
1503 return ((cupsd_location_t
*)cupsArrayFind(Locations
, &key
));
1508 * 'cupsdFreeLocation()' - Free all memory used by a location.
1512 cupsdFreeLocation(cupsd_location_t
*loc
)/* I - Location to free */
1514 cupsArrayDelete(loc
->names
);
1515 cupsArrayDelete(loc
->allow
);
1516 cupsArrayDelete(loc
->deny
);
1518 _cupsStrFree(loc
->location
);
1524 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1527 http_status_t
/* O - HTTP_OK if authorized or error code */
1528 cupsdIsAuthorized(cupsd_client_t
*con
, /* I - Connection */
1529 const char *owner
)/* I - Owner of object */
1531 int i
, /* Looping vars */
1532 auth
, /* Authorization status */
1533 type
; /* Type of authentication */
1534 http_addr_t
*hostaddr
= httpGetAddress(con
->http
);
1535 /* Client address */
1536 const char *hostname
= httpGetHostname(con
->http
, NULL
, 0);
1537 /* Client hostname */
1538 unsigned address
[4]; /* Authorization address */
1539 cupsd_location_t
*best
; /* Best match for location so far */
1540 size_t hostlen
; /* Length of hostname */
1541 char *name
, /* Current username */
1542 username
[256], /* Username to authorize */
1543 ownername
[256], /* Owner name to authorize */
1544 *ptr
; /* Pointer into username */
1545 struct passwd
*pw
; /* User password data */
1546 static const char * const levels
[] = /* Auth levels */
1552 static const char * const types
[] = /* Auth types */
1560 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)" : "");
1562 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: owner=\"%s\"", owner
);
1565 * If there is no "best" authentication rule for this request, then
1566 * access is allowed from the local system and denied from other
1572 if (httpAddrLocalhost(httpGetAddress(con
->http
)) ||
1573 !strcmp(hostname
, ServerName
) ||
1574 cupsArrayFind(ServerAlias
, (void *)hostname
))
1577 return (HTTP_FORBIDDEN
);
1582 if ((type
= best
->type
) == CUPSD_AUTH_DEFAULT
)
1583 type
= cupsdDefaultAuthType();
1585 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
));
1587 if (best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1588 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: op=%x(%s)", best
->op
, ippOpString(best
->op
));
1591 * Check host/ip-based accesses...
1595 if (httpAddrFamily(hostaddr
) == AF_INET6
)
1598 * Copy IPv6 address...
1601 address
[0] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[0]);
1602 address
[1] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[1]);
1603 address
[2] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[2]);
1604 address
[3] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[3]);
1607 #endif /* AF_INET6 */
1608 if (con
->http
->hostaddr
->addr
.sa_family
== AF_INET
)
1611 * Copy IPv4 address...
1617 address
[3] = ntohl(hostaddr
->ipv4
.sin_addr
.s_addr
);
1620 memset(address
, 0, sizeof(address
));
1622 hostlen
= strlen(hostname
);
1624 auth
= cupsdCheckAccess(address
, hostname
, hostlen
, best
)
1625 ? CUPSD_AUTH_ALLOW
: CUPSD_AUTH_DENY
;
1627 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth
? "DENY" : "ALLOW");
1629 if (auth
== CUPSD_AUTH_DENY
&& best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
)
1630 return (HTTP_FORBIDDEN
);
1634 * See if encryption is required...
1637 if ((best
->encryption
>= HTTP_ENCRYPT_REQUIRED
&& !con
->http
->tls
&&
1638 _cups_strcasecmp(hostname
, "localhost") &&
1639 !httpAddrLocalhost(hostaddr
) &&
1640 best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
) &&
1641 !(type
== CUPSD_AUTH_NEGOTIATE
||
1642 (type
== CUPSD_AUTH_NONE
&&
1643 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE
)))
1645 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1646 "cupsdIsAuthorized: Need upgrade to TLS...");
1647 return (HTTP_UPGRADE_REQUIRED
);
1649 #endif /* HAVE_SSL */
1652 * Now see what access level is required...
1655 if (best
->level
== CUPSD_AUTH_ANON
|| /* Anonymous access - allow it */
1656 (type
== CUPSD_AUTH_NONE
&& cupsArrayCount(best
->names
) == 0))
1659 if (!con
->username
[0] && type
== CUPSD_AUTH_NONE
&&
1660 best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1663 * Check for unauthenticated username...
1666 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
1669 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1672 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1673 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1674 attr
->values
[0].string
.text
);
1675 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
1677 else if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1678 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1680 return (HTTP_OK
); /* unless overridden with Satisfy */
1684 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: username=\"%s\"",
1687 #ifdef HAVE_AUTHORIZATION_H
1688 if (!con
->username
[0] && !con
->authref
)
1690 if (!con
->username
[0])
1691 #endif /* HAVE_AUTHORIZATION_H */
1693 if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1694 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1696 return (HTTP_OK
); /* unless overridden with Satisfy */
1700 if (con
->type
!= type
&& type
!= CUPSD_AUTH_NONE
&&
1702 (type
!= CUPSD_AUTH_NEGOTIATE
|| con
->gss_uid
<= 0) &&
1703 #endif /* HAVE_GSSAPI */
1704 con
->type
!= CUPSD_AUTH_BASIC
)
1706 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorized using %s, expected %s.",
1707 types
[con
->type
], types
[type
]);
1709 return (HTTP_UNAUTHORIZED
);
1712 strlcpy(username
, con
->username
, sizeof(username
));
1716 * OK, got a username. See if we need normal user access, or group
1717 * access... (root always matches)
1720 if (!strcmp(username
, "root"))
1724 * Strip any @domain or @KDC from the username and owner...
1727 if ((ptr
= strchr(username
, '@')) != NULL
)
1732 strlcpy(ownername
, owner
, sizeof(ownername
));
1734 if ((ptr
= strchr(ownername
, '@')) != NULL
)
1738 ownername
[0] = '\0';
1741 * Get the user info...
1746 pw
= getpwnam(username
);
1752 if (best
->level
== CUPSD_AUTH_USER
)
1755 * If there are no names associated with this location, then
1756 * any valid user is OK...
1759 if (cupsArrayCount(best
->names
) == 0)
1763 * Otherwise check the user list and return OK if this user is
1767 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking user membership...");
1769 #ifdef HAVE_AUTHORIZATION_H
1771 * If an authorization reference was supplied it must match a right name...
1776 for (name
= (char *)cupsArrayFirst(best
->names
);
1778 name
= (char *)cupsArrayNext(best
->names
))
1780 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) && check_authref(con
, name
+ 9))
1782 else if (!_cups_strcasecmp(name
, "@SYSTEM") && SystemGroupAuthKey
&&
1783 check_authref(con
, SystemGroupAuthKey
))
1787 return (HTTP_FORBIDDEN
);
1789 #endif /* HAVE_AUTHORIZATION_H */
1791 for (name
= (char *)cupsArrayFirst(best
->names
);
1793 name
= (char *)cupsArrayNext(best
->names
))
1795 if (!_cups_strcasecmp(name
, "@OWNER") && owner
&&
1796 !_cups_strcasecmp(username
, ownername
))
1798 else if (!_cups_strcasecmp(name
, "@SYSTEM"))
1800 for (i
= 0; i
< NumSystemGroups
; i
++)
1801 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1804 else if (name
[0] == '@')
1806 if (cupsdCheckGroup(username
, pw
, name
+ 1))
1809 else if (!_cups_strcasecmp(username
, name
))
1813 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1817 * Check to see if this user is in any of the named groups...
1820 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group membership...");
1823 * Check to see if this user is in any of the named groups...
1826 for (name
= (char *)cupsArrayFirst(best
->names
);
1828 name
= (char *)cupsArrayNext(best
->names
))
1830 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership...", name
);
1832 if (!_cups_strcasecmp(name
, "@SYSTEM"))
1834 for (i
= 0; i
< NumSystemGroups
; i
++)
1835 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1838 else if (cupsdCheckGroup(username
, pw
, name
))
1843 * The user isn't part of the specified group, so deny access...
1846 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: User not in group(s).");
1848 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1853 * 'cupsdNewLocation()' - Create a new location for authorization.
1855 * Note: Still need to call cupsdAddLocation() to add it to the list of global
1859 cupsd_location_t
* /* O - Pointer to new location record */
1860 cupsdNewLocation(const char *location
) /* I - Location path */
1862 cupsd_location_t
*temp
; /* New location */
1866 * Try to allocate memory for the new location.
1869 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1873 * Initialize the record and copy the name over...
1876 if ((temp
->location
= _cupsStrAlloc(location
)) == NULL
)
1882 temp
->length
= strlen(temp
->location
);
1885 * Return the new record...
1892 #ifdef HAVE_AUTHORIZATION_H
1894 * 'check_authref()' - Check if an authorization services reference has the
1898 static int /* O - 1 if right is valid, 0 otherwise */
1899 check_authref(cupsd_client_t
*con
, /* I - Connection */
1900 const char *right
) /* I - Right name */
1902 OSStatus status
; /* OS Status */
1903 AuthorizationItem authright
; /* Authorization right */
1904 AuthorizationRights authrights
; /* Authorization rights */
1905 AuthorizationFlags authflags
; /* Authorization flags */
1909 * Check to see if the user is allowed to perform the task...
1915 authright
.name
= right
;
1916 authright
.valueLength
= 0;
1917 authright
.value
= NULL
;
1918 authright
.flags
= 0;
1920 authrights
.count
= 1;
1921 authrights
.items
= &authright
;
1923 authflags
= kAuthorizationFlagDefaults
|
1924 kAuthorizationFlagExtendRights
;
1926 if ((status
= AuthorizationCopyRights(con
->authref
, &authrights
,
1927 kAuthorizationEmptyEnvironment
,
1928 authflags
, NULL
)) != 0)
1930 cupsdLogMessage(CUPSD_LOG_ERROR
,
1931 "AuthorizationCopyRights(\"%s\") returned %d (%s)",
1932 authright
.name
, (int)status
, cssmErrorString(status
));
1936 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "AuthorizationCopyRights(\"%s\") succeeded.", authright
.name
);
1940 #endif /* HAVE_AUTHORIZATION_H */
1944 * 'compare_locations()' - Compare two locations.
1947 static int /* O - Result of comparison */
1948 compare_locations(cupsd_location_t
*a
, /* I - First location */
1949 cupsd_location_t
*b
) /* I - Second location */
1951 return (strcmp(b
->location
, a
->location
));
1956 * 'copy_authmask()' - Copy function for auth masks.
1959 static cupsd_authmask_t
* /* O - New auth mask */
1960 copy_authmask(cupsd_authmask_t
*mask
, /* I - Existing auth mask */
1961 void *data
) /* I - User data (unused) */
1963 cupsd_authmask_t
*temp
; /* New auth mask */
1968 if ((temp
= malloc(sizeof(cupsd_authmask_t
))) != NULL
)
1970 memcpy(temp
, mask
, sizeof(cupsd_authmask_t
));
1972 if (temp
->type
== CUPSD_AUTH_NAME
|| temp
->type
== CUPSD_AUTH_INTERFACE
)
1975 * Make a copy of the name...
1978 if ((temp
->mask
.name
.name
= _cupsStrAlloc(temp
->mask
.name
.name
)) == NULL
)
1981 * Failed to make copy...
1996 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
2000 static char * /* O - Encrypted password */
2001 cups_crypt(const char *pw
, /* I - Password string */
2002 const char *salt
) /* I - Salt (key) string */
2004 if (!strncmp(salt
, "$1$", 3))
2007 * Use MD5 passwords without the benefit of PAM; this is for
2008 * Slackware Linux, and the algorithm was taken from the
2009 * old shadow-19990827/lib/md5crypt.c source code... :(
2012 int i
; /* Looping var */
2013 unsigned long n
; /* Output number */
2014 int pwlen
; /* Length of password string */
2015 const char *salt_end
; /* End of "salt" data for MD5 */
2016 char *ptr
; /* Pointer into result string */
2017 _cups_md5_state_t state
; /* Primary MD5 state info */
2018 _cups_md5_state_t state2
; /* Secondary MD5 state info */
2019 unsigned char digest
[16]; /* MD5 digest result */
2020 static char result
[120]; /* Final password string */
2024 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
2025 * Get a maximum of 8 characters of salt data after $1$...
2028 for (salt_end
= salt
+ 3; *salt_end
&& (salt_end
- salt
) < 11; salt_end
++)
2029 if (*salt_end
== '$')
2033 * Compute the MD5 sum we need...
2038 _cupsMD5Init(&state
);
2039 _cupsMD5Append(&state
, (unsigned char *)pw
, pwlen
);
2040 _cupsMD5Append(&state
, (unsigned char *)salt
, salt_end
- salt
);
2042 _cupsMD5Init(&state2
);
2043 _cupsMD5Append(&state2
, (unsigned char *)pw
, pwlen
);
2044 _cupsMD5Append(&state2
, (unsigned char *)salt
+ 3, salt_end
- salt
- 3);
2045 _cupsMD5Append(&state2
, (unsigned char *)pw
, pwlen
);
2046 _cupsMD5Finish(&state2
, digest
);
2048 for (i
= pwlen
; i
> 0; i
-= 16)
2049 _cupsMD5Append(&state
, digest
, i
> 16 ? 16 : i
);
2051 for (i
= pwlen
; i
> 0; i
>>= 1)
2052 _cupsMD5Append(&state
, (unsigned char *)((i
& 1) ? "" : pw
), 1);
2054 _cupsMD5Finish(&state
, digest
);
2056 for (i
= 0; i
< 1000; i
++)
2058 _cupsMD5Init(&state
);
2061 _cupsMD5Append(&state
, (unsigned char *)pw
, pwlen
);
2063 _cupsMD5Append(&state
, digest
, 16);
2066 _cupsMD5Append(&state
, (unsigned char *)salt
+ 3, salt_end
- salt
- 3);
2069 _cupsMD5Append(&state
, (unsigned char *)pw
, pwlen
);
2072 _cupsMD5Append(&state
, digest
, 16);
2074 _cupsMD5Append(&state
, (unsigned char *)pw
, pwlen
);
2076 _cupsMD5Finish(&state
, digest
);
2080 * Copy the final sum to the result string and return...
2083 memcpy(result
, salt
, (size_t)(salt_end
- salt
));
2084 ptr
= result
+ (salt_end
- salt
);
2087 for (i
= 0; i
< 5; i
++, ptr
+= 4)
2089 n
= ((((unsigned)digest
[i
] << 8) | (unsigned)digest
[i
+ 6]) << 8);
2092 n
|= (unsigned)digest
[i
+ 12];
2094 n
|= (unsigned)digest
[5];
2099 to64(ptr
, (unsigned)digest
[11], 2);
2108 * Use the standard crypt() function...
2111 return (crypt(pw
, salt
));
2114 #endif /* !HAVE_LIBPAM */
2118 * 'free_authmask()' - Free function for auth masks.
2122 free_authmask(cupsd_authmask_t
*mask
, /* I - Auth mask to free */
2123 void *data
) /* I - User data (unused) */
2127 if (mask
->type
== CUPSD_AUTH_NAME
|| mask
->type
== CUPSD_AUTH_INTERFACE
)
2128 _cupsStrFree(mask
->mask
.name
.name
);
2136 * 'pam_func()' - PAM conversation function.
2139 static int /* O - Success or failure */
2141 int num_msg
, /* I - Number of messages */
2142 const struct pam_message
**msg
, /* I - Messages */
2143 struct pam_response
**resp
, /* O - Responses */
2145 /* I - Pointer to connection */
2147 int i
; /* Looping var */
2148 struct pam_response
*replies
; /* Replies */
2149 cupsd_authdata_t
*data
; /* Pointer to auth data */
2153 * Allocate memory for the responses...
2156 if ((replies
= malloc(sizeof(struct pam_response
) * (size_t)num_msg
)) == NULL
)
2157 return (PAM_CONV_ERR
);
2160 * Answer all of the messages...
2163 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr
));
2165 data
= (cupsd_authdata_t
*)appdata_ptr
;
2167 for (i
= 0; i
< num_msg
; i
++)
2169 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg
[i
]->msg
));
2171 switch (msg
[i
]->msg_style
)
2173 case PAM_PROMPT_ECHO_ON
:
2174 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2176 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2177 replies
[i
].resp
= strdup(data
->username
);
2180 case PAM_PROMPT_ECHO_OFF
:
2181 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2183 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2184 replies
[i
].resp
= strdup(data
->password
);
2188 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2189 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2190 replies
[i
].resp
= NULL
;
2194 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2195 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2196 replies
[i
].resp
= NULL
;
2200 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2201 msg
[i
]->msg_style
));
2203 return (PAM_CONV_ERR
);
2208 * Return the responses back to PAM...
2213 return (PAM_SUCCESS
);
2219 * 'to64()' - Base64-encode an integer value...
2223 to64(char *s
, /* O - Output string */
2224 unsigned long v
, /* I - Value to encode */
2225 int n
) /* I - Number of digits */
2227 const char *itoa64
= "./0123456789"
2228 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2229 "abcdefghijklmnopqrstuvwxyz";
2232 for (; n
> 0; n
--, v
>>= 6)
2233 *s
++ = itoa64
[v
& 0x3f];
2235 #endif /* HAVE_LIBPAM */