]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/auth.c
Import CUPS 1.4svn-r7226.
[thirdparty/cups.git] / scheduler / auth.c
index 3f5f724788078e3a5fa41e0e622b2cf41ec8c602..5b2dd3e9632fff42d1147f58fdabf040cceb4cf6 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: auth.c 6949 2007-09-12 21:33:23Z mike $"
+ * "$Id: auth.c 6947 2007-09-12 21:09:49Z mike $"
  *
  *   Authorization routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2008 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   This file contains Kerberos support code, copyright 2006 by
  *   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.
+ *   cupsdCheckAccess()        - Check whether the given address is allowed to
+ *                               access a location.
  *   cupsdCheckAuth()          - Check authorization masks.
  *   cupsdCheckGroup()         - Check for a user's group membership.
  *   cupsdCopyLocation()       - Make a copy of a location...
@@ -40,6 +42,8 @@
  *   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.
+ *   check_authref()           - Check if an authorization services reference
+ *                               has the supplied right.
  *   compare_locations()       - Compare two locations.
  *   cups_crypt()              - Encrypt the password using the DES or MD5
  *                               algorithms, as needed.
@@ -47,7 +51,6 @@
  *   get_md5_password()        - Get an MD5 password.
  *   pam_func()                - PAM conversation function.
  *   to64()                    - Base64-encode an integer value...
- *   check_authref()           - Check an authorization services reference.
  */
 
 /*
@@ -176,8 +179,13 @@ cupsdAddLocation(const char *location)     /* I - Location path */
   * Initialize the record and copy the name over...
   */
 
-  temp->location = strdup(location);
-  temp->length   = strlen(temp->location);
+  if ((temp->location = strdup(location)) == NULL)
+  {
+    free(temp);
+    return (NULL);
+  }
+
+  temp->length = strlen(temp->location);
 
   cupsArrayAdd(Locations, temp);
 
@@ -363,6 +371,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
   */
 
   con->best = cupsdFindBest(con->uri, con->http.state);
+  con->type = AUTH_NONE;
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "cupsdAuthorize: con->uri=\"%s\", con->best=%p(%s)",
@@ -398,17 +407,7 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
   }
 #endif /* HAVE_AUTHORIZATION_H */
 
-  if (type == AUTH_NONE)
-  {
-   /*
-    * No authorization required, return early...
-    */
-
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdAuthorize: No authentication required.");
-    return;
-  }
-  else if (!*authorization)
+  if (!*authorization)
   {
    /*
     * No authorization data provided, return early...
@@ -471,6 +470,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
                    username);
 
     AuthorizationFreeItemSet(authinfo);
+
+    con->type = AUTH_BASIC;
   }
 #endif /* HAVE_AUTHORIZATION_H */
 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
@@ -526,6 +527,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     cupsdLogMessage(CUPSD_LOG_DEBUG,
                     "cupsdAuthorize: Authorized as %s using PeerCred",
                    username);
+
+    con->type = AUTH_BASIC;
   }
 #endif /* SO_PEERCRED && AF_LOCAL */
   else if (!strncmp(authorization, "Local", 5) &&
@@ -554,9 +557,10 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
                      "found!");
       return;
     }
+
+    con->type = AUTH_BASIC;
   }
-  else if (!strncmp(authorization, "Basic", 5) &&
-           (type == AUTH_BASIC || type == AUTH_BASICDIGEST))
+  else if (!strncmp(authorization, "Basic", 5))
   {
    /*
     * Get the Basic authentication data...
@@ -615,6 +619,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
 
     switch (type)
     {
+      default :
       case AUTH_BASIC :
           {
 #if HAVE_LIBPAM
@@ -660,6 +665,14 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
              return;
            }
 
+#  if defined(HAVE_PAM_SET_ITEM) && defined(PAM_RHOST)
+           pamerr = pam_set_item(pamh, PAM_RHOST, con->http.hostname);
+           if (pamerr != PAM_SUCCESS)
+             cupsdLogMessage(CUPSD_LOG_WARN,
+                             "cupsdAuthorize: pam_set_item() returned %d "
+                             "(%s)!\n", pamerr, pam_strerror(pamh, pamerr));
+#  endif /* HAVE_PAM_SET_ITEM && PAM_RHOST */
+
            pamerr = pam_authenticate(pamh, PAM_SILENT);
            if (pamerr != PAM_SUCCESS)
            {
@@ -842,8 +855,10 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
                          username);
          break;
     }
+
+    con->type = type;
   }
-  else if (!strncmp(authorization, "Digest", 6) && type == AUTH_DIGEST)
+  else if (!strncmp(authorization, "Digest", 6))
   {
    /*
     * Get the username, password, and nonce from the Digest attributes...
@@ -915,6 +930,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     cupsdLogMessage(CUPSD_LOG_DEBUG,
                     "cupsdAuthorize: Authorized as %s using Digest",
                    username);
+
+    con->type = AUTH_DIGEST;
   }
 #ifdef HAVE_GSSAPI
   else if (!strncmp(authorization, "Negotiate", 9)) 
@@ -1054,30 +1071,23 @@ cupsdAuthorize(cupsd_client_t *con)     /* I - Client connection */
       gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
 
       con->gss_have_creds = 1;
+
+      con->type = AUTH_NEGOTIATE;
     }
     else
       gss_release_name(&minor_status, &client_name);
   }
 #endif /* HAVE_GSSAPI */
