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