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