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