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