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