]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/auth.c
Move debug printfs to internal usage only.
[thirdparty/cups.git] / scheduler / auth.c
index ea9a071013203b4b79346b4c69e01a683553f86e..0774ae3cf6627af289781549ca9d9df79872d231 100644 (file)
@@ -1,57 +1,14 @@
 /*
- * "$Id: auth.c 5568 2006-05-22 15:34:01Z mike $"
+ * Authorization routines for the CUPS scheduler.
  *
- *   Authorization routines for the Common UNIX Printing System (CUPS).
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
  *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
- *
- * Contents:
- *
- *   cupsdAddLocation()        - Add a location for authorization.
- *   cupsdAddName()            - Add a name to a location...
- *   cupsdAllowHost()          - Add a host name that is allowed to access the
- *                               location.
- *   cupsdAllowIP()            - Add an IP address or network that is allowed
- *                               to access the location.
- *   cupsdAuthorize()          - Validate any authorization credentials.
- *   cupsdCheckAuth()          - Check authorization masks.
- *   cupsdCheckGroup()         - Check for a user's group membership.
- *   cupsdCopyLocation()       - Make a copy of a location...
- *   cupsdDeleteAllLocations() - Free all memory used for location
- *                               authorization.
- *   cupsdDeleteLocation()     - Free all memory used by a location.
- *   cupsdDenyHost()           - Add a host name that is not allowed to access
- *                               the location.
- *   cupsdDenyIP()             - Add an IP address or network that is not
- *                               allowed to access the location.
- *   cupsdFindBest()           - Find the location entry that best matches the
- *                               resource.
- *   cupsdFindLocation()       - Find the named location.
- *   cupsdIsAuthorized()       - Check to see if the user is authorized...
- *   add_allow()               - Add an allow mask to the location.
- *   add_deny()                - Add a deny mask to the location.
- *   compare_locations()       - Compare two locations.
- *   cups_crypt()              - Encrypt the password using the DES or MD5
- *                               algorithms, as needed.
- *   get_md5_password()        - Get an MD5 password.
- *   pam_func()                - PAM conversation function.
- *   to64()                    - Base64-encode an integer value...
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
 #    include <security/pam_appl.h>
 #  endif /* HAVE_PAM_PAM_APPL_H */
 #endif /* HAVE_LIBPAM */
-#ifdef HAVE_USERSEC_H
-#  include <usersec.h>
-#endif /* HAVE_USERSEC_H */
 #ifdef HAVE_MEMBERSHIP_H
 #  include <membership.h>
 #endif /* HAVE_MEMBERSHIP_H */
+#ifdef HAVE_AUTHORIZATION_H
+#  include <Security/AuthorizationTags.h>
+#  ifdef HAVE_SECBASEPRIV_H
+#    include <Security/SecBasePriv.h>
+#  else
+extern const char *cssmErrorString(int error);
+#  endif /* HAVE_SECBASEPRIV_H */
+#endif /* HAVE_AUTHORIZATION_H */
+#ifdef HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+#ifdef HAVE_SYS_UCRED_H
+#  include <sys/ucred.h>
+typedef struct xucred cupsd_ucred_t;
+#  define CUPSD_UCRED_UID(c) (c).cr_uid
+#else
+#  ifndef __OpenBSD__
+typedef struct ucred cupsd_ucred_t;
+#  else
+typedef struct sockpeercred cupsd_ucred_t;
+#  endif
+#  define CUPSD_UCRED_UID(c) (c).uid
+#endif /* HAVE_SYS_UCRED_H */
 
 
 /*
  * Local functions...
  */
 
-static cupsd_authmask_t        *add_allow(cupsd_location_t *loc);
-static cupsd_authmask_t        *add_deny(cupsd_location_t *loc);
+#ifdef HAVE_AUTHORIZATION_H
+static int             check_authref(cupsd_client_t *con, const char *right);
+#endif /* HAVE_AUTHORIZATION_H */
 static int             compare_locations(cupsd_location_t *a,
                                          cupsd_location_t *b);
-#if !HAVE_LIBPAM
-static char            *cups_crypt(const char *pw, const char *salt);
-#endif /* !HAVE_LIBPAM */
-static char            *get_md5_password(const char *username,
-                                         const char *group, char passwd[33]);
+static cupsd_authmask_t        *copy_authmask(cupsd_authmask_t *am, void *data);
+static void            free_authmask(cupsd_authmask_t *am, void *data);
 #if HAVE_LIBPAM
 static int             pam_func(int, const struct pam_message **,
                                 struct pam_response **, void *);
@@ -109,65 +84,67 @@ static void                to64(char *s, unsigned long v, int n);
 #if HAVE_LIBPAM
 typedef struct cupsd_authdata_s                /**** Authentication data ****/
 {
-  char username[33],                   /* Username string */
-       password[33];                   /* Password string */
+  char username[HTTP_MAX_VALUE],       /* Username string */
+       password[HTTP_MAX_VALUE];       /* Password string */
 } cupsd_authdata_t;
 #endif /* HAVE_LIBPAM */
 
 
 /*
- * Local globals...
+ * 'cupsdAddIPMask()' - Add an IP address authorization mask.
  */
 
-#if defined(__hpux) && HAVE_LIBPAM
-static cupsd_authdata_t        *auth_data;     /* Current client being authenticated */
-#endif /* __hpux && HAVE_LIBPAM */
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddIPMask(
+    cups_array_t   **masks,            /* IO - Masks array (created as needed) */
+    const unsigned address[4],         /* I  - IP address */
+    const unsigned netmask[4])         /* I  - IP netmask */
+{
+  cupsd_authmask_t     temp;           /* New host/domain mask */
 
 
-/*
- * 'cupsdAddLocation()' - Add a location for authorization.
- */
-
-cupsd_location_t *                     /* O - Pointer to new location record */
-cupsdAddLocation(const char *location) /* I - Location path */
-{
-  cupsd_location_t     *temp;          /* New location */
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", masks, *masks, address[0], address[1], address[2], address[3], netmask[0], netmask[1], netmask[2], netmask[3]);
 
+  temp.type = CUPSD_AUTH_IP;
+  memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address));
+  memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask));
 
  /*
-  * Make sure the locations array is created...
+  * Create the masks array as needed and add...
   */
 
-  if (!Locations)
-    Locations = cupsArrayNew((cups_array_func_t)compare_locations, NULL);
+  if (!*masks)
+    *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+                          (cups_acopy_func_t)copy_authmask,
+                          (cups_afree_func_t)free_authmask);
 
-  if (!Locations)
-    return (NULL);
+  return (cupsArrayAdd(*masks, &temp));
+}
 
- /*
-  * Try to allocate memory for the new location.
-  */
 
-  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
-    return (NULL);
+/*
+ * 'cupsdAddLocation()' - Add a location for authorization.
+ */
 
+void
+cupsdAddLocation(cupsd_location_t *loc)        /* I - Location to add */
+{
  /*
-  * Initialize the record and copy the name over...
+  * Make sure the locations array is created...
   */
 
-  temp->location = strdup(location);
-  temp->length   = strlen(temp->location);
-
-  cupsArrayAdd(Locations, temp);
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: added location \'%s\'",
-                  location);
+  if (!Locations)
+    Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL,
+                              (cups_ahash_func_t)NULL, 0,
+                             (cups_acopy_func_t)NULL,
+                             (cups_afree_func_t)cupsdFreeLocation);
 
- /*
-  * Return the new record...
-  */
+  if (Locations)
+  {
+    cupsArrayAdd(Locations, loc);
 
-  return (temp);
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"", loc->location ? loc->location : "(null)");
+  }
 }
 
 
@@ -179,125 +156,95 @@ void
 cupsdAddName(cupsd_location_t *loc,    /* I - Location to add to */
              char             *name)   /* I - Name to add */
 {
-  char **temp;                         /* Pointer to names array */
-
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", loc, name);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")",
-                  loc, name);
-
-  if (loc->num_names == 0)
-    temp = malloc(sizeof(char *));
-  else
-    temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
+  if (!loc->names)
+    loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
+                               (cups_acopy_func_t)_cupsStrAlloc,
+                               (cups_afree_func_t)_cupsStrFree);
 
-  if (temp == NULL)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add name to location %s: %s",
-                    loc->location ? loc->location : "nil", strerror(errno));
-    return;
-  }
-
-  loc->names = temp;
-
-  if ((temp[loc->num_names] = strdup(name)) == NULL)
+  if (!cupsArrayAdd(loc->names, name))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "Unable to duplicate name for location %s: %s",
                     loc->location ? loc->location : "nil", strerror(errno));
     return;
   }
-
-  loc->num_names ++;
 }
 
 
 /*
- * 'cupsdAllowHost()' - Add a host name that is allowed to access the location.
+ * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
  */
 
-void
-cupsdAllowHost(cupsd_location_t *loc,  /* I - Location to add to */
-               char             *name) /* I - Name of host or domain to add */
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
+                 char         *name)   /* I  - Host or interface name */
 {
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
+  cupsd_authmask_t     temp;           /* New host/domain mask */
   char                 ifname[32],     /* Interface name */
                        *ifptr;         /* Pointer to end of name */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAllowHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location ? loc->location : "nil", name);
-
-  if ((temp = add_allow(loc)) == NULL)
-    return;
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks, *masks, name);
 
-  if (!strcasecmp(name, "@LOCAL"))
+  if (!_cups_strcasecmp(name, "@LOCAL"))
   {
    /*
-    * Allow *interface*...
+    * Deny *interface*...
     */
 
-    temp->type             = AUTH_INTERFACE;
-    temp->mask.name.name   = strdup("*");
-    temp->mask.name.length = 1;
+    temp.type           = CUPSD_AUTH_INTERFACE;
+    temp.mask.name.name = (char *)"*";
   }
-  else if (!strncasecmp(name, "@IF(", 4))
+  else if (!_cups_strncasecmp(name, "@IF(", 4))
   {
    /*
-    * Allow *interface*...
+    * Deny *interface*...
     */
 
     strlcpy(ifname, name + 4, sizeof(ifname));
 
-    ifptr = ifname + strlen(ifname);
+    ifptr = ifname + strlen(ifname) - 1;
 
-    if (ifptr[-1] == ')')
+    if (ifptr >= ifname && *ifptr == ')')
     {
       ifptr --;
       *ifptr = '\0';
     }
 
-    temp->type             = AUTH_INTERFACE;
-    temp->mask.name.name   = strdup(ifname);
-    temp->mask.name.length = ifptr - ifname;
+    temp.type             = CUPSD_AUTH_INTERFACE;
+    temp.mask.name.name   = ifname;
   }
   else
   {
    /*
-    * Allow name...
+    * Deny name...
     */
 
-    temp->type             = AUTH_NAME;
-    temp->mask.name.name   = strdup(name);
-    temp->mask.name.length = strlen(name);
-  }
-}
-
+    if (*name == '*')
+      name ++;
 
