]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/auth.c
Full sweep of all Clang warnings, plus some bug fixes for incorrect memcpy usage.
[thirdparty/cups.git] / scheduler / auth.c
1 /*
2 * "$Id$"
3 *
4 * Authorization routines for the CUPS scheduler.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * This file contains Kerberos support code, copyright 2006 by
10 * Jelmer Vernooij.
11 *
12 * These coded instructions, statements, and computer programs are the
13 * property of Apple Inc. and are protected by Federal copyright
14 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
15 * which should have been included with this file. If this file is
16 * file is missing or damaged, see the license at "http://www.cups.org/".
17 */
18
19 /*
20 * Include necessary headers...
21 */
22
23 #include "cupsd.h"
24 #include <grp.h>
25 #ifdef HAVE_SHADOW_H
26 # include <shadow.h>
27 #endif /* HAVE_SHADOW_H */
28 #ifdef HAVE_CRYPT_H
29 # include <crypt.h>
30 #endif /* HAVE_CRYPT_H */
31 #if HAVE_LIBPAM
32 # ifdef HAVE_PAM_PAM_APPL_H
33 # include <pam/pam_appl.h>
34 # else
35 # include <security/pam_appl.h>
36 # endif /* HAVE_PAM_PAM_APPL_H */
37 #endif /* HAVE_LIBPAM */
38 #ifdef HAVE_MEMBERSHIP_H
39 # include <membership.h>
40 #endif /* HAVE_MEMBERSHIP_H */
41 #ifdef HAVE_AUTHORIZATION_H
42 # include <Security/AuthorizationTags.h>
43 # ifdef HAVE_SECBASEPRIV_H
44 # include <Security/SecBasePriv.h>
45 # else
46 extern const char *cssmErrorString(int error);
47 # endif /* HAVE_SECBASEPRIV_H */
48 #endif /* HAVE_AUTHORIZATION_H */
49 #ifdef HAVE_SYS_PARAM_H
50 # include <sys/param.h>
51 #endif /* HAVE_SYS_PARAM_H */
52 #ifdef HAVE_SYS_UCRED_H
53 # include <sys/ucred.h>
54 typedef struct xucred cupsd_ucred_t;
55 # define CUPSD_UCRED_UID(c) (c).cr_uid
56 #else
57 # ifndef __OpenBSD__
58 typedef struct ucred cupsd_ucred_t;
59 # else
60 typedef struct sockpeercred cupsd_ucred_t;
61 # endif
62 # define CUPSD_UCRED_UID(c) (c).uid
63 #endif /* HAVE_SYS_UCRED_H */
64
65
66 /*
67 * Local functions...
68 */
69
70 #ifdef HAVE_AUTHORIZATION_H
71 static int check_authref(cupsd_client_t *con, const char *right);
72 #endif /* HAVE_AUTHORIZATION_H */
73 static int compare_locations(cupsd_location_t *a,
74 cupsd_location_t *b);
75 static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data);
76 #if !HAVE_LIBPAM
77 static char *cups_crypt(const char *pw, const char *salt);
78 #endif /* !HAVE_LIBPAM */
79 static void free_authmask(cupsd_authmask_t *am, void *data);
80 static char *get_md5_password(const char *username,
81 const char *group, char passwd[33]);
82 #if HAVE_LIBPAM
83 static int pam_func(int, const struct pam_message **,
84 struct pam_response **, void *);
85 #else
86 static void to64(char *s, unsigned long v, int n);
87 #endif /* HAVE_LIBPAM */
88
89
90 /*
91 * Local structures...
92 */
93
94 #if HAVE_LIBPAM
95 typedef struct cupsd_authdata_s /**** Authentication data ****/
96 {
97 char username[HTTP_MAX_VALUE], /* Username string */
98 password[HTTP_MAX_VALUE]; /* Password string */
99 } cupsd_authdata_t;
100 #endif /* HAVE_LIBPAM */
101
102
103 /*
104 * 'cupsdAddIPMask()' - Add an IP address authorization mask.
105 */
106
107 int /* O - 1 on success, 0 on failure */
108 cupsdAddIPMask(
109 cups_array_t **masks, /* IO - Masks array (created as needed) */
110 const unsigned address[4], /* I - IP address */
111 const unsigned netmask[4]) /* I - IP netmask */
112 {
113 cupsd_authmask_t temp; /* New host/domain mask */
114
115
116 cupsdLogMessage(CUPSD_LOG_DEBUG2,
117 "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, "
118 "netmask=%x:%x:%x:%x)",
119 masks, *masks,
120 address[0], address[1], address[2], address[3],
121 netmask[0], netmask[1], netmask[2], netmask[3]);
122
123 temp.type = CUPSD_AUTH_IP;
124 memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address));
125 memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask));
126
127 /*
128 * Create the masks array as needed and add...
129 */
130
131 if (!*masks)
132 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
133 (cups_acopy_func_t)copy_authmask,
134 (cups_afree_func_t)free_authmask);
135
136 return (cupsArrayAdd(*masks, &temp));
137 }
138
139
140 /*
141 * 'cupsdAddLocation()' - Add a location for authorization.
142 */
143
144 void
145 cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */
146 {
147 /*
148 * Make sure the locations array is created...
149 */
150
151 if (!Locations)
152 Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL,
153 (cups_ahash_func_t)NULL, 0,
154 (cups_acopy_func_t)NULL,
155 (cups_afree_func_t)cupsdFreeLocation);
156
157 if (Locations)
158 {
159 cupsArrayAdd(Locations, loc);
160
161 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"",
162 loc->location ? loc->location : "(null)");
163 }
164 }
165
166
167 /*
168 * 'cupsdAddName()' - Add a name to a location...
169 */
170
171 void
172 cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
173 char *name) /* I - Name to add */
174 {
175 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")",
176 loc, name);
177
178 if (!loc->names)
179 loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
180 (cups_acopy_func_t)_cupsStrAlloc,
181 (cups_afree_func_t)_cupsStrFree);
182
183 if (!cupsArrayAdd(loc->names, name))
184 {
185 cupsdLogMessage(CUPSD_LOG_ERROR,
186 "Unable to duplicate name for location %s: %s",
187 loc->location ? loc->location : "nil", strerror(errno));
188 return;
189 }
190 }
191
192
193 /*
194 * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
195 */
196
197 int /* O - 1 on success, 0 on failure */
198 cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
199 char *name) /* I - Host or interface name */
200 {
201 cupsd_authmask_t temp; /* New host/domain mask */
202 char ifname[32], /* Interface name */
203 *ifptr; /* Pointer to end of name */
204
205
206 cupsdLogMessage(CUPSD_LOG_DEBUG2,
207 "cupsdAddNameMask(masks=%p(%p), name=\"%s\")",
208 masks, *masks, name);
209
210 if (!_cups_strcasecmp(name, "@LOCAL"))
211 {
212 /*
213 * Deny *interface*...
214 */
215
216 temp.type = CUPSD_AUTH_INTERFACE;
217 temp.mask.name.name = (char *)"*";
218 }
219 else if (!_cups_strncasecmp(name, "@IF(", 4))
220 {
221 /*
222 * Deny *interface*...
223 */
224
225 strlcpy(ifname, name + 4, sizeof(ifname));
226
227 ifptr = ifname + strlen(ifname) - 1;
228
229 if (ifptr >= ifname && *ifptr == ')')
230 {
231 ifptr --;
232 *ifptr = '\0';
233 }
234
235 temp.type = CUPSD_AUTH_INTERFACE;
236 temp.mask.name.name = ifname;
237 }
238 else
239 {
240 /*
241 * Deny name...
242 */
243
244 if (*name == '*')
245 name ++;
246
247 temp.type = CUPSD_AUTH_NAME;
248 temp.mask.name.name = (char *)name;
249 }
250
251 /*
252 * Set the name length...
253 */
254
255 temp.mask.name.length = strlen(temp.mask.name.name);
256
257 /*
258 * Create the masks array as needed and add...
259 */
260
261 if (!*masks)
262 *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
263 (cups_acopy_func_t)copy_authmask,
264 (cups_afree_func_t)free_authmask);
265
266 return (cupsArrayAdd(*masks, &temp));
267 }
268
269
270 /*
271 * 'cupsdAuthorize()' - Validate any authorization credentials.
272 */
273
274 void
275 cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
276 {
277 int type; /* Authentication type */
278 const char *authorization; /* Pointer into Authorization string */
279 char *ptr, /* Pointer into string */
280 username[HTTP_MAX_VALUE],
281 /* Username string */
282 password[HTTP_MAX_VALUE];
283 /* Password string */
284 cupsd_cert_t *localuser; /* Certificate username */
285 char nonce[HTTP_MAX_VALUE], /* Nonce value from client */
286 md5[33], /* MD5 password */
287 basicmd5[33]; /* MD5 of Basic password */
288 static const char * const states[] = /* HTTP client states... */
289 {
290 "WAITING",
291 "OPTIONS",
292 "GET",
293 "GET",
294 "HEAD",
295 "POST",
296 "POST",
297 "POST",
298 "PUT",
299 "PUT",
300 "DELETE",
301 "TRACE",
302 "CLOSE",
303 "STATUS"
304 };
305
306
307 /*
308 * Locate the best matching location so we know what kind of
309 * authentication to expect...
310 */
311
312 con->best = cupsdFindBest(con->uri, httpGetState(con->http));
313 con->type = CUPSD_AUTH_NONE;
314
315 cupsdLogMessage(CUPSD_LOG_DEBUG2,
316 "[Client %d] con->uri=\"%s\", con->best=%p(%s)",
317 con->number, con->uri, con->best,
318 con->best ? con->best->location : "");
319
320 if (con->best && con->best->type != CUPSD_AUTH_NONE)
321 {
322 if (con->best->type == CUPSD_AUTH_DEFAULT)
323 type = cupsdDefaultAuthType();
324 else
325 type = con->best->type;
326 }
327 else
328 type = cupsdDefaultAuthType();
329
330 /*
331 * Decode the Authorization string...
332 */
333
334 authorization = httpGetField(con->http, HTTP_FIELD_AUTHORIZATION);
335
336 cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Client %d] Authorization=\"%s\"",
337 con->number, authorization);
338
339 username[0] = '\0';
340 password[0] = '\0';
341
342 #ifdef HAVE_GSSAPI
343 con->gss_uid = 0;
344 #endif /* HAVE_GSSAPI */
345
346 #ifdef HAVE_AUTHORIZATION_H
347 if (con->authref)
348 {
349 AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
350 con->authref = NULL;
351 }
352 #endif /* HAVE_AUTHORIZATION_H */
353
354 if (!*authorization)
355 {
356 /*
357 * No authorization data provided, return early...
358 */
359
360 cupsdLogMessage(CUPSD_LOG_DEBUG,
361 "[Client %d] No authentication data provided.",
362 con->number);
363 return;
364 }
365 #ifdef HAVE_AUTHORIZATION_H
366 else if (!strncmp(authorization, "AuthRef ", 8) &&
367 httpAddrLocalhost(httpGetAddress(con->http)))
368 {
369 OSStatus status; /* Status */
370 int authlen; /* Auth string length */
371 AuthorizationItemSet *authinfo; /* Authorization item set */
372
373 /*
374 * Get the Authorization Services data...
375 */
376
377 authorization += 8;
378 while (isspace(*authorization & 255))
379 authorization ++;
380
381 authlen = sizeof(nonce);
382 httpDecode64_2(nonce, &authlen, authorization);
383
384 if (authlen != kAuthorizationExternalFormLength)
385 {
386 cupsdLogMessage(CUPSD_LOG_ERROR,
387 "[Client %d] External Authorization reference size is "
388 "incorrect.", con->number);
389 return;
390 }
391
392 if ((status = AuthorizationCreateFromExternalForm(
393 (AuthorizationExternalForm *)nonce, &con->authref)) != 0)
394 {
395 cupsdLogMessage(CUPSD_LOG_ERROR,
396 "[Client %d] AuthorizationCreateFromExternalForm "
397 "returned %d (%s)", con->number, (int)status,
398 cssmErrorString(status));
399 return;
400 }
401
402 username[0] = '\0';
403
404 if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
405 &authinfo))
406 {
407 if (authinfo->count == 1 && authinfo->items[0].value &&
408 authinfo->items[0].valueLength >= 2)
409 {
410 strlcpy(username, authinfo->items[0].value, sizeof(username));
411
412 cupsdLogMessage(CUPSD_LOG_DEBUG,
413 "[Client %d] Authorized as \"%s\" using AuthRef",
414 con->number, username);
415 }
416
417 AuthorizationFreeItemSet(authinfo);
418 }
419
420 if (!username[0])
421 {
422 /*
423 * No username in AuthRef, grab username using peer credentials...
424 */
425
426 struct passwd *pwd; /* Password entry for this user */
427 cupsd_ucred_t peercred; /* Peer credentials */
428 socklen_t peersize; /* Size of peer credentials */
429
430 peersize = sizeof(peercred);
431
432 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
433 {
434 cupsdLogMessage(CUPSD_LOG_ERROR,
435 "[Client %d] Unable to get peer credentials - %s",
436 con->number, strerror(errno));
437 return;
438 }
439
440 if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
441 {
442 cupsdLogMessage(CUPSD_LOG_ERROR,
443 "[Client %d] Unable to find UID %d for peer "
444 "credentials.", con->number,
445 (int)CUPSD_UCRED_UID(peercred));
446 return;
447 }
448
449 strlcpy(username, pwd->pw_name, sizeof(username));
450
451 cupsdLogMessage(CUPSD_LOG_DEBUG,
452 "[Client %d] Authorized as \"%s\" using "
453 "AuthRef + PeerCred", con->number, username);
454 }
455
456 con->type = CUPSD_AUTH_BASIC;
457 }
458 #endif /* HAVE_AUTHORIZATION_H */
459 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
460 else if (!strncmp(authorization, "PeerCred ", 9) &&
461 con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best)
462 {
463 /*
464 * Use peer credentials from domain socket connection...
465 */
466
467 struct passwd *pwd; /* Password entry for this user */
468 cupsd_ucred_t peercred; /* Peer credentials */
469 socklen_t peersize; /* Size of peer credentials */
470 #ifdef HAVE_AUTHORIZATION_H
471 const char *name; /* Authorizing name */
472 int no_peer = 0; /* Don't allow peer credentials? */
473
474 /*
475 * See if we should allow peer credentials...
476 */
477
478 for (name = (char *)cupsArrayFirst(con->best->names);
479 name;
480 name = (char *)cupsArrayNext(con->best->names))
481 {
482 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) ||
483 !_cups_strcasecmp(name, "@SYSTEM"))
484 {
485 /* Normally don't want peer credentials if we need an auth key... */
486 no_peer = 1;
487 }
488 else if (!_cups_strcasecmp(name, "@OWNER"))
489 {
490 /* but if @OWNER is present then we allow it... */
491 no_peer = 0;
492 break;
493 }
494 }
495
496 if (no_peer)
497 {
498 cupsdLogMessage(CUPSD_LOG_ERROR,
499 "[Client %d] PeerCred authentication not allowed for "
500 "resource per AUTHKEY policy.", con->number);
501 return;
502 }
503 #endif /* HAVE_AUTHORIZATION_H */
504
505 if ((pwd = getpwnam(authorization + 9)) == NULL)
506 {
507 cupsdLogMessage(CUPSD_LOG_ERROR,
508 "[Client %d] User \"%s\" does not exist.", con->number,
509 authorization + 9);
510 return;
511 }
512
513 peersize = sizeof(peercred);
514
515 # ifdef __APPLE__
516 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
517 # else
518 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
519 # endif /* __APPLE__ */
520 {
521 cupsdLogMessage(CUPSD_LOG_ERROR,
522 "[Client %d] Unable to get peer credentials - %s",
523 con->number, strerror(errno));
524 return;
525 }
526
527 if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
528 {
529 cupsdLogMessage(CUPSD_LOG_ERROR,
530 "[Client %d] Invalid peer credentials for \"%s\" - got "
531 "%d, expected %d!", con->number, authorization + 9,
532 CUPSD_UCRED_UID(peercred), pwd->pw_uid);
533 # ifdef HAVE_SYS_UCRED_H
534 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_version=%d",
535 con->number, peercred.cr_version);
536 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_uid=%d",
537 con->number, peercred.cr_uid);
538 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_ngroups=%d",
539 con->number, peercred.cr_ngroups);
540 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_groups[0]=%d",
541 con->number, peercred.cr_groups[0]);
542 # endif /* HAVE_SYS_UCRED_H */
543 return;
544 }
545
546 strlcpy(username, authorization + 9, sizeof(username));
547
548 # ifdef HAVE_GSSAPI
549 con->gss_uid = CUPSD_UCRED_UID(peercred);
550 # endif /* HAVE_GSSAPI */
551
552 cupsdLogMessage(CUPSD_LOG_DEBUG,
553 "[Client %d] Authorized as %s using PeerCred", con->number,
554 username);
555
556 con->type = CUPSD_AUTH_BASIC;
557 }
558 #endif /* SO_PEERCRED && AF_LOCAL */
559 else if (!strncmp(authorization, "Local", 5) &&
560 httpAddrLocalhost(httpGetAddress(con->http)))
561 {
562 /*
563 * Get Local certificate authentication data...
564 */
565
566 authorization += 5;
567 while (isspace(*authorization & 255))
568 authorization ++;
569
570 if ((localuser = cupsdFindCert(authorization)) == NULL)
571 {
572 cupsdLogMessage(CUPSD_LOG_ERROR,
573 "[Client %d] Local authentication certificate not found.",
574 con->number);
575 return;
576 }
577
578 strlcpy(username, localuser->username, sizeof(username));
579 con->type = localuser->type;
580
581 cupsdLogMessage(CUPSD_LOG_DEBUG,
582 "[Client %d] Authorized as %s using Local", con->number,
583 username);
584 }
585 else if (!strncmp(authorization, "Basic", 5))
586 {
587 /*
588 * Get the Basic authentication data...
589 */
590
591 int userlen; /* Username:password length */
592
593
594 authorization += 5;
595 while (isspace(*authorization & 255))
596 authorization ++;
597
598 userlen = sizeof(username);
599 httpDecode64_2(username, &userlen, authorization);
600
601 /*
602 * Pull the username and password out...
603 */
604
605 if ((ptr = strchr(username, ':')) == NULL)
606 {
607 cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Missing Basic password.",
608 con->number);
609 return;
610 }
611
612 *ptr++ = '\0';
613
614 if (!username[0])
615 {
616 /*
617 * Username must not be empty...
618 */
619
620 cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Empty Basic username.",
621 con->number);
622 return;
623 }
624
625 if (!*ptr)
626 {
627 /*
628 * Password must not be empty...
629 */
630
631 cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Empty Basic password.",
632 con->number);
633 return;
634 }
635
636 strlcpy(password, ptr, sizeof(password));
637
638 /*
639 * Validate the username and password...
640 */
641
642 switch (type)
643 {
644 default :
645 case CUPSD_AUTH_BASIC :
646 {
647 #if HAVE_LIBPAM
648 /*
649 * Only use PAM to do authentication. This supports MD5
650 * passwords, among other things...
651 */
652
653 pam_handle_t *pamh; /* PAM authentication handle */
654 int pamerr; /* PAM error code */
655 struct pam_conv pamdata;/* PAM conversation data */
656 cupsd_authdata_t data; /* Authentication data */
657
658
659 strlcpy(data.username, username, sizeof(data.username));
660 strlcpy(data.password, password, sizeof(data.password));
661
662 # ifdef __sun
663 pamdata.conv = (int (*)(int, struct pam_message **,
664 struct pam_response **,
665 void *))pam_func;
666 # else
667 pamdata.conv = pam_func;
668 # endif /* __sun */
669 pamdata.appdata_ptr = &data;
670
671 pamerr = pam_start("cups", username, &pamdata, &pamh);
672 if (pamerr != PAM_SUCCESS)
673 {
674 cupsdLogMessage(CUPSD_LOG_ERROR,
675 "[Client %d] pam_start() returned %d (%s)",
676 con->number, pamerr, pam_strerror(pamh, pamerr));
677 return;
678 }
679
680 # ifdef HAVE_PAM_SET_ITEM
681 # ifdef PAM_RHOST
682 pamerr = pam_set_item(pamh, PAM_RHOST, con->http->hostname);
683 if (pamerr != PAM_SUCCESS)
684 cupsdLogMessage(CUPSD_LOG_WARN,
685 "[Client %d] pam_set_item(PAM_RHOST) "
686 "returned %d (%s)", con->number, pamerr,
687 pam_strerror(pamh, pamerr));
688 # endif /* PAM_RHOST */
689
690 # ifdef PAM_TTY
691 pamerr = pam_set_item(pamh, PAM_TTY, "cups");
692 if (pamerr != PAM_SUCCESS)
693 cupsdLogMessage(CUPSD_LOG_WARN,
694 "[Client %d] pam_set_item(PAM_TTY) "
695 "returned %d (%s)!", con->number, pamerr,
696 pam_strerror(pamh, pamerr));
697 # endif /* PAM_TTY */
698 # endif /* HAVE_PAM_SET_ITEM */
699
700 pamerr = pam_authenticate(pamh, PAM_SILENT);
701 if (pamerr != PAM_SUCCESS)
702 {
703 cupsdLogMessage(CUPSD_LOG_ERROR,
704 "[Client %d] pam_authenticate() returned %d (%s)",
705 con->number, pamerr, pam_strerror(pamh, pamerr));
706 pam_end(pamh, 0);
707 return;
708 }
709
710 # ifdef HAVE_PAM_SETCRED
711 pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
712 if (pamerr != PAM_SUCCESS)
713 cupsdLogMessage(CUPSD_LOG_WARN,
714 "[Client %d] pam_setcred() returned %d (%s)",
715 con->number, pamerr,
716 pam_strerror(pamh, pamerr));
717 # endif /* HAVE_PAM_SETCRED */
718
719 pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
720 if (pamerr != PAM_SUCCESS)
721 {
722 cupsdLogMessage(CUPSD_LOG_ERROR,
723 "[Client %d] pam_acct_mgmt() returned %d (%s)",
724 con->number, pamerr, pam_strerror(pamh, pamerr));
725 pam_end(pamh, 0);
726 return;
727 }
728
729 pam_end(pamh, PAM_SUCCESS);
730
731 #else
732 /*
733 * Use normal UNIX password file-based authentication...
734 */
735
736 char *pass; /* Encrypted password */
737 struct passwd *pw; /* User password data */
738 # ifdef HAVE_SHADOW_H
739 struct spwd *spw; /* Shadow password data */
740 # endif /* HAVE_SHADOW_H */
741
742
743 pw = getpwnam(username); /* Get the current password */
744 endpwent(); /* Close the password file */
745
746 if (!pw)
747 {
748 /*
749 * No such user...
750 */
751
752 cupsdLogMessage(CUPSD_LOG_ERROR,
753 "[Client %d] Unknown username \"%s\".",
754 con->number, username);
755 return;
756 }
757
758 # ifdef HAVE_SHADOW_H
759 spw = getspnam(username);
760 endspent();
761
762 if (!spw && !strcmp(pw->pw_passwd, "x"))
763 {
764 /*
765 * Don't allow blank passwords!
766 */
767
768 cupsdLogMessage(CUPSD_LOG_ERROR,
769 "[Client %d] Username \"%s\" has no shadow "
770 "password.", con->number, username);
771 return;
772 }
773
774 if (spw && !spw->sp_pwdp[0] && !pw->pw_passwd[0])
775 # else
776 if (!pw->pw_passwd[0])
777 # endif /* HAVE_SHADOW_H */
778 {
779 /*
780 * Don't allow blank passwords!
781 */
782
783 cupsdLogMessage(CUPSD_LOG_ERROR,
784 "[Client %d] Username \"%s\" has no password.",
785 con->number, username);
786 return;
787 }
788
789 /*
790 * OK, the password isn't blank, so compare with what came from the
791 * client...
792 */
793
794 pass = cups_crypt(password, pw->pw_passwd);
795
796 cupsdLogMessage(CUPSD_LOG_DEBUG2,
797 "[Client %d] pw_passwd=\"%s\", crypt=\"%s\"",
798 con->number, pw->pw_passwd, pass);
799
800 if (!pass || strcmp(pw->pw_passwd, pass))
801 {
802 # ifdef HAVE_SHADOW_H
803 if (spw)
804 {
805 pass = cups_crypt(password, spw->sp_pwdp);
806
807 cupsdLogMessage(CUPSD_LOG_DEBUG2,
808 "[Client %d] sp_pwdp=\"%s\", crypt=\"%s\"",
809 con->number, spw->sp_pwdp, pass);
810
811 if (pass == NULL || strcmp(spw->sp_pwdp, pass))
812 {
813 cupsdLogMessage(CUPSD_LOG_ERROR,
814 "[Client %d] Authentication failed for user "
815 "\"%s\".", con->number, username);
816 return;
817 }
818 }
819 else
820 # endif /* HAVE_SHADOW_H */
821 {
822 cupsdLogMessage(CUPSD_LOG_ERROR,
823 "[Client %d] Authentication failed for user "
824 "\"%s\".", con->number, username);
825 return;
826 }
827 }
828 #endif /* HAVE_LIBPAM */
829 }
830
831 cupsdLogMessage(CUPSD_LOG_DEBUG,
832 "[Client %d] Authorized as %s using Basic",
833 con->number, username);
834 break;
835
836 case CUPSD_AUTH_BASICDIGEST :
837 /*
838 * Do Basic authentication with the Digest password file...
839 */
840
841 if (!get_md5_password(username, NULL, md5))
842 {
843 cupsdLogMessage(CUPSD_LOG_ERROR,
844 "[Client %d] Unknown MD5 username \"%s\".",
845 con->number, username);
846 return;
847 }
848
849 httpMD5(username, "CUPS", password, basicmd5);
850
851 if (strcmp(md5, basicmd5))
852 {
853 cupsdLogMessage(CUPSD_LOG_ERROR,
854 "[Client %d] Authentication failed for \"%s\".",
855 con->number, username);
856 return;
857 }
858
859 cupsdLogMessage(CUPSD_LOG_DEBUG,
860 "[Client %d] Authorized as %s using BasicDigest",
861 con->number, username);
862 break;
863 }
864
865 con->type = type;
866 }
867 else if (!strncmp(authorization, "Digest", 6))
868 {
869 /*
870 * Get the username, password, and nonce from the Digest attributes...
871 */
872
873 if (!httpGetSubField2(con->http, HTTP_FIELD_AUTHORIZATION, "username",
874 username, sizeof(username)) || !username[0])
875 {
876 /*
877 * Username must not be empty...
878 */
879
880 cupsdLogMessage(CUPSD_LOG_ERROR,
881 "[Client %d] Empty or missing Digest username.",
882 con->number);
883 return;
884 }
885
886 if (!httpGetSubField2(con->http, HTTP_FIELD_AUTHORIZATION, "response",
887 password, sizeof(password)) || !password[0])
888 {
889 /*
890 * Password must not be empty...
891 */
892
893 cupsdLogMessage(CUPSD_LOG_ERROR,
894 "[Client %d] Empty or missing Digest password.",
895 con->number);
896 return;
897 }
898
899 if (!httpGetSubField(con->http, HTTP_FIELD_AUTHORIZATION, "nonce",
900 nonce))
901 {
902 cupsdLogMessage(CUPSD_LOG_ERROR,
903 "[Client %d] No nonce value for Digest authentication.",
904 con->number);
905 return;
906 }
907
908 if (strcmp(con->http->hostname, nonce))
909 {
910 cupsdLogMessage(CUPSD_LOG_ERROR,
911 "[Client %d] Bad nonce value, expected \"%s\", "
912 "got \"%s\".", con->number, con->http->hostname, nonce);
913 return;
914 }
915
916 /*
917 * Validate the username and password...
918 */
919
920 if (!get_md5_password(username, NULL, md5))
921 {
922 cupsdLogMessage(CUPSD_LOG_ERROR,
923 "[Client %d] Unknown MD5 username \"%s\".",
924 con->number, username);
925 return;
926 }
927
928 httpMD5Final(nonce, states[httpGetState(con->http)], con->uri, md5);
929
930 if (strcmp(md5, password))
931 {
932 cupsdLogMessage(CUPSD_LOG_ERROR,
933 "[Client %d] Authentication failed for \"%s\".",
934 con->number, username);
935 return;
936 }
937
938 cupsdLogMessage(CUPSD_LOG_DEBUG,
939 "[Client %d] Authorized as %s using Digest", con->number,
940 username);
941
942 con->type = CUPSD_AUTH_DIGEST;
943 }
944 #ifdef HAVE_GSSAPI
945 else if (!strncmp(authorization, "Negotiate", 9))
946 {
947 int len; /* Length of authorization string */
948 gss_ctx_id_t context; /* Authorization context */
949 OM_uint32 major_status, /* Major status code */
950 minor_status; /* Minor status code */
951 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER,
952 /* Input token from string */
953 output_token = GSS_C_EMPTY_BUFFER;
954 /* Output token for username */
955 gss_name_t client_name; /* Client name */
956
957
958 # ifdef __APPLE__
959 /*
960 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
961 * to use it...
962 */
963
964 if (gss_init_sec_context == NULL)
965 {
966 cupsdLogMessage(CUPSD_LOG_WARN,
967 "[Client %d] GSSAPI/Kerberos authentication failed "
968 "because the Kerberos framework is not present.",
969 con->number);
970 return;
971 }
972 # endif /* __APPLE__ */
973
974 /*
975 * Find the start of the Kerberos input token...
976 */
977
978 authorization += 9;
979 while (isspace(*authorization & 255))
980 authorization ++;
981
982 if (!*authorization)
983 {
984 cupsdLogMessage(CUPSD_LOG_DEBUG2,
985 "[Client %d] No authentication data specified.",
986 con->number);
987 return;
988 }
989
990 /*
991 * Decode the authorization string to get the input token...
992 */
993
994 len = (int)strlen(authorization);
995 input_token.value = malloc((size_t)len);
996 input_token.value = httpDecode64_2(input_token.value, &len,
997 authorization);
998 input_token.length = (size_t)len;
999
1000 /*
1001 * Accept the input token to get the authorization info...
1002 */
1003
1004 context = GSS_C_NO_CONTEXT;
1005 client_name = GSS_C_NO_NAME;
1006 major_status = gss_accept_sec_context(&minor_status,
1007 &context,
1008 ServerCreds,
1009 &input_token,
1010 GSS_C_NO_CHANNEL_BINDINGS,
1011 &client_name,
1012 NULL,
1013 &output_token,
1014 NULL,
1015 NULL,
1016 NULL);
1017
1018 if (output_token.length > 0)
1019 gss_release_buffer(&minor_status, &output_token);
1020
1021 if (GSS_ERROR(major_status))
1022 {
1023 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
1024 "[Client %d] Error accepting GSSAPI security context",
1025 con->number);
1026
1027 if (context != GSS_C_NO_CONTEXT)
1028 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
1029 return;
1030 }
1031
1032 con->have_gss = 1;
1033
1034 /*
1035 * Get the username associated with the client's credentials...
1036 */
1037
1038 if (major_status == GSS_S_CONTINUE_NEEDED)
1039 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
1040 "[Client %d] Credentials not complete", con->number);
1041 else if (major_status == GSS_S_COMPLETE)
1042 {
1043 major_status = gss_display_name(&minor_status, client_name,
1044 &output_token, NULL);
1045
1046 if (GSS_ERROR(major_status))
1047 {
1048 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
1049 "[Client %d] Error getting username", con->number);
1050 gss_release_name(&minor_status, &client_name);
1051 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
1052 return;
1053 }
1054
1055 strlcpy(username, output_token.value, sizeof(username));
1056
1057 cupsdLogMessage(CUPSD_LOG_DEBUG,
1058 "[Client %d] Authorized as %s using Negotiate",
1059 con->number, username);
1060
1061 gss_release_name(&minor_status, &client_name);
1062 gss_release_buffer(&minor_status, &output_token);
1063
1064 con->type = CUPSD_AUTH_NEGOTIATE;
1065 }
1066
1067 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
1068
1069 # if defined(SO_PEERCRED) && defined(AF_LOCAL)
1070 /*
1071 * Get the client's UID if we are printing locally - that allows a backend
1072 * to run as the correct user to get Kerberos credentials of its own.
1073 */
1074
1075 if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL)
1076 {
1077 cupsd_ucred_t peercred; /* Peer credentials */
1078 socklen_t peersize; /* Size of peer credentials */
1079
1080 peersize = sizeof(peercred);
1081
1082 # ifdef __APPLE__
1083 if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
1084 # else
1085 if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred,
1086 &peersize))
1087 # endif /* __APPLE__ */
1088 {
1089 cupsdLogMessage(CUPSD_LOG_ERROR,
1090 "[Client %d] Unable to get peer credentials - %s",
1091 con->number, strerror(errno));
1092 }
1093 else
1094 {
1095 cupsdLogMessage(CUPSD_LOG_DEBUG,
1096 "[Client %d] Using credentials for UID %d.",
1097 con->number, CUPSD_UCRED_UID(peercred));
1098 con->gss_uid = CUPSD_UCRED_UID(peercred);
1099 }
1100 }
1101 # endif /* SO_PEERCRED && AF_LOCAL */
1102 }
1103 #endif /* HAVE_GSSAPI */
1104 else
1105 {
1106 char scheme[256]; /* Auth scheme... */
1107
1108
1109 if (sscanf(authorization, "%255s", scheme) != 1)
1110 strlcpy(scheme, "UNKNOWN", sizeof(scheme));
1111
1112 cupsdLogMessage(CUPSD_LOG_ERROR,
1113 "[Client %d] Bad authentication data \"%s ...\"",
1114 con->number, scheme);
1115 return;
1116 }
1117
1118 /*
1119 * If we get here, then we were able to validate the username and
1120 * password - copy the validated username and password to the client
1121 * data and return...
1122 */
1123
1124 strlcpy(con->username, username, sizeof(con->username));
1125 strlcpy(con->password, password, sizeof(con->password));
1126 }
1127
1128
1129 /*
1130 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
1131 * access a location.
1132 */
1133
1134 int /* O - 1 if allowed, 0 otherwise */
1135 cupsdCheckAccess(
1136 unsigned ip[4], /* I - Client address */
1137 const char *name, /* I - Client hostname */
1138 size_t namelen, /* I - Length of hostname */
1139 cupsd_location_t *loc) /* I - Location to check */
1140 {
1141 int allow; /* 1 if allowed, 0 otherwise */
1142
1143
1144 if (!_cups_strcasecmp(name, "localhost"))
1145 {
1146 /*
1147 * Access from localhost (127.0.0.1 or ::1) is always allowed...
1148 */
1149
1150 return (1);
1151 }
1152 else
1153 {
1154 /*
1155 * Do authorization checks on the domain/address...
1156 */
1157
1158 switch (loc->order_type)
1159 {
1160 default :
1161 allow = 0; /* anti-compiler-warning-code */
1162 break;
1163
1164 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
1165 allow = 1;
1166
1167 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
1168 allow = 0;
1169
1170 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
1171 allow = 1;
1172 break;
1173
1174 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
1175 allow = 0;
1176
1177 if (cupsdCheckAuth(ip, name, namelen, loc->allow))
1178 allow = 1;
1179
1180 if (cupsdCheckAuth(ip, name, namelen, loc->deny))
1181 allow = 0;
1182 break;
1183 }
1184 }
1185
1186 return (allow);
1187 }
1188
1189
1190 /*
1191 * 'cupsdCheckAuth()' - Check authorization masks.
1192 */
1193
1194 int /* O - 1 if mask matches, 0 otherwise */
1195 cupsdCheckAuth(unsigned ip[4], /* I - Client address */
1196 const char *name, /* I - Client hostname */
1197 size_t name_len, /* I - Length of hostname */
1198 cups_array_t *masks) /* I - Masks */
1199 {
1200 int i; /* Looping var */
1201 cupsd_authmask_t *mask; /* Current mask */
1202 cupsd_netif_t *iface; /* Network interface */
1203 unsigned netip4; /* IPv4 network address */
1204 #ifdef AF_INET6
1205 unsigned netip6[4]; /* IPv6 network address */
1206 #endif /* AF_INET6 */
1207
1208
1209 for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
1210 mask;
1211 mask = (cupsd_authmask_t *)cupsArrayNext(masks))
1212 {
1213 switch (mask->type)
1214 {
1215 case CUPSD_AUTH_INTERFACE :
1216 /*
1217 * Check for a match with a network interface...
1218 */
1219
1220 netip4 = htonl(ip[3]);
1221
1222 #ifdef AF_INET6
1223 netip6[0] = htonl(ip[0]);
1224 netip6[1] = htonl(ip[1]);
1225 netip6[2] = htonl(ip[2]);
1226 netip6[3] = htonl(ip[3]);
1227 #endif /* AF_INET6 */
1228
1229 cupsdNetIFUpdate();
1230
1231 if (!strcmp(mask->mask.name.name, "*"))
1232 {
1233 #ifdef __APPLE__
1234 /*
1235 * Allow Back-to-My-Mac addresses...
1236 */
1237
1238 if ((ip[0] & 0xff000000) == 0xfd000000)
1239 return (1);
1240 #endif /* __APPLE__ */
1241
1242 /*
1243 * Check against all local interfaces...
1244 */
1245
1246 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1247 iface;
1248 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1249 {
1250 /*
1251 * Only check local interfaces...
1252 */
1253
1254 if (!iface->is_local)
1255 continue;
1256
1257 if (iface->address.addr.sa_family == AF_INET)
1258 {
1259 /*
1260 * Check IPv4 address...
1261 */
1262
1263 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1264 (iface->address.ipv4.sin_addr.s_addr &
1265 iface->mask.ipv4.sin_addr.s_addr))
1266 return (1);
1267 }
1268 #ifdef AF_INET6
1269 else
1270 {
1271 /*
1272 * Check IPv6 address...
1273 */
1274
1275 for (i = 0; i < 4; i ++)
1276 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1277 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1278 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1279 break;
1280
1281 if (i == 4)
1282 return (1);
1283 }
1284 #endif /* AF_INET6 */
1285 }
1286 }
1287 else
1288 {
1289 /*
1290 * Check the named interface...
1291 */
1292
1293 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1294 iface;
1295 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1296 {
1297 if (strcmp(mask->mask.name.name, iface->name))
1298 continue;
1299
1300 if (iface->address.addr.sa_family == AF_INET)
1301 {
1302 /*
1303 * Check IPv4 address...
1304 */
1305
1306 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1307 (iface->address.ipv4.sin_addr.s_addr &
1308 iface->mask.ipv4.sin_addr.s_addr))
1309 return (1);
1310 }
1311 #ifdef AF_INET6
1312 else
1313 {
1314 /*
1315 * Check IPv6 address...
1316 */
1317
1318 for (i = 0; i < 4; i ++)
1319 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1320 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1321 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1322 break;
1323
1324 if (i == 4)
1325 return (1);
1326 }
1327 #endif /* AF_INET6 */
1328 }
1329 }
1330 break;
1331
1332 case CUPSD_AUTH_NAME :
1333 /*
1334 * Check for exact name match...
1335 */
1336
1337 if (!_cups_strcasecmp(name, mask->mask.name.name))
1338 return (1);
1339
1340 /*
1341 * Check for domain match...
1342 */
1343
1344 if (name_len >= mask->mask.name.length &&
1345 mask->mask.name.name[0] == '.' &&
1346 !_cups_strcasecmp(name + name_len - mask->mask.name.length,
1347 mask->mask.name.name))
1348 return (1);
1349 break;
1350
1351 case CUPSD_AUTH_IP :
1352 /*
1353 * Check for IP/network address match...
1354 */
1355
1356 for (i = 0; i < 4; i ++)
1357 if ((ip[i] & mask->mask.ip.netmask[i]) !=
1358 mask->mask.ip.address[i])
1359 break;
1360
1361 if (i == 4)
1362 return (1);
1363 break;
1364 }
1365 }
1366
1367 return (0);
1368 }
1369
1370
1371 /*
1372 * 'cupsdCheckGroup()' - Check for a user's group membership.
1373 */
1374
1375 int /* O - 1 if user is a member, 0 otherwise */
1376 cupsdCheckGroup(
1377 const char *username, /* I - User name */
1378 struct passwd *user, /* I - System user info */
1379 const char *groupname) /* I - Group name */
1380 {
1381 int i; /* Looping var */
1382 struct group *group; /* System group info */
1383 char junk[33]; /* MD5 password (not used) */
1384 #ifdef HAVE_MBR_UID_TO_UUID
1385 uuid_t useruuid, /* UUID for username */
1386 groupuuid; /* UUID for groupname */
1387 int is_member; /* True if user is a member of group */
1388 #endif /* HAVE_MBR_UID_TO_UUID */
1389
1390
1391 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1392 "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")",
1393 username, user, groupname);
1394
1395 /*
1396 * Validate input...
1397 */
1398
1399 if (!username || !groupname)
1400 return (0);
1401
1402 /*
1403 * Check to see if the user is a member of the named group...
1404 */
1405
1406 group = getgrnam(groupname);
1407 endgrent();
1408
1409 if (group != NULL)
1410 {
1411 /*
1412 * Group exists, check it...
1413 */
1414
1415 for (i = 0; group->gr_mem[i]; i ++)
1416 if (!_cups_strcasecmp(username, group->gr_mem[i]))
1417 return (1);
1418 }
1419
1420 /*
1421 * Group doesn't exist or user not in group list, check the group ID
1422 * against the user's group ID...
1423 */
1424
1425 if (user && group && group->gr_gid == user->pw_gid)
1426 return (1);
1427
1428 #ifdef HAVE_MBR_UID_TO_UUID
1429 /*
1430 * Check group membership through MacOS X membership API...
1431 */
1432
1433 if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
1434 {
1435 if (group)
1436 {
1437 /*
1438 * Map group name to UUID and check membership...
1439 */
1440
1441 if (!mbr_gid_to_uuid(group->gr_gid, groupuuid))
1442 if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1443 if (is_member)
1444 return (1);
1445 }
1446 else if (groupname[0] == '#')
1447 {
1448 /*
1449 * Use UUID directly and check for equality (user UUID) and
1450 * membership (group UUID)...
1451 */
1452
1453 if (!uuid_parse((char *)groupname + 1, groupuuid))
1454 {
1455 if (!uuid_compare(useruuid, groupuuid))
1456 return (1);
1457 else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1458 if (is_member)
1459 return (1);
1460 }
1461
1462 return (0);
1463 }
1464 }
1465 else if (groupname[0] == '#')
1466 return (0);
1467 #endif /* HAVE_MBR_UID_TO_UUID */
1468
1469 /*
1470 * Username not found, group not found, or user is not part of the
1471 * system group... Check for a user and group in the MD5 password
1472 * file...
1473 */
1474
1475 if (get_md5_password(username, groupname, junk) != NULL)
1476 return (1);
1477
1478 /*
1479 * If we get this far, then the user isn't part of the named group...
1480 */
1481
1482 return (0);
1483 }
1484
1485
1486 /*
1487 * 'cupsdCopyLocation()' - Make a copy of a location...
1488 */
1489
1490 cupsd_location_t * /* O - New location */
1491 cupsdCopyLocation(
1492 cupsd_location_t *loc) /* I - Original location */
1493 {
1494 cupsd_location_t *temp; /* New location */
1495
1496
1497 /*
1498 * Make a copy of the original location...
1499 */
1500
1501 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
1502 return (NULL);
1503
1504 /*
1505 * Copy the information from the original location to the new one.
1506 */
1507
1508 if (!loc)
1509 return (temp);
1510
1511 if (loc->location)
1512 temp->location = _cupsStrAlloc(loc->location);
1513
1514 temp->limit = loc->limit;
1515 temp->order_type = loc->order_type;
1516 temp->type = loc->type;
1517 temp->level = loc->level;
1518 temp->satisfy = loc->satisfy;
1519 temp->encryption = loc->encryption;
1520
1521 if (loc->names)
1522 {
1523 if ((temp->names = cupsArrayDup(loc->names)) == NULL)
1524 {
1525 cupsdLogMessage(CUPSD_LOG_ERROR,
1526 "Unable to allocate memory for %d names: %s",
1527 cupsArrayCount(loc->names), strerror(errno));
1528
1529 cupsdFreeLocation(temp);
1530 return (NULL);
1531 }
1532 }
1533
1534 if (loc->allow)
1535 {
1536 /*
1537 * Copy allow rules...
1538 */
1539
1540 if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
1541 {
1542 cupsdLogMessage(CUPSD_LOG_ERROR,
1543 "Unable to allocate memory for %d allow rules: %s",
1544 cupsArrayCount(loc->allow), strerror(errno));
1545 cupsdFreeLocation(temp);
1546 return (NULL);
1547 }
1548 }
1549
1550 if (loc->deny)
1551 {
1552 /*
1553 * Copy deny rules...
1554 */
1555
1556 if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
1557 {
1558 cupsdLogMessage(CUPSD_LOG_ERROR,
1559 "Unable to allocate memory for %d deny rules: %s",
1560 cupsArrayCount(loc->deny), strerror(errno));
1561 cupsdFreeLocation(temp);
1562 return (NULL);
1563 }
1564 }
1565
1566 return (temp);
1567 }
1568
1569
1570 /*
1571 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1572 */
1573
1574 void
1575 cupsdDeleteAllLocations(void)
1576 {
1577 /*
1578 * Free the location array, which will free all of the locations...
1579 */
1580
1581 cupsArrayDelete(Locations);
1582 Locations = NULL;
1583 }
1584
1585
1586 /*
1587 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1588 */
1589
1590 cupsd_location_t * /* O - Location that matches */
1591 cupsdFindBest(const char *path, /* I - Resource path */
1592 http_state_t state) /* I - HTTP state/request */
1593 {
1594 char uri[HTTP_MAX_URI],
1595 /* URI in request... */
1596 *uriptr; /* Pointer into URI */
1597 cupsd_location_t *loc, /* Current location */
1598 *best; /* Best match for location so far */
1599 size_t bestlen; /* Length of best match */
1600 int limit; /* Limit field */
1601 static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
1602 {
1603 CUPSD_AUTH_LIMIT_ALL,
1604 CUPSD_AUTH_LIMIT_OPTIONS,
1605 CUPSD_AUTH_LIMIT_GET,
1606 CUPSD_AUTH_LIMIT_GET,
1607 CUPSD_AUTH_LIMIT_HEAD,
1608 CUPSD_AUTH_LIMIT_POST,
1609 CUPSD_AUTH_LIMIT_POST,
1610 CUPSD_AUTH_LIMIT_POST,
1611 CUPSD_AUTH_LIMIT_PUT,
1612 CUPSD_AUTH_LIMIT_PUT,
1613 CUPSD_AUTH_LIMIT_DELETE,
1614 CUPSD_AUTH_LIMIT_TRACE,
1615 CUPSD_AUTH_LIMIT_ALL,
1616 CUPSD_AUTH_LIMIT_ALL
1617 };
1618
1619
1620 /*
1621 * First copy the connection URI to a local string so we have drop
1622 * any .ppd extension from the pathname in /printers or /classes
1623 * URIs...
1624 */
1625
1626 strlcpy(uri, path, sizeof(uri));
1627
1628 if (!strncmp(uri, "/printers/", 10) ||
1629 !strncmp(uri, "/classes/", 9))
1630 {
1631 /*
1632 * Check if the URI has .ppd on the end...
1633 */
1634
1635 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
1636
1637 if (!strcmp(uriptr, ".ppd"))
1638 *uriptr = '\0';
1639 }
1640
1641 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri = \"%s\"...", uri);
1642
1643 /*
1644 * Loop through the list of locations to find a match...
1645 */
1646
1647 limit = limits[state];
1648 best = NULL;
1649 bestlen = 0;
1650
1651 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1652 loc;
1653 loc = (cupsd_location_t *)cupsArrayNext(Locations))
1654 {
1655 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x",
1656 loc->location ? loc->location : "nil", loc->limit);
1657
1658 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
1659 {
1660 /*
1661 * Use case-insensitive comparison for queue names...
1662 */
1663
1664 if (loc->length > bestlen && loc->location &&
1665 !_cups_strncasecmp(uri, loc->location, loc->length) &&
1666 loc->location[0] == '/' &&
1667 (limit & loc->limit) != 0)
1668 {
1669 best = loc;
1670 bestlen = loc->length;
1671 }
1672 }
1673 else
1674 {
1675 /*
1676 * Use case-sensitive comparison for other URIs...
1677 */
1678
1679 if (loc->length > bestlen && loc->location &&
1680 !strncmp(uri, loc->location, loc->length) &&
1681 loc->location[0] == '/' &&
1682 (limit & loc->limit) != 0)
1683 {
1684 best = loc;
1685 bestlen = loc->length;
1686 }
1687 }
1688 }
1689
1690 /*
1691 * Return the match, if any...
1692 */
1693
1694 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s",
1695 best ? best->location : "NONE");
1696
1697 return (best);
1698 }
1699
1700
1701 /*
1702 * 'cupsdFindLocation()' - Find the named location.
1703 */
1704
1705 cupsd_location_t * /* O - Location that matches */
1706 cupsdFindLocation(const char *location) /* I - Connection */
1707 {
1708 cupsd_location_t key; /* Search key */
1709
1710
1711 key.location = (char *)location;
1712
1713 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
1714 }
1715
1716
1717 /*
1718 * 'cupsdFreeLocation()' - Free all memory used by a location.
1719 */
1720
1721 void
1722 cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */
1723 {
1724 cupsArrayDelete(loc->names);
1725 cupsArrayDelete(loc->allow);
1726 cupsArrayDelete(loc->deny);
1727
1728 _cupsStrFree(loc->location);
1729 free(loc);
1730 }
1731
1732
1733 /*
1734 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
1735 */
1736
1737 http_status_t /* O - HTTP_OK if authorized or error code */
1738 cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
1739 const char *owner)/* I - Owner of object */
1740 {
1741 int i, /* Looping vars */
1742 auth, /* Authorization status */
1743 type; /* Type of authentication */
1744 http_addr_t *hostaddr = httpGetAddress(con->http);
1745 /* Client address */
1746 const char *hostname = httpGetHostname(con->http, NULL, 0);
1747 /* Client hostname */
1748 unsigned address[4]; /* Authorization address */
1749 cupsd_location_t *best; /* Best match for location so far */
1750 size_t hostlen; /* Length of hostname */
1751 char *name, /* Current username */
1752 username[256], /* Username to authorize */
1753 ownername[256], /* Owner name to authorize */
1754 *ptr; /* Pointer into username */
1755 struct passwd *pw; /* User password data */
1756 static const char * const levels[] = /* Auth levels */
1757 {
1758 "ANON",
1759 "USER",
1760 "GROUP"
1761 };
1762 static const char * const types[] = /* Auth types */
1763 {
1764 "None",
1765 "Basic",
1766 "Digest",
1767 "BasicDigest",
1768 "Negotiate"
1769 };
1770
1771
1772 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1773 "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
1774 con->uri, con->best, con->best ? con->best->location ?
1775 con->best->location : "(null)" : "");
1776 if (owner)
1777 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1778 "cupsdIsAuthorized: owner=\"%s\"", owner);
1779
1780 /*
1781 * If there is no "best" authentication rule for this request, then
1782 * access is allowed from the local system and denied from other
1783 * addresses...
1784 */
1785
1786 if (!con->best)
1787 {
1788 if (httpAddrLocalhost(httpGetAddress(con->http)) ||
1789 !strcmp(hostname, ServerName) ||
1790 cupsArrayFind(ServerAlias, (void *)hostname))
1791 return (HTTP_OK);
1792 else
1793 return (HTTP_FORBIDDEN);
1794 }
1795
1796 best = con->best;
1797
1798 if ((type = best->type) == CUPSD_AUTH_DEFAULT)
1799 type = cupsdDefaultAuthType();
1800
1801 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1802 "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, "
1803 "satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d",
1804 levels[best->level], types[type],
1805 best->satisfy ? "ANY" : "ALL", cupsArrayCount(best->names));
1806
1807 if (best->limit == CUPSD_AUTH_LIMIT_IPP)
1808 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
1809 best->op, ippOpString(best->op));
1810
1811 /*
1812 * Check host/ip-based accesses...
1813 */
1814
1815 #ifdef AF_INET6
1816 if (httpAddrFamily(hostaddr) == AF_INET6)
1817 {
1818 /*
1819 * Copy IPv6 address...
1820 */
1821
1822 address[0] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[0]);
1823 address[1] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[1]);
1824 address[2] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[2]);
1825 address[3] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[3]);
1826 }
1827 else
1828 #endif /* AF_INET6 */
1829 if (con->http->hostaddr->addr.sa_family == AF_INET)
1830 {
1831 /*
1832 * Copy IPv4 address...
1833 */
1834
1835 address[0] = 0;
1836 address[1] = 0;
1837 address[2] = 0;
1838 address[3] = ntohl(hostaddr->ipv4.sin_addr.s_addr);
1839 }
1840 else
1841 memset(address, 0, sizeof(address));
1842
1843 hostlen = strlen(hostname);
1844
1845 auth = cupsdCheckAccess(address, hostname, hostlen, best)
1846 ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
1847
1848 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...",
1849 auth ? "DENY" : "ALLOW");
1850
1851 if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
1852 return (HTTP_FORBIDDEN);
1853
1854 #ifdef HAVE_SSL
1855 /*
1856 * See if encryption is required...
1857 */
1858
1859 if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http->tls &&
1860 _cups_strcasecmp(hostname, "localhost") &&
1861 !httpAddrLocalhost(hostaddr) &&
1862 best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
1863 !(type == CUPSD_AUTH_NEGOTIATE ||
1864 (type == CUPSD_AUTH_NONE &&
1865 cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE)))
1866 {
1867 cupsdLogMessage(CUPSD_LOG_DEBUG,
1868 "cupsdIsAuthorized: Need upgrade to TLS...");
1869 return (HTTP_UPGRADE_REQUIRED);
1870 }
1871 #endif /* HAVE_SSL */
1872
1873 /*
1874 * Now see what access level is required...
1875 */
1876
1877 if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
1878 (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
1879 return (HTTP_OK);
1880
1881 if (!con->username[0] && type == CUPSD_AUTH_NONE &&
1882 best->limit == CUPSD_AUTH_LIMIT_IPP)
1883 {
1884 /*
1885 * Check for unauthenticated username...
1886 */
1887
1888 ipp_attribute_t *attr; /* requesting-user-name attribute */
1889
1890
1891 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1892 if (attr)
1893 {
1894 cupsdLogMessage(CUPSD_LOG_DEBUG,
1895 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
1896 attr->values[0].string.text);
1897 strlcpy(username, attr->values[0].string.text, sizeof(username));
1898 }
1899 else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
1900 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1901 else
1902 return (HTTP_OK); /* unless overridden with Satisfy */
1903 }
1904 else
1905 {
1906 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
1907 con->username);
1908
1909 #ifdef HAVE_AUTHORIZATION_H
1910 if (!con->username[0] && !con->authref)
1911 #else
1912 if (!con->username[0])
1913 #endif /* HAVE_AUTHORIZATION_H */
1914 {
1915 if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
1916 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
1917 else
1918 return (HTTP_OK); /* unless overridden with Satisfy */
1919 }
1920
1921
1922 if (con->type != type && type != CUPSD_AUTH_NONE &&
1923 #ifdef HAVE_GSSAPI
1924 (type != CUPSD_AUTH_NEGOTIATE || con->gss_uid <= 0) &&
1925 #endif /* HAVE_GSSAPI */
1926 (con->type != CUPSD_AUTH_BASIC || type != CUPSD_AUTH_BASICDIGEST))
1927 {
1928 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s!",
1929 types[con->type], types[type]);
1930
1931 return (HTTP_UNAUTHORIZED);
1932 }
1933
1934 strlcpy(username, con->username, sizeof(username));
1935 }
1936
1937 /*
1938 * OK, got a username. See if we need normal user access, or group
1939 * access... (root always matches)
1940 */
1941
1942 if (!strcmp(username, "root"))
1943 return (HTTP_OK);
1944
1945 /*
1946 * Strip any @domain or @KDC from the username and owner...
1947 */
1948
1949 if ((ptr = strchr(username, '@')) != NULL)
1950 *ptr = '\0';
1951
1952 if (owner)
1953 {
1954 strlcpy(ownername, owner, sizeof(ownername));
1955
1956 if ((ptr = strchr(ownername, '@')) != NULL)
1957 *ptr = '\0';
1958 }
1959 else
1960 ownername[0] = '\0';
1961
1962 /*
1963 * Get the user info...
1964 */
1965
1966 if (username[0])
1967 {
1968 pw = getpwnam(username);
1969 endpwent();
1970 }
1971 else
1972 pw = NULL;
1973
1974 if (best->level == CUPSD_AUTH_USER)
1975 {
1976 /*
1977 * If there are no names associated with this location, then
1978 * any valid user is OK...
1979 */
1980
1981 if (cupsArrayCount(best->names) == 0)
1982 return (HTTP_OK);
1983
1984 /*
1985 * Otherwise check the user list and return OK if this user is
1986 * allowed...
1987 */
1988
1989 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1990 "cupsdIsAuthorized: Checking user membership...");
1991
1992 #ifdef HAVE_AUTHORIZATION_H
1993 /*
1994 * If an authorization reference was supplied it must match a right name...
1995 */
1996
1997 if (con->authref)
1998 {
1999 for (name = (char *)cupsArrayFirst(best->names);
2000 name;
2001 name = (char *)cupsArrayNext(best->names))
2002 {
2003 if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
2004 return (HTTP_OK);
2005 else if (!_cups_strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
2006 check_authref(con, SystemGroupAuthKey))
2007 return (HTTP_OK);
2008 }
2009
2010 return (HTTP_FORBIDDEN);
2011 }
2012 #endif /* HAVE_AUTHORIZATION_H */
2013
2014 for (name = (char *)cupsArrayFirst(best->names);
2015 name;
2016 name = (char *)cupsArrayNext(best->names))
2017 {
2018 if (!_cups_strcasecmp(name, "@OWNER") && owner &&
2019 !_cups_strcasecmp(username, ownername))
2020 return (HTTP_OK);
2021 else if (!_cups_strcasecmp(name, "@SYSTEM"))
2022 {
2023 for (i = 0; i < NumSystemGroups; i ++)
2024 if (cupsdCheckGroup(username, pw, SystemGroups[i]))
2025 return (HTTP_OK);
2026 }
2027 else if (name[0] == '@')
2028 {
2029 if (cupsdCheckGroup(username, pw, name + 1))
2030 return (HTTP_OK);
2031 }
2032 else if (!_cups_strcasecmp(username, name))
2033 return (HTTP_OK);
2034 }
2035
2036 return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
2037 }
2038
2039 /*
2040 * Check to see if this user is in any of the named groups...
2041 */
2042
2043 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2044 "cupsdIsAuthorized: Checking group membership...");
2045
2046 /*
2047 * Check to see if this user is in any of the named groups...
2048 */
2049
2050 for (name = (char *)cupsArrayFirst(best->names);
2051 name;
2052 name = (char *)cupsArrayNext(best->names))
2053 {
2054 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2055 "cupsdIsAuthorized: Checking group \"%s\" membership...",
2056 name);
2057
2058 if (!_cups_strcasecmp(name, "@SYSTEM"))
2059 {
2060 for (i = 0; i < NumSystemGroups; i ++)
2061 if (cupsdCheckGroup(username, pw, SystemGroups[i]))
2062 return (HTTP_OK);
2063 }
2064 else if (cupsdCheckGroup(username, pw, name))
2065 return (HTTP_OK);
2066 }
2067
2068 /*
2069 * The user isn't part of the specified group, so deny access...
2070 */
2071
2072 cupsdLogMessage(CUPSD_LOG_DEBUG,
2073 "cupsdIsAuthorized: User not in group(s)!");
2074
2075 return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
2076 }
2077
2078
2079 /*
2080 * 'cupsdNewLocation()' - Create a new location for authorization.
2081 *
2082 * Note: Still need to call cupsdAddLocation() to add it to the list of global
2083 * locations.
2084 */
2085
2086 cupsd_location_t * /* O - Pointer to new location record */
2087 cupsdNewLocation(const char *location) /* I - Location path */
2088 {
2089 cupsd_location_t *temp; /* New location */
2090
2091
2092 /*
2093 * Try to allocate memory for the new location.
2094 */
2095
2096 if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
2097 return (NULL);
2098
2099 /*
2100 * Initialize the record and copy the name over...
2101 */
2102
2103 if ((temp->location = _cupsStrAlloc(location)) == NULL)
2104 {
2105 free(temp);
2106 return (NULL);
2107 }
2108
2109 temp->length = strlen(temp->location);
2110
2111 /*
2112 * Return the new record...
2113 */
2114
2115 return (temp);
2116 }
2117
2118
2119 #ifdef HAVE_AUTHORIZATION_H
2120 /*
2121 * 'check_authref()' - Check if an authorization services reference has the
2122 * supplied right.
2123 */
2124
2125 static int /* O - 1 if right is valid, 0 otherwise */
2126 check_authref(cupsd_client_t *con, /* I - Connection */
2127 const char *right) /* I - Right name */
2128 {
2129 OSStatus status; /* OS Status */
2130 AuthorizationItem authright; /* Authorization right */
2131 AuthorizationRights authrights; /* Authorization rights */
2132 AuthorizationFlags authflags; /* Authorization flags */
2133
2134
2135 /*
2136 * Check to see if the user is allowed to perform the task...
2137 */
2138
2139 if (!con->authref)
2140 return (0);
2141
2142 authright.name = right;
2143 authright.valueLength = 0;
2144 authright.value = NULL;
2145 authright.flags = 0;
2146
2147 authrights.count = 1;
2148 authrights.items = &authright;
2149
2150 authflags = kAuthorizationFlagDefaults |
2151 kAuthorizationFlagExtendRights;
2152
2153 if ((status = AuthorizationCopyRights(con->authref, &authrights,
2154 kAuthorizationEmptyEnvironment,
2155 authflags, NULL)) != 0)
2156 {
2157 cupsdLogMessage(CUPSD_LOG_ERROR,
2158 "AuthorizationCopyRights(\"%s\") returned %d (%s)",
2159 authright.name, (int)status, cssmErrorString(status));
2160 return (0);
2161 }
2162
2163 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2164 "AuthorizationCopyRights(\"%s\") succeeded!",
2165 authright.name);
2166
2167 return (1);
2168 }
2169 #endif /* HAVE_AUTHORIZATION_H */
2170
2171
2172 /*
2173 * 'compare_locations()' - Compare two locations.
2174 */
2175
2176 static int /* O - Result of comparison */
2177 compare_locations(cupsd_location_t *a, /* I - First location */
2178 cupsd_location_t *b) /* I - Second location */
2179 {
2180 return (strcmp(b->location, a->location));
2181 }
2182
2183
2184 /*
2185 * 'copy_authmask()' - Copy function for auth masks.
2186 */
2187
2188 static cupsd_authmask_t * /* O - New auth mask */
2189 copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */
2190 void *data) /* I - User data (unused) */
2191 {
2192 cupsd_authmask_t *temp; /* New auth mask */
2193
2194
2195 (void)data;
2196
2197 if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
2198 {
2199 memcpy(temp, mask, sizeof(cupsd_authmask_t));
2200
2201 if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
2202 {
2203 /*
2204 * Make a copy of the name...
2205 */
2206
2207 if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
2208 {
2209 /*
2210 * Failed to make copy...
2211 */
2212
2213 free(temp);
2214 temp = NULL;
2215 }
2216 }
2217 }
2218
2219 return (temp);
2220 }
2221
2222
2223 #if !HAVE_LIBPAM
2224 /*
2225 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
2226 * as needed.
2227 */
2228
2229 static char * /* O - Encrypted password */
2230 cups_crypt(const char *pw, /* I - Password string */
2231 const char *salt) /* I - Salt (key) string */
2232 {
2233 if (!strncmp(salt, "$1$", 3))
2234 {
2235 /*
2236 * Use MD5 passwords without the benefit of PAM; this is for
2237 * Slackware Linux, and the algorithm was taken from the
2238 * old shadow-19990827/lib/md5crypt.c source code... :(
2239 */
2240
2241 int i; /* Looping var */
2242 unsigned long n; /* Output number */
2243 int pwlen; /* Length of password string */
2244 const char *salt_end; /* End of "salt" data for MD5 */
2245 char *ptr; /* Pointer into result string */
2246 _cups_md5_state_t state; /* Primary MD5 state info */
2247 _cups_md5_state_t state2; /* Secondary MD5 state info */
2248 unsigned char digest[16]; /* MD5 digest result */
2249 static char result[120]; /* Final password string */
2250
2251
2252 /*
2253 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
2254 * Get a maximum of 8 characters of salt data after $1$...
2255 */
2256
2257 for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
2258 if (*salt_end == '$')
2259 break;
2260
2261 /*
2262 * Compute the MD5 sum we need...
2263 */
2264
2265 pwlen = strlen(pw);
2266
2267 _cupsMD5Init(&state);
2268 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2269 _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
2270
2271 _cupsMD5Init(&state2);
2272 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2273 _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
2274 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2275 _cupsMD5Finish(&state2, digest);
2276
2277 for (i = pwlen; i > 0; i -= 16)
2278 _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
2279
2280 for (i = pwlen; i > 0; i >>= 1)
2281 _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
2282
2283 _cupsMD5Finish(&state, digest);
2284
2285 for (i = 0; i < 1000; i ++)
2286 {
2287 _cupsMD5Init(&state);
2288
2289 if (i & 1)
2290 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2291 else
2292 _cupsMD5Append(&state, digest, 16);
2293
2294 if (i % 3)
2295 _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
2296
2297 if (i % 7)
2298 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2299
2300 if (i & 1)
2301 _cupsMD5Append(&state, digest, 16);
2302 else
2303 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2304
2305 _cupsMD5Finish(&state, digest);
2306 }
2307
2308 /*
2309 * Copy the final sum to the result string and return...
2310 */
2311
2312 memcpy(result, salt, salt_end - salt);
2313 ptr = result + (salt_end - salt);
2314 *ptr++ = '$';
2315
2316 for (i = 0; i < 5; i ++, ptr += 4)
2317 {
2318 n = (((digest[i] << 8) | digest[i + 6]) << 8);
2319
2320 if (i < 4)
2321 n |= digest[i + 12];
2322 else
2323 n |= digest[5];
2324
2325 to64(ptr, n, 4);
2326 }
2327
2328 to64(ptr, digest[11], 2);
2329 ptr += 2;
2330 *ptr = '\0';
2331
2332 return (result);
2333 }
2334 else
2335 {
2336 /*
2337 * Use the standard crypt() function...
2338 */
2339
2340 return (crypt(pw, salt));
2341 }
2342 }
2343 #endif /* !HAVE_LIBPAM */
2344
2345
2346 /*
2347 * 'free_authmask()' - Free function for auth masks.
2348 */
2349
2350 static void
2351 free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */
2352 void *data) /* I - User data (unused) */
2353 {
2354 (void)data;
2355
2356 if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
2357 _cupsStrFree(mask->mask.name.name);
2358
2359 free(mask);
2360 }
2361
2362
2363 /*
2364 * 'get_md5_password()' - Get an MD5 password.
2365 */
2366
2367 static char * /* O - MD5 password string */
2368 get_md5_password(const char *username, /* I - Username */
2369 const char *group, /* I - Group */
2370 char passwd[33]) /* O - MD5 password string */
2371 {
2372 cups_file_t *fp; /* passwd.md5 file */
2373 char filename[1024], /* passwd.md5 filename */
2374 line[256], /* Line from file */
2375 tempuser[33], /* User from file */
2376 tempgroup[33]; /* Group from file */
2377
2378
2379 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2380 "get_md5_password(username=\"%s\", group=\"%s\", passwd=%p)",
2381 username, group ? group : "(null)", passwd);
2382
2383 snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
2384 if ((fp = cupsFileOpen(filename, "r")) == NULL)
2385 {
2386 if (errno != ENOENT)
2387 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename,
2388 strerror(errno));
2389
2390 return (NULL);
2391 }
2392
2393 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
2394 {
2395 if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
2396 {
2397 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line);
2398 continue;
2399 }
2400
2401 if (!strcmp(username, tempuser) &&
2402 (group == NULL || !strcmp(group, tempgroup)))
2403 {
2404 /*
2405 * Found the password entry!
2406 */
2407
2408 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
2409 username, tempgroup);
2410
2411 cupsFileClose(fp);
2412 return (passwd);
2413 }
2414 }
2415
2416 /*
2417 * Didn't find a password entry - return NULL!
2418 */
2419
2420 cupsFileClose(fp);
2421 return (NULL);
2422 }
2423
2424
2425 #if HAVE_LIBPAM
2426 /*
2427 * 'pam_func()' - PAM conversation function.
2428 */
2429
2430 static int /* O - Success or failure */
2431 pam_func(
2432 int num_msg, /* I - Number of messages */
2433 const struct pam_message **msg, /* I - Messages */
2434 struct pam_response **resp, /* O - Responses */
2435 void *appdata_ptr)
2436 /* I - Pointer to connection */
2437 {
2438 int i; /* Looping var */
2439 struct pam_response *replies; /* Replies */
2440 cupsd_authdata_t *data; /* Pointer to auth data */
2441
2442
2443 /*
2444 * Allocate memory for the responses...
2445 */
2446
2447 if ((replies = malloc(sizeof(struct pam_response) * (size_t)num_msg)) == NULL)
2448 return (PAM_CONV_ERR);
2449
2450 /*
2451 * Answer all of the messages...
2452 */
2453
2454 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
2455
2456 data = (cupsd_authdata_t *)appdata_ptr;
2457
2458 for (i = 0; i < num_msg; i ++)
2459 {
2460 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
2461
2462 switch (msg[i]->msg_style)
2463 {
2464 case PAM_PROMPT_ECHO_ON:
2465 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2466 data->username));
2467 replies[i].resp_retcode = PAM_SUCCESS;
2468 replies[i].resp = strdup(data->username);
2469 break;
2470
2471 case PAM_PROMPT_ECHO_OFF:
2472 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2473 data->password));
2474 replies[i].resp_retcode = PAM_SUCCESS;
2475 replies[i].resp = strdup(data->password);
2476 break;
2477
2478 case PAM_TEXT_INFO:
2479 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2480 replies[i].resp_retcode = PAM_SUCCESS;
2481 replies[i].resp = NULL;
2482 break;
2483
2484 case PAM_ERROR_MSG:
2485 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2486 replies[i].resp_retcode = PAM_SUCCESS;
2487 replies[i].resp = NULL;
2488 break;
2489
2490 default:
2491 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2492 msg[i]->msg_style));
2493 free(replies);
2494 return (PAM_CONV_ERR);
2495 }
2496 }
2497
2498 /*
2499 * Return the responses back to PAM...
2500 */
2501
2502 *resp = replies;
2503
2504 return (PAM_SUCCESS);
2505 }
2506 #else
2507
2508
2509 /*
2510 * 'to64()' - Base64-encode an integer value...
2511 */
2512
2513 static void
2514 to64(char *s, /* O - Output string */
2515 unsigned long v, /* I - Value to encode */
2516 int n) /* I - Number of digits */
2517 {
2518 const char *itoa64 = "./0123456789"
2519 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2520 "abcdefghijklmnopqrstuvwxyz";
2521
2522
2523 for (; n > 0; n --, v >>= 6)
2524 *s++ = itoa64[v & 0x3f];
2525 }
2526 #endif /* HAVE_LIBPAM */
2527
2528
2529 /*
2530 * End of "$Id$".
2531 */