]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/auth.c
ff14770293c164ee64dff206568da228b03fe4d6
[thirdparty/cups.git] / scheduler / auth.c
1 /*
2 * "$Id: auth.c,v 1.70 2003/04/10 12:57:43 mike Exp $"
3 *
4 * Authorization routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 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 * GetMD5Passwd() - Get an MD5 password.
43 * IsAuthorized() - Check to see if the user is authorized...
44 * add_allow() - Add an allow mask to the location.
45 * add_deny() - Add a deny mask to the location.
46 * cups_crypt() - Encrypt the password using the DES or MD5
47 * algorithms, as needed.
48 * pam_func() - PAM conversation function.
49 * to64() - Base64-encode an integer value...
50 */
51
52 /*
53 * Include necessary headers...
54 */
55
56 #include "cupsd.h"
57 #include <pwd.h>
58 #include <grp.h>
59 #include <cups/md5.h>
60 #ifdef HAVE_SHADOW_H
61 # include <shadow.h>
62 #endif /* HAVE_SHADOW_H */
63 #ifdef HAVE_CRYPT_H
64 # include <crypt.h>
65 #endif /* HAVE_CRYPT_H */
66 #if HAVE_LIBPAM
67 # ifdef HAVE_PAM_PAM_APPL_H
68 # include <pam/pam_appl.h>
69 # else
70 # include <security/pam_appl.h>
71 # endif /* HAVE_PAM_PAM_APPL_H */
72 #endif /* HAVE_LIBPAM */
73 #ifdef HAVE_USERSEC_H
74 # include <usersec.h>
75 #endif /* HAVE_USERSEC_H */
76
77
78 /*
79 * Local functions...
80 */
81
82 static authmask_t *add_allow(location_t *loc);
83 static authmask_t *add_deny(location_t *loc);
84 #if !HAVE_LIBPAM
85 static char *cups_crypt(const char *pw, const char *salt);
86 #endif /* !HAVE_LIBPAM */
87 #if HAVE_LIBPAM
88 static int pam_func(int, const struct pam_message **,
89 struct pam_response **, void *);
90 #else
91 static void to64(char *s, unsigned long v, int n);
92 #endif /* HAVE_LIBPAM */
93
94
95 /*
96 * Local globals...
97 */
98
99 #if defined(__hpux) && defined(HAVE_LIBPAM)
100 static client_t *auth_client; /* Current client being authenticated */
101 #endif /* __hpux && HAVE_LIBPAM */
102
103
104 /*
105 * 'AddLocation()' - Add a location for authorization.
106 */
107
108 location_t * /* O - Pointer to new location record */
109 AddLocation(const char *location) /* I - Location path */
110 {
111 location_t *temp; /* New location */
112
113
114 /*
115 * Try to allocate memory for the new location.
116 */
117
118 if (NumLocations == 0)
119 temp = malloc(sizeof(location_t));
120 else
121 temp = realloc(Locations, sizeof(location_t) * (NumLocations + 1));
122
123 if (temp == NULL)
124 return (NULL);
125
126 Locations = temp;
127 temp += NumLocations;
128 NumLocations ++;
129
130 /*
131 * Initialize the record and copy the name over...
132 */
133
134 memset(temp, 0, sizeof(location_t));
135 strlcpy(temp->location, location, sizeof(temp->location));
136 temp->length = strlen(temp->location);
137
138 LogMessage(L_DEBUG, "AddLocation: added location \'%s\'", location);
139
140 /*
141 * Return the new record...
142 */
143
144 return (temp);
145 }
146
147
148 /*
149 * 'AddName()' - Add a name to a location...
150 */
151
152 void
153 AddName(location_t *loc, /* I - Location to add to */
154 char *name) /* I - Name to add */
155 {
156 char **temp; /* Pointer to names array */
157
158
159 if (loc->num_names == 0)
160 temp = malloc(sizeof(char *));
161 else
162 temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
163
164 if (temp == NULL)
165 {
166 LogMessage(L_ERROR, "Unable to add name to location %s: %s", loc->location,
167 strerror(errno));
168 return;
169 }
170
171 loc->names = temp;
172
173 if ((temp[loc->num_names] = strdup(name)) == NULL)
174 {
175 LogMessage(L_ERROR, "Unable to duplicate name for location %s: %s",
176 loc->location, strerror(errno));
177 return;
178 }
179
180 loc->num_names ++;
181 }
182
183
184 /*
185 * 'AllowHost()' - Add a host name that is allowed to access the location.
186 */
187
188 void
189 AllowHost(location_t *loc, /* I - Location to add to */
190 char *name) /* I - Name of host or domain to add */
191 {
192 authmask_t *temp; /* New host/domain mask */
193 char ifname[32], /* Interface name */
194 *ifptr; /* Pointer to end of name */
195
196
197 if ((temp = add_allow(loc)) == NULL)
198 return;
199
200 if (strcasecmp(name, "@LOCAL") == 0)
201 {
202 /*
203 * Allow *interface*...
204 */
205
206 temp->type = AUTH_INTERFACE;
207 temp->mask.name.name = strdup("*");
208 temp->mask.name.length = 1;
209 }
210 else if (strncasecmp(name, "@IF(", 4) == 0)
211 {
212 /*
213 * Allow *interface*...
214 */
215
216 strlcpy(ifname, name + 4, sizeof(ifname));
217
218 ifptr = ifname + strlen(ifname);
219
220 if (ifptr[-1] == ')')
221 {
222 ifptr --;
223 *ifptr = '\0';
224 }
225
226 temp->type = AUTH_INTERFACE;
227 temp->mask.name.name = strdup(ifname);
228 temp->mask.name.length = ifptr - ifname;
229 }
230 else
231 {
232 /*
233 * Allow name...
234 */
235
236 temp->type = AUTH_NAME;
237 temp->mask.name.name = strdup(name);
238 temp->mask.name.length = strlen(name);
239 }
240
241 LogMessage(L_DEBUG, "AllowHost: %s allow %s", loc->location, name);
242 }
243
244
245 /*
246 * 'AllowIP()' - Add an IP address or network that is allowed to access the
247 * location.
248 */
249
250 void
251 AllowIP(location_t *loc, /* I - Location to add to */
252 unsigned address, /* I - IP address to add */
253 unsigned netmask) /* I - Netmask of address */
254 {
255 authmask_t *temp; /* New host/domain mask */
256
257
258 if ((temp = add_allow(loc)) == NULL)
259 return;
260
261 temp->type = AUTH_IP;
262 temp->mask.ip.address = address;
263 temp->mask.ip.netmask = netmask;
264
265 LogMessage(L_DEBUG, "AllowIP: %s allow %08x/%08x", loc->location,
266 address, netmask);
267 }
268
269
270 /*
271 * 'CheckAuth()' - Check authorization masks.
272 */
273
274 int /* O - 1 if mask matches, 0 otherwise */
275 CheckAuth(unsigned ip, /* I - Client address */
276 char *name, /* I - Client hostname */
277 int name_len, /* I - Length of hostname */
278 int num_masks, /* I - Number of masks */
279 authmask_t *masks) /* I - Masks */
280 {
281 cups_netif_t *iface; /* Network interface */
282 unsigned netip; /* Network address */
283
284
285 while (num_masks > 0)
286 {
287 switch (masks->type)
288 {
289 case AUTH_INTERFACE :
290 /*
291 * Check for a match with a network interface...
292 */
293
294 netip = htonl(ip);
295
296 if (strcmp(masks->mask.name.name, "*") == 0)
297 {
298 /*
299 * Check against all local interfaces...
300 */
301
302 NetIFUpdate();
303
304 for (iface = NetIFList; iface != NULL; iface = iface->next)
305 {
306 /*
307 * Only check local interfaces...
308 */
309
310 if (!iface->is_local)
311 continue;
312
313 if ((netip & iface->mask.sin_addr.s_addr) ==
314 (iface->address.sin_addr.s_addr &
315 iface->mask.sin_addr.s_addr))
316 return (1);
317 }
318 }
319 else
320 {
321 /*
322 * Check the named interface...
323 */
324
325 if ((iface = NetIFFind(masks->mask.name.name)) != NULL)
326 {
327 if ((netip & iface->mask.sin_addr.s_addr) ==
328 (iface->address.sin_addr.s_addr &
329 iface->mask.sin_addr.s_addr))
330 return (1);
331 }
332 }
333 break;
334
335 case AUTH_NAME :
336 /*
337 * Check for exact name match...
338 */
339
340 if (strcasecmp(name, masks->mask.name.name) == 0)
341 return (1);
342
343 /*
344 * Check for domain match...
345 */
346
347 if (name_len >= masks->mask.name.length &&
348 masks->mask.name.name[0] == '.' &&
349 strcasecmp(name + name_len - masks->mask.name.length,
350 masks->mask.name.name) == 0)
351 return (1);
352 break;
353
354 case AUTH_IP :
355 /*
356 * Check for IP/network address match...
357 */
358
359 if ((ip & masks->mask.ip.netmask) == masks->mask.ip.address)
360 return (1);
361 break;
362 }
363
364 masks ++;
365 num_masks --;
366 }
367
368 return (0);
369 }
370
371
372 /*
373 * 'CopyLocation()' - Make a copy of a location...
374 */
375
376 location_t * /* O - New location */
377 CopyLocation(location_t **loc) /* IO - Original location */
378 {
379 int i; /* Looping var */
380 int locindex; /* Index into Locations array */
381 location_t *temp; /* New location */
382
383
384 /*
385 * Add the new location, updating the original location
386 * pointer as needed...
387 */
388
389 locindex = *loc - Locations;
390
391 if ((temp = AddLocation((*loc)->location)) == NULL)
392 return (NULL);
393
394 *loc = Locations + locindex;
395
396 /*
397 * Copy the information from the original location to the new one.
398 */
399
400 temp->limit = (*loc)->limit;
401 temp->order_type = (*loc)->order_type;
402 temp->type = (*loc)->type;
403 temp->level = (*loc)->level;
404 temp->satisfy = (*loc)->satisfy;
405 temp->encryption = (*loc)->encryption;
406
407 if ((temp->num_names = (*loc)->num_names) > 0)
408 {
409 /*
410 * Copy the names array...
411 */
412
413 if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
414 {
415 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d names: %s",
416 temp->num_names, strerror(errno));
417 NumLocations --;
418 return (NULL);
419 }
420
421 for (i = 0; i < temp->num_names; i ++)
422 if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
423 {
424 LogMessage(L_ERROR, "CopyLocation: Unable to copy name \"%s\": %s",
425 (*loc)->names[i], strerror(errno));
426
427 NumLocations --;
428 return (NULL);
429 }
430 }
431
432 if ((temp->num_allow = (*loc)->num_allow) > 0)
433 {
434 /*
435 * Copy allow rules...
436 */
437
438 if ((temp->allow = calloc(temp->num_allow, sizeof(authmask_t))) == NULL)
439 {
440 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
441 temp->num_allow, strerror(errno));
442 NumLocations --;
443 return (NULL);
444 }
445
446 for (i = 0; i < temp->num_allow; i ++)
447 switch (temp->allow[i].type = (*loc)->allow[i].type)
448 {
449 case AUTH_NAME :
450 temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
451 temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
452
453 if (temp->allow[i].mask.name.name == NULL)
454 {
455 LogMessage(L_ERROR, "CopyLocation: Unable to copy allow name \"%s\": %s",
456 (*loc)->allow[i].mask.name.name, strerror(errno));
457 NumLocations --;
458 return (NULL);
459 }
460 break;
461 case AUTH_IP :
462 memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
463 sizeof(ipmask_t));
464 break;
465 }
466 }
467
468 if ((temp->num_deny = (*loc)->num_deny) > 0)
469 {
470 /*
471 * Copy deny rules...
472 */
473
474 if ((temp->deny = calloc(temp->num_deny, sizeof(authmask_t))) == NULL)
475 {
476 LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
477 temp->num_deny, strerror(errno));
478 NumLocations --;
479 return (NULL);
480 }
481
482 for (i = 0; i < temp->num_deny; i ++)
483 switch (temp->deny[i].type = (*loc)->deny[i].type)
484 {
485 case AUTH_NAME :
486 temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
487 temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
488
489 if (temp->deny[i].mask.name.name == NULL)
490 {
491 LogMessage(L_ERROR, "CopyLocation: Unable to copy deny name \"%s\": %s",
492 (*loc)->deny[i].mask.name.name, strerror(errno));
493 NumLocations --;
494 return (NULL);
495 }
496 break;
497 case AUTH_IP :
498 memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
499 sizeof(ipmask_t));
500 break;
501 }
502 }
503
504 return (temp);
505 }
506
507
508 /*
509 * 'DeleteAllLocations()' - Free all memory used for location authorization.
510 */
511
512 void
513 DeleteAllLocations(void)
514 {
515 int i, j; /* Looping vars */
516 location_t *loc; /* Current location */
517 authmask_t *mask; /* Current mask */
518
519
520 /*
521 * Free all of the allow/deny records first...
522 */
523
524 for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
525 {
526 for (j = loc->num_names - 1; j >= 0; j --)
527 free(loc->names[j]);
528
529 if (loc->num_names > 0)
530 free(loc->names);
531
532 for (j = loc->num_allow, mask = loc->allow; j > 0; j --, mask ++)
533 if (mask->type == AUTH_NAME)
534 free(mask->mask.name.name);
535
536 if (loc->num_allow > 0)
537 free(loc->allow);
538
539 for (j = loc->num_deny, mask = loc->deny; j > 0; j --, mask ++)
540 if (mask->type == AUTH_NAME)
541 free(mask->mask.name.name);
542
543 if (loc->num_deny > 0)
544 free(loc->deny);
545 }
546
547 /*
548 * Then free the location array...
549 */
550
551 if (NumLocations > 0)
552 free(Locations);
553
554 Locations = NULL;
555 NumLocations = 0;
556 }
557
558
559 /*
560 * 'DenyHost()' - Add a host name that is not allowed to access the location.
561 */
562
563 void
564 DenyHost(location_t *loc, /* I - Location to add to */
565 char *name) /* I - Name of host or domain to add */
566 {
567 authmask_t *temp; /* New host/domain mask */
568 char ifname[32], /* Interface name */
569 *ifptr; /* Pointer to end of name */
570
571
572 if ((temp = add_deny(loc)) == NULL)
573 return;
574
575 if (strcasecmp(name, "@LOCAL") == 0)
576 {
577 /*
578 * Deny *interface*...
579 */
580
581 temp->type = AUTH_INTERFACE;
582 temp->mask.name.name = strdup("*");
583 temp->mask.name.length = 1;
584 }
585 else if (strncasecmp(name, "@IF(", 4) == 0)
586 {
587 /*
588 * Deny *interface*...
589 */
590
591 strlcpy(ifname, name + 4, sizeof(ifname));
592
593 ifptr = ifname + strlen(ifname);
594
595 if (ifptr[-1] == ')')
596 {
597 ifptr --;
598 *ifptr = '\0';
599 }
600
601 temp->type = AUTH_INTERFACE;
602 temp->mask.name.name = strdup(ifname);
603 temp->mask.name.length = ifptr - ifname;
604 }
605 else
606 {
607 /*
608 * Deny name...
609 */
610
611 temp->type = AUTH_NAME;
612 temp->mask.name.name = strdup(name);
613 temp->mask.name.length = strlen(name);
614 }
615
616 LogMessage(L_DEBUG, "DenyHost: %s deny %s", loc->location, name);
617 }
618
619
620 /*
621 * 'DenyIP()' - Add an IP address or network that is not allowed to access
622 * the location.
623 */
624
625 void
626 DenyIP(location_t *loc, /* I - Location to add to */
627 unsigned address, /* I - IP address to add */
628 unsigned netmask) /* I - Netmask of address */
629 {
630 authmask_t *temp; /* New host/domain mask */
631
632
633 if ((temp = add_deny(loc)) == NULL)
634 return;
635
636 temp->type = AUTH_IP;
637 temp->mask.ip.address = address;
638 temp->mask.ip.netmask = netmask;
639
640 LogMessage(L_DEBUG, "DenyIP: %s deny %08x/%08x\n", loc->location,
641 address, netmask);
642 }
643
644
645 /*
646 * 'FindBest()' - Find the location entry that best matches the resource.
647 */
648
649 location_t * /* O - Location that matches */
650 FindBest(const char *path, /* I - Resource path */
651 http_state_t state) /* I - HTTP state/request */
652 {
653 int i; /* Looping var */
654 char uri[HTTP_MAX_URI],
655 /* URI in request... */
656 *uriptr; /* Pointer into URI */
657 location_t *loc, /* Current location */
658 *best; /* Best match for location so far */
659 int bestlen; /* Length of best match */
660 int limit; /* Limit field */
661 static const int limits[] = /* Map http_status_t to AUTH_LIMIT_xyz */
662 {
663 AUTH_LIMIT_ALL,
664 AUTH_LIMIT_OPTIONS,
665 AUTH_LIMIT_GET,
666 AUTH_LIMIT_GET,
667 AUTH_LIMIT_HEAD,
668 AUTH_LIMIT_POST,
669 AUTH_LIMIT_POST,
670 AUTH_LIMIT_POST,
671 AUTH_LIMIT_PUT,
672 AUTH_LIMIT_PUT,
673 AUTH_LIMIT_DELETE,
674 AUTH_LIMIT_TRACE,
675 AUTH_LIMIT_ALL,
676 AUTH_LIMIT_ALL
677 };
678
679
680 /*
681 * First copy the connection URI to a local string so we have drop
682 * any .ppd extension from the pathname in /printers or /classes
683 * URIs...
684 */
685
686 strlcpy(uri, path, sizeof(uri));
687
688 if (strncmp(uri, "/printers/", 10) == 0 ||
689 strncmp(uri, "/classes/", 9) == 0)
690 {
691 /*
692 * Check if the URI has .ppd on the end...
693 */
694
695 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
696
697 if (strcmp(uriptr, ".ppd") == 0)
698 *uriptr = '\0';
699 }
700
701 LogMessage(L_DEBUG2, "FindBest: uri = \"%s\"...", uri);
702
703 /*
704 * Loop through the list of locations to find a match...
705 */
706
707 limit = limits[state];
708 best = NULL;
709 bestlen = 0;
710
711 for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
712 {
713 LogMessage(L_DEBUG2, "FindBest: Location %s Limit %x",
714 loc->location, loc->limit);
715
716 if (loc->length > bestlen &&
717 strncmp(uri, loc->location, loc->length) == 0 &&
718 loc->location[0] == '/' &&
719 (limit & loc->limit) != 0)
720 {
721 best = loc;
722 bestlen = loc->length;
723 }
724 }
725
726 /*
727 * Return the match, if any...
728 */
729
730 LogMessage(L_DEBUG2, "FindBest: best = \"%s\"",
731 best ? best->location : "NONE");
732
733 return (best);
734 }
735
736
737 /*
738 * 'FindLocation()' - Find the named location.
739 */
740
741 location_t * /* O - Location that matches */
742 FindLocation(const char *location) /* I - Connection */
743 {
744 int i; /* Looping var */
745
746
747 /*
748 * Loop through the list of locations to find a match...
749 */
750
751 for (i = 0; i < NumLocations; i ++)
752 if (strcasecmp(Locations[i].location, location) == 0)
753 return (Locations + i);
754
755 return (NULL);
756 }
757
758
759 /*
760 * 'GetMD5Passwd()' - Get an MD5 password.
761 */
762
763 char * /* O - MD5 password string */
764 GetMD5Passwd(const char *username, /* I - Username */
765 const char *group, /* I - Group */
766 char passwd[33]) /* O - MD5 password string */
767 {
768 cups_file_t *fp; /* passwd.md5 file */
769 char filename[1024], /* passwd.md5 filename */
770 line[256], /* Line from file */
771 tempuser[33], /* User from file */
772 tempgroup[33]; /* Group from file */
773
774
775 LogMessage(L_DEBUG2, "GetMD5Passwd(username=\"%s\", group=\"%s\", passwd=%p)",
776 username, group ? group : "(null)", passwd);
777
778 snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
779 if ((fp = cupsFileOpen(filename, "r")) == NULL)
780 {
781 LogMessage(L_ERROR, "Unable to open %s - %s", filename, strerror(errno));
782 return (NULL);
783 }
784
785 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
786 {
787 if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
788 {
789 LogMessage(L_ERROR, "Bad MD5 password line: %s", line);
790 continue;
791 }
792
793 if (strcmp(username, tempuser) == 0 &&
794 (group == NULL || strcmp(group, tempgroup) == 0))
795 {
796 /*
797 * Found the password entry!
798 */
799
800 LogMessage(L_DEBUG2, "Found MD5 user %s, group %s...", username,
801 tempgroup);
802
803 cupsFileClose(fp);
804 return (passwd);
805 }
806 }
807
808 /*
809 * Didn't find a password entry - return NULL!
810 */
811
812 cupsFileClose(fp);
813 return (NULL);
814 }
815
816
817 /*
818 * 'IsAuthorized()' - Check to see if the user is authorized...
819 */
820
821 http_status_t /* O - HTTP_OK if authorized or error code */
822 IsAuthorized(client_t *con) /* I - Connection */
823 {
824 int i, j, /* Looping vars */
825 auth; /* Authorization status */
826 unsigned address; /* Authorization address */
827 location_t *best; /* Best match for location so far */
828 int hostlen; /* Length of hostname */
829 struct passwd *pw; /* User password data */
830 struct group *grp; /* Group data */
831 char nonce[HTTP_MAX_VALUE],
832 /* Nonce value from client */
833 md5[33], /* MD5 password */
834 basicmd5[33]; /* MD5 of Basic password */
835 #if HAVE_LIBPAM
836 pam_handle_t *pamh; /* PAM authentication handle */
837 int pamerr; /* PAM error code */
838 struct pam_conv pamdata; /* PAM conversation data */
839 #elif defined(HAVE_USERSEC_H)
840 char *authmsg; /* Authentication message */
841 char *loginmsg; /* Login message */
842 int reenter; /* ??? */
843 #else
844 char *pass; /* Encrypted password */
845 # ifdef HAVE_SHADOW_H
846 struct spwd *spw; /* Shadow password data */
847 # endif /* HAVE_SHADOW_H */
848 #endif /* HAVE_LIBPAM */
849 static const char * const states[] = /* HTTP client states... */
850 {
851 "WAITING",
852 "OPTIONS",
853 "GET",
854 "GET",
855 "HEAD",
856 "POST",
857 "POST",
858 "POST",
859 "PUT",
860 "PUT",
861 "DELETE",
862 "TRACE",
863 "CLOSE",
864 "STATUS"
865 };
866
867
868 LogMessage(L_DEBUG2, "IsAuthorized: con->uri = \"%s\"", con->uri);
869
870 /*
871 * Find a matching location; if there is no match then access is
872 * not authorized...
873 */
874
875 if ((best = FindBest(con->uri, con->http.state)) == NULL)
876 return (HTTP_FORBIDDEN);
877
878 /*
879 * Check host/ip-based accesses...
880 */
881
882 address = ntohl(con->http.hostaddr.sin_addr.s_addr);
883 hostlen = strlen(con->http.hostname);
884
885 if (address == 0x7f000001 || strcasecmp(con->http.hostname, "localhost") == 0)
886 {
887 /*
888 * Access from localhost (127.0.0.1) is always allowed...
889 */
890
891 auth = AUTH_ALLOW;
892 }
893 else if (best->num_allow == 0 && best->num_deny == 0)
894 {
895 /*
896 * No allow/deny lines - allow access...
897 */
898
899 auth = AUTH_ALLOW;
900 }
901 else
902 {
903 /*
904 * Do authorization checks on the domain/address...
905 */
906
907 switch (best->order_type)
908 {
909 default :
910 auth = AUTH_DENY; /* anti-compiler-warning-code */
911 break;
912
913 case AUTH_ALLOW : /* Order Deny,Allow */
914 auth = AUTH_ALLOW;
915
916 if (CheckAuth(address, con->http.hostname, hostlen,
917 best->num_deny, best->deny))
918 auth = AUTH_DENY;
919
920 if (CheckAuth(address, con->http.hostname, hostlen,
921 best->num_allow, best->allow))
922 auth = AUTH_ALLOW;
923 break;
924
925 case AUTH_DENY : /* Order Allow,Deny */
926 auth = AUTH_DENY;
927
928 if (CheckAuth(address, con->http.hostname, hostlen,
929 best->num_allow, best->allow))
930 auth = AUTH_ALLOW;
931
932 if (CheckAuth(address, con->http.hostname, hostlen,
933 best->num_deny, best->deny))
934 auth = AUTH_DENY;
935 break;
936 }
937 }
938
939 LogMessage(L_DEBUG2, "IsAuthorized: auth = %d, satisfy=%d...",
940 auth, best->satisfy);
941
942 if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
943 return (HTTP_FORBIDDEN);
944
945 #ifdef HAVE_SSL
946 /*
947 * See if encryption is required...
948 */
949
950 if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
951 {
952 LogMessage(L_DEBUG2, "IsAuthorized: Need upgrade to TLS...");
953 return (HTTP_UPGRADE_REQUIRED);
954 }
955 #endif /* HAVE_SSL */
956
957 /*
958 * Now see what access level is required...
959 */
960
961 if (best->level == AUTH_ANON) /* Anonymous access - allow it */
962 return (HTTP_OK);
963
964 LogMessage(L_DEBUG2, "IsAuthorized: username = \"%s\" password = %d chars",
965 con->username, (int)strlen(con->password));
966 DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
967 con->username, con->password));
968
969 if (con->username[0] == '\0')
970 {
971 if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
972 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
973 else
974 return (HTTP_OK); /* unless overridden with Satisfy */
975 }
976
977 /*
978 * Check the user's password...
979 */
980
981 LogMessage(L_DEBUG2, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
982 con->username, address, con->http.hostname);
983
984 pw = NULL;
985
986 if ((address != 0x7f000001 &&
987 strcasecmp(con->http.hostname, "localhost") != 0) ||
988 strncmp(con->http.fields[HTTP_FIELD_AUTHORIZATION], "Local", 5) != 0)
989 {
990 /*
991 * Not doing local certificate-based authentication; check the password...
992 */
993
994 if (!con->password[0])
995 return (HTTP_UNAUTHORIZED);
996
997 /*
998 * See what kind of authentication we are doing...
999 */
1000
1001 switch (best->type)
1002 {
1003 case AUTH_BASIC :
1004 /*
1005 * Get the user info...
1006 */
1007
1008 pw = getpwnam(con->username); /* Get the current password */
1009 endpwent(); /* Close the password file */
1010
1011 #if HAVE_LIBPAM
1012 /*
1013 * Only use PAM to do authentication. This allows MD5 passwords, among
1014 * other things...
1015 */
1016
1017 pamdata.conv = pam_func;
1018 pamdata.appdata_ptr = con;
1019
1020 # ifdef __hpux
1021 /*
1022 * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
1023 * more info...
1024 */
1025
1026 auth_client = con;
1027 # endif /* __hpux */
1028
1029 DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
1030
1031 pamerr = pam_start("cups", con->username, &pamdata, &pamh);
1032 if (pamerr != PAM_SUCCESS)
1033 {
1034 LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
1035 pamerr, pam_strerror(pamh, pamerr));
1036 pam_end(pamh, 0);
1037 return (HTTP_UNAUTHORIZED);
1038 }
1039
1040 pamerr = pam_authenticate(pamh, PAM_SILENT);
1041 if (pamerr != PAM_SUCCESS)
1042 {
1043 LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
1044 pamerr, pam_strerror(pamh, pamerr));
1045 pam_end(pamh, 0);
1046 return (HTTP_UNAUTHORIZED);
1047 }
1048
1049 pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
1050 if (pamerr != PAM_SUCCESS)
1051 {
1052 LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
1053 pamerr, pam_strerror(pamh, pamerr));
1054 pam_end(pamh, 0);
1055 return (HTTP_UNAUTHORIZED);
1056 }
1057
1058 pam_end(pamh, PAM_SUCCESS);
1059 #elif defined(HAVE_USERSEC_H)
1060 /*
1061 * Use AIX authentication interface...
1062 */
1063
1064 LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
1065 con->username);
1066
1067 reenter = 1;
1068 if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
1069 {
1070 LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
1071 con->username, strerror(errno));
1072 return (HTTP_UNAUTHORIZED);
1073 }
1074 #else
1075 /*
1076 * Use normal UNIX password file-based authentication...
1077 */
1078
1079 if (pw == NULL) /* No such user... */
1080 {
1081 LogMessage(L_WARN, "IsAuthorized: Unknown username \"%s\"; access denied.",
1082 con->username);
1083 return (HTTP_UNAUTHORIZED);
1084 }
1085
1086 # ifdef HAVE_SHADOW_H
1087 spw = getspnam(con->username);
1088 endspent();
1089
1090 if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
1091 { /* Don't allow blank passwords! */
1092 LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
1093 con->username);
1094 return (HTTP_UNAUTHORIZED); /* No such user or bad shadow file */
1095 }
1096
1097 # ifdef DEBUG
1098 if (spw != NULL)
1099 printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
1100 else
1101 puts("spw = NULL");
1102 # endif /* DEBUG */
1103
1104 if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
1105 # else
1106 if (pw->pw_passwd[0] == '\0')
1107 # endif /* HAVE_SHADOW_H */
1108 { /* Don't allow blank passwords! */
1109 LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
1110 con->username);
1111 return (HTTP_UNAUTHORIZED);
1112 }
1113
1114 /*
1115 * OK, the password isn't blank, so compare with what came from the client...
1116 */
1117
1118 pass = cups_crypt(con->password, pw->pw_passwd);
1119
1120 LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
1121 pw->pw_passwd, pass);
1122
1123 if (pass == NULL || strcmp(pw->pw_passwd, pass) != 0)
1124 {
1125 # ifdef HAVE_SHADOW_H
1126 if (spw != NULL)
1127 {
1128 pass = cups_crypt(con->password, spw->sp_pwdp);
1129
1130 LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
1131 spw->sp_pwdp, pass);
1132
1133 if (pass == NULL || strcmp(spw->sp_pwdp, pass) != 0)
1134 return (HTTP_UNAUTHORIZED);
1135 }
1136 else
1137 # endif /* HAVE_SHADOW_H */
1138 return (HTTP_UNAUTHORIZED);
1139 }
1140 #endif /* HAVE_LIBPAM */
1141 break;
1142
1143 case AUTH_DIGEST :
1144 /*
1145 * Do Digest authentication...
1146 */
1147
1148 if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
1149 nonce))
1150 {
1151 LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
1152 return (HTTP_UNAUTHORIZED);
1153 }
1154
1155 if (strcmp(con->http.hostname, nonce) != 0)
1156 {
1157 LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
1158 LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
1159 con->http.hostname);
1160 LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
1161 return (HTTP_UNAUTHORIZED);
1162 }
1163
1164 LogMessage(L_DEBUG2, "IsAuthorized: nonce = \"%s\"", nonce);
1165
1166 if (best->num_names && best->level == AUTH_GROUP)
1167 {
1168 LogMessage(L_DEBUG2, "IsAuthorized: num_names = %d", best->num_names);
1169
1170 for (i = 0; i < best->num_names; i ++)
1171 if (GetMD5Passwd(con->username, best->names[i], md5))
1172 break;
1173
1174 if (i >= best->num_names)
1175 md5[0] = '\0';
1176 }
1177 else if (!GetMD5Passwd(con->username, NULL, md5))
1178 md5[0] = '\0';
1179
1180
1181 if (!md5[0])
1182 {
1183 LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
1184 con->username);
1185 return (HTTP_UNAUTHORIZED);
1186 }
1187
1188 httpMD5Final(nonce, states[con->http.state], con->uri, md5);
1189
1190 if (strcmp(md5, con->password) != 0)
1191 {
1192 LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
1193 md5, con->password);
1194 return (HTTP_UNAUTHORIZED);
1195 }
1196 break;
1197
1198 case AUTH_BASICDIGEST :
1199 /*
1200 * Do Basic authentication with the Digest password file...
1201 */
1202
1203 if (best->num_names && best->level == AUTH_GROUP)
1204 {
1205 LogMessage(L_DEBUG2, "IsAuthorized: num_names = %d", best->num_names);
1206
1207 for (i = 0; i < best->num_names; i ++)
1208 if (GetMD5Passwd(con->username, best->names[i], md5))
1209 break;
1210
1211 if (i >= best->num_names)
1212 md5[0] = '\0';
1213 }
1214 else if (!GetMD5Passwd(con->username, NULL, md5))
1215 md5[0] = '\0';
1216
1217 if (!md5[0])
1218 {
1219 LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
1220 con->username);
1221 return (HTTP_UNAUTHORIZED);
1222 }
1223
1224 httpMD5(con->username, "CUPS", con->password, basicmd5);
1225
1226 if (strcmp(md5, basicmd5) != 0)
1227 {
1228 LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
1229 md5, basicmd5);
1230 return (HTTP_UNAUTHORIZED);
1231 }
1232 break;
1233 }
1234 }
1235 else
1236 {
1237 /*
1238 * Get password entry for certificate-based auth...
1239 */
1240
1241 pw = getpwnam(con->username); /* Get the current password */
1242 endpwent(); /* Close the password file */
1243 }
1244
1245 /*
1246 * OK, the password is good. See if we need normal user access, or group
1247 * access... (root always matches)
1248 */
1249
1250 if (strcmp(con->username, "root") == 0)
1251 return (HTTP_OK);
1252
1253 if (best->level == AUTH_USER)
1254 {
1255 /*
1256 * If there are no names associated with this location, then
1257 * any valid user is OK...
1258 */
1259
1260 LogMessage(L_DEBUG2, "IsAuthorized: Checking user membership...");
1261
1262 if (best->num_names == 0)
1263 return (HTTP_OK);
1264
1265 /*
1266 * Otherwise check the user list and return OK if this user is
1267 * allowed...
1268 */
1269
1270 for (i = 0; i < best->num_names; i ++)
1271 if (strcmp(con->username, best->names[i]) == 0)
1272 return (HTTP_OK);
1273
1274 return (HTTP_UNAUTHORIZED);
1275 }
1276
1277 if (best->type == AUTH_BASIC)
1278 {
1279 /*
1280 * Check to see if this user is in any of the named groups...
1281 */
1282
1283 LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
1284
1285 for (i = 0; i < best->num_names; i ++)
1286 {
1287 grp = getgrnam(best->names[i]);
1288 endgrent();
1289
1290 if (grp == NULL) /* No group by that name??? */
1291 {
1292 LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
1293 best->names[i]);
1294 return (HTTP_FORBIDDEN);
1295 }
1296
1297 for (j = 0; grp->gr_mem[j] != NULL; j ++)
1298 if (strcmp(con->username, grp->gr_mem[j]) == 0)
1299 return (HTTP_OK);
1300
1301 /*
1302 * Check to see if the default group ID matches for the user...
1303 */
1304
1305 if (pw != NULL && grp->gr_gid == pw->pw_gid)
1306 return (HTTP_OK);
1307 }
1308
1309 /*
1310 * The user isn't part of the specified group, so deny access...
1311 */
1312
1313 LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
1314
1315 return (HTTP_UNAUTHORIZED);
1316 }
1317
1318 /*
1319 * All checks passed...
1320 */
1321
1322 return (HTTP_OK);
1323 }
1324
1325
1326 /*
1327 * 'add_allow()' - Add an allow mask to the location.
1328 */
1329
1330 static authmask_t * /* O - New mask record */
1331 add_allow(location_t *loc) /* I - Location to add to */
1332 {
1333 authmask_t *temp; /* New mask record */
1334
1335
1336 /*
1337 * Range-check...
1338 */
1339
1340 if (loc == NULL)
1341 return (NULL);
1342
1343 /*
1344 * Try to allocate memory for the record...
1345 */
1346
1347 if (loc->num_allow == 0)
1348 temp = malloc(sizeof(authmask_t));
1349 else
1350 temp = realloc(loc->allow, sizeof(authmask_t) * (loc->num_allow + 1));
1351
1352 if (temp == NULL)
1353 return (NULL);
1354
1355 loc->allow = temp;
1356 temp += loc->num_allow;
1357 loc->num_allow ++;
1358
1359 /*
1360 * Clear the mask record and return...
1361 */
1362
1363 memset(temp, 0, sizeof(authmask_t));
1364 return (temp);
1365 }
1366
1367
1368 /*
1369 * 'add_deny()' - Add a deny mask to the location.
1370 */
1371
1372 static authmask_t * /* O - New mask record */
1373 add_deny(location_t *loc) /* I - Location to add to */
1374 {
1375 authmask_t *temp; /* New mask record */
1376
1377
1378 /*
1379 * Range-check...
1380 */
1381
1382 if (loc == NULL)
1383 return (NULL);
1384
1385 /*
1386 * Try to allocate memory for the record...
1387 */
1388
1389 if (loc->num_deny == 0)
1390 temp = malloc(sizeof(authmask_t));
1391 else
1392 temp = realloc(loc->deny, sizeof(authmask_t) * (loc->num_deny + 1));
1393
1394 if (temp == NULL)
1395 return (NULL);
1396
1397 loc->deny = temp;
1398 temp += loc->num_deny;
1399 loc->num_deny ++;
1400
1401 /*
1402 * Clear the mask record and return...
1403 */
1404
1405 memset(temp, 0, sizeof(authmask_t));
1406 return (temp);
1407 }
1408
1409
1410 #if !HAVE_LIBPAM
1411 /*
1412 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
1413 * as needed.
1414 */
1415
1416 static char * /* O - Encrypted password */
1417 cups_crypt(const char *pw, /* I - Password string */
1418 const char *salt) /* I - Salt (key) string */
1419 {
1420 if (strncmp(salt, "$1$", 3) == 0)
1421 {
1422 /*
1423 * Use MD5 passwords without the benefit of PAM; this is for
1424 * Slackware Linux, and the algorithm was taken from the
1425 * old shadow-19990827/lib/md5crypt.c source code... :(
1426 */
1427
1428 int i; /* Looping var */
1429 unsigned long n; /* Output number */
1430 int pwlen; /* Length of password string */
1431 const char *salt_end; /* End of "salt" data for MD5 */
1432 char *ptr; /* Pointer into result string */
1433 md5_state_t state; /* Primary MD5 state info */
1434 md5_state_t state2; /* Secondary MD5 state info */
1435 md5_byte_t digest[16]; /* MD5 digest result */
1436 static char result[120]; /* Final password string */
1437
1438
1439 /*
1440 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
1441 * Get a maximum of 8 characters of salt data after $1$...
1442 */
1443
1444 for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
1445 if (*salt_end == '$')
1446 break;
1447
1448 /*
1449 * Compute the MD5 sum we need...
1450 */
1451
1452 pwlen = strlen(pw);
1453
1454 md5_init(&state);
1455 md5_append(&state, (md5_byte_t *)pw, pwlen);
1456 md5_append(&state, (md5_byte_t *)salt, salt_end - salt);
1457
1458 md5_init(&state2);
1459 md5_append(&state2, (md5_byte_t *)pw, pwlen);
1460 md5_append(&state2, (md5_byte_t *)salt + 3, salt_end - salt - 3);
1461 md5_append(&state2, (md5_byte_t *)pw, pwlen);
1462 md5_finish(&state2, digest);
1463
1464 for (i = pwlen; i > 0; i -= 16)
1465 md5_append(&state, digest, i > 16 ? 16 : i);
1466
1467 for (i = pwlen; i > 0; i >>= 1)
1468 md5_append(&state, (md5_byte_t *)((i & 1) ? "" : pw), 1);
1469
1470 md5_finish(&state, digest);
1471
1472 for (i = 0; i < 1000; i ++)
1473 {
1474 md5_init(&state);
1475
1476 if (i & 1)
1477 md5_append(&state, (md5_byte_t *)pw, pwlen);
1478 else
1479 md5_append(&state, digest, 16);
1480
1481 if (i % 3)
1482 md5_append(&state, (md5_byte_t *)salt + 3, salt_end - salt - 3);
1483
1484 if (i % 7)
1485 md5_append(&state, (md5_byte_t *)pw, pwlen);
1486
1487 if (i & 1)
1488 md5_append(&state, digest, 16);
1489 else
1490 md5_append(&state, (md5_byte_t *)pw, pwlen);
1491
1492 md5_finish(&state, digest);
1493 }
1494
1495 /*
1496 * Copy the final sum to the result string and return...
1497 */
1498
1499 memcpy(result, salt, salt_end - salt);
1500 ptr = result + (salt_end - salt);
1501 *ptr++ = '$';
1502
1503 for (i = 0; i < 5; i ++, ptr += 4)
1504 {
1505 n = (((digest[i] << 8) | digest[i + 6]) << 8);
1506
1507 if (i < 4)
1508 n |= digest[i + 12];
1509 else
1510 n |= digest[5];
1511
1512 to64(ptr, n, 4);
1513 }
1514
1515 to64(ptr, digest[11], 2);
1516 ptr += 2;
1517 *ptr = '\0';
1518
1519 return (result);
1520 }
1521 else
1522 {
1523 /*
1524 * Use the standard crypt() function...
1525 */
1526
1527 return (crypt(pw, salt));
1528 }
1529 }
1530 #endif /* !HAVE_LIBPAM */
1531
1532
1533 #if HAVE_LIBPAM
1534 /*
1535 * 'pam_func()' - PAM conversation function.
1536 */
1537
1538 static int /* O - Success or failure */
1539 pam_func(int num_msg, /* I - Number of messages */
1540 const struct pam_message **msg, /* I - Messages */
1541 struct pam_response **resp, /* O - Responses */
1542 void *appdata_ptr) /* I - Pointer to connection */
1543 {
1544 int i; /* Looping var */
1545 struct pam_response *replies; /* Replies */
1546 client_t *client; /* Pointer client connection */
1547
1548
1549 /*
1550 * Allocate memory for the responses...
1551 */
1552
1553 if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
1554 return (PAM_CONV_ERR);
1555
1556 /*
1557 * Answer all of the messages...
1558 */
1559
1560 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
1561
1562 #ifdef __hpux
1563 /*
1564 * Apparently some versions of HP-UX 11 have a broken pam_unix security
1565 * module. This is a workaround...
1566 */
1567
1568 client = auth_client;
1569 (void)appdata_ptr;
1570 #else
1571 client = (client_t *)appdata_ptr;
1572 #endif /* __hpux */
1573
1574 for (i = 0; i < num_msg; i ++)
1575 {
1576 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
1577
1578 switch (msg[i]->msg_style)
1579 {
1580 case PAM_PROMPT_ECHO_ON:
1581 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
1582 client->username));
1583 replies[i].resp_retcode = PAM_SUCCESS;
1584 replies[i].resp = strdup(client->username);
1585 break;
1586
1587 case PAM_PROMPT_ECHO_OFF:
1588 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
1589 client->password));
1590 replies[i].resp_retcode = PAM_SUCCESS;
1591 replies[i].resp = strdup(client->password);
1592 break;
1593
1594 case PAM_TEXT_INFO:
1595 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
1596 replies[i].resp_retcode = PAM_SUCCESS;
1597 replies[i].resp = NULL;
1598 break;
1599
1600 case PAM_ERROR_MSG:
1601 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
1602 replies[i].resp_retcode = PAM_SUCCESS;
1603 replies[i].resp = NULL;
1604 break;
1605
1606 default:
1607 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
1608 msg[i]->msg_style));
1609 free(replies);
1610 return (PAM_CONV_ERR);
1611 }
1612 }
1613
1614 /*
1615 * Return the responses back to PAM...
1616 */
1617
1618 *resp = replies;
1619
1620 return (PAM_SUCCESS);
1621 }
1622 #else
1623
1624
1625 /*
1626 * 'to64()' - Base64-encode an integer value...
1627 */
1628
1629 static void
1630 to64(char *s, /* O - Output string */
1631 unsigned long v, /* I - Value to encode */
1632 int n) /* I - Number of digits */
1633 {
1634 const char *itoa64 = "./0123456789"
1635 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1636 "abcdefghijklmnopqrstuvwxyz";
1637
1638
1639 for (; n > 0; n --, v >>= 6)
1640 *s++ = itoa64[v & 0x3f];
1641 }
1642 #endif /* HAVE_LIBPAM */
1643
1644
1645 /*
1646 * End of "$Id: auth.c,v 1.70 2003/04/10 12:57:43 mike Exp $".
1647 */