-/*
- * 'cupsdAllowIP()' - Add an IP address or network that is allowed to access
- *                    the location.
- */
+    temp.type             = CUPSD_AUTH_NAME;
+    temp.mask.name.name   = (char *)name;
+  }
 
-void
-cupsdAllowIP(cupsd_location_t *loc,    /* I - Location to add to */
-             unsigned   address[4],    /* I - IP address to add */
-             unsigned   netmask[4])    /* I - Netmask of address */
-{
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
+ /*
+  * Set the name length...
+  */
 
+  temp.mask.name.length = strlen(temp.mask.name.name);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdAllowIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location ? loc->location : "nil",
-                 address[0], address[1], address[2], address[3],
-                 netmask[0], netmask[1], netmask[2], netmask[3]);
+ /*
+  * Create the masks array as needed and add...
+  */
 
-  if ((temp = add_allow(loc)) == NULL)
-    return;
+  if (!*masks)
+    *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+                          (cups_acopy_func_t)copy_authmask,
+                          (cups_afree_func_t)free_authmask);
 
-  temp->type = AUTH_IP;
-  memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
-  memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
+  return (cupsArrayAdd(*masks, &temp));
 }
 
 
@@ -309,31 +256,13 @@ void
 cupsdAuthorize(cupsd_client_t *con)    /* I - Client connection */
 {
   int          type;                   /* Authentication type */
-  char         *authorization,         /* Pointer into Authorization string */
-               *ptr,                   /* Pointer into string */
-               username[65],           /* Username string */
-               password[33];           /* Password string */
-  const char   *localuser;             /* Certificate username */
-  char         nonce[HTTP_MAX_VALUE],  /* Nonce value from client */
-               md5[33],                /* MD5 password */
-               basicmd5[33];           /* MD5 of Basic password */
-  static const char * const states[] = /* HTTP client states... */
-               {
-                 "WAITING",
-                 "OPTIONS",
-                 "GET",
-                 "GET",
-                 "HEAD",
-                 "POST",
-                 "POST",
-                 "POST",
-                 "PUT",
-                 "PUT",
-                 "DELETE",
-                 "TRACE",
-                 "CLOSE",
-                 "STATUS"
-               };
+  const char   *authorization;         /* Pointer into Authorization string */
+  char         *ptr,                   /* Pointer into string */
+               username[HTTP_MAX_VALUE],
+                                       /* Username string */
+               password[HTTP_MAX_VALUE];
+                                       /* Password string */
+  cupsd_cert_t *localuser;             /* Certificate username */
 
 
  /*
@@ -341,51 +270,219 @@ cupsdAuthorize(cupsd_client_t *con)      /* I - Client connection */
   * authentication to expect...
   */
 
-  con->best = cupsdFindBest(con->uri, con->http.state);
+  con->best = cupsdFindBest(con->uri, httpGetState(con->http));
+  con->type = CUPSD_AUTH_NONE;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdAuthorize: con->uri=\"%s\", con->best=%p(%s)",
-                  con->uri, con->best, con->best ? con->best->location : "");
+  cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location : "");
 
-  if (con->best && con->best->type != AUTH_NONE)
-    type = con->best->type;
+  if (con->best && con->best->type != CUPSD_AUTH_NONE)
+  {
+    if (con->best->type == CUPSD_AUTH_DEFAULT)
+      type = cupsdDefaultAuthType();
+    else
+      type = con->best->type;
+  }
   else
-    type = DefaultAuthType;
+    type = cupsdDefaultAuthType();
 
  /*
   * Decode the Authorization string...
   */
 
-  authorization = con->http.fields[HTTP_FIELD_AUTHORIZATION];
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAuthorize: Authorization=\"%s\"",
-                  authorization);
+  authorization = httpGetField(con->http, HTTP_FIELD_AUTHORIZATION);
 
   username[0] = '\0';
   password[0] = '\0';
 
-  if (type == AUTH_NONE)
+#ifdef HAVE_GSSAPI
+  con->gss_uid = 0;
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_AUTHORIZATION_H
+  if (con->authref)
+  {
+    AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
+    con->authref = NULL;
+  }
+#endif /* HAVE_AUTHORIZATION_H */
+
+  if (!*authorization)
   {
    /*
-    * No authorization required, return early...
+    * No authorization data provided, return early...
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdAuthorize: No authentication required.");
+    cupsdLogClient(con, CUPSD_LOG_DEBUG, "No authentication data provided.");
     return;
   }
-  else if (!*authorization)
+#ifdef HAVE_AUTHORIZATION_H
+  else if (!strncmp(authorization, "AuthRef ", 8) &&
+           httpAddrLocalhost(httpGetAddress(con->http)))
   {
+    OSStatus           status;         /* Status */
+    char               authdata[HTTP_MAX_VALUE];
+                                       /* Nonce value from client */
+    int                        authlen;        /* Auth string length */
+    AuthorizationItemSet *authinfo;    /* Authorization item set */
+
    /*
-    * No authorization data provided, return early...
+    * Get the Authorization Services data...
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdAuthorize: No authentication data provided.");
-    return;
+    authorization += 8;
+    while (isspace(*authorization & 255))
+      authorization ++;
+
+    authlen = sizeof(authdata);
+    httpDecode64_2(authdata, &authlen, authorization);
+
+    if (authlen != kAuthorizationExternalFormLength)
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "External Authorization reference size is incorrect.");
+      return;
+    }
+
+    if ((status = AuthorizationCreateFromExternalForm((AuthorizationExternalForm *)authdata, &con->authref)) != 0)
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "AuthorizationCreateFromExternalForm returned %d (%s)", (int)status, cssmErrorString(status));
+      return;
+    }
+
+    username[0] = '\0';
+
+    if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
+                              &authinfo))
+    {
+      if (authinfo->count == 1 && authinfo->items[0].value &&
+          authinfo->items[0].valueLength >= 2)
+      {
+        strlcpy(username, authinfo->items[0].value, sizeof(username));
+
+        cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef.", username);
+      }
+
+      AuthorizationFreeItemSet(authinfo);
+    }
+
+    if (!username[0])
+    {
+     /*
+      * No username in AuthRef, grab username using peer credentials...
+      */
+
+      struct passwd    *pwd;           /* Password entry for this user */
+      cupsd_ucred_t    peercred;       /* Peer credentials */
+      socklen_t                peersize;       /* Size of peer credentials */
+
+      peersize = sizeof(peercred);
+
+      if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
+      {
+        cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
+        return;
+      }
+
+      if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
+      {
+        cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to find UID %d for peer credentials.", (int)CUPSD_UCRED_UID(peercred));
+        return;
+      }
+
+      strlcpy(username, pwd->pw_name, sizeof(username));
+
+      cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using AuthRef + PeerCred.", username);
+    }
+
+    con->type = CUPSD_AUTH_BASIC;
+  }
+#endif /* HAVE_AUTHORIZATION_H */
+#if defined(SO_PEERCRED) && defined(AF_LOCAL)
+  else if (!strncmp(authorization, "PeerCred ", 9) &&
+           con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best)
+  {
+   /*
+    * Use peer credentials from domain socket connection...
+    */
+
+    struct passwd      *pwd;           /* Password entry for this user */
+    cupsd_ucred_t      peercred;       /* Peer credentials */
+    socklen_t          peersize;       /* Size of peer credentials */
+#ifdef HAVE_AUTHORIZATION_H
+    const char         *name;          /* Authorizing name */
+    int                        no_peer = 0;    /* Don't allow peer credentials? */
+
+   /*
+    * See if we should allow peer credentials...
+    */
+
+    for (name = (char *)cupsArrayFirst(con->best->names);
+         name;
+         name = (char *)cupsArrayNext(con->best->names))
+    {
+      if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) ||
+          !_cups_strcasecmp(name, "@SYSTEM"))
+      {
+       /* Normally don't want peer credentials if we need an auth key... */
+       no_peer = 1;
+      }
+      else if (!_cups_strcasecmp(name, "@OWNER"))
+      {
+       /* but if @OWNER is present then we allow it... */
+        no_peer = 0;
+        break;
+      }
+    }
+
+    if (no_peer)
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "PeerCred authentication not allowed for resource per AUTHKEY policy.");
+      return;
+    }
+#endif /* HAVE_AUTHORIZATION_H */
+
+    if ((pwd = getpwnam(authorization + 9)) == NULL)
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9);
+      return;
+    }
+
+    peersize = sizeof(peercred);
+
+#  ifdef __APPLE__
+    if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
+#  else
+    if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
+#  endif /* __APPLE__ */
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
+      return;
+    }
+
+    if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
+    {
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Invalid peer credentials for \"%s\" - got %d, expected %d.", authorization + 9, CUPSD_UCRED_UID(peercred), pwd->pw_uid);
+#  ifdef HAVE_SYS_UCRED_H
+      cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_version=%d", peercred.cr_version);
+      cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_uid=%d", peercred.cr_uid);
+      cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_ngroups=%d", peercred.cr_ngroups);
+      cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cr_groups[0]=%d", peercred.cr_groups[0]);
+#  endif /* HAVE_SYS_UCRED_H */
+      return;
+    }
+
+    strlcpy(username, authorization + 9, sizeof(username));
+
+#  ifdef HAVE_GSSAPI
+    con->gss_uid = CUPSD_UCRED_UID(peercred);
+#  endif /* HAVE_GSSAPI */
+
+    cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using PeerCred.", username);
+
+    con->type = CUPSD_AUTH_BASIC;
   }
+#endif /* SO_PEERCRED && AF_LOCAL */
   else if (!strncmp(authorization, "Local", 5) &&
-           !strcasecmp(con->http.hostname, "localhost"))
+          httpAddrLocalhost(httpGetAddress(con->http)))
   {
    /*
     * Get Local certificate authentication data...
@@ -395,18 +492,18 @@ cupsdAuthorize(cupsd_client_t *con)       /* I - Client connection */
     while (isspace(*authorization & 255))
       authorization ++;
 
-    if ((localuser = cupsdFindCert(authorization)) != NULL)
-      strlcpy(username, localuser, sizeof(username));
-    else
+    if ((localuser = cupsdFindCert(authorization)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Local authentication certificate not "
-                     "found!");
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Local authentication certificate not found.");
       return;
     }
+
+    strlcpy(username, localuser->username, sizeof(username));
+    con->type = localuser->type;
+
+    cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as %s using Local.", username);
   }
