]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/auth.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / auth.c
index e71cfaa403173f57af6296d4347703c918fc18a9..78e82d52ec8eacfce733864f8004e4bfcccfb16e 100644 (file)
@@ -1,5 +1,5 @@
-;/*
- * "$Id: auth.c 5043 2006-02-01 18:55:16Z mike $"
+/*
+ * "$Id: auth.c 5464 2006-04-26 01:34:14Z mike $"
  *
  *   Authorization routines for the Common UNIX Printing System (CUPS).
  *
  *   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.
+ *   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.
+ *   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.
+ *   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.
- *   cupsdGetMD5Passwd()       - Get an MD5 password.
  *   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...
  */
@@ -73,6 +76,9 @@
 #ifdef HAVE_USERSEC_H
 #  include <usersec.h>
 #endif /* HAVE_USERSEC_H */
+#ifdef HAVE_MEMBERSHIP_H
+#  include <membership.h>
+#endif /* HAVE_MEMBERSHIP_H */
 
 
 /*
 
 static cupsd_authmask_t        *add_allow(cupsd_location_t *loc);
 static cupsd_authmask_t        *add_deny(cupsd_location_t *loc);
+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]);
 #if HAVE_LIBPAM
 static int             pam_func(int, const struct pam_message **,
                                 struct pam_response **, void *);
@@ -110,7 +120,7 @@ typedef struct cupsd_authdata_s             /**** Authentication data ****/
  */
 
 #if defined(__hpux) && defined(HAVE_LIBPAM)
-static cupsd_authdata_t        *auth_datat;    /* Current client being authenticated */
+static cupsd_authdata_t        *auth_data    /* Current client being authenticated */
 #endif /* __hpux && HAVE_LIBPAM */
 
 
@@ -125,30 +135,32 @@ cupsdAddLocation(const char *location)    /* I - Location path */
 
 
  /*
-  * Try to allocate memory for the new location.
+  * Make sure the locations array is created...
   */
 
-  if (NumLocations == 0)
-    temp = malloc(sizeof(cupsd_location_t));
-  else
-    temp = realloc(Locations, sizeof(cupsd_location_t) * (NumLocations + 1));
+  if (!Locations)
+    Locations = cupsArrayNew((cups_array_func_t)compare_locations, NULL);
 
-  if (temp == NULL)
+  if (!Locations)
     return (NULL);
 
-  Locations = temp;
-  temp      += NumLocations;
-  NumLocations ++;
+ /*
+  * Try to allocate memory for the new location.
+  */
+
+  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
+    return (NULL);
 
  /*
   * Initialize the record and copy the name over...
   */
 
-  memset(temp, 0, sizeof(cupsd_location_t));
-  strlcpy(temp->location, location, sizeof(temp->location));
-  temp->length = strlen(temp->location);
+  temp->location = strdup(location);
+  temp->length   = strlen(temp->location);
+
+  cupsArrayAdd(Locations, temp);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddLocation: added location \'%s\'",
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: added location \'%s\'",
                   location);
 
  /*
@@ -181,7 +193,7 @@ cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
   if (temp == NULL)
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add name to location %s: %s",
-                    loc->location, strerror(errno));
+                    loc->location ? loc->location : "nil", strerror(errno));
     return;
   }
 
@@ -191,7 +203,7 @@ cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "Unable to duplicate name for location %s: %s",
-                    loc->location, strerror(errno));
+                    loc->location ? loc->location : "nil", strerror(errno));
     return;
   }
 
@@ -213,12 +225,12 @@ cupsdAllowHost(cupsd_location_t *loc,     /* I - Location to add to */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAllowHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location, name);
+                  loc, loc->location ? loc->location : "nil", name);
 
   if ((temp = add_allow(loc)) == NULL)
     return;
 
-  if (strcasecmp(name, "@LOCAL") == 0)
+  if (!strcasecmp(name, "@LOCAL"))
   {
    /*
     * Allow *interface*...
@@ -228,7 +240,7 @@ cupsdAllowHost(cupsd_location_t *loc,       /* I - Location to add to */
     temp->mask.name.name   = strdup("*");
     temp->mask.name.length = 1;
   }
