2 * Authorization routines for the CUPS scheduler.
4 * Copyright © 2007-2019 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 #endif /* HAVE_AUTHORIZATION_H */
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>
41 #endif /* HAVE_SYS_PARAM_H */
42 #ifdef HAVE_SYS_UCRED_H
43 # include <sys/ucred.h>
44 typedef struct xucred cupsd_ucred_t
;
45 # define CUPSD_UCRED_UID(c) (c).cr_uid
48 typedef struct ucred cupsd_ucred_t
;
50 typedef struct sockpeercred cupsd_ucred_t
;
52 # define CUPSD_UCRED_UID(c) (c).uid
53 #endif /* HAVE_SYS_UCRED_H */
60 #ifdef HAVE_AUTHORIZATION_H
61 static int check_authref(cupsd_client_t
*con
, const char *right
);
62 #endif /* HAVE_AUTHORIZATION_H */
63 static int compare_locations(cupsd_location_t
*a
,
65 static cupsd_authmask_t
*copy_authmask(cupsd_authmask_t
*am
, void *data
);
66 static void free_authmask(cupsd_authmask_t
*am
, void *data
);
68 static int pam_func(int, const struct pam_message
**,
69 struct pam_response
**, void *);
70 #endif /* HAVE_LIBPAM */
78 typedef struct cupsd_authdata_s
/**** Authentication data ****/
80 char username
[HTTP_MAX_VALUE
], /* Username string */
81 password
[HTTP_MAX_VALUE
]; /* Password string */
83 #endif /* HAVE_LIBPAM */
87 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
90 int /* O - 1 on success, 0 on failure */
92 cups_array_t
**masks
, /* IO - Masks array (created as needed) */
93 const unsigned address
[4], /* I - IP address */
94 const unsigned netmask
[4]) /* I - IP netmask */
96 cupsd_authmask_t temp
; /* New host/domain mask */
99 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]);
101 temp
.type
= CUPSD_AUTH_IP
;
102 memcpy(temp
.mask
.ip
.address
, address
, sizeof(temp
.mask
.ip
.address
));
103 memcpy(temp
.mask
.ip
.netmask
, netmask
, sizeof(temp
.mask
.ip
.netmask
));
106 * Create the masks array as needed and add...
110 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
111 (cups_acopy_func_t
)copy_authmask
,
112 (cups_afree_func_t
)free_authmask
);
114 return (cupsArrayAdd(*masks
, &temp
));
119 * 'cupsdAddLocation()' - Add a location for authorization.
123 cupsdAddLocation(cupsd_location_t
*loc
) /* I - Location to add */
126 * Make sure the locations array is created...
130 Locations
= cupsArrayNew3((cups_array_func_t
)compare_locations
, NULL
,
131 (cups_ahash_func_t
)NULL
, 0,
132 (cups_acopy_func_t
)NULL
,
133 (cups_afree_func_t
)cupsdFreeLocation
);
137 cupsArrayAdd(Locations
, loc
);
139 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddLocation: Added location \"%s\"", loc
->location
? loc
->location
: "(null)");
145 * 'cupsdAddName()' - Add a name to a location...
149 cupsdAddName(cupsd_location_t
*loc
, /* I - Location to add to */
150 char *name
) /* I - Name to add */
152 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddName(loc=%p, name=\"%s\")", loc
, name
);
155 loc
->names
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
156 (cups_acopy_func_t
)_cupsStrAlloc
,
157 (cups_afree_func_t
)_cupsStrFree
);
159 if (!cupsArrayAdd(loc
->names
, name
))
161 cupsdLogMessage(CUPSD_LOG_ERROR
,
162 "Unable to duplicate name for location %s: %s",
163 loc
->location
? loc
->location
: "nil", strerror(errno
));
170 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
173 int /* O - 1 on success, 0 on failure */
174 cupsdAddNameMask(cups_array_t
**masks
, /* IO - Masks array (created as needed) */
175 char *name
) /* I - Host or interface name */
177 cupsd_authmask_t temp
; /* New host/domain mask */
178 char ifname
[32], /* Interface name */
179 *ifptr
; /* Pointer to end of name */
182 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks
, *masks
, name
);
184 if (!_cups_strcasecmp(name
, "@LOCAL"))
187 * Deny *interface*...
190 temp
.type
= CUPSD_AUTH_INTERFACE
;
191 temp
.mask
.name
.name
= (char *)"*";
193 else if (!_cups_strncasecmp(name
, "@IF(", 4))
196 * Deny *interface*...
199 strlcpy(ifname
, name
+ 4, sizeof(ifname
));
201 ifptr
= ifname
+ strlen(ifname
) - 1;
203 if (ifptr
>= ifname
&& *ifptr
== ')')
209 temp
.type
= CUPSD_AUTH_INTERFACE
;
210 temp
.mask
.name
.name
= ifname
;
221 temp
.type
= CUPSD_AUTH_NAME
;
222 temp
.mask
.name
.name
= (char *)name
;
226 * Set the name length...
229 temp
.mask
.name
.length
= strlen(temp
.mask
.name
.name
);
232 * Create the masks array as needed and add...
236 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
237 (cups_acopy_func_t
)copy_authmask
,
238 (cups_afree_func_t
)free_authmask
);
240 return (cupsArrayAdd(*masks
, &temp
));
245 * 'cupsdAuthorize()' - Validate any authorization credentials.
249 cupsdAuthorize(cupsd_client_t
*con
) /* I - Client connection */
251 int type
; /* Authentication type */
252 const char *authorization
; /* Pointer into Authorization string */
253 char *ptr
, /* Pointer into string */
254 username
[HTTP_MAX_VALUE
],
255 /* Username string */
256 password
[HTTP_MAX_VALUE
];
257 /* Password string */
258 cupsd_cert_t
*localuser
; /* Certificate username */
262 * Locate the best matching location so we know what kind of
263 * authentication to expect...
266 con
->best
= cupsdFindBest(con
->uri
, httpGetState(con
->http
));
267 con
->type
= CUPSD_AUTH_NONE
;
269 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "con->uri=\"%s\", con->best=%p(%s)", con
->uri
, con
->best
, con
->best
? con
->best
->location
: "");
271 if (con
->best
&& con
->best
->type
!= CUPSD_AUTH_NONE
)
273 if (con
->best
->type
== CUPSD_AUTH_DEFAULT
)
274 type
= cupsdDefaultAuthType();
276 type
= con
->best
->type
;
279 type
= cupsdDefaultAuthType();
282 * Decode the Authorization string...
285 authorization
= httpGetField(con
->http
, HTTP_FIELD_AUTHORIZATION
);
292 #endif /* HAVE_GSSAPI */
294 #ifdef HAVE_AUTHORIZATION_H
297 AuthorizationFree(con
->authref
, kAuthorizationFlagDefaults
);
300 #endif /* HAVE_AUTHORIZATION_H */
305 * No authorization data provided, return early...
308 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "No authentication data provided.");
311 #ifdef HAVE_AUTHORIZATION_H
312 else if (!strncmp(authorization
, "AuthRef ", 8) &&
313 httpAddrLocalhost(httpGetAddress(con
->http
)))
315 OSStatus status
; /* Status */
316 char authdata
[HTTP_MAX_VALUE
];
317 /* Nonce value from client */
318 int authlen
; /* Auth string length */
319 AuthorizationItemSet
*authinfo
; /* Authorization item set */
322 * Get the Authorization Services data...
326 while (isspace(*authorization
& 255))
329 authlen
= sizeof(authdata
);
330 httpDecode64_2(authdata
, &authlen
, authorization
);
332 if (authlen
!= kAuthorizationExternalFormLength
)
334 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "External Authorization reference size is incorrect.");
338 if ((status
= AuthorizationCreateFromExternalForm((AuthorizationExternalForm
*)authdata
, &con
->authref
)) != 0)
340 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "AuthorizationCreateFromExternalForm returned %d", (int)status
);
346 if (!AuthorizationCopyInfo(con
->authref
, kAuthorizationEnvironmentUsername
,
349 if (authinfo
->count
== 1 && authinfo
->items
[0].value
&&
350 authinfo
->items
[0].valueLength
>= 2)
352 strlcpy(username
, authinfo
->items
[0].value
, sizeof(username
));
354 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef.", username
);
357 AuthorizationFreeItemSet(authinfo
);
363 * No username in AuthRef, grab username using peer credentials...
366 struct passwd
*pwd
; /* Password entry for this user */
367 cupsd_ucred_t peercred
; /* Peer credentials */
368 socklen_t peersize
; /* Size of peer credentials */
370 peersize
= sizeof(peercred
);
372 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
374 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
378 if ((pwd
= getpwuid(CUPSD_UCRED_UID(peercred
))) == NULL
)
380 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred
));
384 strlcpy(username
, pwd
->pw_name
, sizeof(username
));
386 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef + PeerCred.", username
);
389 con
->type
= CUPSD_AUTH_BASIC
;
391 #endif /* HAVE_AUTHORIZATION_H */
392 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
393 else if (!strncmp(authorization
, "PeerCred ", 9) &&
394 con
->http
->hostaddr
->addr
.sa_family
== AF_LOCAL
&& con
->best
)
397 * Use peer credentials from domain socket connection...
400 struct passwd
*pwd
; /* Password entry for this user */
401 cupsd_ucred_t peercred
; /* Peer credentials */
402 socklen_t peersize
; /* Size of peer credentials */
403 #ifdef HAVE_AUTHORIZATION_H
404 const char *name
; /* Authorizing name */
405 int no_peer
= 0; /* Don't allow peer credentials? */
408 * See if we should allow peer credentials...
411 for (name
= (char *)cupsArrayFirst(con
->best
->names
);
413 name
= (char *)cupsArrayNext(con
->best
->names
))
415 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) ||
416 !_cups_strcasecmp(name
, "@SYSTEM"))
418 /* Normally don't want peer credentials if we need an auth key... */
421 else if (!_cups_strcasecmp(name
, "@OWNER"))
423 /* but if @OWNER is present then we allow it... */
431 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
434 #endif /* HAVE_AUTHORIZATION_H */
436 if ((pwd
= getpwnam(authorization
+ 9)) == NULL
)
438 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "User \"%s\" does not exist.", authorization
+ 9);
442 peersize
= sizeof(peercred
);
445 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
447 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
, &peersize
))
448 # endif /* __APPLE__ */
450 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
454 if (pwd
->pw_uid
!= CUPSD_UCRED_UID(peercred
))
456 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization
+ 9, CUPSD_UCRED_UID(peercred
), pwd
->pw_uid
);
457 # ifdef HAVE_SYS_UCRED_H
458 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_version=%d", peercred
.cr_version
);
459 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_uid=%d", peercred
.cr_uid
);
460 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_ngroups=%d", peercred
.cr_ngroups
);
461 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_groups[0]=%d", peercred
.cr_groups
[0]);
462 # endif /* HAVE_SYS_UCRED_H */
466 strlcpy(username
, authorization
+ 9, sizeof(username
));
469 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
470 # endif /* HAVE_GSSAPI */
472 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using PeerCred.", username
);
474 con
->type
= CUPSD_AUTH_BASIC
;
476 #endif /* SO_PEERCRED && AF_LOCAL */
477 else if (!strncmp(authorization
, "Local", 5) &&
478 httpAddrLocalhost(httpGetAddress(con
->http
)))
481 * Get Local certificate authentication data...
485 while (isspace(*authorization
& 255))
488 if ((localuser
= cupsdFindCert(authorization
)) == NULL
)
490 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Local authentication certificate not found.");
494 strlcpy(username
, localuser
->username
, sizeof(username
));
495 con
->type
= localuser
->type
;
497 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using Local.", username
);
499 else if (!strncmp(authorization
, "Basic", 5))
502 * Get the Basic authentication data...
505 int userlen
; /* Username:password length */
509 while (isspace(*authorization
& 255))
512 userlen
= sizeof(username
);
513 httpDecode64_2(username
, &userlen
, authorization
);
516 * Pull the username and password out...
519 if ((ptr
= strchr(username
, ':')) == NULL
)
521 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Missing Basic password.");
530 * Username must not be empty...
533 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic username.");
540 * Password must not be empty...
543 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic password.");
547 strlcpy(password
, ptr
, sizeof(password
));
550 * Validate the username and password...
556 case CUPSD_AUTH_BASIC
:
560 * Only use PAM to do authentication. This supports MD5
561 * passwords, among other things...
564 pam_handle_t
*pamh
; /* PAM authentication handle */
565 int pamerr
; /* PAM error code */
566 struct pam_conv pamdata
;/* PAM conversation data */
567 cupsd_authdata_t data
; /* Authentication data */
570 strlcpy(data
.username
, username
, sizeof(data
.username
));
571 strlcpy(data
.password
, password
, sizeof(data
.password
));
574 pamdata
.conv
= (int (*)(int, struct pam_message
**,
575 struct pam_response
**,
578 pamdata
.conv
= pam_func
;
580 pamdata
.appdata_ptr
= &data
;
582 pamerr
= pam_start("cups", username
, &pamdata
, &pamh
);
583 if (pamerr
!= PAM_SUCCESS
)
585 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_start() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
589 # ifdef HAVE_PAM_SET_ITEM
591 pamerr
= pam_set_item(pamh
, PAM_RHOST
, con
->http
->hostname
);
592 if (pamerr
!= PAM_SUCCESS
)
593 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
594 # endif /* PAM_RHOST */
597 pamerr
= pam_set_item(pamh
, PAM_TTY
, "cups");
598 if (pamerr
!= PAM_SUCCESS
)
599 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
600 # endif /* PAM_TTY */
601 # endif /* HAVE_PAM_SET_ITEM */
603 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
604 if (pamerr
!= PAM_SUCCESS
)
606 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_authenticate() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
611 # ifdef HAVE_PAM_SETCRED
612 pamerr
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
| PAM_SILENT
);
613 if (pamerr
!= PAM_SUCCESS
)
614 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_setcred() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
615 # endif /* HAVE_PAM_SETCRED */
617 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
618 if (pamerr
!= PAM_SUCCESS
)
620 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_acct_mgmt() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
625 pam_end(pamh
, PAM_SUCCESS
);
629 * Use normal UNIX password file-based authentication...
632 char *pass
; /* Encrypted password */
633 struct passwd
*pw
; /* User password data */
634 # ifdef HAVE_SHADOW_H
635 struct spwd
*spw
; /* Shadow password data */
636 # endif /* HAVE_SHADOW_H */
639 pw
= getpwnam(username
); /* Get the current password */
640 endpwent(); /* Close the password file */
648 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unknown username \"%s\".", username
);
652 # ifdef HAVE_SHADOW_H
653 spw
= getspnam(username
);
656 if (!spw
&& !strcmp(pw
->pw_passwd
, "x"))
659 * Don't allow blank passwords!
662 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no shadow password.", username
);
666 if (spw
&& !spw
->sp_pwdp
[0] && !pw
->pw_passwd
[0])
668 if (!pw
->pw_passwd
[0])
669 # endif /* HAVE_SHADOW_H */
672 * Don't allow blank passwords!
675 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Username \"%s\" has no password.", username
);
680 * OK, the password isn't blank, so compare with what came from the
684 pass
= crypt(password
, pw
->pw_passwd
);
686 if (!pass
|| strcmp(pw
->pw_passwd
, pass
))
688 # ifdef HAVE_SHADOW_H
691 pass
= crypt(password
, spw
->sp_pwdp
);
693 if (pass
== NULL
|| strcmp(spw
->sp_pwdp
, pass
))
695 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
700 # endif /* HAVE_SHADOW_H */
702 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Authentication failed for user \"%s\".", username
);
706 #endif /* HAVE_LIBPAM */
709 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Basic.", username
);
716 else if (!strncmp(authorization
, "Negotiate", 9))
718 int len
; /* Length of authorization string */
719 gss_ctx_id_t context
; /* Authorization context */
720 OM_uint32 major_status
, /* Major status code */
721 minor_status
; /* Minor status code */
722 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
,
723 /* Input token from string */
724 output_token
= GSS_C_EMPTY_BUFFER
;
725 /* Output token for username */
726 gss_name_t client_name
; /* Client name */
731 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
735 if (&gss_init_sec_context
== NULL
)
737 cupsdLogClient(con
, CUPSD_LOG_WARN
, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
740 # endif /* __APPLE__ */
743 * Find the start of the Kerberos input token...
747 while (isspace(*authorization
& 255))
752 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "No authentication data specified.");
757 * Decode the authorization string to get the input token...
760 len
= (int)strlen(authorization
);
761 input_token
.value
= malloc((size_t)len
);
762 input_token
.value
= httpDecode64_2(input_token
.value
, &len
,
764 input_token
.length
= (size_t)len
;
767 * Accept the input token to get the authorization info...
770 context
= GSS_C_NO_CONTEXT
;
771 client_name
= GSS_C_NO_NAME
;
772 major_status
= gss_accept_sec_context(&minor_status
,
776 GSS_C_NO_CHANNEL_BINDINGS
,
784 if (output_token
.length
> 0)
785 gss_release_buffer(&minor_status
, &output_token
);
787 if (GSS_ERROR(major_status
))
789 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error accepting GSSAPI security context.", con
->number
);
791 if (context
!= GSS_C_NO_CONTEXT
)
792 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
799 * Get the username associated with the client's credentials...
802 if (major_status
== GSS_S_CONTINUE_NEEDED
)
803 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Credentials not complete.", con
->number
);
804 else if (major_status
== GSS_S_COMPLETE
)
806 major_status
= gss_display_name(&minor_status
, client_name
,
807 &output_token
, NULL
);
809 if (GSS_ERROR(major_status
))
811 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error getting username.", con
->number
);
812 gss_release_name(&minor_status
, &client_name
);
813 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
817 strlcpy(username
, output_token
.value
, sizeof(username
));
819 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Negotiate.", username
);
821 gss_release_name(&minor_status
, &client_name
);
822 gss_release_buffer(&minor_status
, &output_token
);
824 con
->type
= CUPSD_AUTH_NEGOTIATE
;
827 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
829 # if defined(SO_PEERCRED) && defined(AF_LOCAL)
831 * Get the client's UID if we are printing locally - that allows a backend
832 * to run as the correct user to get Kerberos credentials of its own.
835 if (httpAddrFamily(con
->http
->hostaddr
) == AF_LOCAL
)
837 cupsd_ucred_t peercred
; /* Peer credentials */
838 socklen_t peersize
; /* Size of peer credentials */
840 peersize
= sizeof(peercred
);
843 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
845 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
,
847 # endif /* __APPLE__ */
849 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
853 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred
));
854 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
857 # endif /* SO_PEERCRED && AF_LOCAL */
859 #endif /* HAVE_GSSAPI */
862 char scheme
[256]; /* Auth scheme... */
865 if (sscanf(authorization
, "%255s", scheme
) != 1)
866 strlcpy(scheme
, "UNKNOWN", sizeof(scheme
));
868 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Bad authentication data \"%s ...\".", scheme
);
873 * If we get here, then we were able to validate the username and
874 * password - copy the validated username and password to the client
878 strlcpy(con
->username
, username
, sizeof(con
->username
));
879 strlcpy(con
->password
, password
, sizeof(con
->password
));
884 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
888 int /* O - 1 if allowed, 0 otherwise */
890 unsigned ip
[4], /* I - Client address */
891 const char *name
, /* I - Client hostname */
892 size_t namelen
, /* I - Length of hostname */
893 cupsd_location_t
*loc
) /* I - Location to check */
895 int allow
; /* 1 if allowed, 0 otherwise */
898 if (!_cups_strcasecmp(name
, "localhost"))
901 * Access from localhost (127.0.0.1 or ::1) is always allowed...
909 * Do authorization checks on the domain/address...
912 switch (loc
->order_type
)
915 allow
= 0; /* anti-compiler-warning-code */
918 case CUPSD_AUTH_ALLOW
: /* Order Deny,Allow */
921 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
924 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
928 case CUPSD_AUTH_DENY
: /* Order Allow,Deny */
931 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
934 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
945 * 'cupsdCheckAuth()' - Check authorization masks.
948 int /* O - 1 if mask matches, 0 otherwise */
949 cupsdCheckAuth(unsigned ip
[4], /* I - Client address */
950 const char *name
, /* I - Client hostname */
951 size_t name_len
, /* I - Length of hostname */
952 cups_array_t
*masks
) /* I - Masks */
954 int i
; /* Looping var */
955 cupsd_authmask_t
*mask
; /* Current mask */
956 cupsd_netif_t
*iface
; /* Network interface */
957 unsigned netip4
; /* IPv4 network address */
959 unsigned netip6
[4]; /* IPv6 network address */
960 #endif /* AF_INET6 */
963 for (mask
= (cupsd_authmask_t
*)cupsArrayFirst(masks
);
965 mask
= (cupsd_authmask_t
*)cupsArrayNext(masks
))
969 case CUPSD_AUTH_INTERFACE
:
971 * Check for a match with a network interface...
974 netip4
= htonl(ip
[3]);
977 netip6
[0] = htonl(ip
[0]);
978 netip6
[1] = htonl(ip
[1]);
979 netip6
[2] = htonl(ip
[2]);
980 netip6
[3] = htonl(ip
[3]);
981 #endif /* AF_INET6 */
985 if (!strcmp(mask
->mask
.name
.name
, "*"))
989 * Allow Back-to-My-Mac addresses...
992 if ((ip
[0] & 0xff000000) == 0xfd000000)
994 #endif /* __APPLE__ */
997 * Check against all local interfaces...
1000 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1002 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1005 * Only check local interfaces...
1008 if (!iface
->is_local
)
1011 if (iface
->address
.addr
.sa_family
== AF_INET
)
1014 * Check IPv4 address...
1017 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1018 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1019 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1026 * Check IPv6 address...
1029 for (i
= 0; i
< 4; i
++)
1030 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1031 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1032 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1038 #endif /* AF_INET6 */
1044 * Check the named interface...
1047 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1049 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1051 if (strcmp(mask
->mask
.name
.name
, iface
->name
))
1054 if (iface
->address
.addr
.sa_family
== AF_INET
)
1057 * Check IPv4 address...
1060 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1061 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1062 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1069 * Check IPv6 address...
1072 for (i
= 0; i
< 4; i
++)
1073 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1074 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1075 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1081 #endif /* AF_INET6 */
1086 case CUPSD_AUTH_NAME
:
1088 * Check for exact name match...
1091 if (!_cups_strcasecmp(name
, mask
->mask
.name
.name
))
1095 * Check for domain match...
1098 if (name_len
>= mask
->mask
.name
.length
&&
1099 mask
->mask
.name
.name
[0] == '.' &&
1100 !_cups_strcasecmp(name
+ name_len
- mask
->mask
.name
.length
,
1101 mask
->mask
.name
.name
))
1105 case CUPSD_AUTH_IP
:
1107 * Check for IP/network address match...
1110 for (i
= 0; i
< 4; i
++)
1111 if ((ip
[i
] & mask
->mask
.ip
.netmask
[i
]) !=
1112 mask
->mask
.ip
.address
[i
])
1126 * 'cupsdCheckGroup()' - Check for a user's group membership.
1129 int /* O - 1 if user is a member, 0 otherwise */
1131 const char *username
, /* I - User name */
1132 struct passwd
*user
, /* I - System user info */
1133 const char *groupname
) /* I - Group name */
1135 int i
; /* Looping var */
1136 struct group
*group
; /* Group info */
1137 gid_t groupid
; /* ID of named group */
1138 #ifdef HAVE_MBR_UID_TO_UUID
1139 uuid_t useruuid
, /* UUID for username */
1140 groupuuid
; /* UUID for groupname */
1141 int is_member
; /* True if user is a member of group */
1142 #endif /* HAVE_MBR_UID_TO_UUID */
1145 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username
, user
, groupname
);
1151 if (!username
|| !groupname
)
1155 * Check to see if the user is a member of the named group...
1158 group
= getgrnam(groupname
);
1164 * Group exists, check it...
1167 groupid
= group
->gr_gid
;
1169 #ifdef HAVE_GETGROUPLIST
1172 int ngroups
; /* Number of groups */
1174 int groups
[2048]; /* Groups that user belongs to */
1176 gid_t groups
[2048]; /* Groups that user belongs to */
1177 # endif /* __APPLE__ */
1179 ngroups
= (int)(sizeof(groups
) / sizeof(groups
[0]));
1181 getgrouplist(username
, (int)user
->pw_gid
, groups
, &ngroups
);
1183 getgrouplist(username
, user
->pw_gid
, groups
, &ngroups
);
1184 #endif /* __APPLE__ */
1186 for (i
= 0; i
< ngroups
; i
++)
1187 if ((int)groupid
== (int)groups
[i
])
1192 for (i
= 0; group
->gr_mem
[i
]; i
++)
1194 if (!_cups_strcasecmp(username
, group
->gr_mem
[i
]))
1197 #endif /* HAVE_GETGROUPLIST */
1200 groupid
= (gid_t
)-1;
1203 * Group doesn't exist or user not in group list, check the group ID
1204 * against the user's group ID...
1207 if (user
&& groupid
== user
->pw_gid
)
1210 #ifdef HAVE_MBR_UID_TO_UUID
1212 * Check group membership through macOS membership API...
1215 if (user
&& !mbr_uid_to_uuid(user
->pw_uid
, useruuid
))
1217 if (groupid
!= (gid_t
)-1)
1220 * Map group name to UUID and check membership...
1223 if (!mbr_gid_to_uuid(groupid
, groupuuid
))
1224 if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1228 else if (groupname
[0] == '#')
1231 * Use UUID directly and check for equality (user UUID) and
1232 * membership (group UUID)...
1235 if (!uuid_parse((char *)groupname
+ 1, groupuuid
))
1237 if (!uuid_compare(useruuid
, groupuuid
))
1239 else if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1247 else if (groupname
[0] == '#')
1249 #endif /* HAVE_MBR_UID_TO_UUID */
1252 * If we get this far, then the user isn't part of the named group...
1260 * 'cupsdCopyLocation()' - Make a copy of a location...
1263 cupsd_location_t
* /* O - New location */
1265 cupsd_location_t
*loc
) /* I - Original location */
1267 cupsd_location_t
*temp
; /* New location */
1271 * Make a copy of the original location...
1274 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1278 * Copy the information from the original location to the new one.
1285 temp
->location
= _cupsStrAlloc(loc
->location
);
1287 temp
->length
= loc
->length
;
1288 temp
->limit
= loc
->limit
;
1289 temp
->order_type
= loc
->order_type
;
1290 temp
->type
= loc
->type
;
1291 temp
->level
= loc
->level
;
1292 temp
->satisfy
= loc
->satisfy
;
1293 temp
->encryption
= loc
->encryption
;
1297 if ((temp
->names
= cupsArrayDup(loc
->names
)) == NULL
)
1299 cupsdLogMessage(CUPSD_LOG_ERROR
,
1300 "Unable to allocate memory for %d names: %s",
1301 cupsArrayCount(loc
->names
), strerror(errno
));
1303 cupsdFreeLocation(temp
);
1311 * Copy allow rules...
1314 if ((temp
->allow
= cupsArrayDup(loc
->allow
)) == NULL
)
1316 cupsdLogMessage(CUPSD_LOG_ERROR
,
1317 "Unable to allocate memory for %d allow rules: %s",
1318 cupsArrayCount(loc
->allow
), strerror(errno
));
1319 cupsdFreeLocation(temp
);
1327 * Copy deny rules...
1330 if ((temp
->deny
= cupsArrayDup(loc
->deny
)) == NULL
)
1332 cupsdLogMessage(CUPSD_LOG_ERROR
,
1333 "Unable to allocate memory for %d deny rules: %s",
1334 cupsArrayCount(loc
->deny
), strerror(errno
));
1335 cupsdFreeLocation(temp
);
1345 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1349 cupsdDeleteAllLocations(void)
1352 * Free the location array, which will free all of the locations...
1355 cupsArrayDelete(Locations
);
1361 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1364 cupsd_location_t
* /* O - Location that matches */
1365 cupsdFindBest(const char *path
, /* I - Resource path */
1366 http_state_t state
) /* I - HTTP state/request */
1368 char uri
[HTTP_MAX_URI
],
1369 /* URI in request... */
1370 *uriptr
; /* Pointer into URI */
1371 cupsd_location_t
*loc
, /* Current location */
1372 *best
; /* Best match for location so far */
1373 size_t bestlen
; /* Length of best match */
1374 int limit
; /* Limit field */
1375 static const int limits
[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1377 CUPSD_AUTH_LIMIT_ALL
,
1378 CUPSD_AUTH_LIMIT_OPTIONS
,
1379 CUPSD_AUTH_LIMIT_GET
,
1380 CUPSD_AUTH_LIMIT_GET
,
1381 CUPSD_AUTH_LIMIT_HEAD
,
1382 CUPSD_AUTH_LIMIT_POST
,
1383 CUPSD_AUTH_LIMIT_POST
,
1384 CUPSD_AUTH_LIMIT_POST
,
1385 CUPSD_AUTH_LIMIT_PUT
,
1386 CUPSD_AUTH_LIMIT_PUT
,
1387 CUPSD_AUTH_LIMIT_DELETE
,
1388 CUPSD_AUTH_LIMIT_TRACE
,
1389 CUPSD_AUTH_LIMIT_ALL
,
1390 CUPSD_AUTH_LIMIT_ALL
,
1391 CUPSD_AUTH_LIMIT_ALL
,
1392 CUPSD_AUTH_LIMIT_ALL
1397 * First copy the connection URI to a local string so we have drop
1398 * any .ppd extension from the pathname in /printers or /classes
1402 strlcpy(uri
, path
, sizeof(uri
));
1404 if ((uriptr
= strchr(uri
, '?')) != NULL
)
1405 *uriptr
= '\0'; /* Drop trailing query string */
1407 if ((uriptr
= uri
+ strlen(uri
) - 1) > uri
&& *uriptr
== '/')
1408 *uriptr
= '\0'; /* Remove trailing '/' */
1410 if (!strncmp(uri
, "/printers/", 10) ||
1411 !strncmp(uri
, "/classes/", 9))
1414 * Check if the URI has .ppd on the end...
1417 uriptr
= uri
+ strlen(uri
) - 4; /* len > 4 if we get here... */
1419 if (!strcmp(uriptr
, ".ppd"))
1424 * Loop through the list of locations to find a match...
1427 limit
= limits
[state
];
1431 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: uri=\"%s\", limit=%x...", uri
, limit
);
1434 for (loc
= (cupsd_location_t
*)cupsArrayFirst(Locations
);
1436 loc
= (cupsd_location_t
*)cupsArrayNext(Locations
))
1438 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: Location %s(%d) Limit %x", loc
->location
? loc
->location
: "(null)", (int)loc
->length
, loc
->limit
);
1440 if (!strncmp(uri
, "/printers/", 10) || !strncmp(uri
, "/classes/", 9))
1443 * Use case-insensitive comparison for queue names...
1446 if (loc
->length
> bestlen
&& loc
->location
&&
1447 !_cups_strncasecmp(uri
, loc
->location
, loc
->length
) &&
1448 loc
->location
[0] == '/' &&
1449 (limit
& loc
->limit
) != 0)
1452 bestlen
= loc
->length
;
1458 * Use case-sensitive comparison for other URIs...
1461 if (loc
->length
> bestlen
&& loc
->location
&&
1462 !strncmp(uri
, loc
->location
, loc
->length
) &&
1463 loc
->location
[0] == '/' &&
1464 (limit
& loc
->limit
) != 0)
1467 bestlen
= loc
->length
;
1473 * Return the match, if any...
1476 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: best=%s", best
? best
->location
: "NONE");
1483 * 'cupsdFindLocation()' - Find the named location.
1486 cupsd_location_t
* /* O - Location that matches */
1487 cupsdFindLocation(const char *location
) /* I - Connection */
1489 cupsd_location_t key
; /* Search key */
1492 key
.location
= (char *)location
;
1494 return ((cupsd_location_t
*)cupsArrayFind(Locations
, &key
));
1499 * 'cupsdFreeLocation()' - Free all memory used by a location.
1503 cupsdFreeLocation(cupsd_location_t
*loc
)/* I - Location to free */
1505 cupsArrayDelete(loc
->names
);
1506 cupsArrayDelete(loc
->allow
);
1507 cupsArrayDelete(loc
->deny
);
1509 _cupsStrFree(loc
->location
);
1515 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1518 http_status_t
/* O - HTTP_OK if authorized or error code */
1519 cupsdIsAuthorized(cupsd_client_t
*con
, /* I - Connection */
1520 const char *owner
)/* I - Owner of object */
1522 int i
, /* Looping vars */
1523 auth
, /* Authorization status */
1524 type
; /* Type of authentication */
1525 http_addr_t
*hostaddr
= httpGetAddress(con
->http
);
1526 /* Client address */
1527 const char *hostname
= httpGetHostname(con
->http
, NULL
, 0);
1528 /* Client hostname */
1529 unsigned address
[4]; /* Authorization address */
1530 cupsd_location_t
*best
; /* Best match for location so far */
1531 size_t hostlen
; /* Length of hostname */
1532 char *name
, /* Current username */
1533 username
[256], /* Username to authorize */
1534 ownername
[256], /* Owner name to authorize */
1535 *ptr
; /* Pointer into username */
1536 struct passwd
*pw
; /* User password data */
1537 static const char * const levels
[] = /* Auth levels */
1543 static const char * const types
[] = /* Auth types */
1551 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)" : "");
1553 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: owner=\"%s\"", owner
);
1556 * If there is no "best" authentication rule for this request, then
1557 * access is allowed from the local system and denied from other
1563 if (httpAddrLocalhost(httpGetAddress(con
->http
)) ||
1564 !strcmp(hostname
, ServerName
) ||
1565 cupsArrayFind(ServerAlias
, (void *)hostname
))
1568 return (HTTP_FORBIDDEN
);
1573 if ((type
= best
->type
) == CUPSD_AUTH_DEFAULT
)
1574 type
= cupsdDefaultAuthType();
1576 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
));
1578 if (best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1579 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: op=%x(%s)", best
->op
, ippOpString(best
->op
));
1582 * Check host/ip-based accesses...
1586 if (httpAddrFamily(hostaddr
) == AF_INET6
)
1589 * Copy IPv6 address...
1592 address
[0] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[0]);
1593 address
[1] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[1]);
1594 address
[2] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[2]);
1595 address
[3] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[3]);
1598 #endif /* AF_INET6 */
1599 if (con
->http
->hostaddr
->addr
.sa_family
== AF_INET
)
1602 * Copy IPv4 address...
1608 address
[3] = ntohl(hostaddr
->ipv4
.sin_addr
.s_addr
);
1611 memset(address
, 0, sizeof(address
));
1613 hostlen
= strlen(hostname
);
1615 auth
= cupsdCheckAccess(address
, hostname
, hostlen
, best
)
1616 ? CUPSD_AUTH_ALLOW
: CUPSD_AUTH_DENY
;
1618 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth
? "DENY" : "ALLOW");
1620 if (auth
== CUPSD_AUTH_DENY
&& best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
)
1621 return (HTTP_FORBIDDEN
);
1625 * See if encryption is required...
1628 if ((best
->encryption
>= HTTP_ENCRYPT_REQUIRED
&& !con
->http
->tls
&&
1629 _cups_strcasecmp(hostname
, "localhost") &&
1630 !httpAddrLocalhost(hostaddr
) &&
1631 best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
) &&
1632 !(type
== CUPSD_AUTH_NEGOTIATE
||
1633 (type
== CUPSD_AUTH_NONE
&&
1634 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE
)))
1636 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1637 "cupsdIsAuthorized: Need upgrade to TLS...");
1638 return (HTTP_UPGRADE_REQUIRED
);
1640 #endif /* HAVE_SSL */
1643 * Now see what access level is required...
1646 if (best
->level
== CUPSD_AUTH_ANON
|| /* Anonymous access - allow it */
1647 (type
== CUPSD_AUTH_NONE
&& cupsArrayCount(best
->names
) == 0))
1650 if (!con
->username
[0] && type
== CUPSD_AUTH_NONE
&&
1651 best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1654 * Check for unauthenticated username...
1657 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
1660 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1663 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1664 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1665 attr
->values
[0].string
.text
);
1666 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
1668 else if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1669 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1671 return (HTTP_OK
); /* unless overridden with Satisfy */
1675 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: username=\"%s\"",
1678 #ifdef HAVE_AUTHORIZATION_H
1679 if (!con
->username
[0] && !con
->authref
)
1681 if (!con
->username
[0])
1682 #endif /* HAVE_AUTHORIZATION_H */
1684 if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1685 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1687 return (HTTP_OK
); /* unless overridden with Satisfy */
1691 if (con
->type
!= type
&& type
!= CUPSD_AUTH_NONE
&&
1693 (type
!= CUPSD_AUTH_NEGOTIATE
|| con
->gss_uid
<= 0) &&
1694 #endif /* HAVE_GSSAPI */
1695 con
->type
!= CUPSD_AUTH_BASIC
)
1697 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorized using %s, expected %s.",
1698 types
[con
->type
], types
[type
]);
1700 return (HTTP_UNAUTHORIZED
);
1703 strlcpy(username
, con
->username
, sizeof(username
));
1707 * OK, got a username. See if we need normal user access, or group
1708 * access... (root always matches)
1711 if (!strcmp(username
, "root"))
1715 * Strip any @domain or @KDC from the username and owner...
1718 if ((ptr
= strchr(username
, '@')) != NULL
)
1723 strlcpy(ownername
, owner
, sizeof(ownername
));
1725 if ((ptr
= strchr(ownername
, '@')) != NULL
)
1729 ownername
[0] = '\0';
1732 * Get the user info...
1737 pw
= getpwnam(username
);
1743 if (best
->level
== CUPSD_AUTH_USER
)
1746 * If there are no names associated with this location, then
1747 * any valid user is OK...
1750 if (cupsArrayCount(best
->names
) == 0)
1754 * Otherwise check the user list and return OK if this user is
1758 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking user membership...");
1760 #ifdef HAVE_AUTHORIZATION_H
1762 * If an authorization reference was supplied it must match a right name...
1767 for (name
= (char *)cupsArrayFirst(best
->names
);
1769 name
= (char *)cupsArrayNext(best
->names
))
1771 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) && check_authref(con
, name
+ 9))
1773 else if (!_cups_strcasecmp(name
, "@SYSTEM") && SystemGroupAuthKey
&&
1774 check_authref(con
, SystemGroupAuthKey
))
1778 return (HTTP_FORBIDDEN
);
1780 #endif /* HAVE_AUTHORIZATION_H */
1782 for (name
= (char *)cupsArrayFirst(best
->names
);
1784 name
= (char *)cupsArrayNext(best
->names
))
1786 if (!_cups_strcasecmp(name
, "@OWNER") && owner
&&
1787 !_cups_strcasecmp(username
, ownername
))
1789 else if (!_cups_strcasecmp(name
, "@SYSTEM"))
1791 for (i
= 0; i
< NumSystemGroups
; i
++)
1792 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1795 else if (name
[0] == '@')
1797 if (cupsdCheckGroup(username
, pw
, name
+ 1))
1800 else if (!_cups_strcasecmp(username
, name
))
1804 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1808 * Check to see if this user is in any of the named groups...
1811 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group membership...");
1814 * Check to see if this user is in any of the named groups...
1817 for (name
= (char *)cupsArrayFirst(best
->names
);
1819 name
= (char *)cupsArrayNext(best
->names
))
1821 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership...", name
);
1823 if (!_cups_strcasecmp(name
, "@SYSTEM"))
1825 for (i
= 0; i
< NumSystemGroups
; i
++)
1826 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]))
1829 else if (cupsdCheckGroup(username
, pw
, name
))
1834 * The user isn't part of the specified group, so deny access...
1837 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: User not in group(s).");
1839 return (con
->username
[0] ? HTTP_FORBIDDEN
: HTTP_UNAUTHORIZED
);
1844 * 'cupsdNewLocation()' - Create a new location for authorization.
1846 * Note: Still need to call cupsdAddLocation() to add it to the list of global
1850 cupsd_location_t
* /* O - Pointer to new location record */
1851 cupsdNewLocation(const char *location
) /* I - Location path */
1853 cupsd_location_t
*temp
; /* New location */
1857 * Try to allocate memory for the new location.
1860 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1864 * Initialize the record and copy the name over...
1867 if ((temp
->location
= _cupsStrAlloc(location
)) == NULL
)
1873 temp
->length
= strlen(temp
->location
);
1876 * Return the new record...
1883 #ifdef HAVE_AUTHORIZATION_H
1885 * 'check_authref()' - Check if an authorization services reference has the
1889 static int /* O - 1 if right is valid, 0 otherwise */
1890 check_authref(cupsd_client_t
*con
, /* I - Connection */
1891 const char *right
) /* I - Right name */
1893 OSStatus status
; /* OS Status */
1894 AuthorizationItem authright
; /* Authorization right */
1895 AuthorizationRights authrights
; /* Authorization rights */
1896 AuthorizationFlags authflags
; /* Authorization flags */
1900 * Check to see if the user is allowed to perform the task...
1906 authright
.name
= right
;
1907 authright
.valueLength
= 0;
1908 authright
.value
= NULL
;
1909 authright
.flags
= 0;
1911 authrights
.count
= 1;
1912 authrights
.items
= &authright
;
1914 authflags
= kAuthorizationFlagDefaults
|
1915 kAuthorizationFlagExtendRights
;
1917 if ((status
= AuthorizationCopyRights(con
->authref
, &authrights
,
1918 kAuthorizationEmptyEnvironment
,
1919 authflags
, NULL
)) != 0)
1921 cupsdLogMessage(CUPSD_LOG_ERROR
, "AuthorizationCopyRights(\"%s\") returned %d", authright
.name
, (int)status
);
1925 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "AuthorizationCopyRights(\"%s\") succeeded.", authright
.name
);
1929 #endif /* HAVE_AUTHORIZATION_H */
1933 * 'compare_locations()' - Compare two locations.
1936 static int /* O - Result of comparison */
1937 compare_locations(cupsd_location_t
*a
, /* I - First location */
1938 cupsd_location_t
*b
) /* I - Second location */
1940 return (strcmp(b
->location
, a
->location
));
1945 * 'copy_authmask()' - Copy function for auth masks.
1948 static cupsd_authmask_t
* /* O - New auth mask */
1949 copy_authmask(cupsd_authmask_t
*mask
, /* I - Existing auth mask */
1950 void *data
) /* I - User data (unused) */
1952 cupsd_authmask_t
*temp
; /* New auth mask */
1957 if ((temp
= malloc(sizeof(cupsd_authmask_t
))) != NULL
)
1959 memcpy(temp
, mask
, sizeof(cupsd_authmask_t
));
1961 if (temp
->type
== CUPSD_AUTH_NAME
|| temp
->type
== CUPSD_AUTH_INTERFACE
)
1964 * Make a copy of the name...
1967 if ((temp
->mask
.name
.name
= _cupsStrAlloc(temp
->mask
.name
.name
)) == NULL
)
1970 * Failed to make copy...
1984 * 'free_authmask()' - Free function for auth masks.
1988 free_authmask(cupsd_authmask_t
*mask
, /* I - Auth mask to free */
1989 void *data
) /* I - User data (unused) */
1993 if (mask
->type
== CUPSD_AUTH_NAME
|| mask
->type
== CUPSD_AUTH_INTERFACE
)
1994 _cupsStrFree(mask
->mask
.name
.name
);
2002 * 'pam_func()' - PAM conversation function.
2005 static int /* O - Success or failure */
2007 int num_msg
, /* I - Number of messages */
2008 const struct pam_message
**msg
, /* I - Messages */
2009 struct pam_response
**resp
, /* O - Responses */
2011 /* I - Pointer to connection */
2013 int i
; /* Looping var */
2014 struct pam_response
*replies
; /* Replies */
2015 cupsd_authdata_t
*data
; /* Pointer to auth data */
2019 * Allocate memory for the responses...
2022 if ((replies
= malloc(sizeof(struct pam_response
) * (size_t)num_msg
)) == NULL
)
2023 return (PAM_CONV_ERR
);
2026 * Answer all of the messages...
2029 data
= (cupsd_authdata_t
*)appdata_ptr
;
2031 for (i
= 0; i
< num_msg
; i
++)
2033 switch (msg
[i
]->msg_style
)
2035 case PAM_PROMPT_ECHO_ON
:
2036 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2037 replies
[i
].resp
= strdup(data
->username
);
2040 case PAM_PROMPT_ECHO_OFF
:
2041 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2042 replies
[i
].resp
= strdup(data
->password
);
2046 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2047 replies
[i
].resp
= NULL
;
2051 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2052 replies
[i
].resp
= NULL
;
2057 return (PAM_CONV_ERR
);
2062 * Return the responses back to PAM...
2067 return (PAM_SUCCESS
);
2069 #endif /* HAVE_LIBPAM */