-  else if (!strncmp(authorization, "Basic", 5) &&
-           (type == AUTH_BASIC || type == AUTH_BASICDIGEST))
+  else if (!strncmp(authorization, "Basic", 5))
   {
    /*
     * Get the Basic authentication data...
@@ -428,8 +525,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
 
     if ((ptr = strchr(username, ':')) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Missing Basic password!");
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Basic password.");
       return;
     }
 
@@ -441,8 +537,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
       * Username must not be empty...
       */
 
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Empty Basic username!");
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic username.");
       return;
     }
 
@@ -452,8 +547,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
       * Password must not be empty...
       */
 
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Empty Basic password!");
+      cupsdLogClient(con, CUPSD_LOG_ERROR, "Empty Basic password.");
       return;
     }
 
@@ -465,7 +559,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
 
     switch (type)
     {
-      case AUTH_BASIC :
+      default :
+      case CUPSD_AUTH_BASIC :
           {
 #if HAVE_LIBPAM
           /*
@@ -491,73 +586,51 @@ cupsdAuthorize(cupsd_client_t *con)       /* I - Client connection */
 #  endif /* __sun */
            pamdata.appdata_ptr = &data;
 
-#  ifdef __hpux
-          /*
-           * Workaround for HP-UX bug in pam_unix; see pam_func() below for
-           * more info...
-           */
-
-           auth_data = &data;
-#  endif /* __hpux */
-
            pamerr = pam_start("cups", username, &pamdata, &pamh);
            if (pamerr != PAM_SUCCESS)
            {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: pam_start() returned %d (%s)!\n",
-                             pamerr, pam_strerror(pamh, pamerr));
-             pam_end(pamh, 0);
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_start() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
              return;
            }
 
+#  ifdef HAVE_PAM_SET_ITEM
+#    ifdef PAM_RHOST
+           pamerr = pam_set_item(pamh, PAM_RHOST, con->http->hostname);
+           if (pamerr != PAM_SUCCESS)
+             cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_RHOST) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
+#    endif /* PAM_RHOST */
+
+#    ifdef PAM_TTY
+           pamerr = pam_set_item(pamh, PAM_TTY, "cups");
+           if (pamerr != PAM_SUCCESS)
+             cupsdLogClient(con, CUPSD_LOG_WARN, "pam_set_item(PAM_TTY) returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
+#    endif /* PAM_TTY */
+#  endif /* HAVE_PAM_SET_ITEM */
+
            pamerr = pam_authenticate(pamh, PAM_SILENT);
            if (pamerr != PAM_SUCCESS)
            {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: pam_authenticate() returned %d "
-                             "(%s)!\n",
-                             pamerr, pam_strerror(pamh, pamerr));
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_authenticate() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
              pam_end(pamh, 0);
              return;
            }
 
+#  ifdef HAVE_PAM_SETCRED
+            pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
+           if (pamerr != PAM_SUCCESS)
+             cupsdLogClient(con, CUPSD_LOG_WARN, "pam_setcred() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
+#  endif /* HAVE_PAM_SETCRED */
+
            pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
            if (pamerr != PAM_SUCCESS)
            {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: pam_acct_mgmt() returned %d "
-                             "(%s)!\n",
-                             pamerr, pam_strerror(pamh, pamerr));
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "pam_acct_mgmt() returned %d (%s)", pamerr, pam_strerror(pamh, pamerr));
              pam_end(pamh, 0);
              return;
            }
 
            pam_end(pamh, PAM_SUCCESS);
 
-#elif defined(HAVE_USERSEC_H)
-          /*
-           * Use AIX authentication interface...
-           */
-
-           char        *authmsg;       /* Authentication message */
-           char        *loginmsg;      /* Login message */
-           int         reenter;        /* ??? */
-
-
-           cupsdLogMessage(CUPSD_LOG_DEBUG,
-                           "cupsdAuthorize: AIX authenticate of username \"%s\"",
-                            username);
-
-           reenter = 1;
-           if (authenticate(username, password, &reenter, &authmsg) != 0)
-           {
-             cupsdLogMessage(CUPSD_LOG_DEBUG,
-                             "cupsdAuthorize: Unable to authenticate username "
-                             "\"%s\": %s",
-                             username, strerror(errno));
-             return;
-           }
-
 #else
            /*
            * Use normal UNIX password file-based authentication...
@@ -579,9 +652,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
              * No such user...
              */
 
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: Unknown username \"%s\"!",
-                             username);
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "Unknown username \"%s\".", username);
              return;
            }
 
@@ -595,9 +666,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
              * Don't allow blank passwords!
              */
 
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: Username \"%s\" has no shadow "
-                             "password!", username);
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "Username \"%s\" has no shadow password.", username);
              return;
            }
 
@@ -610,9 +679,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
              * Don't allow blank passwords!
              */
 
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdAuthorize: Username \"%s\" has no password!",
-                             username);
+             cupsdLogClient(con, CUPSD_LOG_ERROR, "Username \"%s\" has no password.", username);
              return;
            }
 
@@ -621,144 +688,191 @@ cupsdAuthorize(cupsd_client_t *con)     /* I - Client connection */
            * client...
            */
 
-           pass = cups_crypt(password, pw->pw_passwd);
-
-           cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdAuthorize: pw_passwd=\"%s\", crypt=\"%s\"",
-                           pw->pw_passwd, pass);
+           pass = crypt(password, pw->pw_passwd);
 
            if (!pass || strcmp(pw->pw_passwd, pass))
            {
 #  ifdef HAVE_SHADOW_H
              if (spw)
              {
-               pass = cups_crypt(password, spw->sp_pwdp);
-
-               cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                               "cupsdAuthorize: sp_pwdp=\"%s\", crypt=\"%s\"",
-                               spw->sp_pwdp, pass);
+               pass = crypt(password, spw->sp_pwdp);
 
                if (pass == NULL || strcmp(spw->sp_pwdp, pass))
                {
-                 cupsdLogMessage(CUPSD_LOG_ERROR,
-                                 "cupsdAuthorize: Authentication failed for "
-                                 "user \"%s\"!",
-                                 username);
+                 cupsdLogClient(con, CUPSD_LOG_ERROR, "Authentication failed for user \"%s\".", username);
                  return;
                }
              }
              else
 #  endif /* HAVE_SHADOW_H */
              {
-               cupsdLogMessage(CUPSD_LOG_ERROR,
-                               "cupsdAuthorize: Authentication failed for "
-                               "user \"%s\"!",
-                               username);
+               cupsdLogClient(con, CUPSD_LOG_ERROR, "Authentication failed for user \"%s\".", username);
                return;
               }
            }
 #endif /* HAVE_LIBPAM */
           }
-          break;
-
-      case AUTH_BASICDIGEST :
-         /*
-         * Do Basic authentication with the Digest password file...
-         */
-
-         if (!get_md5_password(username, NULL, md5))
-         {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdAuthorize: Unknown MD5 username \"%s\"!",
-                           username);
-            return;
-         }
-
-         httpMD5(username, "CUPS", password, basicmd5);
 
-         if (strcmp(md5, basicmd5))
-         {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdAuthorize: Authentication failed for \"%s\"!",
-                           username);
-            return;
-         }
-         break;
+         cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Basic.", username);
+          break;
     }
+
+    con->type = type;
   }
-  else if (!strncmp(authorization, "Digest", 6) && type == AUTH_DIGEST)
+#ifdef HAVE_GSSAPI
+  else if (!strncmp(authorization, "Negotiate", 9))
   {
+    int                        len;            /* Length of authorization string */
+    gss_ctx_id_t       context;        /* Authorization context */
+    OM_uint32          major_status,   /* Major status code */
+                       minor_status;   /* Minor status code */
+    gss_buffer_desc    input_token = GSS_C_EMPTY_BUFFER,
+                                       /* Input token from string */
+                       output_token = GSS_C_EMPTY_BUFFER;
+                                       /* Output token for username */
+    gss_name_t         client_name;    /* Client name */
+
+
+#  ifdef __APPLE__
    /*
-    * Get the username, password, and nonce from the Digest attributes...
+    * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+    * to use it...
     */
 
-    if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "username",
-                          username, sizeof(username)) || !username[0])
+    if (&gss_init_sec_context == NULL)
     {
-     /*
-      * Username must not be empty...
-      */
-
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Empty or missing Digest username!");
+      cupsdLogClient(con, CUPSD_LOG_WARN, "GSSAPI/Kerberos authentication failed because the Kerberos framework is not present.");
       return;
     }
+#  endif /* __APPLE__ */
 
-    if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "response",
-                          password, sizeof(password)) || !password[0])
-    {
-     /*
-      * Password must not be empty...
-      */
+   /*
+    * Find the start of the Kerberos input token...
+    */
 
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdAuthorize: Empty or missing Digest password!");
-      return;
-    }
+    authorization += 9;
+    while (isspace(*authorization & 255))
+      authorization ++;
 
-    if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
-                         nonce))
+    if (!*authorization)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "cupsdAuthorize: No nonce value for Digest "
-                     "authentication!");
+      cupsdLogClient(con, CUPSD_LOG_DEBUG2, "No authentication data specified.");
       return;
     }
 
-    if (strcmp(con->http.hostname, nonce))
+   /*
+    * Decode the authorization string to get the input token...
+    */
+
+    len                = (int)strlen(authorization);
+    input_token.value  = malloc((size_t)len);
+    input_token.value  = httpDecode64_2(input_token.value, &len,
+                                       authorization);
+    input_token.length = (size_t)len;
+
+   /*
+    * Accept the input token to get the authorization info...
+    */
+
+    context      = GSS_C_NO_CONTEXT;
+    client_name  = GSS_C_NO_NAME;
+    major_status = gss_accept_sec_context(&minor_status,
+                                         &context,
+                                         ServerCreds,
+                                         &input_token,
+                                         GSS_C_NO_CHANNEL_BINDINGS,
+                                         &client_name,
+                                         NULL,
+                                         &output_token,
+                                         NULL,
+                                         NULL,
+                                         NULL);
+
+    if (output_token.length > 0)
+      gss_release_buffer(&minor_status, &output_token);
+
+    if (GSS_ERROR(major_status))
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "cupsdAuthorize: Bad nonce value, expected \"%s\", "
-                     "got \"%s\"!", con->http.hostname, nonce);
+      cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error accepting GSSAPI security context.", con->number);
+
+      if (context != GSS_C_NO_CONTEXT)
+       gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
       return;
     }
 
