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