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