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