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