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