-  else if (strncasecmp(name, "@IF(", 4) == 0)
+  else if (!strncasecmp(name, "@IF(", 4))
   {
    /*
     * Allow *interface*...
@@ -276,9 +288,9 @@ cupsdAllowIP(cupsd_location_t *loc, /* I - Location to add to */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "cupsdAllowIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location, address[0], address[1], address[2],
-                 address[3], netmask[0], netmask[1], netmask[2],
-                 netmask[3]);
+                 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_allow(loc)) == NULL)
     return;
@@ -380,7 +392,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     */
 
     authorization += 5;
-    while (isspace(*authorization))
+    while (isspace(*authorization & 255))
       authorization ++;
 
     if ((localuser = cupsdFindCert(authorization)) != NULL)
@@ -404,7 +416,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
 
 
     authorization += 5;
-    while (isspace(*authorization))
+    while (isspace(*authorization & 255))
       authorization ++;
 
     userlen = sizeof(username);
@@ -470,7 +482,13 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
             strlcpy(data.username, username, sizeof(data.username));
            strlcpy(data.password, password, sizeof(data.password));
 
+#  ifdef __sun
+           pamdata.conv        = (int (*)(int, struct pam_message **,
+                                          struct pam_response **,
+                                          void *))pam_func;
+#  else
            pamdata.conv        = pam_func;
+#  endif /* __sun */
            pamdata.appdata_ptr = &data;
 
 #  ifdef __hpux
@@ -564,7 +582,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
              cupsdLogMessage(CUPSD_LOG_ERROR,
                              "cupsdAuthorize: Unknown username \"%s\"!",
                              username);
-             return (HTTP_UNAUTHORIZED);
+             return;
            }
 
 #  ifdef HAVE_SHADOW_H
@@ -648,7 +666,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
          * Do Basic authentication with the Digest password file...
          */
 
-         if (!cupsdGetMD5Passwd(username, NULL, md5))
+         if (!get_md5_password(username, NULL, md5))
          {
             cupsdLogMessage(CUPSD_LOG_ERROR,
                            "cupsdAuthorize: Unknown MD5 username \"%s\"!",
@@ -719,7 +737,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     * Validate the username and password...
     */
 
-    if (!cupsdGetMD5Passwd(username, NULL, md5))
+    if (!get_md5_password(username, NULL, md5))
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
                      "cupsdAuthorize: Unknown MD5 username \"%s\"!",
@@ -900,8 +918,8 @@ cupsdCheckAuth(
 
          if (name_len >= masks->mask.name.length &&
              masks->mask.name.name[0] == '.' &&
-             strcasecmp(name + name_len - masks->mask.name.length,
-                        masks->mask.name.name) == 0)
+             !strcasecmp(name + name_len - masks->mask.name.length,
+                         masks->mask.name.name))
            return (1);
           break;
 
@@ -941,6 +959,11 @@ cupsdCheckGroup(
   int                  i;              /* Looping var */
   struct group         *group;         /* System group info */
   char                 junk[33];       /* MD5 password (not used) */
+#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 */
+#endif /* HAVE_MBR_UID_TO_UUID */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -980,13 +1003,26 @@ cupsdCheckGroup(
   if (user && group && group->gr_gid == 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...
   */
 
-  if (cupsdGetMD5Passwd(username, groupname, junk) != NULL)
+  if (get_md5_password(username, groupname, junk) != NULL)
     return (1);
 
  /*
@@ -1006,19 +1042,11 @@ cupsdCopyLocation(
     cupsd_location_t **loc)            /* IO - Original location */
 {
   int                  i;              /* Looping var */
-  int                  locindex;       /* Index into Locations array */
   cupsd_location_t     *temp;          /* New location */
   char                 location[HTTP_MAX_URI];
                                        /* Location of resource */
 
 
- /*
-  * Add the new location, updating the original location
-  * pointer as needed...
-  */
-
-  locindex = *loc - Locations;
-
  /*
   * Use a local copy of location because cupsdAddLocation may cause
   * this memory to be moved...
@@ -1029,8 +1057,6 @@ cupsdCopyLocation(
   if ((temp = cupsdAddLocation(location)) == NULL)
     return (NULL);
 
-  *loc = Locations + locindex;
-
  /*
   * Copy the information from the original location to the new one.
   */
@@ -1053,7 +1079,8 @@ cupsdCopyLocation(
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "cupsdCopyLocation: Unable to allocate memory for %d names: %s",
                       temp->num_names, strerror(errno));
-      NumLocations --;
+
+      cupsdDeleteLocation(temp);
       return (NULL);
     }
 
@@ -1064,7 +1091,7 @@ cupsdCopyLocation(
                        "cupsdCopyLocation: Unable to copy name \"%s\": %s",
                         (*loc)->names[i], strerror(errno));
 
-       NumLocations --;
+        cupsdDeleteLocation(temp);
        return (NULL);
       }
   }
@@ -1080,7 +1107,7 @@ cupsdCopyLocation(
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s",
                       temp->num_allow, strerror(errno));
-      NumLocations --;
+      cupsdDeleteLocation(temp);
       return (NULL);
     }
 
@@ -1096,7 +1123,7 @@ cupsdCopyLocation(
              cupsdLogMessage(CUPSD_LOG_ERROR,
                              "cupsdCopyLocation: Unable to copy allow name \"%s\": %s",
                              (*loc)->allow[i].mask.name.name, strerror(errno));
-             NumLocations --;
+              cupsdDeleteLocation(temp);
              return (NULL);
            }
            break;
@@ -1118,7 +1145,7 @@ cupsdCopyLocation(
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s",
                       temp->num_deny, strerror(errno));
-      NumLocations --;
+      cupsdDeleteLocation(temp);
       return (NULL);
     }
 
