]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/auth.c
fc0e2d809c8423b1d71e8577f8faa9acafddabdc
[thirdparty/cups.git] / scheduler / auth.c
1 /*
2 * "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $"
3 *
4 * Authorization routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * AddLocation() - Add a location for authorization.
27 * AddName() - Add a name to a location...
28 * AllowHost() - Add a host name that is allowed to access the
29 * location.
30 * AllowIP() - Add an IP address or network that is allowed to
31 * access the location.
32 * CheckAuth() - Check authorization masks.
33 * CopyLocation() - Make a copy of a location...
34 * DeleteAllLocations() - Free all memory used for location authorization.
35 * DenyHost() - Add a host name that is not allowed to access the
36 * location.
37 * DenyIP() - Add an IP address or network that is not allowed
38 * to access the location.
39 * FindBest() - Find the location entry that best matches the
40 * resource.
41 * FindLocation() - Find the named location.
42 * IsAuthorized() - Check to see if the user is authorized...
43 * add_allow() - Add an allow mask to the location.
44 * add_deny() - Add a deny mask to the location.
45 * get_md5_passwd() - Get an MD5 password.
46 * pam_func() - PAM conversation function.
47 */
48
49 /*
50 * Include necessary headers...
51 */
52
53 #include "cupsd.h"
54 #include <pwd.h>
55 #include <grp.h>
56 #ifdef HAVE_SHADOW_H
57 # include <shadow.h>
58 #endif /* HAVE_SHADOW_H */
59 #ifdef HAVE_CRYPT_H
60 # include <crypt.h>
61 #endif /* HAVE_CRYPT_H */
62 #if HAVE_LIBPAM
63 # include <security/pam_appl.h>
64 #endif /* HAVE_LIBPAM */
65 #ifdef HAVE_USERSEC_H
66 # include <usersec.h>
67 #endif /* HAVE_USERSEC_H */
68
69
70 /*
71 * Local functions...
72 */
73
74 static authmask_t *add_allow(location_t *loc);
75 static authmask_t *add_deny(location_t *loc);
76 static char *get_md5_passwd(const char *username, const char *group,
77 char passwd[33]);
78 #if HAVE_LIBPAM
79 static int pam_func(int, const struct pam_message **,
80 struct pam_response **, void *);
81 #endif /* HAVE_LIBPAM */
82
83
84 /*
85 * Local globals...
86 */
87
88 #ifdef __hpux
89 static client_t *auth_client; /* Current client being authenticated */
90 #endif /* __hpux */
91
92
93 /*
94 * 'AddLocation()' - Add a location for authorization.
95 */
96
97 location_t * /* O - Pointer to new location record */
98 AddLocation(const char *location) /* I - Location path */
99 {
100 location_t *temp; /* New location */
101
102
103 /*
104 * Try to allocate memory for the new location.
105 */
106
107 if (NumLocations == 0)
108 temp = malloc(sizeof(location_t));
109 else
110 temp = realloc(Locations, sizeof(location_t) * (NumLocations + 1));
111
112 if (temp == NULL)
113 return (NULL);
114
115 Locations = temp;
116 temp += NumLocations;
117 NumLocations ++;
118
119 /*
120 * Initialize the record and copy the name over...
121 */
122
123 memset(temp, 0, sizeof(location_t));
124 strncpy(temp->location, location, sizeof(temp->location) - 1);
125 temp->length = strlen(temp->location);
126
127 LogMessage(L_DEBUG, "AddLocation: added location \'%s\'", location);
128
129 /*
130 * Return the new record...
131 */
132
133 return (temp);
134 }
135
136
137 /*
138 * 'AddName()' - Add a name to a location...
139 */
140
141 void
142 AddName(location_t *loc, /* I - Location to add to */
143 char *name) /* I - Name to add */
144 {
145 char **temp; /* Pointer to names array */
146
147
148 if (loc->num_names == 0)
149 temp = malloc(sizeof(char *));
150 else
151 temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
152
153 if (temp == NULL)
154 {
155 LogMessage(L_ERROR, "Unable to add name to location %s: %s", loc->location,
156 strerror(errno));
157 return;
158 }
159
160 loc->names = temp;
161
162 if ((temp[loc->num_names] = strdup(name)) == NULL)
163 {
164 LogMessage(L_ERROR, "Unable to duplicate name for location %s: %s",
165 loc->location, strerror(errno));
166 return;
167 }
168
169 loc->num_names ++;
170 }
171
172
173 /*
174 * 'AllowHost()' - Add a host name that is allowed to access the location.
175 */
176
177 void
178 AllowHost(location_t *loc, /* I - Location to add to */
179 char *name) /* I - Name of host or domain to add */
180 {
181 authmask_t *temp; /* New host/domain mask */
182
183
184 if ((temp = add_allow(loc)) == NULL)
185 return;
186
187 temp->type = AUTH_NAME;
188 temp->mask.name.name = strdup(name);
189 temp->mask.name.length = strlen(name);
190
191 LogMessage(L_DEBUG, "AllowHost: %s allow %s", loc->location, name);
192 }
193
194
195 /*
196 * 'AllowIP()' - Add an IP address or network that is allowed to access the
197 * location.
198 */
199
200 void
201 AllowIP(location_t *loc, /* I - Location to add to */
202 unsigned address[4], /* I - IP address to add */
203 unsigned netmask[4]) /* I - Netmask of address */
204 {
205 authmask_t *temp; /* New host/domain mask */
206
207
208 if ((temp = add_allow(loc)) == NULL)
209 return;
210
211 temp->type = AUTH_IP;
212 memcpy(temp->mask.ip.address, address, sizeof(address));
213 memcpy(temp->mask.ip.netmask, netmask, sizeof(netmask));
214
215 LogMessage(L_DEBUG, "AllowIP: %s allow %08x/%08x", loc->location,
216 address, netmask);
217 }
218
219
220 /*
221 * 'CheckAuth()' - Check authorization masks.
222 */
223
224 int /* O - 1 if mask matches, 0 otherwise */
225 CheckAuth(unsigned ip[4], /* I - Client address */
226 char *name, /* I - Client hostname */
227 int name_len, /* I - Length of hostname */
228 int num_masks, /* I - Number of masks */
229 authmask_t *masks) /* I - Masks */
230 {
231 int i; /* Looping var */
232
233
234 while (num_masks > 0)
235 {
236 switch (masks->type)
237 {
238 case AUTH_NAME :
239 /*
240 * Check for exact name match...
241 */
242
243 if (strcasecmp(name, masks->mask.name.name) == 0)
244 return (1);
245
246 /*
247 * Check for domain match...
248 */
249
250 if (name_len >= masks->mask.name.length &&
251 masks->mask.name.name[0] == '.' &&
252 strcasecmp(name + name_len - masks->mask.name.length,
253 masks->mask.name.name) == 0)
254 return (1);
255 break;
256
257 case AUTH_IP :
258 /*
259 * Check for IP/network address match...
260 */
261
262 for (i = 0; i < 4; i ++)
263 if ((ip[i] & masks->mask.ip.netmask[i]) != masks->mask.ip.address[i])
264 break;
265
266 if (i == 4)
267 return (1);
268 break;
269 }
270
271 masks ++;
272 num_masks --;
273 }
274
275 return (0);
276 }
277
278
279 /*
280 * 'CopyLocation()' - Make a copy of a location...
281 */
282
283 location_t * /* O - New location */
284 CopyLocation(location_t **loc) /* IO - Original location */
285 {
286 int i; /* Looping var */
287 int locindex; /* Index into Locations array */
288 location_t *temp; /* New location */
289
290
291 /*
292 * Add the new location, updating the original location
293 * pointer as needed...
294 */
295
296 locindex = *loc - Locations;
297
298 if ((temp = AddLocation((*loc)->location)) == NULL)
299 return (NULL);
300
301 *loc = Locations + locindex;
302
303 /*
304 * Copy the information from the original location to the new one.
305 */
306
307 temp->limit = (*loc)->limit;
308 temp->order_type = (*loc)->order_type;
309 temp->type = (*loc)->type;
310 temp->level = (*loc)->level;
311 temp->satisfy = (*loc)->satisfy;
312 temp->encryption = (*loc)->encryption;
313
314 if ((temp->num_names = (*loc)->num_names) > 0)
315 {
316 /*
317 * Copy the names array...
318 */
319
320 if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
321 {
322 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d names: %s",
323 temp->num_names, strerror(errno));
324 NumLocations --;
325 return (NULL);
326 }
327
328 for (i = 0; i < temp->num_names; i ++)
329 if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
330 {
331 LogMessage(L_ERROR, "CopyLocation: Unable to copy name \"%s\": %s",
332 (*loc)->names[i], strerror(errno));
333
334 NumLocations --;
335 return (NULL);
336 }
337 }
338
339 if ((temp->num_allow = (*loc)->num_allow) > 0)
340 {
341 /*
342 * Copy allow rules...
343 */
344
345 if ((temp->allow = calloc(temp->num_allow, sizeof(authmask_t))) == NULL)
346 {
347 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
348 temp->num_allow, strerror(errno));
349 NumLocations --;
350 return (NULL);
351 }
352
353 for (i = 0; i < temp->num_allow; i ++)
354 switch (temp->allow[i].type = (*loc)->allow[i].type)
355 {
356 case AUTH_NAME :
357 temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
358 temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
359
360 if (temp->allow[i].mask.name.name == NULL)
361 {
362 LogMessage(L_ERROR, "CopyLocation: Unable to copy allow name \"%s\": %s",
363 (*loc)->allow[i].mask.name.name, strerror(errno));
364 NumLocations --;
365 return (NULL);
366 }
367 break;
368 case AUTH_IP :
369 memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
370 sizeof(ipmask_t));
371 break;
372 }
373 }
374
375 if ((temp->num_deny = (*loc)->num_deny) > 0)
376 {
377 /*
378 * Copy deny rules...
379 */
380
381 if ((temp->deny = calloc(temp->num_deny, sizeof(authmask_t))) == NULL)
382 {
383 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
384 temp->num_deny, strerror(errno));
385 NumLocations --;
386 return (NULL);
387 }
388
389 for (i = 0; i < temp->num_deny; i ++)
390 switch (temp->deny[i].type = (*loc)->deny[i].type)
391 {
392 case AUTH_NAME :
393 temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
394 temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
395
396 if (temp->deny[i].mask.name.name == NULL)
397 {
398 LogMessage(L_ERROR, "CopyLocation: Unable to copy deny name \"%s\": %s",
399 (*loc)->deny[i].mask.name.name, strerror(errno));
400 NumLocations --;
401 return (NULL);
402 }
403 break;
404 case AUTH_IP :
405 memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
406 sizeof(ipmask_t));
407 break;
408 }
409 }
410
411 return (temp);
412 }
413
414
415 /*
416 * 'DeleteAllLocations()' - Free all memory used for location authorization.
417 */
418
419 void
420 DeleteAllLocations(void)
421 {
422 int i, j; /* Looping vars */
423 location_t *loc; /* Current location */
424 authmask_t *mask; /* Current mask */
425
426
427 /*
428 * Free all of the allow/deny records first...
429 */
430
431 for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
432 {
433 for (j = loc->num_names - 1; j >= 0; j --)
434 free(loc->names[j]);
435
436 if (loc->num_names > 0)
437 free(loc->names);
438
439 for (j = loc->num_allow, mask = loc->allow; j > 0; j --, mask ++)
440 if (mask->type == AUTH_NAME)
441 free(mask->mask.name.name);
442
443 if (loc->num_allow > 0)
444 free(loc->allow);
445
446 for (j = loc->num_deny, mask = loc->deny; j > 0; j --, mask ++)
447 if (mask->type == AUTH_NAME)
448 free(mask->mask.name.name);
449
450 if (loc->num_deny > 0)
451 free(loc->deny);
452 }
453
454 /*
455 * Then free the location array...
456 */
457
458 if (NumLocations > 0)
459 free(Locations);
460
461 Locations = NULL;
462 NumLocations = 0;
463 }
464
465
466 /*
467 * 'DenyHost()' - Add a host name that is not allowed to access the location.
468 */
469
470 void
471 DenyHost(location_t *loc, /* I - Location to add to */
472 char *name) /* I - Name of host or domain to add */
473 {
474 authmask_t *temp; /* New host/domain mask */
475
476
477 if ((temp = add_deny(loc)) == NULL)
478 return;
479
480 temp->type = AUTH_NAME;
481 temp->mask.name.name = strdup(name);
482 temp->mask.name.length = strlen(name);
483
484 LogMessage(L_DEBUG, "DenyHost: %s deny %s", loc->location, name);
485 }
486
487
488 /*
489 * 'DenyIP()' - Add an IP address or network that is not allowed to access
490 * the location.
491 */
492
493 void
494 DenyIP(location_t *loc, /* I - Location to add to */
495 unsigned address[4], /* I - IP address to add */
496 unsigned netmask[4]) /* I - Netmask of address */
497 {
498 authmask_t *temp; /* New host/domain mask */
499
500
501 if ((temp = add_deny(loc)) == NULL)
502 return;
503
504 temp->type = AUTH_IP;
505 memcpy(temp->mask.ip.address, address, sizeof(address));
506 memcpy(temp->mask.ip.netmask, netmask, sizeof(netmask));
507
508 LogMessage(L_DEBUG, "DenyIP: %s deny %08x/%08x\n", loc->location,
509 address, netmask);
510 }
511
512
513 /*
514 * 'FindBest()' - Find the location entry that best matches the resource.
515 */
516
517 location_t * /* O - Location that matches */
518 FindBest(client_t *con) /* I - Connection */
519 {
520 int i; /* Looping var */
521 location_t *loc, /* Current location */
522 *best; /* Best match for location so far */
523 int bestlen; /* Length of best match */
524 int limit; /* Limit field */
525 static int limits[] = /* Map http_status_t to AUTH_LIMIT_xyz */
526 {
527 AUTH_LIMIT_ALL,
528 AUTH_LIMIT_OPTIONS,
529 AUTH_LIMIT_GET,
530 AUTH_LIMIT_GET,
531 AUTH_LIMIT_HEAD,
532 AUTH_LIMIT_POST,
533 AUTH_LIMIT_POST,
534 AUTH_LIMIT_POST,
535 AUTH_LIMIT_PUT,
536 AUTH_LIMIT_PUT,
537 AUTH_LIMIT_DELETE,
538 AUTH_LIMIT_TRACE,
539 AUTH_LIMIT_ALL,
540 AUTH_LIMIT_ALL
541 };
542
543
544 /*
545 * Loop through the list of locations to find a match...
546 */
547
548 limit = limits[con->http.state];
549 best = NULL;
550 bestlen = 0;
551
552 for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
553 {
554 LogMessage(L_DEBUG2, "FindBest: Location %s Limit %x",
555 loc->location, loc->limit);
556
557 if (loc->length > bestlen &&
558 strncmp(con->uri, loc->location, loc->length) == 0 &&
559 loc->location[0] == '/' &&
560 (limit & loc->limit) != 0)
561 {
562 best = loc;
563 bestlen = loc->length;
564 }
565 }
566
567 /*
568 * Return the match, if any...
569 */
570
571 LogMessage(L_DEBUG2, "FindBest: best = %s", best ? best->location : "NONE");
572
573 return (best);
574 }
575
576
577 /*
578 * 'FindLocation()' - Find the named location.
579 */
580
581 location_t * /* O - Location that matches */
582 FindLocation(const char *location) /* I - Connection */
583 {
584 int i; /* Looping var */
585
586
587 /*
588 * Loop through the list of locations to find a match...
589 */
590
591 for (i = 0; i < NumLocations; i ++)
592 if (strcasecmp(Locations[i].location, location) == 0)
593 return (Locations + i);
594
595 return (NULL);
596 }
597
598
599 /*
600 * 'IsAuthorized()' - Check to see if the user is authorized...
601 */
602
603 http_status_t /* O - HTTP_OK if authorized or error code */
604 IsAuthorized(client_t *con) /* I - Connection */
605 {
606 int i, j, /* Looping vars */
607 auth; /* Authorization status */
608 unsigned address[4]; /* Authorization address */
609 location_t *best; /* Best match for location so far */
610 int hostlen; /* Length of hostname */
611 struct passwd *pw; /* User password data */
612 struct group *grp; /* Group data */
613 char nonce[HTTP_MAX_VALUE],
614 /* Nonce value from client */
615 md5[33]; /* MD5 password */
616 #if HAVE_LIBPAM
617 pam_handle_t *pamh; /* PAM authentication handle */
618 int pamerr; /* PAM error code */
619 struct pam_conv pamdata; /* PAM conversation data */
620 #elif defined(HAVE_USERSEC_H)
621 char *authmsg; /* Authentication message */
622 char *loginmsg; /* Login message */
623 int reenter; /* ??? */
624 #else
625 char *pass; /* Encrypted password */
626 # ifdef HAVE_SHADOW_H
627 struct spwd *spw; /* Shadow password data */
628 # endif /* HAVE_SHADOW_H */
629 #endif /* HAVE_LIBPAM */
630 static const char *states[] = /* HTTP client states... */
631 {
632 "WAITING",
633 "OPTIONS",
634 "GET",
635 "GET",
636 "HEAD",
637 "POST",
638 "POST",
639 "POST",
640 "PUT",
641 "PUT",
642 "DELETE",
643 "TRACE",
644 "CLOSE",
645 "STATUS"
646 };
647
648
649 LogMessage(L_DEBUG2, "IsAuthorized: URI = %s", con->uri);
650
651 /*
652 * Find a matching location; if there is no match then access is
653 * not authorized...
654 */
655
656 if ((best = FindBest(con)) == NULL)
657 return (HTTP_FORBIDDEN);
658
659 /*
660 * Check host/ip-based accesses...
661 */
662
663 #ifdef AF_INET6
664 if (con->http.hostaddr.addr.sa_family == AF_INET6)
665 {
666 address[0] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[0]);
667 address[1] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[1]);
668 address[2] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[2]);
669 address[3] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[3]);
670 }
671 else
672 #endif /* AF_INET6 */
673 if (con->http.hostaddr.addr.sa_family == AF_INET)
674 {
675 unsigned temp; /* Temporary address variable */
676
677
678 /*
679 * Convert 32-bit IPv4 address to 128 bits...
680 */
681
682 temp = ntohl(con->http.hostaddr.ipv4.sin_addr.s_addr);
683
684 address[3] = temp & 255;
685 temp >>= 8;
686 address[2] = temp & 255;
687 temp >>= 8;
688 address[1] = temp & 255;
689 temp >>= 8;
690 address[0] = temp & 255;
691 }
692 else
693 memset(address, 0, sizeof(address));
694
695 hostlen = strlen(con->http.hostname);
696
697 if (strcasecmp(con->http.hostname, "localhost") == 0)
698 {
699 /*
700 * Access from localhost (127.0.0.1 or 0.0.0.1) is always allowed...
701 */
702
703 auth = AUTH_ALLOW;
704 }
705 else
706 {
707 /*
708 * Do authorization checks on the domain/address...
709 */
710
711 switch (best->order_type)
712 {
713 default :
714 auth = AUTH_DENY; /* anti-compiler-warning-code */
715 break;
716
717 case AUTH_ALLOW : /* Order Deny,Allow */
718 auth = AUTH_ALLOW;
719
720 if (CheckAuth(address, con->http.hostname, hostlen,
721 best->num_deny, best->deny))
722 auth = AUTH_DENY;
723
724 if (CheckAuth(address, con->http.hostname, hostlen,
725 best->num_allow, best->allow))
726 auth = AUTH_ALLOW;
727 break;
728
729 case AUTH_DENY : /* Order Allow,Deny */
730 auth = AUTH_DENY;
731
732 if (CheckAuth(address, con->http.hostname, hostlen,
733 best->num_allow, best->allow))
734 auth = AUTH_ALLOW;
735
736 if (CheckAuth(address, con->http.hostname, hostlen,
737 best->num_deny, best->deny))
738 auth = AUTH_DENY;
739 break;
740 }
741 }
742
743 LogMessage(L_DEBUG2, "IsAuthorized: auth = %d, satisfy=%d...",
744 auth, best->satisfy);
745
746 if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
747 return (HTTP_FORBIDDEN);
748
749 #ifdef HAVE_LIBSSL
750 /*
751 * See if encryption is required...
752 */
753
754 if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
755 {
756 LogMessage(L_DEBUG2, "IsAuthorized: Need upgrade to TLS...");
757 return (HTTP_UPGRADE_REQUIRED);
758 }
759 #endif /* HAVE_LIBSSL */
760
761 /*
762 * Now see what access level is required...
763 */
764
765 if (best->level == AUTH_ANON) /* Anonymous access - allow it */
766 return (HTTP_OK);
767
768 LogMessage(L_DEBUG2, "IsAuthorized: username = \"%s\" password = %d chars",
769 con->username, strlen(con->password));
770 DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
771 con->username, con->password));
772
773 if (con->username[0] == '\0')
774 {
775 if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
776 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
777 else
778 return (HTTP_OK); /* unless overridden with Satisfy */
779 }
780
781 /*
782 * Check the user's password...
783 */
784
785 pw = getpwnam(con->username); /* Get the current password */
786 endpwent(); /* Close the password file */
787
788 if (pw == NULL) /* No such user... */
789 {
790 LogMessage(L_WARN, "IsAuthorized: Unknown username \"%s\"; access denied.",
791 con->username);
792 return (HTTP_UNAUTHORIZED);
793 }
794
795 LogMessage(L_DEBUG2, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
796 con->username, address, con->http.hostname);
797
798 if (strcasecmp(con->http.hostname, "localhost") != 0 ||
799 strncmp(con->http.fields[HTTP_FIELD_AUTHORIZATION], "Local", 5) != 0)
800 {
801 /*
802 * Not doing local certificate-based authentication; check the password...
803 */
804
805 if (!con->password[0])
806 return (HTTP_UNAUTHORIZED);
807
808 /*
809 * See if we are doing Digest or Basic authentication...
810 */
811
812 if (best->type == AUTH_BASIC)
813 {
814 #if HAVE_LIBPAM
815 /*
816 * Only use PAM to do authentication. This allows MD5 passwords, among
817 * other things...
818 */
819
820 pamdata.conv = pam_func;
821 pamdata.appdata_ptr = con;
822
823 # ifdef __hpux
824 /*
825 * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
826 * more info...
827 */
828
829 auth_client = con;
830 # endif /* __hpux */
831
832 DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
833
834 pamerr = pam_start("cups", con->username, &pamdata, &pamh);
835 if (pamerr != PAM_SUCCESS)
836 {
837 LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
838 pamerr, pam_strerror(pamh, pamerr));
839 pam_end(pamh, 0);
840 return (HTTP_UNAUTHORIZED);
841 }
842
843 pamerr = pam_authenticate(pamh, PAM_SILENT);
844 if (pamerr != PAM_SUCCESS)
845 {
846 LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
847 pamerr, pam_strerror(pamh, pamerr));
848 pam_end(pamh, 0);
849 return (HTTP_UNAUTHORIZED);
850 }
851
852 pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
853 if (pamerr != PAM_SUCCESS)
854 {
855 LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
856 pamerr, pam_strerror(pamh, pamerr));
857 pam_end(pamh, 0);
858 return (HTTP_UNAUTHORIZED);
859 }
860
861 pam_end(pamh, PAM_SUCCESS);
862 #elif defined(HAVE_USERSEC_H)
863 /*
864 * Use AIX authentication interface...
865 */
866
867 LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
868 con->username);
869
870 reenter = 1;
871 if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
872 {
873 LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
874 con->username, strerror(errno));
875 return (HTTP_UNAUTHORIZED);
876 }
877 #else
878 # ifdef HAVE_SHADOW_H
879 spw = getspnam(con->username);
880 endspent();
881
882 if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
883 { /* Don't allow blank passwords! */
884 LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
885 con->username);
886 return (HTTP_UNAUTHORIZED); /* No such user or bad shadow file */
887 }
888
889 # ifdef DEBUG
890 if (spw != NULL)
891 printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
892 else
893 puts("spw = NULL");
894 # endif /* DEBUG */
895
896 if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
897 # else
898 if (pw->pw_passwd[0] == '\0') /* Don't allow blank passwords! */
899 # endif /* HAVE_SHADOW_H */
900 { /* Don't allow blank passwords! */
901 LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
902 con->username);
903 return (HTTP_UNAUTHORIZED);
904 }
905
906 /*
907 * OK, the password isn't blank, so compare with what came from the client...
908 */
909
910 LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
911 pw->pw_passwd, crypt(con->password, pw->pw_passwd));
912
913 pass = crypt(con->password, pw->pw_passwd);
914
915 if (pass == NULL ||
916 strcmp(pw->pw_passwd, crypt(con->password, pw->pw_passwd)) != 0)
917 {
918 # ifdef HAVE_SHADOW_H
919 if (spw != NULL)
920 {
921 LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
922 spw->sp_pwdp, crypt(con->password, spw->sp_pwdp));
923
924 pass = crypt(con->password, spw->sp_pwdp);
925
926 if (pass == NULL ||
927 strcmp(spw->sp_pwdp, crypt(con->password, spw->sp_pwdp)) != 0)
928 return (HTTP_UNAUTHORIZED);
929 }
930 else
931 # endif /* HAVE_SHADOW_H */
932 return (HTTP_UNAUTHORIZED);
933 }
934 #endif /* HAVE_LIBPAM */
935 }
936 else
937 {
938 /*
939 * Do Digest authentication...
940 */
941
942 if (!httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "nonce",
943 nonce))
944 {
945 LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
946 return (HTTP_UNAUTHORIZED);
947 }
948
949 if (strcmp(con->http.hostname, nonce) != 0)
950 {
951 LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
952 LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
953 con->http.hostname);
954 LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
955 return (HTTP_UNAUTHORIZED);
956 }
957
958 if (!get_md5_passwd(con->username, best->names[0], md5))
959 {
960 LogMessage(L_ERROR, "IsAuthorized: No user:group for \"%s:%s\" in passwd.md5!",
961 con->username, best->names[0]);
962 return (HTTP_UNAUTHORIZED);
963 }
964
965 httpMD5Final(nonce, states[con->http.state], con->uri, md5);
966
967 if (strcmp(md5, con->password) != 0)
968 {
969 LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
970 md5, con->password);
971 return (HTTP_UNAUTHORIZED);
972 }
973 }
974 }
975
976 /*
977 * OK, the password is good. See if we need normal user access, or group
978 * access... (root always matches)
979 */
980
981 if (strcmp(con->username, "root") == 0)
982 return (HTTP_OK);
983
984 if (best->level == AUTH_USER)
985 {
986 /*
987 * If there are no names associated with this location, then
988 * any valid user is OK...
989 */
990
991 LogMessage(L_DEBUG2, "IsAuthorized: Checking user membership...");
992
993 if (best->num_names == 0)
994 return (HTTP_OK);
995
996 /*
997 * Otherwise check the user list and return OK if this user is
998 * allowed...
999 */
1000
1001 for (i = 0; i < best->num_names; i ++)
1002 if (strcmp(con->username, best->names[i]) == 0)
1003 return (HTTP_OK);
1004
1005 return (HTTP_UNAUTHORIZED);
1006 }
1007
1008 /*
1009 * Check to see if this user is in any of the named groups...
1010 */
1011
1012 LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
1013
1014 for (i = 0; i < best->num_names; i ++)
1015 {
1016 grp = getgrnam(best->names[i]);
1017 endgrent();
1018
1019 if (grp == NULL) /* No group by that name??? */
1020 {
1021 LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
1022 best->names[i]);
1023 return (HTTP_FORBIDDEN);
1024 }
1025
1026 for (j = 0; grp->gr_mem[j] != NULL; j ++)
1027 if (strcmp(con->username, grp->gr_mem[j]) == 0)
1028 return (HTTP_OK);
1029
1030 /*
1031 * Check to see if the default group ID matches for the user...
1032 */
1033
1034 if (grp->gr_gid == pw->pw_gid)
1035 return (HTTP_OK);
1036 }
1037
1038 /*
1039 * The user isn't part of the specified group, so deny access...
1040 */
1041
1042 LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
1043
1044 return (HTTP_UNAUTHORIZED);
1045 }
1046
1047
1048 /*
1049 * 'add_allow()' - Add an allow mask to the location.
1050 */
1051
1052 static authmask_t * /* O - New mask record */
1053 add_allow(location_t *loc) /* I - Location to add to */
1054 {
1055 authmask_t *temp; /* New mask record */
1056
1057
1058 /*
1059 * Range-check...
1060 */
1061
1062 if (loc == NULL)
1063 return (NULL);
1064
1065 /*
1066 * Try to allocate memory for the record...
1067 */
1068
1069 if (loc->num_allow == 0)
1070 temp = malloc(sizeof(authmask_t));
1071 else
1072 temp = realloc(loc->allow, sizeof(authmask_t) * (loc->num_allow + 1));
1073
1074 if (temp == NULL)
1075 return (NULL);
1076
1077 loc->allow = temp;
1078 temp += loc->num_allow;
1079 loc->num_allow ++;
1080
1081 /*
1082 * Clear the mask record and return...
1083 */
1084
1085 memset(temp, 0, sizeof(authmask_t));
1086 return (temp);
1087 }
1088
1089
1090 /*
1091 * 'add_deny()' - Add a deny mask to the location.
1092 */
1093
1094 static authmask_t * /* O - New mask record */
1095 add_deny(location_t *loc) /* I - Location to add to */
1096 {
1097 authmask_t *temp; /* New mask record */
1098
1099
1100 /*
1101 * Range-check...
1102 */
1103
1104 if (loc == NULL)
1105 return (NULL);
1106
1107 /*
1108 * Try to allocate memory for the record...
1109 */
1110
1111 if (loc->num_deny == 0)
1112 temp = malloc(sizeof(authmask_t));
1113 else
1114 temp = realloc(loc->deny, sizeof(authmask_t) * (loc->num_deny + 1));
1115
1116 if (temp == NULL)
1117 return (NULL);
1118
1119 loc->deny = temp;
1120 temp += loc->num_deny;
1121 loc->num_deny ++;
1122
1123 /*
1124 * Clear the mask record and return...
1125 */
1126
1127 memset(temp, 0, sizeof(authmask_t));
1128 return (temp);
1129 }
1130
1131
1132 /*
1133 * 'get_md5_passwd()' - Get an MD5 password.
1134 */
1135
1136 static char * /* O - MD5 password string */
1137 get_md5_passwd(const char *username, /* I - Username */
1138 const char *group, /* I - Group */
1139 char passwd[33]) /* O - MD5 password string */
1140 {
1141 FILE *fp; /* passwd.md5 file */
1142 char filename[1024], /* passwd.md5 filename */
1143 line[256], /* Line from file */
1144 tempuser[33], /* User from file */
1145 tempgroup[33]; /* Group from file */
1146
1147
1148 snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
1149 if ((fp = fopen(filename, "r")) == NULL)
1150 return (NULL);
1151
1152 while (fgets(line, sizeof(line), fp) != NULL)
1153 {
1154 if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
1155 continue;
1156
1157 if (strcmp(username, tempuser) == 0 &&
1158 strcmp(group, tempgroup) == 0)
1159 {
1160 /*
1161 * Found the password entry!
1162 */
1163
1164 fclose(fp);
1165 return (passwd);
1166 }
1167 }
1168
1169 /*
1170 * Didn't find a password entry - return NULL!
1171 */
1172
1173 fclose(fp);
1174 return (NULL);
1175 }
1176
1177
1178 #if HAVE_LIBPAM
1179 /*
1180 * 'pam_func()' - PAM conversation function.
1181 */
1182
1183 static int /* O - Success or failure */
1184 pam_func(int num_msg, /* I - Number of messages */
1185 const struct pam_message **msg, /* I - Messages */
1186 struct pam_response **resp, /* O - Responses */
1187 void *appdata_ptr) /* I - Pointer to connection */
1188 {
1189 int i; /* Looping var */
1190 struct pam_response *replies; /* Replies */
1191 client_t *client; /* Pointer client connection */
1192
1193
1194 /*
1195 * Allocate memory for the responses...
1196 */
1197
1198 if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
1199 return (PAM_CONV_ERR);
1200
1201 /*
1202 * Answer all of the messages...
1203 */
1204
1205 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
1206
1207 #ifdef __hpux
1208 /*
1209 * Apparently some versions of HP-UX 11 have a broken pam_unix security
1210 * module. This is a workaround...
1211 */
1212
1213 client = auth_client;
1214 (void)appdata_ptr;
1215 #else
1216 client = (client_t *)appdata_ptr;
1217 #endif /* __hpux */
1218
1219 for (i = 0; i < num_msg; i ++)
1220 {
1221 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
1222
1223 switch (msg[i]->msg_style)
1224 {
1225 case PAM_PROMPT_ECHO_ON:
1226 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
1227 client->username));
1228 replies[i].resp_retcode = PAM_SUCCESS;
1229 replies[i].resp = strdup(client->username);
1230 break;
1231
1232 case PAM_PROMPT_ECHO_OFF:
1233 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
1234 client->password));
1235 replies[i].resp_retcode = PAM_SUCCESS;
1236 replies[i].resp = strdup(client->password);
1237 break;
1238
1239 case PAM_TEXT_INFO:
1240 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
1241 replies[i].resp_retcode = PAM_SUCCESS;
1242 replies[i].resp = NULL;
1243 break;
1244
1245 case PAM_ERROR_MSG:
1246 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
1247 replies[i].resp_retcode = PAM_SUCCESS;
1248 replies[i].resp = NULL;
1249 break;
1250
1251 default:
1252 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
1253 msg[i]->msg_style));
1254 free(replies);
1255 return (PAM_CONV_ERR);
1256 }
1257 }
1258
1259 /*
1260 * Return the responses back to PAM...
1261 */
1262
1263 *resp = replies;
1264
1265 return (PAM_SUCCESS);
1266 }
1267 #endif /* HAVE_LIBPAM */
1268
1269
1270 /*
1271 * End of "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $".
1272 */