]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/auth.c
Import changes from CUPS 1.4svn-r8704.
[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
97c9a8d7
MS
1049 con->have_gss = 1;
1050
76cd9e37
MS
1051 /*
1052 * Get the username associated with the client's credentials...
f7deaa1a 1053 */
1054
e07d4801 1055 if (!con->gss_creds)
355e94dc 1056 cupsdLogMessage(CUPSD_LOG_DEBUG,
68b10830 1057 "cupsdAuthorize: No delegated credentials!");
355e94dc
MS
1058
1059 if (major_status == GSS_S_CONTINUE_NEEDED)
1060 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
e07d4801 1061 "cupsdAuthorize: Credentials not complete");
355e94dc 1062 else if (major_status == GSS_S_COMPLETE)
f7deaa1a 1063 {
1064 major_status = gss_display_name(&minor_status, client_name,
1065 &output_token, NULL);
1066
1067 if (GSS_ERROR(major_status))
1068 {
1069 cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
1070 "cupsdAuthorize: Error getting username");
e07d4801 1071 gss_release_cred(&minor_status, &con->gss_creds);
f7deaa1a 1072 gss_release_name(&minor_status, &client_name);
1073 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 1074 return;
1075 }
1076
f7deaa1a 1077 strlcpy(username, output_token.value, sizeof(username));
355e94dc
MS
1078
1079 cupsdLogMessage(CUPSD_LOG_DEBUG,
1080 "cupsdAuthorize: Authorized as %s using Negotiate",
1081 username);
f7deaa1a 1082
e07d4801 1083 gss_release_name(&minor_status, &client_name);
f7deaa1a 1084 gss_release_buffer(&minor_status, &output_token);
2fb76298 1085
5bd77a73 1086 con->type = CUPSD_AUTH_NEGOTIATE;
f7deaa1a 1087 }
1088 else
e07d4801
MS
1089 gss_release_cred(&minor_status, &con->gss_creds);
1090
1091 gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
f7deaa1a 1092 }
1093#endif /* HAVE_GSSAPI */
2fb76298 1094 else
ef416fc2 1095 {
355e94dc 1096 char scheme[256]; /* Auth scheme... */
355e94dc
MS
1097
1098
1099 if (sscanf(authorization, "%255s", scheme) != 1)
1100 strcpy(scheme, "UNKNOWN");
1101
2fb76298
MS
1102 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\"",
1103 scheme);
ef416fc2 1104 return;
1105 }
1106
1107 /*
1108 * If we get here, then we were able to validate the username and
1109 * password - copy the validated username and password to the client
1110 * data and return...
1111 */
1112
1113 strlcpy(con->username, username, sizeof(con->username));
1114 strlcpy(con->password, password, sizeof(con->password));
ef416fc2 1115}
1116
1117
080811b1
MS
1118/*
1119 * 'cupsdCheckAccess()' - Check whether the given address is allowed to
1120 * access a location.
1121 */
1122
1123int /* O - 1 if allowed, 0 otherwise */
1124cupsdCheckAccess(
1125 unsigned ip[4], /* I - Client address */
1126 char *name, /* I - Client hostname */
1127 int namelen, /* I - Length of hostname */
1128 cupsd_location_t *loc) /* I - Location to check */
1129{
1130 int allow; /* 1 if allowed, 0 otherwise */
1131
1132
1133 if (!strcasecmp(name, "localhost"))
1134 {
1135 /*
1136 * Access from localhost (127.0.0.1 or ::1) is always allowed...
1137 */
1138
1139 return (1);
1140 }
1141 else
1142 {
1143 /*
1144 * Do authorization checks on the domain/address...
1145 */
1146
1147 switch (loc->order_type)
1148 {
1149 default :
1150 allow = 0; /* anti-compiler-warning-code */
1151 break;
1152
5bd77a73 1153 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
080811b1
MS
1154 allow = 1;
1155
1156 if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
1157 allow = 0;
1158
1159 if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
1160 allow = 1;
1161 break;
1162
5bd77a73 1163 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
080811b1
MS
1164 allow = 0;
1165
1166 if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
1167 allow = 1;
1168
1169 if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
1170 allow = 0;
1171 break;
1172 }
1173 }
1174
1175 return (allow);
1176}
1177
1178
ef416fc2 1179/*
1180 * 'cupsdCheckAuth()' - Check authorization masks.
1181 */
1182
1183int /* O - 1 if mask matches, 0 otherwise */
1184cupsdCheckAuth(
1185 unsigned ip[4], /* I - Client address */
1186 char *name, /* I - Client hostname */
1187 int name_len, /* I - Length of hostname */
1188 int num_masks, /* I - Number of masks */
1189 cupsd_authmask_t *masks) /* I - Masks */
1190{
1191 int i; /* Looping var */
1192 cupsd_netif_t *iface; /* Network interface */
1193 unsigned netip4; /* IPv4 network address */
1194#ifdef AF_INET6
1195 unsigned netip6[4]; /* IPv6 network address */
1196#endif /* AF_INET6 */
1197
e07d4801 1198
ef416fc2 1199 while (num_masks > 0)
1200 {
1201 switch (masks->type)
1202 {
5bd77a73 1203 case CUPSD_AUTH_INTERFACE :
ef416fc2 1204 /*
1205 * Check for a match with a network interface...
1206 */
1207
1208 netip4 = htonl(ip[3]);
1209
1210#ifdef AF_INET6
1211 netip6[0] = htonl(ip[0]);
1212 netip6[1] = htonl(ip[1]);
1213 netip6[2] = htonl(ip[2]);
1214 netip6[3] = htonl(ip[3]);
1215#endif /* AF_INET6 */
1216
1217 if (!strcmp(masks->mask.name.name, "*"))
1218 {
e07d4801
MS
1219#ifdef __APPLE__
1220 /*
1221 * Allow Back-to-My-Mac addresses...
1222 */
1223
1224 if ((ip[0] & 0xff000000) == 0xfd000000)
1225 return (1);
1226#endif /* __APPLE__ */
1227
ef416fc2 1228 /*
1229 * Check against all local interfaces...
1230 */
1231
1232 cupsdNetIFUpdate();
1233
e00b005a 1234 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1235 iface;
1236 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 1237 {
1238 /*
1239 * Only check local interfaces...
1240 */
1241
1242 if (!iface->is_local)
1243 continue;
1244
1245 if (iface->address.addr.sa_family == AF_INET)
1246 {
1247 /*
1248 * Check IPv4 address...
1249 */
1250
1251 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1252 (iface->address.ipv4.sin_addr.s_addr &
1253 iface->mask.ipv4.sin_addr.s_addr))
1254 return (1);
1255 }
1256#ifdef AF_INET6
1257 else
1258 {
1259 /*
1260 * Check IPv6 address...
1261 */
1262
1263 for (i = 0; i < 4; i ++)
1264 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1265 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1266 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1267 break;
1268
1269 if (i == 4)
1270 return (1);
1271 }
1272#endif /* AF_INET6 */
1273 }
1274 }
1275 else
1276 {
1277 /*
1278 * Check the named interface...
1279 */
1280
e00b005a 1281 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
ed486911 1282 iface;
e00b005a 1283 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 1284 {
ed486911 1285 if (strcmp(masks->mask.name.name, iface->name))
1286 continue;
1287
ef416fc2 1288 if (iface->address.addr.sa_family == AF_INET)
1289 {
1290 /*
1291 * Check IPv4 address...
1292 */
1293
1294 if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
1295 (iface->address.ipv4.sin_addr.s_addr &
1296 iface->mask.ipv4.sin_addr.s_addr))
1297 return (1);
1298 }
1299#ifdef AF_INET6
1300 else
1301 {
1302 /*
1303 * Check IPv6 address...
1304 */
1305
1306 for (i = 0; i < 4; i ++)
1307 if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
1308 (iface->address.ipv6.sin6_addr.s6_addr32[i] &
1309 iface->mask.ipv6.sin6_addr.s6_addr32[i]))
1310 break;
1311
1312 if (i == 4)
1313 return (1);
1314 }
1315#endif /* AF_INET6 */
1316 }
1317 }
1318 break;
1319
5bd77a73 1320 case CUPSD_AUTH_NAME :
ef416fc2 1321 /*
1322 * Check for exact name match...
1323 */
1324
1325 if (!strcasecmp(name, masks->mask.name.name))
1326 return (1);
1327
1328 /*
1329 * Check for domain match...
1330 */
1331
1332 if (name_len >= masks->mask.name.length &&
1333 masks->mask.name.name[0] == '.' &&
bd7854cb 1334 !strcasecmp(name + name_len - masks->mask.name.length,
1335 masks->mask.name.name))
ef416fc2 1336 return (1);
1337 break;
1338
5bd77a73 1339 case CUPSD_AUTH_IP :
ef416fc2 1340 /*
1341 * Check for IP/network address match...
1342 */
1343
1344 for (i = 0; i < 4; i ++)
1345 if ((ip[i] & masks->mask.ip.netmask[i]) !=
1346 masks->mask.ip.address[i])
1347 break;
1348
1349 if (i == 4)
1350 return (1);
1351 break;
1352 }
1353
1354 masks ++;
1355 num_masks --;
1356 }
1357
1358 return (0);
1359}
1360
1361
1362/*
1363 * 'cupsdCheckGroup()' - Check for a user's group membership.
1364 */
1365
1366int /* O - 1 if user is a member, 0 otherwise */
1367cupsdCheckGroup(
1368 const char *username, /* I - User name */
1369 struct passwd *user, /* I - System user info */
1370 const char *groupname) /* I - Group name */
1371{
8922323b
MS
1372 int i; /* Looping var */
1373 struct group *group; /* System group info */
1374 char junk[33]; /* MD5 password (not used) */
bd7854cb 1375#ifdef HAVE_MBR_UID_TO_UUID
8922323b
MS
1376 uuid_t useruuid, /* UUID for username */
1377 groupuuid; /* UUID for groupname */
1378 int is_member; /* True if user is a member of group */
bd7854cb 1379#endif /* HAVE_MBR_UID_TO_UUID */
ef416fc2 1380
1381
1382 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1383 "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")",
1384 username, user, groupname);
1385
1386 /*
1387 * Validate input...
1388 */
1389
1390 if (!username || !groupname)
1391 return (0);
1392
1393 /*
1394 * Check to see if the user is a member of the named group...
1395 */
1396
1397 group = getgrnam(groupname);
1398 endgrent();
1399
1400 if (group != NULL)
1401 {
1402 /*
1403 * Group exists, check it...
1404 */
1405
1406 for (i = 0; group->gr_mem[i]; i ++)
1407 if (!strcasecmp(username, group->gr_mem[i]))
1408 return (1);
1409 }
1410
1411 /*
1412 * Group doesn't exist or user not in group list, check the group ID
1413 * against the user's group ID...
1414 */
1415
1416 if (user && group && group->gr_gid == user->pw_gid)
1417 return (1);
1418
bd7854cb 1419#ifdef HAVE_MBR_UID_TO_UUID
1420 /*
1421 * Check group membership through MacOS X membership API...
1422 */
1423
dd1abb6b 1424 if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
c9fc04c6 1425 {
8922323b
MS
1426 if (group)
1427 {
1428 /*
1429 * Map group name to UUID and check membership...
1430 */
c9fc04c6 1431
8922323b
MS
1432 if (!mbr_gid_to_uuid(group->gr_gid, groupuuid))
1433 if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1434 if (is_member)
1435 return (1);
1436 }
1437 else if (groupname[0] == '#')
1438 {
1439 /*
1440 * Use UUID directly and check for equality (user UUID) and
1441 * membership (group UUID)...
1442 */
1443
1444 if (!uuid_parse((char *)groupname + 1, groupuuid))
1445 {
1446 if (!uuid_compare(useruuid, groupuuid))
c9fc04c6 1447 return (1);
8922323b
MS
1448 else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
1449 if (is_member)
1450 return (1);
1451 }
1452
1453 return (0);
1454 }
1455 }
1456 else if (groupname[0] == '#')
1457 return (0);
bd7854cb 1458#endif /* HAVE_MBR_UID_TO_UUID */
1459
ef416fc2 1460 /*
1461 * Username not found, group not found, or user is not part of the
1462 * system group... Check for a user and group in the MD5 password
1463 * file...
1464 */
1465
e1d6a774 1466 if (get_md5_password(username, groupname, junk) != NULL)
ef416fc2 1467 return (1);
1468
1469 /*
1470 * If we get this far, then the user isn't part of the named group...
1471 */
1472
1473 return (0);
1474}
1475
1476
e07d4801
MS
1477#ifdef HAVE_GSSAPI
1478/*
1479 * 'cupsdCopyKrb5Creds()' - Get a copy of the Kerberos credentials.
1480 */
1481
1482krb5_ccache /* O - Credentials or NULL */
1483cupsdCopyKrb5Creds(cupsd_client_t *con) /* I - Client connection */
1484{
1485# if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL)
1486 cupsdLogMessage(CUPSD_LOG_INFO,
1487 "Sorry, your version of Kerberos does not support delegated "
1488 "credentials!");
1489 return (NULL);
1490
1491# else
1492 krb5_ccache ccache = NULL; /* Credentials */
1493 krb5_error_code error; /* Kerberos error code */
1494 OM_uint32 major_status, /* Major status code */
1495 minor_status; /* Minor status code */
1496 krb5_principal principal; /* Kerberos principal */
1497
1498
1499# ifdef __APPLE__
1500 /*
1501 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
1502 * to use it...
1503 */
1504
1505 if (krb5_init_context == NULL)
1506 return (NULL);
1507# endif /* __APPLE__ */
1508
1509 if (!KerberosInitialized)
1510 {
1511 /*
1512 * Setup a Kerberos context for the scheduler to use...
1513 */
1514
1515 KerberosInitialized = 1;
1516
1517 if (krb5_init_context(&KerberosContext))
1518 {
1519 KerberosContext = NULL;
1520
1521 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
1522 return (NULL);
1523 }
1524 }
1525
1526 /*
1527 * We MUST create a file-based cache because memory-based caches are
1528 * only valid for the current process/address space.
1529 *
1530 * Due to various bugs/features in different versions of Kerberos, we
1531 * need either the krb5_cc_new_unique() function or Heimdal's version
1532 * of krb5_cc_gen_new() to create a new FILE: credential cache that
1533 * can be passed to the backend. These functions create a temporary
1534 * file (typically in /tmp) containing the cached credentials, which
1535 * are removed when we have successfully printed a job.
1536 */
1537
1538# ifdef HAVE_KRB5_CC_NEW_UNIQUE
1539 if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL, &ccache)) != 0)
1540# else /* HAVE_HEIMDAL */
1541 if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops, &ccache)) != 0)
1542# endif /* HAVE_KRB5_CC_NEW_UNIQUE */
1543 {
1544 cupsdLogMessage(CUPSD_LOG_ERROR,
1545 "Unable to create new credentials cache (%d/%s)",
1546 error, strerror(errno));
1547 return (NULL);
1548 }
1549
1550 if ((error = krb5_parse_name(KerberosContext, con->username, &principal)) != 0)
1551 {
1552 cupsdLogMessage(CUPSD_LOG_ERROR,
1553 "Unable to parse kerberos username (%d/%s)", error,
1554 strerror(errno));
1555 krb5_cc_destroy(KerberosContext, ccache);
1556 return (NULL);
1557 }
1558
1559 if ((error = krb5_cc_initialize(KerberosContext, ccache, principal)))
1560 {
1561 cupsdLogMessage(CUPSD_LOG_ERROR,
1562 "Unable to initialize credentials cache (%d/%s)", error,
1563 strerror(errno));
1564 krb5_cc_destroy(KerberosContext, ccache);
1565 krb5_free_principal(KerberosContext, principal);
1566 return (NULL);
1567 }
1568
1569 krb5_free_principal(KerberosContext, principal);
1570
1571 /*
1572 * Copy the user's credentials to the new cache file...
1573 */
1574
1575# ifdef HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID
1576 if (con->http.hostaddr->addr.sa_family == AF_LOCAL &&
1577 !(con->gss_flags & GSS_C_DELEG_FLAG))
1578 {
1579 /*
1580 * Pull the credentials directly from the user...
1581 */
1582
1583 cupsd_ucred_t peercred; /* Peer credentials */
1584 socklen_t peersize; /* Size of peer credentials */
1585 krb5_ccache peerccache; /* Peer Kerberos credentials */
1586
1587 peersize = sizeof(peercred);
1588
68b10830
MS
1589# ifdef __APPLE__
1590 if (getsockopt(con->http.fd, 0, LOCAL_PEERCRED, &peercred, &peersize))
1591# else
e07d4801 1592 if (getsockopt(con->http.fd, SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
68b10830 1593# endif /* __APPLE__ */
e07d4801
MS
1594 {
1595 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s",
1596 strerror(errno));
1597 krb5_cc_destroy(KerberosContext, ccache);
1598 return (NULL);
1599 }
1600
68b10830
MS
1601 cupsdLogMessage(CUPSD_LOG_DEBUG,
1602 "cupsdCopyKrb5Creds: Copying credentials for UID %d...",
1603 CUPSD_UCRED_UID(peercred));
1604
e07d4801
MS
1605 krb5_ipc_client_set_target_uid(CUPSD_UCRED_UID(peercred));
1606
1607 if ((error = krb5_cc_default(KerberosContext, &peerccache)) != 0)
1608 {
1609 cupsdLogMessage(CUPSD_LOG_ERROR,
1610 "Unable to get credentials cache for UID %d (%d/%s)",
1611 (int)CUPSD_UCRED_UID(peercred), error, strerror(errno));
1612 krb5_cc_destroy(KerberosContext, ccache);
1613 return (NULL);
1614 }
1615
1616 error = krb5_cc_copy_creds(KerberosContext, peerccache, ccache);
1617 krb5_cc_close(KerberosContext, peerccache);
1618 krb5_ipc_client_clear_target();
1619
1620 if (error)
1621 {
1622 cupsdLogMessage(CUPSD_LOG_ERROR,
1623 "Unable to copy credentials cache for UID %d (%d/%s)",
1624 (int)CUPSD_UCRED_UID(peercred), error, strerror(errno));
1625 krb5_cc_destroy(KerberosContext, ccache);
1626 return (NULL);
1627 }
1628 }
1629 else
1630# endif /* HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID */
1631 {
1632 major_status = gss_krb5_copy_ccache(&minor_status, con->gss_creds, ccache);
1633
1634 if (GSS_ERROR(major_status))
1635 {
1636 cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status,
1637 "Unable to copy client credentials cache");
1638 krb5_cc_destroy(KerberosContext, ccache);
1639 return (NULL);
1640 }
1641 }
1642
1643 return (ccache);
1644# endif /* !HAVE_KRB5_CC_NEW_UNIQUE && !HAVE_HEIMDAL */
1645}
1646#endif /* HAVE_GSSAPI */
1647
1648
ef416fc2 1649/*
1650 * 'cupsdCopyLocation()' - Make a copy of a location...
1651 */
1652
1653cupsd_location_t * /* O - New location */
1654cupsdCopyLocation(
1655 cupsd_location_t **loc) /* IO - Original location */
1656{
1657 int i; /* Looping var */
ef416fc2 1658 cupsd_location_t *temp; /* New location */
1659 char location[HTTP_MAX_URI];
1660 /* Location of resource */
1661
1662
ef416fc2 1663 /*
1664 * Use a local copy of location because cupsdAddLocation may cause
1665 * this memory to be moved...
1666 */
1667
1668 strlcpy(location, (*loc)->location, sizeof(location));
1669
1670 if ((temp = cupsdAddLocation(location)) == NULL)
1671 return (NULL);
1672
ef416fc2 1673 /*
1674 * Copy the information from the original location to the new one.
1675 */
1676
1677 temp->limit = (*loc)->limit;
1678 temp->order_type = (*loc)->order_type;
1679 temp->type = (*loc)->type;
1680 temp->level = (*loc)->level;
1681 temp->satisfy = (*loc)->satisfy;
1682 temp->encryption = (*loc)->encryption;
1683
1684 if ((temp->num_names = (*loc)->num_names) > 0)
1685 {
1686 /*
1687 * Copy the names array...
1688 */
1689
1690 if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
1691 {
1692 cupsdLogMessage(CUPSD_LOG_ERROR,
1693 "cupsdCopyLocation: Unable to allocate memory for %d names: %s",
1694 temp->num_names, strerror(errno));
bd7854cb 1695
1696 cupsdDeleteLocation(temp);
ef416fc2 1697 return (NULL);
1698 }
1699
1700 for (i = 0; i < temp->num_names; i ++)
1701 if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
1702 {
1703 cupsdLogMessage(CUPSD_LOG_ERROR,
1704 "cupsdCopyLocation: Unable to copy name \"%s\": %s",
1705 (*loc)->names[i], strerror(errno));
1706
bd7854cb 1707 cupsdDeleteLocation(temp);
ef416fc2 1708 return (NULL);
1709 }
1710 }
1711
1712 if ((temp->num_allow = (*loc)->num_allow) > 0)
1713 {
1714 /*
1715 * Copy allow rules...
1716 */
1717
1718 if ((temp->allow = calloc(temp->num_allow, sizeof(cupsd_authmask_t))) == NULL)
1719 {
1720 cupsdLogMessage(CUPSD_LOG_ERROR,
1721 "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s",
1722 temp->num_allow, strerror(errno));
bd7854cb 1723 cupsdDeleteLocation(temp);
ef416fc2 1724 return (NULL);
1725 }
1726
1727 for (i = 0; i < temp->num_allow; i ++)
1728 switch (temp->allow[i].type = (*loc)->allow[i].type)
1729 {
5bd77a73 1730 case CUPSD_AUTH_NAME :
ef416fc2 1731 temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
1732 temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
1733
1734 if (temp->allow[i].mask.name.name == NULL)
1735 {
1736 cupsdLogMessage(CUPSD_LOG_ERROR,
1737 "cupsdCopyLocation: Unable to copy allow name \"%s\": %s",
1738 (*loc)->allow[i].mask.name.name, strerror(errno));
bd7854cb 1739 cupsdDeleteLocation(temp);
ef416fc2 1740 return (NULL);
1741 }
1742 break;
5bd77a73 1743 case CUPSD_AUTH_IP :
ef416fc2 1744 memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
1745 sizeof(cupsd_ipmask_t));
1746 break;
1747 }
1748 }
1749
1750 if ((temp->num_deny = (*loc)->num_deny) > 0)
1751 {
1752 /*
1753 * Copy deny rules...
1754 */
1755
1756 if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL)
1757 {
1758 cupsdLogMessage(CUPSD_LOG_ERROR,
1759 "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s",
1760 temp->num_deny, strerror(errno));
bd7854cb 1761 cupsdDeleteLocation(temp);
ef416fc2 1762 return (NULL);
1763 }
1764
1765 for (i = 0; i < temp->num_deny; i ++)
1766 switch (temp->deny[i].type = (*loc)->deny[i].type)
1767 {
5bd77a73 1768 case CUPSD_AUTH_NAME :
ef416fc2 1769 temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
1770 temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
1771
1772 if (temp->deny[i].mask.name.name == NULL)
1773 {
1774 cupsdLogMessage(CUPSD_LOG_ERROR,
1775 "cupsdCopyLocation: Unable to copy deny name \"%s\": %s",
1776 (*loc)->deny[i].mask.name.name, strerror(errno));
bd7854cb 1777 cupsdDeleteLocation(temp);
ef416fc2 1778 return (NULL);
1779 }
1780 break;
5bd77a73 1781 case CUPSD_AUTH_IP :
ef416fc2 1782 memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
1783 sizeof(cupsd_ipmask_t));
1784 break;
1785 }
1786 }
1787
1788 return (temp);
1789}
1790
1791
1792/*
1793 * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
1794 */
1795
1796void
1797cupsdDeleteAllLocations(void)
1798{
ef416fc2 1799 cupsd_location_t *loc; /* Current location */
1800
1801
1802 /*
1803 * Free all of the allow/deny records first...
1804 */
1805
bd7854cb 1806 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
1807 loc;
1808 loc = (cupsd_location_t *)cupsArrayNext(Locations))
ef416fc2 1809 cupsdDeleteLocation(loc);
1810
1811 /*
1812 * Then free the location array...
1813 */
1814
bd7854cb 1815 cupsArrayDelete(Locations);
1816 Locations = NULL;
ef416fc2 1817}
1818
1819
1820/*
1821 * 'cupsdDeleteLocation()' - Free all memory used by a location.
1822 */
1823
1824void
1825cupsdDeleteLocation(
1826 cupsd_location_t *loc) /* I - Location to delete */
1827{
1828 int i; /* Looping var */
1829 cupsd_authmask_t *mask; /* Current mask */
1830
1831
bd7854cb 1832 cupsArrayRemove(Locations, loc);
1833
ef416fc2 1834 for (i = loc->num_names - 1; i >= 0; i --)
1835 free(loc->names[i]);
1836
1837 if (loc->num_names > 0)
1838 free(loc->names);
1839
1840 for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++)
5bd77a73 1841 if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
ef416fc2 1842 free(mask->mask.name.name);
1843
1844 if (loc->num_allow > 0)
1845 free(loc->allow);
1846
1847 for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++)
5bd77a73 1848 if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
ef416fc2 1849 free(mask->mask.name.name);
1850
1851 if (loc->num_deny > 0)
1852 free(loc->deny);
bd7854cb 1853
1854 free(loc->location);
1855 free(loc);
ef416fc2 1856}
1857
1858
1859/*
1860 * 'cupsdDenyHost()' - Add a host name that is not allowed to access the
1861 * location.
1862 */
1863
1864void
1865cupsdDenyHost(cupsd_location_t *loc, /* I - Location to add to */
1866 char *name) /* I - Name of host or domain to add */
1867{
1868 cupsd_authmask_t *temp; /* New host/domain mask */
1869 char ifname[32], /* Interface name */
1870 *ifptr; /* Pointer to end of name */
1871
1872
1873 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")",
e1d6a774 1874 loc, loc->location ? loc->location : "nil", name);
ef416fc2 1875
1876 if ((temp = add_deny(loc)) == NULL)
1877 return;
1878
bd7854cb 1879 if (!strcasecmp(name, "@LOCAL"))
ef416fc2 1880 {
1881 /*
1882 * Deny *interface*...
1883 */
1884
5bd77a73 1885 temp->type = CUPSD_AUTH_INTERFACE;
ef416fc2 1886 temp->mask.name.name = strdup("*");
1887 temp->mask.name.length = 1;
1888 }
bd7854cb 1889 else if (!strncasecmp(name, "@IF(", 4))
ef416fc2 1890 {
1891 /*
1892 * Deny *interface*...
1893 */
1894
1895 strlcpy(ifname, name + 4, sizeof(ifname));
1896
1897 ifptr = ifname + strlen(ifname);
1898
1899 if (ifptr[-1] == ')')
1900 {
1901 ifptr --;
1902 *ifptr = '\0';
1903 }
1904
5bd77a73 1905 temp->type = CUPSD_AUTH_INTERFACE;
ef416fc2 1906 temp->mask.name.name = strdup(ifname);
1907 temp->mask.name.length = ifptr - ifname;
1908 }
1909 else
1910 {
1911 /*
1912 * Deny name...
1913 */
1914
5bd77a73 1915 temp->type = CUPSD_AUTH_NAME;
ef416fc2 1916 temp->mask.name.name = strdup(name);
1917 temp->mask.name.length = strlen(name);
1918 }
1919}
1920
1921
1922/*
1923 * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to
1924 * access the location.
1925 */
1926
1927void
1928cupsdDenyIP(cupsd_location_t *loc, /* I - Location to add to */
ac884b6a
MS
1929 const unsigned address[4],/* I - IP address to add */
1930 const unsigned netmask[4])/* I - Netmask of address */
ef416fc2 1931{
1932 cupsd_authmask_t *temp; /* New host/domain mask */
1933
1934
1935 cupsdLogMessage(CUPSD_LOG_DEBUG,
1936 "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
e1d6a774 1937 loc, loc->location ? loc->location : "nil",
1938 address[0], address[1], address[2], address[3],
1939 netmask[0], netmask[1], netmask[2], netmask[3]);
ef416fc2 1940
1941 if ((temp = add_deny(loc)) == NULL)
1942 return;
1943
5bd77a73 1944 temp->type = CUPSD_AUTH_IP;
ef416fc2 1945 memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
1946 memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
1947}
1948
1949
1950/*
1951 * 'cupsdFindBest()' - Find the location entry that best matches the resource.
1952 */
1953
1954cupsd_location_t * /* O - Location that matches */
1955cupsdFindBest(const char *path, /* I - Resource path */
1956 http_state_t state) /* I - HTTP state/request */
1957{
ef416fc2 1958 char uri[HTTP_MAX_URI],
1959 /* URI in request... */
1960 *uriptr; /* Pointer into URI */
1961 cupsd_location_t *loc, /* Current location */
1962 *best; /* Best match for location so far */
1963 int bestlen; /* Length of best match */
1964 int limit; /* Limit field */
5bd77a73 1965 static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
ef416fc2 1966 {
5bd77a73
MS
1967 CUPSD_AUTH_LIMIT_ALL,
1968 CUPSD_AUTH_LIMIT_OPTIONS,
1969 CUPSD_AUTH_LIMIT_GET,
1970 CUPSD_AUTH_LIMIT_GET,
1971 CUPSD_AUTH_LIMIT_HEAD,
1972 CUPSD_AUTH_LIMIT_POST,
1973 CUPSD_AUTH_LIMIT_POST,
1974 CUPSD_AUTH_LIMIT_POST,
1975 CUPSD_AUTH_LIMIT_PUT,
1976 CUPSD_AUTH_LIMIT_PUT,
1977 CUPSD_AUTH_LIMIT_DELETE,
1978 CUPSD_AUTH_LIMIT_TRACE,
1979 CUPSD_AUTH_LIMIT_ALL,
1980 CUPSD_AUTH_LIMIT_ALL
ef416fc2 1981 };
1982
1983
1984 /*
1985 * First copy the connection URI to a local string so we have drop
1986 * any .ppd extension from the pathname in /printers or /classes
1987 * URIs...
1988 */
1989
1990 strlcpy(uri, path, sizeof(uri));
1991
1992 if (!strncmp(uri, "/printers/", 10) ||
1993 !strncmp(uri, "/classes/", 9))
1994 {
1995 /*
1996 * Check if the URI has .ppd on the end...
1997 */
1998
1999 uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
2000
2001 if (!strcmp(uriptr, ".ppd"))
2002 *uriptr = '\0';
2003 }
2004
2005 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri = \"%s\"...", uri);
2006
2007 /*
2008 * Loop through the list of locations to find a match...
2009 */
2010
2011 limit = limits[state];
2012 best = NULL;
2013 bestlen = 0;
2014
bd7854cb 2015 for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
2016 loc;
2017 loc = (cupsd_location_t *)cupsArrayNext(Locations))
ef416fc2 2018 {
2019 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x",
e1d6a774 2020 loc->location ? loc->location : "nil", loc->limit);
ef416fc2 2021
2022 if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
2023 {
2024 /*
2025 * Use case-insensitive comparison for queue names...
2026 */
2027
e1d6a774 2028 if (loc->length > bestlen && loc->location &&
bd7854cb 2029 !strncasecmp(uri, loc->location, loc->length) &&
ef416fc2 2030 loc->location[0] == '/' &&
2031 (limit & loc->limit) != 0)
2032 {
2033 best = loc;
2034 bestlen = loc->length;
2035 }
2036 }
2037 else
2038 {
2039 /*
2040 * Use case-sensitive comparison for other URIs...
2041 */
2042
e1d6a774 2043 if (loc->length > bestlen && loc->location &&
ef416fc2 2044 !strncmp(uri, loc->location, loc->length) &&
2045 loc->location[0] == '/' &&
2046 (limit & loc->limit) != 0)
2047 {
2048 best = loc;
2049 bestlen = loc->length;
2050 }
2051 }
2052 }
2053
2054 /*
2055 * Return the match, if any...
2056 */
2057
2058 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s",
2059 best ? best->location : "NONE");
2060
2061 return (best);
2062}
2063
2064
2065/*
2066 * 'cupsdFindLocation()' - Find the named location.
2067 */
2068
2069cupsd_location_t * /* O - Location that matches */
2070cupsdFindLocation(const char *location) /* I - Connection */
2071{
bd7854cb 2072 cupsd_location_t key; /* Search key */
ef416fc2 2073
2074
bd7854cb 2075 key.location = (char *)location;
ef416fc2 2076
bd7854cb 2077 return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
ef416fc2 2078}
2079
2080
ef416fc2 2081/*
2082 * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
2083 */
2084
2085http_status_t /* O - HTTP_OK if authorized or error code */
2086cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
2087 const char *owner)/* I - Owner of object */
2088{
2089 int i, j, /* Looping vars */
2fb76298
MS
2090 auth, /* Authorization status */
2091 type; /* Type of authentication */
ef416fc2 2092 unsigned address[4]; /* Authorization address */
2093 cupsd_location_t *best; /* Best match for location so far */
2094 int hostlen; /* Length of hostname */
db1f069b
MS
2095 char username[256], /* Username to authorize */
2096 ownername[256], /* Owner name to authorize */
2097 *ptr; /* Pointer into username */
ef416fc2 2098 struct passwd *pw; /* User password data */
2099 static const char * const levels[] = /* Auth levels */
2100 {
2101 "ANON",
2102 "USER",
2103 "GROUP"
2104 };
2105 static const char * const types[] = /* Auth types */
2106 {
2fb76298
MS
2107 "None",
2108 "Basic",
2109 "Digest",
2110 "BasicDigest",
2111 "Negotiate"
ef416fc2 2112 };
2113
2114
2115 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2116 "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
f301802f 2117 con->uri, con->best, con->best ? con->best->location ?
2118 con->best->location : "(null)" : "");
fa73b229 2119 if (owner)
2120 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2121 "cupsdIsAuthorized: owner=\"%s\"", owner);
ef416fc2 2122
2123 /*
2124 * If there is no "best" authentication rule for this request, then
2125 * access is allowed from the local system and denied from other
2126 * addresses...
2127 */
2128
2129 if (!con->best)
2130 {
2131 if (!strcmp(con->http.hostname, "localhost") ||
2132 !strcmp(con->http.hostname, ServerName))
2133 return (HTTP_OK);
2134 else
2135 return (HTTP_FORBIDDEN);
2136 }
2137
2138 best = con->best;
2139
5bd77a73 2140 if ((type = best->type) == CUPSD_AUTH_DEFAULT)
2fb76298
MS
2141 type = DefaultAuthType;
2142
ef416fc2 2143 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5bd77a73
MS
2144 "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, "
2145 "satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d",
2fb76298 2146 levels[best->level], types[type],
ef416fc2 2147 best->satisfy ? "ANY" : "ALL", best->num_names);
2148
5bd77a73 2149 if (best->limit == CUPSD_AUTH_LIMIT_IPP)
ef416fc2 2150 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
2151 best->op, ippOpString(best->op));
2152
2153 /*
2154 * Check host/ip-based accesses...
2155 */
2156
2157#ifdef AF_INET6
2158 if (con->http.hostaddr->addr.sa_family == AF_INET6)
2159 {
2160 /*
2161 * Copy IPv6 address...
2162 */
2163
2164 address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]);
2165 address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]);
2166 address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]);
2167 address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]);
2168 }
2169 else
2170#endif /* AF_INET6 */
2171 if (con->http.hostaddr->addr.sa_family == AF_INET)
2172 {
2173 /*
2174 * Copy IPv4 address...
2175 */
2176
2177 address[0] = 0;
2178 address[1] = 0;
2179 address[2] = 0;
2180 address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr);
2181 }
2182 else
2183 memset(address, 0, sizeof(address));
2184
2185 hostlen = strlen(con->http.hostname);
2186
080811b1 2187 auth = cupsdCheckAccess(address, con->http.hostname, hostlen, best)
5bd77a73 2188 ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
ef416fc2 2189
5bd77a73 2190 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...",
ef416fc2 2191 auth ? "DENY" : "ALLOW");
2192
5bd77a73 2193 if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
ef416fc2 2194 return (HTTP_FORBIDDEN);
2195
2196#ifdef HAVE_SSL
2197 /*
2198 * See if encryption is required...
2199 */
2200
f7deaa1a 2201 if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
a74454a7 2202 strcasecmp(con->http.hostname, "localhost") &&
5bd77a73
MS
2203 best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
2204 !(type == CUPSD_AUTH_NEGOTIATE ||
2205 (type == CUPSD_AUTH_NONE && DefaultAuthType == CUPSD_AUTH_NEGOTIATE)))
ef416fc2 2206 {
355e94dc 2207 cupsdLogMessage(CUPSD_LOG_DEBUG,
ef416fc2 2208 "cupsdIsAuthorized: Need upgrade to TLS...");
2209 return (HTTP_UPGRADE_REQUIRED);
2210 }
2211#endif /* HAVE_SSL */
2212
2213 /*
2214 * Now see what access level is required...
2215 */
2216
5bd77a73
MS
2217 if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
2218 (type == CUPSD_AUTH_NONE && best->num_names == 0))
ef416fc2 2219 return (HTTP_OK);
2220
5bd77a73
MS
2221 if (!con->username[0] && type == CUPSD_AUTH_NONE &&
2222 best->limit == CUPSD_AUTH_LIMIT_IPP)
ef416fc2 2223 {
2224 /*
2225 * Check for unauthenticated username...
2226 */
2227
2228 ipp_attribute_t *attr; /* requesting-user-name attribute */
2229
2230
2231 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
2232 if (attr)
2233 {
355e94dc 2234 cupsdLogMessage(CUPSD_LOG_DEBUG,
ef416fc2 2235 "cupsdIsAuthorized: requesting-user-name=\"%s\"",
2236 attr->values[0].string.text);
db1f069b 2237 strlcpy(username, attr->values[0].string.text, sizeof(username));
ef416fc2 2238 }
5bd77a73 2239 else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
ef416fc2 2240 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
2241 else
2242 return (HTTP_OK); /* unless overridden with Satisfy */
2243 }
fa73b229 2244 else
2245 {
355e94dc 2246 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
fa73b229 2247 con->username);
2248
f7deaa1a 2249#ifdef HAVE_AUTHORIZATION_H
2250 if (!con->username[0] && !con->authref)
2251#else
fa73b229 2252 if (!con->username[0])
f7deaa1a 2253#endif /* HAVE_AUTHORIZATION_H */
fa73b229 2254 {
5bd77a73 2255 if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
fa73b229 2256 return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
2257 else
2258 return (HTTP_OK); /* unless overridden with Satisfy */
2259 }
2260
5bd77a73
MS
2261 if (con->type != type && type != CUPSD_AUTH_NONE &&
2262 (con->type != CUPSD_AUTH_BASIC || type != CUPSD_AUTH_BASICDIGEST))
2fb76298
MS
2263 {
2264 cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s!",
2265 types[con->type], types[type]);
2266
2267 return (HTTP_UNAUTHORIZED);
2268 }
2269
db1f069b 2270 strlcpy(username, con->username, sizeof(username));
fa73b229 2271 }
ef416fc2 2272
2273 /*
fa73b229 2274 * OK, got a username. See if we need normal user access, or group
ef416fc2 2275 * access... (root always matches)
2276 */
2277
fa73b229 2278 if (!strcmp(username, "root"))
ef416fc2 2279 return (HTTP_OK);
2280
db1f069b
MS
2281 /*
2282 * Strip any @domain or @KDC from the username and owner...
2283 */
2284
2285 if ((ptr = strchr(username, '@')) != NULL)
2286 *ptr = '\0';
2287
2288 if (owner)
2289 {
2290 strlcpy(ownername, owner, sizeof(ownername));
2291
2292 if ((ptr = strchr(ownername, '@')) != NULL)
2293 *ptr = '\0';
2294 }
2295 else
2296 ownername[0] = '\0';
2297
ef416fc2 2298 /*
2299 * Get the user info...
2300 */
2301
f7deaa1a 2302 if (username[0])
2303 {
2304 pw = getpwnam(username);
2305 endpwent();
2306 }
2307 else
2308 pw = NULL;
ef416fc2 2309
5bd77a73 2310 if (best->level == CUPSD_AUTH_USER)
ef416fc2 2311 {
2312 /*
2313 * If there are no names associated with this location, then
2314 * any valid user is OK...
2315 */
2316
2317 if (best->num_names == 0)
2318 return (HTTP_OK);
2319
2320 /*
2321 * Otherwise check the user list and return OK if this user is
2322 * allowed...
2323 */
2324
2325 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2326 "cupsdIsAuthorized: Checking user membership...");
2327
f7deaa1a 2328#ifdef HAVE_AUTHORIZATION_H
2329 /*
2330 * If an authorization reference was supplied it must match a right name...
2331 */
2332
2333 if (con->authref)
2334 {
2335 for (i = 0; i < best->num_names; i ++)
2336 {
2337 if (!strncasecmp(best->names[i], "@AUTHKEY(", 9) &&
2338 check_authref(con, best->names[i] + 9))
2339 return (HTTP_OK);
2340 else if (!strcasecmp(best->names[i], "@SYSTEM") &&
2341 SystemGroupAuthKey &&
2342 check_authref(con, SystemGroupAuthKey))
2343 return (HTTP_OK);
2344 }
2345
ee571f26 2346 return (HTTP_FORBIDDEN);
f7deaa1a 2347 }
2348#endif /* HAVE_AUTHORIZATION_H */
2349
ef416fc2 2350 for (i = 0; i < best->num_names; i ++)
2351 {
2352 if (!strcasecmp(best->names[i], "@OWNER") && owner &&
db1f069b 2353 !strcasecmp(username, ownername))
ef416fc2 2354 return (HTTP_OK);
2355 else if (!strcasecmp(best->names[i], "@SYSTEM"))
2356 {
2357 for (j = 0; j < NumSystemGroups; j ++)
fa73b229 2358 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
ef416fc2 2359 return (HTTP_OK);
2360 }
2361 else if (best->names[i][0] == '@')
2362 {
fa73b229 2363 if (cupsdCheckGroup(username, pw, best->names[i] + 1))
ef416fc2 2364 return (HTTP_OK);
2365 }
fa73b229 2366 else if (!strcasecmp(username, best->names[i]))
ef416fc2 2367 return (HTTP_OK);
2368 }
2369
ee571f26 2370 return (HTTP_FORBIDDEN);
ef416fc2 2371 }
2372
2373 /*
2374 * Check to see if this user is in any of the named groups...
2375 */
2376
2377 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2378 "cupsdIsAuthorized: Checking group membership...");
2379
2380 /*
2381 * Check to see if this user is in any of the named groups...
2382 */
2383
2384 for (i = 0; i < best->num_names; i ++)
2385 {
2386 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2387 "cupsdIsAuthorized: Checking group \"%s\" membership...",
2388 best->names[i]);
2389
2390 if (!strcasecmp(best->names[i], "@SYSTEM"))
2391 {
2392 for (j = 0; j < NumSystemGroups; j ++)
fa73b229 2393 if (cupsdCheckGroup(username, pw, SystemGroups[j]))
ef416fc2 2394 return (HTTP_OK);
2395 }
fa73b229 2396 else if (cupsdCheckGroup(username, pw, best->names[i]))
ef416fc2 2397 return (HTTP_OK);
2398 }
2399
2400 /*
2401 * The user isn't part of the specified group, so deny access...
2402 */
2403
355e94dc 2404 cupsdLogMessage(CUPSD_LOG_DEBUG,
ef416fc2 2405 "cupsdIsAuthorized: User not in group(s)!");
2406
ee571f26 2407 return (HTTP_FORBIDDEN);
ef416fc2 2408}
2409
2410
2411/*
2412 * 'add_allow()' - Add an allow mask to the location.
2413 */
2414
2415static cupsd_authmask_t * /* O - New mask record */
2416add_allow(cupsd_location_t *loc) /* I - Location to add to */
2417{
2418 cupsd_authmask_t *temp; /* New mask record */
2419
2420
2421 /*
2422 * Range-check...
2423 */
2424
2425 if (loc == NULL)
2426 return (NULL);
2427
2428 /*
2429 * Try to allocate memory for the record...
2430 */
2431
2432 if (loc->num_allow == 0)
2433 temp = malloc(sizeof(cupsd_authmask_t));
2434 else
2435 temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1));
2436
2437 if (temp == NULL)
2438 return (NULL);
2439
2440 loc->allow = temp;
2441 temp += loc->num_allow;
2442 loc->num_allow ++;
2443
2444 /*
2445 * Clear the mask record and return...
2446 */
2447
2448 memset(temp, 0, sizeof(cupsd_authmask_t));
2449 return (temp);
2450}
2451
2452
2453/*
2454 * 'add_deny()' - Add a deny mask to the location.
2455 */
2456
2457static cupsd_authmask_t * /* O - New mask record */
2458add_deny(cupsd_location_t *loc) /* I - Location to add to */
2459{
2460 cupsd_authmask_t *temp; /* New mask record */
2461
2462
2463 /*
2464 * Range-check...
2465 */
2466
2467 if (loc == NULL)
2468 return (NULL);
2469
2470 /*
2471 * Try to allocate memory for the record...
2472 */
2473
2474 if (loc->num_deny == 0)
2475 temp = malloc(sizeof(cupsd_authmask_t));
2476 else
2477 temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1));
2478
2479 if (temp == NULL)
2480 return (NULL);
2481
2482 loc->deny = temp;
2483 temp += loc->num_deny;
2484 loc->num_deny ++;
2485
2486 /*
2487 * Clear the mask record and return...
2488 */
2489
2490 memset(temp, 0, sizeof(cupsd_authmask_t));
2491 return (temp);
2492}
2493
2494
f7deaa1a 2495#ifdef HAVE_AUTHORIZATION_H
2496/*
2497 * 'check_authref()' - Check if an authorization services reference has the
2498 * supplied right.
2499 */
2500
2501static int /* O - 1 if right is valid, 0 otherwise */
2502check_authref(cupsd_client_t *con, /* I - Connection */
2503 const char *right) /* I - Right name */
2504{
2505 OSStatus status; /* OS Status */
2506 AuthorizationItem authright; /* Authorization right */
2507 AuthorizationRights authrights; /* Authorization rights */
2508 AuthorizationFlags authflags; /* Authorization flags */
2509
2510
2511 /*
2512 * Check to see if the user is allowed to perform the task...
2513 */
2514
2515 if (!con->authref)
2516 return (0);
2517
2518 authright.name = right;
2519 authright.valueLength = 0;
2520 authright.value = NULL;
2521 authright.flags = 0;
2522
2523 authrights.count = 1;
2524 authrights.items = &authright;
2525
2526 authflags = kAuthorizationFlagDefaults |
2527 kAuthorizationFlagExtendRights;
2528
2529 if ((status = AuthorizationCopyRights(con->authref, &authrights,
2530 kAuthorizationEmptyEnvironment,
2531 authflags, NULL)) != 0)
2532 {
2533 cupsdLogMessage(CUPSD_LOG_ERROR,
2534 "AuthorizationCopyRights(\"%s\") returned %d (%s)",
2535 authright.name, (int)status, cssmErrorString(status));
2536 return (0);
2537 }
2538
2539 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2540 "AuthorizationCopyRights(\"%s\") succeeded!",
2541 authright.name);
2542
2543 return (1);
2544}
2545#endif /* HAVE_AUTHORIZATION_H */
2546
2547
bd7854cb 2548/*
2549 * 'compare_locations()' - Compare two locations.
2550 */
2551
2552static int /* O - Result of comparison */
2553compare_locations(cupsd_location_t *a, /* I - First location */
2554 cupsd_location_t *b) /* I - Second location */
2555{
2556 return (strcmp(b->location, a->location));
2557}
2558
2559
d09495fa 2560#if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
ef416fc2 2561/*
2562 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
2563 * as needed.
2564 */
2565
2566static char * /* O - Encrypted password */
2567cups_crypt(const char *pw, /* I - Password string */
2568 const char *salt) /* I - Salt (key) string */
2569{
bd7854cb 2570 if (!strncmp(salt, "$1$", 3))
ef416fc2 2571 {
2572 /*
2573 * Use MD5 passwords without the benefit of PAM; this is for
2574 * Slackware Linux, and the algorithm was taken from the
2575 * old shadow-19990827/lib/md5crypt.c source code... :(
2576 */
2577
2578 int i; /* Looping var */
2579 unsigned long n; /* Output number */
2580 int pwlen; /* Length of password string */
2581 const char *salt_end; /* End of "salt" data for MD5 */
2582 char *ptr; /* Pointer into result string */
2583 _cups_md5_state_t state; /* Primary MD5 state info */
2584 _cups_md5_state_t state2; /* Secondary MD5 state info */
2585 unsigned char digest[16]; /* MD5 digest result */
2586 static char result[120]; /* Final password string */
2587
2588
2589 /*
2590 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
2591 * Get a maximum of 8 characters of salt data after $1$...
2592 */
2593
2594 for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
2595 if (*salt_end == '$')
2596 break;
2597
2598 /*
2599 * Compute the MD5 sum we need...
2600 */
2601
2602 pwlen = strlen(pw);
2603
757d2cad 2604 _cupsMD5Init(&state);
2605 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
2606 _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
ef416fc2 2607
757d2cad 2608 _cupsMD5Init(&state2);
2609 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2610 _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
2611 _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
2612 _cupsMD5Finish(&state2, digest);
ef416fc2 2613
2614 for (i = pwlen; i > 0; i -= 16)
757d2cad 2615 _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
ef416fc2 2616
2617 for (i = pwlen; i > 0; i >>= 1)
757d2cad 2618 _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
ef416fc2 2619
757d2cad 2620 _cupsMD5Finish(&state, digest);
ef416fc2 2621
2622 for (i = 0; i < 1000; i ++)
2623 {
757d2cad 2624 _cupsMD5Init(&state);
ef416fc2 2625
2626 if (i & 1)
757d2cad 2627 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
ef416fc2 2628 else
757d2cad 2629 _cupsMD5Append(&state, digest, 16);
ef416fc2 2630
2631 if (i % 3)
757d2cad 2632 _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
ef416fc2 2633
2634 if (i % 7)
757d2cad 2635 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
ef416fc2 2636
2637 if (i & 1)
757d2cad 2638 _cupsMD5Append(&state, digest, 16);
ef416fc2 2639 else
757d2cad 2640 _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
ef416fc2 2641
757d2cad 2642 _cupsMD5Finish(&state, digest);
ef416fc2 2643 }
2644
2645 /*
2646 * Copy the final sum to the result string and return...
2647 */
2648
2649 memcpy(result, salt, salt_end - salt);
2650 ptr = result + (salt_end - salt);
2651 *ptr++ = '$';
2652
2653 for (i = 0; i < 5; i ++, ptr += 4)
2654 {
2655 n = (((digest[i] << 8) | digest[i + 6]) << 8);
2656
2657 if (i < 4)
2658 n |= digest[i + 12];
2659 else
2660 n |= digest[5];
2661
2662 to64(ptr, n, 4);
2663 }
2664
2665 to64(ptr, digest[11], 2);
2666 ptr += 2;
2667 *ptr = '\0';
2668
2669 return (result);
2670 }
2671 else
2672 {
2673 /*
2674 * Use the standard crypt() function...
2675 */
2676
2677 return (crypt(pw, salt));
2678 }
2679}
d09495fa 2680#endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
ef416fc2 2681
2682
e1d6a774 2683/*
2684 * 'get_md5_password()' - Get an MD5 password.
2685 */
2686
2687static char * /* O - MD5 password string */
2688get_md5_password(const char *username, /* I - Username */
2689 const char *group, /* I - Group */
2690 char passwd[33]) /* O - MD5 password string */
2691{
2692 cups_file_t *fp; /* passwd.md5 file */
2693 char filename[1024], /* passwd.md5 filename */
2694 line[256], /* Line from file */
2695 tempuser[33], /* User from file */
2696 tempgroup[33]; /* Group from file */
2697
2698
2699 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2700 "get_md5_password(username=\"%s\", group=\"%s\", passwd=%p)",
2701 username, group ? group : "(null)", passwd);
2702
2703 snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
2704 if ((fp = cupsFileOpen(filename, "r")) == NULL)
2705 {
2706 if (errno != ENOENT)
2707 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename,
2708 strerror(errno));
2709
2710 return (NULL);
2711 }
2712
2713 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
2714 {
2715 if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
2716 {
2717 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line);
2718 continue;
2719 }
2720
2721 if (!strcmp(username, tempuser) &&
2722 (group == NULL || !strcmp(group, tempgroup)))
2723 {
2724 /*
2725 * Found the password entry!
2726 */
2727
2728 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
2729 username, tempgroup);
2730
2731 cupsFileClose(fp);
2732 return (passwd);
2733 }
2734 }
2735
2736 /*
2737 * Didn't find a password entry - return NULL!
2738 */
2739
2740 cupsFileClose(fp);
2741 return (NULL);
2742}
2743
2744
ef416fc2 2745#if HAVE_LIBPAM
2746/*
2747 * 'pam_func()' - PAM conversation function.
2748 */
2749
2750static int /* O - Success or failure */
2751pam_func(
2752 int num_msg, /* I - Number of messages */
2753 const struct pam_message **msg, /* I - Messages */
2754 struct pam_response **resp, /* O - Responses */
2755 void *appdata_ptr)
2756 /* I - Pointer to connection */
2757{
2758 int i; /* Looping var */
2759 struct pam_response *replies; /* Replies */
2760 cupsd_authdata_t *data; /* Pointer to auth data */
2761
2762
2763 /*
2764 * Allocate memory for the responses...
2765 */
2766
2767 if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
2768 return (PAM_CONV_ERR);
2769
2770 /*
2771 * Answer all of the messages...
2772 */
2773
2774 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
2775
2776#ifdef __hpux
2777 /*
2778 * Apparently some versions of HP-UX 11 have a broken pam_unix security
2779 * module. This is a workaround...
2780 */
2781
2782 data = auth_data;
2783 (void)appdata_ptr;
2784#else
2785 data = (cupsd_authdata_t *)appdata_ptr;
2786#endif /* __hpux */
2787
2788 for (i = 0; i < num_msg; i ++)
2789 {
2790 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
2791
2792 switch (msg[i]->msg_style)
2793 {
2794 case PAM_PROMPT_ECHO_ON:
2795 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
2796 data->username));
2797 replies[i].resp_retcode = PAM_SUCCESS;
2798 replies[i].resp = strdup(data->username);
2799 break;
2800
2801 case PAM_PROMPT_ECHO_OFF:
2802 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
2803 data->password));
2804 replies[i].resp_retcode = PAM_SUCCESS;
2805 replies[i].resp = strdup(data->password);
2806 break;
2807
2808 case PAM_TEXT_INFO:
2809 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
2810 replies[i].resp_retcode = PAM_SUCCESS;
2811 replies[i].resp = NULL;
2812 break;
2813
2814 case PAM_ERROR_MSG:
2815 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
2816 replies[i].resp_retcode = PAM_SUCCESS;
2817 replies[i].resp = NULL;
2818 break;
2819
2820 default:
2821 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
2822 msg[i]->msg_style));
2823 free(replies);
2824 return (PAM_CONV_ERR);
2825 }
2826 }
2827
2828 /*
2829 * Return the responses back to PAM...
2830 */
2831
2832 *resp = replies;
2833
2834 return (PAM_SUCCESS);
2835}
f7deaa1a 2836#elif !defined(HAVE_USERSEC_H)
ef416fc2 2837
2838
2839/*
2840 * 'to64()' - Base64-encode an integer value...
2841 */
2842
2843static void
2844to64(char *s, /* O - Output string */
2845 unsigned long v, /* I - Value to encode */
2846 int n) /* I - Number of digits */
2847{
2848 const char *itoa64 = "./0123456789"
2849 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2850 "abcdefghijklmnopqrstuvwxyz";
2851
2852
2853 for (; n > 0; n --, v >>= 6)
2854 *s++ = itoa64[v & 0x3f];
2855}
2856#endif /* HAVE_LIBPAM */
2857
2858
2859/*
b19ccc9e 2860 * End of "$Id: auth.c 7830 2008-08-04 20:38:50Z mike $".
ef416fc2 2861 */