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