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