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