]> 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 4929 2006-01-13 16:38:43Z 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
82 static cupsd_authmask_t *add_allow(cupsd_location_t *loc);
83 static cupsd_authmask_t *add_deny(cupsd_location_t *loc);
84 #if !HAVE_LIBPAM
85 static char *cups_crypt(const char *pw, const char *salt);
86 #endif /* !HAVE_LIBPAM */
87 #if HAVE_LIBPAM
88 static int pam_func(int, const struct pam_message **,
89 struct pam_response **, void *);
90 #else
91 static void to64(char *s, unsigned long v, int n);
92 #endif /* HAVE_LIBPAM */
93
94
95 /*
96 * Local structures...
97 */
98
99 #if HAVE_LIBPAM
100 typedef 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)
113 static 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
121 cupsd_location_t * /* O - Pointer to new location record */
122 cupsdAddLocation(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
166 void
167 cupsdAddName(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
206 void
207 cupsdAllowHost(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
269 void
270 cupsdAllowIP(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
296 void
297 cupsdAuthorize(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
765 int /* O - 1 if mask matches, 0 otherwise */
766 cupsdCheckAuth(
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
933 int /* O - 1 if user is a member, 0 otherwise */
934 cupsdCheckGroup(
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
1002 cupsd_location_t * /* O - New location */
1003 cupsdCopyLocation(
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
1154 void
1155 cupsdDeleteAllLocations(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
1184 void
1185 cupsdDeleteLocation(
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
1219 void
1220 cupsdDenyHost(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
1282 void
1283 cupsdDenyIP(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
1309 cupsd_location_t * /* O - Location that matches */
1310 cupsdFindBest(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
1423 cupsd_location_t * /* O - Location that matches */
1424 cupsdFindLocation(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
1445 char * /* O - MD5 password string */
1446 cupsdGetMD5Passwd(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
1507 http_status_t /* O - HTTP_OK if authorized or error code */
1508 cupsdIsAuthorized(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 const char *username; /* Username to authorize */
1517 struct passwd *pw; /* User password data */
1518 static const char * const levels[] = /* Auth levels */
1519 {
1520 "ANON",
1521 "USER",
1522 "GROUP"
1523 };
1524 static const char * const types[] = /* Auth types */
1525 {
1526 "NONE",
1527 "BASIC",
1528 "DIGEST",
1529 "BASICDIGEST"
1530 };
1531
1532
1533 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1534 "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
1535 con->uri, con->best, con->best ? con->best->location : "");
1536 if (owner)
1537 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1538 "cupsdIsAuthorized: owner=\"%s\"", owner);
1539
1540 /*
1541 * If there is no "best" authentication rule for this request, then
1542 * access is allowed from the local system and denied from other
1543 * addresses...
1544 */
1545
1546 if (!con->best)
1547 {
1548 if (!strcmp(con->http.hostname, "localhost") ||
1549 !strcmp(con->http.hostname, ServerName))
1550 return (HTTP_OK);
1551 else
1552 return (HTTP_FORBIDDEN);
1553 }
1554
1555 best = con->best;
1556
1557 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1558 "cupsdIsAuthorized: level=AUTH_%s, type=AUTH_%s, satisfy=AUTH_SATISFY_%s, num_names=%d",
1559 levels[best->level], types[best->type],
1560 best->satisfy ? "ANY" : "ALL", best->num_names);
1561
1562 if (best->limit == AUTH_LIMIT_IPP)
1563 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
1564 best->op, ippOpString(best->op));
1565
1566 /*
1567 * Check host/ip-based accesses...
1568 */
1569
1570 #ifdef AF_INET6
1571 if (con->http.hostaddr->addr.sa_family == AF_INET6)
1572 {
1573 /*
1574 * Copy IPv6 address...
1575 */
1576
1577 address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]);
1578 address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]);
1579 address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]);
1580 address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]);
1581 }
1582 else
1583 #endif /* AF_INET6 */
1584 if (con->http.hostaddr->addr.sa_family == AF_INET)
1585 {
1586 /*
1587 * Copy IPv4 address...
1588 */
1589
1590 address[0] = 0;
1591 address[1] = 0;
1592 address[2] = 0;
1593 address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr);
1594 }
1595 else
1596 memset(address, 0, sizeof(address));
1597
1598 hostlen = strlen(con->http.hostname);
1599
1600 if (!strcasecmp(con->http.hostname, "localhost"))
1601 {
1602 /*
1603 * Access from localhost (127.0.0.1 or :::1) is always allowed...
1604 */
1605
1606 auth = AUTH_ALLOW;
1607 }
1608 else
1609 {
1610 /*
1611 * Do authorization checks on the domain/address...
1612 */
1613
1614 switch (best->order_type)
1615 {
1616 default :
1617 auth = AUTH_DENY; /* anti-compiler-warning-code */
1618 break;
1619
1620 case AUTH_ALLOW : /* Order Deny,Allow */
1621 auth = AUTH_ALLOW;
1622
1623 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1624 best->num_deny, best->deny))
1625 auth = AUTH_DENY;
1626
1627 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1628 best->num_allow, best->allow))
1629 auth = AUTH_ALLOW;
1630 break;
1631
1632 case AUTH_DENY : /* Order Allow,Deny */
1633 auth = AUTH_DENY;
1634
1635 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1636 best->num_allow, best->allow))
1637 auth = AUTH_ALLOW;
1638
1639 if (cupsdCheckAuth(address, con->http.hostname, hostlen,
1640 best->num_deny, best->deny))
1641 auth = AUTH_DENY;
1642 break;
1643 }
1644 }
1645
1646 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=AUTH_%s...",
1647 auth ? "DENY" : "ALLOW");
1648
1649 if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
1650 return (HTTP_FORBIDDEN);
1651
1652 #ifdef HAVE_SSL
1653 /*
1654 * See if encryption is required...
1655 */
1656
1657 if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
1658 {
1659 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1660 "cupsdIsAuthorized: Need upgrade to TLS...");
1661 return (HTTP_UPGRADE_REQUIRED);
1662 }
1663 #endif /* HAVE_SSL */
1664
1665 /*
1666 * Now see what access level is required...
1667 */
1668
1669 if (best->level == AUTH_ANON || /* Anonymous access - allow it */
1670 (best->type == AUTH_NONE && best->num_names == 0))
1671 return (HTTP_OK);
1672
1673 if (!con->username[0] && best->type == AUTH_NONE &&
1674 best->limit == AUTH_LIMIT_IPP)
1675 {
1676 /*
1677 * Check for unauthenticated username...
1678 */
1679
1680 ipp_attribute_t *attr; /* requesting-user-name attribute */
1681
1682
1683 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1684 if (attr)
1685 {
1686 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1687 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1688 attr->values[0].string.text);
1689 username = attr->values[0].string.text;
1690 }
1691 else if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
1692 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1693 else
1694 return (HTTP_OK); /* unless overridden with Satisfy */
1695 }
1696 else
1697 {
1698 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"",
1699 con->username);
1700
1701 if (!con->username[0])
1702 {
1703 if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
1704 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1705 else
1706 return (HTTP_OK); /* unless overridden with Satisfy */
1707 }
1708
1709 username = con->username;
1710 }
1711
1712 /*
1713 * OK, got a username. See if we need normal user access, or group
1714 * access... (root always matches)
1715 */
1716
1717 if (!strcmp(username, "root"))
1718 return (HTTP_OK);
1719
1720 /*
1721 * Get the user info...
1722 */
1723
1724 pw = getpwnam(username);
1725 endpwent();
1726
1727 if (best->level == AUTH_USER)
1728 {
1729 /*
1730 * If there are no names associated with this location, then
1731 * any valid user is OK...
1732 */
1733
1734 if (best->num_names == 0)
1735 return (HTTP_OK);
1736
1737 /*
1738 * Otherwise check the user list and return OK if this user is
1739 * allowed...
1740 */
1741
1742 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1743 "cupsdIsAuthorized: Checking user membership...");
1744
1745 for (i = 0; i < best->num_names; i ++)
1746 {
1747 if (!strcasecmp(best->names[i], "@OWNER") && owner &&
1748 !strcasecmp(username, owner))
1749 return (HTTP_OK);
1750 else if (!strcasecmp(best->names[i], "@SYSTEM"))
1751 {
1752 for (j = 0; j < NumSystemGroups; j ++)
1753 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
1754 return (HTTP_OK);
1755 }
1756 else if (best->names[i][0] == '@')
1757 {
1758 if (cupsdCheckGroup(username, pw, best->names[i] + 1))
1759 return (HTTP_OK);
1760 }
1761 else if (!strcasecmp(username, best->names[i]))
1762 return (HTTP_OK);
1763 }
1764
1765 return (HTTP_UNAUTHORIZED);
1766 }
1767
1768 /*
1769 * Check to see if this user is in any of the named groups...
1770 */
1771
1772 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1773 "cupsdIsAuthorized: Checking group membership...");
1774
1775 /*
1776 * Check to see if this user is in any of the named groups...
1777 */
1778
1779 for (i = 0; i < best->num_names; i ++)
1780 {
1781 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1782 "cupsdIsAuthorized: Checking group \"%s\" membership...",
1783 best->names[i]);
1784
1785 if (!strcasecmp(best->names[i], "@SYSTEM"))
1786 {
1787 for (j = 0; j < NumSystemGroups; j ++)
1788 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
1789 return (HTTP_OK);
1790 }
1791 else if (cupsdCheckGroup(username, pw, best->names[i]))
1792 return (HTTP_OK);
1793 }
1794
1795 /*
1796 * The user isn't part of the specified group, so deny access...
1797 */
1798
1799 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1800 "cupsdIsAuthorized: User not in group(s)!");
1801
1802 return (HTTP_UNAUTHORIZED);
1803 }
1804
1805
1806 /*
1807 * 'add_allow()' - Add an allow mask to the location.
1808 */
1809
1810 static cupsd_authmask_t * /* O - New mask record */
1811 add_allow(cupsd_location_t *loc) /* I - Location to add to */
1812 {
1813 cupsd_authmask_t *temp; /* New mask record */
1814
1815
1816 /*
1817 * Range-check...
1818 */
1819
1820 if (loc == NULL)
1821 return (NULL);
1822
1823 /*
1824 * Try to allocate memory for the record...
1825 */
1826
1827 if (loc->num_allow == 0)
1828 temp = malloc(sizeof(cupsd_authmask_t));
1829 else
1830 temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1));
1831
1832 if (temp == NULL)
1833 return (NULL);
1834
1835 loc->allow = temp;
1836 temp += loc->num_allow;
1837 loc->num_allow ++;
1838
1839 /*
1840 * Clear the mask record and return...
1841 */
1842
1843 memset(temp, 0, sizeof(cupsd_authmask_t));
1844 return (temp);
1845 }
1846
1847
1848 /*
1849 * 'add_deny()' - Add a deny mask to the location.
1850 */
1851
1852 static cupsd_authmask_t * /* O - New mask record */
1853 add_deny(cupsd_location_t *loc) /* I - Location to add to */
1854 {
1855 cupsd_authmask_t *temp; /* New mask record */
1856
1857
1858 /*
1859 * Range-check...
1860 */
1861
1862 if (loc == NULL)
1863 return (NULL);
1864
1865 /*
1866 * Try to allocate memory for the record...
1867 */
1868
1869 if (loc->num_deny == 0)
1870 temp = malloc(sizeof(cupsd_authmask_t));
1871 else
1872 temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1));
1873
1874 if (temp == NULL)
1875 return (NULL);
1876
1877 loc->deny = temp;
1878 temp += loc->num_deny;
1879 loc->num_deny ++;
1880
1881 /*
1882 * Clear the mask record and return...
1883 */
1884
1885 memset(temp, 0, sizeof(cupsd_authmask_t));
1886 return (temp);
1887 }
1888
1889
1890 #if !HAVE_LIBPAM
1891 /*
1892 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
1893 * as needed.
1894 */
1895
1896 static char * /* O - Encrypted password */
1897 cups_crypt(const char *pw, /* I - Password string */
1898 const char *salt) /* I - Salt (key) string */
1899 {
1900 if (strncmp(salt, "$1$", 3) == 0)
1901 {
1902 /*
1903 * Use MD5 passwords without the benefit of PAM; this is for
1904 * Slackware Linux, and the algorithm was taken from the
1905 * old shadow-19990827/lib/md5crypt.c source code... :(
1906 */
1907
1908 int i; /* Looping var */
1909 unsigned long n; /* Output number */
1910 int pwlen; /* Length of password string */
1911 const char *salt_end; /* End of "salt" data for MD5 */
1912 char *ptr; /* Pointer into result string */
1913 _cups_md5_state_t state; /* Primary MD5 state info */
1914 _cups_md5_state_t state2; /* Secondary MD5 state info */
1915 unsigned char digest[16]; /* MD5 digest result */
1916 static char result[120]; /* Final password string */
1917
1918
1919 /*
1920 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
1921 * Get a maximum of 8 characters of salt data after $1$...
1922 */
1923
1924 for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
1925 if (*salt_end == '$')
1926 break;
1927
1928 /*
1929 * Compute the MD5 sum we need...
1930 */
1931
1932 pwlen = strlen(pw);
1933
1934 _cups_md5_init(&state);
1935 _cups_md5_append(&state, (unsigned char *)pw, pwlen);
1936 _cups_md5_append(&state, (unsigned char *)salt, salt_end - salt);
1937
1938 _cups_md5_init(&state2);
1939 _cups_md5_append(&state2, (unsigned char *)pw, pwlen);
1940 _cups_md5_append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
1941 _cups_md5_append(&state2, (unsigned char *)pw, pwlen);
1942 _cups_md5_finish(&state2, digest);
1943
1944 for (i = pwlen; i > 0; i -= 16)
1945 _cups_md5_append(&state, digest, i > 16 ? 16 : i);
1946
1947 for (i = pwlen; i > 0; i >>= 1)
1948 _cups_md5_append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
1949
1950 _cups_md5_finish(&state, digest);
1951
1952 for (i = 0; i < 1000; i ++)
1953 {
1954 _cups_md5_init(&state);
1955
1956 if (i & 1)
1957 _cups_md5_append(&state, (unsigned char *)pw, pwlen);
1958 else
1959 _cups_md5_append(&state, digest, 16);
1960
1961 if (i % 3)
1962 _cups_md5_append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
1963
1964 if (i % 7)
1965 _cups_md5_append(&state, (unsigned char *)pw, pwlen);
1966
1967 if (i & 1)
1968 _cups_md5_append(&state, digest, 16);
1969 else
1970 _cups_md5_append(&state, (unsigned char *)pw, pwlen);
1971
1972 _cups_md5_finish(&state, digest);
1973 }
1974
1975 /*
1976 * Copy the final sum to the result string and return...
1977 */
1978
1979 memcpy(result, salt, salt_end - salt);
1980 ptr = result + (salt_end - salt);
1981 *ptr++ = '$';
1982
1983 for (i = 0; i < 5; i ++, ptr += 4)
1984 {
1985 n = (((digest[i] << 8) | digest[i + 6]) << 8);
1986
1987 if (i < 4)
1988 n |= digest[i + 12];
1989 else
1990 n |= digest[5];
1991
1992 to64(ptr, n, 4);
1993 }
1994
1995 to64(ptr, digest[11], 2);
1996 ptr += 2;
1997 *ptr = '\0';
1998
1999 return (result);
2000 }
2001 else
2002 {
2003 /*
2004 * Use the standard crypt() function...
2005 */
2006
2007 return (crypt(pw, salt));
2008 }
2009 }
2010 #endif /* !HAVE_LIBPAM */
2011
2012
2013 #if HAVE_LIBPAM
2014 /*
2015 * 'pam_func()' - PAM conversation function.
2016 */
2017
2018 static int /* O - Success or failure */
2019 pam_func(
2020 int num_msg, /* I - Number of messages */
2021 const struct pam_message **msg, /* I - Messages */
2022 struct pam_response **resp, /* O - Responses */
2023 void *appdata_ptr)
2024 /* I - Pointer to connection */
2025 {
2026 int i; /* Looping var */
2027 struct pam_response *replies; /* Replies */
2028 cupsd_authdata_t *data; /* Pointer to auth data */
2029
2030
2031 /*
2032 * Allocate memory for the responses...
2033 */
2034
2035 if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
2036 return (PAM_CONV_ERR);
2037
2038 /*
2039 * Answer all of the messages...
2040 */
2041
2042 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
2043
2044 #ifdef __hpux
2045 /*
2046 * Apparently some versions of HP-UX 11 have a broken pam_unix security
2047 * module. This is a workaround...
2048 */
2049
2050 data = auth_data;
2051 (void)appdata_ptr;
2052 #else
2053 data = (cupsd_authdata_t *)appdata_ptr;
2054 #endif /* __hpux */
2055
2056 for (i = 0; i < num_msg; i ++)
2057 {
2058 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
2059
2060 switch (msg[i]->msg_style)
2061 {
2062 case PAM_PROMPT_ECHO_ON:
2063 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2064 data->username));
2065 replies[i].resp_retcode = PAM_SUCCESS;
2066 replies[i].resp = strdup(data->username);
2067 break;
2068
2069 case PAM_PROMPT_ECHO_OFF:
2070 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2071 data->password));
2072 replies[i].resp_retcode = PAM_SUCCESS;
2073 replies[i].resp = strdup(data->password);
2074 break;
2075
2076 case PAM_TEXT_INFO:
2077 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2078 replies[i].resp_retcode = PAM_SUCCESS;
2079 replies[i].resp = NULL;
2080 break;
2081
2082 case PAM_ERROR_MSG:
2083 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2084 replies[i].resp_retcode = PAM_SUCCESS;
2085 replies[i].resp = NULL;
2086 break;
2087
2088 default:
2089 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2090 msg[i]->msg_style));
2091 free(replies);
2092 return (PAM_CONV_ERR);
2093 }
2094 }
2095
2096 /*
2097 * Return the responses back to PAM...
2098 */
2099
2100 *resp = replies;
2101
2102 return (PAM_SUCCESS);
2103 }
2104 #else
2105
2106
2107 /*
2108 * 'to64()' - Base64-encode an integer value...
2109 */
2110
2111 static void
2112 to64(char *s, /* O - Output string */
2113 unsigned long v, /* I - Value to encode */
2114 int n) /* I - Number of digits */
2115 {
2116 const char *itoa64 = "./0123456789"
2117 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2118 "abcdefghijklmnopqrstuvwxyz";
2119
2120
2121 for (; n > 0; n --, v >>= 6)
2122 *s++ = itoa64[v & 0x3f];
2123 }
2124 #endif /* HAVE_LIBPAM */
2125
2126
2127 /*
2128 * End of "$Id: auth.c 4929 2006-01-13 16:38:43Z mike $".
2129 */