2 * Authorization routines for the CUPS scheduler.
4 * Copyright © 2020-2025 by OpenPrinting.
5 * Copyright © 2007-2019 by Apple Inc.
6 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
8 * This file contains Kerberos support code, copyright 2006 by
11 * Licensed under Apache License v2.0. See the file "LICENSE" for more
18 # ifdef HAVE_PAM_PAM_APPL_H
19 # include <pam/pam_appl.h>
21 # include <security/pam_appl.h>
22 # endif /* HAVE_PAM_PAM_APPL_H */
23 #endif /* HAVE_LIBPAM */
24 #ifdef HAVE_MEMBERSHIP_H
25 # include <membership.h>
26 #endif /* HAVE_MEMBERSHIP_H */
27 #ifdef HAVE_AUTHORIZATION_H
28 # include <Security/AuthorizationTags.h>
29 #endif /* HAVE_AUTHORIZATION_H */
30 #ifdef HAVE_SYS_PARAM_H
31 # include <sys/param.h>
32 #endif /* HAVE_SYS_PARAM_H */
33 #ifdef HAVE_SYS_UCRED_H
34 # include <sys/ucred.h>
35 typedef struct xucred cupsd_ucred_t
;
36 # define CUPSD_UCRED_UID(c) (c).cr_uid
39 typedef struct ucred cupsd_ucred_t
;
41 typedef struct sockpeercred cupsd_ucred_t
;
43 # define CUPSD_UCRED_UID(c) (c).uid
44 #endif /* HAVE_SYS_UCRED_H */
45 #ifdef HAVE_LIBAPPARMOR
46 # include <sys/apparmor.h>
47 #endif /* HAVE_LIBAPPARMOR */
48 #ifdef HAVE_LIBSNAPDGLIB
50 # include <snapd-glib/snapd-glib.h>
51 #endif /* HAVE_LIBSNAPDGLIB */
58 static int check_admin_access(cupsd_client_t
*con
);
59 #ifdef HAVE_AUTHORIZATION_H
60 static int check_authref(cupsd_client_t
*con
, const char *right
);
61 #endif /* HAVE_AUTHORIZATION_H */
62 static int compare_locations(cupsd_location_t
*a
, cupsd_location_t
*b
, void *data
);
63 static int compare_ogroups(cupsd_ogroup_t
*a
, cupsd_ogroup_t
*b
, void *data
);
64 static cupsd_authmask_t
*copy_authmask(cupsd_authmask_t
*am
, void *data
);
65 static void free_authmask(cupsd_authmask_t
*am
, void *data
);
66 static void free_ogroup(cupsd_ogroup_t
*og
, void *data
);
67 static int load_ogroup(cupsd_ogroup_t
*og
, struct stat
*fileinfo
);
69 static int pam_func(int, const struct pam_message
**,
70 struct pam_response
**, void *);
71 #endif /* HAVE_LIBPAM */
79 typedef struct cupsd_authdata_s
/**** Authentication data ****/
81 char username
[HTTP_MAX_VALUE
], /* Username string */
82 password
[HTTP_MAX_VALUE
]; /* Password string */
84 #endif /* HAVE_LIBPAM */
88 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
91 int /* O - 1 on success, 0 on failure */
93 cups_array_t
**masks
, /* IO - Masks array (created as needed) */
94 const unsigned address
[4], /* I - IP address */
95 const unsigned netmask
[4]) /* I - IP netmask */
97 cupsd_authmask_t temp
; /* New host/domain mask */
100 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", (void *)masks
, (void *)*masks
, address
[0], address
[1], address
[2], address
[3], netmask
[0], netmask
[1], netmask
[2], netmask
[3]);
102 temp
.type
= CUPSD_AUTH_IP
;
103 memcpy(temp
.mask
.ip
.address
, address
, sizeof(temp
.mask
.ip
.address
));
104 memcpy(temp
.mask
.ip
.netmask
, netmask
, sizeof(temp
.mask
.ip
.netmask
));
107 * Create the masks array as needed and add...
111 *masks
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
112 (cups_acopy_func_t
)copy_authmask
,
113 (cups_afree_func_t
)free_authmask
);
115 return (cupsArrayAdd(*masks
, &temp
));
120 * 'cupsdAddLocation()' - Add a location for authorization.
124 cupsdAddLocation(cupsd_location_t
*loc
) /* I - Location to add */
127 * Make sure the locations array is created...
131 Locations
= cupsArrayNew3((cups_array_func_t
)compare_locations
, NULL
,
132 (cups_ahash_func_t
)NULL
, 0,
133 (cups_acopy_func_t
)NULL
,
134 (cups_afree_func_t
)cupsdFreeLocation
);
138 cupsArrayAdd(Locations
, loc
);
140 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddLocation: Added location \"%s\"", loc
->location
? loc
->location
: "(null)");
146 * 'cupsdAddName()' - Add a name to a location...
150 cupsdAddName(cupsd_location_t
*loc
, /* I - Location to add to */
151 char *name
) /* I - Name to add */
153 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddName(loc=%p, name=\"%s\")", (void *)loc
, name
);
156 loc
->names
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
157 (cups_acopy_func_t
)_cupsArrayStrdup
,
158 (cups_afree_func_t
)_cupsArrayFree
);
160 if (!cupsArrayAdd(loc
->names
, name
))
162 cupsdLogMessage(CUPSD_LOG_ERROR
,
163 "Unable to duplicate name for location %s: %s",
164 loc
->location
? loc
->location
: "nil", strerror(errno
));
171 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
174 int /* O - 1 on success, 0 on failure */
175 cupsdAddNameMask(cups_array_t
**masks
, /* IO - Masks array (created as needed) */
176 char *name
) /* I - Host or interface name */
178 cupsd_authmask_t temp
; /* New host/domain mask */
179 char ifname
[32], /* Interface name */
180 *ifptr
; /* Pointer to end of name */
183 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", (void *)masks
, (void *)*masks
, name
);
185 if (!_cups_strcasecmp(name
, "@LOCAL"))
188 * Deny *interface*...
191 temp
.type
= CUPSD_AUTH_INTERFACE
;
192 temp
.mask
.name
.name
= (char *)"*";
194 else if (!_cups_strncasecmp(name
, "@IF(", 4))
197 * Deny *interface*...
200 cupsCopyString(ifname
, name
+ 4, sizeof(ifname
));
202 ifptr
= ifname
+ strlen(ifname
) - 1;
204 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 * 'cupsdAddOAuthGroup()' - Add an OAuth group file.
248 int /* O - 1 on success, 0 on error */
249 cupsdAddOAuthGroup(const char *name
, /* I - Group name */
250 const char *filename
)/* I - Group filename */
252 cupsd_ogroup_t
*og
; /* Group */
253 struct stat fileinfo
; /* File information */
257 * Check OAuth group file...
260 if (stat(filename
, &fileinfo
))
262 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to access OAuthGroup %s file \"%s\": %s", name
, filename
, strerror(errno
));
267 * Create the new group...
273 * Create groups array...
276 if ((OAuthGroups
= cupsArrayNew3((cups_array_cb_t
)compare_ogroups
, /*d*/NULL
, /*h*/NULL
, /*hsize*/0, /*cf*/NULL
, (cups_afree_cb_t
)free_ogroup
)) == NULL
)
278 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to allocate memory for OAuthGroup array: %s", strerror(errno
));
283 if ((og
= (cupsd_ogroup_t
*)calloc(1, sizeof(cupsd_ogroup_t
))) == NULL
)
285 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to allocate memory for OAuthGroup %s: %s", name
, strerror(errno
));
289 if ((og
->name
= strdup(name
)) == NULL
|| (og
->filename
= strdup(filename
)) == NULL
)
291 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to allocate memory for OAuthGroup %s: %s", name
, strerror(errno
));
292 free_ogroup(og
, NULL
);
297 * Add the group to the array...
300 cupsArrayAdd(OAuthGroups
, og
);
303 * Load the group and return...
306 return (load_ogroup(og
, &fileinfo
));
311 * 'cupsdAuthorize()' - Validate any authorization credentials.
315 cupsdAuthorize(cupsd_client_t
*con
) /* I - Client connection */
317 int type
; /* Authentication type */
318 const char *authorization
; /* Pointer into Authorization string */
319 char *ptr
, /* Pointer into string */
320 bearer
[4096], /* CUPS_BEARER cookie string */
321 username
[HTTP_MAX_VALUE
],
322 /* Username string */
323 password
[HTTP_MAX_VALUE
];
324 /* Password string */
325 cupsd_cert_t
*localuser
; /* Certificate username */
329 * Locate the best matching location so we know what kind of
330 * authentication to expect...
333 con
->best
= cupsdFindBest(con
->uri
, httpGetState(con
->http
));
334 con
->type
= CUPSD_AUTH_NONE
;
336 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "con->uri=\"%s\", con->best=%p(%s)", con
->uri
, (void *)con
->best
, con
->best
? con
->best
->location
: "");
338 if (con
->best
&& con
->best
->type
!= CUPSD_AUTH_NONE
)
340 if (con
->best
->type
== CUPSD_AUTH_DEFAULT
)
341 type
= cupsdDefaultAuthType();
343 type
= con
->best
->type
;
346 type
= cupsdDefaultAuthType();
349 * Decode the Authorization string...
352 authorization
= httpGetField(con
->http
, HTTP_FIELD_AUTHORIZATION
);
354 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cookie=\"%s\"", httpGetCookie(con
->http
));
356 if (!*authorization
&& httpGetCookieValue(con
->http
, "CUPS_BEARER", bearer
, sizeof(bearer
)) && bearer
[0])
357 authorization
= "Bearer COOKIE";
364 #endif /* HAVE_GSSAPI */
366 #ifdef HAVE_AUTHORIZATION_H
369 AuthorizationFree(con
->authref
, kAuthorizationFlagDefaults
);
372 #endif /* HAVE_AUTHORIZATION_H */
377 * No authorization data provided, return early...
380 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "No authentication data provided.");
383 #ifdef HAVE_AUTHORIZATION_H
384 else if (!strncmp(authorization
, "AuthRef ", 8) &&
385 httpAddrLocalhost(httpGetAddress(con
->http
)))
387 OSStatus status
; /* Status */
388 char authdata
[HTTP_MAX_VALUE
];
389 /* Nonce value from client */
390 int authlen
; /* Auth string length */
391 AuthorizationItemSet
*authinfo
; /* Authorization item set */
394 * Get the Authorization Services data...
398 while (isspace(*authorization
& 255))
401 authlen
= sizeof(authdata
);
402 httpDecode64_2(authdata
, &authlen
, authorization
);
404 if (authlen
!= kAuthorizationExternalFormLength
)
406 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "External Authorization reference size is incorrect.");
410 if ((status
= AuthorizationCreateFromExternalForm((AuthorizationExternalForm
*)authdata
, &con
->authref
)) != 0)
412 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "AuthorizationCreateFromExternalForm returned %d", (int)status
);
418 if (!AuthorizationCopyInfo(con
->authref
, kAuthorizationEnvironmentUsername
,
421 if (authinfo
->count
== 1 && authinfo
->items
[0].value
&&
422 authinfo
->items
[0].valueLength
>= 2)
424 cupsCopyString(username
, authinfo
->items
[0].value
, sizeof(username
));
426 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef.", username
);
429 AuthorizationFreeItemSet(authinfo
);
435 * No username in AuthRef, grab username using peer credentials...
438 struct passwd
*pwd
; /* Password entry for this user */
439 cupsd_ucred_t peercred
; /* Peer credentials */
440 socklen_t peersize
; /* Size of peer credentials */
442 peersize
= sizeof(peercred
);
444 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
446 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
450 if ((pwd
= getpwuid(CUPSD_UCRED_UID(peercred
))) == NULL
)
452 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred
));
456 cupsCopyString(username
, pwd
->pw_name
, sizeof(username
));
458 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using AuthRef + PeerCred.", username
);
461 con
->type
= CUPSD_AUTH_BASIC
;
463 #endif /* HAVE_AUTHORIZATION_H */
464 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
465 else if (!strncmp(authorization
, "PeerCred ", 9) &&
466 con
->http
->hostaddr
->addr
.sa_family
== AF_LOCAL
&& con
->best
)
469 * Use peer credentials from domain socket connection...
472 struct passwd
*pwd
; /* Password entry for this user */
473 cupsd_ucred_t peercred
; /* Peer credentials */
474 socklen_t peersize
; /* Size of peer credentials */
475 #ifdef HAVE_AUTHORIZATION_H
476 const char *name
; /* Authorizing name */
477 int no_peer
= 0; /* Don't allow peer credentials? */
480 * See if we should allow peer credentials...
483 for (name
= (char *)cupsArrayFirst(con
->best
->names
);
485 name
= (char *)cupsArrayNext(con
->best
->names
))
487 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) ||
488 !_cups_strcasecmp(name
, "@SYSTEM"))
490 /* Normally don't want peer credentials if we need an auth key... */
493 else if (!_cups_strcasecmp(name
, "@OWNER"))
495 /* but if @OWNER is present then we allow it... */
503 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
506 #endif /* HAVE_AUTHORIZATION_H */
508 if ((pwd
= getpwnam(authorization
+ 9)) == NULL
)
510 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "User \"%s\" does not exist.", authorization
+ 9);
514 peersize
= sizeof(peercred
);
517 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
519 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
, &peersize
))
520 # endif /* __APPLE__ */
522 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
526 if (pwd
->pw_uid
!= CUPSD_UCRED_UID(peercred
))
528 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization
+ 9, CUPSD_UCRED_UID(peercred
), pwd
->pw_uid
);
529 # ifdef HAVE_SYS_UCRED_H
530 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_version=%d", peercred
.cr_version
);
531 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_uid=%d", peercred
.cr_uid
);
532 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_ngroups=%d", peercred
.cr_ngroups
);
533 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "cr_groups[0]=%d", peercred
.cr_groups
[0]);
534 # endif /* HAVE_SYS_UCRED_H */
538 cupsCopyString(username
, authorization
+ 9, sizeof(username
));
541 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
542 # endif /* HAVE_GSSAPI */
544 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using PeerCred.", username
);
546 con
->type
= CUPSD_AUTH_BASIC
;
548 #endif /* SO_PEERCRED && AF_LOCAL */
549 else if (!strncmp(authorization
, "Local", 5) &&
550 httpAddrLocalhost(httpGetAddress(con
->http
)))
553 * Get Local certificate authentication data...
557 while (isspace(*authorization
& 255))
560 if ((localuser
= cupsdFindCert(authorization
)) == NULL
)
562 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Local authentication certificate not found.");
566 cupsCopyString(username
, localuser
->username
, sizeof(username
));
567 con
->type
= localuser
->type
;
569 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as %s using Local.", username
);
571 else if (!strncmp(authorization
, "Basic ", 6))
574 * Get the Basic authentication data...
577 int userlen
; /* Username:password length */
580 while (isspace(*authorization
& 255))
583 userlen
= sizeof(username
);
584 httpDecode64_2(username
, &userlen
, authorization
);
587 * Pull the username and password out...
590 if ((ptr
= strchr(username
, ':')) == NULL
)
592 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Missing Basic password.");
601 * Username must not be empty...
604 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic username.");
611 * Password must not be empty...
614 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Empty Basic password.");
618 cupsCopyString(password
, ptr
, sizeof(password
));
621 * Validate the username and password...
624 if (type
== CUPSD_AUTH_BASIC
)
628 * Only use PAM to do authentication. This supports MD5
629 * passwords, among other things...
632 pam_handle_t
*pamh
; /* PAM authentication handle */
633 int pamerr
; /* PAM error code */
634 struct pam_conv pamdata
; /* PAM conversation data */
635 cupsd_authdata_t data
; /* Authentication data */
636 struct passwd
*userinfo
; /* User information */
638 cupsCopyString(data
.username
, username
, sizeof(data
.username
));
639 cupsCopyString(data
.password
, password
, sizeof(data
.password
));
642 pamdata
.conv
= (int (*)(int, struct pam_message
**,
643 struct pam_response
**,
646 pamdata
.conv
= pam_func
;
648 pamdata
.appdata_ptr
= &data
;
650 pamerr
= pam_start("cups", username
, &pamdata
, &pamh
);
651 if (pamerr
!= PAM_SUCCESS
)
653 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_start() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
657 # ifdef HAVE_PAM_SET_ITEM
659 pamerr
= pam_set_item(pamh
, PAM_RHOST
, con
->http
->hostname
);
660 if (pamerr
!= PAM_SUCCESS
)
661 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
662 # endif /* PAM_RHOST */
665 pamerr
= pam_set_item(pamh
, PAM_TTY
, "cups");
666 if (pamerr
!= PAM_SUCCESS
)
667 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
668 # endif /* PAM_TTY */
669 # endif /* HAVE_PAM_SET_ITEM */
671 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
672 if (pamerr
!= PAM_SUCCESS
)
674 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_authenticate() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
679 # ifdef HAVE_PAM_SETCRED
680 pamerr
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
| PAM_SILENT
);
681 if (pamerr
!= PAM_SUCCESS
)
682 cupsdLogClient(con
, CUPSD_LOG_WARN
, "pam_setcred() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
683 # endif /* HAVE_PAM_SETCRED */
685 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
686 if (pamerr
!= PAM_SUCCESS
)
688 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "pam_acct_mgmt() returned %d (%s)", pamerr
, pam_strerror(pamh
, pamerr
));
693 pam_end(pamh
, PAM_SUCCESS
);
696 * Copy GECOS information, if available, to get the user's real name...
699 if ((userinfo
= getpwnam(username
)) != NULL
&& userinfo
->pw_gecos
)
700 cupsCopyString(con
->realname
, userinfo
->pw_gecos
, sizeof(con
->realname
));
702 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "No authentication support is available.");
704 #endif /* HAVE_LIBPAM */
707 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Basic.", username
);
710 else if (!strncmp(authorization
, "Bearer ", 7))
712 // OAuth/OpenID authorization using JWT bearer tokens...
713 cups_jwt_t
*jwt
; // JWT user information
714 const char *sub
, // Subject/user ID
716 *email
; // Email address
718 // Skip whitespace after "Bearer"...
720 while (isspace(*authorization
& 255))
723 if (!strcmp(authorization
, "COOKIE"))
724 authorization
= bearer
; // Use the cookie value for authorization
726 // Decode and validate the JWT...
727 if ((jwt
= cupsOAuthGetUserId(OAuthServer
, OAuthMetadata
, authorization
)) == NULL
)
729 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get user information from bearer token: %s", cupsGetErrorString());
730 cupsCopyString(con
->autherror
, cupsGetErrorString(), sizeof(con
->autherror
));
733 else if ((sub
= cupsJWTGetClaimString(jwt
, CUPS_JWT_SUB
)) == NULL
)
735 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Missing subject name in user information.");
736 cupsCopyString(con
->autherror
, "Missing subject name.", sizeof(con
->autherror
));
741 // Good JWT, grab information from it and return...
742 con
->type
= CUPSD_AUTH_BEARER
;
743 con
->autherror
[0] = '\0';
744 con
->password
[0] = '\0';
746 httpSetAuthString(con
->http
, "Bearer", authorization
);
747 cupsCopyString(con
->username
, sub
, sizeof(con
->username
));
748 if ((name
= cupsJWTGetClaimString(jwt
, CUPS_JWT_NAME
)) != NULL
)
749 cupsCopyString(con
->realname
, name
, sizeof(con
->realname
));
750 if ((email
= cupsJWTGetClaimString(jwt
, "email")) != NULL
)
751 cupsCopyString(con
->email
, email
, sizeof(con
->email
));
755 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" (%s <%s>) using OAuth/OpenID.", con
->username
, con
->realname
, con
->email
);
759 else if (!strncmp(authorization
, "Negotiate ", 10))
761 int len
; /* Length of authorization string */
762 gss_ctx_id_t context
; /* Authorization context */
763 OM_uint32 major_status
, /* Major status code */
764 minor_status
; /* Minor status code */
765 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
,
766 /* Input token from string */
767 output_token
= GSS_C_EMPTY_BUFFER
;
768 /* Output token for username */
769 gss_name_t client_name
; /* Client name */
771 # ifdef __APPLE__DISABLED // Remove DISABLED if ever this code is used for macOS installer
773 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
777 if (&gss_init_sec_context
== NULL
)
779 cupsdLogClient(con
, CUPSD_LOG_WARN
, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
782 # endif /* __APPLE__DISABLED */
785 * Find the start of the Kerberos input token...
789 while (isspace(*authorization
& 255))
794 cupsdLogClient(con
, CUPSD_LOG_DEBUG2
, "No authentication data specified.");
799 * Decode the authorization string to get the input token...
802 len
= (int)strlen(authorization
) + 0;
803 input_token
.value
= malloc((size_t)len
);
804 input_token
.value
= httpDecode64_2(input_token
.value
, &len
,
806 input_token
.length
= (size_t)len
;
809 * Accept the input token to get the authorization info...
812 context
= GSS_C_NO_CONTEXT
;
813 client_name
= GSS_C_NO_NAME
;
814 major_status
= gss_accept_sec_context(&minor_status
,
818 GSS_C_NO_CHANNEL_BINDINGS
,
826 if (output_token
.length
> 0)
827 gss_release_buffer(&minor_status
, &output_token
);
829 if (GSS_ERROR(major_status
))
831 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error accepting GSSAPI security context.", con
->number
);
833 if (context
!= GSS_C_NO_CONTEXT
)
834 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
841 * Get the username associated with the client's credentials...
844 if (major_status
== GSS_S_CONTINUE_NEEDED
)
845 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Credentials not complete.", con
->number
);
846 else if (major_status
== GSS_S_COMPLETE
)
848 major_status
= gss_display_name(&minor_status
, client_name
,
849 &output_token
, NULL
);
851 if (GSS_ERROR(major_status
))
853 cupsdLogGSSMessage(CUPSD_LOG_DEBUG
, major_status
, minor_status
, "[Client %d] Error getting username.", con
->number
);
854 gss_release_name(&minor_status
, &client_name
);
855 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
859 cupsCopyString(username
, output_token
.value
, sizeof(username
));
861 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Authorized as \"%s\" using Negotiate.", username
);
863 gss_release_name(&minor_status
, &client_name
);
864 gss_release_buffer(&minor_status
, &output_token
);
866 con
->type
= CUPSD_AUTH_NEGOTIATE
;
869 gss_delete_sec_context(&minor_status
, &context
, GSS_C_NO_BUFFER
);
871 # if defined(SO_PEERCRED) && defined(AF_LOCAL)
873 * Get the client's UID if we are printing locally - that allows a backend
874 * to run as the correct user to get Kerberos credentials of its own.
877 if (httpAddrFamily(con
->http
->hostaddr
) == AF_LOCAL
)
879 cupsd_ucred_t peercred
; /* Peer credentials */
880 socklen_t peersize
; /* Size of peer credentials */
882 peersize
= sizeof(peercred
);
885 if (getsockopt(httpGetFd(con
->http
), 0, LOCAL_PEERCRED
, &peercred
, &peersize
))
887 if (getsockopt(httpGetFd(con
->http
), SOL_SOCKET
, SO_PEERCRED
, &peercred
,
889 # endif /* __APPLE__ */
891 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to get peer credentials - %s", strerror(errno
));
895 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred
));
896 con
->gss_uid
= CUPSD_UCRED_UID(peercred
);
899 # endif /* SO_PEERCRED && AF_LOCAL */
901 #endif /* HAVE_GSSAPI */
904 char scheme
[256]; /* Auth scheme... */
907 if (sscanf(authorization
, "%255s", scheme
) != 1)
908 cupsCopyString(scheme
, "UNKNOWN", sizeof(scheme
));
910 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Bad authentication data \"%s ...\".", scheme
);
915 * If we get here, then we were able to validate the username and
916 * password - copy the validated username and password to the client
920 cupsCopyString(con
->username
, username
, sizeof(con
->username
));
922 if (!con
->realname
[0])
923 cupsCopyString(con
->realname
, username
, sizeof(con
->realname
));
925 cupsCopyString(con
->password
, password
, sizeof(con
->password
));
930 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
934 int /* O - 1 if allowed, 0 otherwise */
936 unsigned ip
[4], /* I - Client address */
937 const char *name
, /* I - Client hostname */
938 size_t namelen
, /* I - Length of hostname */
939 cupsd_location_t
*loc
) /* I - Location to check */
941 int allow
; /* 1 if allowed, 0 otherwise */
944 if (!_cups_strcasecmp(name
, "localhost"))
947 * Access from localhost (127.0.0.1 or ::1) is always allowed...
955 * Do authorization checks on the domain/address...
958 switch (loc
->order_type
)
961 allow
= 0; /* anti-compiler-warning-code */
964 case CUPSD_AUTH_ALLOW
: /* Order Deny,Allow */
967 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
970 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
974 case CUPSD_AUTH_DENY
: /* Order Allow,Deny */
977 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->allow
))
980 if (cupsdCheckAuth(ip
, name
, namelen
, loc
->deny
))
991 * 'cupsdCheckAuth()' - Check authorization masks.
994 int /* O - 1 if mask matches, 0 otherwise */
995 cupsdCheckAuth(unsigned ip
[4], /* I - Client address */
996 const char *name
, /* I - Client hostname */
997 size_t name_len
, /* I - Length of hostname */
998 cups_array_t
*masks
) /* I - Masks */
1000 int i
; /* Looping var */
1001 cupsd_authmask_t
*mask
; /* Current mask */
1002 cupsd_netif_t
*iface
; /* Network interface */
1003 unsigned netip4
; /* IPv4 network address */
1005 unsigned netip6
[4]; /* IPv6 network address */
1006 #endif /* AF_INET6 */
1009 for (mask
= (cupsd_authmask_t
*)cupsArrayFirst(masks
);
1011 mask
= (cupsd_authmask_t
*)cupsArrayNext(masks
))
1015 case CUPSD_AUTH_INTERFACE
:
1017 * Check for a match with a network interface...
1020 netip4
= htonl(ip
[3]);
1023 netip6
[0] = htonl(ip
[0]);
1024 netip6
[1] = htonl(ip
[1]);
1025 netip6
[2] = htonl(ip
[2]);
1026 netip6
[3] = htonl(ip
[3]);
1027 #endif /* AF_INET6 */
1031 if (!strcmp(mask
->mask
.name
.name
, "*"))
1035 * Allow Back-to-My-Mac addresses...
1038 if ((ip
[0] & 0xff000000) == 0xfd000000)
1040 #endif /* __APPLE__ */
1043 * Check against all local interfaces...
1046 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1048 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1051 * Only check local interfaces...
1054 if (!iface
->is_local
)
1057 if (iface
->address
.addr
.sa_family
== AF_INET
)
1060 * Check IPv4 address...
1063 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1064 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1065 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1072 * Check IPv6 address...
1075 for (i
= 0; i
< 4; i
++)
1076 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1077 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1078 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1084 #endif /* AF_INET6 */
1090 * Check the named interface...
1093 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
1095 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
1097 if (strcmp(mask
->mask
.name
.name
, iface
->name
))
1100 if (iface
->address
.addr
.sa_family
== AF_INET
)
1103 * Check IPv4 address...
1106 if ((netip4
& iface
->mask
.ipv4
.sin_addr
.s_addr
) ==
1107 (iface
->address
.ipv4
.sin_addr
.s_addr
&
1108 iface
->mask
.ipv4
.sin_addr
.s_addr
))
1115 * Check IPv6 address...
1118 for (i
= 0; i
< 4; i
++)
1119 if ((netip6
[i
] & iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]) !=
1120 (iface
->address
.ipv6
.sin6_addr
.s6_addr32
[i
] &
1121 iface
->mask
.ipv6
.sin6_addr
.s6_addr32
[i
]))
1127 #endif /* AF_INET6 */
1132 case CUPSD_AUTH_NAME
:
1134 * Check for exact name match...
1137 if (!_cups_strcasecmp(name
, mask
->mask
.name
.name
))
1141 * Check for domain match...
1144 if (name_len
>= mask
->mask
.name
.length
&&
1145 mask
->mask
.name
.name
[0] == '.' &&
1146 !_cups_strcasecmp(name
+ name_len
- mask
->mask
.name
.length
,
1147 mask
->mask
.name
.name
))
1151 case CUPSD_AUTH_IP
:
1153 * Check for IP/network address match...
1156 for (i
= 0; i
< 4; i
++)
1157 if ((ip
[i
] & mask
->mask
.ip
.netmask
[i
]) !=
1158 mask
->mask
.ip
.address
[i
])
1172 * 'cupsdCheckGroup()' - Check for a user's group membership.
1175 int /* O - 1 if user is a member, 0 otherwise */
1177 const char *username
, /* I - User name */
1178 struct passwd
*user
, /* I - System user info */
1179 const char *groupname
) /* I - Group name */
1181 int i
; /* Looping var */
1182 struct group
*group
; /* Group info */
1183 gid_t groupid
; /* ID of named group */
1184 #ifdef HAVE_MBR_UID_TO_UUID
1185 uuid_t useruuid
, /* UUID for username */
1186 groupuuid
; /* UUID for groupname */
1187 int is_member
; /* True if user is a member of group */
1188 #endif /* HAVE_MBR_UID_TO_UUID */
1191 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username
, (void *)user
, groupname
);
1197 if (!username
|| !groupname
)
1201 * Check to see if the user is a member of the named group...
1204 group
= getgrnam(groupname
);
1210 * Group exists, check it...
1213 groupid
= group
->gr_gid
;
1215 for (i
= 0; group
->gr_mem
[i
]; i
++)
1218 * User appears in the group membership...
1221 if (!_cups_strcasecmp(username
, group
->gr_mem
[i
]))
1225 #ifdef HAVE_GETGROUPLIST
1227 * If the user isn't in the group membership list, try the results from
1228 * getgrouplist() which is supposed to return the full list of groups a user
1234 int ngroups
; /* Number of groups */
1236 int groups
[2048]; /* Groups that user belongs to */
1238 gid_t groups
[2048]; /* Groups that user belongs to */
1239 # endif /* __APPLE__ */
1241 ngroups
= (int)(sizeof(groups
) / sizeof(groups
[0]));
1243 getgrouplist(username
, (int)user
->pw_gid
, groups
, &ngroups
);
1245 getgrouplist(username
, user
->pw_gid
, groups
, &ngroups
);
1246 #endif /* __APPLE__ */
1248 for (i
= 0; i
< ngroups
; i
++)
1249 if ((int)groupid
== (int)groups
[i
])
1252 #endif /* HAVE_GETGROUPLIST */
1255 groupid
= (gid_t
)-1;
1258 * Group doesn't exist or user not in group list, check the group ID
1259 * against the user's group ID...
1262 if (user
&& groupid
== user
->pw_gid
)
1265 #ifdef HAVE_MBR_UID_TO_UUID
1267 * Check group membership through macOS membership API...
1270 if (user
&& !mbr_uid_to_uuid(user
->pw_uid
, useruuid
))
1272 if (groupid
!= (gid_t
)-1)
1275 * Map group name to UUID and check membership...
1278 if (!mbr_gid_to_uuid(groupid
, groupuuid
))
1279 if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1283 else if (groupname
[0] == '#')
1286 * Use UUID directly and check for equality (user UUID) and
1287 * membership (group UUID)...
1290 if (!uuid_parse((char *)groupname
+ 1, groupuuid
))
1292 if (!uuid_compare(useruuid
, groupuuid
))
1294 else if (!mbr_check_membership(useruuid
, groupuuid
, &is_member
))
1302 else if (groupname
[0] == '#')
1304 #endif /* HAVE_MBR_UID_TO_UUID */
1307 * If we get this far, then the user isn't part of the named group...
1315 * 'cupsdCopyLocation()' - Make a copy of a location...
1318 cupsd_location_t
* /* O - New location */
1320 cupsd_location_t
*loc
) /* I - Original location */
1322 cupsd_location_t
*temp
; /* New location */
1326 * Make a copy of the original location...
1329 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
1333 * Copy the information from the original location to the new one.
1340 temp
->location
= _cupsStrAlloc(loc
->location
);
1342 temp
->length
= loc
->length
;
1343 temp
->limit
= loc
->limit
;
1344 temp
->order_type
= loc
->order_type
;
1345 temp
->type
= loc
->type
;
1346 temp
->level
= loc
->level
;
1347 temp
->satisfy
= loc
->satisfy
;
1348 temp
->encryption
= loc
->encryption
;
1352 if ((temp
->names
= cupsArrayDup(loc
->names
)) == NULL
)
1354 cupsdLogMessage(CUPSD_LOG_ERROR
,
1355 "Unable to allocate memory for %d names: %s",
1356 cupsArrayCount(loc
->names
), strerror(errno
));
1358 cupsdFreeLocation(temp
, NULL
);
1366 * Copy allow rules...
1369 if ((temp
->allow
= cupsArrayDup(loc
->allow
)) == NULL
)
1371 cupsdLogMessage(CUPSD_LOG_ERROR
,
1372 "Unable to allocate memory for %d allow rules: %s",
1373 cupsArrayCount(loc
->allow
), strerror(errno
));
1374 cupsdFreeLocation(temp
, NULL
);
1382 * Copy deny rules...
1385 if ((temp
->deny
= cupsArrayDup(loc
->deny
)) == NULL
)
1387 cupsdLogMessage(CUPSD_LOG_ERROR
,
1388 "Unable to allocate memory for %d deny rules: %s",
1389 cupsArrayCount(loc
->deny
), strerror(errno
));
1390 cupsdFreeLocation(temp
, NULL
);
1400 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1404 cupsdDeleteAllLocations(void)
1407 * Free the location array, which will free all of the locations...
1410 cupsArrayDelete(Locations
);
1416 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1419 cupsd_location_t
* /* O - Location that matches */
1420 cupsdFindBest(const char *path
, /* I - Resource path */
1421 http_state_t state
) /* I - HTTP state/request */
1423 char uri
[HTTP_MAX_URI
],
1424 /* URI in request... */
1425 *uriptr
; /* Pointer into URI */
1426 cupsd_location_t
*loc
, /* Current location */
1427 *best
; /* Best match for location so far */
1428 size_t bestlen
; /* Length of best match */
1429 int limit
; /* Limit field */
1430 static const int limits
[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1432 CUPSD_AUTH_LIMIT_ALL
,
1433 CUPSD_AUTH_LIMIT_OPTIONS
,
1434 CUPSD_AUTH_LIMIT_GET
,
1435 CUPSD_AUTH_LIMIT_GET
,
1436 CUPSD_AUTH_LIMIT_HEAD
,
1437 CUPSD_AUTH_LIMIT_POST
,
1438 CUPSD_AUTH_LIMIT_POST
,
1439 CUPSD_AUTH_LIMIT_POST
,
1440 CUPSD_AUTH_LIMIT_PUT
,
1441 CUPSD_AUTH_LIMIT_PUT
,
1442 CUPSD_AUTH_LIMIT_DELETE
,
1443 CUPSD_AUTH_LIMIT_TRACE
,
1444 CUPSD_AUTH_LIMIT_ALL
,
1445 CUPSD_AUTH_LIMIT_ALL
,
1446 CUPSD_AUTH_LIMIT_ALL
,
1447 CUPSD_AUTH_LIMIT_ALL
1452 * First copy the connection URI to a local string so we have drop
1453 * any .ppd extension from the pathname in /printers or /classes
1457 cupsCopyString(uri
, path
, sizeof(uri
));
1459 if ((uriptr
= strchr(uri
, '?')) != NULL
)
1460 *uriptr
= '\0'; /* Drop trailing query string */
1462 if ((uriptr
= uri
+ strlen(uri
) - 1) > uri
&& *uriptr
== '/')
1463 *uriptr
= '\0'; /* Remove trailing '/' */
1465 if (!strncmp(uri
, "/printers/", 10) ||
1466 !strncmp(uri
, "/classes/", 9))
1469 * Check if the URI has .ppd on the end...
1472 uriptr
= uri
+ strlen(uri
) - 4; /* len > 4 if we get here... */
1474 if (!strcmp(uriptr
, ".ppd"))
1479 * Loop through the list of locations to find a match...
1482 limit
= limits
[state
];
1486 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: uri=\"%s\", limit=%x...", uri
, limit
);
1489 for (loc
= (cupsd_location_t
*)cupsArrayFirst(Locations
);
1491 loc
= (cupsd_location_t
*)cupsArrayNext(Locations
))
1493 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: Location %s(%d) Limit %x", loc
->location
? loc
->location
: "(null)", (int)loc
->length
, loc
->limit
);
1495 if (!strncmp(uri
, "/printers/", 10) || !strncmp(uri
, "/classes/", 9))
1498 * Use case-insensitive comparison for queue names...
1501 if (loc
->length
> bestlen
&& loc
->location
&&
1502 !_cups_strncasecmp(uri
, loc
->location
, loc
->length
) &&
1503 loc
->location
[0] == '/' &&
1504 (limit
& loc
->limit
) != 0)
1507 bestlen
= loc
->length
;
1513 * Use case-sensitive comparison for other URIs...
1516 if (loc
->length
> bestlen
&& loc
->location
&&
1517 !strncmp(uri
, loc
->location
, loc
->length
) &&
1518 loc
->location
[0] == '/' &&
1519 (limit
& loc
->limit
) != 0)
1522 bestlen
= loc
->length
;
1528 * Return the match, if any...
1531 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindBest: best=%s", best
? best
->location
: "NONE");
1538 * 'cupsdFindLocation()' - Find the named location.
1541 cupsd_location_t
* /* O - Location that matches */
1542 cupsdFindLocation(const char *location
) /* I - Connection */
1544 cupsd_location_t key
; /* Search key */
1547 key
.location
= (char *)location
;
1549 return ((cupsd_location_t
*)cupsArrayFind(Locations
, &key
));
1554 * 'cupsdFindOAuthGroup()' - Find an OAuth group.
1557 cupsd_ogroup_t
* /* O - Group or `NULL` */
1558 cupsdFindOAuthGroup(const char *name
) /* I - Group name */
1560 cupsd_ogroup_t key
, /* Search key */
1561 *og
; /* Matching group */
1562 struct stat fileinfo
; /* Group file information */
1565 key
.name
= (char *)name
;
1566 if ((og
= (cupsd_ogroup_t
*)cupsArrayFind(OAuthGroups
, &key
)) != NULL
)
1569 * See if we need to reload the group file...
1572 if (!stat(og
->filename
, &fileinfo
) && (fileinfo
.st_size
!= og
->fileinfo
.st_size
|| fileinfo
.st_mtime
> og
->fileinfo
.st_mtime
))
1573 load_ogroup(og
, &fileinfo
);
1581 * 'cupsdFreeLocation()' - Free all memory used by a location.
1584 void cupsdFreeLocation(cupsd_location_t
*loc
, /* I - Location to free */
1585 void *data
) /* Unused */
1588 cupsArrayDelete(loc
->names
);
1589 cupsArrayDelete(loc
->allow
);
1590 cupsArrayDelete(loc
->deny
);
1592 _cupsStrFree(loc
->location
);
1598 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1601 http_status_t
/* O - HTTP_OK if authorized or error code */
1602 cupsdIsAuthorized(cupsd_client_t
*con
, /* I - Connection */
1603 const char *owner
)/* I - Owner of object */
1605 int i
, /* Looping vars */
1606 auth
, /* Authorization status */
1607 type
; /* Type of authentication */
1608 http_addr_t
*hostaddr
= httpGetAddress(con
->http
);
1609 /* Client address */
1610 const char *hostname
= httpGetHostname(con
->http
, NULL
, 0);
1611 /* Client hostname */
1612 unsigned address
[4]; /* Authorization address */
1613 cupsd_location_t
*best
; /* Best match for location so far */
1614 size_t hostlen
; /* Length of hostname */
1615 char *name
, /* Current username */
1616 username
[256], /* Username to authorize */
1617 ownername
[256], /* Owner name to authorize */
1618 *ptr
; /* Pointer into username */
1619 struct passwd
*pw
; /* User password data */
1620 static const char * const levels
[] = /* Auth levels */
1626 static const char * const types
[] = /* Auth types */
1635 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con
->uri
, (void *)con
->best
, con
->best
? con
->best
->location
? con
->best
->location
: "(null)" : "");
1637 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: owner=\"%s\"", owner
);
1640 * If there is no "best" authentication rule for this request, then
1641 * access is allowed from the local system and denied from other
1647 if (httpAddrLocalhost(httpGetAddress(con
->http
)) ||
1648 !strcmp(hostname
, ServerName
) ||
1649 cupsArrayFind(ServerAlias
, (void *)hostname
))
1650 return (HTTP_STATUS_OK
);
1652 return (HTTP_STATUS_FORBIDDEN
);
1657 if ((type
= best
->type
) == CUPSD_AUTH_DEFAULT
)
1658 type
= cupsdDefaultAuthType();
1660 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
));
1662 if (best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1663 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: op=%x(%s)", best
->op
, ippOpString(best
->op
));
1666 * Check host/ip-based accesses...
1670 if (httpAddrFamily(hostaddr
) == AF_INET6
)
1673 * Copy IPv6 address...
1676 address
[0] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[0]);
1677 address
[1] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[1]);
1678 address
[2] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[2]);
1679 address
[3] = ntohl(hostaddr
->ipv6
.sin6_addr
.s6_addr32
[3]);
1682 #endif /* AF_INET6 */
1683 if (con
->http
->hostaddr
->addr
.sa_family
== AF_INET
)
1686 * Copy IPv4 address...
1692 address
[3] = ntohl(hostaddr
->ipv4
.sin_addr
.s_addr
);
1695 memset(address
, 0, sizeof(address
));
1697 hostlen
= strlen(hostname
);
1699 auth
= cupsdCheckAccess(address
, hostname
, hostlen
, best
)
1700 ? CUPSD_AUTH_ALLOW
: CUPSD_AUTH_DENY
;
1702 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth
? "DENY" : "ALLOW");
1704 if (auth
== CUPSD_AUTH_DENY
&& best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
)
1705 return (HTTP_STATUS_FORBIDDEN
);
1708 * See if encryption is required...
1711 if ((best
->encryption
>= HTTP_ENCRYPTION_REQUIRED
&& !con
->http
->tls
&&
1712 _cups_strcasecmp(hostname
, "localhost") &&
1713 !httpAddrLocalhost(hostaddr
) &&
1714 best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
) &&
1715 !(type
== CUPSD_AUTH_NEGOTIATE
||
1716 (type
== CUPSD_AUTH_NONE
&&
1717 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE
)))
1719 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1720 "cupsdIsAuthorized: Need upgrade to TLS...");
1721 return (HTTP_STATUS_UPGRADE_REQUIRED
);
1725 * Now see what access level is required...
1728 if (best
->level
== CUPSD_AUTH_ANON
|| /* Anonymous access - allow it */
1729 (type
== CUPSD_AUTH_NONE
&& cupsArrayCount(best
->names
) == 0))
1730 return (HTTP_STATUS_OK
);
1732 if (!con
->username
[0] && type
== CUPSD_AUTH_NONE
&&
1733 best
->limit
== CUPSD_AUTH_LIMIT_IPP
)
1736 * Check for unauthenticated username...
1739 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
1742 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1745 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1746 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1747 attr
->values
[0].string
.text
);
1748 cupsCopyString(username
, attr
->values
[0].string
.text
, sizeof(username
));
1750 else if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1751 return (HTTP_STATUS_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1753 return (HTTP_STATUS_OK
); /* unless overridden with Satisfy */
1757 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: username=\"%s\"",
1760 #ifdef HAVE_AUTHORIZATION_H
1761 if (!con
->username
[0] && !con
->authref
)
1763 if (!con
->username
[0])
1764 #endif /* HAVE_AUTHORIZATION_H */
1766 if (best
->satisfy
== CUPSD_AUTH_SATISFY_ALL
|| auth
== CUPSD_AUTH_DENY
)
1767 return (HTTP_STATUS_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
1769 return (HTTP_STATUS_OK
); /* unless overridden with Satisfy */
1773 if (con
->type
!= type
&& type
!= CUPSD_AUTH_NONE
&&
1775 (type
!= CUPSD_AUTH_NEGOTIATE
|| con
->gss_uid
<= 0) &&
1776 #endif /* HAVE_GSSAPI */
1777 con
->type
!= CUPSD_AUTH_BASIC
)
1779 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorized using %s, expected %s.",
1780 types
[con
->type
], types
[type
]);
1782 return (HTTP_STATUS_UNAUTHORIZED
);
1785 cupsCopyString(username
, con
->username
, sizeof(username
));
1789 * OK, got a username. See if we need normal user access, or group
1794 * Strip any @domain or @KDC from the username and owner...
1797 if (type
!= CUPSD_AUTH_BEARER
&& StripUserDomain
&& (ptr
= strchr(username
, '@')) != NULL
)
1802 cupsCopyString(ownername
, owner
, sizeof(ownername
));
1804 if (type
!= CUPSD_AUTH_BEARER
&& StripUserDomain
&& (ptr
= strchr(ownername
, '@')) != NULL
)
1808 ownername
[0] = '\0';
1810 if (type
== CUPSD_AUTH_BEARER
)
1813 * Lookup access via OAuth groups...
1816 cupsd_ogroup_t
*og
; // Current OAuth group
1818 if (best
->level
== CUPSD_AUTH_USER
)
1821 * If there are no names associated with this location, then any valid user
1825 if (cupsArrayCount(best
->names
) == 0)
1826 return (HTTP_STATUS_OK
);
1829 * Otherwise check the user list and return OK if this user is allowed...
1832 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking user membership...");
1834 for (name
= (char *)cupsArrayFirst(best
->names
); name
; name
= (char *)cupsArrayNext(best
->names
))
1836 if (!_cups_strcasecmp(name
, "@OWNER") && owner
&& !_cups_strcasecmp(username
, ownername
))
1839 return (HTTP_STATUS_OK
);
1841 else if (name
[0] == '@')
1843 // Check OAuth group membership...
1844 if ((og
= cupsdFindOAuthGroup(name
+ 1)) == NULL
)
1846 // Group not defined...
1847 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorization policy requires undefined OAuth group \"%s\", ignoring.", name
+ 1);
1849 else if (cupsArrayFind(og
->members
, username
) || (con
->email
[0] && cupsArrayFind(og
->members
, con
->email
)))
1851 // User is in group...
1852 return (HTTP_STATUS_OK
);
1855 else if (!_cups_strcasecmp(username
, name
) || (con
->email
[0] && !_cups_strcasecmp(con
->email
, name
)))
1857 return (HTTP_STATUS_OK
);
1864 * Check to see if this user is in any of the named groups...
1867 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group membership...");
1870 * Check to see if this user is in any of the named groups...
1873 for (name
= (char *)cupsArrayFirst(best
->names
); name
; name
= (char *)cupsArrayNext(best
->names
))
1875 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership.", name
);
1877 if ((og
= cupsdFindOAuthGroup(name
)) == NULL
)
1879 // Group not defined...
1880 cupsdLogMessage(CUPSD_LOG_ERROR
, "Authorization policy requires undefined OAuth group \"%s\", ignoring.", name
+ 1);
1882 else if (cupsArrayFind(og
->members
, username
) || (con
->email
[0] && cupsArrayFind(og
->members
, con
->email
)))
1884 // User is in group...
1885 return (HTTP_STATUS_OK
);
1893 * Get the (local) user info...
1898 pw
= getpwnam(username
);
1905 * For matching user and group memberships below we will first go
1906 * through all names except @SYSTEM to authorize the task as
1907 * non-administrative, like printing or deleting one's own job, if this
1908 * fails we will check whether we can authorize via the special name
1909 * @SYSTEM, as an administrative task, like creating a print queue or
1910 * deleting someone else's job.
1912 * Note that tasks are considered as administrative by the policies
1913 * in cupsd.conf, when they require the user or group @SYSTEM.
1914 * We do this separation because if the client is a Snap connecting via
1915 * domain socket, we need to additionally check whether it plugs to us
1916 * through the "cups-control" interface which allows administration and
1917 * not through the "cups" interface which allows only printing.
1920 if (best
->level
== CUPSD_AUTH_USER
)
1923 * If there are no names associated with this location, then
1924 * any valid user is OK...
1927 if (cupsArrayCount(best
->names
) == 0)
1928 return (HTTP_STATUS_OK
);
1931 * Otherwise check the user list and return OK if this user is
1935 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking user membership...");
1937 #ifdef HAVE_AUTHORIZATION_H
1939 * If an authorization reference was supplied it must match a right name...
1944 for (name
= (char *)cupsArrayFirst(best
->names
);
1946 name
= (char *)cupsArrayNext(best
->names
))
1948 if (!_cups_strncasecmp(name
, "@AUTHKEY(", 9) && check_authref(con
, name
+ 9))
1949 return (HTTP_STATUS_OK
);
1952 for (name
= (char *)cupsArrayFirst(best
->names
);
1954 name
= (char *)cupsArrayNext(best
->names
))
1956 if (!_cups_strcasecmp(name
, "@SYSTEM") && SystemGroupAuthKey
&&
1957 check_authref(con
, SystemGroupAuthKey
))
1958 return (HTTP_STATUS_OK
);
1961 return (HTTP_STATUS_FORBIDDEN
);
1963 #endif /* HAVE_AUTHORIZATION_H */
1965 for (name
= (char *)cupsArrayFirst(best
->names
);
1967 name
= (char *)cupsArrayNext(best
->names
))
1969 if (!_cups_strcasecmp(name
, "@OWNER") && owner
&&
1970 !_cups_strcasecmp(username
, ownername
))
1971 return (HTTP_STATUS_OK
);
1972 else if (!_cups_strcasecmp(name
, "@SYSTEM"))
1974 /* Do @SYSTEM later, when every other entry fails */
1977 else if (name
[0] == '@')
1979 if (cupsdCheckGroup(username
, pw
, name
+ 1))
1980 return (HTTP_STATUS_OK
);
1982 else if (!_cups_strcasecmp(username
, name
))
1983 return (HTTP_STATUS_OK
);
1986 for (name
= (char *)cupsArrayFirst(best
->names
);
1988 name
= (char *)cupsArrayNext(best
->names
))
1990 if (!_cups_strcasecmp(name
, "@SYSTEM"))
1992 for (i
= 0; i
< NumSystemGroups
; i
++)
1993 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]) && check_admin_access(con
))
1994 return (HTTP_STATUS_OK
);
2001 * Check to see if this user is in any of the named groups...
2004 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group membership...");
2007 * Check to see if this user is in any of the named groups...
2010 for (name
= (char *)cupsArrayFirst(best
->names
);
2012 name
= (char *)cupsArrayNext(best
->names
))
2014 if (!_cups_strcasecmp(name
, "@SYSTEM"))
2016 /* Do @SYSTEM later, when every other entry fails */
2020 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership...", name
);
2022 if (cupsdCheckGroup(username
, pw
, name
))
2023 return (HTTP_STATUS_OK
);
2026 for (name
= (char *)cupsArrayFirst(best
->names
);
2028 name
= (char *)cupsArrayNext(best
->names
))
2030 if (!_cups_strcasecmp(name
, "@SYSTEM"))
2032 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdIsAuthorized: Checking group \"%s\" membership...", name
);
2034 for (i
= 0; i
< NumSystemGroups
; i
++)
2035 if (cupsdCheckGroup(username
, pw
, SystemGroups
[i
]) && check_admin_access(con
))
2036 return (HTTP_STATUS_OK
);
2043 * The user isn't part of the specified users or groups, so deny access...
2046 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdIsAuthorized: User not in group(s).");
2048 return (con
->username
[0] ? HTTP_STATUS_FORBIDDEN
: HTTP_STATUS_UNAUTHORIZED
);
2053 * 'cupsdNewLocation()' - Create a new location for authorization.
2055 * Note: Still need to call cupsdAddLocation() to add it to the list of global
2059 cupsd_location_t
* /* O - Pointer to new location record */
2060 cupsdNewLocation(const char *location
) /* I - Location path */
2062 cupsd_location_t
*temp
; /* New location */
2066 * Try to allocate memory for the new location.
2069 if ((temp
= calloc(1, sizeof(cupsd_location_t
))) == NULL
)
2073 * Initialize the record and copy the name over...
2076 if ((temp
->location
= _cupsStrAlloc(location
)) == NULL
)
2082 temp
->length
= strlen(temp
->location
);
2085 * Return the new record...
2093 * 'check_admin_access()' - Verify that the client has administrative access.
2096 static int // O - 1 if authorized, 0 otherwise
2097 check_admin_access(cupsd_client_t
*con
) // I - Client connection
2101 #if defined(HAVE_LIBAPPARMOR) && defined(HAVE_LIBSNAPDGLIB)
2103 * If the client accesses locally via domain socket, find out whether it
2104 * is a Snap. Grant access if it is not a Snap, if it is a classic Snap
2105 * or if it is a confined Snap which plugs "cups-control". Otherwise deny
2109 int fd
= httpGetFd(con
->http
);
2110 // Client socket file descriptor
2111 char *context
= NULL
; // AppArmor profile name of client
2112 SnapdClient
*client
= NULL
; // Data structure of snapd access
2113 GError
*error
= NULL
; // Glib error
2114 int ret
= 1; // Return value
2116 SnapdSnap
*snap
= NULL
; // Data structure of client Snap
2117 # endif // !CUPS_SNAP
2121 // Only check domain sockets...
2122 if (httpAddrFamily(con
->http
->hostaddr
) != AF_LOCAL
)
2127 // If AppArmor is not enabled, then we can't identify the client...
2128 if (!aa_is_enabled())
2130 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "AppArmor not in use.");
2133 # endif /* !CUPS_SNAP */
2135 // Get the client's AppArmor context using the socket...
2136 if (aa_getpeercon(fd
, &context
, NULL
) < 0)
2138 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "AppArmor profile could not be retrieved: %s", strerror(errno
));
2143 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "AppArmor profile is '%s'.", context
);
2146 // Allow access from "cups" snap...
2147 if (!strncmp(context
, "snap.cups.", 10))
2149 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Client from the CUPS Snap itself - allowed.");
2153 # if CUPS_SNAP && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC)
2155 * CUPS is snapped, so check whether the client is also snapped. If so,
2156 * determine whether the client snap has a "cups-control" plug which allows
2157 * the application to perform CUPS administrative tasks.
2160 const char *cookie
; // snapd access cookie
2161 int status
= 65535; // Status of client Snap context check
2162 const char *args
[] = // snapctl arguments
2172 if ((client
= snapd_client_new()) == NULL
)
2174 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to connect to snapd.");
2179 // snapctl commands are sent over a domain socket
2180 snapd_client_set_socket_path(client
, "/run/snapd-snap.socket");
2182 // Take cookie from the environment if available
2183 if ((cookie
= g_getenv("SNAP_COOKIE")) == NULL
)
2186 cupsdLogClient(con
, CUPSD_LOG_WARN
, "No SNAP_COOKIE set in the Snap environment.");
2189 // Do the client Snap context check...
2192 if (!snapd_client_run_snapctl2_sync(client
, cookie
, (char **)args
, NULL
, NULL
, &status
, NULL
, &error
))
2194 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to check snap context: %s", error
->message
);
2201 case 0 : // The client is a confined Snap and plugs cups-control
2202 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Snap with cups-control plug - allowed.");
2204 case 1 : // The client is a confined Snap and does not plug cups-control
2205 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Snap without cups-control plug - denied.");
2208 case 10 : // The client is a classic Snap
2209 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Classic snap - allowed.");
2211 case 11 : // The client is not a Snap
2212 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Not a snap - allowed.");
2214 default : // Unexpected status...
2215 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Snap check returned unexpected status %d - denied.", status
);
2222 * If CUPS is not snapped, check whether the client is snapped and if it has
2223 * the "cups-control" plug.
2226 // Is the client a snapped application?
2227 if (strncmp(context
, "snap.", 5))
2229 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Not a snap - allowed.");
2233 // Extract the snap name from the context (snap.name.instance)
2234 char *snap_name
= strdup(context
+ 5);// Snap name follows "snap."
2235 char *ptr
= strchr(snap_name
, '.'); // instance follows the name...
2238 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Malformed snapd AppArmor profile name '%s' - denied.", context
);
2245 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Client snap is '%s'.", snap_name
);
2248 if ((client
= snapd_client_new()) == NULL
)
2250 cupsdLogClient(con
, CUPSD_LOG_ERROR
, "Unable to connect to snapd.");
2256 // Check whether the client Snap is under classic confinement
2257 GPtrArray
*plugs
= NULL
; // List of plugs for snap
2259 if ((snap
= snapd_client_get_snap_sync(client
, snap_name
, NULL
, &error
)) == NULL
)
2261 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Unable to get client Snap data: %s", error
->message
);
2264 // Snaps using classic confinement are granted access
2265 else if (snapd_snap_get_confinement(snap
) == SNAPD_CONFINEMENT_CLASSIC
)
2267 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Classic snap - allowed.");
2269 // Check whether the client Snap has the cups-control plug
2270 else if (!snapd_client_get_connections2_sync(client
, SNAPD_GET_CONNECTIONS_FLAGS_NONE
, snap_name
, "cups-control", NULL
, NULL
, &plugs
, NULL
, NULL
, &error
))
2272 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Unable to get client Snap plugs: %s", error
->message
);
2275 else if (!plugs
|| plugs
->len
<= 0)
2277 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Snap without cups-control plug - denied.");
2282 cupsdLogClient(con
, CUPSD_LOG_DEBUG
, "Snap with cups-control plug - allowed.");
2286 g_ptr_array_unref(plugs
);
2289 g_clear_object(&snap
);
2291 # endif // CUPS_SNAP
2296 g_clear_object(&client
);
2301 // No AppArmor/snapd to deal with...
2303 #endif // HAVE_LIBAPPARMOR && HAVE_LIBSNAPDGLIB
2307 #ifdef HAVE_AUTHORIZATION_H
2309 * 'check_authref()' - Check if an authorization services reference has the
2313 static int /* O - 1 if right is valid, 0 otherwise */
2314 check_authref(cupsd_client_t
*con
, /* I - Connection */
2315 const char *right
) /* I - Right name */
2317 OSStatus status
; /* OS Status */
2318 AuthorizationItem authright
; /* Authorization right */
2319 AuthorizationRights authrights
; /* Authorization rights */
2320 AuthorizationFlags authflags
; /* Authorization flags */
2324 * Check to see if the user is allowed to perform the task...
2330 authright
.name
= right
;
2331 authright
.valueLength
= 0;
2332 authright
.value
= NULL
;
2333 authright
.flags
= 0;
2335 authrights
.count
= 1;
2336 authrights
.items
= &authright
;
2338 authflags
= kAuthorizationFlagDefaults
|
2339 kAuthorizationFlagExtendRights
;
2341 if ((status
= AuthorizationCopyRights(con
->authref
, &authrights
,
2342 kAuthorizationEmptyEnvironment
,
2343 authflags
, NULL
)) != 0)
2345 cupsdLogMessage(CUPSD_LOG_ERROR
, "AuthorizationCopyRights(\"%s\") returned %d", authright
.name
, (int)status
);
2349 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "AuthorizationCopyRights(\"%s\") succeeded.", authright
.name
);
2353 #endif /* HAVE_AUTHORIZATION_H */
2357 * 'compare_locations()' - Compare two locations.
2360 static int /* O - Result of comparison */
2361 compare_locations(cupsd_location_t
*a
, /* I - First location */
2362 cupsd_location_t
*b
, /* I - Second location */
2363 void *data
) /* I - Callback data (unused) */
2367 return (strcmp(b
->location
, a
->location
));
2372 * 'compare_ogroups()' - Compare two OAuth groups.
2375 static int /* O - Result of comparison */
2376 compare_ogroups(cupsd_ogroup_t
*a
, /* I - First group */
2377 cupsd_ogroup_t
*b
, /* I - Second group */
2378 void *data
) /* I - Callback data (unused) */
2382 return (_cups_strcasecmp(a
->name
, b
->name
));
2387 * 'copy_authmask()' - Copy function for auth masks.
2390 static cupsd_authmask_t
* /* O - New auth mask */
2391 copy_authmask(cupsd_authmask_t
*mask
, /* I - Existing auth mask */
2392 void *data
) /* I - User data (unused) */
2394 cupsd_authmask_t
*temp
; /* New auth mask */
2399 if ((temp
= malloc(sizeof(cupsd_authmask_t
))) != NULL
)
2401 memcpy(temp
, mask
, sizeof(cupsd_authmask_t
));
2403 if (temp
->type
== CUPSD_AUTH_NAME
|| temp
->type
== CUPSD_AUTH_INTERFACE
)
2406 * Make a copy of the name...
2409 if ((temp
->mask
.name
.name
= _cupsStrAlloc(temp
->mask
.name
.name
)) == NULL
)
2412 * Failed to make copy...
2426 * 'free_authmask()' - Free function for auth masks.
2430 free_authmask(cupsd_authmask_t
*mask
, /* I - Auth mask to free */
2431 void *data
) /* I - Callback data (unused) */
2435 if (mask
->type
== CUPSD_AUTH_NAME
|| mask
->type
== CUPSD_AUTH_INTERFACE
)
2436 _cupsStrFree(mask
->mask
.name
.name
);
2443 * 'free_ogroup()' - Free an OAuth group.
2447 free_ogroup(cupsd_ogroup_t
*og
, /* I - OAuth group */
2448 void *data
) /* I - Callback data (unused) */
2454 cupsArrayDelete(og
->members
);
2460 * 'load_ogroup()' - Load an OAuth group file.
2463 static int /* O - 1 on success, 0 on failure */
2464 load_ogroup(cupsd_ogroup_t
*og
, /* I - OAuth group */
2465 struct stat
*fileinfo
) /* I - File information */
2467 cups_file_t
*fp
; /* File pointer */
2468 char line
[1024]; /* Line from file */
2472 * Make sure we have a fresh members array...
2475 cupsArrayDelete(og
->members
);
2476 if ((og
->members
= cupsArrayNewStrings(/*s*/NULL
, /*delim*/'\0')) == NULL
)
2478 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to allocate members array for OAuth group %s: %s", og
->name
, strerror(errno
));
2483 * Load the members file...
2486 if ((fp
= cupsFileOpen(og
->filename
, "r")) == NULL
)
2488 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open OAuth group %s filename \"%s\": %s", og
->name
, og
->filename
, strerror(errno
));
2492 while (cupsFileGets(fp
, line
, sizeof(line
)))
2493 cupsArrayAdd(og
->members
, line
);
2497 og
->fileinfo
= *fileinfo
;
2505 * 'pam_func()' - PAM conversation function.
2508 static int /* O - Success or failure */
2510 int num_msg
, /* I - Number of messages */
2511 const struct pam_message
**msg
, /* I - Messages */
2512 struct pam_response
**resp
, /* O - Responses */
2514 /* I - Pointer to connection */
2516 int i
; /* Looping var */
2517 struct pam_response
*replies
; /* Replies */
2518 cupsd_authdata_t
*data
; /* Pointer to auth data */
2522 * Allocate memory for the responses...
2525 if ((replies
= malloc(sizeof(struct pam_response
) * (size_t)num_msg
)) == NULL
)
2526 return (PAM_CONV_ERR
);
2529 * Answer all of the messages...
2532 data
= (cupsd_authdata_t
*)appdata_ptr
;
2534 for (i
= 0; i
< num_msg
; i
++)
2536 switch (msg
[i
]->msg_style
)
2538 case PAM_PROMPT_ECHO_ON
:
2539 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2540 replies
[i
].resp
= strdup(data
->username
);
2543 case PAM_PROMPT_ECHO_OFF
:
2544 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2545 replies
[i
].resp
= strdup(data
->password
);
2549 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2550 replies
[i
].resp
= NULL
;
2554 replies
[i
].resp_retcode
= PAM_SUCCESS
;
2555 replies
[i
].resp
= NULL
;
2560 return (PAM_CONV_ERR
);
2565 * Return the responses back to PAM...
2570 return (PAM_SUCCESS
);
2572 #endif /* HAVE_LIBPAM */