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