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