-  else if (type != AUTH_NONE)
+  else
   {
     char       scheme[256];            /* Auth scheme... */
-    static const char * const types[] =        /* Auth types */
-    {
-      "None",
-      "Basic",
-      "Digest",
-      "BasicDigest",
-      "Negotiate"
-    };
 
 
     if (sscanf(authorization, "%255s", scheme) != 1)
       strcpy(scheme, "UNKNOWN");
 
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "Bad authentication data \"%s ...\", expected \"%s ...\"",
-                    scheme, types[type]);
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\"",
+                    scheme);
     return;
   }
 
@@ -1092,6 +1102,67 @@ cupsdAuthorize(cupsd_client_t *con)      /* I - Client connection */
 }
 
 
+/*
+ * '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 */
+    char             *name,            /* I - Client hostname */
+    int              namelen,          /* I - Length of hostname */
+    cupsd_location_t *loc)             /* I - Location to check */
+{
+  int  allow;                          /* 1 if allowed, 0 otherwise */
+
+
+  if (!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 AUTH_ALLOW : /* Order Deny,Allow */
+          allow = 1;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
+           allow = 0;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
+           allow = 1;
+         break;
+
+      case AUTH_DENY : /* Order Allow,Deny */
+          allow = 0;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
+           allow = 1;
+
+          if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
+           allow = 0;
+         break;
+    }
+  }
+
+  return (allow);
+}
+
+
 /*
  * 'cupsdCheckAuth()' - Check authorization masks.
  */
@@ -1793,7 +1864,8 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
                   const char     *owner)/* I - Owner of object */
 {
   int                  i, j,           /* Looping vars */
-                       auth;           /* Authorization status */
+                       auth,           /* Authorization status */
+                       type;           /* Type of authentication */
   unsigned             address[4];     /* Authorization address */
   cupsd_location_t     *best;          /* Best match for location so far */
   int                  hostlen;        /* Length of hostname */
@@ -1809,11 +1881,11 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
                };
   static const char * const types[] =  /* Auth types */
                {
-                 "NONE",
-                 "BASIC",
-                 "DIGEST",
-                 "BASICDIGEST",
-                 "KERBEROS"
+                 "None",
+                 "Basic",
+                 "Digest",
+                 "BasicDigest",
+                 "Negotiate"
                };
 
 
@@ -1842,10 +1914,13 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
 
   best = con->best;
 
+  if ((type = best->type) == AUTH_DEFAULT)
+    type = DefaultAuthType;
+
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdIsAuthorized: level=AUTH_%s, type=AUTH_%s, "
+                  "cupsdIsAuthorized: level=AUTH_%s, type=%s, "
                  "satisfy=AUTH_SATISFY_%s, num_names=%d",
-                  levels[best->level], types[best->type],
+                  levels[best->level], types[type],
                  best->satisfy ? "ANY" : "ALL", best->num_names);
 
   if (best->limit == AUTH_LIMIT_IPP)
@@ -1886,51 +1961,8 @@ cupsdIsAuthorized(cupsd_client_t *con,   /* I - Connection */
 
   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;
-
-          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, con->http.hostname, hostlen, best)
+             ? AUTH_ALLOW : AUTH_DENY;
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=AUTH_%s...",
                   auth ? "DENY" : "ALLOW");
@@ -1946,8 +1978,8 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
   if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
       strcasecmp(con->http.hostname, "localhost") &&
       best->satisfy == AUTH_SATISFY_ALL) &&
-      !(best->type == AUTH_NEGOTIATE || 
-        (best->type == AUTH_NONE && DefaultAuthType == AUTH_NEGOTIATE)))
+      !(type == AUTH_NEGOTIATE || 
+        (type == AUTH_NONE && DefaultAuthType == AUTH_NEGOTIATE)))
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
                     "cupsdIsAuthorized: Need upgrade to TLS...");
@@ -1960,10 +1992,10 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
   */
 
   if (best->level == AUTH_ANON ||      /* Anonymous access - allow it */
-      (best->type == AUTH_NONE && best->num_names == 0))
+      (type == AUTH_NONE && best->num_names == 0))
     return (HTTP_OK);
 
-  if (!con->username[0] && best->type == AUTH_NONE &&
+  if (!con->username[0] && type == AUTH_NONE &&
       best->limit == AUTH_LIMIT_IPP)
   {
    /*
@@ -2003,6 +2035,15 @@ cupsdIsAuthorized(cupsd_client_t *con,   /* I - Connection */
        return (HTTP_OK);               /* unless overridden with Satisfy */
     }
 
+    if (con->type != type && type != AUTH_NONE &&
+        (con->type != AUTH_BASIC || type != AUTH_BASICDIGEST))
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s!",
+                      types[con->type], types[type]);
+
+      return (HTTP_UNAUTHORIZED);
+    }
+
     strlcpy(username, con->username, sizeof(username));
   }
 
@@ -2668,5 +2709,5 @@ to64(char          *s,                    /* O - Output string */
 
 
 /*
- * End of "$Id: auth.c 6949 2007-09-12 21:33:23Z mike $".
+ * End of "$Id: auth.c 6947 2007-09-12 21:09:49Z mike $".
  */