]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/auth.c
Fix some issues with job-presets-supported and printer-strings-languages-supported.
[thirdparty/cups.git] / scheduler / auth.c
CommitLineData
b423cd4c 1/*
5ec1fd3d 2 * Authorization routines for the CUPS scheduler.
ef416fc2 3 *
732dcc06 4 * Copyright © 2020-2025 by OpenPrinting.
fa26ab95 5 * Copyright © 2007-2019 by Apple Inc.
3cd7b5e0 6 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
f7deaa1a 7 *
5ec1fd3d
MS
8 * This file contains Kerberos support code, copyright 2006 by
9 * Jelmer Vernooij.
ef416fc2 10 *
3cd7b5e0
MS
11 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * information.
ef416fc2 13 */
14
ef416fc2 15#include "cupsd.h"
16#include <grp.h>
ef416fc2 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 */
bd7854cb 24#ifdef HAVE_MEMBERSHIP_H
25# include <membership.h>
26#endif /* HAVE_MEMBERSHIP_H */
f7deaa1a 27#ifdef HAVE_AUTHORIZATION_H
28# include <Security/AuthorizationTags.h>
f7deaa1a 29#endif /* HAVE_AUTHORIZATION_H */
db1f069b
MS
30#ifdef HAVE_SYS_PARAM_H
31# include <sys/param.h>
32#endif /* HAVE_SYS_PARAM_H */
bc44d920 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
5a9febac 38# ifndef __OpenBSD__
bc44d920 39typedef struct ucred cupsd_ucred_t;
5a9febac
MS
40# else
41typedef struct sockpeercred cupsd_ucred_t;
42# endif
bc44d920 43# define CUPSD_UCRED_UID(c) (c).uid
44#endif /* HAVE_SYS_UCRED_H */
9968d013
MS
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 */
ef416fc2 52
53
54/*
55 * Local functions...
56 */
57
8e46966d 58static int check_admin_access(cupsd_client_t *con);
f7deaa1a 59#ifdef HAVE_AUTHORIZATION_H
60static int check_authref(cupsd_client_t *con, const char *right);
61#endif /* HAVE_AUTHORIZATION_H */
732dcc06
MS
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);
10d09e33 64static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data);
10d09e33 65static void free_authmask(cupsd_authmask_t *am, void *data);
732dcc06
MS
66static void free_ogroup(cupsd_ogroup_t *og, void *data);
67static int load_ogroup(cupsd_ogroup_t *og, struct stat *fileinfo);
ef416fc2 68#if HAVE_LIBPAM
69static int pam_func(int, const struct pam_message **,
70 struct pam_response **, void *);
ef416fc2 71#endif /* HAVE_LIBPAM */
72
73
74/*
75 * Local structures...
76 */
77
78#if HAVE_LIBPAM
79typedef struct cupsd_authdata_s /**** Authentication data ****/
80{
3e7fe0ca
MS
81 char username[HTTP_MAX_VALUE], /* Username string */
82 password[HTTP_MAX_VALUE]; /* Password string */
ef416fc2 83} cupsd_authdata_t;
84#endif /* HAVE_LIBPAM */
85
86
ef416fc2 87/*
10d09e33 88 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
ef416fc2 89 */
90
10d09e33
MS
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 */
ef416fc2 96{
10d09e33 97 cupsd_authmask_t temp; /* New host/domain mask */
ef416fc2 98
99
4f05fa3b 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]);
ef416fc2 101
10d09e33
MS
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));
ef416fc2 105
bd7854cb 106 /*
10d09e33 107 * Create the masks array as needed and add...
bd7854cb 108 */
109
10d09e33
MS
110 if (!*masks)
111 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
112 (cups_acopy_func_t)copy_authmask,
113 (cups_afree_func_t)free_authmask);
ef416fc2 114
10d09e33
MS
115 return (cupsArrayAdd(*masks, &temp));
116}
ef416fc2 117
bd7854cb 118
10d09e33
MS
119/*
120 * 'cupsdAddLocation()' - Add a location for authorization.
121 */
ef416fc2 122
10d09e33
MS
123void
124cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */
125{
ef416fc2 126 /*
10d09e33 127 * Make sure the locations array is created...
ef416fc2 128 */
129
10d09e33
MS
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
ffe32673 140 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"", loc->location ? loc->location : "(null)");
10d09e33 141 }
ef416fc2 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{
4f05fa3b 153 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", (void *)loc, name);
ef416fc2 154
10d09e33
MS
155 if (!loc->names)
156 loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
ef4ccd7f
MS
157 (cups_acopy_func_t)_cupsArrayStrdup,
158 (cups_afree_func_t)_cupsArrayFree);
ef416fc2 159
10d09e33 160 if (!cupsArrayAdd(loc->names, name))
ef416fc2 161 {
162 cupsdLogMessage(CUPSD_LOG_ERROR,
163 "Unable to duplicate name for location %s: %s",
e1d6a774 164 loc->location ? loc->location : "nil", strerror(errno));
ef416fc2 165 return;
166 }
ef416fc2 167}
168
169
170/*
10d09e33 171 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
ef416fc2 172 */
173
10d09e33
MS
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 */
ef416fc2 177{
10d09e33 178 cupsd_authmask_t temp; /* New host/domain mask */
ef416fc2 179 char ifname[32], /* Interface name */
180 *ifptr; /* Pointer to end of name */
181
182
4f05fa3b 183 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", (void *)masks, (void *)*masks, name);
ef416fc2 184
88f9aafc 185 if (!_cups_strcasecmp(name, "@LOCAL"))
ef416fc2 186 {
187 /*
10d09e33 188 * Deny *interface*...
ef416fc2 189 */
190
10d09e33
MS
191 temp.type = CUPSD_AUTH_INTERFACE;
192 temp.mask.name.name = (char *)"*";
ef416fc2 193 }
88f9aafc 194 else if (!_cups_strncasecmp(name, "@IF(", 4))
ef416fc2 195 {
196 /*
10d09e33 197 * Deny *interface*...
ef416fc2 198 */
199
6ac4da6b 200 cupsCopyString(ifname, name + 4, sizeof(ifname));
ef416fc2 201
10d09e33 202 ifptr = ifname + strlen(ifname) - 1;
ef416fc2 203
10d09e33 204 if (ifptr >= ifname && *ifptr == ')')
ef416fc2 205 {
ef416fc2 206 *ifptr = '\0';
207 }
208
10d09e33
MS
209 temp.type = CUPSD_AUTH_INTERFACE;
210 temp.mask.name.name = ifname;
ef416fc2 211 }
212 else
213 {
214 /*
10d09e33 215 * Deny name...
ef416fc2 216 */
217
10d09e33
MS
218 if (*name == '*')
219 name ++;
ef416fc2 220
10d09e33
MS
221 temp.type = CUPSD_AUTH_NAME;
222 temp.mask.name.name = (char *)name;
223 }
ef416fc2 224
10d09e33
MS
225 /*
226 * Set the name length...
227 */
ef416fc2 228
10d09e33 229 temp.mask.name.length = strlen(temp.mask.name.name);
ef416fc2 230
10d09e33
MS
231 /*
232 * Create the masks array as needed and add...
233 */
ef416fc2 234
10d09e33
MS
235 if (!*masks)
236 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
237 (cups_acopy_func_t)copy_authmask,
238 (cups_afree_func_t)free_authmask);
ef416fc2 239
10d09e33 240 return (cupsArrayAdd(*masks, &temp));
ef416fc2 241}
242
243
732dcc06
MS
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
ef416fc2 310/*
311 * 'cupsdAuthorize()' - Validate any authorization credentials.
312 */
313
314void
315cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
316{
317 int type; /* Authentication type */
f7deaa1a 318 const char *authorization; /* Pointer into Authorization string */
319 char *ptr, /* Pointer into string */
9756c004 320 bearer[4096], /* CUPS_BEARER cookie string */
3e7fe0ca
MS
321 username[HTTP_MAX_VALUE],
322 /* Username string */
323 password[HTTP_MAX_VALUE];
324 /* Password string */
db0bd74a 325 cupsd_cert_t *localuser; /* Certificate username */
ef416fc2 326
327
328 /*
329 * Locate the best matching location so we know what kind of
330 * authentication to expect...
331 */
332
996acce8 333 con->best = cupsdFindBest(con->uri, httpGetState(con->http));
5bd77a73 334 con->type = CUPSD_AUTH_NONE;
ef416fc2 335
4f05fa3b 336 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, (void *)con->best, con->best ? con->best->location : "");
ef416fc2 337
5bd77a73 338 if (con->best && con->best->type != CUPSD_AUTH_NONE)
7ff4fea9 339 {
5bd77a73 340 if (con->best->type == CUPSD_AUTH_DEFAULT)
dcb445bc 341 type = cupsdDefaultAuthType();
7ff4fea9
MS
342 else
343 type = con->best->type;
344 }
ef416fc2 345 else
dcb445bc 346 type = cupsdDefaultAuthType();
ef416fc2 347
348 /*
349 * Decode the Authorization string...
350 */
351
996acce8 352 authorization = httpGetField(con->http, HTTP_FIELD_AUTHORIZATION);
ef416fc2 353
9756c004
MS
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])
4b4586e7
MS
357 authorization = "Bearer COOKIE";
358
ef416fc2 359 username[0] = '\0';
360 password[0] = '\0';
361
07ed0e9a
MS
362#ifdef HAVE_GSSAPI
363 con->gss_uid = 0;
364#endif /* HAVE_GSSAPI */
365
f7deaa1a 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
2fb76298 374 if (!*authorization)
ef416fc2 375 {
376 /*
377 * No authorization data provided, return early...
378 */
379
ffe32673 380 cupsdLogClient(con, CUPSD_LOG_DEBUG, "No authentication data provided.");
ef416fc2 381 return;
382 }
f7deaa1a 383#ifdef HAVE_AUTHORIZATION_H
c8fef167 384 else if (!strncmp(authorization, "AuthRef ", 8) &&
5ec1fd3d 385 httpAddrLocalhost(httpGetAddress(con->http)))
f7deaa1a 386 {
387 OSStatus status; /* Status */
e0660879
MS
388 char authdata[HTTP_MAX_VALUE];
389 /* Nonce value from client */
f7deaa1a 390 int authlen; /* Auth string length */
391 AuthorizationItemSet *authinfo; /* Authorization item set */
392
393 /*
394 * Get the Authorization Services data...
395 */
396
c8fef167 397 authorization += 8;
f7deaa1a 398 while (isspace(*authorization & 255))
399 authorization ++;
400
e0660879
MS
401 authlen = sizeof(authdata);
402 httpDecode64_2(authdata, &authlen, authorization);
f7deaa1a 403
404 if (authlen != kAuthorizationExternalFormLength)
405 {
ffe32673 406 cupsdLogClient(con, CUPSD_LOG_ERROR, "External Authorization reference size is incorrect.");
f7deaa1a 407 return;
408 }
409
e0660879 410 if ((status = AuthorizationCreateFromExternalForm((AuthorizationExternalForm *)authdata, &con->authref)) != 0)
f7deaa1a 411 {
fa26ab95 412 cupsdLogClient(con, CUPSD_LOG_ERROR, "AuthorizationCreateFromExternalForm returned %d", (int)status);
f7deaa1a 413 return;
414 }
415
c8fef167 416 username[0] = '\0';
ed6e7faf 417
c8fef167 418 if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
bf3816c7 419 &authinfo))
e4572d57 420 {
ed6e7faf
MS
421 if (authinfo->count == 1 && authinfo->items[0].value &&
422 authinfo->items[0].valueLength >= 2)
c8fef167 423 {
6ac4da6b 424 cupsCopyString(username, authinfo->items[0].value, sizeof(username));
ed6e7faf 425
ffe32673 426 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef.", username);
c8fef167
MS
427 }
428
e4572d57 429 AuthorizationFreeItemSet(authinfo);
e4572d57 430 }
355e94dc 431
c8fef167
MS
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
996acce8 444 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
c8fef167 445 {
ffe32673 446 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
c8fef167
MS
447 return;
448 }
449
450 if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
451 {
ffe32673 452 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred));
c8fef167
MS
453 return;
454 }
455
6ac4da6b 456 cupsCopyString(username, pwd->pw_name, sizeof(username));
c8fef167 457
ffe32673 458 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef + PeerCred.", username);
c8fef167
MS
459 }
460
5bd77a73 461 con->type = CUPSD_AUTH_BASIC;
f7deaa1a 462 }
463#endif /* HAVE_AUTHORIZATION_H */
bc44d920 464#if defined(SO_PEERCRED) && defined(AF_LOCAL)
465 else if (!strncmp(authorization, "PeerCred ", 9) &&
0d40cb1e 466 con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best)
bc44d920 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 */
f14324a7
MS
475#ifdef HAVE_AUTHORIZATION_H
476 const char *name; /* Authorizing name */
6961465f
MS
477 int no_peer = 0; /* Don't allow peer credentials? */
478
479 /*
480 * See if we should allow peer credentials...
481 */
bc44d920 482
f14324a7
MS
483 for (name = (char *)cupsArrayFirst(con->best->names);
484 name;
485 name = (char *)cupsArrayNext(con->best->names))
6961465f 486 {
dcb445bc
MS
487 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) ||
488 !_cups_strcasecmp(name, "@SYSTEM"))
f14324a7 489 {
6961465f
MS
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;
f14324a7 498 }
6961465f
MS
499 }
500
501 if (no_peer)
502 {
ffe32673 503 cupsdLogClient(con, CUPSD_LOG_ERROR, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
6961465f
MS
504 return;
505 }
f14324a7 506#endif /* HAVE_AUTHORIZATION_H */
bc44d920 507
508 if ((pwd = getpwnam(authorization + 9)) == NULL)
509 {
ffe32673 510 cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9);
bc44d920 511 return;
512 }
513
514 peersize = sizeof(peercred);
515
f11a948a 516# ifdef __APPLE__
996acce8 517 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
f11a948a 518# else
996acce8 519 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
f11a948a 520# endif /* __APPLE__ */
bc44d920 521 {
ffe32673 522 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
bc44d920 523 return;
524 }
525
526 if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
527 {
ffe32673 528 cupsdLogClient(con, CUPSD_LOG_ERROR, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization + 9, CUPSD_UCRED_UID(peercred), pwd->pw_uid);
bc44d920 529# ifdef HAVE_SYS_UCRED_H
ffe32673
MS
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]);
bc44d920 534# endif /* HAVE_SYS_UCRED_H */
535 return;
536 }
537
6ac4da6b 538 cupsCopyString(username, authorization + 9, sizeof(username));
355e94dc 539
eac3a0a0
MS
540# ifdef HAVE_GSSAPI
541 con->gss_uid = CUPSD_UCRED_UID(peercred);
542# endif /* HAVE_GSSAPI */
543
ffe32673 544 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using PeerCred.", username);
2fb76298 545
5bd77a73 546 con->type = CUPSD_AUTH_BASIC;
bc44d920 547 }
548#endif /* SO_PEERCRED && AF_LOCAL */
ef416fc2 549 else if (!strncmp(authorization, "Local", 5) &&
5ec1fd3d 550 httpAddrLocalhost(httpGetAddress(con->http)))
ef416fc2 551 {
552 /*
553 * Get Local certificate authentication data...
554 */
555
556 authorization += 5;
80ca4592 557 while (isspace(*authorization & 255))
ef416fc2 558 authorization ++;
559
0fa6c7fa 560 if ((localuser = cupsdFindCert(authorization)) == NULL)
ef416fc2 561 {
ffe32673 562 cupsdLogClient(con, CUPSD_LOG_ERROR, "Local authentication certificate not found.");
ef416fc2 563 return;
564 }
2fb76298 565
6ac4da6b 566 cupsCopyString(username, localuser->username, sizeof(username));
0fa6c7fa
MS
567 con->type = localuser->type;
568
ffe32673 569 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using Local.", username);
ef416fc2 570 }
b5dc6af7 571 else if (!strncmp(authorization, "Basic ", 6))
ef416fc2 572 {
573 /*
574 * Get the Basic authentication data...
575 */
576
577 int userlen; /* Username:password length */
578
2f700337
MS
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
ef416fc2 589 authorization += 5;
80ca4592 590 while (isspace(*authorization & 255))
ef416fc2 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 {
ffe32673 602 cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Basic password.");
ef416fc2 603 return;
604 }
605
606 *ptr++ = '\0';
607
608 if (!username[0])
609 {
610 /*
611 * Username must not be empty...
612 */
613
ffe32673 614 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic username.");
ef416fc2 615 return;
616 }
617
618 if (!*ptr)
619 {
620 /*
621 * Password must not be empty...
622 */
623
ffe32673 624 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic password.");
ef416fc2 625 return;
626 }
627
6ac4da6b 628 cupsCopyString(password, ptr, sizeof(password));
ef416fc2 629
630 /*
631 * Validate the username and password...
632 */
633
ef416fc2 634 {
ef416fc2 635#if HAVE_LIBPAM
e70cfeec
MS
636 /*
637 * Only use PAM to do authentication. This supports MD5
638 * passwords, among other things...
639 */
ef416fc2 640
e70cfeec
MS
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 */
4b4586e7 645 struct passwd *userinfo; /* User information */
ef416fc2 646
6ac4da6b
MS
647 cupsCopyString(data.username, username, sizeof(data.username));
648 cupsCopyString(data.password, password, sizeof(data.password));
ef416fc2 649
5a1d7a17 650# ifdef __sun
e70cfeec
MS
651 pamdata.conv = (int (*)(int, struct pam_message **,
652 struct pam_response **,
653 void *))pam_func;
e1d6a774 654# else
e70cfeec 655 pamdata.conv = pam_func;
5a1d7a17 656# endif /* __sun */
e70cfeec 657 pamdata.appdata_ptr = &data;
ef416fc2 658
e70cfeec
MS
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 }
ef416fc2 665
ee571f26
MS
666# ifdef HAVE_PAM_SET_ITEM
667# ifdef PAM_RHOST
e70cfeec
MS
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));
ee571f26
MS
671# endif /* PAM_RHOST */
672
673# ifdef PAM_TTY
e70cfeec
MS
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));
ee571f26
MS
677# endif /* PAM_TTY */
678# endif /* HAVE_PAM_SET_ITEM */
679
e70cfeec
MS
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 }
ef416fc2 687
94da7e34 688# ifdef HAVE_PAM_SETCRED
e70cfeec
MS
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));
94da7e34
MS
692# endif /* HAVE_PAM_SETCRED */
693
e70cfeec
MS
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 }
ef416fc2 701
e70cfeec 702 pam_end(pamh, PAM_SUCCESS);
4b4586e7
MS
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));
ef416fc2 710#else
ee9f25aa
MS
711 cupsdLogClient(con, CUPSD_LOG_ERROR, "No authentication support is available.");
712 return;
ef416fc2 713#endif /* HAVE_LIBPAM */
ef416fc2 714 }
2fb76298 715
e70cfeec 716 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Basic.", username);
2fb76298 717 con->type = type;
ef416fc2 718 }
b5dc6af7
MS
719 else if (!strncmp(authorization, "Bearer ", 7))
720 {
721 // OAuth/OpenID authorization using JWT bearer tokens...
f214077c 722 cups_jwt_t *jwt; // JWT user information
b5dc6af7
MS
723 const char *sub, // Subject/user ID
724 *name, // Real name
725 *email; // Email address
726
2f700337
MS
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
b5dc6af7
MS
737 // Skip whitespace after "Bearer"...
738 authorization += 7;
739 while (isspace(*authorization & 255))
740 authorization ++;
741
4b4586e7
MS
742 if (!strcmp(authorization, "COOKIE"))
743 authorization = bearer; // Use the cookie value for authorization
744
b5dc6af7 745 // Decode and validate the JWT...
f214077c 746 if ((jwt = cupsOAuthGetUserId(OAuthServer, OAuthMetadata, authorization)) == NULL)
b5dc6af7 747 {
f214077c 748 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get user information from bearer token: %s", cupsGetErrorString());
b5dc6af7
MS
749 cupsCopyString(con->autherror, cupsGetErrorString(), sizeof(con->autherror));
750 return;
751 }
b5dc6af7
MS
752 else if ((sub = cupsJWTGetClaimString(jwt, CUPS_JWT_SUB)) == NULL)
753 {
f214077c 754 cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing subject name in user information.");
b5dc6af7
MS
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...
f214077c 761 con->type = CUPSD_AUTH_BEARER;
b5dc6af7
MS
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 }
f7deaa1a 777#ifdef HAVE_GSSAPI
b5dc6af7 778 else if (!strncmp(authorization, "Negotiate ", 10))
f7deaa1a 779 {
780 int len; /* Length of authorization string */
f7deaa1a 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
2f700337
MS
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
4b4586e7 800# ifdef __APPLE__DISABLED // Remove DISABLED if ever this code is used for macOS installer
f42414bf 801 /*
802 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
803 * to use it...
804 */
805
d2ff4622 806 if (&gss_init_sec_context == NULL)
f42414bf 807 {
ffe32673 808 cupsdLogClient(con, CUPSD_LOG_WARN, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
f42414bf 809 return;
810 }
4b4586e7 811# endif /* __APPLE__DISABLED */
f42414bf 812
f7deaa1a 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 {
ffe32673 823 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "No authentication data specified.");
f7deaa1a 824 return;
825 }
826
f7deaa1a 827 /*
828 * Decode the authorization string to get the input token...
829 */
830
b31d4ca5 831 len = (int)strlen(authorization) + 0;
7e86f2f6 832 input_token.value = malloc((size_t)len);
f7deaa1a 833 input_token.value = httpDecode64_2(input_token.value, &len,
c7017ecc 834 authorization);
7e86f2f6 835 input_token.length = (size_t)len;
f7deaa1a 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,
dcb445bc 845 ServerCreds,
f7deaa1a 846 &input_token,
847 GSS_C_NO_CHANNEL_BINDINGS,
848 &client_name,
849 NULL,
07ed0e9a
MS
850 &output_token,
851 NULL,
f7deaa1a 852 NULL,
07ed0e9a
MS
853 NULL);
854
855 if (output_token.length > 0)
856 gss_release_buffer(&minor_status, &output_token);
f7deaa1a 857
858 if (GSS_ERROR(major_status))
859 {
ffe32673 860 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error accepting GSSAPI security context.", con->number);
f7deaa1a 861
862 if (context != GSS_C_NO_CONTEXT)
863 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 864 return;
865 }
866
97c9a8d7
MS
867 con->have_gss = 1;
868
76cd9e37
MS
869 /*
870 * Get the username associated with the client's credentials...
f7deaa1a 871 */
872
355e94dc 873 if (major_status == GSS_S_CONTINUE_NEEDED)
ffe32673 874 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Credentials not complete.", con->number);
355e94dc 875 else if (major_status == GSS_S_COMPLETE)
f7deaa1a 876 {
c8fef167 877 major_status = gss_display_name(&minor_status, client_name,
f7deaa1a 878 &output_token, NULL);
879
880 if (GSS_ERROR(major_status))
881 {
ffe32673 882 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error getting username.", con->number);
f7deaa1a 883 gss_release_name(&minor_status, &client_name);
884 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 885 return;
886 }
887
6ac4da6b 888 cupsCopyString(username, output_token.value, sizeof(username));
355e94dc 889
ffe32673 890 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Negotiate.", username);
f7deaa1a 891
e07d4801 892 gss_release_name(&minor_status, &client_name);
f7deaa1a 893 gss_release_buffer(&minor_status, &output_token);
2fb76298 894
5bd77a73 895 con->type = CUPSD_AUTH_NEGOTIATE;
f7deaa1a 896 }
e07d4801
MS
897
898 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
07ed0e9a
MS
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
5ec1fd3d 906 if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL)
07ed0e9a
MS
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__
996acce8 914 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
07ed0e9a 915# else
996acce8 916 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred,
07ed0e9a
MS
917 &peersize))
918# endif /* __APPLE__ */
919 {
ffe32673 920 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
07ed0e9a
MS
921 }
922 else
923 {
ffe32673 924 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred));
07ed0e9a
MS
925 con->gss_uid = CUPSD_UCRED_UID(peercred);
926 }
927 }
928# endif /* SO_PEERCRED && AF_LOCAL */
f7deaa1a 929 }
930#endif /* HAVE_GSSAPI */
2fb76298 931 else
ef416fc2 932 {
355e94dc 933 char scheme[256]; /* Auth scheme... */
355e94dc
MS
934
935
936 if (sscanf(authorization, "%255s", scheme) != 1)
6ac4da6b 937 cupsCopyString(scheme, "UNKNOWN", sizeof(scheme));
355e94dc 938
ffe32673 939 cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\".", scheme);
ef416fc2 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
6ac4da6b 949 cupsCopyString(con->username, username, sizeof(con->username));
4b4586e7
MS
950
951 if (!con->realname[0])
952 cupsCopyString(con->realname, username, sizeof(con->realname));
953
6ac4da6b 954 cupsCopyString(con->password, password, sizeof(con->password));
ef416fc2 955}
956
957
080811b1
MS
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 */
5ec1fd3d 966 const char *name, /* I - Client hostname */
7e86f2f6 967 size_t namelen, /* I - Length of hostname */
080811b1
MS
968 cupsd_location_t *loc) /* I - Location to check */
969{
970 int allow; /* 1 if allowed, 0 otherwise */
971
972
88f9aafc 973 if (!_cups_strcasecmp(name, "localhost"))
080811b1
MS
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
5bd77a73 993 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
080811b1
MS
994 allow = 1;
995
10d09e33 996 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
080811b1
MS
997 allow = 0;
998
10d09e33 999 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
080811b1
MS
1000 allow = 1;
1001 break;
1002
5bd77a73 1003 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
080811b1
MS
1004 allow = 0;
1005
10d09e33 1006 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
080811b1
MS
1007 allow = 1;
1008
10d09e33 1009 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
080811b1
MS
1010 allow = 0;
1011 break;
1012 }
1013 }
1014
1015 return (allow);
1016}
1017
1018
ef416fc2 1019/*
1020 * 'cupsdCheckAuth()' - Check authorization masks.
1021 */
1022
1023int /* O - 1 if mask matches, 0 otherwise */
10d09e33 1024cupsdCheckAuth(unsigned ip[4], /* I - Client address */
5ec1fd3d 1025 const char *name, /* I - Client hostname */
7e86f2f6 1026 size_t name_len, /* I - Length of hostname */
10d09e33 1027 cups_array_t *masks) /* I - Masks */
ef416fc2 1028{
10d09e33
MS
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 */
ef416fc2 1033#ifdef AF_INET6
10d09e33 1034 unsigned netip6[4]; /* IPv6 network address */
ef416fc2 1035#endif /* AF_INET6 */
1036
e07d4801 1037
10d09e33
MS
1038 for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
1039 mask;
1040 mask = (cupsd_authmask_t *)cupsArrayNext(masks))
ef416fc2 1041 {
10d09e33 1042 switch (mask->type)
ef416fc2 1043 {
5bd77a73 1044 case CUPSD_AUTH_INTERFACE :
ef416fc2 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
84ec3a84
MS
1058 cupsdNetIFUpdate();
1059
10d09e33 1060 if (!strcmp(mask->mask.name.name, "*"))
ef416fc2 1061 {
e07d4801
MS
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
ef416fc2 1071 /*
1072 * Check against all local interfaces...
1073 */
1074
e00b005a 1075 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1076 iface;
1077 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 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
e00b005a 1122 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
ed486911 1123 iface;
e00b005a 1124 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 1125 {
10d09e33 1126 if (strcmp(mask->mask.name.name, iface->name))
ed486911 1127 continue;
1128
ef416fc2 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
5bd77a73 1161 case CUPSD_AUTH_NAME :
ef416fc2 1162 /*
1163 * Check for exact name match...
1164 */
1165
88f9aafc 1166 if (!_cups_strcasecmp(name, mask->mask.name.name))
ef416fc2 1167 return (1);
1168
1169 /*
1170 * Check for domain match...
1171 */
1172
10d09e33
MS
1173 if (name_len >= mask->mask.name.length &&
1174 mask->mask.name.name[0] == '.' &&
88f9aafc 1175 !_cups_strcasecmp(name + name_len - mask->mask.name.length,
10d09e33 1176 mask->mask.name.name))
ef416fc2 1177 return (1);
1178 break;
1179
5bd77a73 1180 case CUPSD_AUTH_IP :
ef416fc2 1181 /*
1182 * Check for IP/network address match...
1183 */
1184
1185 for (i = 0; i < 4; i ++)
10d09e33
MS
1186 if ((ip[i] & mask->mask.ip.netmask[i]) !=
1187 mask->mask.ip.address[i])
ef416fc2 1188 break;
1189
1190 if (i == 4)
1191 return (1);
1192 break;
1193 }
ef416fc2 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{
8922323b 1210 int i; /* Looping var */
36374693
MS
1211 struct group *group; /* Group info */
1212 gid_t groupid; /* ID of named group */
bd7854cb 1213#ifdef HAVE_MBR_UID_TO_UUID
8922323b
MS
1214 uuid_t useruuid, /* UUID for username */
1215 groupuuid; /* UUID for groupname */
1216 int is_member; /* True if user is a member of group */
bd7854cb 1217#endif /* HAVE_MBR_UID_TO_UUID */
ef416fc2 1218
1219
4f05fa3b 1220 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, (void *)user, groupname);
ef416fc2 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
36374693
MS
1242 groupid = group->gr_gid;
1243
3c27d2a6
MS
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
6eb98aee 1254#ifdef HAVE_GETGROUPLIST
3c27d2a6
MS
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
6eb98aee
MS
1261 if (user)
1262 {
f093225b 1263 int ngroups; /* Number of groups */
fdc3c81a
MS
1264# ifdef __APPLE__
1265 int groups[2048]; /* Groups that user belongs to */
1266# else
f093225b 1267 gid_t groups[2048]; /* Groups that user belongs to */
fdc3c81a 1268# endif /* __APPLE__ */
6eb98aee
MS
1269
1270 ngroups = (int)(sizeof(groups) / sizeof(groups[0]));
fdc3c81a
MS
1271# ifdef __APPLE__
1272 getgrouplist(username, (int)user->pw_gid, groups, &ngroups);
1273# else
f093225b 1274 getgrouplist(username, user->pw_gid, groups, &ngroups);
fdc3c81a 1275#endif /* __APPLE__ */
6eb98aee
MS
1276
1277 for (i = 0; i < ngroups; i ++)
36374693 1278 if ((int)groupid == (int)groups[i])
6eb98aee
MS
1279 return (1);
1280 }
36374693 1281#endif /* HAVE_GETGROUPLIST */
ef416fc2 1282 }
36374693
MS
1283 else
1284 groupid = (gid_t)-1;
ef416fc2 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
36374693 1291 if (user && groupid == user->pw_gid)
ef416fc2 1292 return (1);
1293
bd7854cb 1294#ifdef HAVE_MBR_UID_TO_UUID
1295 /*
d4874933 1296 * Check group membership through macOS membership API...
bd7854cb 1297 */
1298
dd1abb6b 1299 if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
c9fc04c6 1300 {
36374693 1301 if (groupid != (gid_t)-1)
8922323b
MS
1302 {
1303 /*
1304 * Map group name to UUID and check membership...
1305 */
c9fc04c6 1306
36374693 1307 if (!mbr_gid_to_uuid(groupid, groupuuid))
8922323b
MS
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))
c9fc04c6 1322 return (1);
8922323b
MS
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);
bd7854cb 1333#endif /* HAVE_MBR_UID_TO_UUID */
1334
ef416fc2 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(
10d09e33 1349 cupsd_location_t *loc) /* I - Original location */
ef416fc2 1350{
ef416fc2 1351 cupsd_location_t *temp; /* New location */
ef416fc2 1352
1353
ef416fc2 1354 /*
10d09e33 1355 * Make a copy of the original location...
ef416fc2 1356 */
1357
10d09e33 1358 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
ef416fc2 1359 return (NULL);
1360
ef416fc2 1361 /*
1362 * Copy the information from the original location to the new one.
1363 */
1364
10d09e33
MS
1365 if (!loc)
1366 return (temp);
ef416fc2 1367
10d09e33
MS
1368 if (loc->location)
1369 temp->location = _cupsStrAlloc(loc->location);
ef416fc2 1370
d2ff4622 1371 temp->length = loc->length;
10d09e33
MS
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)
ef416fc2 1382 {
1383 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1384 "Unable to allocate memory for %d names: %s",
1385 cupsArrayCount(loc->names), strerror(errno));
bd7854cb 1386
cfe4c0c3 1387 cupsdFreeLocation(temp, NULL);
ef416fc2 1388 return (NULL);
1389 }
ef416fc2 1390 }
1391
10d09e33 1392 if (loc->allow)
ef416fc2 1393 {
1394 /*
1395 * Copy allow rules...
1396 */
1397
10d09e33 1398 if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
ef416fc2 1399 {
1400 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1401 "Unable to allocate memory for %d allow rules: %s",
1402 cupsArrayCount(loc->allow), strerror(errno));
cfe4c0c3 1403 cupsdFreeLocation(temp, NULL);
ef416fc2 1404 return (NULL);
1405 }
ef416fc2 1406 }
1407
10d09e33 1408 if (loc->deny)
ef416fc2 1409 {
1410 /*
1411 * Copy deny rules...
1412 */
1413
10d09e33 1414 if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
ef416fc2 1415 {
1416 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1417 "Unable to allocate memory for %d deny rules: %s",
1418 cupsArrayCount(loc->deny), strerror(errno));
cfe4c0c3 1419 cupsdFreeLocation(temp, NULL);
ef416fc2 1420 return (NULL);
1421 }
ef416fc2 1422 }
1423
1424 return (temp);
1425}
1426
1427
1428/*
1429 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1430 */
1431
1432void
1433cupsdDeleteAllLocations(void)
1434{
ef416fc2 1435 /*
10d09e33 1436 * Free the location array, which will free all of the locations...
ef416fc2 1437 */
1438
bd7854cb 1439 cupsArrayDelete(Locations);
1440 Locations = NULL;
ef416fc2 1441}
1442
1443
ef416fc2 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{
ef416fc2 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 */
7e86f2f6 1457 size_t bestlen; /* Length of best match */
ef416fc2 1458 int limit; /* Limit field */
5bd77a73 1459 static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
ef416fc2 1460 {
5bd77a73
MS
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,
d2ff4622
MS
1474 CUPSD_AUTH_LIMIT_ALL,
1475 CUPSD_AUTH_LIMIT_ALL,
5bd77a73 1476 CUPSD_AUTH_LIMIT_ALL
ef416fc2 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
6ac4da6b 1486 cupsCopyString(uri, path, sizeof(uri));
ef416fc2 1487
c26ceab0
MS
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
ef416fc2 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
ef416fc2 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
ffe32673 1515 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri=\"%s\", limit=%x...", uri, limit);
d2ff4622
MS
1516
1517
bd7854cb 1518 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1519 loc;
1520 loc = (cupsd_location_t *)cupsArrayNext(Locations))
ef416fc2 1521 {
d2ff4622 1522 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s(%d) Limit %x", loc->location ? loc->location : "(null)", (int)loc->length, loc->limit);
ef416fc2 1523
1524 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
1525 {
1526 /*
1527 * Use case-insensitive comparison for queue names...
1528 */
1529
e1d6a774 1530 if (loc->length > bestlen && loc->location &&
88f9aafc 1531 !_cups_strncasecmp(uri, loc->location, loc->length) &&
ef416fc2 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
e1d6a774 1545 if (loc->length > bestlen && loc->location &&
ef416fc2 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
ffe32673 1560 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best=%s", best ? best->location : "NONE");
ef416fc2 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{
bd7854cb 1573 cupsd_location_t key; /* Search key */
ef416fc2 1574
1575
bd7854cb 1576 key.location = (char *)location;
ef416fc2 1577
bd7854cb 1578 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
ef416fc2 1579}
1580
1581
732dcc06
MS
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
10d09e33
MS
1609/*
1610 * 'cupsdFreeLocation()' - Free all memory used by a location.
1611 */
1612
cfe4c0c3
R
1613void cupsdFreeLocation(cupsd_location_t *loc, /* I - Location to free */
1614 void *data) /* Unused */
10d09e33 1615{
cfe4c0c3 1616 (void)data;
10d09e33
MS
1617 cupsArrayDelete(loc->names);
1618 cupsArrayDelete(loc->allow);
1619 cupsArrayDelete(loc->deny);
1620
1621 _cupsStrFree(loc->location);
1622 free(loc);
1623}
1624
1625
0cdf79ef 1626/*
ce784173 1627 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
0cdf79ef
TK
1628 */
1629
ce784173
MS
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 */
0cdf79ef 1633{
ce784173
MS
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",
5578f804 1659 "Bearer",
ce784173
MS
1660 "Negotiate"
1661 };
0cdf79ef 1662
0cdf79ef 1663
4f05fa3b 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)" : "");
ce784173
MS
1665 if (owner)
1666 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: owner=\"%s\"", owner);
0cdf79ef
TK
1667
1668 /*
ce784173
MS
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...
0cdf79ef
TK
1672 */
1673
ce784173 1674 if (!con->best)
0cdf79ef 1675 {
ce784173
MS
1676 if (httpAddrLocalhost(httpGetAddress(con->http)) ||
1677 !strcmp(hostname, ServerName) ||
1678 cupsArrayFind(ServerAlias, (void *)hostname))
e3952d3e 1679 return (HTTP_STATUS_OK);
0cdf79ef 1680 else
e3952d3e 1681 return (HTTP_STATUS_FORBIDDEN);
ce784173 1682 }
0cdf79ef 1683
ce784173 1684 best = con->best;
0cdf79ef 1685
ce784173
MS
1686 if ((type = best->type) == CUPSD_AUTH_DEFAULT)
1687 type = cupsdDefaultAuthType();
0cdf79ef 1688
ce784173 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));
0cdf79ef 1690
ce784173
MS
1691 if (best->limit == CUPSD_AUTH_LIMIT_IPP)
1692 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", best->op, ippOpString(best->op));
0cdf79ef 1693
ce784173
MS
1694 /*
1695 * Check host/ip-based accesses...
1696 */
09c4144f 1697
ce784173
MS
1698#ifdef AF_INET6
1699 if (httpAddrFamily(hostaddr) == AF_INET6)
1700 {
1701 /*
1702 * Copy IPv6 address...
1703 */
0cdf79ef 1704
ce784173
MS
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 */
0cdf79ef 1717
ce784173
MS
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));
3885bb6c 1725
ce784173 1726 hostlen = strlen(hostname);
3885bb6c 1727
ce784173
MS
1728 auth = cupsdCheckAccess(address, hostname, hostlen, best)
1729 ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
3885bb6c 1730
ce784173 1731 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth ? "DENY" : "ALLOW");
3885bb6c 1732
ce784173 1733 if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
e3952d3e 1734 return (HTTP_STATUS_FORBIDDEN);
3885bb6c 1735
ce784173
MS
1736 /*
1737 * See if encryption is required...
1738 */
3885bb6c 1739
e3952d3e 1740 if ((best->encryption >= HTTP_ENCRYPTION_REQUIRED && !con->http->tls &&
ce784173
MS
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...");
e3952d3e 1750 return (HTTP_STATUS_UPGRADE_REQUIRED);
ce784173 1751 }
3885bb6c 1752
ce784173
MS
1753 /*
1754 * Now see what access level is required...
1755 */
3885bb6c 1756
ce784173
MS
1757 if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
1758 (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
e3952d3e 1759 return (HTTP_STATUS_OK);
3885bb6c 1760
ce784173
MS
1761 if (!con->username[0] && type == CUPSD_AUTH_NONE &&
1762 best->limit == CUPSD_AUTH_LIMIT_IPP)
1763 {
1764 /*
1765 * Check for unauthenticated username...
1766 */
0cdf79ef 1767
ce784173 1768 ipp_attribute_t *attr; /* requesting-user-name attribute */
0cdf79ef 1769
0cdf79ef 1770
ce784173
MS
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);
6ac4da6b 1777 cupsCopyString(username, attr->values[0].string.text, sizeof(username));
ce784173
MS
1778 }
1779 else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
e3952d3e 1780 return (HTTP_STATUS_UNAUTHORIZED); /* Non-anonymous needs user/pass */
ce784173 1781 else
e3952d3e 1782 return (HTTP_STATUS_OK); /* unless overridden with Satisfy */
ce784173
MS
1783 }
1784 else
1785 {
1786 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
1787 con->username);
0cdf79ef 1788
ce784173
MS
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)
e3952d3e 1796 return (HTTP_STATUS_UNAUTHORIZED); /* Non-anonymous needs user/pass */
ce784173 1797 else
e3952d3e 1798 return (HTTP_STATUS_OK); /* unless overridden with Satisfy */
ce784173 1799 }
0cdf79ef 1800
0cdf79ef 1801
ce784173
MS
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]);
0cdf79ef 1810
e3952d3e 1811 return (HTTP_STATUS_UNAUTHORIZED);
ce784173 1812 }
0cdf79ef 1813
6ac4da6b 1814 cupsCopyString(username, con->username, sizeof(username));
ce784173 1815 }
0cdf79ef 1816
ce784173
MS
1817 /*
1818 * OK, got a username. See if we need normal user access, or group
1819 * access...
1820 */
3885bb6c 1821
ce784173
MS
1822 /*
1823 * Strip any @domain or @KDC from the username and owner...
1824 */
3885bb6c 1825
5578f804 1826 if (type != CUPSD_AUTH_BEARER && StripUserDomain && (ptr = strchr(username, '@')) != NULL)
ce784173 1827 *ptr = '\0';
0cdf79ef 1828
ce784173
MS
1829 if (owner)
1830 {
6ac4da6b 1831 cupsCopyString(ownername, owner, sizeof(ownername));
0cdf79ef 1832
5578f804 1833 if (type != CUPSD_AUTH_BEARER && StripUserDomain && (ptr = strchr(ownername, '@')) != NULL)
ce784173
MS
1834 *ptr = '\0';
1835 }
1836 else
1837 ownername[0] = '\0';
0cdf79ef 1838
5578f804 1839 if (type == CUPSD_AUTH_BEARER)
ce784173
MS
1840 {
1841 /*
5578f804 1842 * Lookup access via OAuth groups...
ce784173 1843 */
0cdf79ef 1844
5578f804 1845 cupsd_ogroup_t *og; // Current OAuth group
ce784173 1846
5578f804
MS
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 */
ce784173 1853
5578f804
MS
1854 if (cupsArrayCount(best->names) == 0)
1855 return (HTTP_STATUS_OK);
ce784173 1856
5578f804
MS
1857 /*
1858 * Otherwise check the user list and return OK if this user is allowed...
1859 */
ce784173 1860
5578f804
MS
1861 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership...");
1862
1863 for (name = (char *)cupsArrayFirst(best->names); name; name = (char *)cupsArrayNext(best->names))
0cdf79ef 1864 {
5578f804
MS
1865 if (!_cups_strcasecmp(name, "@OWNER") && owner && !_cups_strcasecmp(username, ownername))
1866 {
1867 // User is owner...
e3952d3e 1868 return (HTTP_STATUS_OK);
5578f804
MS
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 }
0cdf79ef 1888 }
5578f804
MS
1889 }
1890 else
1891 {
1892 /*
1893 * Check to see if this user is in any of the named groups...
1894 */
0cdf79ef 1895
5578f804
MS
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))
0cdf79ef 1903 {
5578f804
MS
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...
e3952d3e 1914 return (HTTP_STATUS_OK);
5578f804 1915 }
0cdf79ef 1916 }
5578f804
MS
1917 }
1918 }
1919 else
1920 {
1921 /*
1922 * Get the (local) user info...
1923 */
0cdf79ef 1924
5578f804
MS
1925 if (username[0])
1926 {
1927 pw = getpwnam(username);
1928 endpwent();
ce784173 1929 }
5578f804
MS
1930 else
1931 pw = NULL;
ce784173 1932
5578f804
MS
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)
ce784173 1950 {
5578f804
MS
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)
e3952d3e 1957 return (HTTP_STATUS_OK);
5578f804
MS
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)
0cdf79ef 1972 {
5578f804
MS
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);
0cdf79ef 1991 }
5578f804
MS
1992#endif /* HAVE_AUTHORIZATION_H */
1993
1994 for (name = (char *)cupsArrayFirst(best->names);
1995 name;
1996 name = (char *)cupsArrayNext(best->names))
0cdf79ef 1997 {
5578f804
MS
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);
0cdf79ef
TK
2013 }
2014
5578f804
MS
2015 for (name = (char *)cupsArrayFirst(best->names);
2016 name;
2017 name = (char *)cupsArrayNext(best->names))
ce784173 2018 {
5578f804
MS
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 }
ce784173
MS
2025 }
2026 }
5578f804 2027 else
ce784173 2028 {
5578f804
MS
2029 /*
2030 * Check to see if this user is in any of the named groups...
2031 */
0cdf79ef 2032
5578f804 2033 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group membership...");
0cdf79ef 2034
5578f804
MS
2035 /*
2036 * Check to see if this user is in any of the named groups...
2037 */
0cdf79ef 2038
5578f804
MS
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 }
0cdf79ef 2048
5578f804
MS
2049 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name);
2050
2051 if (cupsdCheckGroup(username, pw, name))
e3952d3e 2052 return (HTTP_STATUS_OK);
5578f804
MS
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 }
ce784173
MS
2068 }
2069 }
40088fca 2070
ce784173 2071 /*
5578f804 2072 * The user isn't part of the specified users or groups, so deny access...
ce784173 2073 */
40088fca 2074
ce784173 2075 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: User not in group(s).");
40088fca 2076
e3952d3e 2077 return (con->username[0] ? HTTP_STATUS_FORBIDDEN : HTTP_STATUS_UNAUTHORIZED);
0cdf79ef
TK
2078}
2079
2080
ef416fc2 2081/*
ce784173
MS
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.
ef416fc2 2086 */
2087
ce784173
MS
2088cupsd_location_t * /* O - Pointer to new location record */
2089cupsdNewLocation(const char *location) /* I - Location path */
ef416fc2 2090{
ce784173 2091 cupsd_location_t *temp; /* New location */
ef416fc2 2092
2093
ce784173
MS
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);
ef416fc2 2100
2101 /*
ce784173 2102 * Initialize the record and copy the name over...
ef416fc2 2103 */
2104
ce784173 2105 if ((temp->location = _cupsStrAlloc(location)) == NULL)
ef416fc2 2106 {
ce784173
MS
2107 free(temp);
2108 return (NULL);
ef416fc2 2109 }
2110
ce784173 2111 temp->length = strlen(temp->location);
ef416fc2 2112
ce784173
MS
2113 /*
2114 * Return the new record...
2115 */
2fb76298 2116
ce784173
MS
2117 return (temp);
2118}
2119
2120
2121/*
8e46966d 2122 * 'check_admin_access()' - Verify that the client has administrative access.
ce784173
MS
2123 */
2124
8e46966d
MS
2125static int // O - 1 if authorized, 0 otherwise
2126check_admin_access(cupsd_client_t *con) // I - Client connection
ce784173 2127{
4f05fa3b
MS
2128 (void)con;
2129
8e46966d 2130#if defined(HAVE_LIBAPPARMOR) && defined(HAVE_LIBSNAPDGLIB)
ef416fc2 2131 /*
ce784173 2132 * If the client accesses locally via domain socket, find out whether it
8e46966d
MS
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.
ce784173
MS
2136 */
2137
8e46966d
MS
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
8e0d2bc9 2144# if !CUPS_SNAP
2ba81346 2145 SnapdSnap *snap = NULL; // Data structure of client Snap
8e0d2bc9 2146# endif // !CUPS_SNAP
ef416fc2 2147
eac3a0a0 2148
8e46966d
MS
2149# ifdef AF_LOCAL
2150 // Only check domain sockets...
2151 if (httpAddrFamily(con->http->hostaddr) != AF_LOCAL)
2152 return (1);
2153# endif // AF_LOCAL
db1f069b 2154
8e46966d
MS
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 */
ef416fc2 2163
8e46966d
MS
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 }
ef416fc2 2174
8e46966d
MS
2175 // Allow access from "cups" snap...
2176 if (!strncmp(context, "snap.cups.", 10))
8b7da9cd
TK
2177 {
2178 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Client from the CUPS Snap itself - allowed.");
8e46966d 2179 goto done;
8b7da9cd 2180 }
0cdf79ef 2181
8e46966d
MS
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 */
ef416fc2 2188
8e46966d
MS
2189 const char *cookie; // snapd access cookie
2190 int status = 65535; // Status of client Snap context check
5c693e1b 2191 const char *args[] = // snapctl arguments
8e46966d
MS
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 }
ef416fc2 2207
8e46966d
MS
2208 // snapctl commands are sent over a domain socket
2209 snapd_client_set_socket_path(client, "/run/snapd-snap.socket");
ef416fc2 2210
8e46966d
MS
2211 // Take cookie from the environment if available
2212 if ((cookie = g_getenv("SNAP_COOKIE")) == NULL)
2213 {
2214 cookie = "";
8e0d2bc9 2215 cupsdLogClient(con, CUPSD_LOG_WARN, "No SNAP_COOKIE set in the Snap environment.");
8e46966d 2216 }
ef416fc2 2217
8e46966d
MS
2218 // Do the client Snap context check...
2219 args[2] = context;
f7deaa1a 2220
5c693e1b 2221 if (!snapd_client_run_snapctl2_sync(client, cookie, (char **)args, NULL, NULL, &status, NULL, &error))
8e46966d
MS
2222 {
2223 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to check snap context: %s", error->message);
2224 ret = 0;
2225 goto done;
2226 }
0cdf79ef 2227
8e46966d
MS
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.");
ce784173 2235 ret = 0;
8e46966d
MS
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);
ce784173 2245 ret = 0;
8e46966d
MS
2246 break;
2247 }
f7deaa1a 2248
8e46966d
MS
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 */
ce784173 2254
8e46966d
MS
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 }
ef416fc2 2261
8e46966d
MS
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 }
0cdf79ef 2272
8e46966d
MS
2273 *ptr = '\0';
2274 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Client snap is '%s'.", snap_name);
ef416fc2 2275
8e46966d
MS
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 }
ef416fc2 2284
8e46966d
MS
2285 // Check whether the client Snap is under classic confinement
2286 GPtrArray *plugs = NULL; // List of plugs for snap
ef416fc2 2287
8e46966d
MS
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
8e0d2bc9 2299 else if (!snapd_client_get_connections2_sync(client, SNAPD_GET_CONNECTIONS_FLAGS_NONE, snap_name, "cups-control", NULL, NULL, &plugs, NULL, NULL, &error))
8e46966d
MS
2300 {
2301 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Unable to get client Snap plugs: %s", error->message);
2302 ret = 0;
2303 }
69434b4e 2304 else if (!plugs || plugs->len <= 0)
8e46966d
MS
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 }
ef416fc2 2313
8e46966d
MS
2314 if (plugs)
2315 g_ptr_array_unref(plugs);
0cdf79ef 2316
8e46966d
MS
2317 free(snap_name);
2318 g_clear_object(&snap);
ef416fc2 2319
8e46966d 2320# endif // CUPS_SNAP
0cdf79ef 2321
8e46966d 2322 done:
0cdf79ef 2323
8e46966d
MS
2324 free(context);
2325 g_clear_object(&client);
ef416fc2 2326
8e46966d 2327 return (ret);
ef416fc2 2328
ce784173 2329#else
8e46966d
MS
2330 // No AppArmor/snapd to deal with...
2331 return (1);
2332#endif // HAVE_LIBAPPARMOR && HAVE_LIBSNAPDGLIB
ef416fc2 2333}
2334
2335
f7deaa1a 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
c8fef167 2367 authflags = kAuthorizationFlagDefaults |
f7deaa1a 2368 kAuthorizationFlagExtendRights;
2369
c8fef167
MS
2370 if ((status = AuthorizationCopyRights(con->authref, &authrights,
2371 kAuthorizationEmptyEnvironment,
f7deaa1a 2372 authflags, NULL)) != 0)
2373 {
fa26ab95 2374 cupsdLogMessage(CUPSD_LOG_ERROR, "AuthorizationCopyRights(\"%s\") returned %d", authright.name, (int)status);
f7deaa1a 2375 return (0);
2376 }
2377
ffe32673 2378 cupsdLogMessage(CUPSD_LOG_DEBUG2, "AuthorizationCopyRights(\"%s\") succeeded.", authright.name);
f7deaa1a 2379
2380 return (1);
2381}
2382#endif /* HAVE_AUTHORIZATION_H */
2383
2384
bd7854cb 2385/*
2386 * 'compare_locations()' - Compare two locations.
2387 */
2388
732dcc06
MS
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) */
bd7854cb 2393{
cfe4c0c3 2394 (void)data;
732dcc06 2395
bd7854cb 2396 return (strcmp(b->location, a->location));
2397}
2398
2399
732dcc06
MS
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
10d09e33
MS
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
10d09e33
MS
2454/*
2455 * 'free_authmask()' - Free function for auth masks.
2456 */
2457
2458static void
2459free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */
732dcc06 2460 void *data) /* I - Callback data (unused) */
10d09e33
MS
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
732dcc06
MS
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
ef416fc2 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
7e86f2f6 2554 if ((replies = malloc(sizeof(struct pam_response) * (size_t)num_msg)) == NULL)
ef416fc2 2555 return (PAM_CONV_ERR);
2556
2557 /*
2558 * Answer all of the messages...
2559 */
2560
ef416fc2 2561 data = (cupsd_authdata_t *)appdata_ptr;
ef416fc2 2562
2563 for (i = 0; i < num_msg; i ++)
2564 {
ef416fc2 2565 switch (msg[i]->msg_style)
2566 {
2567 case PAM_PROMPT_ECHO_ON:
ef416fc2 2568 replies[i].resp_retcode = PAM_SUCCESS;
2569 replies[i].resp = strdup(data->username);
2570 break;
2571
2572 case PAM_PROMPT_ECHO_OFF:
ef416fc2 2573 replies[i].resp_retcode = PAM_SUCCESS;
2574 replies[i].resp = strdup(data->password);
2575 break;
2576
2577 case PAM_TEXT_INFO:
ef416fc2 2578 replies[i].resp_retcode = PAM_SUCCESS;
2579 replies[i].resp = NULL;
2580 break;
2581
2582 case PAM_ERROR_MSG:
ef416fc2 2583 replies[i].resp_retcode = PAM_SUCCESS;
2584 replies[i].resp = NULL;
2585 break;
2586
2587 default:
ef416fc2 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}
ef416fc2 2601#endif /* HAVE_LIBPAM */