@@ -1134,7 +1161,7 @@ cupsdCopyLocation(
              cupsdLogMessage(CUPSD_LOG_ERROR,
                              "cupsdCopyLocation: Unable to copy deny name \"%s\": %s",
                              (*loc)->deny[i].mask.name.name, strerror(errno));
-             NumLocations --;
+              cupsdDeleteLocation(temp);
              return (NULL);
            }
            break;
@@ -1156,7 +1183,6 @@ cupsdCopyLocation(
 void
 cupsdDeleteAllLocations(void)
 {
-  int                  i;              /* Looping var */
   cupsd_location_t     *loc;           /* Current location */
 
 
@@ -1164,18 +1190,17 @@ cupsdDeleteAllLocations(void)
   * Free all of the allow/deny records first...
   */
 
-  for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
+  for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
+       loc;
+       loc = (cupsd_location_t *)cupsArrayNext(Locations))
     cupsdDeleteLocation(loc);
 
  /*
   * Then free the location array...
   */
 
-  if (NumLocations > 0)
-    free(Locations);
-
-  Locations    = NULL;
-  NumLocations = 0;
+  cupsArrayDelete(Locations);
+  Locations = NULL;
 }
 
 
@@ -1191,6 +1216,8 @@ cupsdDeleteLocation(
   cupsd_authmask_t     *mask;          /* Current mask */
 
 
+  cupsArrayRemove(Locations, loc);
+
   for (i = loc->num_names - 1; i >= 0; i --)
     free(loc->names[i]);
 
@@ -1210,6 +1237,9 @@ cupsdDeleteLocation(
 
   if (loc->num_deny > 0)
     free(loc->deny);
+
+  free(loc->location);
+  free(loc);
 }
 
 
@@ -1228,12 +1258,12 @@ cupsdDenyHost(cupsd_location_t *loc,    /* I - Location to add to */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location, name);
+                  loc, loc->location ? loc->location : "nil", name);
 
   if ((temp = add_deny(loc)) == NULL)
     return;
 
-  if (strcasecmp(name, "@LOCAL") == 0)
+  if (!strcasecmp(name, "@LOCAL"))
   {
    /*
     * Deny *interface*...
@@ -1243,7 +1273,7 @@ cupsdDenyHost(cupsd_location_t *loc,      /* I - Location to add to */
     temp->mask.name.name   = strdup("*");
     temp->mask.name.length = 1;
   }
