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