]> git.ipfire.org Git - thirdparty/cups.git/blame_incremental - scheduler/auth.c
Fix some issues with job-presets-supported and printer-strings-languages-supported.
[thirdparty/cups.git] / scheduler / auth.c
... / ...
CommitLineData
1/*
2 * Authorization routines for the CUPS scheduler.
3 *
4 * Copyright © 2020-2025 by OpenPrinting.
5 * Copyright © 2007-2019 by Apple Inc.
6 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7 *
8 * This file contains Kerberos support code, copyright 2006 by
9 * Jelmer Vernooij.
10 *
11 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * information.
13 */
14
15#include "cupsd.h"
16#include <grp.h>
17#if HAVE_LIBPAM
18# ifdef HAVE_PAM_PAM_APPL_H
19# include <pam/pam_appl.h>
20# else
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>
35typedef struct xucred cupsd_ucred_t;
36# define CUPSD_UCRED_UID(c) (c).cr_uid
37#else
38# ifndef __OpenBSD__
39typedef struct ucred cupsd_ucred_t;
40# else
41typedef struct sockpeercred cupsd_ucred_t;
42# endif
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
49# include <glib.h>
50# include <snapd-glib/snapd-glib.h>
51#endif /* HAVE_LIBSNAPDGLIB */
52
53
54/*
55 * Local functions...
56 */
57
58static int check_admin_access(cupsd_client_t *con);
59#ifdef HAVE_AUTHORIZATION_H
60static int check_authref(cupsd_client_t *con, const char *right);
61#endif /* HAVE_AUTHORIZATION_H */
62static int compare_locations(cupsd_location_t *a, cupsd_location_t *b, void *data);
63static int compare_ogroups(cupsd_ogroup_t *a, cupsd_ogroup_t *b, void *data);
64static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data);
65static void free_authmask(cupsd_authmask_t *am, void *data);
66static void free_ogroup(cupsd_ogroup_t *og, void *data);
67static int load_ogroup(cupsd_ogroup_t *og, struct stat *fileinfo);
68#if HAVE_LIBPAM
69static int pam_func(int, const struct pam_message **,
70 struct pam_response **, void *);
71#endif /* HAVE_LIBPAM */
72
73
74/*
75 * Local structures...
76 */
77
78#if HAVE_LIBPAM
79typedef struct cupsd_authdata_s /**** Authentication data ****/
80{
81 char username[HTTP_MAX_VALUE], /* Username string */
82 password[HTTP_MAX_VALUE]; /* Password string */
83} cupsd_authdata_t;
84#endif /* HAVE_LIBPAM */
85
86
87/*
88 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
89 */
90
91int /* O - 1 on success, 0 on failure */
92cupsdAddIPMask(
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 */
96{
97 cupsd_authmask_t temp; /* New host/domain mask */
98
99
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]);
101
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));
105
106 /*
107 * Create the masks array as needed and add...
108 */
109
110 if (!*masks)
111 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
112 (cups_acopy_func_t)copy_authmask,
113 (cups_afree_func_t)free_authmask);
114
115 return (cupsArrayAdd(*masks, &temp));
116}
117
118
119/*
120 * 'cupsdAddLocation()' - Add a location for authorization.
121 */
122
123void
124cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */
125{
126 /*
127 * Make sure the locations array is created...
128 */
129
130 if (!Locations)
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);
135
136 if (Locations)
137 {
138 cupsArrayAdd(Locations, loc);
139
140 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"", loc->location ? loc->location : "(null)");
141 }
142}
143
144
145/*
146 * 'cupsdAddName()' - Add a name to a location...
147 */
148
149void
150cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
151 char *name) /* I - Name to add */
152{
153 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", (void *)loc, name);
154
155 if (!loc->names)
156 loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
157 (cups_acopy_func_t)_cupsArrayStrdup,
158 (cups_afree_func_t)_cupsArrayFree);
159
160 if (!cupsArrayAdd(loc->names, name))
161 {
162 cupsdLogMessage(CUPSD_LOG_ERROR,
163 "Unable to duplicate name for location %s: %s",
164 loc->location ? loc->location : "nil", strerror(errno));
165 return;
166 }
167}
168
169
170/*
171 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
172 */
173
174int /* O - 1 on success, 0 on failure */
175cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
176 char *name) /* I - Host or interface name */
177{
178 cupsd_authmask_t temp; /* New host/domain mask */
179 char ifname[32], /* Interface name */
180 *ifptr; /* Pointer to end of name */
181
182
183 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", (void *)masks, (void *)*masks, name);
184
185 if (!_cups_strcasecmp(name, "@LOCAL"))
186 {
187 /*
188 * Deny *interface*...
189 */
190
191 temp.type = CUPSD_AUTH_INTERFACE;
192 temp.mask.name.name = (char *)"*";
193 }
194 else if (!_cups_strncasecmp(name, "@IF(", 4))
195 {
196 /*
197 * Deny *interface*...
198 */
199
200 cupsCopyString(ifname, name + 4, sizeof(ifname));
201
202 ifptr = ifname + strlen(ifname) - 1;
203
204 if (ifptr >= ifname && *ifptr == ')')
205 {
206 *ifptr = '\0';
207 }
208
209 temp.type = CUPSD_AUTH_INTERFACE;
210 temp.mask.name.name = ifname;
211 }
212 else
213 {
214 /*
215 * Deny name...
216 */
217
218 if (*name == '*')
219 name ++;
220
221 temp.type = CUPSD_AUTH_NAME;
222 temp.mask.name.name = (char *)name;
223 }
224
225 /*
226 * Set the name length...
227 */
228
229 temp.mask.name.length = strlen(temp.mask.name.name);
230
231 /*
232 * Create the masks array as needed and add...
233 */
234
235 if (!*masks)
236 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
237 (cups_acopy_func_t)copy_authmask,
238 (cups_afree_func_t)free_authmask);
239
240 return (cupsArrayAdd(*masks, &temp));
241}
242
243
244/*
245 * 'cupsdAddOAuthGroup()' - Add an OAuth group file.
246 */
247
248int /* O - 1 on success, 0 on error */
249cupsdAddOAuthGroup(const char *name, /* I - Group name */
250 const char *filename)/* I - Group filename */
251{
252 cupsd_ogroup_t *og; /* Group */
253 struct stat fileinfo; /* File information */
254
255
256 /*
257 * Check OAuth group file...
258 */
259
260 if (stat(filename, &fileinfo))
261 {
262 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to access OAuthGroup %s file \"%s\": %s", name, filename, strerror(errno));
263 return (0);
264 }
265
266 /*
267 * Create the new group...
268 */
269
270 if (!OAuthGroups)
271 {
272 /*
273 * Create groups array...
274 */
275
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)
277 {
278 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for OAuthGroup array: %s", strerror(errno));
279 return (0);
280 }
281 }
282
283 if ((og = (cupsd_ogroup_t *)calloc(1, sizeof(cupsd_ogroup_t))) == NULL)
284 {
285 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for OAuthGroup %s: %s", name, strerror(errno));
286 return (0);
287 }
288
289 if ((og->name = strdup(name)) == NULL || (og->filename = strdup(filename)) == NULL)
290 {
291 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for OAuthGroup %s: %s", name, strerror(errno));
292 free_ogroup(og, NULL);
293 return (0);
294 }
295
296 /*
297 * Add the group to the array...
298 */
299
300 cupsArrayAdd(OAuthGroups, og);
301
302 /*
303 * Load the group and return...
304 */
305
306 return (load_ogroup(og, &fileinfo));
307}
308
309
310/*
311 * 'cupsdAuthorize()' - Validate any authorization credentials.
312 */
313
314void
315cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
316{
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 */
326
327
328 /*
329 * Locate the best matching location so we know what kind of
330 * authentication to expect...
331 */
332
333 con->best = cupsdFindBest(con->uri, httpGetState(con->http));
334 con->type = CUPSD_AUTH_NONE;
335
336 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, (void *)con->best, con->best ? con->best->location : "");
337
338 if (con->best && con->best->type != CUPSD_AUTH_NONE)
339 {
340 if (con->best->type == CUPSD_AUTH_DEFAULT)
341 type = cupsdDefaultAuthType();
342 else
343 type = con->best->type;
344 }
345 else
346 type = cupsdDefaultAuthType();
347
348 /*
349 * Decode the Authorization string...
350 */
351
352 authorization = httpGetField(con->http, HTTP_FIELD_AUTHORIZATION);
353
354 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cookie=\"%s\"", httpGetCookie(con->http));
355
356 if (!*authorization && httpGetCookieValue(con->http, "CUPS_BEARER", bearer, sizeof(bearer)) && bearer[0])
357 authorization = "Bearer COOKIE";
358
359 username[0] = '\0';
360 password[0] = '\0';
361
362#ifdef HAVE_GSSAPI
363 con->gss_uid = 0;
364#endif /* HAVE_GSSAPI */
365
366#ifdef HAVE_AUTHORIZATION_H
367 if (con->authref)
368 {
369 AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
370 con->authref = NULL;
371 }
372#endif /* HAVE_AUTHORIZATION_H */
373
374 if (!*authorization)
375 {
376 /*
377 * No authorization data provided, return early...
378 */
379
380 cupsdLogClient(con, CUPSD_LOG_DEBUG, "No authentication data provided.");
381 return;
382 }
383#ifdef HAVE_AUTHORIZATION_H
384 else if (!strncmp(authorization, "AuthRef ", 8) &&
385 httpAddrLocalhost(httpGetAddress(con->http)))
386 {
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 */
392
393 /*
394 * Get the Authorization Services data...
395 */
396
397 authorization += 8;
398 while (isspace(*authorization & 255))
399 authorization ++;
400
401 authlen = sizeof(authdata);
402 httpDecode64_2(authdata, &authlen, authorization);
403
404 if (authlen != kAuthorizationExternalFormLength)
405 {
406 cupsdLogClient(con, CUPSD_LOG_ERROR, "External Authorization reference size is incorrect.");
407 return;
408 }
409
410 if ((status = AuthorizationCreateFromExternalForm((AuthorizationExternalForm *)authdata, &con->authref)) != 0)
411 {
412 cupsdLogClient(con, CUPSD_LOG_ERROR, "AuthorizationCreateFromExternalForm returned %d", (int)status);
413 return;
414 }
415
416 username[0] = '\0';
417
418 if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
419 &authinfo))
420 {
421 if (authinfo->count == 1 && authinfo->items[0].value &&
422 authinfo->items[0].valueLength >= 2)
423 {
424 cupsCopyString(username, authinfo->items[0].value, sizeof(username));
425
426 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef.", username);
427 }
428
429 AuthorizationFreeItemSet(authinfo);
430 }
431
432 if (!username[0])
433 {
434 /*
435 * No username in AuthRef, grab username using peer credentials...
436 */
437
438 struct passwd *pwd; /* Password entry for this user */
439 cupsd_ucred_t peercred; /* Peer credentials */
440 socklen_t peersize; /* Size of peer credentials */
441
442 peersize = sizeof(peercred);
443
444 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
445 {
446 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
447 return;
448 }
449
450 if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
451 {
452 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred));
453 return;
454 }
455
456 cupsCopyString(username, pwd->pw_name, sizeof(username));
457
458 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef + PeerCred.", username);
459 }
460
461 con->type = CUPSD_AUTH_BASIC;
462 }
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)
467 {
468 /*
469 * Use peer credentials from domain socket connection...
470 */
471
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? */
478
479 /*
480 * See if we should allow peer credentials...
481 */
482
483 for (name = (char *)cupsArrayFirst(con->best->names);
484 name;
485 name = (char *)cupsArrayNext(con->best->names))
486 {
487 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) ||
488 !_cups_strcasecmp(name, "@SYSTEM"))
489 {
490 /* Normally don't want peer credentials if we need an auth key... */
491 no_peer = 1;
492 }
493 else if (!_cups_strcasecmp(name, "@OWNER"))
494 {
495 /* but if @OWNER is present then we allow it... */
496 no_peer = 0;
497 break;
498 }
499 }
500
501 if (no_peer)
502 {
503 cupsdLogClient(con, CUPSD_LOG_ERROR, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
504 return;
505 }
506#endif /* HAVE_AUTHORIZATION_H */
507
508 if ((pwd = getpwnam(authorization + 9)) == NULL)
509 {
510 cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9);
511 return;
512 }
513
514 peersize = sizeof(peercred);
515
516# ifdef __APPLE__
517 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
518# else
519 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
520# endif /* __APPLE__ */
521 {
522 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
523 return;
524 }
525
526 if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
527 {
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 */
535 return;
536 }
537
538 cupsCopyString(username, authorization + 9, sizeof(username));
539
540# ifdef HAVE_GSSAPI
541 con->gss_uid = CUPSD_UCRED_UID(peercred);
542# endif /* HAVE_GSSAPI */
543
544 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using PeerCred.", username);
545
546 con->type = CUPSD_AUTH_BASIC;
547 }
548#endif /* SO_PEERCRED && AF_LOCAL */
549 else if (!strncmp(authorization, "Local", 5) &&
550 httpAddrLocalhost(httpGetAddress(con->http)))
551 {
552 /*
553 * Get Local certificate authentication data...
554 */
555
556 authorization += 5;
557 while (isspace(*authorization & 255))
558 authorization ++;
559
560 if ((localuser = cupsdFindCert(authorization)) == NULL)
561 {
562 cupsdLogClient(con, CUPSD_LOG_ERROR, "Local authentication certificate not found.");
563 return;
564 }
565
566 cupsCopyString(username, localuser->username, sizeof(username));
567 con->type = localuser->type;
568
569 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using Local.", username);
570 }
571 else if (!strncmp(authorization, "Basic ", 6))
572 {
573 /*
574 * Get the Basic authentication data...
575 */
576
577 int userlen; /* Username:password length */
578
579 /*
580 * Only allow Basic if enabled...
581 */
582
583 if (type != CUPSD_AUTH_BASIC)
584 {
585 cupsdLogClient(con, CUPSD_LOG_ERROR, "Basic authentication is not enabled.");
586 return;
587 }
588
589 authorization += 5;
590 while (isspace(*authorization & 255))
591 authorization ++;
592
593 userlen = sizeof(username);
594 httpDecode64_2(username, &userlen, authorization);
595
596 /*
597 * Pull the username and password out...
598 */
599
600 if ((ptr = strchr(username, ':')) == NULL)
601 {
602 cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Basic password.");
603 return;
604 }
605
606 *ptr++ = '\0';
607
608 if (!username[0])
609 {
610 /*
611 * Username must not be empty...
612 */
613
614 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic username.");
615 return;
616 }
617
618 if (!*ptr)
619 {
620 /*
621 * Password must not be empty...
622 */
623
624 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic password.");
625 return;
626 }
627
628 cupsCopyString(password, ptr, sizeof(password));
629
630 /*
631 * Validate the username and password...
632 */
633
634 {
635#if HAVE_LIBPAM
636 /*
637 * Only use PAM to do authentication. This supports MD5
638 * passwords, among other things...
639 */
640
641 pam_handle_t *pamh; /* PAM authentication handle */
642 int pamerr; /* PAM error code */
643 struct pam_conv pamdata; /* PAM conversation data */
644 cupsd_authdata_t data; /* Authentication data */
645 struct passwd *userinfo; /* User information */
646
647 cupsCopyString(data.username, username, sizeof(data.username));
648 cupsCopyString(data.password, password, sizeof(data.password));
649
650# ifdef __sun
651 pamdata.conv = (int (*)(int, struct pam_message **,
652 struct pam_response **,
653 void *))pam_func;
654# else
655 pamdata.conv = pam_func;
656# endif /* __sun */
657 pamdata.appdata_ptr = &data;
658
659 pamerr = pam_start("cups", username, &pamdata, &pamh);
660 if (pamerr != PAM_SUCCESS)
661 {
662 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_start() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
663 return;
664 }
665
666# ifdef HAVE_PAM_SET_ITEM
667# ifdef PAM_RHOST
668 pamerr = pam_set_item(pamh, PAM_RHOST, con->http->hostname);
669 if (pamerr != PAM_SUCCESS)
670 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
671# endif /* PAM_RHOST */
672
673# ifdef PAM_TTY
674 pamerr = pam_set_item(pamh, PAM_TTY, "cups");
675 if (pamerr != PAM_SUCCESS)
676 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
677# endif /* PAM_TTY */
678# endif /* HAVE_PAM_SET_ITEM */
679
680 pamerr = pam_authenticate(pamh, PAM_SILENT);
681 if (pamerr != PAM_SUCCESS)
682 {
683 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_authenticate() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
684 pam_end(pamh, 0);
685 return;
686 }
687
688# ifdef HAVE_PAM_SETCRED
689 pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
690 if (pamerr != PAM_SUCCESS)
691 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_setcred() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
692# endif /* HAVE_PAM_SETCRED */
693
694 pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
695 if (pamerr != PAM_SUCCESS)
696 {
697 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_acct_mgmt() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
698 pam_end(pamh, 0);
699 return;
700 }
701
702 pam_end(pamh, PAM_SUCCESS);
703
704 /*
705 * Copy GECOS information, if available, to get the user's real name...
706 */
707
708 if ((userinfo = getpwnam(username)) != NULL && userinfo->pw_gecos)
709 cupsCopyString(con->realname, userinfo->pw_gecos, sizeof(con->realname));
710#else
711 cupsdLogClient(con, CUPSD_LOG_ERROR, "No authentication support is available.");
712 return;
713#endif /* HAVE_LIBPAM */
714 }
715
716 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Basic.", username);
717 con->type = type;
718 }
719 else if (!strncmp(authorization, "Bearer ", 7))
720 {
721 // OAuth/OpenID authorization using JWT bearer tokens...
722 cups_jwt_t *jwt; // JWT user information
723 const char *sub, // Subject/user ID
724 *name, // Real name
725 *email; // Email address
726
727 /*
728 * Only allow OAuth if enabled...
729 */
730
731 if (type != CUPSD_AUTH_BEARER)
732 {
733 cupsdLogClient(con, CUPSD_LOG_ERROR, "OAuth authentication is not enabled.");
734 return;
735 }
736
737 // Skip whitespace after "Bearer"...
738 authorization += 7;
739 while (isspace(*authorization & 255))
740 authorization ++;
741
742 if (!strcmp(authorization, "COOKIE"))
743 authorization = bearer; // Use the cookie value for authorization
744
745 // Decode and validate the JWT...
746 if ((jwt = cupsOAuthGetUserId(OAuthServer, OAuthMetadata, authorization)) == NULL)
747 {
748 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get user information from bearer token: %s", cupsGetErrorString());
749 cupsCopyString(con->autherror, cupsGetErrorString(), sizeof(con->autherror));
750 return;
751 }
752 else if ((sub = cupsJWTGetClaimString(jwt, CUPS_JWT_SUB)) == NULL)
753 {
754 cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing subject name in user information.");
755 cupsCopyString(con->autherror, "Missing subject name.", sizeof(con->autherror));
756 cupsJWTDelete(jwt);
757 return;
758 }
759
760 // Good JWT, grab information from it and return...
761 con->type = CUPSD_AUTH_BEARER;
762 con->autherror[0] = '\0';
763 con->password[0] = '\0';
764
765 httpSetAuthString(con->http, "Bearer", authorization);
766 cupsCopyString(con->username, sub, sizeof(con->username));
767 if ((name = cupsJWTGetClaimString(jwt, CUPS_JWT_NAME)) != NULL)
768 cupsCopyString(con->realname, name, sizeof(con->realname));
769 if ((email = cupsJWTGetClaimString(jwt, "email")) != NULL)
770 cupsCopyString(con->email, email, sizeof(con->email));
771
772 cupsJWTDelete(jwt);
773
774 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" (%s <%s>) using OAuth/OpenID.", con->username, con->realname, con->email);
775 return;
776 }
777#ifdef HAVE_GSSAPI
778 else if (!strncmp(authorization, "Negotiate ", 10))
779 {
780 int len; /* Length of authorization string */
781 gss_ctx_id_t context; /* Authorization context */
782 OM_uint32 major_status, /* Major status code */
783 minor_status; /* Minor status code */
784 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER,
785 /* Input token from string */
786 output_token = GSS_C_EMPTY_BUFFER;
787 /* Output token for username */
788 gss_name_t client_name; /* Client name */
789
790 /*
791 * Only allow Kerberos if enabled...
792 */
793
794 if (type != CUPSD_AUTH_NEGOTIATE)
795 {
796 cupsdLogClient(con, CUPSD_LOG_ERROR, "Kerberos authentication is not enabled.");
797 return;
798 }
799
800# ifdef __APPLE__DISABLED // Remove DISABLED if ever this code is used for macOS installer
801 /*
802 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
803 * to use it...
804 */
805
806 if (&gss_init_sec_context == NULL)
807 {
808 cupsdLogClient(con, CUPSD_LOG_WARN, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
809 return;
810 }
811# endif /* __APPLE__DISABLED */
812
813 /*
814 * Find the start of the Kerberos input token...
815 */
816
817 authorization += 9;
818 while (isspace(*authorization & 255))
819 authorization ++;
820
821 if (!*authorization)
822 {
823 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "No authentication data specified.");
824 return;
825 }
826
827 /*
828 * Decode the authorization string to get the input token...
829 */
830
831 len = (int)strlen(authorization) + 0;
832 input_token.value = malloc((size_t)len);
833 input_token.value = httpDecode64_2(input_token.value, &len,
834 authorization);
835 input_token.length = (size_t)len;
836
837 /*
838 * Accept the input token to get the authorization info...
839 */
840
841 context = GSS_C_NO_CONTEXT;
842 client_name = GSS_C_NO_NAME;
843 major_status = gss_accept_sec_context(&minor_status,
844 &context,
845 ServerCreds,
846 &input_token,
847 GSS_C_NO_CHANNEL_BINDINGS,
848 &client_name,
849 NULL,
850 &output_token,
851 NULL,
852 NULL,
853 NULL);
854
855 if (output_token.length > 0)
856 gss_release_buffer(&minor_status, &output_token);
857
858 if (GSS_ERROR(major_status))
859 {
860 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error accepting GSSAPI security context.", con->number);
861
862 if (context != GSS_C_NO_CONTEXT)
863 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
864 return;
865 }
866
867 con->have_gss = 1;
868
869 /*
870 * Get the username associated with the client's credentials...
871 */
872
873 if (major_status == GSS_S_CONTINUE_NEEDED)
874 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Credentials not complete.", con->number);
875 else if (major_status == GSS_S_COMPLETE)
876 {
877 major_status = gss_display_name(&minor_status, client_name,
878 &output_token, NULL);
879
880 if (GSS_ERROR(major_status))
881 {
882 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error getting username.", con->number);
883 gss_release_name(&minor_status, &client_name);
884 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
885 return;
886 }
887
888 cupsCopyString(username, output_token.value, sizeof(username));
889
890 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Negotiate.", username);
891
892 gss_release_name(&minor_status, &client_name);
893 gss_release_buffer(&minor_status, &output_token);
894
895 con->type = CUPSD_AUTH_NEGOTIATE;
896 }
897
898 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
899
900# if defined(SO_PEERCRED) && defined(AF_LOCAL)
901 /*
902 * Get the client's UID if we are printing locally - that allows a backend
903 * to run as the correct user to get Kerberos credentials of its own.
904 */
905
906 if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL)
907 {
908 cupsd_ucred_t peercred; /* Peer credentials */
909 socklen_t peersize; /* Size of peer credentials */
910
911 peersize = sizeof(peercred);
912
913# ifdef __APPLE__
914 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
915# else
916 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred,
917 &peersize))
918# endif /* __APPLE__ */
919 {
920 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
921 }
922 else
923 {
924 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred));
925 con->gss_uid = CUPSD_UCRED_UID(peercred);
926 }
927 }
928# endif /* SO_PEERCRED && AF_LOCAL */
929 }
930#endif /* HAVE_GSSAPI */
931 else
932 {
933 char scheme[256]; /* Auth scheme... */
934
935
936 if (sscanf(authorization, "%255s", scheme) != 1)
937 cupsCopyString(scheme, "UNKNOWN", sizeof(scheme));
938
939 cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\".", scheme);
940 return;
941 }
942
943 /*
944 * If we get here, then we were able to validate the username and
945 * password - copy the validated username and password to the client
946 * data and return...
947 */
948
949 cupsCopyString(con->username, username, sizeof(con->username));
950
951 if (!con->realname[0])
952 cupsCopyString(con->realname, username, sizeof(con->realname));
953
954 cupsCopyString(con->password, password, sizeof(con->password));
955}
956
957
958/*
959 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
960 * access a location.
961 */
962
963int /* O - 1 if allowed, 0 otherwise */
964cupsdCheckAccess(
965 unsigned ip[4], /* I - Client address */
966 const char *name, /* I - Client hostname */
967 size_t namelen, /* I - Length of hostname */
968 cupsd_location_t *loc) /* I - Location to check */
969{
970 int allow; /* 1 if allowed, 0 otherwise */
971
972
973 if (!_cups_strcasecmp(name, "localhost"))
974 {
975 /*
976 * Access from localhost (127.0.0.1 or ::1) is always allowed...
977 */
978
979 return (1);
980 }
981 else
982 {
983 /*
984 * Do authorization checks on the domain/address...
985 */
986
987 switch (loc->order_type)
988 {
989 default :
990 allow = 0; /* anti-compiler-warning-code */
991 break;
992
993 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
994 allow = 1;
995
996 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
997 allow = 0;
998
999 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
1000 allow = 1;
1001 break;
1002
1003 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
1004 allow = 0;
1005
1006 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
1007 allow = 1;
1008
1009 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
1010 allow = 0;
1011 break;
1012 }
1013 }
1014
1015 return (allow);
1016}
1017
1018
1019/*
1020 * 'cupsdCheckAuth()' - Check authorization masks.
1021 */
1022
1023int /* O - 1 if mask matches, 0 otherwise */
1024cupsdCheckAuth(unsigned ip[4], /* I - Client address */
1025 const char *name, /* I - Client hostname */
1026 size_t name_len, /* I - Length of hostname */
1027 cups_array_t *masks) /* I - Masks */
1028{
1029 int i; /* Looping var */
1030 cupsd_authmask_t *mask; /* Current mask */
1031 cupsd_netif_t *iface; /* Network interface */
1032 unsigned netip4; /* IPv4 network address */
1033#ifdef AF_INET6
1034 unsigned netip6[4]; /* IPv6 network address */
1035#endif /* AF_INET6 */
1036
1037
1038 for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
1039 mask;
1040 mask = (cupsd_authmask_t *)cupsArrayNext(masks))
1041 {
1042 switch (mask->type)
1043 {
1044 case CUPSD_AUTH_INTERFACE :
1045 /*
1046 * Check for a match with a network interface...
1047 */
1048
1049 netip4 = htonl(ip[3]);
1050
1051#ifdef AF_INET6
1052 netip6[0] = htonl(ip[0]);
1053 netip6[1] = htonl(ip[1]);
1054 netip6[2] = htonl(ip[2]);
1055 netip6[3] = htonl(ip[3]);
1056#endif /* AF_INET6 */
1057
1058 cupsdNetIFUpdate();
1059
1060 if (!strcmp(mask->mask.name.name, "*"))
1061 {
1062#ifdef __APPLE__
1063 /*
1064 * Allow Back-to-My-Mac addresses...
1065 */
1066
1067 if ((ip[0] & 0xff000000) == 0xfd000000)
1068 return (1);
1069#endif /* __APPLE__ */
1070
1071 /*
1072 * Check against all local interfaces...
1073 */
1074
1075 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1076 iface;
1077 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1078 {
1079 /*
1080 * Only check local interfaces...
1081 */
1082
1083 if (!iface->is_local)
1084 continue;
1085
1086 if (iface->address.addr.sa_family == AF_INET)
1087 {
1088 /*
1089 * Check IPv4 address...
1090 */
1091
1092 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1093 (iface->address.ipv4.sin_addr.s_addr &
1094 iface->mask.ipv4.sin_addr.s_addr))
1095 return (1);
1096 }
1097#ifdef AF_INET6
1098 else
1099 {
1100 /*
1101 * Check IPv6 address...
1102 */
1103
1104 for (i = 0; i < 4; i ++)
1105 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1106 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1107 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1108 break;
1109
1110 if (i == 4)
1111 return (1);
1112 }
1113#endif /* AF_INET6 */
1114 }
1115 }
1116 else
1117 {
1118 /*
1119 * Check the named interface...
1120 */
1121
1122 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1123 iface;
1124 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1125 {
1126 if (strcmp(mask->mask.name.name, iface->name))
1127 continue;
1128
1129 if (iface->address.addr.sa_family == AF_INET)
1130 {
1131 /*
1132 * Check IPv4 address...
1133 */
1134
1135 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1136 (iface->address.ipv4.sin_addr.s_addr &
1137 iface->mask.ipv4.sin_addr.s_addr))
1138 return (1);
1139 }
1140#ifdef AF_INET6
1141 else
1142 {
1143 /*
1144 * Check IPv6 address...
1145 */
1146
1147 for (i = 0; i < 4; i ++)
1148 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1149 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1150 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1151 break;
1152
1153 if (i == 4)
1154 return (1);
1155 }
1156#endif /* AF_INET6 */
1157 }
1158 }
1159 break;
1160
1161 case CUPSD_AUTH_NAME :
1162 /*
1163 * Check for exact name match...
1164 */
1165
1166 if (!_cups_strcasecmp(name, mask->mask.name.name))
1167 return (1);
1168
1169 /*
1170 * Check for domain match...
1171 */
1172
1173 if (name_len >= mask->mask.name.length &&
1174 mask->mask.name.name[0] == '.' &&
1175 !_cups_strcasecmp(name + name_len - mask->mask.name.length,
1176 mask->mask.name.name))
1177 return (1);
1178 break;
1179
1180 case CUPSD_AUTH_IP :
1181 /*
1182 * Check for IP/network address match...
1183 */
1184
1185 for (i = 0; i < 4; i ++)
1186 if ((ip[i] & mask->mask.ip.netmask[i]) !=
1187 mask->mask.ip.address[i])
1188 break;
1189
1190 if (i == 4)
1191 return (1);
1192 break;
1193 }
1194 }
1195
1196 return (0);
1197}
1198
1199
1200/*
1201 * 'cupsdCheckGroup()' - Check for a user's group membership.
1202 */
1203
1204int /* O - 1 if user is a member, 0 otherwise */
1205cupsdCheckGroup(
1206 const char *username, /* I - User name */
1207 struct passwd *user, /* I - System user info */
1208 const char *groupname) /* I - Group name */
1209{
1210 int i; /* Looping var */
1211 struct group *group; /* Group info */
1212 gid_t groupid; /* ID of named group */
1213#ifdef HAVE_MBR_UID_TO_UUID
1214 uuid_t useruuid, /* UUID for username */
1215 groupuuid; /* UUID for groupname */
1216 int is_member; /* True if user is a member of group */
1217#endif /* HAVE_MBR_UID_TO_UUID */
1218
1219
1220 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, (void *)user, groupname);
1221
1222 /*
1223 * Validate input...
1224 */
1225
1226 if (!username || !groupname)
1227 return (0);
1228
1229 /*
1230 * Check to see if the user is a member of the named group...
1231 */
1232
1233 group = getgrnam(groupname);
1234 endgrent();
1235
1236 if (group != NULL)
1237 {
1238 /*
1239 * Group exists, check it...
1240 */
1241
1242 groupid = group->gr_gid;
1243
1244 for (i = 0; group->gr_mem[i]; i ++)
1245 {
1246 /*
1247 * User appears in the group membership...
1248 */
1249
1250 if (!_cups_strcasecmp(username, group->gr_mem[i]))
1251 return (1);
1252 }
1253
1254#ifdef HAVE_GETGROUPLIST
1255 /*
1256 * If the user isn't in the group membership list, try the results from
1257 * getgrouplist() which is supposed to return the full list of groups a user
1258 * belongs to...
1259 */
1260
1261 if (user)
1262 {
1263 int ngroups; /* Number of groups */
1264# ifdef __APPLE__
1265 int groups[2048]; /* Groups that user belongs to */
1266# else
1267 gid_t groups[2048]; /* Groups that user belongs to */
1268# endif /* __APPLE__ */
1269
1270 ngroups = (int)(sizeof(groups) / sizeof(groups[0]));
1271# ifdef __APPLE__
1272 getgrouplist(username, (int)user->pw_gid, groups, &ngroups);
1273# else
1274 getgrouplist(username, user->pw_gid, groups, &ngroups);
1275#endif /* __APPLE__ */
1276
1277 for (i = 0; i < ngroups; i ++)
1278 if ((int)groupid == (int)groups[i])
1279 return (1);
1280 }
1281#endif /* HAVE_GETGROUPLIST */
1282 }
1283 else
1284 groupid = (gid_t)-1;
1285
1286 /*
1287 * Group doesn't exist or user not in group list, check the group ID
1288 * against the user's group ID...
1289 */
1290
1291 if (user && groupid == user->pw_gid)
1292 return (1);
1293
1294#ifdef HAVE_MBR_UID_TO_UUID
1295 /*
1296 * Check group membership through macOS membership API...
1297 */
1298
1299 if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
1300 {
1301 if (groupid != (gid_t)-1)
1302 {
1303 /*
1304 * Map group name to UUID and check membership...
1305 */
1306
1307 if (!mbr_gid_to_uuid(groupid, groupuuid))
1308 if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1309 if (is_member)
1310 return (1);
1311 }
1312 else if (groupname[0] == '#')
1313 {
1314 /*
1315 * Use UUID directly and check for equality (user UUID) and
1316 * membership (group UUID)...
1317 */
1318
1319 if (!uuid_parse((char *)groupname + 1, groupuuid))
1320 {
1321 if (!uuid_compare(useruuid, groupuuid))
1322 return (1);
1323 else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1324 if (is_member)
1325 return (1);
1326 }
1327
1328 return (0);
1329 }
1330 }
1331 else if (groupname[0] == '#')
1332 return (0);
1333#endif /* HAVE_MBR_UID_TO_UUID */
1334
1335 /*
1336 * If we get this far, then the user isn't part of the named group...
1337 */
1338
1339 return (0);
1340}
1341
1342
1343/*
1344 * 'cupsdCopyLocation()' - Make a copy of a location...
1345 */
1346
1347cupsd_location_t * /* O - New location */
1348cupsdCopyLocation(
1349 cupsd_location_t *loc) /* I - Original location */
1350{
1351 cupsd_location_t *temp; /* New location */
1352
1353
1354 /*
1355 * Make a copy of the original location...
1356 */
1357
1358 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
1359 return (NULL);
1360
1361 /*
1362 * Copy the information from the original location to the new one.
1363 */
1364
1365 if (!loc)
1366 return (temp);
1367
1368 if (loc->location)
1369 temp->location = _cupsStrAlloc(loc->location);
1370
1371 temp->length = loc->length;
1372 temp->limit = loc->limit;
1373 temp->order_type = loc->order_type;
1374 temp->type = loc->type;
1375 temp->level = loc->level;
1376 temp->satisfy = loc->satisfy;
1377 temp->encryption = loc->encryption;
1378
1379 if (loc->names)
1380 {
1381 if ((temp->names = cupsArrayDup(loc->names)) == NULL)
1382 {
1383 cupsdLogMessage(CUPSD_LOG_ERROR,
1384 "Unable to allocate memory for %d names: %s",
1385 cupsArrayCount(loc->names), strerror(errno));
1386
1387 cupsdFreeLocation(temp, NULL);
1388 return (NULL);
1389 }
1390 }
1391
1392 if (loc->allow)
1393 {
1394 /*
1395 * Copy allow rules...
1396 */
1397
1398 if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
1399 {
1400 cupsdLogMessage(CUPSD_LOG_ERROR,
1401 "Unable to allocate memory for %d allow rules: %s",
1402 cupsArrayCount(loc->allow), strerror(errno));
1403 cupsdFreeLocation(temp, NULL);
1404 return (NULL);
1405 }
1406 }
1407
1408 if (loc->deny)
1409 {
1410 /*
1411 * Copy deny rules...
1412 */
1413
1414 if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
1415 {
1416 cupsdLogMessage(CUPSD_LOG_ERROR,
1417 "Unable to allocate memory for %d deny rules: %s",
1418 cupsArrayCount(loc->deny), strerror(errno));
1419 cupsdFreeLocation(temp, NULL);
1420 return (NULL);
1421 }
1422 }
1423
1424 return (temp);
1425}
1426
1427
1428/*
1429 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1430 */
1431
1432void
1433cupsdDeleteAllLocations(void)
1434{
1435 /*
1436 * Free the location array, which will free all of the locations...
1437 */
1438
1439 cupsArrayDelete(Locations);
1440 Locations = NULL;
1441}
1442
1443
1444/*
1445 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1446 */
1447
1448cupsd_location_t * /* O - Location that matches */
1449cupsdFindBest(const char *path, /* I - Resource path */
1450 http_state_t state) /* I - HTTP state/request */
1451{
1452 char uri[HTTP_MAX_URI],
1453 /* URI in request... */
1454 *uriptr; /* Pointer into URI */
1455 cupsd_location_t *loc, /* Current location */
1456 *best; /* Best match for location so far */
1457 size_t bestlen; /* Length of best match */
1458 int limit; /* Limit field */
1459 static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1460 {
1461 CUPSD_AUTH_LIMIT_ALL,
1462 CUPSD_AUTH_LIMIT_OPTIONS,
1463 CUPSD_AUTH_LIMIT_GET,
1464 CUPSD_AUTH_LIMIT_GET,
1465 CUPSD_AUTH_LIMIT_HEAD,
1466 CUPSD_AUTH_LIMIT_POST,
1467 CUPSD_AUTH_LIMIT_POST,
1468 CUPSD_AUTH_LIMIT_POST,
1469 CUPSD_AUTH_LIMIT_PUT,
1470 CUPSD_AUTH_LIMIT_PUT,
1471 CUPSD_AUTH_LIMIT_DELETE,
1472 CUPSD_AUTH_LIMIT_TRACE,
1473 CUPSD_AUTH_LIMIT_ALL,
1474 CUPSD_AUTH_LIMIT_ALL,
1475 CUPSD_AUTH_LIMIT_ALL,
1476 CUPSD_AUTH_LIMIT_ALL
1477 };
1478
1479
1480 /*
1481 * First copy the connection URI to a local string so we have drop
1482 * any .ppd extension from the pathname in /printers or /classes
1483 * URIs...
1484 */
1485
1486 cupsCopyString(uri, path, sizeof(uri));
1487
1488 if ((uriptr = strchr(uri, '?')) != NULL)
1489 *uriptr = '\0'; /* Drop trailing query string */
1490
1491 if ((uriptr = uri + strlen(uri) - 1) > uri && *uriptr == '/')
1492 *uriptr = '\0'; /* Remove trailing '/' */
1493
1494 if (!strncmp(uri, "/printers/", 10) ||
1495 !strncmp(uri, "/classes/", 9))
1496 {
1497 /*
1498 * Check if the URI has .ppd on the end...
1499 */
1500
1501 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
1502
1503 if (!strcmp(uriptr, ".ppd"))
1504 *uriptr = '\0';
1505 }
1506
1507 /*
1508 * Loop through the list of locations to find a match...
1509 */
1510
1511 limit = limits[state];
1512 best = NULL;
1513 bestlen = 0;
1514
1515 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri=\"%s\", limit=%x...", uri, limit);
1516
1517
1518 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1519 loc;
1520 loc = (cupsd_location_t *)cupsArrayNext(Locations))
1521 {
1522 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s(%d) Limit %x", loc->location ? loc->location : "(null)", (int)loc->length, loc->limit);
1523
1524 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
1525 {
1526 /*
1527 * Use case-insensitive comparison for queue names...
1528 */
1529
1530 if (loc->length > bestlen && loc->location &&
1531 !_cups_strncasecmp(uri, loc->location, loc->length) &&
1532 loc->location[0] == '/' &&
1533 (limit & loc->limit) != 0)
1534 {
1535 best = loc;
1536 bestlen = loc->length;
1537 }
1538 }
1539 else
1540 {
1541 /*
1542 * Use case-sensitive comparison for other URIs...
1543 */
1544
1545 if (loc->length > bestlen && loc->location &&
1546 !strncmp(uri, loc->location, loc->length) &&
1547 loc->location[0] == '/' &&
1548 (limit & loc->limit) != 0)
1549 {
1550 best = loc;
1551 bestlen = loc->length;
1552 }
1553 }
1554 }
1555
1556 /*
1557 * Return the match, if any...
1558 */
1559
1560 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best=%s", best ? best->location : "NONE");
1561
1562 return (best);
1563}
1564
1565
1566/*
1567 * 'cupsdFindLocation()' - Find the named location.
1568 */
1569
1570cupsd_location_t * /* O - Location that matches */
1571cupsdFindLocation(const char *location) /* I - Connection */
1572{
1573 cupsd_location_t key; /* Search key */
1574
1575
1576 key.location = (char *)location;
1577
1578 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
1579}
1580
1581
1582/*
1583 * 'cupsdFindOAuthGroup()' - Find an OAuth group.
1584 */
1585
1586cupsd_ogroup_t * /* O - Group or `NULL` */
1587cupsdFindOAuthGroup(const char *name) /* I - Group name */
1588{
1589 cupsd_ogroup_t key, /* Search key */
1590 *og; /* Matching group */
1591 struct stat fileinfo; /* Group file information */
1592
1593
1594 key.name = (char *)name;
1595 if ((og = (cupsd_ogroup_t *)cupsArrayFind(OAuthGroups, &key)) != NULL)
1596 {
1597 /*
1598 * See if we need to reload the group file...
1599 */
1600
1601 if (!stat(og->filename, &fileinfo) && (fileinfo.st_size != og->fileinfo.st_size || fileinfo.st_mtime > og->fileinfo.st_mtime))
1602 load_ogroup(og, &fileinfo);
1603 }
1604
1605 return (og);
1606}
1607
1608
1609/*
1610 * 'cupsdFreeLocation()' - Free all memory used by a location.
1611 */
1612
1613void cupsdFreeLocation(cupsd_location_t *loc, /* I - Location to free */
1614 void *data) /* Unused */
1615{
1616 (void)data;
1617 cupsArrayDelete(loc->names);
1618 cupsArrayDelete(loc->allow);
1619 cupsArrayDelete(loc->deny);
1620
1621 _cupsStrFree(loc->location);
1622 free(loc);
1623}
1624
1625
1626/*
1627 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1628 */
1629
1630http_status_t /* O - HTTP_OK if authorized or error code */
1631cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
1632 const char *owner)/* I - Owner of object */
1633{
1634 int i, /* Looping vars */
1635 auth, /* Authorization status */
1636 type; /* Type of authentication */
1637 http_addr_t *hostaddr = httpGetAddress(con->http);
1638 /* Client address */
1639 const char *hostname = httpGetHostname(con->http, NULL, 0);
1640 /* Client hostname */
1641 unsigned address[4]; /* Authorization address */
1642 cupsd_location_t *best; /* Best match for location so far */
1643 size_t hostlen; /* Length of hostname */
1644 char *name, /* Current username */
1645 username[256], /* Username to authorize */
1646 ownername[256], /* Owner name to authorize */
1647 *ptr; /* Pointer into username */
1648 struct passwd *pw; /* User password data */
1649 static const char * const levels[] = /* Auth levels */
1650 {
1651 "ANON",
1652 "USER",
1653 "GROUP"
1654 };
1655 static const char * const types[] = /* Auth types */
1656 {
1657 "None",
1658 "Basic",
1659 "Bearer",
1660 "Negotiate"
1661 };
1662
1663
1664 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)" : "");
1665 if (owner)
1666 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: owner=\"%s\"", owner);
1667
1668 /*
1669 * If there is no "best" authentication rule for this request, then
1670 * access is allowed from the local system and denied from other
1671 * addresses...
1672 */
1673
1674 if (!con->best)
1675 {
1676 if (httpAddrLocalhost(httpGetAddress(con->http)) ||
1677 !strcmp(hostname, ServerName) ||
1678 cupsArrayFind(ServerAlias, (void *)hostname))
1679 return (HTTP_STATUS_OK);
1680 else
1681 return (HTTP_STATUS_FORBIDDEN);
1682 }
1683
1684 best = con->best;
1685
1686 if ((type = best->type) == CUPSD_AUTH_DEFAULT)
1687 type = cupsdDefaultAuthType();
1688
1689 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));
1690
1691 if (best->limit == CUPSD_AUTH_LIMIT_IPP)
1692 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", best->op, ippOpString(best->op));
1693
1694 /*
1695 * Check host/ip-based accesses...
1696 */
1697
1698#ifdef AF_INET6
1699 if (httpAddrFamily(hostaddr) == AF_INET6)
1700 {
1701 /*
1702 * Copy IPv6 address...
1703 */
1704
1705 address[0] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[0]);
1706 address[1] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[1]);
1707 address[2] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[2]);
1708 address[3] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[3]);
1709 }
1710 else
1711#endif /* AF_INET6 */
1712 if (con->http->hostaddr->addr.sa_family == AF_INET)
1713 {
1714 /*
1715 * Copy IPv4 address...
1716 */
1717
1718 address[0] = 0;
1719 address[1] = 0;
1720 address[2] = 0;
1721 address[3] = ntohl(hostaddr->ipv4.sin_addr.s_addr);
1722 }
1723 else
1724 memset(address, 0, sizeof(address));
1725
1726 hostlen = strlen(hostname);
1727
1728 auth = cupsdCheckAccess(address, hostname, hostlen, best)
1729 ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
1730
1731 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth ? "DENY" : "ALLOW");
1732
1733 if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
1734 return (HTTP_STATUS_FORBIDDEN);
1735
1736 /*
1737 * See if encryption is required...
1738 */
1739
1740 if ((best->encryption >= HTTP_ENCRYPTION_REQUIRED && !con->http->tls &&
1741 _cups_strcasecmp(hostname, "localhost") &&
1742 !httpAddrLocalhost(hostaddr) &&
1743 best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
1744 !(type == CUPSD_AUTH_NEGOTIATE ||
1745 (type == CUPSD_AUTH_NONE &&
1746 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE)))
1747 {
1748 cupsdLogMessage(CUPSD_LOG_DEBUG,
1749 "cupsdIsAuthorized: Need upgrade to TLS...");
1750 return (HTTP_STATUS_UPGRADE_REQUIRED);
1751 }
1752
1753 /*
1754 * Now see what access level is required...
1755 */
1756
1757 if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
1758 (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
1759 return (HTTP_STATUS_OK);
1760
1761 if (!con->username[0] && type == CUPSD_AUTH_NONE &&
1762 best->limit == CUPSD_AUTH_LIMIT_IPP)
1763 {
1764 /*
1765 * Check for unauthenticated username...
1766 */
1767
1768 ipp_attribute_t *attr; /* requesting-user-name attribute */
1769
1770
1771 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1772 if (attr)
1773 {
1774 cupsdLogMessage(CUPSD_LOG_DEBUG,
1775 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1776 attr->values[0].string.text);
1777 cupsCopyString(username, attr->values[0].string.text, sizeof(username));
1778 }
1779 else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
1780 return (HTTP_STATUS_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1781 else
1782 return (HTTP_STATUS_OK); /* unless overridden with Satisfy */
1783 }
1784 else
1785 {
1786 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
1787 con->username);
1788
1789#ifdef HAVE_AUTHORIZATION_H
1790 if (!con->username[0] && !con->authref)
1791#else
1792 if (!con->username[0])
1793#endif /* HAVE_AUTHORIZATION_H */
1794 {
1795 if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
1796 return (HTTP_STATUS_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1797 else
1798 return (HTTP_STATUS_OK); /* unless overridden with Satisfy */
1799 }
1800
1801
1802 if (con->type != type && type != CUPSD_AUTH_NONE &&
1803#ifdef HAVE_GSSAPI
1804 (type != CUPSD_AUTH_NEGOTIATE || con->gss_uid <= 0) &&
1805#endif /* HAVE_GSSAPI */
1806 con->type != CUPSD_AUTH_BASIC)
1807 {
1808 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s.",
1809 types[con->type], types[type]);
1810
1811 return (HTTP_STATUS_UNAUTHORIZED);
1812 }
1813
1814 cupsCopyString(username, con->username, sizeof(username));
1815 }
1816
1817 /*
1818 * OK, got a username. See if we need normal user access, or group
1819 * access...
1820 */
1821
1822 /*
1823 * Strip any @domain or @KDC from the username and owner...
1824 */
1825
1826 if (type != CUPSD_AUTH_BEARER && StripUserDomain && (ptr = strchr(username, '@')) != NULL)
1827 *ptr = '\0';
1828
1829 if (owner)
1830 {
1831 cupsCopyString(ownername, owner, sizeof(ownername));
1832
1833 if (type != CUPSD_AUTH_BEARER && StripUserDomain && (ptr = strchr(ownername, '@')) != NULL)
1834 *ptr = '\0';
1835 }
1836 else
1837 ownername[0] = '\0';
1838
1839 if (type == CUPSD_AUTH_BEARER)
1840 {
1841 /*
1842 * Lookup access via OAuth groups...
1843 */
1844
1845 cupsd_ogroup_t *og; // Current OAuth group
1846
1847 if (best->level == CUPSD_AUTH_USER)
1848 {
1849 /*
1850 * If there are no names associated with this location, then any valid user
1851 * is OK...
1852 */
1853
1854 if (cupsArrayCount(best->names) == 0)
1855 return (HTTP_STATUS_OK);
1856
1857 /*
1858 * Otherwise check the user list and return OK if this user is allowed...
1859 */
1860
1861 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership...");
1862
1863 for (name = (char *)cupsArrayFirst(best->names); name; name = (char *)cupsArrayNext(best->names))
1864 {
1865 if (!_cups_strcasecmp(name, "@OWNER") && owner && !_cups_strcasecmp(username, ownername))
1866 {
1867 // User is owner...
1868 return (HTTP_STATUS_OK);
1869 }
1870 else if (name[0] == '@')
1871 {
1872 // Check OAuth group membership...
1873 if ((og = cupsdFindOAuthGroup(name + 1)) == NULL)
1874 {
1875 // Group not defined...
1876 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorization policy requires undefined OAuth group \"%s\", ignoring.", name + 1);
1877 }
1878 else if (cupsArrayFind(og->members, username) || (con->email[0] && cupsArrayFind(og->members, con->email)))
1879 {
1880 // User is in group...
1881 return (HTTP_STATUS_OK);
1882 }
1883 }
1884 else if (!_cups_strcasecmp(username, name) || (con->email[0] && !_cups_strcasecmp(con->email, name)))
1885 {
1886 return (HTTP_STATUS_OK);
1887 }
1888 }
1889 }
1890 else
1891 {
1892 /*
1893 * Check to see if this user is in any of the named groups...
1894 */
1895
1896 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group membership...");
1897
1898 /*
1899 * Check to see if this user is in any of the named groups...
1900 */
1901
1902 for (name = (char *)cupsArrayFirst(best->names); name; name = (char *)cupsArrayNext(best->names))
1903 {
1904 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership.", name);
1905
1906 if ((og = cupsdFindOAuthGroup(name)) == NULL)
1907 {
1908 // Group not defined...
1909 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorization policy requires undefined OAuth group \"%s\", ignoring.", name + 1);
1910 }
1911 else if (cupsArrayFind(og->members, username) || (con->email[0] && cupsArrayFind(og->members, con->email)))
1912 {
1913 // User is in group...
1914 return (HTTP_STATUS_OK);
1915 }
1916 }
1917 }
1918 }
1919 else
1920 {
1921 /*
1922 * Get the (local) user info...
1923 */
1924
1925 if (username[0])
1926 {
1927 pw = getpwnam(username);
1928 endpwent();
1929 }
1930 else
1931 pw = NULL;
1932
1933 /*
1934 * For matching user and group memberships below we will first go
1935 * through all names except @SYSTEM to authorize the task as
1936 * non-administrative, like printing or deleting one's own job, if this
1937 * fails we will check whether we can authorize via the special name
1938 * @SYSTEM, as an administrative task, like creating a print queue or
1939 * deleting someone else's job.
1940 *
1941 * Note that tasks are considered as administrative by the policies
1942 * in cupsd.conf, when they require the user or group @SYSTEM.
1943 * We do this separation because if the client is a Snap connecting via
1944 * domain socket, we need to additionally check whether it plugs to us
1945 * through the "cups-control" interface which allows administration and
1946 * not through the "cups" interface which allows only printing.
1947 */
1948
1949 if (best->level == CUPSD_AUTH_USER)
1950 {
1951 /*
1952 * If there are no names associated with this location, then
1953 * any valid user is OK...
1954 */
1955
1956 if (cupsArrayCount(best->names) == 0)
1957 return (HTTP_STATUS_OK);
1958
1959 /*
1960 * Otherwise check the user list and return OK if this user is
1961 * allowed...
1962 */
1963
1964 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership...");
1965
1966#ifdef HAVE_AUTHORIZATION_H
1967 /*
1968 * If an authorization reference was supplied it must match a right name...
1969 */
1970
1971 if (con->authref)
1972 {
1973 for (name = (char *)cupsArrayFirst(best->names);
1974 name;
1975 name = (char *)cupsArrayNext(best->names))
1976 {
1977 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
1978 return (HTTP_STATUS_OK);
1979 }
1980
1981 for (name = (char *)cupsArrayFirst(best->names);
1982 name;
1983 name = (char *)cupsArrayNext(best->names))
1984 {
1985 if (!_cups_strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
1986 check_authref(con, SystemGroupAuthKey))
1987 return (HTTP_STATUS_OK);
1988 }
1989
1990 return (HTTP_STATUS_FORBIDDEN);
1991 }
1992#endif /* HAVE_AUTHORIZATION_H */
1993
1994 for (name = (char *)cupsArrayFirst(best->names);
1995 name;
1996 name = (char *)cupsArrayNext(best->names))
1997 {
1998 if (!_cups_strcasecmp(name, "@OWNER") && owner &&
1999 !_cups_strcasecmp(username, ownername))
2000 return (HTTP_STATUS_OK);
2001 else if (!_cups_strcasecmp(name, "@SYSTEM"))
2002 {
2003 /* Do @SYSTEM later, when every other entry fails */
2004 continue;
2005 }
2006 else if (name[0] == '@')
2007 {
2008 if (cupsdCheckGroup(username, pw, name + 1))
2009 return (HTTP_STATUS_OK);
2010 }
2011 else if (!_cups_strcasecmp(username, name))
2012 return (HTTP_STATUS_OK);
2013 }
2014
2015 for (name = (char *)cupsArrayFirst(best->names);
2016 name;
2017 name = (char *)cupsArrayNext(best->names))
2018 {
2019 if (!_cups_strcasecmp(name, "@SYSTEM"))
2020 {
2021 for (i = 0; i < NumSystemGroups; i ++)
2022 if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_access(con))
2023 return (HTTP_STATUS_OK);
2024 }
2025 }
2026 }
2027 else
2028 {
2029 /*
2030 * Check to see if this user is in any of the named groups...
2031 */
2032
2033 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group membership...");
2034
2035 /*
2036 * Check to see if this user is in any of the named groups...
2037 */
2038
2039 for (name = (char *)cupsArrayFirst(best->names);
2040 name;
2041 name = (char *)cupsArrayNext(best->names))
2042 {
2043 if (!_cups_strcasecmp(name, "@SYSTEM"))
2044 {
2045 /* Do @SYSTEM later, when every other entry fails */
2046 continue;
2047 }
2048
2049 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name);
2050
2051 if (cupsdCheckGroup(username, pw, name))
2052 return (HTTP_STATUS_OK);
2053 }
2054
2055 for (name = (char *)cupsArrayFirst(best->names);
2056 name;
2057 name = (char *)cupsArrayNext(best->names))
2058 {
2059 if (!_cups_strcasecmp(name, "@SYSTEM"))
2060 {
2061 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name);
2062
2063 for (i = 0; i < NumSystemGroups; i ++)
2064 if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_access(con))
2065 return (HTTP_STATUS_OK);
2066 }
2067 }
2068 }
2069 }
2070
2071 /*
2072 * The user isn't part of the specified users or groups, so deny access...
2073 */
2074
2075 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: User not in group(s).");
2076
2077 return (con->username[0] ? HTTP_STATUS_FORBIDDEN : HTTP_STATUS_UNAUTHORIZED);
2078}
2079
2080
2081/*
2082 * 'cupsdNewLocation()' - Create a new location for authorization.
2083 *
2084 * Note: Still need to call cupsdAddLocation() to add it to the list of global
2085 * locations.
2086 */
2087
2088cupsd_location_t * /* O - Pointer to new location record */
2089cupsdNewLocation(const char *location) /* I - Location path */
2090{
2091 cupsd_location_t *temp; /* New location */
2092
2093
2094 /*
2095 * Try to allocate memory for the new location.
2096 */
2097
2098 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
2099 return (NULL);
2100
2101 /*
2102 * Initialize the record and copy the name over...
2103 */
2104
2105 if ((temp->location = _cupsStrAlloc(location)) == NULL)
2106 {
2107 free(temp);
2108 return (NULL);
2109 }
2110
2111 temp->length = strlen(temp->location);
2112
2113 /*
2114 * Return the new record...
2115 */
2116
2117 return (temp);
2118}
2119
2120
2121/*
2122 * 'check_admin_access()' - Verify that the client has administrative access.
2123 */
2124
2125static int // O - 1 if authorized, 0 otherwise
2126check_admin_access(cupsd_client_t *con) // I - Client connection
2127{
2128 (void)con;
2129
2130#if defined(HAVE_LIBAPPARMOR) && defined(HAVE_LIBSNAPDGLIB)
2131 /*
2132 * If the client accesses locally via domain socket, find out whether it
2133 * is a Snap. Grant access if it is not a Snap, if it is a classic Snap
2134 * or if it is a confined Snap which plugs "cups-control". Otherwise deny
2135 * access.
2136 */
2137
2138 int fd = httpGetFd(con->http);
2139 // Client socket file descriptor
2140 char *context = NULL; // AppArmor profile name of client
2141 SnapdClient *client = NULL; // Data structure of snapd access
2142 GError *error = NULL; // Glib error
2143 int ret = 1; // Return value
2144# if !CUPS_SNAP
2145 SnapdSnap *snap = NULL; // Data structure of client Snap
2146# endif // !CUPS_SNAP
2147
2148
2149# ifdef AF_LOCAL
2150 // Only check domain sockets...
2151 if (httpAddrFamily(con->http->hostaddr) != AF_LOCAL)
2152 return (1);
2153# endif // AF_LOCAL
2154
2155# if !CUPS_SNAP
2156 // If AppArmor is not enabled, then we can't identify the client...
2157 if (!aa_is_enabled())
2158 {
2159 cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor not in use.");
2160 return (1);
2161 }
2162# endif /* !CUPS_SNAP */
2163
2164 // Get the client's AppArmor context using the socket...
2165 if (aa_getpeercon(fd, &context, NULL) < 0)
2166 {
2167 cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor profile could not be retrieved: %s", strerror(errno));
2168 return (1);
2169 }
2170 else
2171 {
2172 cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor profile is '%s'.", context);
2173 }
2174
2175 // Allow access from "cups" snap...
2176 if (!strncmp(context, "snap.cups.", 10))
2177 {
2178 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Client from the CUPS Snap itself - allowed.");
2179 goto done;
2180 }
2181
2182# if CUPS_SNAP && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC)
2183 /*
2184 * CUPS is snapped, so check whether the client is also snapped. If so,
2185 * determine whether the client snap has a "cups-control" plug which allows
2186 * the application to perform CUPS administrative tasks.
2187 */
2188
2189 const char *cookie; // snapd access cookie
2190 int status = 65535; // Status of client Snap context check
2191 const char *args[] = // snapctl arguments
2192 {
2193 "is-connected",
2194 "--apparmor-label",
2195 NULL,
2196 "cups-control",
2197 NULL
2198 };
2199
2200 // Connect to snapd
2201 if ((client = snapd_client_new()) == NULL)
2202 {
2203 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to connect to snapd.");
2204 ret = 0;
2205 goto done;
2206 }
2207
2208 // snapctl commands are sent over a domain socket
2209 snapd_client_set_socket_path(client, "/run/snapd-snap.socket");
2210
2211 // Take cookie from the environment if available
2212 if ((cookie = g_getenv("SNAP_COOKIE")) == NULL)
2213 {
2214 cookie = "";
2215 cupsdLogClient(con, CUPSD_LOG_WARN, "No SNAP_COOKIE set in the Snap environment.");
2216 }
2217
2218 // Do the client Snap context check...
2219 args[2] = context;
2220
2221 if (!snapd_client_run_snapctl2_sync(client, cookie, (char **)args, NULL, NULL, &status, NULL, &error))
2222 {
2223 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to check snap context: %s", error->message);
2224 ret = 0;
2225 goto done;
2226 }
2227
2228 switch (status)
2229 {
2230 case 0 : // The client is a confined Snap and plugs cups-control
2231 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap with cups-control plug - allowed.");
2232 break;
2233 case 1 : // The client is a confined Snap and does not plug cups-control
2234 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap without cups-control plug - denied.");
2235 ret = 0;
2236 break;
2237 case 10 : // The client is a classic Snap
2238 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Classic snap - allowed.");
2239 break;
2240 case 11 : // The client is not a Snap
2241 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Not a snap - allowed.");
2242 break;
2243 default : // Unexpected status...
2244 cupsdLogClient(con, CUPSD_LOG_ERROR, "Snap check returned unexpected status %d - denied.", status);
2245 ret = 0;
2246 break;
2247 }
2248
2249# elif !CUPS_SNAP
2250 /*
2251 * If CUPS is not snapped, check whether the client is snapped and if it has
2252 * the "cups-control" plug.
2253 */
2254
2255 // Is the client a snapped application?
2256 if (strncmp(context, "snap.", 5))
2257 {
2258 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Not a snap - allowed.");
2259 goto done;
2260 }
2261
2262 // Extract the snap name from the context (snap.name.instance)
2263 char *snap_name = strdup(context + 5);// Snap name follows "snap."
2264 char *ptr = strchr(snap_name, '.'); // instance follows the name...
2265 if (!ptr)
2266 {
2267 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Malformed snapd AppArmor profile name '%s' - denied.", context);
2268 free(snap_name);
2269 ret = 0;
2270 goto done;
2271 }
2272
2273 *ptr = '\0';
2274 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Client snap is '%s'.", snap_name);
2275
2276 // Connect to snapd
2277 if ((client = snapd_client_new()) == NULL)
2278 {
2279 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to connect to snapd.");
2280 free(snap_name);
2281 ret = 0;
2282 goto done;
2283 }
2284
2285 // Check whether the client Snap is under classic confinement
2286 GPtrArray *plugs = NULL; // List of plugs for snap
2287
2288 if ((snap = snapd_client_get_snap_sync(client, snap_name, NULL, &error)) == NULL)
2289 {
2290 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Unable to get client Snap data: %s", error->message);
2291 ret = 0;
2292 }
2293 // Snaps using classic confinement are granted access
2294 else if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC)
2295 {
2296 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Classic snap - allowed.");
2297 }
2298 // Check whether the client Snap has the cups-control plug
2299 else if (!snapd_client_get_connections2_sync(client, SNAPD_GET_CONNECTIONS_FLAGS_NONE, snap_name, "cups-control", NULL, NULL, &plugs, NULL, NULL, &error))
2300 {
2301 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Unable to get client Snap plugs: %s", error->message);
2302 ret = 0;
2303 }
2304 else if (!plugs || plugs->len <= 0)
2305 {
2306 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap without cups-control plug - denied.");
2307 ret = 0;
2308 }
2309 else
2310 {
2311 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap with cups-control plug - allowed.");
2312 }
2313
2314 if (plugs)
2315 g_ptr_array_unref(plugs);
2316
2317 free(snap_name);
2318 g_clear_object(&snap);
2319
2320# endif // CUPS_SNAP
2321
2322 done:
2323
2324 free(context);
2325 g_clear_object(&client);
2326
2327 return (ret);
2328
2329#else
2330 // No AppArmor/snapd to deal with...
2331 return (1);
2332#endif // HAVE_LIBAPPARMOR && HAVE_LIBSNAPDGLIB
2333}
2334
2335
2336#ifdef HAVE_AUTHORIZATION_H
2337/*
2338 * 'check_authref()' - Check if an authorization services reference has the
2339 * supplied right.
2340 */
2341
2342static int /* O - 1 if right is valid, 0 otherwise */
2343check_authref(cupsd_client_t *con, /* I - Connection */
2344 const char *right) /* I - Right name */
2345{
2346 OSStatus status; /* OS Status */
2347 AuthorizationItem authright; /* Authorization right */
2348 AuthorizationRights authrights; /* Authorization rights */
2349 AuthorizationFlags authflags; /* Authorization flags */
2350
2351
2352 /*
2353 * Check to see if the user is allowed to perform the task...
2354 */
2355
2356 if (!con->authref)
2357 return (0);
2358
2359 authright.name = right;
2360 authright.valueLength = 0;
2361 authright.value = NULL;
2362 authright.flags = 0;
2363
2364 authrights.count = 1;
2365 authrights.items = &authright;
2366
2367 authflags = kAuthorizationFlagDefaults |
2368 kAuthorizationFlagExtendRights;
2369
2370 if ((status = AuthorizationCopyRights(con->authref, &authrights,
2371 kAuthorizationEmptyEnvironment,
2372 authflags, NULL)) != 0)
2373 {
2374 cupsdLogMessage(CUPSD_LOG_ERROR, "AuthorizationCopyRights(\"%s\") returned %d", authright.name, (int)status);
2375 return (0);
2376 }
2377
2378 cupsdLogMessage(CUPSD_LOG_DEBUG2, "AuthorizationCopyRights(\"%s\") succeeded.", authright.name);
2379
2380 return (1);
2381}
2382#endif /* HAVE_AUTHORIZATION_H */
2383
2384
2385/*
2386 * 'compare_locations()' - Compare two locations.
2387 */
2388
2389static int /* O - Result of comparison */
2390compare_locations(cupsd_location_t *a, /* I - First location */
2391 cupsd_location_t *b, /* I - Second location */
2392 void *data) /* I - Callback data (unused) */
2393{
2394 (void)data;
2395
2396 return (strcmp(b->location, a->location));
2397}
2398
2399
2400/*
2401 * 'compare_ogroups()' - Compare two OAuth groups.
2402 */
2403
2404static int /* O - Result of comparison */
2405compare_ogroups(cupsd_ogroup_t *a, /* I - First group */
2406 cupsd_ogroup_t *b, /* I - Second group */
2407 void *data) /* I - Callback data (unused) */
2408{
2409 (void)data;
2410
2411 return (_cups_strcasecmp(a->name, b->name));
2412}
2413
2414
2415/*
2416 * 'copy_authmask()' - Copy function for auth masks.
2417 */
2418
2419static cupsd_authmask_t * /* O - New auth mask */
2420copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */
2421 void *data) /* I - User data (unused) */
2422{
2423 cupsd_authmask_t *temp; /* New auth mask */
2424
2425
2426 (void)data;
2427
2428 if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
2429 {
2430 memcpy(temp, mask, sizeof(cupsd_authmask_t));
2431
2432 if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
2433 {
2434 /*
2435 * Make a copy of the name...
2436 */
2437
2438 if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
2439 {
2440 /*
2441 * Failed to make copy...
2442 */
2443
2444 free(temp);
2445 temp = NULL;
2446 }
2447 }
2448 }
2449
2450 return (temp);
2451}
2452
2453
2454/*
2455 * 'free_authmask()' - Free function for auth masks.
2456 */
2457
2458static void
2459free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */
2460 void *data) /* I - Callback data (unused) */
2461{
2462 (void)data;
2463
2464 if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
2465 _cupsStrFree(mask->mask.name.name);
2466
2467 free(mask);
2468}
2469
2470
2471/*
2472 * 'free_ogroup()' - Free an OAuth group.
2473 */
2474
2475static void
2476free_ogroup(cupsd_ogroup_t *og, /* I - OAuth group */
2477 void *data) /* I - Callback data (unused) */
2478{
2479 (void)data;
2480
2481 free(og->name);
2482 free(og->filename);
2483 cupsArrayDelete(og->members);
2484 free(og);
2485}
2486
2487
2488/*
2489 * 'load_ogroup()' - Load an OAuth group file.
2490 */
2491
2492static int /* O - 1 on success, 0 on failure */
2493load_ogroup(cupsd_ogroup_t *og, /* I - OAuth group */
2494 struct stat *fileinfo) /* I - File information */
2495{
2496 cups_file_t *fp; /* File pointer */
2497 char line[1024]; /* Line from file */
2498
2499
2500 /*
2501 * Make sure we have a fresh members array...
2502 */
2503
2504 cupsArrayDelete(og->members);
2505 if ((og->members = cupsArrayNewStrings(/*s*/NULL, /*delim*/'\0')) == NULL)
2506 {
2507 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate members array for OAuth group %s: %s", og->name, strerror(errno));
2508 return (0);
2509 }
2510
2511 /*
2512 * Load the members file...
2513 */
2514
2515 if ((fp = cupsFileOpen(og->filename, "r")) == NULL)
2516 {
2517 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open OAuth group %s filename \"%s\": %s", og->name, og->filename, strerror(errno));
2518 return (0);
2519 }
2520
2521 while (cupsFileGets(fp, line, sizeof(line)))
2522 cupsArrayAdd(og->members, line);
2523
2524 cupsFileClose(fp);
2525
2526 og->fileinfo = *fileinfo;
2527
2528 return (1);
2529}
2530
2531
2532#if HAVE_LIBPAM
2533/*
2534 * 'pam_func()' - PAM conversation function.
2535 */
2536
2537static int /* O - Success or failure */
2538pam_func(
2539 int num_msg, /* I - Number of messages */
2540 const struct pam_message **msg, /* I - Messages */
2541 struct pam_response **resp, /* O - Responses */
2542 void *appdata_ptr)
2543 /* I - Pointer to connection */
2544{
2545 int i; /* Looping var */
2546 struct pam_response *replies; /* Replies */
2547 cupsd_authdata_t *data; /* Pointer to auth data */
2548
2549
2550 /*
2551 * Allocate memory for the responses...
2552 */
2553
2554 if ((replies = malloc(sizeof(struct pam_response) * (size_t)num_msg)) == NULL)
2555 return (PAM_CONV_ERR);
2556
2557 /*
2558 * Answer all of the messages...
2559 */
2560
2561 data = (cupsd_authdata_t *)appdata_ptr;
2562
2563 for (i = 0; i < num_msg; i ++)
2564 {
2565 switch (msg[i]->msg_style)
2566 {
2567 case PAM_PROMPT_ECHO_ON:
2568 replies[i].resp_retcode = PAM_SUCCESS;
2569 replies[i].resp = strdup(data->username);
2570 break;
2571
2572 case PAM_PROMPT_ECHO_OFF:
2573 replies[i].resp_retcode = PAM_SUCCESS;
2574 replies[i].resp = strdup(data->password);
2575 break;
2576
2577 case PAM_TEXT_INFO:
2578 replies[i].resp_retcode = PAM_SUCCESS;
2579 replies[i].resp = NULL;
2580 break;
2581
2582 case PAM_ERROR_MSG:
2583 replies[i].resp_retcode = PAM_SUCCESS;
2584 replies[i].resp = NULL;
2585 break;
2586
2587 default:
2588 free(replies);
2589 return (PAM_CONV_ERR);
2590 }
2591 }
2592
2593 /*
2594 * Return the responses back to PAM...
2595 */
2596
2597 *resp = replies;
2598
2599 return (PAM_SUCCESS);
2600}
2601#endif /* HAVE_LIBPAM */