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