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