+    con->have_gss = 1;
+
    /*
-    * Validate the username and password...
+    * Get the username associated with the client's credentials...
     */
 
-    if (!get_md5_password(username, NULL, md5))
+    if (major_status == GSS_S_CONTINUE_NEEDED)
+      cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Credentials not complete.", con->number);
+    else if (major_status == GSS_S_COMPLETE)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "cupsdAuthorize: Unknown MD5 username \"%s\"!",
-                     username);
-      return;
+      major_status = gss_display_name(&minor_status, client_name,
+                                     &output_token, NULL);
+
+      if (GSS_ERROR(major_status))
+      {
+       cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, "[Client %d] Error getting username.", con->number);
+       gss_release_name(&minor_status, &client_name);
+       gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+       return;
+      }
+
+      strlcpy(username, output_token.value, sizeof(username));
+
+      cupsdLogClient(con, CUPSD_LOG_DEBUG, "Authorized as \"%s\" using Negotiate.", username);
+
+      gss_release_name(&minor_status, &client_name);
+      gss_release_buffer(&minor_status, &output_token);
+
+      con->type = CUPSD_AUTH_NEGOTIATE;
     }
 
-    httpMD5Final(nonce, states[con->http.state], con->uri, md5);
+    gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
 
-    if (strcmp(md5, password))
+#  if defined(SO_PEERCRED) && defined(AF_LOCAL)
+   /*
+    * Get the client's UID if we are printing locally - that allows a backend
+    * to run as the correct user to get Kerberos credentials of its own.
+    */
+
+    if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "cupsdAuthorize: Authentication failed for \"%s\"!",
-                     username);
-      return;
+      cupsd_ucred_t    peercred;       /* Peer credentials */
+      socklen_t                peersize;       /* Size of peer credentials */
+
+      peersize = sizeof(peercred);
+
+#    ifdef __APPLE__
+      if (getsockopt(httpGetFd(con->http), 0, LOCAL_PEERCRED, &peercred, &peersize))
+#    else
+      if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &peercred,
+                     &peersize))
+#    endif /* __APPLE__ */
+      {
+       cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", strerror(errno));
+      }
+      else
+      {
+       cupsdLogClient(con, CUPSD_LOG_DEBUG, "Using credentials for UID %d.", CUPSD_UCRED_UID(peercred));
+        con->gss_uid = CUPSD_UCRED_UID(peercred);
+      }
     }
+#  endif /* SO_PEERCRED && AF_LOCAL */
   }
+#endif /* HAVE_GSSAPI */
   else
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdAuthorize: Bad authentication data.");
+    char       scheme[256];            /* Auth scheme... */
+
+
+    if (sscanf(authorization, "%255s", scheme) != 1)
+      strlcpy(scheme, "UNKNOWN", sizeof(scheme));
+
+    cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\".", scheme);
     return;
   }
 
@@ -770,9 +884,67 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
 
   strlcpy(con->username, username, sizeof(con->username));
   strlcpy(con->password, password, sizeof(con->password));
+}
+
+
+/*
+ * 'cupsdCheckAccess()' - Check whether the given address is allowed to
+ *                        access a location.
+ */
+
+int                                    /* O - 1 if allowed, 0 otherwise */
+cupsdCheckAccess(
+    unsigned         ip[4],            /* I - Client address */
+    const char       *name,            /* I - Client hostname */
+    size_t           namelen,          /* I - Length of hostname */
+    cupsd_location_t *loc)             /* I - Location to check */
+{
+  int  allow;                          /* 1 if allowed, 0 otherwise */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: username=\"%s\"",
-                  con->username);
+
+  if (!_cups_strcasecmp(name, "localhost"))
+  {
+   /*
+    * Access from localhost (127.0.0.1 or ::1) is always allowed...
+    */
+
+    return (1);
+  }
+  else
+  {
+   /*
+    * Do authorization checks on the domain/address...
+    */
+
+    switch (loc->order_type)
+    {
+      default :
+         allow = 0;    /* anti-compiler-warning-code */
+         break;
+
+      case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+          allow = 1;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->deny))
+           allow = 0;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->allow))
+           allow = 1;
+         break;
+
+      case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+          allow = 0;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->allow))
+           allow = 1;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->deny))
+           allow = 0;
+         break;
+    }
+  }
+
+  return (allow);
 }
 
 
@@ -781,25 +953,27 @@ cupsdAuthorize(cupsd_client_t *con)       /* I - Client connection */
  */
 
 int                                    /* O - 1 if mask matches, 0 otherwise */
-cupsdCheckAuth(
-    unsigned         ip[4],            /* I - Client address */
-    char             *name,            /* I - Client hostname */
-    int              name_len,         /* I - Length of hostname */
-    int              num_masks,                /* I - Number of masks */
-    cupsd_authmask_t *masks)           /* I - Masks */
+cupsdCheckAuth(unsigned     ip[4],     /* I - Client address */
+              const char   *name,      /* I - Client hostname */
+              size_t       name_len,   /* I - Length of hostname */
+              cups_array_t *masks)     /* I - Masks */
 {
-  int          i;                      /* Looping var */
-  cupsd_netif_t        *iface;                 /* Network interface */
-  unsigned     netip4;                 /* IPv4 network address */
+  int                  i;              /* Looping var */
+  cupsd_authmask_t     *mask;          /* Current mask */
+  cupsd_netif_t                *iface;         /* Network interface */
+  unsigned             netip4;         /* IPv4 network address */
 #ifdef AF_INET6
-  unsigned     netip6[4];              /* IPv6 network address */
+  unsigned             netip6[4];      /* IPv6 network address */
 #endif /* AF_INET6 */
 
-  while (num_masks > 0)
+
+  for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
+       mask;
+       mask = (cupsd_authmask_t *)cupsArrayNext(masks))
   {
-    switch (masks->type)
+    switch (mask->type)
     {
-      case AUTH_INTERFACE :
+      case CUPSD_AUTH_INTERFACE :
          /*
          * Check for a match with a network interface...
          */
@@ -813,14 +987,23 @@ cupsdCheckAuth(
           netip6[3] = htonl(ip[3]);
 #endif /* AF_INET6 */
 
-          if (!strcmp(masks->mask.name.name, "*"))
+         cupsdNetIFUpdate();
+
+          if (!strcmp(mask->mask.name.name, "*"))
          {
+#ifdef __APPLE__
+           /*
+           * Allow Back-to-My-Mac addresses...
+           */
+
+           if ((ip[0] & 0xff000000) == 0xfd000000)
+             return (1);
+#endif /* __APPLE__ */
+
           /*
            * Check against all local interfaces...
            */
 
-            cupsdNetIFUpdate();
-
            for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
                 iface;
                 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
@@ -869,9 +1052,12 @@ cupsdCheckAuth(
            */
 
            for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
-                iface && !strcmp(masks->mask.name.name, iface->name);
+                iface;
                 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
            {
+              if (strcmp(mask->mask.name.name, iface->name))
+                continue;
+
               if (iface->address.addr.sa_family == AF_INET)
              {
               /*
@@ -904,42 +1090,39 @@ cupsdCheckAuth(
          }
          break;
 
-      case AUTH_NAME :
+      case CUPSD_AUTH_NAME :
          /*
          * Check for exact name match...
          */
 
-          if (!strcasecmp(name, masks->mask.name.name))
+          if (!_cups_strcasecmp(name, mask->mask.name.name))
            return (1);
 
          /*
          * Check for domain match...
          */
 
-         if (name_len >= masks->mask.name.length &&
-             masks->mask.name.name[0] == '.' &&
-             !strcasecmp(name + name_len - masks->mask.name.length,
-                         masks->mask.name.name))
+         if (name_len >= mask->mask.name.length &&
+             mask->mask.name.name[0] == '.' &&
+             !_cups_strcasecmp(name + name_len - mask->mask.name.length,
+                         mask->mask.name.name))
            return (1);
           break;
 
-      case AUTH_IP :
+      case CUPSD_AUTH_IP :
          /*
          * Check for IP/network address match...
          */
 
           for (i = 0; i < 4; i ++)
-           if ((ip[i] & masks->mask.ip.netmask[i]) !=
-                   masks->mask.ip.address[i])
+           if ((ip[i] & mask->mask.ip.netmask[i]) !=
+                   mask->mask.ip.address[i])
              break;
 
          if (i == 4)
            return (1);
           break;
     }
-
-    masks ++;
-    num_masks --;
   }
 
   return (0);
@@ -956,19 +1139,17 @@ cupsdCheckGroup(
     struct passwd *user,               /* I - System user info */
     const char    *groupname)          /* I - Group name */
 {
-  int                  i;              /* Looping var */
-  struct group         *group;         /* System group info */
-  char                 junk[33];       /* MD5 password (not used) */
+  int          i;                      /* Looping var */
+  struct group *group;                 /* Group info */
+  gid_t                groupid;                /* ID of named group */
 #ifdef HAVE_MBR_UID_TO_UUID
-  uuid_t               useruuid,       /* UUID for username */
-                       groupuuid;      /* UUID for groupname */
-  int                  is_member;      /* True if user is a member of group */
+  uuid_t       useruuid,               /* UUID for username */
+               groupuuid;              /* UUID for groupname */
+  int          is_member;              /* True if user is a member of group */
 #endif /* HAVE_MBR_UID_TO_UUID */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")",
-                  username, user, groupname);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, user, groupname);
 
  /*
   * Validate input...
@@ -990,347 +1171,196 @@ cupsdCheckGroup(
     * Group exists, check it...
     */
 
+    groupid = group->gr_gid;
+
+#ifdef HAVE_GETGROUPLIST
+    if (user)
+    {
+      int      ngroups;                /* Number of groups */
+#  ifdef __APPLE__
+      int      groups[2048];           /* Groups that user belongs to */
+#  else
+      gid_t    groups[2048];           /* Groups that user belongs to */
+#  endif /* __APPLE__ */
+
+      ngroups = (int)(sizeof(groups) / sizeof(groups[0]));
+#  ifdef __APPLE__
+      getgrouplist(username, (int)user->pw_gid, groups, &ngroups);
+#  else
+      getgrouplist(username, user->pw_gid, groups, &ngroups);
+#endif /* __APPLE__ */
+
+      for (i = 0; i < ngroups; i ++)
+        if ((int)groupid == (int)groups[i])
+         return (1);
+    }
+
+#else
     for (i = 0; group->gr_mem[i]; i ++)
-      if (!strcasecmp(username, group->gr_mem[i]))
+    {
+      if (!_cups_strcasecmp(username, group->gr_mem[i]))
        return (1);
+    }
+#endif /* HAVE_GETGROUPLIST */
   }
+  else
+    groupid = (gid_t)-1;
 
  /*
   * Group doesn't exist or user not in group list, check the group ID
   * against the user's group ID...
   */
 
-  if (user && group && group->gr_gid == user->pw_gid)
+  if (user && groupid == user->pw_gid)
     return (1);
 
 #ifdef HAVE_MBR_UID_TO_UUID
  /*
-  * Check group membership through MacOS X membership API...
-  */
-
-  if (user && group)
-    if (!mbr_uid_to_uuid(user->pw_uid, useruuid))
-      if (!mbr_gid_to_uuid(group->gr_gid, groupuuid))
-       if (!mbr_check_membership(useruuid, groupuuid, &is_member))
-         if (is_member)
-           return (1);
-#endif /* HAVE_MBR_UID_TO_UUID */
-
- /*
-  * Username not found, group not found, or user is not part of the
-  * system group...  Check for a user and group in the MD5 password
-  * file...
+  * Check group membership through macOS membership API...
   */
 
-  if (get_md5_password(username, groupname, junk) != NULL)
-    return (1);
-
- /*
-  * If we get this far, then the user isn't part of the named group...
-  */
-
-  return (0);
-}
-
-
-/*
- * 'cupsdCopyLocation()' - Make a copy of a location...
- */
-
-cupsd_location_t *                     /* O - New location */
-cupsdCopyLocation(
-    cupsd_location_t **loc)            /* IO - Original location */
-{
-  int                  i;              /* Looping var */
-  cupsd_location_t     *temp;          /* New location */
-  char                 location[HTTP_MAX_URI];
-                                       /* Location of resource */
-
-
- /*
-  * Use a local copy of location because cupsdAddLocation may cause
-  * this memory to be moved...
-  */
-
-  strlcpy(location, (*loc)->location, sizeof(location));
-
-  if ((temp = cupsdAddLocation(location)) == NULL)
-    return (NULL);
-
- /*
-  * Copy the information from the original location to the new one.
-  */
-
-  temp->limit      = (*loc)->limit;
-  temp->order_type = (*loc)->order_type;
-  temp->type       = (*loc)->type;
-  temp->level      = (*loc)->level;
-  temp->satisfy    = (*loc)->satisfy;
-  temp->encryption = (*loc)->encryption;
-
-  if ((temp->num_names  = (*loc)->num_names) > 0)
+  if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
   {
-   /*
-    * Copy the names array...
-    */
-
-    if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
+    if (groupid != (gid_t)-1)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d names: %s",
-                      temp->num_names, strerror(errno));
-
-      cupsdDeleteLocation(temp);
-      return (NULL);
-    }
-
-    for (i = 0; i < temp->num_names; i ++)
-      if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdCopyLocation: Unable to copy name \"%s\": %s",
-                        (*loc)->names[i], strerror(errno));
-
-        cupsdDeleteLocation(temp);
-       return (NULL);
-      }
-  }
-
-  if ((temp->num_allow  = (*loc)->num_allow) > 0)
-  {
-   /*
-    * Copy allow rules...
-    */
+     /*
+      * Map group name to UUID and check membership...
+      */
 
-    if ((temp->allow = calloc(temp->num_allow, sizeof(cupsd_authmask_t))) == NULL)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s",
-                      temp->num_allow, strerror(errno));
-      cupsdDeleteLocation(temp);
-      return (NULL);
+      if (!mbr_gid_to_uuid(groupid, groupuuid))
+        if (!mbr_check_membership(useruuid, groupuuid, &is_member))
+         if (is_member)
+           return (1);
     }
