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