]> 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 6397 2007-03-25 23:33:32Z 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 else
961 gss_release_name(&minor_status, &client_name);
962 }
963 #endif /* HAVE_GSSAPI */
964 else
965 {
966 cupsdLogMessage(CUPSD_LOG_DEBUG,
967 "cupsdAuthorize: Bad authentication data.");
968 return;
969 }
970
971 /*
972 * If we get here, then we were able to validate the username and
973 * password - copy the validated username and password to the client
974 * data and return...
975 */
976
977 strlcpy(con->username, username, sizeof(con->username));
978 strlcpy(con->password, password, sizeof(con->password));
979
980 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: username=\"%s\"",
981 con->username);
982 }
983
984
985 /*
986 * 'cupsdCheckAuth()' - Check authorization masks.
987 */
988
989 int /* O - 1 if mask matches, 0 otherwise */
990 cupsdCheckAuth(
991 unsigned ip[4], /* I - Client address */
992 char *name, /* I - Client hostname */
993 int name_len, /* I - Length of hostname */
994 int num_masks, /* I - Number of masks */
995 cupsd_authmask_t *masks) /* I - Masks */
996 {
997 int i; /* Looping var */
998 cupsd_netif_t *iface; /* Network interface */
999 unsigned netip4; /* IPv4 network address */
1000 #ifdef AF_INET6
1001 unsigned netip6[4]; /* IPv6 network address */
1002 #endif /* AF_INET6 */
1003
1004 while (num_masks > 0)
1005 {
1006 switch (masks->type)
1007 {
1008 case AUTH_INTERFACE :
1009 /*
1010 * Check for a match with a network interface...
1011 */
1012
1013 netip4 = htonl(ip[3]);
1014
1015 #ifdef AF_INET6
1016 netip6[0] = htonl(ip[0]);
1017 netip6[1] = htonl(ip[1]);
1018 netip6[2] = htonl(ip[2]);
1019 netip6[3] = htonl(ip[3]);
1020 #endif /* AF_INET6 */
1021
1022 if (!strcmp(masks->mask.name.name, "*"))
1023 {
1024 /*
1025 * Check against all local interfaces...
1026 */
1027
1028 cupsdNetIFUpdate();
1029
1030 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1031 iface;
1032 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1033 {
1034 /*
1035 * Only check local interfaces...
1036 */
1037
1038 if (!iface->is_local)
1039 continue;
1040
1041 if (iface->address.addr.sa_family == AF_INET)
1042 {
1043 /*
1044 * Check IPv4 address...
1045 */
1046
1047 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1048 (iface->address.ipv4.sin_addr.s_addr &
1049 iface->mask.ipv4.sin_addr.s_addr))
1050 return (1);
1051 }
1052 #ifdef AF_INET6
1053 else
1054 {
1055 /*
1056 * Check IPv6 address...
1057 */
1058
1059 for (i = 0; i < 4; i ++)
1060 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1061 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1062 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1063 break;
1064
1065 if (i == 4)
1066 return (1);
1067 }
1068 #endif /* AF_INET6 */
1069 }
1070 }
1071 else
1072 {
1073 /*
1074 * Check the named interface...
1075 */
1076
1077 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1078 iface;
1079 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1080 {
1081 if (strcmp(masks->mask.name.name, iface->name))
1082 continue;
1083
1084 if (iface->address.addr.sa_family == AF_INET)
1085 {
1086 /*
1087 * Check IPv4 address...
1088 */
1089
1090 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1091 (iface->address.ipv4.sin_addr.s_addr &
1092 iface->mask.ipv4.sin_addr.s_addr))
1093 return (1);
1094 }
1095 #ifdef AF_INET6
1096 else
1097 {
1098 /*
1099 * Check IPv6 address...
1100 */
1101
1102 for (i = 0; i < 4; i ++)
1103 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1104 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1105 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1106 break;
1107
1108 if (i == 4)
1109 return (1);
1110 }
1111 #endif /* AF_INET6 */
1112 }
1113 }
1114 break;
1115
1116 case AUTH_NAME :
1117 /*
1118 * Check for exact name match...
1119 */
1120
1121 if (!strcasecmp(name, masks->mask.name.name))
1122 return (1);
1123
1124 /*
1125 * Check for domain match...
1126 */
1127
1128 if (name_len >= masks->mask.name.length &&
1129 masks->mask.name.name[0] == '.' &&
1130 !strcasecmp(name + name_len - masks->mask.name.length,
1131 masks->mask.name.name))
1132 return (1);
1133 break;
1134
1135 case AUTH_IP :
1136 /*
1137 * Check for IP/network address match...
1138 */
1139
1140 for (i = 0; i < 4; i ++)
1141 if ((ip[i] & masks->mask.ip.netmask[i]) !=
1142 masks->mask.ip.address[i])
1143 break;
1144
1145 if (i == 4)
1146 return (1);
1147 break;
1148 }
1149
1150 masks ++;
1151 num_masks --;
1152 }
1153
1154 return (0);
1155 }
1156
1157
1158 /*
1159 * 'cupsdCheckGroup()' - Check for a user's group membership.
1160 */
1161
1162 int /* O - 1 if user is a member, 0 otherwise */
1163 cupsdCheckGroup(
1164 const char *username, /* I - User name */
1165 struct passwd *user, /* I - System user info */
1166 const char *groupname) /* I - Group name */
1167 {
1168 int i; /* Looping var */
1169 struct group *group; /* System group info */
1170 char junk[33]; /* MD5 password (not used) */
1171 #ifdef HAVE_MBR_UID_TO_UUID
1172 uuid_t useruuid, /* UUID for username */
1173 groupuuid; /* UUID for groupname */
1174 int is_member; /* True if user is a member of group */
1175 #endif /* HAVE_MBR_UID_TO_UUID */
1176
1177
1178 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1179 "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")",
1180 username, user, groupname);
1181
1182 /*
1183 * Validate input...
1184 */
1185
1186 if (!username || !groupname)
1187 return (0);
1188
1189 /*
1190 * Check to see if the user is a member of the named group...
1191 */
1192
1193 group = getgrnam(groupname);
1194 endgrent();
1195
1196 if (group != NULL)
1197 {
1198 /*
1199 * Group exists, check it...
1200 */
1201
1202 for (i = 0; group->gr_mem[i]; i ++)
1203 if (!strcasecmp(username, group->gr_mem[i]))
1204 return (1);
1205 }
1206
1207 /*
1208 * Group doesn't exist or user not in group list, check the group ID
1209 * against the user's group ID...
1210 */
1211
1212 if (user && group && group->gr_gid == user->pw_gid)
1213 return (1);
1214
1215 #ifdef HAVE_MBR_UID_TO_UUID
1216 /*
1217 * Check group membership through MacOS X membership API...
1218 */
1219
1220 if (user && group)
1221 if (!mbr_uid_to_uuid(user->pw_uid, useruuid))
1222 if (!mbr_gid_to_uuid(group->gr_gid, groupuuid))
1223 if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1224 if (is_member)
1225 return (1);
1226 #endif /* HAVE_MBR_UID_TO_UUID */
1227
1228 /*
1229 * Username not found, group not found, or user is not part of the
1230 * system group... Check for a user and group in the MD5 password
1231 * file...
1232 */
1233
1234 if (get_md5_password(username, groupname, junk) != NULL)
1235 return (1);
1236
1237 /*
1238 * If we get this far, then the user isn't part of the named group...
1239 */
1240
1241 return (0);
1242 }
1243
1244
1245 /*
1246 * 'cupsdCopyLocation()' - Make a copy of a location...
1247 */
1248
1249 cupsd_location_t * /* O - New location */
1250 cupsdCopyLocation(
1251 cupsd_location_t **loc) /* IO - Original location */
1252 {
1253 int i; /* Looping var */
1254 cupsd_location_t *temp; /* New location */
1255 char location[HTTP_MAX_URI];
1256 /* Location of resource */
1257
1258
1259 /*
1260 * Use a local copy of location because cupsdAddLocation may cause
1261 * this memory to be moved...
1262 */
1263
1264 strlcpy(location, (*loc)->location, sizeof(location));
1265
1266 if ((temp = cupsdAddLocation(location)) == NULL)
1267 return (NULL);
1268
1269 /*
1270 * Copy the information from the original location to the new one.
1271 */
1272
1273 temp->limit = (*loc)->limit;
1274 temp->order_type = (*loc)->order_type;
1275 temp->type = (*loc)->type;
1276 temp->level = (*loc)->level;
1277 temp->satisfy = (*loc)->satisfy;
1278 temp->encryption = (*loc)->encryption;
1279
1280 if ((temp->num_names = (*loc)->num_names) > 0)
1281 {
1282 /*
1283 * Copy the names array...
1284 */
1285
1286 if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
1287 {
1288 cupsdLogMessage(CUPSD_LOG_ERROR,
1289 "cupsdCopyLocation: Unable to allocate memory for %d names: %s",
1290 temp->num_names, strerror(errno));
1291
1292 cupsdDeleteLocation(temp);
1293 return (NULL);
1294 }
1295
1296 for (i = 0; i < temp->num_names; i ++)
1297 if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
1298 {
1299 cupsdLogMessage(CUPSD_LOG_ERROR,
1300 "cupsdCopyLocation: Unable to copy name \"%s\": %s",
1301 (*loc)->names[i], strerror(errno));
1302
1303 cupsdDeleteLocation(temp);
1304 return (NULL);
1305 }
1306 }
1307
1308 if ((temp->num_allow = (*loc)->num_allow) > 0)
1309 {
1310 /*
1311 * Copy allow rules...
1312 */
1313
1314 if ((temp->allow = calloc(temp->num_allow, sizeof(cupsd_authmask_t))) == NULL)
1315 {
1316 cupsdLogMessage(CUPSD_LOG_ERROR,
1317 "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s",
1318 temp->num_allow, strerror(errno));
1319 cupsdDeleteLocation(temp);
1320 return (NULL);
1321 }
1322
1323 for (i = 0; i < temp->num_allow; i ++)
1324 switch (temp->allow[i].type = (*loc)->allow[i].type)
1325 {
1326 case AUTH_NAME :
1327 temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
1328 temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
1329
1330 if (temp->allow[i].mask.name.name == NULL)
1331 {
1332 cupsdLogMessage(CUPSD_LOG_ERROR,
1333 "cupsdCopyLocation: Unable to copy allow name \"%s\": %s",
1334 (*loc)->allow[i].mask.name.name, strerror(errno));
1335 cupsdDeleteLocation(temp);
1336 return (NULL);
1337 }
1338 break;
1339 case AUTH_IP :
1340 memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
1341 sizeof(cupsd_ipmask_t));
1342 break;
1343 }
1344 }
1345
1346 if ((temp->num_deny = (*loc)->num_deny) > 0)
1347 {
1348 /*
1349 * Copy deny rules...
1350 */
1351
1352 if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL)
1353 {
1354 cupsdLogMessage(CUPSD_LOG_ERROR,
1355 "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s",
1356 temp->num_deny, strerror(errno));
1357 cupsdDeleteLocation(temp);
1358 return (NULL);
1359 }
1360
1361 for (i = 0; i < temp->num_deny; i ++)
1362 switch (temp->deny[i].type = (*loc)->deny[i].type)
1363 {
1364 case AUTH_NAME :
1365 temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
1366 temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
1367
1368 if (temp->deny[i].mask.name.name == NULL)
1369 {
1370 cupsdLogMessage(CUPSD_LOG_ERROR,
1371 "cupsdCopyLocation: Unable to copy deny name \"%s\": %s",
1372 (*loc)->deny[i].mask.name.name, strerror(errno));
1373 cupsdDeleteLocation(temp);
1374 return (NULL);
1375 }
1376 break;
1377 case AUTH_IP :
1378 memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
1379 sizeof(cupsd_ipmask_t));
1380 break;
1381 }
1382 }
1383
1384 return (temp);
1385 }
1386
1387
1388 /*
1389 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1390 */
1391
1392 void
1393 cupsdDeleteAllLocations(void)
1394 {
1395 cupsd_location_t *loc; /* Current location */
1396
1397
1398 /*
1399 * Free all of the allow/deny records first...
1400 */
1401
1402 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1403 loc;
1404 loc = (cupsd_location_t *)cupsArrayNext(Locations))
1405 cupsdDeleteLocation(loc);
1406
1407 /*
1408 * Then free the location array...
1409 */
1410
1411 cupsArrayDelete(Locations);
1412 Locations = NULL;
1413 }
1414
1415
1416 /*
1417 * 'cupsdDeleteLocation()' - Free all memory used by a location.
1418 */
1419
1420 void
1421 cupsdDeleteLocation(
1422 cupsd_location_t *loc) /* I - Location to delete */
1423 {
1424 int i; /* Looping var */
1425 cupsd_authmask_t *mask; /* Current mask */
1426
1427
1428 cupsArrayRemove(Locations, loc);
1429
1430 for (i = loc->num_names - 1; i >= 0; i --)
1431 free(loc->names[i]);
1432
1433 if (loc->num_names > 0)
1434 free(loc->names);
1435
1436 for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++)
1437 if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE)
1438 free(mask->mask.name.name);
1439
1440 if (loc->num_allow > 0)
1441 free(loc->allow);
1442
1443 for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++)
1444 if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE)
1445 free(mask->mask.name.name);
1446
1447 if (loc->num_deny > 0)
1448 free(loc->deny);
1449
1450 free(loc->location);
1451 free(loc);
1452 }
1453
1454
1455 /*
1456 * 'cupsdDenyHost()' - Add a host name that is not allowed to access the
1457 * location.
1458 */
1459
1460 void
1461 cupsdDenyHost(cupsd_location_t *loc, /* I - Location to add to */
1462 char *name) /* I - Name of host or domain to add */
1463 {
1464 cupsd_authmask_t *temp; /* New host/domain mask */
1465 char ifname[32], /* Interface name */
1466 *ifptr; /* Pointer to end of name */
1467
1468
1469 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")",
1470 loc, loc->location ? loc->location : "nil", name);
1471
1472 if ((temp = add_deny(loc)) == NULL)
1473 return;
1474
1475 if (!strcasecmp(name, "@LOCAL"))
1476 {
1477 /*
1478 * Deny *interface*...
1479 */
1480
1481 temp->type = AUTH_INTERFACE;
1482 temp->mask.name.name = strdup("*");
1483 temp->mask.name.length = 1;
1484 }
1485 else if (!strncasecmp(name, "@IF(", 4))
1486 {
1487 /*
1488 * Deny *interface*...
1489 */
1490
1491 strlcpy(ifname, name + 4, sizeof(ifname));
1492
1493 ifptr = ifname + strlen(ifname);
1494
1495 if (ifptr[-1] == ')')
1496 {
1497 ifptr --;
1498 *ifptr = '\0';
1499 }
1500
1501 temp->type = AUTH_INTERFACE;
1502 temp->mask.name.name = strdup(ifname);
1503 temp->mask.name.length = ifptr - ifname;
1504 }
1505 else
1506 {
1507 /*
1508 * Deny name...
1509 */
1510
1511 temp->type = AUTH_NAME;
1512 temp->mask.name.name = strdup(name);
1513 temp->mask.name.length = strlen(name);
1514 }
1515 }
1516
1517
1518 /*
1519 * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to
1520 * access the location.
1521 */
1522
1523 void
1524 cupsdDenyIP(cupsd_location_t *loc, /* I - Location to add to */
1525 unsigned address[4],/* I - IP address to add */
1526 unsigned netmask[4])/* I - Netmask of address */
1527 {
1528 cupsd_authmask_t *temp; /* New host/domain mask */
1529
1530
1531 cupsdLogMessage(CUPSD_LOG_DEBUG,
1532 "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
1533 loc, loc->location ? loc->location : "nil",
1534 address[0], address[1], address[2], address[3],
1535 netmask[0], netmask[1], netmask[2], netmask[3]);
1536
1537 if ((temp = add_deny(loc)) == NULL)
1538 return;
1539
1540 temp->type = AUTH_IP;
1541 memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
1542 memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
1543 }
1544
1545
1546 /*
1547 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1548 */
1549
1550 cupsd_location_t * /* O - Location that matches */
1551 cupsdFindBest(const char *path, /* I - Resource path */
1552 http_state_t state) /* I - HTTP state/request */
1553 {
1554 char uri[HTTP_MAX_URI],
1555 /* URI in request... */
1556 *uriptr; /* Pointer into URI */
1557 cupsd_location_t *loc, /* Current location */
1558 *best; /* Best match for location so far */
1559 int bestlen; /* Length of best match */
1560 int limit; /* Limit field */
1561 static const int limits[] = /* Map http_status_t to AUTH_LIMIT_xyz */
1562 {
1563 AUTH_LIMIT_ALL,
1564 AUTH_LIMIT_OPTIONS,
1565 AUTH_LIMIT_GET,
1566 AUTH_LIMIT_GET,
1567 AUTH_LIMIT_HEAD,
1568 AUTH_LIMIT_POST,
1569 AUTH_LIMIT_POST,
1570 AUTH_LIMIT_POST,
1571 AUTH_LIMIT_PUT,
1572 AUTH_LIMIT_PUT,
1573 AUTH_LIMIT_DELETE,
1574 AUTH_LIMIT_TRACE,
1575 AUTH_LIMIT_ALL,
1576 AUTH_LIMIT_ALL
1577 };
1578
1579
1580 /*
1581 * First copy the connection URI to a local string so we have drop
1582 * any .ppd extension from the pathname in /printers or /classes
1583 * URIs...
1584 */
1585
1586 strlcpy(uri, path, sizeof(uri));
1587
1588 if (!strncmp(uri, "/printers/", 10) ||
1589 !strncmp(uri, "/classes/", 9))
1590 {
1591 /*
1592 * Check if the URI has .ppd on the end...
1593 */
1594
1595 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
1596
1597 if (!strcmp(uriptr, ".ppd"))
1598 *uriptr = '\0';
1599 }
1600
1601 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri = \"%s\"...", uri);
1602
1603 /*
1604 * Loop through the list of locations to find a match...
1605 */
1606
1607 limit = limits[state];
1608 best = NULL;
1609 bestlen = 0;
1610
1611 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1612 loc;
1613 loc = (cupsd_location_t *)cupsArrayNext(Locations))
1614 {
1615 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x",
1616 loc->location ? loc->location : "nil", loc->limit);
1617
1618 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
1619 {
1620 /*
1621 * Use case-insensitive comparison for queue names...
1622 */
1623
1624 if (loc->length > bestlen && loc->location &&
1625 !strncasecmp(uri, loc->location, loc->length) &&
1626 loc->location[0] == '/' &&
1627 (limit & loc->limit) != 0)
1628 {
1629 best = loc;
1630 bestlen = loc->length;
1631 }
1632 }
1633 else
1634 {
1635 /*
1636 * Use case-sensitive comparison for other URIs...
1637 */
1638
1639 if (loc->length > bestlen && loc->location &&
1640 !strncmp(uri, loc->location, loc->length) &&
1641 loc->location[0] == '/' &&
1642 (limit & loc->limit) != 0)
1643 {
1644 best = loc;
1645 bestlen = loc->length;
1646 }
1647 }
1648 }
1649
1650 /*
1651 * Return the match, if any...
1652 */
1653
1654 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s",
1655 best ? best->location : "NONE");
1656
1657 return (best);
1658 }
1659
1660
1661 /*
1662 * 'cupsdFindLocation()' - Find the named location.
1663 */
1664
1665 cupsd_location_t * /* O - Location that matches */
1666 cupsdFindLocation(const char *location) /* I - Connection */
1667 {
1668 cupsd_location_t key; /* Search key */
1669
1670
1671 key.location = (char *)location;
1672
1673 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
1674 }
1675
1676
1677 /*
1678 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1679 */
1680
1681 http_status_t /* O - HTTP_OK if authorized or error code */
1682 cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
1683 const char *owner)/* I - Owner of object */
1684 {
1685 int i, j, /* Looping vars */
1686 auth; /* Authorization status */
1687 unsigned address[4]; /* Authorization address */
1688 cupsd_location_t *best; /* Best match for location so far */
1689 int hostlen; /* Length of hostname */
1690 const char *username; /* Username to authorize */
1691 struct passwd *pw; /* User password data */
1692 static const char * const levels[] = /* Auth levels */
1693 {
1694 "ANON",
1695 "USER",
1696 "GROUP"
1697 };
1698 static const char * const types[] = /* Auth types */
1699 {
1700 "NONE",
1701 "BASIC",
1702 "DIGEST",
1703 "BASICDIGEST",
1704 "KERBEROS"
1705 };
1706
1707
1708 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1709 "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
1710 con->uri, con->best, con->best ? con->best->location ?
1711 con->best->location : "(null)" : "");
1712 if (owner)
1713 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1714 "cupsdIsAuthorized: owner=\"%s\"", owner);
1715
1716 /*
1717 * If there is no "best" authentication rule for this request, then
1718 * access is allowed from the local system and denied from other
1719 * addresses...
1720 */
1721
1722 if (!con->best)
1723 {
1724 if (!strcmp(con->http.hostname, "localhost") ||
1725 !strcmp(con->http.hostname, ServerName))
1726 return (HTTP_OK);
1727 else
1728 return (HTTP_FORBIDDEN);
1729 }
1730
1731 best = con->best;
1732
1733 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1734 "cupsdIsAuthorized: level=AUTH_%s, type=AUTH_%s, "
1735 "satisfy=AUTH_SATISFY_%s, num_names=%d",
1736 levels[best->level], types[best->type],
1737 best->satisfy ? "ANY" : "ALL", best->num_names);
1738
1739 if (best->limit == AUTH_LIMIT_IPP)
1740 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
1741 best->op, ippOpString(best->op));
1742
1743 /*
1744 * Check host/ip-based accesses...
1745 */
1746
1747 #ifdef AF_INET6
1748 if (con->http.hostaddr->addr.sa_family == AF_INET6)
1749 {
1750 /*
1751 * Copy IPv6 address...
1752 */
1753
1754 address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]);
1755 address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]);
1756 address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]);
1757 address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]);
1758 }
1759 else
1760 #endif /* AF_INET6 */
1761 if (con->http.hostaddr->addr.sa_family == AF_INET)
1762 {
1763 /*
1764 * Copy IPv4 address...
1765 */
1766
1767 address[0] = 0;
1768 address[1] = 0;
1769 address[2] = 0;
1770 address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr);
1771 }
1772 else
1773 memset(address, 0, sizeof(address));
1774
1775 hostlen = strlen(con->http.hostname);
1776
1777 if (!strcasecmp(con->http.hostname, "localhost"))
1778 {
1779 /*
1780 * Access from localhost (127.0.0.1 or ::1) is always allowed...
1781 */
1782
1783 auth = AUTH_ALLOW;
1784 }
1785 else
1786 {
1787 /*
1788 * Do authorization checks on the domain/address...
1789 */
1790
1791 switch (best->order_type)
1792 {
1793 default :
1794 auth = AUTH_DENY; /* anti-compiler-warning-code */
1795 break;
1796
1797 case AUTH_ALLOW : /* Order Deny,Allow */
1798 auth = AUTH_ALLOW;
1799
1800 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1801 best->num_deny, best->deny))
1802 auth = AUTH_DENY;
1803
1804 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1805 best->num_allow, best->allow))
1806 auth = AUTH_ALLOW;
1807 break;
1808
1809 case AUTH_DENY : /* Order Allow,Deny */
1810 auth = AUTH_DENY;
1811
1812 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1813 best->num_allow, best->allow))
1814 auth = AUTH_ALLOW;
1815
1816 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1817 best->num_deny, best->deny))
1818 auth = AUTH_DENY;
1819 break;
1820 }
1821 }
1822
1823 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=AUTH_%s...",
1824 auth ? "DENY" : "ALLOW");
1825
1826 if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
1827 return (HTTP_FORBIDDEN);
1828
1829 #ifdef HAVE_SSL
1830 /*
1831 * See if encryption is required...
1832 */
1833
1834 if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
1835 strcasecmp(con->http.hostname, "localhost") &&
1836 best->satisfy == AUTH_SATISFY_ALL) &&
1837 !(best->type == AUTH_NEGOTIATE ||
1838 (best->type == AUTH_NONE && DefaultAuthType == AUTH_NEGOTIATE)))
1839 {
1840 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1841 "cupsdIsAuthorized: Need upgrade to TLS...");
1842 return (HTTP_UPGRADE_REQUIRED);
1843 }
1844 #endif /* HAVE_SSL */
1845
1846 /*
1847 * Now see what access level is required...
1848 */
1849
1850 if (best->level == AUTH_ANON || /* Anonymous access - allow it */
1851 (best->type == AUTH_NONE && best->num_names == 0))
1852 return (HTTP_OK);
1853
1854 if (!con->username[0] && best->type == AUTH_NONE &&
1855 best->limit == AUTH_LIMIT_IPP)
1856 {
1857 /*
1858 * Check for unauthenticated username...
1859 */
1860
1861 ipp_attribute_t *attr; /* requesting-user-name attribute */
1862
1863
1864 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1865 if (attr)
1866 {
1867 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1868 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1869 attr->values[0].string.text);
1870 username = attr->values[0].string.text;
1871 }
1872 else if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
1873 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1874 else
1875 return (HTTP_OK); /* unless overridden with Satisfy */
1876 }
1877 else
1878 {
1879 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"",
1880 con->username);
1881
1882 #ifdef HAVE_AUTHORIZATION_H
1883 if (!con->username[0] && !con->authref)
1884 #else
1885 if (!con->username[0])
1886 #endif /* HAVE_AUTHORIZATION_H */
1887 {
1888 if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
1889 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1890 else
1891 return (HTTP_OK); /* unless overridden with Satisfy */
1892 }
1893
1894 username = con->username;
1895 }
1896
1897 /*
1898 * OK, got a username. See if we need normal user access, or group
1899 * access... (root always matches)
1900 */
1901
1902 if (!strcmp(username, "root"))
1903 return (HTTP_OK);
1904
1905 /*
1906 * Get the user info...
1907 */
1908
1909 if (username[0])
1910 {
1911 pw = getpwnam(username);
1912 endpwent();
1913 }
1914 else
1915 pw = NULL;
1916
1917 if (best->level == AUTH_USER)
1918 {
1919 /*
1920 * If there are no names associated with this location, then
1921 * any valid user is OK...
1922 */
1923
1924 if (best->num_names == 0)
1925 return (HTTP_OK);
1926
1927 /*
1928 * Otherwise check the user list and return OK if this user is
1929 * allowed...
1930 */
1931
1932 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1933 "cupsdIsAuthorized: Checking user membership...");
1934
1935 #ifdef HAVE_AUTHORIZATION_H
1936 /*
1937 * If an authorization reference was supplied it must match a right name...
1938 */
1939
1940 if (con->authref)
1941 {
1942 for (i = 0; i < best->num_names; i ++)
1943 {
1944 if (!strncasecmp(best->names[i], "@AUTHKEY(", 9) &&
1945 check_authref(con, best->names[i] + 9))
1946 return (HTTP_OK);
1947 else if (!strcasecmp(best->names[i], "@SYSTEM") &&
1948 SystemGroupAuthKey &&
1949 check_authref(con, SystemGroupAuthKey))
1950 return (HTTP_OK);
1951 }
1952
1953 return (HTTP_UNAUTHORIZED);
1954 }
1955 #endif /* HAVE_AUTHORIZATION_H */
1956
1957 for (i = 0; i < best->num_names; i ++)
1958 {
1959 if (!strcasecmp(best->names[i], "@OWNER") && owner &&
1960 !strcasecmp(username, owner))
1961 return (HTTP_OK);
1962 else if (!strcasecmp(best->names[i], "@SYSTEM"))
1963 {
1964 for (j = 0; j < NumSystemGroups; j ++)
1965 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
1966 return (HTTP_OK);
1967 }
1968 else if (best->names[i][0] == '@')
1969 {
1970 if (cupsdCheckGroup(username, pw, best->names[i] + 1))
1971 return (HTTP_OK);
1972 }
1973 else if (!strcasecmp(username, best->names[i]))
1974 return (HTTP_OK);
1975 }
1976
1977 return (HTTP_UNAUTHORIZED);
1978 }
1979
1980 /*
1981 * Check to see if this user is in any of the named groups...
1982 */
1983
1984 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1985 "cupsdIsAuthorized: Checking group membership...");
1986
1987 /*
1988 * Check to see if this user is in any of the named groups...
1989 */
1990
1991 for (i = 0; i < best->num_names; i ++)
1992 {
1993 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1994 "cupsdIsAuthorized: Checking group \"%s\" membership...",
1995 best->names[i]);
1996
1997 if (!strcasecmp(best->names[i], "@SYSTEM"))
1998 {
1999 for (j = 0; j < NumSystemGroups; j ++)
2000 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
2001 return (HTTP_OK);
2002 }
2003 else if (cupsdCheckGroup(username, pw, best->names[i]))
2004 return (HTTP_OK);
2005 }
2006
2007 /*
2008 * The user isn't part of the specified group, so deny access...
2009 */
2010
2011 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2012 "cupsdIsAuthorized: User not in group(s)!");
2013
2014 return (HTTP_UNAUTHORIZED);
2015 }
2016
2017
2018 /*
2019 * 'add_allow()' - Add an allow mask to the location.
2020 */
2021
2022 static cupsd_authmask_t * /* O - New mask record */
2023 add_allow(cupsd_location_t *loc) /* I - Location to add to */
2024 {
2025 cupsd_authmask_t *temp; /* New mask record */
2026
2027
2028 /*
2029 * Range-check...
2030 */
2031
2032 if (loc == NULL)
2033 return (NULL);
2034
2035 /*
2036 * Try to allocate memory for the record...
2037 */
2038
2039 if (loc->num_allow == 0)
2040 temp = malloc(sizeof(cupsd_authmask_t));
2041 else
2042 temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1));
2043
2044 if (temp == NULL)
2045 return (NULL);
2046
2047 loc->allow = temp;
2048 temp += loc->num_allow;
2049 loc->num_allow ++;
2050
2051 /*
2052 * Clear the mask record and return...
2053 */
2054
2055 memset(temp, 0, sizeof(cupsd_authmask_t));
2056 return (temp);
2057 }
2058
2059
2060 /*
2061 * 'add_deny()' - Add a deny mask to the location.
2062 */
2063
2064 static cupsd_authmask_t * /* O - New mask record */
2065 add_deny(cupsd_location_t *loc) /* I - Location to add to */
2066 {
2067 cupsd_authmask_t *temp; /* New mask record */
2068
2069
2070 /*
2071 * Range-check...
2072 */
2073
2074 if (loc == NULL)
2075 return (NULL);
2076
2077 /*
2078 * Try to allocate memory for the record...
2079 */
2080
2081 if (loc->num_deny == 0)
2082 temp = malloc(sizeof(cupsd_authmask_t));
2083 else
2084 temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1));
2085
2086 if (temp == NULL)
2087 return (NULL);
2088
2089 loc->deny = temp;
2090 temp += loc->num_deny;
2091 loc->num_deny ++;
2092
2093 /*
2094 * Clear the mask record and return...
2095 */
2096
2097 memset(temp, 0, sizeof(cupsd_authmask_t));
2098 return (temp);
2099 }
2100
2101
2102 #ifdef HAVE_AUTHORIZATION_H
2103 /*
2104 * 'check_authref()' - Check if an authorization services reference has the
2105 * supplied right.
2106 */
2107
2108 static int /* O - 1 if right is valid, 0 otherwise */
2109 check_authref(cupsd_client_t *con, /* I - Connection */
2110 const char *right) /* I - Right name */
2111 {
2112 OSStatus status; /* OS Status */
2113 AuthorizationItem authright; /* Authorization right */
2114 AuthorizationRights authrights; /* Authorization rights */
2115 AuthorizationFlags authflags; /* Authorization flags */
2116
2117
2118 /*
2119 * Check to see if the user is allowed to perform the task...
2120 */
2121
2122 if (!con->authref)
2123 return (0);
2124
2125 authright.name = right;
2126 authright.valueLength = 0;
2127 authright.value = NULL;
2128 authright.flags = 0;
2129
2130 authrights.count = 1;
2131 authrights.items = &authright;
2132
2133 authflags = kAuthorizationFlagDefaults |
2134 kAuthorizationFlagExtendRights;
2135
2136 if ((status = AuthorizationCopyRights(con->authref, &authrights,
2137 kAuthorizationEmptyEnvironment,
2138 authflags, NULL)) != 0)
2139 {
2140 cupsdLogMessage(CUPSD_LOG_ERROR,
2141 "AuthorizationCopyRights(\"%s\") returned %d (%s)",
2142 authright.name, (int)status, cssmErrorString(status));
2143 return (0);
2144 }
2145
2146 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2147 "AuthorizationCopyRights(\"%s\") succeeded!",
2148 authright.name);
2149
2150 return (1);
2151 }
2152 #endif /* HAVE_AUTHORIZATION_H */
2153
2154
2155 /*
2156 * 'compare_locations()' - Compare two locations.
2157 */
2158
2159 static int /* O - Result of comparison */
2160 compare_locations(cupsd_location_t *a, /* I - First location */
2161 cupsd_location_t *b) /* I - Second location */
2162 {
2163 return (strcmp(b->location, a->location));
2164 }
2165
2166
2167 #if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
2168 /*
2169 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
2170 * as needed.
2171 */
2172
2173 static char * /* O - Encrypted password */
2174 cups_crypt(const char *pw, /* I - Password string */
2175 const char *salt) /* I - Salt (key) string */
2176 {
2177 if (!strncmp(salt, "$1$", 3))
2178 {
2179 /*
2180 * Use MD5 passwords without the benefit of PAM; this is for
2181 * Slackware Linux, and the algorithm was taken from the
2182 * old shadow-19990827/lib/md5crypt.c source code... :(
2183 */
2184
2185 int i; /* Looping var */
2186 unsigned long n; /* Output number */
2187 int pwlen; /* Length of password string */
2188 const char *salt_end; /* End of "salt" data for MD5 */
2189 char *ptr; /* Pointer into result string */
2190 _cups_md5_state_t state; /* Primary MD5 state info */
2191 _cups_md5_state_t state2; /* Secondary MD5 state info */
2192 unsigned char digest[16]; /* MD5 digest result */
2193 static char result[120]; /* Final password string */
2194
2195
2196 /*
2197 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
2198 * Get a maximum of 8 characters of salt data after $1$...
2199 */
2200
2201 for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
2202 if (*salt_end == '$')
2203 break;
2204
2205 /*
2206 * Compute the MD5 sum we need...
2207 */
2208
2209 pwlen = strlen(pw);
2210
2211 _cupsMD5Init(&state);
2212 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2213 _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
2214
2215 _cupsMD5Init(&state2);
2216 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2217 _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
2218 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2219 _cupsMD5Finish(&state2, digest);
2220
2221 for (i = pwlen; i > 0; i -= 16)
2222 _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
2223
2224 for (i = pwlen; i > 0; i >>= 1)
2225 _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
2226
2227 _cupsMD5Finish(&state, digest);
2228
2229 for (i = 0; i < 1000; i ++)
2230 {
2231 _cupsMD5Init(&state);
2232
2233 if (i & 1)
2234 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2235 else
2236 _cupsMD5Append(&state, digest, 16);
2237
2238 if (i % 3)
2239 _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
2240
2241 if (i % 7)
2242 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2243
2244 if (i & 1)
2245 _cupsMD5Append(&state, digest, 16);
2246 else
2247 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2248
2249 _cupsMD5Finish(&state, digest);
2250 }
2251
2252 /*
2253 * Copy the final sum to the result string and return...
2254 */
2255
2256 memcpy(result, salt, salt_end - salt);
2257 ptr = result + (salt_end - salt);
2258 *ptr++ = '$';
2259
2260 for (i = 0; i < 5; i ++, ptr += 4)
2261 {
2262 n = (((digest[i] << 8) | digest[i + 6]) << 8);
2263
2264 if (i < 4)
2265 n |= digest[i + 12];
2266 else
2267 n |= digest[5];
2268
2269 to64(ptr, n, 4);
2270 }
2271
2272 to64(ptr, digest[11], 2);
2273 ptr += 2;
2274 *ptr = '\0';
2275
2276 return (result);
2277 }
2278 else
2279 {
2280 /*
2281 * Use the standard crypt() function...
2282 */
2283
2284 return (crypt(pw, salt));
2285 }
2286 }
2287 #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
2288
2289
2290 #ifdef HAVE_GSSAPI
2291 /*
2292 * 'get_gss_creds()' - Obtain GSS credentials.
2293 */
2294
2295 static gss_cred_id_t /* O - Server credentials */
2296 get_gss_creds(const char *service_name) /* I - Service name */
2297 {
2298 OM_uint32 major_status, /* Major status code */
2299 minor_status; /* Minor status code */
2300 gss_name_t server_name; /* Server name */
2301 gss_cred_id_t server_creds; /* Server credentials */
2302 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
2303 /* Service name token */
2304 char buf[1024], /* Service name buffer */
2305 fqdn[HTTP_MAX_URI]; /* Hostname of server */
2306
2307
2308 snprintf(buf, sizeof(buf), "%s@%s", service_name,
2309 httpGetHostname(NULL, fqdn, sizeof(fqdn)));
2310
2311 token.value = buf;
2312 token.length = strlen(buf);
2313 server_name = GSS_C_NO_NAME;
2314 major_status = gss_import_name(&minor_status, &token,
2315 GSS_C_NT_HOSTBASED_SERVICE,
2316 &server_name);
2317
2318 memset(&token, 0, sizeof(token));
2319
2320 if (GSS_ERROR(major_status))
2321 {
2322 cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status,
2323 "gss_import_name() failed");
2324 return (NULL);
2325 }
2326
2327 major_status = gss_display_name(&minor_status, server_name, &token, NULL);
2328
2329 if (GSS_ERROR(major_status))
2330 {
2331 cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status,
2332 "gss_display_name() failed");
2333 return (NULL);
2334 }
2335
2336 cupsdLogMessage(CUPSD_LOG_INFO, "Attempting to acquire credentials for %s...",
2337 (char *)token.value);
2338
2339 server_creds = GSS_C_NO_CREDENTIAL;
2340 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
2341 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
2342 &server_creds, NULL, NULL);
2343 if (GSS_ERROR(major_status))
2344 {
2345 cupsdLogGSSMessage(CUPSD_LOG_WARN, major_status, minor_status,
2346 "gss_acquire_cred() failed");
2347 gss_release_name(&minor_status, &server_name);
2348 gss_release_buffer(&minor_status, &token);
2349 return (NULL);
2350 }
2351
2352 cupsdLogMessage(CUPSD_LOG_INFO, "Credentials acquired successfully for %s.",
2353 (char *)token.value);
2354
2355 gss_release_name(&minor_status, &server_name);
2356 gss_release_buffer(&minor_status, &token);
2357
2358 return (server_creds);
2359 }
2360 #endif /* HAVE_GSSAPI */
2361
2362
2363 /*
2364 * 'get_md5_password()' - Get an MD5 password.
2365 */
2366
2367 static char * /* O - MD5 password string */
2368 get_md5_password(const char *username, /* I - Username */
2369 const char *group, /* I - Group */
2370 char passwd[33]) /* O - MD5 password string */
2371 {
2372 cups_file_t *fp; /* passwd.md5 file */
2373 char filename[1024], /* passwd.md5 filename */
2374 line[256], /* Line from file */
2375 tempuser[33], /* User from file */
2376 tempgroup[33]; /* Group from file */
2377
2378
2379 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2380 "get_md5_password(username=\"%s\", group=\"%s\", passwd=%p)",
2381 username, group ? group : "(null)", passwd);
2382
2383 snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
2384 if ((fp = cupsFileOpen(filename, "r")) == NULL)
2385 {
2386 if (errno != ENOENT)
2387 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename,
2388 strerror(errno));
2389
2390 return (NULL);
2391 }
2392
2393 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
2394 {
2395 if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
2396 {
2397 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line);
2398 continue;
2399 }
2400
2401 if (!strcmp(username, tempuser) &&
2402 (group == NULL || !strcmp(group, tempgroup)))
2403 {
2404 /*
2405 * Found the password entry!
2406 */
2407
2408 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
2409 username, tempgroup);
2410
2411 cupsFileClose(fp);
2412 return (passwd);
2413 }
2414 }
2415
2416 /*
2417 * Didn't find a password entry - return NULL!
2418 */
2419
2420 cupsFileClose(fp);
2421 return (NULL);
2422 }
2423
2424
2425 #if HAVE_LIBPAM
2426 /*
2427 * 'pam_func()' - PAM conversation function.
2428 */
2429
2430 static int /* O - Success or failure */
2431 pam_func(
2432 int num_msg, /* I - Number of messages */
2433 const struct pam_message **msg, /* I - Messages */
2434 struct pam_response **resp, /* O - Responses */
2435 void *appdata_ptr)
2436 /* I - Pointer to connection */
2437 {
2438 int i; /* Looping var */
2439 struct pam_response *replies; /* Replies */
2440 cupsd_authdata_t *data; /* Pointer to auth data */
2441
2442
2443 /*
2444 * Allocate memory for the responses...
2445 */
2446
2447 if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
2448 return (PAM_CONV_ERR);
2449
2450 /*
2451 * Answer all of the messages...
2452 */
2453
2454 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
2455
2456 #ifdef __hpux
2457 /*
2458 * Apparently some versions of HP-UX 11 have a broken pam_unix security
2459 * module. This is a workaround...
2460 */
2461
2462 data = auth_data;
2463 (void)appdata_ptr;
2464 #else
2465 data = (cupsd_authdata_t *)appdata_ptr;
2466 #endif /* __hpux */
2467
2468 for (i = 0; i < num_msg; i ++)
2469 {
2470 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
2471
2472 switch (msg[i]->msg_style)
2473 {
2474 case PAM_PROMPT_ECHO_ON:
2475 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2476 data->username));
2477 replies[i].resp_retcode = PAM_SUCCESS;
2478 replies[i].resp = strdup(data->username);
2479 break;
2480
2481 case PAM_PROMPT_ECHO_OFF:
2482 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2483 data->password));
2484 replies[i].resp_retcode = PAM_SUCCESS;
2485 replies[i].resp = strdup(data->password);
2486 break;
2487
2488 case PAM_TEXT_INFO:
2489 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2490 replies[i].resp_retcode = PAM_SUCCESS;
2491 replies[i].resp = NULL;
2492 break;
2493
2494 case PAM_ERROR_MSG:
2495 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2496 replies[i].resp_retcode = PAM_SUCCESS;
2497 replies[i].resp = NULL;
2498 break;
2499
2500 default:
2501 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2502 msg[i]->msg_style));
2503 free(replies);
2504 return (PAM_CONV_ERR);
2505 }
2506 }
2507
2508 /*
2509 * Return the responses back to PAM...
2510 */
2511
2512 *resp = replies;
2513
2514 return (PAM_SUCCESS);
2515 }
2516 #elif !defined(HAVE_USERSEC_H)
2517
2518
2519 /*
2520 * 'to64()' - Base64-encode an integer value...
2521 */
2522
2523 static void
2524 to64(char *s, /* O - Output string */
2525 unsigned long v, /* I - Value to encode */
2526 int n) /* I - Number of digits */
2527 {
2528 const char *itoa64 = "./0123456789"
2529 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2530 "abcdefghijklmnopqrstuvwxyz";
2531
2532
2533 for (; n > 0; n --, v >>= 6)
2534 *s++ = itoa64[v & 0x3f];
2535 }
2536 #endif /* HAVE_LIBPAM */
2537
2538
2539 /*
2540 * End of "$Id: auth.c 6397 2007-03-25 23:33:32Z mike $".
2541 */