-  else if (strncasecmp(name, "@IF(", 4) == 0)
+  else if (!strncasecmp(name, "@IF(", 4))
   {
    /*
     * Deny *interface*...
@@ -1291,9 +1321,9 @@ cupsdDenyIP(cupsd_location_t *loc,        /* I - Location to add to */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG,
                   "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location, address[0], address[1], address[2],
-                 address[3], netmask[0], netmask[1], netmask[2],
-                 netmask[3]);
+                 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;
@@ -1312,7 +1342,6 @@ cupsd_location_t *                        /* O - Location that matches */
 cupsdFindBest(const char   *path,      /* I - Resource path */
               http_state_t state)      /* I - HTTP state/request */
 {
-  int                  i;              /* Looping var */
   char                 uri[HTTP_MAX_URI],
                                        /* URI in request... */
                        *uriptr;        /* Pointer into URI */
@@ -1370,10 +1399,12 @@ cupsdFindBest(const char   *path,       /* I - Resource path */
   best    = NULL;
   bestlen = 0;
 
-  for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
+  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->limit);
+                    loc->location ? loc->location : "nil", loc->limit);
 
     if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
     {
@@ -1381,8 +1412,8 @@ cupsdFindBest(const char   *path, /* I - Resource path */
       * Use case-insensitive comparison for queue names...
       */
 
-      if (loc->length > bestlen &&
-          strncasecmp(uri, loc->location, loc->length) == 0 &&
+      if (loc->length > bestlen && loc->location &&
+          !strncasecmp(uri, loc->location, loc->length) &&
          loc->location[0] == '/' &&
          (limit & loc->limit) != 0)
       {
@@ -1396,7 +1427,7 @@ cupsdFindBest(const char   *path, /* I - Resource path */
       * Use case-sensitive comparison for other URIs...
       */
 
-      if (loc->length > bestlen &&
+      if (loc->length > bestlen && loc->location &&
           !strncmp(uri, loc->location, loc->length) &&
          loc->location[0] == '/' &&
          (limit & loc->limit) != 0)
@@ -1425,80 +1456,12 @@ cupsdFindBest(const char   *path,       /* I - Resource path */
 cupsd_location_t *                     /* O - Location that matches */
 cupsdFindLocation(const char *location)        /* I - Connection */
 {
-  int          i;                      /* Looping var */
-
-
- /*
-  * Loop through the list of locations to find a match...
-  */
-
-  for (i = 0; i < NumLocations; i ++)
-    if (!strcasecmp(Locations[i].location, location))
-      return (Locations + i);
-
-  return (NULL);
-}
-
-
-/*
- * 'cupsdGetMD5Passwd()' - Get an MD5 password.
- */
-
-char *                                 /* O - MD5 password string */
-cupsdGetMD5Passwd(const char *username,        /* I - Username */
-                  const char *group,   /* I - Group */
-                  char       passwd[33])/* O - MD5 password string */
-{
-  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,
-                  "cupsdGetMD5Passwd(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) == 0 &&
-        (group == NULL || strcmp(group, tempgroup) == 0))
-    {
-     /*
-      * Found the password entry!
-      */
+  cupsd_location_t     key;            /* Search key */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
-                      username, tempgroup);
 
-      cupsFileClose(fp);
-      return (passwd);
-    }
-  }
+  key.location = (char *)location;
 
- /*
-  * Didn't find a password entry - return NULL!
-  */
-
-  cupsFileClose(fp);
-  return (NULL);
+  return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
 }
 
 
@@ -1557,7 +1520,8 @@ 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",
+                  "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);
 
@@ -1602,7 +1566,7 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
   if (!strcasecmp(con->http.hostname, "localhost"))
   {
    /*
-    * Access from localhost (127.0.0.1 or :::1) is always allowed...
+    * Access from localhost (127.0.0.1 or ::1) is always allowed...
     */
 
     auth = AUTH_ALLOW;
@@ -1656,7 +1620,9 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
   * See if encryption is required...
   */
 
-  if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
+  if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
+      strcasecmp(con->http.hostname, "localhost") &&
+      best->satisfy == AUTH_SATISFY_ALL)
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "cupsdIsAuthorized: Need upgrade to TLS...");
@@ -1889,6 +1855,18 @@ add_deny(cupsd_location_t *loc)          /* I - Location to add to */
 }
 
 
+/*
+ * 'compare_locations()' - Compare two locations.
+ */
+
+static int                             /* O - Result of comparison */
+compare_locations(cupsd_location_t *a, /* I - First location */
+                  cupsd_location_t *b) /* I - Second location */
+{
+  return (strcmp(b->location, a->location));
+}
+
+
 #if !HAVE_LIBPAM
 /*
  * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
@@ -1899,7 +1877,7 @@ static char *                             /* O - Encrypted password */
 cups_crypt(const char *pw,             /* I - Password string */
            const char *salt)           /* I - Salt (key) string */
 {
-  if (strncmp(salt, "$1$", 3) == 0)
+  if (!strncmp(salt, "$1$", 3))
   {
    /*
     * Use MD5 passwords without the benefit of PAM; this is for
@@ -1933,45 +1911,45 @@ cups_crypt(const char *pw,              /* I - Password string */
 
     pwlen = strlen(pw);
 
-    _cups_md5_init(&state);
-    _cups_md5_append(&state, (unsigned char *)pw, pwlen);
-    _cups_md5_append(&state, (unsigned char *)salt, salt_end - salt);
+    _cupsMD5Init(&state);
+    _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
+    _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
 
-    _cups_md5_init(&state2);
-    _cups_md5_append(&state2, (unsigned char *)pw, pwlen);
-    _cups_md5_append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
-    _cups_md5_append(&state2, (unsigned char *)pw, pwlen);
-    _cups_md5_finish(&state2, digest);
+    _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)
-      _cups_md5_append(&state, digest, i > 16 ? 16 : i);
+      _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
 
     for (i = pwlen; i > 0; i >>= 1)
-      _cups_md5_append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
+      _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
 
-    _cups_md5_finish(&state, digest);
+    _cupsMD5Finish(&state, digest);
 
     for (i = 0; i < 1000; i ++)
     {
-      _cups_md5_init(&state);
+      _cupsMD5Init(&state);
 
       if (i & 1)
-        _cups_md5_append(&state, (unsigned char *)pw, pwlen);
+        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
       else
-        _cups_md5_append(&state, digest, 16);
+        _cupsMD5Append(&state, digest, 16);
 
       if (i % 3)
-        _cups_md5_append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
+        _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
 
       if (i % 7)
-        _cups_md5_append(&state, (unsigned char *)pw, pwlen);
+        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
 
       if (i & 1)
-        _cups_md5_append(&state, digest, 16);
+        _cupsMD5Append(&state, digest, 16);
       else
-        _cups_md5_append(&state, (unsigned char *)pw, pwlen);
+        _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
 
-      _cups_md5_finish(&state, digest);
+      _cupsMD5Finish(&state, digest);
     }
 
    /*
@@ -2012,6 +1990,68 @@ cups_crypt(const char *pw,               /* I - Password string */
 #endif /* !HAVE_LIBPAM */
 
 
+/*
+ * 'get_md5_password()' - Get an MD5 password.
+ */
+
+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 */
+{
+  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!
+      */
+
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
+                      username, tempgroup);
+
+      cupsFileClose(fp);
+      return (passwd);
+    }
+  }
+
+ /*
+  * Didn't find a password entry - return NULL!
+  */
+
+  cupsFileClose(fp);
+  return (NULL);
+}
+
+
 #if HAVE_LIBPAM
 /*
  * 'pam_func()' - PAM conversation function.
@@ -2127,5 +2167,5 @@ to64(char          *s,                    /* O - Output string */
 
 
 /*
- * End of "$Id: auth.c 5043 2006-02-01 18:55:16Z mike $".
+ * End of "$Id: auth.c 5464 2006-04-26 01:34:14Z mike $".
  */