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