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