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