-
-    for (i = 0; i < temp->num_allow; i ++)
-      switch (temp->allow[i].type = (*loc)->allow[i].type)
-      {
-        case AUTH_NAME :
-           temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
-           temp->allow[i].mask.name.name   = strdup((*loc)->allow[i].mask.name.name);
-
-            if (temp->allow[i].mask.name.name == NULL)
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdCopyLocation: Unable to copy allow name \"%s\": %s",
-                             (*loc)->allow[i].mask.name.name, strerror(errno));
-              cupsdDeleteLocation(temp);
-             return (NULL);
-           }
-           break;
-       case AUTH_IP :
-           memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
-                  sizeof(cupsd_ipmask_t));
-           break;
-      }
-  }
-
-  if ((temp->num_deny  = (*loc)->num_deny) > 0)
-  {
-   /*
-    * Copy deny rules...
-    */
-
-    if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL)
+    else if (groupname[0] == '#')
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s",
-                      temp->num_deny, strerror(errno));
-      cupsdDeleteLocation(temp);
-      return (NULL);
-    }
+     /*
+      * Use UUID directly and check for equality (user UUID) and
+      * membership (group UUID)...
+      */
 
-    for (i = 0; i < temp->num_deny; i ++)
-      switch (temp->deny[i].type = (*loc)->deny[i].type)
+      if (!uuid_parse((char *)groupname + 1, groupuuid))
       {
-        case AUTH_NAME :
-           temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
-           temp->deny[i].mask.name.name   = strdup((*loc)->deny[i].mask.name.name);
-
-            if (temp->deny[i].mask.name.name == NULL)
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdCopyLocation: Unable to copy deny name \"%s\": %s",
-                             (*loc)->deny[i].mask.name.name, strerror(errno));
-              cupsdDeleteLocation(temp);
-             return (NULL);
-           }
-           break;
-       case AUTH_IP :
-           memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
-                  sizeof(cupsd_ipmask_t));
-           break;
-      }
-  }
-
-  return (temp);
-}
-
-
-/*
- * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
- */
-
-void
-cupsdDeleteAllLocations(void)
-{
-  cupsd_location_t     *loc;           /* Current location */
-
-
- /*
-  * Free all of the allow/deny records first...
-  */
+        if (!uuid_compare(useruuid, groupuuid))
+         return (1);
+       else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
+         if (is_member)
+           return (1);
+      }
 
-  for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
-       loc;
-       loc = (cupsd_location_t *)cupsArrayNext(Locations))
-    cupsdDeleteLocation(loc);
+      return (0);
+    }
+  }
+  else if (groupname[0] == '#')
+    return (0);
+#endif /* HAVE_MBR_UID_TO_UUID */
 
  /*
-  * Then free the location array...
+  * If we get this far, then the user isn't part of the named group...
   */
 
-  cupsArrayDelete(Locations);
-  Locations = NULL;
+  return (0);
 }
 
 
 /*
- * 'cupsdDeleteLocation()' - Free all memory used by a location.
+ * 'cupsdCopyLocation()' - Make a copy of a location...
  */
 
-void
-cupsdDeleteLocation(
-    cupsd_location_t *loc)             /* I - Location to delete */
+cupsd_location_t *                     /* O - New location */
+cupsdCopyLocation(
+    cupsd_location_t *loc)             /* I - Original location */
 {
-  int                  i;              /* Looping var */
-  cupsd_authmask_t     *mask;          /* Current mask */
-
-
-  cupsArrayRemove(Locations, loc);
-
-  for (i = loc->num_names - 1; i >= 0; i --)
-    free(loc->names[i]);
-
-  if (loc->num_names > 0)
-    free(loc->names);
-
-  for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++)
-    if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE)
-      free(mask->mask.name.name);
-
-  if (loc->num_allow > 0)
-    free(loc->allow);
-
-  for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++)
-    if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE)
-      free(mask->mask.name.name);
-
-  if (loc->num_deny > 0)
-    free(loc->deny);
+  cupsd_location_t     *temp;          /* New location */
 
-  free(loc->location);
-  free(loc);
-}
 
+ /*
+  * Make a copy of the original location...
+  */
 
-/*
- * 'cupsdDenyHost()' - Add a host name that is not allowed to access the
- *                     location.
- */
+  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
+    return (NULL);
 
-void
-cupsdDenyHost(cupsd_location_t *loc,   /* I - Location to add to */
-              char             *name)  /* I - Name of host or domain to add */
-{
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
-  char                 ifname[32],     /* Interface name */
-                       *ifptr;         /* Pointer to end of name */
+ /*
+  * Copy the information from the original location to the new one.
+  */
 
+  if (!loc)
+    return (temp);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location ? loc->location : "nil", name);
+  if (loc->location)
+    temp->location = _cupsStrAlloc(loc->location);
 
-  if ((temp = add_deny(loc)) == NULL)
-    return;
+  temp->length     = loc->length;
+  temp->limit      = loc->limit;
+  temp->order_type = loc->order_type;
+  temp->type       = loc->type;
+  temp->level      = loc->level;
+  temp->satisfy    = loc->satisfy;
+  temp->encryption = loc->encryption;
 
-  if (!strcasecmp(name, "@LOCAL"))
+  if (loc->names)
   {
-   /*
-    * Deny *interface*...
-    */
+    if ((temp->names = cupsArrayDup(loc->names)) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to allocate memory for %d names: %s",
+                     cupsArrayCount(loc->names), strerror(errno));
 
-    temp->type             = AUTH_INTERFACE;
-    temp->mask.name.name   = strdup("*");
-    temp->mask.name.length = 1;
+      cupsdFreeLocation(temp);
+      return (NULL);
+    }
   }
-  else if (!strncasecmp(name, "@IF(", 4))
+
+  if (loc->allow)
   {
    /*
-    * Deny *interface*...
+    * Copy allow rules...
     */
 
-    strlcpy(ifname, name + 4, sizeof(ifname));
-
-    ifptr = ifname + strlen(ifname);
-
-    if (ifptr[-1] == ')')
+    if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
     {
-      ifptr --;
-      *ifptr = '\0';
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to allocate memory for %d allow rules: %s",
+                      cupsArrayCount(loc->allow), strerror(errno));
+      cupsdFreeLocation(temp);
+      return (NULL);
     }
