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