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