-
-    temp->type             = AUTH_INTERFACE;
-    temp->mask.name.name   = strdup(ifname);
-    temp->mask.name.length = ifptr - ifname;
   }
-  else
+
+  if (loc->deny)
   {
    /*
-    * Deny name...
+    * Copy deny rules...
     */
 
-    temp->type             = AUTH_NAME;
-    temp->mask.name.name   = strdup(name);
-    temp->mask.name.length = strlen(name);
+    if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to allocate memory for %d deny rules: %s",
+                      cupsArrayCount(loc->deny), strerror(errno));
+      cupsdFreeLocation(temp);
+      return (NULL);
+    }
   }
+
+  return (temp);
 }
 
 
 /*
- * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to
- *                   access the location.
+ * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
  */
 
 void
-cupsdDenyIP(cupsd_location_t *loc,     /* I - Location to add to */
-           unsigned         address[4],/* I - IP address to add */
-           unsigned         netmask[4])/* I - Netmask of address */
+cupsdDeleteAllLocations(void)
 {
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
-
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
-                  "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location ? loc->location : "nil",
-                 address[0], address[1], address[2], address[3],
-                 netmask[0], netmask[1], netmask[2], netmask[3]);
-
-  if ((temp = add_deny(loc)) == NULL)
-    return;
+ /*
+  * Free the location array, which will free all of the locations...
+  */
 
-  temp->type = AUTH_IP;
-  memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
-  memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
+  cupsArrayDelete(Locations);
+  Locations = NULL;
 }
 
 
@@ -1347,24 +1377,26 @@ cupsdFindBest(const char   *path,       /* I - Resource path */
                        *uriptr;        /* Pointer into URI */
   cupsd_location_t     *loc,           /* Current location */
                        *best;          /* Best match for location so far */
-  int                  bestlen;        /* Length of best match */
+  size_t               bestlen;        /* Length of best match */
   int                  limit;          /* Limit field */
-  static const int     limits[] =      /* Map http_status_t to AUTH_LIMIT_xyz */
+  static const int     limits[] =      /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
                {
-                 AUTH_LIMIT_ALL,
-                 AUTH_LIMIT_OPTIONS,
-                 AUTH_LIMIT_GET,
-                 AUTH_LIMIT_GET,
-                 AUTH_LIMIT_HEAD,
-                 AUTH_LIMIT_POST,
-                 AUTH_LIMIT_POST,
-                 AUTH_LIMIT_POST,
-                 AUTH_LIMIT_PUT,
-                 AUTH_LIMIT_PUT,
-                 AUTH_LIMIT_DELETE,
-                 AUTH_LIMIT_TRACE,
-                 AUTH_LIMIT_ALL,
-                 AUTH_LIMIT_ALL
+                 CUPSD_AUTH_LIMIT_ALL,
+                 CUPSD_AUTH_LIMIT_OPTIONS,
+                 CUPSD_AUTH_LIMIT_GET,
+                 CUPSD_AUTH_LIMIT_GET,
+                 CUPSD_AUTH_LIMIT_HEAD,
+                 CUPSD_AUTH_LIMIT_POST,
+                 CUPSD_AUTH_LIMIT_POST,
+                 CUPSD_AUTH_LIMIT_POST,
+                 CUPSD_AUTH_LIMIT_PUT,
+                 CUPSD_AUTH_LIMIT_PUT,
+                 CUPSD_AUTH_LIMIT_DELETE,
+                 CUPSD_AUTH_LIMIT_TRACE,
+                 CUPSD_AUTH_LIMIT_ALL,
+                 CUPSD_AUTH_LIMIT_ALL,
+                 CUPSD_AUTH_LIMIT_ALL,
+                 CUPSD_AUTH_LIMIT_ALL
                };
 
 
@@ -1376,6 +1408,12 @@ cupsdFindBest(const char   *path,        /* I - Resource path */
 
   strlcpy(uri, path, sizeof(uri));
 
+  if ((uriptr = strchr(uri, '?')) != NULL)
+    *uriptr = '\0';            /* Drop trailing query string */
+
+  if ((uriptr = uri + strlen(uri) - 1) > uri && *uriptr == '/')
+    *uriptr = '\0';            /* Remove trailing '/' */
+
   if (!strncmp(uri, "/printers/", 10) ||
       !strncmp(uri, "/classes/", 9))
   {
@@ -1389,8 +1427,6 @@ cupsdFindBest(const char   *path, /* I - Resource path */
       *uriptr = '\0';
   }
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri = \"%s\"...", uri);
-
  /*
   * Loop through the list of locations to find a match...
   */
@@ -1399,12 +1435,14 @@ cupsdFindBest(const char   *path,       /* I - Resource path */
   best    = NULL;
   bestlen = 0;
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri=\"%s\", limit=%x...", uri, limit);
+
+
   for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
        loc;
        loc = (cupsd_location_t *)cupsArrayNext(Locations))
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x",
-                    loc->location ? loc->location : "nil", loc->limit);
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s(%d) Limit %x", loc->location ? loc->location : "(null)", (int)loc->length, loc->limit);
 
     if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
     {
@@ -1413,7 +1451,7 @@ cupsdFindBest(const char   *path, /* I - Resource path */
       */
 
       if (loc->length > bestlen && loc->location &&
-          !strncasecmp(uri, loc->location, loc->length) &&
+          !_cups_strncasecmp(uri, loc->location, loc->length) &&
          loc->location[0] == '/' &&
          (limit & loc->limit) != 0)
       {
@@ -1442,8 +1480,7 @@ cupsdFindBest(const char   *path, /* I - Resource path */
   * Return the match, if any...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s",
-                  best ? best->location : "NONE");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best=%s", best ? best->location : "NONE");
 
   return (best);
 }
@@ -1465,6 +1502,22 @@ cupsdFindLocation(const char *location)  /* I - Connection */
 }
 
 
+/*
+ * 'cupsdFreeLocation()' - Free all memory used by a location.
+ */
+
+void
+cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */
+{
+  cupsArrayDelete(loc->names);
+  cupsArrayDelete(loc->allow);
+  cupsArrayDelete(loc->deny);
+
+  _cupsStrFree(loc->location);
+  free(loc);
+}
+
+
 /*
  * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
  */
@@ -1473,12 +1526,20 @@ http_status_t                           /* O - HTTP_OK if authorized or error code */
 cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
                   const char     *owner)/* I - Owner of object */
 {
-  int                  i, j,           /* Looping vars */
-                       auth;           /* Authorization status */
+  int                  i,              /* Looping vars */
+                       auth,           /* Authorization status */
+                       type;           /* Type of authentication */
+  http_addr_t          *hostaddr = httpGetAddress(con->http);
+                                       /* Client address */
+  const char           *hostname = httpGetHostname(con->http, NULL, 0);
+                                       /* Client hostname */
   unsigned             address[4];     /* Authorization address */
   cupsd_location_t     *best;          /* Best match for location so far */
-  int                  hostlen;        /* Length of hostname */
-  const char           *username;      /* Username to authorize */
+  size_t               hostlen;        /* Length of hostname */
+  char                 *name,          /* Current username */
+                       username[256],  /* Username to authorize */
+                       ownername[256], /* Owner name to authorize */
+                       *ptr;           /* Pointer into username */
   struct passwd                *pw;            /* User password data */
   static const char * const levels[] = /* Auth levels */
                {
@@ -1488,20 +1549,15 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
                };
   static const char * const types[] =  /* Auth types */
                {
-                 "NONE",
-                 "BASIC",
-                 "DIGEST",
-                 "BASICDIGEST"
+                 "None",
+                 "Basic",
+                 "Negotiate"
                };
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
-                  con->uri, con->best, con->best ? con->best->location ?
-                                          con->best->location : "(null)" : "");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location ? con->best->location : "(null)" : "");
   if (owner)
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdIsAuthorized: owner=\"%s\"", owner);
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: owner=\"%s\"", owner);
 
  /*
   * If there is no "best" authentication rule for this request, then
@@ -1511,8 +1567,9 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
 
   if (!con->best)
   {
-    if (!strcmp(con->http.hostname, "localhost") ||
-        !strcmp(con->http.hostname, ServerName))
+    if (httpAddrLocalhost(httpGetAddress(con->http)) ||
+        !strcmp(hostname, ServerName) ||
+       cupsArrayFind(ServerAlias, (void *)hostname))
       return (HTTP_OK);
     else
       return (HTTP_FORBIDDEN);
@@ -1520,35 +1577,33 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
 
   best = con->best;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdIsAuthorized: level=AUTH_%s, type=AUTH_%s, "
-                 "satisfy=AUTH_SATISFY_%s, num_names=%d",
-                  levels[best->level], types[best->type],
-                 best->satisfy ? "ANY" : "ALL", best->num_names);
+  if ((type = best->type) == CUPSD_AUTH_DEFAULT)
+    type = cupsdDefaultAuthType();
 
-  if (best->limit == AUTH_LIMIT_IPP)
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
-                    best->op, ippOpString(best->op));
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d", levels[best->level], types[type], best->satisfy ? "ANY" : "ALL", cupsArrayCount(best->names));
+
+  if (best->limit == CUPSD_AUTH_LIMIT_IPP)
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", best->op, ippOpString(best->op));
 
  /*
   * Check host/ip-based accesses...
   */
 
 #ifdef AF_INET6
-  if (con->http.hostaddr->addr.sa_family == AF_INET6)
+  if (httpAddrFamily(hostaddr) == AF_INET6)
   {
    /*
     * Copy IPv6 address...
     */
 
-    address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]);
-    address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]);
-    address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]);
-    address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]);
+    address[0] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[0]);
+    address[1] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[1]);
+    address[2] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[2]);
+    address[3] = ntohl(hostaddr->ipv6.sin6_addr.s6_addr32[3]);
   }
   else
 #endif /* AF_INET6 */
