]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/auth.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / scheduler / auth.c
CommitLineData
b423cd4c 1/*
5ec1fd3d 2 * Authorization routines for the CUPS scheduler.
ef416fc2 3 *
fa26ab95 4 * Copyright © 2007-2019 by Apple Inc.
3cd7b5e0 5 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
f7deaa1a 6 *
5ec1fd3d
MS
7 * This file contains Kerberos support code, copyright 2006 by
8 * Jelmer Vernooij.
ef416fc2 9 *
3cd7b5e0
MS
10 * Licensed under Apache License v2.0. See the file "LICENSE" for more
11 * information.
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
18#include "cupsd.h"
19#include <grp.h>
20#ifdef HAVE_SHADOW_H
21# include <shadow.h>
22#endif /* HAVE_SHADOW_H */
23#ifdef HAVE_CRYPT_H
24# include <crypt.h>
25#endif /* HAVE_CRYPT_H */
26#if HAVE_LIBPAM
27# ifdef HAVE_PAM_PAM_APPL_H
28# include <pam/pam_appl.h>
29# else
30# include <security/pam_appl.h>
31# endif /* HAVE_PAM_PAM_APPL_H */
32#endif /* HAVE_LIBPAM */
bd7854cb 33#ifdef HAVE_MEMBERSHIP_H
34# include <membership.h>
35#endif /* HAVE_MEMBERSHIP_H */
f7deaa1a 36#ifdef HAVE_AUTHORIZATION_H
37# include <Security/AuthorizationTags.h>
f7deaa1a 38#endif /* HAVE_AUTHORIZATION_H */
db1f069b
MS
39#ifdef HAVE_SYS_PARAM_H
40# include <sys/param.h>
41#endif /* HAVE_SYS_PARAM_H */
bc44d920 42#ifdef HAVE_SYS_UCRED_H
43# include <sys/ucred.h>
44typedef struct xucred cupsd_ucred_t;
45# define CUPSD_UCRED_UID(c) (c).cr_uid
46#else
5a9febac 47# ifndef __OpenBSD__
bc44d920 48typedef struct ucred cupsd_ucred_t;
5a9febac
MS
49# else
50typedef struct sockpeercred cupsd_ucred_t;
51# endif
bc44d920 52# define CUPSD_UCRED_UID(c) (c).uid
53#endif /* HAVE_SYS_UCRED_H */
ef416fc2 54
55
56/*
57 * Local functions...
58 */
59
f7deaa1a 60#ifdef HAVE_AUTHORIZATION_H
61static int check_authref(cupsd_client_t *con, const char *right);
62#endif /* HAVE_AUTHORIZATION_H */
bd7854cb 63static int compare_locations(cupsd_location_t *a,
64 cupsd_location_t *b);
10d09e33 65static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data);
10d09e33 66static void free_authmask(cupsd_authmask_t *am, void *data);
ef416fc2 67#if HAVE_LIBPAM
68static int pam_func(int, const struct pam_message **,
69 struct pam_response **, void *);
ef416fc2 70#endif /* HAVE_LIBPAM */
71
72
73/*
74 * Local structures...
75 */
76
77#if HAVE_LIBPAM
78typedef struct cupsd_authdata_s /**** Authentication data ****/
79{
3e7fe0ca
MS
80 char username[HTTP_MAX_VALUE], /* Username string */
81 password[HTTP_MAX_VALUE]; /* Password string */
ef416fc2 82} cupsd_authdata_t;
83#endif /* HAVE_LIBPAM */
84
85
ef416fc2 86/*
10d09e33 87 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
ef416fc2 88 */
89
10d09e33
MS
90int /* O - 1 on success, 0 on failure */
91cupsdAddIPMask(
92 cups_array_t **masks, /* IO - Masks array (created as needed) */
93 const unsigned address[4], /* I - IP address */
94 const unsigned netmask[4]) /* I - IP netmask */
ef416fc2 95{
10d09e33 96 cupsd_authmask_t temp; /* New host/domain mask */
ef416fc2 97
98
ffe32673 99 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", masks, *masks, address[0], address[1], address[2], address[3], netmask[0], netmask[1], netmask[2], netmask[3]);
ef416fc2 100
10d09e33
MS
101 temp.type = CUPSD_AUTH_IP;
102 memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address));
103 memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask));
ef416fc2 104
bd7854cb 105 /*
10d09e33 106 * Create the masks array as needed and add...
bd7854cb 107 */
108
10d09e33
MS
109 if (!*masks)
110 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
111 (cups_acopy_func_t)copy_authmask,
112 (cups_afree_func_t)free_authmask);
ef416fc2 113
10d09e33
MS
114 return (cupsArrayAdd(*masks, &temp));
115}
ef416fc2 116
bd7854cb 117
10d09e33
MS
118/*
119 * 'cupsdAddLocation()' - Add a location for authorization.
120 */
ef416fc2 121
10d09e33
MS
122void
123cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */
124{
ef416fc2 125 /*
10d09e33 126 * Make sure the locations array is created...
ef416fc2 127 */
128
10d09e33
MS
129 if (!Locations)
130 Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL,
131 (cups_ahash_func_t)NULL, 0,
132 (cups_acopy_func_t)NULL,
133 (cups_afree_func_t)cupsdFreeLocation);
134
135 if (Locations)
136 {
137 cupsArrayAdd(Locations, loc);
138
ffe32673 139 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"", loc->location ? loc->location : "(null)");
10d09e33 140 }
ef416fc2 141}
142
143
144/*
145 * 'cupsdAddName()' - Add a name to a location...
146 */
147
148void
149cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
150 char *name) /* I - Name to add */
151{
ffe32673 152 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", loc, name);
ef416fc2 153
10d09e33
MS
154 if (!loc->names)
155 loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
156 (cups_acopy_func_t)_cupsStrAlloc,
157 (cups_afree_func_t)_cupsStrFree);
ef416fc2 158
10d09e33 159 if (!cupsArrayAdd(loc->names, name))
ef416fc2 160 {
161 cupsdLogMessage(CUPSD_LOG_ERROR,
162 "Unable to duplicate name for location %s: %s",
e1d6a774 163 loc->location ? loc->location : "nil", strerror(errno));
ef416fc2 164 return;
165 }
ef416fc2 166}
167
168
169/*
10d09e33 170 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
ef416fc2 171 */
172
10d09e33
MS
173int /* O - 1 on success, 0 on failure */
174cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
175 char *name) /* I - Host or interface name */
ef416fc2 176{
10d09e33 177 cupsd_authmask_t temp; /* New host/domain mask */
ef416fc2 178 char ifname[32], /* Interface name */
179 *ifptr; /* Pointer to end of name */
180
181
ffe32673 182 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks, *masks, name);
ef416fc2 183
88f9aafc 184 if (!_cups_strcasecmp(name, "@LOCAL"))
ef416fc2 185 {
186 /*
10d09e33 187 * Deny *interface*...
ef416fc2 188 */
189
10d09e33
MS
190 temp.type = CUPSD_AUTH_INTERFACE;
191 temp.mask.name.name = (char *)"*";
ef416fc2 192 }
88f9aafc 193 else if (!_cups_strncasecmp(name, "@IF(", 4))
ef416fc2 194 {
195 /*
10d09e33 196 * Deny *interface*...
ef416fc2 197 */
198
199 strlcpy(ifname, name + 4, sizeof(ifname));
200
10d09e33 201 ifptr = ifname + strlen(ifname) - 1;
ef416fc2 202
10d09e33 203 if (ifptr >= ifname && *ifptr == ')')
ef416fc2 204 {
ef416fc2 205 *ifptr = '\0';
206 }
207
10d09e33
MS
208 temp.type = CUPSD_AUTH_INTERFACE;
209 temp.mask.name.name = ifname;
ef416fc2 210 }
211 else
212 {
213 /*
10d09e33 214 * Deny name...
ef416fc2 215 */
216
10d09e33
MS
217 if (*name == '*')
218 name ++;
ef416fc2 219
10d09e33
MS
220 temp.type = CUPSD_AUTH_NAME;
221 temp.mask.name.name = (char *)name;
222 }
ef416fc2 223
10d09e33
MS
224 /*
225 * Set the name length...
226 */
ef416fc2 227
10d09e33 228 temp.mask.name.length = strlen(temp.mask.name.name);
ef416fc2 229
10d09e33
MS
230 /*
231 * Create the masks array as needed and add...
232 */
ef416fc2 233
10d09e33
MS
234 if (!*masks)
235 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
236 (cups_acopy_func_t)copy_authmask,
237 (cups_afree_func_t)free_authmask);
ef416fc2 238
10d09e33 239 return (cupsArrayAdd(*masks, &temp));
ef416fc2 240}
241
242
243/*
244 * 'cupsdAuthorize()' - Validate any authorization credentials.
245 */
246
247void
248cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
249{
250 int type; /* Authentication type */
f7deaa1a 251 const char *authorization; /* Pointer into Authorization string */
252 char *ptr, /* Pointer into string */
3e7fe0ca
MS
253 username[HTTP_MAX_VALUE],
254 /* Username string */
255 password[HTTP_MAX_VALUE];
256 /* Password string */
db0bd74a 257 cupsd_cert_t *localuser; /* Certificate username */
ef416fc2 258
259
260 /*
261 * Locate the best matching location so we know what kind of
262 * authentication to expect...
263 */
264
996acce8 265 con->best = cupsdFindBest(con->uri, httpGetState(con->http));
5bd77a73 266 con->type = CUPSD_AUTH_NONE;
ef416fc2 267
ffe32673 268 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location : "");
ef416fc2 269
5bd77a73 270 if (con->best && con->best->type != CUPSD_AUTH_NONE)
7ff4fea9 271 {
5bd77a73 272 if (con->best->type == CUPSD_AUTH_DEFAULT)
dcb445bc 273 type = cupsdDefaultAuthType();
7ff4fea9
MS
274 else
275 type = con->best->type;
276 }
ef416fc2 277 else
dcb445bc 278 type = cupsdDefaultAuthType();
ef416fc2 279
280 /*
281 * Decode the Authorization string...
282 */
283
996acce8 284 authorization = httpGetField(con->http, HTTP_FIELD_AUTHORIZATION);
ef416fc2 285
ef416fc2 286 username[0] = '\0';
287 password[0] = '\0';
288
07ed0e9a
MS
289#ifdef HAVE_GSSAPI
290 con->gss_uid = 0;
291#endif /* HAVE_GSSAPI */
292
f7deaa1a 293#ifdef HAVE_AUTHORIZATION_H
294 if (con->authref)
295 {
296 AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
297 con->authref = NULL;
298 }
299#endif /* HAVE_AUTHORIZATION_H */
300
2fb76298 301 if (!*authorization)
ef416fc2 302 {
303 /*
304 * No authorization data provided, return early...
305 */
306
ffe32673 307 cupsdLogClient(con, CUPSD_LOG_DEBUG, "No authentication data provided.");
ef416fc2 308 return;
309 }
f7deaa1a 310#ifdef HAVE_AUTHORIZATION_H
c8fef167 311 else if (!strncmp(authorization, "AuthRef ", 8) &&
5ec1fd3d 312 httpAddrLocalhost(httpGetAddress(con->http)))
f7deaa1a 313 {
314 OSStatus status; /* Status */
e0660879
MS
315 char authdata[HTTP_MAX_VALUE];
316 /* Nonce value from client */
f7deaa1a 317 int authlen; /* Auth string length */
318 AuthorizationItemSet *authinfo; /* Authorization item set */
319
320 /*
321 * Get the Authorization Services data...
322 */
323
c8fef167 324 authorization += 8;
f7deaa1a 325 while (isspace(*authorization & 255))
326 authorization ++;
327
e0660879
MS
328 authlen = sizeof(authdata);
329 httpDecode64_2(authdata, &authlen, authorization);
f7deaa1a 330
331 if (authlen != kAuthorizationExternalFormLength)
332 {
ffe32673 333 cupsdLogClient(con, CUPSD_LOG_ERROR, "External Authorization reference size is incorrect.");
f7deaa1a 334 return;
335 }
336
e0660879 337 if ((status = AuthorizationCreateFromExternalForm((AuthorizationExternalForm *)authdata, &con->authref)) != 0)
f7deaa1a 338 {
fa26ab95 339 cupsdLogClient(con, CUPSD_LOG_ERROR, "AuthorizationCreateFromExternalForm returned %d", (int)status);
f7deaa1a 340 return;
341 }
342
c8fef167 343 username[0] = '\0';
ed6e7faf 344
c8fef167 345 if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
bf3816c7 346 &authinfo))
e4572d57 347 {
ed6e7faf
MS
348 if (authinfo->count == 1 && authinfo->items[0].value &&
349 authinfo->items[0].valueLength >= 2)
c8fef167 350 {
ed6e7faf
MS
351 strlcpy(username, authinfo->items[0].value, sizeof(username));
352
ffe32673 353 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef.", username);
c8fef167
MS
354 }
355
e4572d57 356 AuthorizationFreeItemSet(authinfo);
e4572d57 357 }
355e94dc 358
c8fef167
MS
359 if (!username[0])
360 {
361 /*
362 * No username in AuthRef, grab username using peer credentials...
363 */
364
365 struct passwd *pwd; /* Password entry for this user */
366 cupsd_ucred_t peercred; /* Peer credentials */
367 socklen_t peersize; /* Size of peer credentials */
368
369 peersize = sizeof(peercred);
370
996acce8 371 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
c8fef167 372 {
ffe32673 373 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
c8fef167
MS
374 return;
375 }
376
377 if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
378 {
ffe32673 379 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred));
c8fef167
MS
380 return;
381 }
382
383 strlcpy(username, pwd->pw_name, sizeof(username));
384
ffe32673 385 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef + PeerCred.", username);
c8fef167
MS
386 }
387
5bd77a73 388 con->type = CUPSD_AUTH_BASIC;
f7deaa1a 389 }
390#endif /* HAVE_AUTHORIZATION_H */
bc44d920 391#if defined(SO_PEERCRED) && defined(AF_LOCAL)
392 else if (!strncmp(authorization, "PeerCred ", 9) &&
0d40cb1e 393 con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best)
bc44d920 394 {
395 /*
396 * Use peer credentials from domain socket connection...
397 */
398
399 struct passwd *pwd; /* Password entry for this user */
400 cupsd_ucred_t peercred; /* Peer credentials */
401 socklen_t peersize; /* Size of peer credentials */
f14324a7
MS
402#ifdef HAVE_AUTHORIZATION_H
403 const char *name; /* Authorizing name */
6961465f
MS
404 int no_peer = 0; /* Don't allow peer credentials? */
405
406 /*
407 * See if we should allow peer credentials...
408 */
bc44d920 409
f14324a7
MS
410 for (name = (char *)cupsArrayFirst(con->best->names);
411 name;
412 name = (char *)cupsArrayNext(con->best->names))
6961465f 413 {
dcb445bc
MS
414 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) ||
415 !_cups_strcasecmp(name, "@SYSTEM"))
f14324a7 416 {
6961465f
MS
417 /* Normally don't want peer credentials if we need an auth key... */
418 no_peer = 1;
419 }
420 else if (!_cups_strcasecmp(name, "@OWNER"))
421 {
422 /* but if @OWNER is present then we allow it... */
423 no_peer = 0;
424 break;
f14324a7 425 }
6961465f
MS
426 }
427
428 if (no_peer)
429 {
ffe32673 430 cupsdLogClient(con, CUPSD_LOG_ERROR, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
6961465f
MS
431 return;
432 }
f14324a7 433#endif /* HAVE_AUTHORIZATION_H */
bc44d920 434
435 if ((pwd = getpwnam(authorization + 9)) == NULL)
436 {
ffe32673 437 cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9);
bc44d920 438 return;
439 }
440
441 peersize = sizeof(peercred);
442
f11a948a 443# ifdef __APPLE__
996acce8 444 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
f11a948a 445# else
996acce8 446 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
f11a948a 447# endif /* __APPLE__ */
bc44d920 448 {
ffe32673 449 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
bc44d920 450 return;
451 }
452
453 if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
454 {
ffe32673 455 cupsdLogClient(con, CUPSD_LOG_ERROR, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization + 9, CUPSD_UCRED_UID(peercred), pwd->pw_uid);
bc44d920 456# ifdef HAVE_SYS_UCRED_H
ffe32673
MS
457 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_version=%d", peercred.cr_version);
458 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_uid=%d", peercred.cr_uid);
459 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_ngroups=%d", peercred.cr_ngroups);
460 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_groups[0]=%d", peercred.cr_groups[0]);
bc44d920 461# endif /* HAVE_SYS_UCRED_H */
462 return;
463 }
464
465 strlcpy(username, authorization + 9, sizeof(username));
355e94dc 466
eac3a0a0
MS
467# ifdef HAVE_GSSAPI
468 con->gss_uid = CUPSD_UCRED_UID(peercred);
469# endif /* HAVE_GSSAPI */
470
ffe32673 471 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using PeerCred.", username);
2fb76298 472
5bd77a73 473 con->type = CUPSD_AUTH_BASIC;
bc44d920 474 }
475#endif /* SO_PEERCRED && AF_LOCAL */
ef416fc2 476 else if (!strncmp(authorization, "Local", 5) &&
5ec1fd3d 477 httpAddrLocalhost(httpGetAddress(con->http)))
ef416fc2 478 {
479 /*
480 * Get Local certificate authentication data...
481 */
482
483 authorization += 5;
80ca4592 484 while (isspace(*authorization & 255))
ef416fc2 485 authorization ++;
486
0fa6c7fa 487 if ((localuser = cupsdFindCert(authorization)) == NULL)
ef416fc2 488 {
ffe32673 489 cupsdLogClient(con, CUPSD_LOG_ERROR, "Local authentication certificate not found.");
ef416fc2 490 return;
491 }
2fb76298 492
0fa6c7fa
MS
493 strlcpy(username, localuser->username, sizeof(username));
494 con->type = localuser->type;
495
ffe32673 496 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using Local.", username);
ef416fc2 497 }
2fb76298 498 else if (!strncmp(authorization, "Basic", 5))
ef416fc2 499 {
500 /*
501 * Get the Basic authentication data...
502 */
503
504 int userlen; /* Username:password length */
505
506
507 authorization += 5;
80ca4592 508 while (isspace(*authorization & 255))
ef416fc2 509 authorization ++;
510
511 userlen = sizeof(username);
512 httpDecode64_2(username, &userlen, authorization);
513
514 /*
515 * Pull the username and password out...
516 */
517
518 if ((ptr = strchr(username, ':')) == NULL)
519 {
ffe32673 520 cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Basic password.");
ef416fc2 521 return;
522 }
523
524 *ptr++ = '\0';
525
526 if (!username[0])
527 {
528 /*
529 * Username must not be empty...
530 */
531
ffe32673 532 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic username.");
ef416fc2 533 return;
534 }
535
536 if (!*ptr)
537 {
538 /*
539 * Password must not be empty...
540 */
541
ffe32673 542 cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic password.");
ef416fc2 543 return;
544 }
545
546 strlcpy(password, ptr, sizeof(password));
547
548 /*
549 * Validate the username and password...
550 */
551
552 switch (type)
553 {
2fb76298 554 default :
5bd77a73 555 case CUPSD_AUTH_BASIC :
ef416fc2 556 {
557#if HAVE_LIBPAM
558 /*
559 * Only use PAM to do authentication. This supports MD5
560 * passwords, among other things...
561 */
562
563 pam_handle_t *pamh; /* PAM authentication handle */
564 int pamerr; /* PAM error code */
565 struct pam_conv pamdata;/* PAM conversation data */
566 cupsd_authdata_t data; /* Authentication data */
567
568
569 strlcpy(data.username, username, sizeof(data.username));
570 strlcpy(data.password, password, sizeof(data.password));
571
5a1d7a17 572# ifdef __sun
e1d6a774 573 pamdata.conv = (int (*)(int, struct pam_message **,
574 struct pam_response **,
575 void *))pam_func;
576# else
ef416fc2 577 pamdata.conv = pam_func;
5a1d7a17 578# endif /* __sun */
ef416fc2 579 pamdata.appdata_ptr = &data;
580
ef416fc2 581 pamerr = pam_start("cups", username, &pamdata, &pamh);
582 if (pamerr != PAM_SUCCESS)
583 {
ffe32673 584 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_start() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
ef416fc2 585 return;
586 }
587
ee571f26
MS
588# ifdef HAVE_PAM_SET_ITEM
589# ifdef PAM_RHOST
996acce8 590 pamerr = pam_set_item(pamh, PAM_RHOST, con->http->hostname);
a4924f6c 591 if (pamerr != PAM_SUCCESS)
ffe32673 592 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
ee571f26
MS
593# endif /* PAM_RHOST */
594
595# ifdef PAM_TTY
596 pamerr = pam_set_item(pamh, PAM_TTY, "cups");
597 if (pamerr != PAM_SUCCESS)
ffe32673 598 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
ee571f26
MS
599# endif /* PAM_TTY */
600# endif /* HAVE_PAM_SET_ITEM */
601
ef416fc2 602 pamerr = pam_authenticate(pamh, PAM_SILENT);
603 if (pamerr != PAM_SUCCESS)
604 {
ffe32673 605 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_authenticate() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
ef416fc2 606 pam_end(pamh, 0);
607 return;
608 }
609
94da7e34
MS
610# ifdef HAVE_PAM_SETCRED
611 pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
612 if (pamerr != PAM_SUCCESS)
ffe32673 613 cupsdLogClient(con, CUPSD_LOG_WARN, "pam_setcred() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
94da7e34
MS
614# endif /* HAVE_PAM_SETCRED */
615
ef416fc2 616 pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
617 if (pamerr != PAM_SUCCESS)
618 {
ffe32673 619 cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_acct_mgmt() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
ef416fc2 620 pam_end(pamh, 0);
621 return;
622 }
623
624 pam_end(pamh, PAM_SUCCESS);
625
ef416fc2 626#else
627 /*
628 * Use normal UNIX password file-based authentication...
629 */
630
631 char *pass; /* Encrypted password */
632 struct passwd *pw; /* User password data */
633# ifdef HAVE_SHADOW_H
634 struct spwd *spw; /* Shadow password data */
635# endif /* HAVE_SHADOW_H */
636
637
638 pw = getpwnam(username); /* Get the current password */
639 endpwent(); /* Close the password file */
640
641 if (!pw)
642 {
643 /*
644 * No such user...
645 */
646
ffe32673 647 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unknown username \"%s\".", username);
80ca4592 648 return;
ef416fc2 649 }
650
651# ifdef HAVE_SHADOW_H
652 spw = getspnam(username);
653 endspent();
654
655 if (!spw && !strcmp(pw->pw_passwd, "x"))
656 {
657 /*
658 * Don't allow blank passwords!
659 */
660
ffe32673 661 cupsdLogClient(con, CUPSD_LOG_ERROR, "Username \"%s\" has no shadow password.", username);
ef416fc2 662 return;
663 }
664
665 if (spw && !spw->sp_pwdp[0] && !pw->pw_passwd[0])
666# else
667 if (!pw->pw_passwd[0])
668# endif /* HAVE_SHADOW_H */
669 {
670 /*
671 * Don't allow blank passwords!
672 */
673
ffe32673 674 cupsdLogClient(con, CUPSD_LOG_ERROR, "Username \"%s\" has no password.", username);
ef416fc2 675 return;
676 }
677
678 /*
679 * OK, the password isn't blank, so compare with what came from the
680 * client...
681 */
682
3cd7b5e0 683 pass = crypt(password, pw->pw_passwd);
ef416fc2 684
ef416fc2 685 if (!pass || strcmp(pw->pw_passwd, pass))
686 {
687# ifdef HAVE_SHADOW_H
688 if (spw)
689 {
3cd7b5e0 690 pass = crypt(password, spw->sp_pwdp);
ef416fc2 691
ef416fc2 692 if (pass == NULL || strcmp(spw->sp_pwdp, pass))
693 {
ffe32673 694 cupsdLogClient(con, CUPSD_LOG_ERROR, "Authentication failed for user \"%s\".", username);
ef416fc2 695 return;
696 }
697 }
698 else
699# endif /* HAVE_SHADOW_H */
700 {
ffe32673 701 cupsdLogClient(con, CUPSD_LOG_ERROR, "Authentication failed for user \"%s\".", username);
ef416fc2 702 return;
703 }
704 }
705#endif /* HAVE_LIBPAM */
706 }
355e94dc 707
ffe32673 708 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Basic.", username);
ef416fc2 709 break;
ef416fc2 710 }
2fb76298
MS
711
712 con->type = type;
ef416fc2 713 }
f7deaa1a 714#ifdef HAVE_GSSAPI
c8fef167 715 else if (!strncmp(authorization, "Negotiate", 9))
f7deaa1a 716 {
717 int len; /* Length of authorization string */
f7deaa1a 718 gss_ctx_id_t context; /* Authorization context */
719 OM_uint32 major_status, /* Major status code */
720 minor_status; /* Minor status code */
721 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER,
722 /* Input token from string */
723 output_token = GSS_C_EMPTY_BUFFER;
724 /* Output token for username */
725 gss_name_t client_name; /* Client name */
726
727
f42414bf 728# ifdef __APPLE__
729 /*
730 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
731 * to use it...
732 */
733
d2ff4622 734 if (&gss_init_sec_context == NULL)
f42414bf 735 {
ffe32673 736 cupsdLogClient(con, CUPSD_LOG_WARN, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
f42414bf 737 return;
738 }
739# endif /* __APPLE__ */
740
f7deaa1a 741 /*
742 * Find the start of the Kerberos input token...
743 */
744
745 authorization += 9;
746 while (isspace(*authorization & 255))
747 authorization ++;
748
749 if (!*authorization)
750 {
ffe32673 751 cupsdLogClient(con, CUPSD_LOG_DEBUG2, "No authentication data specified.");
f7deaa1a 752 return;
753 }
754
f7deaa1a 755 /*
756 * Decode the authorization string to get the input token...
757 */
758
b31d4ca5 759 len = (int)strlen(authorization) + 0;
7e86f2f6 760 input_token.value = malloc((size_t)len);
f7deaa1a 761 input_token.value = httpDecode64_2(input_token.value, &len,
c7017ecc 762 authorization);
7e86f2f6 763 input_token.length = (size_t)len;
f7deaa1a 764
765 /*
766 * Accept the input token to get the authorization info...
767 */
768
769 context = GSS_C_NO_CONTEXT;
770 client_name = GSS_C_NO_NAME;
771 major_status = gss_accept_sec_context(&minor_status,
772 &context,
dcb445bc 773 ServerCreds,
f7deaa1a 774 &input_token,
775 GSS_C_NO_CHANNEL_BINDINGS,
776 &client_name,
777 NULL,
07ed0e9a
MS
778 &output_token,
779 NULL,
f7deaa1a 780 NULL,
07ed0e9a
MS
781 NULL);
782
783 if (output_token.length > 0)
784 gss_release_buffer(&minor_status, &output_token);
f7deaa1a 785
786 if (GSS_ERROR(major_status))
787 {
ffe32673 788 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error accepting GSSAPI security context.", con->number);
f7deaa1a 789
790 if (context != GSS_C_NO_CONTEXT)
791 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 792 return;
793 }
794
97c9a8d7
MS
795 con->have_gss = 1;
796
76cd9e37
MS
797 /*
798 * Get the username associated with the client's credentials...
f7deaa1a 799 */
800
355e94dc 801 if (major_status == GSS_S_CONTINUE_NEEDED)
ffe32673 802 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Credentials not complete.", con->number);
355e94dc 803 else if (major_status == GSS_S_COMPLETE)
f7deaa1a 804 {
c8fef167 805 major_status = gss_display_name(&minor_status, client_name,
f7deaa1a 806 &output_token, NULL);
807
808 if (GSS_ERROR(major_status))
809 {
ffe32673 810 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error getting username.", con->number);
f7deaa1a 811 gss_release_name(&minor_status, &client_name);
812 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 813 return;
814 }
815
f7deaa1a 816 strlcpy(username, output_token.value, sizeof(username));
355e94dc 817
ffe32673 818 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Negotiate.", username);
f7deaa1a 819
e07d4801 820 gss_release_name(&minor_status, &client_name);
f7deaa1a 821 gss_release_buffer(&minor_status, &output_token);
2fb76298 822
5bd77a73 823 con->type = CUPSD_AUTH_NEGOTIATE;
f7deaa1a 824 }
e07d4801
MS
825
826 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
07ed0e9a
MS
827
828# if defined(SO_PEERCRED) && defined(AF_LOCAL)
829 /*
830 * Get the client's UID if we are printing locally - that allows a backend
831 * to run as the correct user to get Kerberos credentials of its own.
832 */
833
5ec1fd3d 834 if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL)
07ed0e9a
MS
835 {
836 cupsd_ucred_t peercred; /* Peer credentials */
837 socklen_t peersize; /* Size of peer credentials */
838
839 peersize = sizeof(peercred);
840
841# ifdef __APPLE__
996acce8 842 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
07ed0e9a 843# else
996acce8 844 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred,
07ed0e9a
MS
845 &peersize))
846# endif /* __APPLE__ */
847 {
ffe32673 848 cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
07ed0e9a
MS
849 }
850 else
851 {
ffe32673 852 cupsdLogClient(con, CUPSD_LOG_DEBUG, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred));
07ed0e9a
MS
853 con->gss_uid = CUPSD_UCRED_UID(peercred);
854 }
855 }
856# endif /* SO_PEERCRED && AF_LOCAL */
f7deaa1a 857 }
858#endif /* HAVE_GSSAPI */
2fb76298 859 else
ef416fc2 860 {
355e94dc 861 char scheme[256]; /* Auth scheme... */
355e94dc
MS
862
863
864 if (sscanf(authorization, "%255s", scheme) != 1)
5a9febac 865 strlcpy(scheme, "UNKNOWN", sizeof(scheme));
355e94dc 866
ffe32673 867 cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\".", scheme);
ef416fc2 868 return;
869 }
870
871 /*
872 * If we get here, then we were able to validate the username and
873 * password - copy the validated username and password to the client
874 * data and return...
875 */
876
877 strlcpy(con->username, username, sizeof(con->username));
878 strlcpy(con->password, password, sizeof(con->password));
ef416fc2 879}
880
881
080811b1
MS
882/*
883 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
884 * access a location.
885 */
886
887int /* O - 1 if allowed, 0 otherwise */
888cupsdCheckAccess(
889 unsigned ip[4], /* I - Client address */
5ec1fd3d 890 const char *name, /* I - Client hostname */
7e86f2f6 891 size_t namelen, /* I - Length of hostname */
080811b1
MS
892 cupsd_location_t *loc) /* I - Location to check */
893{
894 int allow; /* 1 if allowed, 0 otherwise */
895
896
88f9aafc 897 if (!_cups_strcasecmp(name, "localhost"))
080811b1
MS
898 {
899 /*
900 * Access from localhost (127.0.0.1 or ::1) is always allowed...
901 */
902
903 return (1);
904 }
905 else
906 {
907 /*
908 * Do authorization checks on the domain/address...
909 */
910
911 switch (loc->order_type)
912 {
913 default :
914 allow = 0; /* anti-compiler-warning-code */
915 break;
916
5bd77a73 917 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
080811b1
MS
918 allow = 1;
919
10d09e33 920 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
080811b1
MS
921 allow = 0;
922
10d09e33 923 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
080811b1
MS
924 allow = 1;
925 break;
926
5bd77a73 927 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
080811b1
MS
928 allow = 0;
929
10d09e33 930 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
080811b1
MS
931 allow = 1;
932
10d09e33 933 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
080811b1
MS
934 allow = 0;
935 break;
936 }
937 }
938
939 return (allow);
940}
941
942
ef416fc2 943/*
944 * 'cupsdCheckAuth()' - Check authorization masks.
945 */
946
947int /* O - 1 if mask matches, 0 otherwise */
10d09e33 948cupsdCheckAuth(unsigned ip[4], /* I - Client address */
5ec1fd3d 949 const char *name, /* I - Client hostname */
7e86f2f6 950 size_t name_len, /* I - Length of hostname */
10d09e33 951 cups_array_t *masks) /* I - Masks */
ef416fc2 952{
10d09e33
MS
953 int i; /* Looping var */
954 cupsd_authmask_t *mask; /* Current mask */
955 cupsd_netif_t *iface; /* Network interface */
956 unsigned netip4; /* IPv4 network address */
ef416fc2 957#ifdef AF_INET6
10d09e33 958 unsigned netip6[4]; /* IPv6 network address */
ef416fc2 959#endif /* AF_INET6 */
960
e07d4801 961
10d09e33
MS
962 for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
963 mask;
964 mask = (cupsd_authmask_t *)cupsArrayNext(masks))
ef416fc2 965 {
10d09e33 966 switch (mask->type)
ef416fc2 967 {
5bd77a73 968 case CUPSD_AUTH_INTERFACE :
ef416fc2 969 /*
970 * Check for a match with a network interface...
971 */
972
973 netip4 = htonl(ip[3]);
974
975#ifdef AF_INET6
976 netip6[0] = htonl(ip[0]);
977 netip6[1] = htonl(ip[1]);
978 netip6[2] = htonl(ip[2]);
979 netip6[3] = htonl(ip[3]);
980#endif /* AF_INET6 */
981
84ec3a84
MS
982 cupsdNetIFUpdate();
983
10d09e33 984 if (!strcmp(mask->mask.name.name, "*"))
ef416fc2 985 {
e07d4801
MS
986#ifdef __APPLE__
987 /*
988 * Allow Back-to-My-Mac addresses...
989 */
990
991 if ((ip[0] & 0xff000000) == 0xfd000000)
992 return (1);
993#endif /* __APPLE__ */
994
ef416fc2 995 /*
996 * Check against all local interfaces...
997 */
998
e00b005a 999 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1000 iface;
1001 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 1002 {
1003 /*
1004 * Only check local interfaces...
1005 */
1006
1007 if (!iface->is_local)
1008 continue;
1009
1010 if (iface->address.addr.sa_family == AF_INET)
1011 {
1012 /*
1013 * Check IPv4 address...
1014 */
1015
1016 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1017 (iface->address.ipv4.sin_addr.s_addr &
1018 iface->mask.ipv4.sin_addr.s_addr))
1019 return (1);
1020 }
1021#ifdef AF_INET6
1022 else
1023 {
1024 /*
1025 * Check IPv6 address...
1026 */
1027
1028 for (i = 0; i < 4; i ++)
1029 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1030 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1031 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1032 break;
1033
1034 if (i == 4)
1035 return (1);
1036 }
1037#endif /* AF_INET6 */
1038 }
1039 }
1040 else
1041 {
1042 /*
1043 * Check the named interface...
1044 */
1045
e00b005a 1046 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
ed486911 1047 iface;
e00b005a 1048 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 1049 {
10d09e33 1050 if (strcmp(mask->mask.name.name, iface->name))
ed486911 1051 continue;
1052
ef416fc2 1053 if (iface->address.addr.sa_family == AF_INET)
1054 {
1055 /*
1056 * Check IPv4 address...
1057 */
1058
1059 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1060 (iface->address.ipv4.sin_addr.s_addr &
1061 iface->mask.ipv4.sin_addr.s_addr))
1062 return (1);
1063 }
1064#ifdef AF_INET6
1065 else
1066 {
1067 /*
1068 * Check IPv6 address...
1069 */
1070
1071 for (i = 0; i < 4; i ++)
1072 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1073 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1074 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1075 break;
1076
1077 if (i == 4)
1078 return (1);
1079 }
1080#endif /* AF_INET6 */
1081 }
1082 }
1083 break;
1084
5bd77a73 1085 case CUPSD_AUTH_NAME :
ef416fc2 1086 /*
1087 * Check for exact name match...
1088 */
1089
88f9aafc 1090 if (!_cups_strcasecmp(name, mask->mask.name.name))
ef416fc2 1091 return (1);
1092
1093 /*
1094 * Check for domain match...
1095 */
1096
10d09e33
MS
1097 if (name_len >= mask->mask.name.length &&
1098 mask->mask.name.name[0] == '.' &&
88f9aafc 1099 !_cups_strcasecmp(name + name_len - mask->mask.name.length,
10d09e33 1100 mask->mask.name.name))
ef416fc2 1101 return (1);
1102 break;
1103
5bd77a73 1104 case CUPSD_AUTH_IP :
ef416fc2 1105 /*
1106 * Check for IP/network address match...
1107 */
1108
1109 for (i = 0; i < 4; i ++)
10d09e33
MS
1110 if ((ip[i] & mask->mask.ip.netmask[i]) !=
1111 mask->mask.ip.address[i])
ef416fc2 1112 break;
1113
1114 if (i == 4)
1115 return (1);
1116 break;
1117 }
ef416fc2 1118 }
1119
1120 return (0);
1121}
1122
1123
1124/*
1125 * 'cupsdCheckGroup()' - Check for a user's group membership.
1126 */
1127
1128int /* O - 1 if user is a member, 0 otherwise */
1129cupsdCheckGroup(
1130 const char *username, /* I - User name */
1131 struct passwd *user, /* I - System user info */
1132 const char *groupname) /* I - Group name */
1133{
8922323b 1134 int i; /* Looping var */
36374693
MS
1135 struct group *group; /* Group info */
1136 gid_t groupid; /* ID of named group */
bd7854cb 1137#ifdef HAVE_MBR_UID_TO_UUID
8922323b
MS
1138 uuid_t useruuid, /* UUID for username */
1139 groupuuid; /* UUID for groupname */
1140 int is_member; /* True if user is a member of group */
bd7854cb 1141#endif /* HAVE_MBR_UID_TO_UUID */
ef416fc2 1142
1143
ffe32673 1144 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, user, groupname);
ef416fc2 1145
1146 /*
1147 * Validate input...
1148 */
1149
1150 if (!username || !groupname)
1151 return (0);
1152
1153 /*
1154 * Check to see if the user is a member of the named group...
1155 */
1156
1157 group = getgrnam(groupname);
1158 endgrent();
1159
1160 if (group != NULL)
1161 {
1162 /*
1163 * Group exists, check it...
1164 */
1165
36374693
MS
1166 groupid = group->gr_gid;
1167
3c27d2a6
MS
1168 for (i = 0; group->gr_mem[i]; i ++)
1169 {
1170 /*
1171 * User appears in the group membership...
1172 */
1173
1174 if (!_cups_strcasecmp(username, group->gr_mem[i]))
1175 return (1);
1176 }
1177
6eb98aee 1178#ifdef HAVE_GETGROUPLIST
3c27d2a6
MS
1179 /*
1180 * If the user isn't in the group membership list, try the results from
1181 * getgrouplist() which is supposed to return the full list of groups a user
1182 * belongs to...
1183 */
1184
6eb98aee
MS
1185 if (user)
1186 {
f093225b 1187 int ngroups; /* Number of groups */
fdc3c81a
MS
1188# ifdef __APPLE__
1189 int groups[2048]; /* Groups that user belongs to */
1190# else
f093225b 1191 gid_t groups[2048]; /* Groups that user belongs to */
fdc3c81a 1192# endif /* __APPLE__ */
6eb98aee
MS
1193
1194 ngroups = (int)(sizeof(groups) / sizeof(groups[0]));
fdc3c81a
MS
1195# ifdef __APPLE__
1196 getgrouplist(username, (int)user->pw_gid, groups, &ngroups);
1197# else
f093225b 1198 getgrouplist(username, user->pw_gid, groups, &ngroups);
fdc3c81a 1199#endif /* __APPLE__ */
6eb98aee
MS
1200
1201 for (i = 0; i < ngroups; i ++)
36374693 1202 if ((int)groupid == (int)groups[i])
6eb98aee
MS
1203 return (1);
1204 }
36374693 1205#endif /* HAVE_GETGROUPLIST */
ef416fc2 1206 }
36374693
MS
1207 else
1208 groupid = (gid_t)-1;
ef416fc2 1209
1210 /*
1211 * Group doesn't exist or user not in group list, check the group ID
1212 * against the user's group ID...
1213 */
1214
36374693 1215 if (user && groupid == user->pw_gid)
ef416fc2 1216 return (1);
1217
bd7854cb 1218#ifdef HAVE_MBR_UID_TO_UUID
1219 /*
d4874933 1220 * Check group membership through macOS membership API...
bd7854cb 1221 */
1222
dd1abb6b 1223 if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
c9fc04c6 1224 {
36374693 1225 if (groupid != (gid_t)-1)
8922323b
MS
1226 {
1227 /*
1228 * Map group name to UUID and check membership...
1229 */
c9fc04c6 1230
36374693 1231 if (!mbr_gid_to_uuid(groupid, groupuuid))
8922323b
MS
1232 if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1233 if (is_member)
1234 return (1);
1235 }
1236 else if (groupname[0] == '#')
1237 {
1238 /*
1239 * Use UUID directly and check for equality (user UUID) and
1240 * membership (group UUID)...
1241 */
1242
1243 if (!uuid_parse((char *)groupname + 1, groupuuid))
1244 {
1245 if (!uuid_compare(useruuid, groupuuid))
c9fc04c6 1246 return (1);
8922323b
MS
1247 else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1248 if (is_member)
1249 return (1);
1250 }
1251
1252 return (0);
1253 }
1254 }
1255 else if (groupname[0] == '#')
1256 return (0);
bd7854cb 1257#endif /* HAVE_MBR_UID_TO_UUID */
1258
ef416fc2 1259 /*
1260 * If we get this far, then the user isn't part of the named group...
1261 */
1262
1263 return (0);
1264}
1265
1266
1267/*
1268 * 'cupsdCopyLocation()' - Make a copy of a location...
1269 */
1270
1271cupsd_location_t * /* O - New location */
1272cupsdCopyLocation(
10d09e33 1273 cupsd_location_t *loc) /* I - Original location */
ef416fc2 1274{
ef416fc2 1275 cupsd_location_t *temp; /* New location */
ef416fc2 1276
1277
ef416fc2 1278 /*
10d09e33 1279 * Make a copy of the original location...
ef416fc2 1280 */
1281
10d09e33 1282 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
ef416fc2 1283 return (NULL);
1284
ef416fc2 1285 /*
1286 * Copy the information from the original location to the new one.
1287 */
1288
10d09e33
MS
1289 if (!loc)
1290 return (temp);
ef416fc2 1291
10d09e33
MS
1292 if (loc->location)
1293 temp->location = _cupsStrAlloc(loc->location);
ef416fc2 1294
d2ff4622 1295 temp->length = loc->length;
10d09e33
MS
1296 temp->limit = loc->limit;
1297 temp->order_type = loc->order_type;
1298 temp->type = loc->type;
1299 temp->level = loc->level;
1300 temp->satisfy = loc->satisfy;
1301 temp->encryption = loc->encryption;
1302
1303 if (loc->names)
1304 {
1305 if ((temp->names = cupsArrayDup(loc->names)) == NULL)
ef416fc2 1306 {
1307 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1308 "Unable to allocate memory for %d names: %s",
1309 cupsArrayCount(loc->names), strerror(errno));
bd7854cb 1310
10d09e33 1311 cupsdFreeLocation(temp);
ef416fc2 1312 return (NULL);
1313 }
ef416fc2 1314 }
1315
10d09e33 1316 if (loc->allow)
ef416fc2 1317 {
1318 /*
1319 * Copy allow rules...
1320 */
1321
10d09e33 1322 if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
ef416fc2 1323 {
1324 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1325 "Unable to allocate memory for %d allow rules: %s",
1326 cupsArrayCount(loc->allow), strerror(errno));
1327 cupsdFreeLocation(temp);
ef416fc2 1328 return (NULL);
1329 }
ef416fc2 1330 }
1331
10d09e33 1332 if (loc->deny)
ef416fc2 1333 {
1334 /*
1335 * Copy deny rules...
1336 */
1337
10d09e33 1338 if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
ef416fc2 1339 {
1340 cupsdLogMessage(CUPSD_LOG_ERROR,
10d09e33
MS
1341 "Unable to allocate memory for %d deny rules: %s",
1342 cupsArrayCount(loc->deny), strerror(errno));
1343 cupsdFreeLocation(temp);
ef416fc2 1344 return (NULL);
1345 }
ef416fc2 1346 }
1347
1348 return (temp);
1349}
1350
1351
1352/*
1353 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1354 */
1355
1356void
1357cupsdDeleteAllLocations(void)
1358{
ef416fc2 1359 /*
10d09e33 1360 * Free the location array, which will free all of the locations...
ef416fc2 1361 */
1362
bd7854cb 1363 cupsArrayDelete(Locations);
1364 Locations = NULL;
ef416fc2 1365}
1366
1367
ef416fc2 1368/*
1369 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1370 */
1371
1372cupsd_location_t * /* O - Location that matches */
1373cupsdFindBest(const char *path, /* I - Resource path */
1374 http_state_t state) /* I - HTTP state/request */
1375{
ef416fc2 1376 char uri[HTTP_MAX_URI],
1377 /* URI in request... */
1378 *uriptr; /* Pointer into URI */
1379 cupsd_location_t *loc, /* Current location */
1380 *best; /* Best match for location so far */
7e86f2f6 1381 size_t bestlen; /* Length of best match */
ef416fc2 1382 int limit; /* Limit field */
5bd77a73 1383 static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
ef416fc2 1384 {
5bd77a73
MS
1385 CUPSD_AUTH_LIMIT_ALL,
1386 CUPSD_AUTH_LIMIT_OPTIONS,
1387 CUPSD_AUTH_LIMIT_GET,
1388 CUPSD_AUTH_LIMIT_GET,
1389 CUPSD_AUTH_LIMIT_HEAD,
1390 CUPSD_AUTH_LIMIT_POST,
1391 CUPSD_AUTH_LIMIT_POST,
1392 CUPSD_AUTH_LIMIT_POST,
1393 CUPSD_AUTH_LIMIT_PUT,
1394 CUPSD_AUTH_LIMIT_PUT,
1395 CUPSD_AUTH_LIMIT_DELETE,
1396 CUPSD_AUTH_LIMIT_TRACE,
1397 CUPSD_AUTH_LIMIT_ALL,
d2ff4622
MS
1398 CUPSD_AUTH_LIMIT_ALL,
1399 CUPSD_AUTH_LIMIT_ALL,
5bd77a73 1400 CUPSD_AUTH_LIMIT_ALL
ef416fc2 1401 };
1402
1403
1404 /*
1405 * First copy the connection URI to a local string so we have drop
1406 * any .ppd extension from the pathname in /printers or /classes
1407 * URIs...
1408 */
1409
1410 strlcpy(uri, path, sizeof(uri));
1411
c26ceab0
MS
1412 if ((uriptr = strchr(uri, '?')) != NULL)
1413 *uriptr = '\0'; /* Drop trailing query string */
1414
1415 if ((uriptr = uri + strlen(uri) - 1) > uri && *uriptr == '/')
1416 *uriptr = '\0'; /* Remove trailing '/' */
1417
ef416fc2 1418 if (!strncmp(uri, "/printers/", 10) ||
1419 !strncmp(uri, "/classes/", 9))
1420 {
1421 /*
1422 * Check if the URI has .ppd on the end...
1423 */
1424
1425 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
1426
1427 if (!strcmp(uriptr, ".ppd"))
1428 *uriptr = '\0';
1429 }
1430
ef416fc2 1431 /*
1432 * Loop through the list of locations to find a match...
1433 */
1434
1435 limit = limits[state];
1436 best = NULL;
1437 bestlen = 0;
1438
ffe32673 1439 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri=\"%s\", limit=%x...", uri, limit);
d2ff4622
MS
1440
1441
bd7854cb 1442 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1443 loc;
1444 loc = (cupsd_location_t *)cupsArrayNext(Locations))
ef416fc2 1445 {
d2ff4622 1446 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s(%d) Limit %x", loc->location ? loc->location : "(null)", (int)loc->length, loc->limit);
ef416fc2 1447
1448 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
1449 {
1450 /*
1451 * Use case-insensitive comparison for queue names...
1452 */
1453
e1d6a774 1454 if (loc->length > bestlen && loc->location &&
88f9aafc 1455 !_cups_strncasecmp(uri, loc->location, loc->length) &&
ef416fc2 1456 loc->location[0] == '/' &&
1457 (limit & loc->limit) != 0)
1458 {
1459 best = loc;
1460 bestlen = loc->length;
1461 }
1462 }
1463 else
1464 {
1465 /*
1466 * Use case-sensitive comparison for other URIs...
1467 */
1468
e1d6a774 1469 if (loc->length > bestlen && loc->location &&
ef416fc2 1470 !strncmp(uri, loc->location, loc->length) &&
1471 loc->location[0] == '/' &&
1472 (limit & loc->limit) != 0)
1473 {
1474 best = loc;
1475 bestlen = loc->length;
1476 }
1477 }
1478 }
1479
1480 /*
1481 * Return the match, if any...
1482 */
1483
ffe32673 1484 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best=%s", best ? best->location : "NONE");
ef416fc2 1485
1486 return (best);
1487}
1488
1489
1490/*
1491 * 'cupsdFindLocation()' - Find the named location.
1492 */
1493
1494cupsd_location_t * /* O - Location that matches */
1495cupsdFindLocation(const char *location) /* I - Connection */
1496{
bd7854cb 1497 cupsd_location_t key; /* Search key */
ef416fc2 1498
1499
bd7854cb 1500 key.location = (char *)location;
ef416fc2 1501
bd7854cb 1502 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
ef416fc2 1503}
1504
1505
10d09e33
MS
1506/*
1507 * 'cupsdFreeLocation()' - Free all memory used by a location.
1508 */
1509
1510void
1511cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */
1512{
1513 cupsArrayDelete(loc->names);
1514 cupsArrayDelete(loc->allow);
1515 cupsArrayDelete(loc->deny);
1516
1517 _cupsStrFree(loc->location);
1518 free(loc);
1519}
1520
1521
ef416fc2 1522/*
1523 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1524 */
1525
1526http_status_t /* O - HTTP_OK if authorized or error code */
1527cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
1528 const char *owner)/* I - Owner of object */
1529{
10d09e33 1530 int i, /* Looping vars */
2fb76298
MS
1531 auth, /* Authorization status */
1532 type; /* Type of authentication */
5ec1fd3d
MS
1533 http_addr_t *hostaddr = httpGetAddress(con->http);
1534 /* Client address */
1535 const char *hostname = httpGetHostname(con->http, NULL, 0);
1536 /* Client hostname */
ef416fc2 1537 unsigned address[4]; /* Authorization address */
1538 cupsd_location_t *best; /* Best match for location so far */
7e86f2f6 1539 size_t hostlen; /* Length of hostname */
10d09e33
MS
1540 char *name, /* Current username */
1541 username[256], /* Username to authorize */
db1f069b
MS
1542 ownername[256], /* Owner name to authorize */
1543 *ptr; /* Pointer into username */
ef416fc2 1544 struct passwd *pw; /* User password data */
1545 static const char * const levels[] = /* Auth levels */
1546 {
1547 "ANON",
1548 "USER",
1549 "GROUP"
1550 };
1551 static const char * const types[] = /* Auth types */
1552 {
2fb76298
MS
1553 "None",
1554 "Basic",
2fb76298 1555 "Negotiate"
ef416fc2 1556 };
1557
1558
ffe32673 1559 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location ? con->best->location : "(null)" : "");
fa73b229 1560 if (owner)
ffe32673 1561 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: owner=\"%s\"", owner);
ef416fc2 1562
1563 /*
1564 * If there is no "best" authentication rule for this request, then
1565 * access is allowed from the local system and denied from other
1566 * addresses...
1567 */
1568
1569 if (!con->best)
1570 {
5ec1fd3d
MS
1571 if (httpAddrLocalhost(httpGetAddress(con->http)) ||
1572 !strcmp(hostname, ServerName) ||
1573 cupsArrayFind(ServerAlias, (void *)hostname))
ef416fc2 1574 return (HTTP_OK);
1575 else
1576 return (HTTP_FORBIDDEN);
1577 }
1578
1579 best = con->best;
1580
5bd77a73 1581 if ((type = best->type) == CUPSD_AUTH_DEFAULT)
dcb445bc 1582 type = cupsdDefaultAuthType();
2fb76298 1583
ffe32673 1584 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));
ef416fc2 1585
5bd77a73 1586 if (best->limit == CUPSD_AUTH_LIMIT_IPP)
ffe32673 1587 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", best->op, ippOpString(best->op));
ef416fc2 1588
1589 /*
1590 * Check host/ip-based accesses...
1591 */
1592
1593#ifdef AF_INET6
5ec1fd3d 1594 if (httpAddrFamily(hostaddr) == AF_INET6)
ef416fc2 1595 {
1596 /*
1597 * Copy IPv6 address...
1598 */
1599
5ec1fd3d
MS
1600 address[0] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[0]);
1601 address[1] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[1]);
1602 address[2] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[2]);
1603 address[3] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[3]);
ef416fc2 1604 }
1605 else
1606#endif /* AF_INET6 */
996acce8 1607 if (con->http->hostaddr->addr.sa_family == AF_INET)
ef416fc2 1608 {
1609 /*
1610 * Copy IPv4 address...
1611 */
1612
1613 address[0] = 0;
1614 address[1] = 0;
1615 address[2] = 0;
5ec1fd3d 1616 address[3] = ntohl(hostaddr->ipv4.sin_addr.s_addr);
ef416fc2 1617 }
1618 else
1619 memset(address, 0, sizeof(address));
1620
5ec1fd3d 1621 hostlen = strlen(hostname);
ef416fc2 1622
5ec1fd3d 1623 auth = cupsdCheckAccess(address, hostname, hostlen, best)
5bd77a73 1624 ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
ef416fc2 1625
ffe32673 1626 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth ? "DENY" : "ALLOW");
ef416fc2 1627
5bd77a73 1628 if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
ef416fc2 1629 return (HTTP_FORBIDDEN);
1630
1631#ifdef HAVE_SSL
1632 /*
1633 * See if encryption is required...
1634 */
1635
996acce8 1636 if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http->tls &&
5ec1fd3d
MS
1637 _cups_strcasecmp(hostname, "localhost") &&
1638 !httpAddrLocalhost(hostaddr) &&
5bd77a73 1639 best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
c8fef167 1640 !(type == CUPSD_AUTH_NEGOTIATE ||
dcb445bc
MS
1641 (type == CUPSD_AUTH_NONE &&
1642 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE)))
ef416fc2 1643 {
355e94dc 1644 cupsdLogMessage(CUPSD_LOG_DEBUG,
ef416fc2 1645 "cupsdIsAuthorized: Need upgrade to TLS...");
1646 return (HTTP_UPGRADE_REQUIRED);
1647 }
1648#endif /* HAVE_SSL */
1649
1650 /*
1651 * Now see what access level is required...
1652 */
1653
5bd77a73 1654 if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
10d09e33 1655 (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
ef416fc2 1656 return (HTTP_OK);
1657
5bd77a73
MS
1658 if (!con->username[0] && type == CUPSD_AUTH_NONE &&
1659 best->limit == CUPSD_AUTH_LIMIT_IPP)
ef416fc2 1660 {
1661 /*
1662 * Check for unauthenticated username...
1663 */
1664
1665 ipp_attribute_t *attr; /* requesting-user-name attribute */
1666
1667
1668 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1669 if (attr)
1670 {
355e94dc 1671 cupsdLogMessage(CUPSD_LOG_DEBUG,
ef416fc2 1672 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1673 attr->values[0].string.text);
db1f069b 1674 strlcpy(username, attr->values[0].string.text, sizeof(username));
ef416fc2 1675 }
5bd77a73 1676 else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
ef416fc2 1677 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1678 else
1679 return (HTTP_OK); /* unless overridden with Satisfy */
1680 }
fa73b229 1681 else
1682 {
355e94dc 1683 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
fa73b229 1684 con->username);
1685
f7deaa1a 1686#ifdef HAVE_AUTHORIZATION_H
1687 if (!con->username[0] && !con->authref)
1688#else
fa73b229 1689 if (!con->username[0])
f7deaa1a 1690#endif /* HAVE_AUTHORIZATION_H */
fa73b229 1691 {
5bd77a73 1692 if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
fa73b229 1693 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1694 else
1695 return (HTTP_OK); /* unless overridden with Satisfy */
1696 }
1697
eac3a0a0 1698
5bd77a73 1699 if (con->type != type && type != CUPSD_AUTH_NONE &&
eac3a0a0
MS
1700#ifdef HAVE_GSSAPI
1701 (type != CUPSD_AUTH_NEGOTIATE || con->gss_uid <= 0) &&
1702#endif /* HAVE_GSSAPI */
e0660879 1703 con->type != CUPSD_AUTH_BASIC)
2fb76298 1704 {
e0660879 1705 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s.",
2fb76298
MS
1706 types[con->type], types[type]);
1707
1708 return (HTTP_UNAUTHORIZED);
1709 }
1710
db1f069b 1711 strlcpy(username, con->username, sizeof(username));
fa73b229 1712 }
ef416fc2 1713
1714 /*
fa73b229 1715 * OK, got a username. See if we need normal user access, or group
ef416fc2 1716 * access... (root always matches)
1717 */
1718
fa73b229 1719 if (!strcmp(username, "root"))
ef416fc2 1720 return (HTTP_OK);
1721
db1f069b
MS
1722 /*
1723 * Strip any @domain or @KDC from the username and owner...
1724 */
1725
1726 if ((ptr = strchr(username, '@')) != NULL)
1727 *ptr = '\0';
1728
1729 if (owner)
1730 {
1731 strlcpy(ownername, owner, sizeof(ownername));
1732
1733 if ((ptr = strchr(ownername, '@')) != NULL)
1734 *ptr = '\0';
1735 }
1736 else
1737 ownername[0] = '\0';
1738
ef416fc2 1739 /*
1740 * Get the user info...
1741 */
1742
f7deaa1a 1743 if (username[0])
1744 {
1745 pw = getpwnam(username);
1746 endpwent();
1747 }
1748 else
1749 pw = NULL;
ef416fc2 1750
5bd77a73 1751 if (best->level == CUPSD_AUTH_USER)
ef416fc2 1752 {
1753 /*
1754 * If there are no names associated with this location, then
1755 * any valid user is OK...
1756 */
1757
10d09e33 1758 if (cupsArrayCount(best->names) == 0)
ef416fc2 1759 return (HTTP_OK);
1760
1761 /*
1762 * Otherwise check the user list and return OK if this user is
1763 * allowed...
1764 */
1765
ffe32673 1766 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership...");
ef416fc2 1767
f7deaa1a 1768#ifdef HAVE_AUTHORIZATION_H
1769 /*
1770 * If an authorization reference was supplied it must match a right name...
1771 */
1772
1773 if (con->authref)
1774 {
10d09e33
MS
1775 for (name = (char *)cupsArrayFirst(best->names);
1776 name;
1777 name = (char *)cupsArrayNext(best->names))
f7deaa1a 1778 {
88f9aafc 1779 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
f7deaa1a 1780 return (HTTP_OK);
88f9aafc 1781 else if (!_cups_strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
f7deaa1a 1782 check_authref(con, SystemGroupAuthKey))
1783 return (HTTP_OK);
1784 }
1785
ee571f26 1786 return (HTTP_FORBIDDEN);
f7deaa1a 1787 }
1788#endif /* HAVE_AUTHORIZATION_H */
1789
10d09e33
MS
1790 for (name = (char *)cupsArrayFirst(best->names);
1791 name;
1792 name = (char *)cupsArrayNext(best->names))
ef416fc2 1793 {
88f9aafc
MS
1794 if (!_cups_strcasecmp(name, "@OWNER") && owner &&
1795 !_cups_strcasecmp(username, ownername))
ef416fc2 1796 return (HTTP_OK);
88f9aafc 1797 else if (!_cups_strcasecmp(name, "@SYSTEM"))
ef416fc2 1798 {
10d09e33
MS
1799 for (i = 0; i < NumSystemGroups; i ++)
1800 if (cupsdCheckGroup(username, pw, SystemGroups[i]))
ef416fc2 1801 return (HTTP_OK);
1802 }
10d09e33 1803 else if (name[0] == '@')
ef416fc2 1804 {
10d09e33 1805 if (cupsdCheckGroup(username, pw, name + 1))
ef416fc2 1806 return (HTTP_OK);
1807 }
88f9aafc 1808 else if (!_cups_strcasecmp(username, name))
ef416fc2 1809 return (HTTP_OK);
1810 }
1811
85dda01c 1812 return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
ef416fc2 1813 }
1814
1815 /*
1816 * Check to see if this user is in any of the named groups...
1817 */
1818
ffe32673 1819 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group membership...");
ef416fc2 1820
1821 /*
1822 * Check to see if this user is in any of the named groups...
1823 */
1824
10d09e33
MS
1825 for (name = (char *)cupsArrayFirst(best->names);
1826 name;
1827 name = (char *)cupsArrayNext(best->names))
ef416fc2 1828 {
ffe32673 1829 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name);
ef416fc2 1830
88f9aafc 1831 if (!_cups_strcasecmp(name, "@SYSTEM"))
ef416fc2 1832 {
10d09e33
MS
1833 for (i = 0; i < NumSystemGroups; i ++)
1834 if (cupsdCheckGroup(username, pw, SystemGroups[i]))
ef416fc2 1835 return (HTTP_OK);
1836 }
10d09e33 1837 else if (cupsdCheckGroup(username, pw, name))
ef416fc2 1838 return (HTTP_OK);
1839 }
1840
1841 /*
1842 * The user isn't part of the specified group, so deny access...
1843 */
1844
ffe32673 1845 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: User not in group(s).");
ef416fc2 1846
85dda01c 1847 return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
ef416fc2 1848}
1849
1850
1851/*
10d09e33
MS
1852 * 'cupsdNewLocation()' - Create a new location for authorization.
1853 *
1854 * Note: Still need to call cupsdAddLocation() to add it to the list of global
1855 * locations.
ef416fc2 1856 */
1857
10d09e33
MS
1858cupsd_location_t * /* O - Pointer to new location record */
1859cupsdNewLocation(const char *location) /* I - Location path */
ef416fc2 1860{
10d09e33 1861 cupsd_location_t *temp; /* New location */
ef416fc2 1862
1863
1864 /*
10d09e33 1865 * Try to allocate memory for the new location.
ef416fc2 1866 */
1867
10d09e33 1868 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
ef416fc2 1869 return (NULL);
1870
1871 /*
10d09e33 1872 * Initialize the record and copy the name over...
ef416fc2 1873 */
1874
10d09e33
MS
1875 if ((temp->location = _cupsStrAlloc(location)) == NULL)
1876 {
1877 free(temp);
ef416fc2 1878 return (NULL);
10d09e33 1879 }
ef416fc2 1880
10d09e33 1881 temp->length = strlen(temp->location);
ef416fc2 1882
1883 /*
10d09e33 1884 * Return the new record...
ef416fc2 1885 */
1886
ef416fc2 1887 return (temp);
1888}
1889
1890
f7deaa1a 1891#ifdef HAVE_AUTHORIZATION_H
1892/*
1893 * 'check_authref()' - Check if an authorization services reference has the
1894 * supplied right.
1895 */
1896
1897static int /* O - 1 if right is valid, 0 otherwise */
1898check_authref(cupsd_client_t *con, /* I - Connection */
1899 const char *right) /* I - Right name */
1900{
1901 OSStatus status; /* OS Status */
1902 AuthorizationItem authright; /* Authorization right */
1903 AuthorizationRights authrights; /* Authorization rights */
1904 AuthorizationFlags authflags; /* Authorization flags */
1905
1906
1907 /*
1908 * Check to see if the user is allowed to perform the task...
1909 */
1910
1911 if (!con->authref)
1912 return (0);
1913
1914 authright.name = right;
1915 authright.valueLength = 0;
1916 authright.value = NULL;
1917 authright.flags = 0;
1918
1919 authrights.count = 1;
1920 authrights.items = &authright;
1921
c8fef167 1922 authflags = kAuthorizationFlagDefaults |
f7deaa1a 1923 kAuthorizationFlagExtendRights;
1924
c8fef167
MS
1925 if ((status = AuthorizationCopyRights(con->authref, &authrights,
1926 kAuthorizationEmptyEnvironment,
f7deaa1a 1927 authflags, NULL)) != 0)
1928 {
fa26ab95 1929 cupsdLogMessage(CUPSD_LOG_ERROR, "AuthorizationCopyRights(\"%s\") returned %d", authright.name, (int)status);
f7deaa1a 1930 return (0);
1931 }
1932
ffe32673 1933 cupsdLogMessage(CUPSD_LOG_DEBUG2, "AuthorizationCopyRights(\"%s\") succeeded.", authright.name);
f7deaa1a 1934
1935 return (1);
1936}
1937#endif /* HAVE_AUTHORIZATION_H */
1938
1939
bd7854cb 1940/*
1941 * 'compare_locations()' - Compare two locations.
1942 */
1943
1944static int /* O - Result of comparison */
1945compare_locations(cupsd_location_t *a, /* I - First location */
1946 cupsd_location_t *b) /* I - Second location */
1947{
1948 return (strcmp(b->location, a->location));
1949}
1950
1951
10d09e33
MS
1952/*
1953 * 'copy_authmask()' - Copy function for auth masks.
1954 */
1955
1956static cupsd_authmask_t * /* O - New auth mask */
1957copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */
1958 void *data) /* I - User data (unused) */
1959{
1960 cupsd_authmask_t *temp; /* New auth mask */
1961
1962
1963 (void)data;
1964
1965 if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
1966 {
1967 memcpy(temp, mask, sizeof(cupsd_authmask_t));
1968
1969 if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
1970 {
1971 /*
1972 * Make a copy of the name...
1973 */
1974
1975 if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
1976 {
1977 /*
1978 * Failed to make copy...
1979 */
1980
1981 free(temp);
1982 temp = NULL;
1983 }
1984 }
1985 }
1986
1987 return (temp);
1988}
1989
1990
10d09e33
MS
1991/*
1992 * 'free_authmask()' - Free function for auth masks.
1993 */
1994
1995static void
1996free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */
1997 void *data) /* I - User data (unused) */
1998{
1999 (void)data;
2000
2001 if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
2002 _cupsStrFree(mask->mask.name.name);
2003
2004 free(mask);
2005}
2006
2007
ef416fc2 2008#if HAVE_LIBPAM
2009/*
2010 * 'pam_func()' - PAM conversation function.
2011 */
2012
2013static int /* O - Success or failure */
2014pam_func(
2015 int num_msg, /* I - Number of messages */
2016 const struct pam_message **msg, /* I - Messages */
2017 struct pam_response **resp, /* O - Responses */
2018 void *appdata_ptr)
2019 /* I - Pointer to connection */
2020{
2021 int i; /* Looping var */
2022 struct pam_response *replies; /* Replies */
2023 cupsd_authdata_t *data; /* Pointer to auth data */
2024
2025
2026 /*
2027 * Allocate memory for the responses...
2028 */
2029
7e86f2f6 2030 if ((replies = malloc(sizeof(struct pam_response) * (size_t)num_msg)) == NULL)
ef416fc2 2031 return (PAM_CONV_ERR);
2032
2033 /*
2034 * Answer all of the messages...
2035 */
2036
ef416fc2 2037 data = (cupsd_authdata_t *)appdata_ptr;
ef416fc2 2038
2039 for (i = 0; i < num_msg; i ++)
2040 {
ef416fc2 2041 switch (msg[i]->msg_style)
2042 {
2043 case PAM_PROMPT_ECHO_ON:
ef416fc2 2044 replies[i].resp_retcode = PAM_SUCCESS;
2045 replies[i].resp = strdup(data->username);
2046 break;
2047
2048 case PAM_PROMPT_ECHO_OFF:
ef416fc2 2049 replies[i].resp_retcode = PAM_SUCCESS;
2050 replies[i].resp = strdup(data->password);
2051 break;
2052
2053 case PAM_TEXT_INFO:
ef416fc2 2054 replies[i].resp_retcode = PAM_SUCCESS;
2055 replies[i].resp = NULL;
2056 break;
2057
2058 case PAM_ERROR_MSG:
ef416fc2 2059 replies[i].resp_retcode = PAM_SUCCESS;
2060 replies[i].resp = NULL;
2061 break;
2062
2063 default:
ef416fc2 2064 free(replies);
2065 return (PAM_CONV_ERR);
2066 }
2067 }
2068
2069 /*
2070 * Return the responses back to PAM...
2071 */
2072
2073 *resp = replies;
2074
2075 return (PAM_SUCCESS);
2076}
ef416fc2 2077#endif /* HAVE_LIBPAM */