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