-  if (con->http.hostaddr->addr.sa_family == AF_INET)
+  if (con->http->hostaddr->addr.sa_family == AF_INET)
   {
    /*
     * Copy IPv4 address...
@@ -1557,63 +1612,19 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
     address[0] = 0;
     address[1] = 0;
     address[2] = 0;
-    address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr);
+    address[3] = ntohl(hostaddr->ipv4.sin_addr.s_addr);
   }
   else
     memset(address, 0, sizeof(address));
 
-  hostlen = strlen(con->http.hostname);
-
-  if (!strcasecmp(con->http.hostname, "localhost"))
-  {
-   /*
-    * Access from localhost (127.0.0.1 or ::1) is always allowed...
-    */
-
-    auth = AUTH_ALLOW;
-  }
-  else
-  {
-   /*
-    * Do authorization checks on the domain/address...
-    */
-
-    switch (best->order_type)
-    {
-      default :
-         auth = AUTH_DENY;     /* anti-compiler-warning-code */
-         break;
-
-      case AUTH_ALLOW : /* Order Deny,Allow */
-          auth = AUTH_ALLOW;
-
-          if (cupsdCheckAuth(address, con->http.hostname, hostlen,
-                       best->num_deny, best->deny))
-           auth = AUTH_DENY;
-
-          if (cupsdCheckAuth(address, con->http.hostname, hostlen,
-                       best->num_allow, best->allow))
-           auth = AUTH_ALLOW;
-         break;
-
-      case AUTH_DENY : /* Order Allow,Deny */
-          auth = AUTH_DENY;
+  hostlen = strlen(hostname);
 
-          if (cupsdCheckAuth(address, con->http.hostname, hostlen,
-                       best->num_allow, best->allow))
-           auth = AUTH_ALLOW;
-
-          if (cupsdCheckAuth(address, con->http.hostname, hostlen,
-                       best->num_deny, best->deny))
-           auth = AUTH_DENY;
-         break;
-    }
-  }
+  auth = cupsdCheckAccess(address, hostname, hostlen, best)
+             ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=AUTH_%s...",
-                  auth ? "DENY" : "ALLOW");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...", auth ? "DENY" : "ALLOW");
 
-  if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
+  if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
     return (HTTP_FORBIDDEN);
 
 #ifdef HAVE_SSL
@@ -1621,11 +1632,15 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
   * See if encryption is required...
   */
 
-  if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
-      strcasecmp(con->http.hostname, "localhost") &&
-      best->satisfy == AUTH_SATISFY_ALL)
+  if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http->tls &&
+      _cups_strcasecmp(hostname, "localhost") &&
+      !httpAddrLocalhost(hostaddr) &&
+      best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
+      !(type == CUPSD_AUTH_NEGOTIATE ||
+        (type == CUPSD_AUTH_NONE &&
+         cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE)))
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
                     "cupsdIsAuthorized: Need upgrade to TLS...");
     return (HTTP_UPGRADE_REQUIRED);
   }
@@ -1635,12 +1650,12 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
   * Now see what access level is required...
   */
 
-  if (best->level == AUTH_ANON ||      /* Anonymous access - allow it */
-      (best->type == AUTH_NONE && best->num_names == 0))
+  if (best->level == CUPSD_AUTH_ANON ||        /* Anonymous access - allow it */
+      (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
     return (HTTP_OK);
 
-  if (!con->username[0] && best->type == AUTH_NONE &&
-      best->limit == AUTH_LIMIT_IPP)
+  if (!con->username[0] && type == CUPSD_AUTH_NONE &&
+      best->limit == CUPSD_AUTH_LIMIT_IPP)
   {
    /*
     * Check for unauthenticated username...
@@ -1652,30 +1667,47 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
     attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
     if (attr)
     {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+      cupsdLogMessage(CUPSD_LOG_DEBUG,
                       "cupsdIsAuthorized: requesting-user-name=\"%s\"",
                       attr->values[0].string.text);
-      username = attr->values[0].string.text;
+      strlcpy(username, attr->values[0].string.text, sizeof(username));
     }
-    else if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
+    else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
       return (HTTP_UNAUTHORIZED);      /* Non-anonymous needs user/pass */
     else
       return (HTTP_OK);                        /* unless overridden with Satisfy */
   }
   else
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"",
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
                    con->username);
 
+#ifdef HAVE_AUTHORIZATION_H
+    if (!con->username[0] && !con->authref)
+#else
     if (!con->username[0])
+#endif /* HAVE_AUTHORIZATION_H */
     {
-      if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
+      if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
        return (HTTP_UNAUTHORIZED);     /* Non-anonymous needs user/pass */
       else
        return (HTTP_OK);               /* unless overridden with Satisfy */
     }
 
-    username = con->username;
+
+    if (con->type != type && type != CUPSD_AUTH_NONE &&
+#ifdef HAVE_GSSAPI
+        (type != CUPSD_AUTH_NEGOTIATE || con->gss_uid <= 0) &&
+#endif /* HAVE_GSSAPI */
+        con->type != CUPSD_AUTH_BASIC)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s.",
+                      types[con->type], types[type]);
+
+      return (HTTP_UNAUTHORIZED);
+    }
+
+    strlcpy(username, con->username, sizeof(username));
   }
 
  /*
@@ -1686,21 +1718,43 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
   if (!strcmp(username, "root"))
     return (HTTP_OK);
 
+ /*
+  * Strip any @domain or @KDC from the username and owner...
+  */
+
+  if ((ptr = strchr(username, '@')) != NULL)
+    *ptr = '\0';
+
+  if (owner)
+  {
+    strlcpy(ownername, owner, sizeof(ownername));
+
+    if ((ptr = strchr(ownername, '@')) != NULL)
+      *ptr = '\0';
+  }
+  else
+    ownername[0] = '\0';
+
  /*
   * Get the user info...
   */
 
-  pw = getpwnam(username);
-  endpwent();
+  if (username[0])
+  {
+    pw = getpwnam(username);
+    endpwent();
+  }
+  else
+    pw = NULL;
 
-  if (best->level == AUTH_USER)
+  if (best->level == CUPSD_AUTH_USER)
   {
    /*
     * If there are no names associated with this location, then
     * any valid user is OK...
     */
 
-    if (best->num_names == 0)
+    if (cupsArrayCount(best->names) == 0)
       return (HTTP_OK);
 
    /*
@@ -1708,56 +1762,78 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
     * allowed...
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdIsAuthorized: Checking user membership...");
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking user membership...");
+
+#ifdef HAVE_AUTHORIZATION_H
+   /*
+    * If an authorization reference was supplied it must match a right name...
+    */
+
+    if (con->authref)
+    {
+      for (name = (char *)cupsArrayFirst(best->names);
+           name;
+          name = (char *)cupsArrayNext(best->names))
+      {
+       if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
+         return (HTTP_OK);
+       else if (!_cups_strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
+                check_authref(con, SystemGroupAuthKey))
+         return (HTTP_OK);
+      }
+
+      return (HTTP_FORBIDDEN);
+    }
+#endif /* HAVE_AUTHORIZATION_H */
 
-    for (i = 0; i < best->num_names; i ++)
+    for (name = (char *)cupsArrayFirst(best->names);
+        name;
+        name = (char *)cupsArrayNext(best->names))
     {
-      if (!strcasecmp(best->names[i], "@OWNER") && owner &&
-          !strcasecmp(username, owner))
+      if (!_cups_strcasecmp(name, "@OWNER") && owner &&
+          !_cups_strcasecmp(username, ownername))
        return (HTTP_OK);
-      else if (!strcasecmp(best->names[i], "@SYSTEM"))
+      else if (!_cups_strcasecmp(name, "@SYSTEM"))
       {
-        for (j = 0; j < NumSystemGroups; j ++)
-         if (cupsdCheckGroup(username, pw, SystemGroups[j]))
+        for (i = 0; i < NumSystemGroups; i ++)
+         if (cupsdCheckGroup(username, pw, SystemGroups[i]))
            return (HTTP_OK);
       }
-      else if (best->names[i][0] == '@')
+      else if (name[0] == '@')
       {
-        if (cupsdCheckGroup(username, pw, best->names[i] + 1))
+        if (cupsdCheckGroup(username, pw, name + 1))
           return (HTTP_OK);
       }
-      else if (!strcasecmp(username, best->names[i]))
+      else if (!_cups_strcasecmp(username, name))
         return (HTTP_OK);
     }
 
-    return (HTTP_UNAUTHORIZED);
+    return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
   }
 
  /*
   * Check to see if this user is in any of the named groups...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdIsAuthorized: Checking group membership...");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group membership...");
 
  /*
   * Check to see if this user is in any of the named groups...
   */
 
-  for (i = 0; i < best->num_names; i ++)
+  for (name = (char *)cupsArrayFirst(best->names);
+       name;
+       name = (char *)cupsArrayNext(best->names))
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdIsAuthorized: Checking group \"%s\" membership...",
-                    best->names[i]);
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name);
 
-    if (!strcasecmp(best->names[i], "@SYSTEM"))
+    if (!_cups_strcasecmp(name, "@SYSTEM"))
     {
-      for (j = 0; j < NumSystemGroups; j ++)
-       if (cupsdCheckGroup(username, pw, SystemGroups[j]))
+      for (i = 0; i < NumSystemGroups; i ++)
+       if (cupsdCheckGroup(username, pw, SystemGroups[i]))
          return (HTTP_OK);
     }
-    else if (cupsdCheckGroup(username, pw, best->names[i]))
+    else if (cupsdCheckGroup(username, pw, name))
       return (HTTP_OK);
   }
 
@@ -1765,95 +1841,101 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
   * The user isn't part of the specified group, so deny access...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdIsAuthorized: User not in group(s)!");
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: User not in group(s).");
 
-  return (HTTP_UNAUTHORIZED);
+  return (con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED);
 }
 
 
 /*
- * 'add_allow()' - Add an allow mask to the location.
+ * 'cupsdNewLocation()' - Create a new location for authorization.
+ *
+ * Note: Still need to call cupsdAddLocation() to add it to the list of global
+ * locations.
  */
 
-static cupsd_authmask_t *              /* O - New mask record */
-add_allow(cupsd_location_t *loc)       /* I - Location to add to */
+cupsd_location_t *                     /* O - Pointer to new location record */
+cupsdNewLocation(const char *location) /* I - Location path */
 {
-  cupsd_authmask_t     *temp;          /* New mask record */
+  cupsd_location_t     *temp;          /* New location */
 
 
  /*
-  * Range-check...
+  * Try to allocate memory for the new location.
   */
 
-  if (loc == NULL)
+  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
     return (NULL);
 
  /*
-  * Try to allocate memory for the record...
+  * Initialize the record and copy the name over...
   */
 
-  if (loc->num_allow == 0)
-    temp = malloc(sizeof(cupsd_authmask_t));
-  else
-    temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1));
-
-  if (temp == NULL)
+  if ((temp->location = _cupsStrAlloc(location)) == NULL)
+  {
+    free(temp);
     return (NULL);
+  }
 
-  loc->allow = temp;
-  temp       += loc->num_allow;
-  loc->num_allow ++;
+  temp->length = strlen(temp->location);
 
  /*
-  * Clear the mask record and return...
+  * Return the new record...
   */
 
-  memset(temp, 0, sizeof(cupsd_authmask_t));
   return (temp);
 }
 
 
+#ifdef HAVE_AUTHORIZATION_H
 /*
- * 'add_deny()' - Add a deny mask to the location.
+ * 'check_authref()' - Check if an authorization services reference has the
+ *                    supplied right.
  */
 
-static cupsd_authmask_t *              /* O - New mask record */
-add_deny(cupsd_location_t *loc)                /* I - Location to add to */
+static int                             /* O - 1 if right is valid, 0 otherwise */
+check_authref(cupsd_client_t *con,     /* I - Connection */
+             const char     *right)    /* I - Right name */
 {
-  cupsd_authmask_t     *temp;          /* New mask record */
+  OSStatus             status;         /* OS Status */
+  AuthorizationItem    authright;      /* Authorization right */
+  AuthorizationRights  authrights;     /* Authorization rights */
+  AuthorizationFlags   authflags;      /* Authorization flags */
 
 
  /*
-  * Range-check...
+  * Check to see if the user is allowed to perform the task...
   */
 
-  if (loc == NULL)
-    return (NULL);
+  if (!con->authref)
+    return (0);
 
- /*
-  * Try to allocate memory for the record...
-  */
+  authright.name        = right;
+  authright.valueLength = 0;
+  authright.value       = NULL;
+  authright.flags       = 0;
 
-  if (loc->num_deny == 0)
-    temp = malloc(sizeof(cupsd_authmask_t));
-  else
-    temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1));
+  authrights.count = 1;
+  authrights.items = &authright;
 
-  if (temp == NULL)
-    return (NULL);
+  authflags = kAuthorizationFlagDefaults |
+             kAuthorizationFlagExtendRights;
 
-  loc->deny = temp;
-  temp      += loc->num_deny;
-  loc->num_deny ++;
+  if ((status = AuthorizationCopyRights(con->authref, &authrights,
+                                       kAuthorizationEmptyEnvironment,
+                                       authflags, NULL)) != 0)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                   "AuthorizationCopyRights(\"%s\") returned %d (%s)",
+                   authright.name, (int)status, cssmErrorString(status));
+    return (0);
+  }
 
- /*
-  * Clear the mask record and return...
-  */
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "AuthorizationCopyRights(\"%s\") succeeded.", authright.name);
 
-  memset(temp, 0, sizeof(cupsd_authmask_t));
-  return (temp);
+  return (1);
 }
+#endif /* HAVE_AUTHORIZATION_H */
 
 
 /*
@@ -1868,188 +1950,59 @@ compare_locations(cupsd_location_t *a, /* I - First location */
 }
 
 
-#if !HAVE_LIBPAM
 /*
- * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
- *                  as needed.
+ * 'copy_authmask()' - Copy function for auth masks.
  */
 
-static char *                          /* O - Encrypted password */
-cups_crypt(const char *pw,             /* I - Password string */
-           const char *salt)           /* I - Salt (key) string */
+static cupsd_authmask_t        *               /* O - New auth mask */
+copy_authmask(cupsd_authmask_t *mask,  /* I - Existing auth mask */
+              void             *data)  /* I - User data (unused) */
 {
-  if (!strncmp(salt, "$1$", 3))
-  {
-   /*
-    * Use MD5 passwords without the benefit of PAM; this is for
-    * Slackware Linux, and the algorithm was taken from the
-    * old shadow-19990827/lib/md5crypt.c source code... :(
-    */
-
-    int                        i;              /* Looping var */
-    unsigned long      n;              /* Output number */
-    int                        pwlen;          /* Length of password string */
-    const char         *salt_end;      /* End of "salt" data for MD5 */
-    char               *ptr;           /* Pointer into result string */
-    _cups_md5_state_t  state;          /* Primary MD5 state info */
-    _cups_md5_state_t  state2;         /* Secondary MD5 state info */
-    unsigned char      digest[16];     /* MD5 digest result */
-    static char                result[120];    /* Final password string */
-
-
-   /*
-    * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
-    * Get a maximum of 8 characters of salt data after $1$...
-    */
-
-    for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
-      if (*salt_end == '$')
-        break;
-
-   /*
-    * Compute the MD5 sum we need...
-    */
+  cupsd_authmask_t     *temp;          /* New auth mask */
 
-    pwlen = strlen(pw);
 
-    _cupsMD5Init(&state);
-    _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
-    _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
+  (void)data;
 
-    _cupsMD5Init(&state2);
-    _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
-    _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
-    _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
-    _cupsMD5Finish(&state2, digest);
-
-    for (i = pwlen; i > 0; i -= 16)
-      _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
-
-    for (i = pwlen; i > 0; i >>= 1)
-      _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
-
-    _cupsMD5Finish(&state, digest);
-
-    for (i = 0; i < 1000; i ++)
-    {
-      _cupsMD5Init(&state);
-
-      if (i & 1)
-        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
-      else
-        _cupsMD5Append(&state, digest, 16);
-
-      if (i % 3)
-        _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
-
-      if (i % 7)
-        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
-
-      if (i & 1)
-        _cupsMD5Append(&state, digest, 16);
-      else
-        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
-
-      _cupsMD5Finish(&state, digest);
-    }
-
-   /*
-    * Copy the final sum to the result string and return...
-    */
-
-    memcpy(result, salt, salt_end - salt);
-    ptr = result + (salt_end - salt);
-    *ptr++ = '$';
+  if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
+  {
+    memcpy(temp, mask, sizeof(cupsd_authmask_t));
 
-    for (i = 0; i < 5; i ++, ptr += 4)
+    if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
     {
-      n = (((digest[i] << 8) | digest[i + 6]) << 8);
+     /*
+      * Make a copy of the name...
+      */
 
-      if (i < 4)
-        n |= digest[i + 12];
-      else
-        n |= digest[5];
+      if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
+      {
+       /*
+        * Failed to make copy...
+       */
 
-      to64(ptr, n, 4);
+        free(temp);
+       temp = NULL;
+      }
     }
-
-    to64(ptr, digest[11], 2);
-    ptr += 2;
-    *ptr = '\0';
-
-    return (result);
   }
-  else
-  {
-   /*
-    * Use the standard crypt() function...
-    */
 
-    return (crypt(pw, salt));
-  }
+  return (temp);
 }
-#endif /* !HAVE_LIBPAM */
 
 
 /*
- * 'get_md5_password()' - Get an MD5 password.
+ * 'free_authmask()' - Free function for auth masks.
  */
 
-static char *                          /* O - MD5 password string */
-get_md5_password(const char *username, /* I - Username */
-                 const char *group,    /* I - Group */
-                 char       passwd[33])        /* O - MD5 password string */
+static void
+free_authmask(cupsd_authmask_t *mask,  /* I - Auth mask to free */
+              void             *data)  /* I - User data (unused) */
 {
-  cups_file_t  *fp;                    /* passwd.md5 file */
-  char         filename[1024],         /* passwd.md5 filename */
-               line[256],              /* Line from file */
-               tempuser[33],           /* User from file */
-               tempgroup[33];          /* Group from file */
-
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "get_md5_password(username=\"%s\", group=\"%s\", passwd=%p)",
-                  username, group ? group : "(null)", passwd);
-
-  snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
-  if ((fp = cupsFileOpen(filename, "r")) == NULL)
-  {
-    if (errno != ENOENT)
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename,
-                      strerror(errno));
-
-    return (NULL);
-  }
-
-  while (cupsFileGets(fp, line, sizeof(line)) != NULL)
-  {
-    if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line);
-      continue;
-    }
-
-    if (!strcmp(username, tempuser) &&
-        (group == NULL || !strcmp(group, tempgroup)))
-    {
-     /*
-      * Found the password entry!
-      */
+  (void)data;
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
-                      username, tempgroup);
+  if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
+    _cupsStrFree(mask->mask.name.name);
 
-      cupsFileClose(fp);
-      return (passwd);
-    }
-  }
-
- /*
-  * Didn't find a password entry - return NULL!
-  */
-
-  cupsFileClose(fp);
-  return (NULL);
+  free(mask);
 }
 
 
@@ -2075,62 +2028,40 @@ pam_func(
   * Allocate memory for the responses...
   */
 
-  if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
+  if ((replies = malloc(sizeof(struct pam_response) * (size_t)num_msg)) == NULL)
     return (PAM_CONV_ERR);
 
  /*
   * Answer all of the messages...
   */
 
-  DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
-
-#ifdef __hpux
- /*
-  * Apparently some versions of HP-UX 11 have a broken pam_unix security
-  * module.  This is a workaround...
-  */
-
-  data = auth_data;
-  (void)appdata_ptr;
-#else
   data = (cupsd_authdata_t *)appdata_ptr;
-#endif /* __hpux */
 
   for (i = 0; i < num_msg; i ++)
   {
-    DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
-
     switch (msg[i]->msg_style)
     {
       case PAM_PROMPT_ECHO_ON:
-          DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
-                       data->username));
           replies[i].resp_retcode = PAM_SUCCESS;
           replies[i].resp         = strdup(data->username);
           break;
 
       case PAM_PROMPT_ECHO_OFF:
-          DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
-                       data->password));
           replies[i].resp_retcode = PAM_SUCCESS;
           replies[i].resp         = strdup(data->password);
           break;
 
       case PAM_TEXT_INFO:
-          DEBUG_puts("pam_func: PAM_TEXT_INFO...");
           replies[i].resp_retcode = PAM_SUCCESS;
           replies[i].resp         = NULL;
           break;
 
       case PAM_ERROR_MSG:
-          DEBUG_puts("pam_func: PAM_ERROR_MSG...");
           replies[i].resp_retcode = PAM_SUCCESS;
           replies[i].resp         = NULL;
           break;
 
       default:
-          DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
-                       msg[i]->msg_style));
           free(replies);
           return (PAM_CONV_ERR);
     }
@@ -2165,8 +2096,3 @@ to64(char          *s,                    /* O - Output string */
     *s++ = itoa64[v & 0x3f];
 }
 #endif /* HAVE_LIBPAM */
-
-
-/*
- * End of "$Id: auth.c 5568 2006-05-22 15:34:01Z mike $".
- */