]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Support the latest HTTP Digest authentication specification (Issue #4862)
authorMichael R Sweet <michaelrsweet@gmail.com>
Mon, 6 Nov 2017 21:19:27 +0000 (16:19 -0500)
committerMichael R Sweet <michaelrsweet@gmail.com>
Mon, 6 Nov 2017 21:28:31 +0000 (16:28 -0500)
Also deprecates all httpMD5* functions.

- cgi-bin/var.c: Use cupsHashData to compute SID hash.
- cups/auth.c: Rewrite WWW-Authenticate parser to support multiple auth schemes
  and the new RFC 7616 version of HTTP Digest.
- cups/cups.h: Add cupsHashString function to get a hex version of a hash.
- cups/hash.c: Add MD5 support.
- cups/http.c: Track WWW-Authenticate in a long string, concatenate new set
  values.
- cups/http.h: Deprecate httpMD5* and recommend cupsDoAuth and cupsHash*.
- cups/http-private.h: Pull MD5 stuff, nonce_count is unsigned, track
  WWW-Authenticate header as a potentially long string.
- cups/http-support.c: Use cupsHashData to compute UUID hash.
- cups/md5.c: Comment everything out if we have an OS-supplied MD5 hash
  function.
- cups/md5passwd.c: Use cupsHash* functions.
- cups/tls-*.c: Use cupsHash* functions.
- cups/versioning.h: Add CUPS_API_2_3 definition.
- scheduler/client.c: Update WWW-Authenticate header to include AuthRef,
  Local, and PeerCred schemes with parameters as needed.

16 files changed:
CHANGES.md
cgi-bin/var.c
cups/auth.c
cups/cups.h
cups/hash.c
cups/http-private.h
cups/http-support.c
cups/http.c
cups/http.h
cups/md5.c
cups/md5passwd.c
cups/tls-darwin.c
cups/tls-gnutls.c
cups/tls-sspi.c
cups/versioning.h
scheduler/client.c

index ec88104c6a61dd8d6ad415770553ae5696ded8b4..4c3325fe9d6ff1fd7ab3ecaf3cf82d2c5e3bb631 100644 (file)
@@ -1,4 +1,4 @@
-CHANGES - 2.3b1 - 2017-11-03
+CHANGES - 2.3b1 - 2017-11-06
 ============================
 
 
@@ -7,6 +7,8 @@ Changes in CUPS v2.3b1
 
 - Documentation updates (Issue #4580)
 - The `lpstat` command now reports when new jobs are being held (Issue #4761)
+- The CUPS library now supports the latest HTTP Digest authentication
+  specification including support for SHA-256 (Issue #4862)
 - The scheduler now supports the "printer-id" attribute (Issue #4868)
 - No longer support backslash, question mark, or quotes in printer names
   (Issue #4966)
index c50833cbd85701bdda0db691c2fec752f7d9cfbd..649b65ba9a81f7611c70a7e866a1fbe1f3fe3f5d 100644 (file)
@@ -18,7 +18,6 @@
 /*#define DEBUG*/
 #include "cgi-private.h"
 #include <cups/http.h>
-#include <cups/md5-private.h>
 
 
 /*
@@ -1204,7 +1203,6 @@ cgi_set_sid(void)
 {
   char                 buffer[512],    /* SID data */
                        sid[33];        /* SID string */
-  _cups_md5_state_t    md5;            /* MD5 state */
   unsigned char                sum[16];        /* MD5 sum */
   const char           *remote_addr,   /* REMOTE_ADDR */
                        *server_name,   /* SERVER_NAME */
@@ -1225,11 +1223,9 @@ cgi_set_sid(void)
           (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
           (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
           (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255);
-  _cupsMD5Init(&md5);
-  _cupsMD5Append(&md5, (unsigned char *)buffer, (int)strlen(buffer));
-  _cupsMD5Finish(&md5, sum);
+  cupsHashData("md5", (unsigned char *)buffer, strlen(buffer), sum, sizeof(sum));
 
-  cgiSetCookie(CUPS_SID, httpMD5String(sum, sid), "/", NULL, 0, 0);
+  cgiSetCookie(CUPS_SID, cupsHashString(sum, sizeof(sum), sid, sizeof(sid)), "/", NULL, 0, 0);
 
   return (cupsGetOption(CUPS_SID, num_cookies, cookies));
 }
index c051c86ba81e840e6f7a932dd7fe8ad9c6735ffc..7e14939f378fd13be4f19b9f9d70ebd5ef23ccf5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Authentication functions for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products.
  *
  * This file contains Kerberos support code, copyright 2006 by
@@ -47,6 +47,10 @@ extern const char *cssmErrorString(int error);
  * Local functions...
  */
 
+static const char      *cups_auth_find(const char *www_authenticate, const char *scheme);
+static const char      *cups_auth_param(const char *scheme, const char *name, char *value, size_t valsize);
+static const char      *cups_auth_scheme(const char *www_authenticate, char *scheme, size_t schemesize);
+
 #ifdef HAVE_GSSAPI
 #  ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
 #    ifdef HAVE_GSS_GSSAPI_SPI_H
@@ -112,8 +116,10 @@ cupsDoAuthentication(
     const char *resource)              /* I - Resource path */
 {
   const char   *password,              /* Password string */
-               *www_auth;              /* WWW-Authenticate header */
-  char         prompt[1024],           /* Prompt for user */
+               *www_auth,              /* WWW-Authenticate header */
+               *schemedata;            /* Scheme-specific data */
+  char         scheme[256],            /* Scheme name */
+               prompt[1024],           /* Prompt for user */
                realm[HTTP_MAX_VALUE],  /* realm="xyz" string */
                nonce[HTTP_MAX_VALUE];  /* nonce="xyz" string */
   int          localauth;              /* Local authentication result */
@@ -163,122 +169,237 @@ cupsDoAuthentication(
   }
 
  /*
-  * Nope, see if we should retry the current username:password...
+  * Nope, loop through the authentication schemes to find the first we support.
   */
 
-  www_auth = http->fields[HTTP_FIELD_WWW_AUTHENTICATE];
+  www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
 
-  if ((http->digest_tries > 1 || !http->userpass[0]) &&
-      (!_cups_strncasecmp(www_auth, "Basic", 5) ||
-       !_cups_strncasecmp(www_auth, "Digest", 6)))
+  for (schemedata = cups_auth_scheme(www_auth, scheme, sizeof(scheme)); schemedata; schemedata = cups_auth_scheme(schemedata + strlen(scheme), scheme, sizeof(scheme)))
   {
    /*
-    * Nope - get a new password from the user...
+    * Check the scheme name...
     */
 
-    char default_username[HTTP_MAX_VALUE];
-                                       /* Default username */
+#ifdef HAVE_GSSAPI
+    if (!_cups_strcasecmp(scheme, "Negotiate"))
+    {
+     /*
+      * Kerberos authentication...
+      */
 
-    cg = _cupsGlobals();
+      if (_cupsSetNegotiateAuthString(http, method, resource))
+      {
+       http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
+       return (-1);
+      }
 
-    if (!cg->lang_default)
-      cg->lang_default = cupsLangDefault();
+      break;
+    }
+    else
+#endif /* HAVE_GSSAPI */
+    if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest"))
+      continue;                                /* Not supported (yet) */
 
-    if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username",
-                        default_username))
-      cupsSetUser(default_username);
+   /*
+    * See if we should retry the current username:password...
+    */
 
-    snprintf(prompt, sizeof(prompt),
-             _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
-            cupsUser(),
-            http->hostname[0] == '/' ? "localhost" : http->hostname);
+    if ((http->digest_tries > 1 || !http->userpass[0]) && (!_cups_strcasecmp(scheme, "Basic") || (!_cups_strcasecmp(scheme, "Digest"))))
+    {
+     /*
+      * Nope - get a new password from the user...
+      */
 
-    http->digest_tries  = _cups_strncasecmp(www_auth, "Digest", 6) != 0;
-    http->userpass[0]   = '\0';
+      char default_username[HTTP_MAX_VALUE];
+                                       /* Default username */
 
-    if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
-    {
-      http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
-      return (-1);
-    }
+      cg = _cupsGlobals();
 
-    snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(),
-             password);
-  }
-  else if (http->status == HTTP_STATUS_UNAUTHORIZED)
-    http->digest_tries ++;
+      if (!cg->lang_default)
+       cg->lang_default = cupsLangDefault();
 
-  if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3)
-  {
-    DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)",
-                 http->digest_tries));
+      if (cups_auth_param(scheme, "username", default_username, sizeof(default_username)))
+       cupsSetUser(default_username);
 
-    http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
-    return (-1);
-  }
+      snprintf(prompt, sizeof(prompt), _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), cupsUser(), http->hostname[0] == '/' ? "localhost" : http->hostname);
 
- /*
-  * Got a password; encode it for the server...
-  */
+      http->digest_tries  = _cups_strncasecmp(scheme, "Digest", 6) != 0;
+      http->userpass[0]   = '\0';
 
-#ifdef HAVE_GSSAPI
-  if (!_cups_strncasecmp(www_auth, "Negotiate", 9))
-  {
-   /*
-    * Kerberos authentication...
-    */
+      if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
+      {
+       http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
+       return (-1);
+      }
 
-    if (_cupsSetNegotiateAuthString(http, method, resource))
+      snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), password);
+    }
+    else if (http->status == HTTP_STATUS_UNAUTHORIZED)
+      http->digest_tries ++;
+
+    if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3)
     {
+      DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)", http->digest_tries));
+
       http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
       return (-1);
     }
-  }
-  else
-#endif /* HAVE_GSSAPI */
-  if (!_cups_strncasecmp(www_auth, "Basic", 5))
-  {
+
    /*
-    * Basic authentication...
+    * Got a password; encode it for the server...
     */
 
-    char       encode[256];            /* Base64 buffer */
+    if (!_cups_strcasecmp(scheme, "Basic"))
+    {
+     /*
+      * Basic authentication...
+      */
 
+      char     encode[256];            /* Base64 buffer */
 
-    httpEncode64_2(encode, sizeof(encode), http->userpass,
-                   (int)strlen(http->userpass));
-    httpSetAuthString(http, "Basic", encode);
-  }
-  else if (!_cups_strncasecmp(www_auth, "Digest", 6))
-  {
-   /*
-    * Digest authentication...
-    */
+      httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass));
+      httpSetAuthString(http, "Basic", encode);
+    }
+    else if (!_cups_strcasecmp(scheme, "Digest"))
+    {
+     /*
+      * Digest authentication...
+      */
+
+      int              i;              /* Looping var */
+      char             algorithm[65],  /* Hashing algorithm */
+                       opaque[HTTP_MAX_VALUE],
+                                       /* Opaque data from server */
+                       cnonce[65],     /* cnonce value */
+                       kd[65],         /* Final MD5/SHA-256 digest */
+                       ha1[65],        /* Hash of username:realm:password */
+                       ha2[65],        /* Hash of method:request-uri */
+                       hdata[65],      /* Hash of auth data */
+                       temp[1024],     /* Temporary string */
+                       digest[1024];   /* Digest auth data */
+      unsigned char    hash[32];       /* Hash buffer */
+      const char       *hashalg;       /* Hashing algorithm */
+      size_t           hashsize;       /* Size of hash */
+
+      if (strcmp(nonce, http->nonce))
+      {
+        strlcpy(http->nonce, nonce, sizeof(http->nonce));
+        http->nonce_count = 1;
+      }
+      else
+        http->nonce_count ++;
 
-    char       encode[33],             /* MD5 buffer */
-               digest[1024];           /* Digest auth data */
+      cups_auth_param(schemedata, "opaque", opaque, sizeof(opaque));
+      cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce));
+      cups_auth_param(schemedata, "realm", realm, sizeof(realm));
 
-    httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
-    httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
+      for (i = 0; i < 64; i ++)
+        cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15];
+      cnonce[64] = '\0';
 
-    httpMD5(cupsUser(), realm, strchr(http->userpass, ':') + 1, encode);
-    httpMD5Final(nonce, method, resource, encode);
-    snprintf(digest, sizeof(digest),
-            "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
-            "response=\"%s\"", cupsUser(), realm, nonce, resource, encode);
-    httpSetAuthString(http, "Digest", digest);
+      if (cups_auth_param(schemedata, "algorithm", algorithm, sizeof(algorithm)))
+      {
+       /*
+        * Follow RFC 2617/7616...
+        */
+
+        if (!_cups_strcasecmp(algorithm, "MD5"))
+        {
+         /*
+          * RFC 2617 Digest with MD5
+          */
+
+          hashalg = "md5";
+       }
+       else if (!_cups_strcasecmp(algorithm, "SHA-256"))
+       {
+        /*
+         * RFC 7616 Digest with SHA-256
+         */
+
+          hashalg = "sha2-256";
+       }
+       else
+       {
+        /*
+         * Some other algorithm we don't support, skip this one...
+         */
+
+         continue;
+       }
+
+       /*
+        * Calculate digest value...
+        */
+
+        /* H(A1) = H(username:realm:password) */
+        snprintf(temp, sizeof(temp), "%s:%s:%s", cupsUser(), realm, strchr(http->userpass, ':') + 1);
+        hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, ha1, sizeof(ha1));
+
+        /* H(A2) = H(method:uri) */
+       snprintf(temp, sizeof(temp), "%s:%s", method, resource);
+        hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, ha2, sizeof(ha2));
+
+        /* H(data) = H(nonce:nc:cnonce:qop:H(A2)) */
+       snprintf(temp, sizeof(temp), "%s:%08x:%s:auth:%s", nonce, http->nonce_count, cnonce, ha2);
+        hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, hdata, sizeof(hdata));
+
+        /* KD = H(H(A1):H(data)) */
+       snprintf(temp, sizeof(temp), "%s:%s", ha1, hdata);
+        hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, kd, sizeof(kd));
+
+        /* Pass the RFC 2617/7616 WWW-Authenticate header */
+        if (opaque[0])
+         snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, opaque, cnonce, http->nonce_count, resource, kd);
+       else
+         snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, cnonce, http->nonce_count, resource, kd);
+      }
+      else
+      {
+       /*
+        * Use old RFC 2069 Digest method...
+        */
+
+        /* H(A1) = H(username:realm:password) */
+        snprintf(temp, sizeof(temp), "%s:%s:%s", cupsUser(), realm, strchr(http->userpass, ':') + 1);
+        hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, ha1, sizeof(ha1));
+
+        /* H(A2) = H(method:uri) */
+       snprintf(temp, sizeof(temp), "%s:%s", method, resource);
+        hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, ha2, sizeof(ha2));
+
+        /* KD = H(H(A1):nonce:H(A2)) */
+       snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, nonce, ha2);
+       hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
+       cupsHashString(hash, hashsize, kd, sizeof(kd));
+
+        /* Pass the RFC 2069 WWW-Authenticate header */
+       snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, resource, kd);
+      }
+
+      httpSetAuthString(http, "Digest", digest);
+    }
+  }
+
+  if (http->authstring)
+  {
+    DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));
+
+    return (0);
   }
   else
   {
-    DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"",
-                  www_auth));
+    DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"", www_auth));
     http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
+
     return (-1);
   }
-
-  DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));
-
-  return (0);
 }
 
 
@@ -466,6 +587,227 @@ _cupsSetNegotiateAuthString(
 }
 
 
+/*
+ * 'cups_auth_find()' - Find the named WWW-Authenticate scheme.
+ *
+ * The "www_authenticate" parameter points to the current position in the header.
+ *
+ * Returns @code NULL@ if the auth scheme is not present.
+ */
+
+static const char *                            /* O - Start of matching scheme or @code NULL@ if not found */
+cups_auth_find(const char *www_authenticate,   /* I - Pointer into WWW-Authenticate header */
+               const char *scheme)             /* I - Authentication scheme */
+{
+  size_t       schemelen = strlen(scheme);     /* Length of scheme */
+
+
+  while (*www_authenticate)
+  {
+   /*
+    * Skip leading whitespace and commas...
+    */
+
+    while (isspace(*www_authenticate & 255) || *www_authenticate == ',')
+      www_authenticate ++;
+
+   /*
+    * See if this is "Scheme" followed by whitespace or the end of the string.
+    */
+
+    if (!strncmp(www_authenticate, scheme, schemelen) && (isspace(www_authenticate[schemelen] & 255) || !www_authenticate[schemelen]))
+    {
+     /*
+      * Yes, this is the start of the scheme-specific information...
+      */
+
+      return (www_authenticate);
+    }
+
+   /*
+    * Skip the scheme name or param="value" string...
+    */
+
+    while (!isspace(*www_authenticate & 255) && *www_authenticate)
+    {
+      if (*www_authenticate == '\"')
+      {
+       /*
+        * Skip quoted value...
+        */
+
+        while (www_authenticate[1] && www_authenticate[1] != '\"')
+          www_authenticate ++;
+      }
+
+      www_authenticate ++;
+    }
+  }
+
+  return (NULL);
+}
+
+
+/*
+ * 'cups_auth_param()' - Copy the value for the named authentication parameter,
+ *                       if present.
+ */
+
+static const char *                            /* O - Parameter value or @code NULL@ if not present */
+cups_auth_param(const char *scheme,            /* I - Pointer to auth data */
+                const char *name,              /* I - Name of parameter */
+                char       *value,             /* I - Value buffer */
+                size_t     valsize)            /* I - Size of value buffer */
+{
+  char         *valptr = value,                /* Pointer into value buffer */
+               *valend = value + valsize - 1;  /* Pointer to end of buffer */
+  size_t       namelen = strlen(name);         /* Name length */
+  int          param;                          /* Is this a parameter? */
+
+
+  while (!isspace(*scheme & 255) && *scheme)
+    scheme ++;
+
+  while (*scheme)
+  {
+    while (isspace(*scheme & 255) || *scheme == ',')
+      scheme ++;
+
+    if (!strncmp(scheme, name, namelen) && scheme[namelen] == '=')
+    {
+     /*
+      * Found the parameter, copy the value...
+      */
+
+      scheme += namelen + 1;
+      if (*scheme == '\"')
+      {
+        scheme ++;
+
+       while (*scheme && *scheme != '\"')
+       {
+         if (valptr < valend)
+           *valptr++ = *scheme;
+
+         scheme ++;
+       }
+      }
+      else
+      {
+       while (*scheme && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~+/=", *scheme))
+       {
+         if (valptr < valend)
+           *valptr++ = *scheme;
+
+         scheme ++;
+       }
+      }
+
+      *valptr = '\0';
+
+      return (value);
+    }
+
+   /*
+    * Skip the param=value string...
+    */
+
+    param = 0;
+
+    while (!isspace(*scheme & 255) && *scheme)
+    {
+      if (*scheme == '=')
+        param = 1;
+      else if (*scheme == '\"')
+      {
+       /*
+        * Skip quoted value...
+        */
+
+        while (scheme[1] && scheme[1] != '\"')
+          scheme ++;
+      }
+
+      scheme ++;
+    }
+
+   /*
+    * If this wasn't a parameter, we are at the end of this scheme's
+    * parameters...
+    */
+
+    if (!param)
+      break;
+  }
+
+  *value = '\0';
+
+  return (NULL);
+}
+
+
+/*
+ * 'cups_auth_scheme()' - Get the (next) WWW-Authenticate scheme.
+ *
+ * The "www_authenticate" parameter points to the current position in the header.
+ *
+ * Returns @code NULL@ if there are no (more) auth schemes present.
+ */
+
+static const char *                            /* O - Start of scheme or @code NULL@ if not found */
+cups_auth_scheme(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */
+                char       *scheme,            /* I - Scheme name buffer */
+                size_t     schemesize)         /* I - Size of buffer */
+{
+  const char   *start;                         /* Start of scheme data */
+  char         *sptr = scheme,                 /* Pointer into scheme buffer */
+               *send = scheme + schemesize - 1;/* End of scheme buffer */
+  int          param;                          /* Is this a parameter? */
+
+
+  while (*www_authenticate)
+  {
+   /*
+    * Skip leading whitespace and commas...
+    */
+
+    while (isspace(*www_authenticate & 255) || *www_authenticate == ',')
+      www_authenticate ++;
+
+   /*
+    * Parse the scheme name or param="value" string...
+    */
+
+    for (sptr = scheme, start = www_authenticate, param = 0; *www_authenticate && !isspace(*www_authenticate & 255); www_authenticate ++)
+    {
+      if (*www_authenticate == '=')
+        param = 1;
+      else if (!param && sptr < send)
+        *sptr++ = *www_authenticate;
+      else if (*www_authenticate == '\"')
+      {
+       /*
+        * Skip quoted value...
+        */
+
+        while (www_authenticate[1] && www_authenticate[1] != '\"')
+          www_authenticate ++;
+      }
+    }
+
+    if (sptr > scheme && !param)
+    {
+      *sptr = '\0';
+      return (start);
+    }
+  }
+
+  *scheme = '\0';
+
+  return (NULL);
+}
+
+
 #  ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
 /*
  * 'cups_gss_acquire()' - Kerberos credentials callback.
@@ -650,6 +992,8 @@ cups_local_auth(http_t *http)               /* I - HTTP connection to server */
   FILE                 *fp;            /* Certificate file */
   char                 trc[16],        /* Try Root Certificate parameter */
                        filename[1024]; /* Certificate filename */
+  const char           *www_auth,      /* WWW-Authenticate header */
+                       *schemedata;    /* Data for the named auth scheme */
   _cups_globals_t *cg = _cupsGlobals();        /* Global data */
 #  if defined(HAVE_AUTHORIZATION_H)
   OSStatus             status;         /* Status */
@@ -668,8 +1012,7 @@ cups_local_auth(http_t *http)              /* I - HTTP connection to server */
   * See if we are accessing localhost...
   */
 
-  if (!httpAddrLocalhost(http->hostaddr) &&
-      _cups_strcasecmp(http->hostname, "localhost") != 0)
+  if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0)
   {
     DEBUG_puts("8cups_local_auth: Not a local connection!");
     return (1);
@@ -686,12 +1029,11 @@ cups_local_auth(http_t *http)            /* I - HTTP connection to server */
     http->auth_ref = NULL;
   }
 
-  if (!getenv("GATEWAY_INTERFACE") &&
-      httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
-                      auth_key, sizeof(auth_key)))
+  www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
+
+  if (!getenv("GATEWAY_INTERFACE") && (schemedata = cups_auth_find(www_auth, "AuthKey")) != NULL && cups_auth_param(schemedata, "key", auth_key, sizeof(auth_key)))
   {
-    status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
-                                kAuthorizationFlagDefaults, &http->auth_ref);
+    status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &http->auth_ref);
     if (status != errAuthorizationSuccess)
     {
       DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)",
@@ -745,6 +1087,15 @@ cups_local_auth(http_t *http)             /* I - HTTP connection to server */
   }
 #  endif /* HAVE_AUTHORIZATION_H */
 
+#  ifdef HAVE_GSSAPI
+  if (cups_auth_find(www_auth, "Negotiate"))
+    return (1);
+#  endif /* HAVE_GSSAPI */
+#  ifdef HAVE_AUTHORIZATION_H
+  if (cups_auth_find(www_auth, "AuthKey"))
+    return (1);
+#  endif /* HAVE_AUTHORIZATION_H */
+
 #  if defined(SO_PEERCRED) && defined(AF_LOCAL)
  /*
   * See if we can authenticate using the peer credentials provided over a
@@ -752,16 +1103,9 @@ cups_local_auth(http_t *http)             /* I - HTTP connection to server */
   * information...
   */
 
-  if (
-#    ifdef HAVE_GSSAPI
-      _cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9) &&
-#    endif /* HAVE_GSSAPI */
-#    ifdef HAVE_AUTHORIZATION_H
-      !httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
-                       auth_key, sizeof(auth_key)) &&
-#    endif /* HAVE_AUTHORIZATION_H */
-      http->hostaddr->addr.sa_family == AF_LOCAL &&
-      !getenv("GATEWAY_INTERFACE"))    /* Not via CGI programs... */
+  if (http->hostaddr->addr.sa_family == AF_LOCAL &&
+      !getenv("GATEWAY_INTERFACE") &&  /* Not via CGI programs... */
+      cups_auth_find(www_auth, "PeerCred"))
   {
    /*
     * Verify that the current cupsUser() matches the current UID...
@@ -784,6 +1128,9 @@ cups_local_auth(http_t *http)              /* I - HTTP connection to server */
   }
 #  endif /* SO_PEERCRED && AF_LOCAL */
 
+  if ((schemedata = cups_auth_find(www_auth, "Local")) == NULL)
+    return (1);
+
  /*
   * Try opening a certificate file for this PID.  If that fails,
   * try the root certificate...
@@ -797,33 +1144,9 @@ cups_local_auth(http_t *http)             /* I - HTTP connection to server */
     * No certificate for this PID; see if we can get the root certificate...
     */
 
-    DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s",
-                  filename, strerror(errno)));
+    DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s", filename, strerror(errno)));
 
-#  ifdef HAVE_GSSAPI
-    if (!_cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
-    {
-     /*
-      * Kerberos required, don't try the root certificate...
-      */
-
-      return (1);
-    }
-#  endif /* HAVE_GSSAPI */
-
-#  ifdef HAVE_AUTHORIZATION_H
-    if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
-                        auth_key, sizeof(auth_key)))
-    {
-     /*
-      * Don't use the root certificate as a replacement for an authkey...
-      */
-
-      return (1);
-    }
-#  endif /* HAVE_AUTHORIZATION_H */
-    if (!httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "trc", trc,
-                         sizeof(trc)))
+    if (!cups_auth_param(schemedata, "trc", trc, sizeof(trc)))
     {
      /*
       * Scheduler doesn't want us to use the root certificate...
index a4eae86d9e2792cb3c0e33dddb103433d4cf6eab..9896f640ca193de0575734228ad28f3ee15c8ad1 100644 (file)
@@ -606,6 +606,9 @@ extern ssize_t              cupsHashData(const char *algorithm, const void *data, size_t dat
 extern int             cupsAddIntegerOption(const char *name, int value, int num_options, cups_option_t **options) _CUPS_API_2_2_4;
 extern int             cupsGetIntegerOption(const char *name, int num_options, cups_option_t *options) _CUPS_API_2_2_4;
 
+/* New in CUPS 2.3 */
+extern const char      *cupsHashString(const unsigned char *hash, size_t hashsize, char *buffer, size_t bufsize) _CUPS_API_2_3;
+
 #  ifdef __cplusplus
 }
 #  endif /* __cplusplus */
index ede546167b202bdde7f74ed56ccdf8b7db5ab7c0..aa6aca310fb0c913aa7ae360d5856d62d03333e5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Hashing function for CUPS.
  *
- * Copyright 2015-2016 by Apple Inc.
+ * Copyright 2015-2017 by Apple Inc.
  *
  * These coded instructions, statements, and computer programs are the
  * property of Apple Inc. and are protected by Federal copyright
@@ -21,6 +21,8 @@
 #  include <CommonCrypto/CommonDigest.h>
 #elif defined(HAVE_GNUTLS)
 #  include <gnutls/crypto.h>
+#else
+#  include "md5-private.h"
 #endif /* __APPLE__ */
 
 
@@ -53,7 +55,24 @@ cupsHashData(const char    *algorithm,       /* I - Algorithm name */
   }
 
 #ifdef __APPLE__
-  if (!strcmp(algorithm, "sha"))
+  if (!strcmp(algorithm, "md5"))
+  {
+   /*
+    * MD5 (deprecated but widely used...)
+    */
+
+    CC_MD5_CTX ctx;                    /* MD5 context */
+
+    if (hashsize < CC_MD5_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_MD5_Init(&ctx);
+    CC_MD5_Update(&ctx, data, (CC_LONG)datalen);
+    CC_MD5_Final(hash, &ctx);
+
+    return (CC_MD5_DIGEST_LENGTH);
+  }
+  else if (!strcmp(algorithm, "sha"))
   {
    /*
     * SHA-1...
@@ -171,7 +190,9 @@ cupsHashData(const char    *algorithm,      /* I - Algorithm name */
   unsigned char        temp[64];               /* Temporary hash buffer */
   size_t       tempsize = 0;           /* Truncate to this size? */
 
-  if (!strcmp(algorithm, "sha"))
+  if (!strcmp(algorithm, "md5"))
+    alg = GNUTLS_DIG_MD5;
+  else if (!strcmp(algorithm, "sha"))
     alg = GNUTLS_DIG_SHA1;
   else if (!strcmp(algorithm, "sha2-224"))
     alg = GNUTLS_DIG_SHA224;
@@ -219,10 +240,20 @@ cupsHashData(const char    *algorithm,    /* I - Algorithm name */
 
 #else
  /*
-  * No hash support without CommonCrypto or GNU TLS...
+  * No hash support beyond MD5 without CommonCrypto or GNU TLS...
   */
 
-  if (hashsize < 64)
+  if (!strcmp(algorithm, "md5"))
+  {
+    _cups_md5_state_t  state;          /* MD5 state info */
+
+    _cupsMD5Init(&state);
+    _cupsMD5Append(&state, data, datalen);
+    _cupsMD5Finish(&state, hash);
+
+    return (16);
+  }
+  else if (hashsize < 64)
     goto too_small;
 #endif /* __APPLE__ */
 
@@ -243,3 +274,51 @@ cupsHashData(const char    *algorithm,     /* I - Algorithm name */
   _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1);
   return (-1);
 }
+
+
+/*
+ * 'cupsHashString()' - Format a hash value as a hexadecimal string.
+ *
+ * The passed buffer must be at least 2 * hashsize + 1 characters in length.
+ */
+
+const char *                           /* O - Formatted string */
+cupsHashString(
+    const unsigned char *hash,         /* I - Hash */
+    size_t              hashsize,      /* I - Size of hash */
+    char                *buffer,       /* I - String buffer */
+    size_t             bufsize)        /* I - Size of string buffer */
+{
+  char         *bufptr = buffer;       /* Pointer into buffer */
+  static const char *hex = "0123456789abcdef";
+                                       /* Hex characters (lowercase!) */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1))
+  {
+    if (buffer)
+      *buffer = '\0';
+    return (NULL);
+  }
+
+ /*
+  * Loop until we've converted the whole hash...
+  */
+
+  while (hashsize > 0)
+  {
+    *bufptr++ = hex[*hash >> 4];
+    *bufptr++ = hex[*hash & 15];
+
+    hash ++;
+    hashsize --;
+  }
+
+  *bufptr = '\0';
+
+  return (buffer);
+}
index 508d67e3be5e3f0a62c4a3e24ea1240a25fdbcf5..d1835325149851ebf298b617f8819a1e60349075 100644 (file)
@@ -68,7 +68,6 @@ typedef int socklen_t;
 #  endif /* __APPLE__ && !_SOCKLEN_T */
 
 #  include <cups/http.h>
-#  include "md5-private.h"
 #  include "ipp-private.h"
 
 #  ifdef HAVE_GNUTLS
@@ -301,10 +300,10 @@ struct _http_s                            /**** HTTP connection structure ****/
   char                 buffer[HTTP_MAX_BUFFER];
                                        /* Buffer for incoming data */
   int                  _auth_type;     /* Authentication in use (deprecated) */
-  _cups_md5_state_t    md5_state;      /* MD5 state */
+  unsigned char                _md5_state[88]; /* MD5 state (deprecated) */
   char                 nonce[HTTP_MAX_VALUE];
                                        /* Nonce value */
-  int                  nonce_count;    /* Nonce count */
+  unsigned             nonce_count;    /* Nonce count */
   http_tls_t           tls;            /* TLS state information */
   http_encryption_t    encryption;     /* Encryption requirements */
 
@@ -368,6 +367,10 @@ struct _http_s                             /**** HTTP connection structure ****/
   z_stream             stream;         /* (De)compression stream */
   Bytef                        *sbuffer;       /* (De)compression buffer */
 #  endif /* HAVE_LIBZ */
+
+  /**** New in CUPS 2.3 ****/
+  char                 *www_authenticate;
+                                       /* WWW-Authenticate value */
 };
 #  endif /* !_HTTP_NO_PRIVATE */
 
index 76dbb7dbf0926dca038b4ea4578ab7bfea096a50..e2565392ff07ce727f6a18d19fae21a6ca824869 100644 (file)
@@ -502,7 +502,6 @@ httpAssembleUUID(const char *server,        /* I - Server name */
                 size_t     bufsize)    /* I - Size of buffer */
 {
   char                 data[1024];     /* Source string for MD5 */
-  _cups_md5_state_t    md5state;       /* MD5 state */
   unsigned char                md5sum[16];     /* MD5 digest/sum */
 
 
@@ -517,9 +516,7 @@ httpAssembleUUID(const char *server,        /* I - Server name */
            port, name ? name : server, number,
           (unsigned)CUPS_RAND() & 0xffff, (unsigned)CUPS_RAND() & 0xffff);
 
-  _cupsMD5Init(&md5state);
-  _cupsMD5Append(&md5state, (unsigned char *)data, (int)strlen(data));
-  _cupsMD5Finish(&md5state, md5sum);
+  cupsHashData("md5", (unsigned char *)data, strlen(data), md5sum, sizeof(md5sum));
 
  /*
   * Generate the UUID from the MD5...
index 61b88c9db73a38d0bab9896fb996b7c092a0c973..4dd47865ad4de4af3c6f1a9f6084f7a65dbe9d51 100644 (file)
@@ -325,6 +325,12 @@ httpClearFields(http_t *http)              /* I - HTTP connection */
       http->server = NULL;
     }
 
+    if (http->www_authenticate)
+    {
+      free(http->www_authenticate);
+      http->www_authenticate = NULL;
+    }
+
     http->expect = (http_status_t)0;
   }
 }
@@ -973,12 +979,27 @@ httpGetField(http_t       *http,  /* I - HTTP connection */
         if (http->field_authorization)
        {
         /*
-         * Special case for WWW-Authenticate: as its contents can be
+         * Special case for Authorization: as its contents can be
          * longer than HTTP_MAX_VALUE...
          */
 
          return (http->field_authorization);
        }
+       else
+         return (http->fields[field]);
+
+    case HTTP_FIELD_WWW_AUTHENTICATE :
+        if (http->www_authenticate)
+       {
+        /*
+         * Special case for WWW-Authenticate: as its contents can be
+         * longer than HTTP_MAX_VALUE...
+         */
+
+         return (http->www_authenticate);
+       }
+       else
+         return (http->fields[field]);
 
     default :
         return (http->fields[field]);
@@ -2683,17 +2704,35 @@ httpSetField(http_t       *http,        /* I - HTTP connection */
         break;
 
     case HTTP_FIELD_WWW_AUTHENTICATE :
-       /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */
-        if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] &&
-           _cups_strncasecmp(value, "Basic ", 6) &&
-           _cups_strncasecmp(value, "Digest ", 7) &&
-           _cups_strncasecmp(value, "Negotiate ", 10))
-       {
-         DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value));
-          return;
-       }
+        if (!http->www_authenticate)
+        {
+        /*
+         * First WWW-Authenticate seen, just copy it over...
+         */
 
-       /* Fall through to copy */
+         http->www_authenticate = strdup(value);
+         strlcpy(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], value, HTTP_MAX_VALUE);
+        }
+        else
+        {
+         /*
+          * Nth WWW-Authenticate seen, append to existing string...
+          */
+
+         size_t len = strlen(http->www_authenticate) + 2 + strlen(value) + 1;
+         char *temp = realloc(http->www_authenticate, len);
+
+         if (!temp)
+           return;
+
+         http->www_authenticate = temp;
+         strlcat(http->www_authenticate, ", ", len);
+         strlcat(http->www_authenticate, value, len);
+
+          /* Probably more efficient than two more strlcat's */
+         strlcpy(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], http->www_authenticate, HTTP_MAX_VALUE);
+        }
+        break;
 
     default :
        strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
index c61a79ee3dfd1af99706c4ab50646afe3a7d66ed..9856be5384e6f72a5816ac55ccf8e50379d7e208 100644 (file)
@@ -494,10 +494,10 @@ extern char               *httpEncode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use
 extern char            *httpDecode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpDecode64_2 instead.");
 extern int             httpGetLength(http_t *http) _CUPS_DEPRECATED_MSG("Use httpGetLength2 instead.");
 extern char            *httpMD5(const char *, const char *, const char *,
-                                char [33]);
+                                char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead.");
 extern char            *httpMD5Final(const char *, const char *, const char *,
-                                     char [33]);
-extern char            *httpMD5String(const unsigned char *, char [33]);
+                                     char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead.");
+extern char            *httpMD5String(const unsigned char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsHashString instead.");
 
 /**** New in CUPS 1.1.19 ****/
 extern void            httpClearCookie(http_t *http) _CUPS_API_1_1_19;
index c0f5dd73fcebf99d55f80f5bf6728c74e5fc6183..d5057bf191eea0e9872af77a24793578e3f77ebb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Private MD5 implementation for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 2005 by Easy Software Products
  * Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
  *
 #include "md5-private.h"
 #include "string-private.h"
 
-#define T1 0xd76aa478
-#define T2 0xe8c7b756
-#define T3 0x242070db
-#define T4 0xc1bdceee
-#define T5 0xf57c0faf
-#define T6 0x4787c62a
-#define T7 0xa8304613
-#define T8 0xfd469501
-#define T9 0x698098d8
-#define T10 0x8b44f7af
-#define T11 0xffff5bb1
-#define T12 0x895cd7be
-#define T13 0x6b901122
-#define T14 0xfd987193
-#define T15 0xa679438e
-#define T16 0x49b40821
-#define T17 0xf61e2562
-#define T18 0xc040b340
-#define T19 0x265e5a51
-#define T20 0xe9b6c7aa
-#define T21 0xd62f105d
-#define T22 0x02441453
-#define T23 0xd8a1e681
-#define T24 0xe7d3fbc8
-#define T25 0x21e1cde6
-#define T26 0xc33707d6
-#define T27 0xf4d50d87
-#define T28 0x455a14ed
-#define T29 0xa9e3e905
-#define T30 0xfcefa3f8
-#define T31 0x676f02d9
-#define T32 0x8d2a4c8a
-#define T33 0xfffa3942
-#define T34 0x8771f681
-#define T35 0x6d9d6122
-#define T36 0xfde5380c
-#define T37 0xa4beea44
-#define T38 0x4bdecfa9
-#define T39 0xf6bb4b60
-#define T40 0xbebfbc70
-#define T41 0x289b7ec6
-#define T42 0xeaa127fa
-#define T43 0xd4ef3085
-#define T44 0x04881d05
-#define T45 0xd9d4d039
-#define T46 0xe6db99e5
-#define T47 0x1fa27cf8
-#define T48 0xc4ac5665
-#define T49 0xf4292244
-#define T50 0x432aff97
-#define T51 0xab9423a7
-#define T52 0xfc93a039
-#define T53 0x655b59c3
-#define T54 0x8f0ccc92
-#define T55 0xffeff47d
-#define T56 0x85845dd1
-#define T57 0x6fa87e4f
-#define T58 0xfe2ce6e0
-#define T59 0xa3014314
-#define T60 0x4e0811a1
-#define T61 0xf7537e82
-#define T62 0xbd3af235
-#define T63 0x2ad7d2bb
-#define T64 0xeb86d391
+#if !defined(__APPLE__) && !defined(HAVE_GNUTLS)
+#  define T1 0xd76aa478
+#  define T2 0xe8c7b756
+#  define T3 0x242070db
+#  define T4 0xc1bdceee
+#  define T5 0xf57c0faf
+#  define T6 0x4787c62a
+#  define T7 0xa8304613
+#  define T8 0xfd469501
+#  define T9 0x698098d8
+#  define T10 0x8b44f7af
+#  define T11 0xffff5bb1
+#  define T12 0x895cd7be
+#  define T13 0x6b901122
+#  define T14 0xfd987193
+#  define T15 0xa679438e
+#  define T16 0x49b40821
+#  define T17 0xf61e2562
+#  define T18 0xc040b340
+#  define T19 0x265e5a51
+#  define T20 0xe9b6c7aa
+#  define T21 0xd62f105d
+#  define T22 0x02441453
+#  define T23 0xd8a1e681
+#  define T24 0xe7d3fbc8
+#  define T25 0x21e1cde6
+#  define T26 0xc33707d6
+#  define T27 0xf4d50d87
+#  define T28 0x455a14ed
+#  define T29 0xa9e3e905
+#  define T30 0xfcefa3f8
+#  define T31 0x676f02d9
+#  define T32 0x8d2a4c8a
+#  define T33 0xfffa3942
+#  define T34 0x8771f681
+#  define T35 0x6d9d6122
+#  define T36 0xfde5380c
+#  define T37 0xa4beea44
+#  define T38 0x4bdecfa9
+#  define T39 0xf6bb4b60
+#  define T40 0xbebfbc70
+#  define T41 0x289b7ec6
+#  define T42 0xeaa127fa
+#  define T43 0xd4ef3085
+#  define T44 0x04881d05
+#  define T45 0xd9d4d039
+#  define T46 0xe6db99e5
+#  define T47 0x1fa27cf8
+#  define T48 0xc4ac5665
+#  define T49 0xf4292244
+#  define T50 0x432aff97
+#  define T51 0xab9423a7
+#  define T52 0xfc93a039
+#  define T53 0x655b59c3
+#  define T54 0x8f0ccc92
+#  define T55 0xffeff47d
+#  define T56 0x85845dd1
+#  define T57 0x6fa87e4f
+#  define T58 0xfe2ce6e0
+#  define T59 0xa3014314
+#  define T60 0x4e0811a1
+#  define T61 0xf7537e82
+#  define T62 0xbd3af235
+#  define T63 0x2ad7d2bb
+#  define T64 0xeb86d391
 
 static void
 _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
@@ -116,10 +117,10 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
        c = pms->abcd[2], d = pms->abcd[3];
     unsigned int t;
 
-#ifndef ARCH_IS_BIG_ENDIAN
-# define ARCH_IS_BIG_ENDIAN 1  /* slower, default implementation */
-#endif
-#if ARCH_IS_BIG_ENDIAN
+#  ifndef ARCH_IS_BIG_ENDIAN
+#    define ARCH_IS_BIG_ENDIAN 1       /* slower, default implementation */
+#  endif
+#  if ARCH_IS_BIG_ENDIAN
 
     /*
      * On big-endian machines, we must arrange the bytes in the right
@@ -133,7 +134,7 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
        X[i] = (unsigned)xp[0] + ((unsigned)xp[1] << 8) +
               ((unsigned)xp[2] << 16) + ((unsigned)xp[3] << 24);
 
-#else  /* !ARCH_IS_BIG_ENDIAN */
+#  else  /* !ARCH_IS_BIG_ENDIAN */
 
     /*
      * On little-endian machines, we can process properly aligned data
@@ -150,15 +151,15 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
        memcpy(xbuf, data, 64);
        X = xbuf;
     }
-#endif
+#  endif
 
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#  define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
 
     /* Round 1. */
     /* Let [abcd k s i] denote the operation
        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)\
+#  define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#  define SET(a, b, c, d, k, s, Ti)\
   t = a + F(b,c,d) + X[k] + Ti;\
   a = ROTATE_LEFT(t, s) + b
     /* Do the following 16 operations. */
@@ -178,13 +179,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
     SET(d, a, b, c, 13, 12, T14);
     SET(c, d, a, b, 14, 17, T15);
     SET(b, c, d, a, 15, 22, T16);
-#undef SET
+#  undef SET
 
      /* Round 2. */
      /* Let [abcd k s i] denote the operation
           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
+#  define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#  define SET(a, b, c, d, k, s, Ti)\
   t = a + G(b,c,d) + X[k] + Ti;\
   a = ROTATE_LEFT(t, s) + b
      /* Do the following 16 operations. */
@@ -204,13 +205,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
     SET(d, a, b, c,  2,  9, T30);
     SET(c, d, a, b,  7, 14, T31);
     SET(b, c, d, a, 12, 20, T32);
-#undef SET
+#  undef SET
 
      /* Round 3. */
      /* Let [abcd k s t] denote the operation
           a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)\
+#  define H(x, y, z) ((x) ^ (y) ^ (z))
+#  define SET(a, b, c, d, k, s, Ti)\
   t = a + H(b,c,d) + X[k] + Ti;\
   a = ROTATE_LEFT(t, s) + b
      /* Do the following 16 operations. */
@@ -230,13 +231,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
     SET(d, a, b, c, 12, 11, T46);
     SET(c, d, a, b, 15, 16, T47);
     SET(b, c, d, a,  2, 23, T48);
-#undef SET
+#  undef SET
 
      /* Round 4. */
      /* Let [abcd k s t] denote the operation
           a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
+#  define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#  define SET(a, b, c, d, k, s, Ti)\
   t = a + I(b,c,d) + X[k] + Ti;\
   a = ROTATE_LEFT(t, s) + b
      /* Do the following 16 operations. */
@@ -256,7 +257,7 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
     SET(d, a, b, c, 11, 10, T62);
     SET(c, d, a, b,  2, 15, T63);
     SET(b, c, d, a,  9, 21, T64);
-#undef SET
+#  undef SET
 
      /* Then perform the following additions. (That is increment each
         of the four registers by the value it had before this block
@@ -337,3 +338,4 @@ _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16])
     for (i = 0; i < 16; ++i)
        digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3));
 }
+#endif /* !__APPLE__ && !HAVE_GNUTLS */
index a9817aaa22583afacf1074da6741baca7ab77a52..1c3deb5eea97ad22da28ded01fb9e0885e8c09ae 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * MD5 password support for CUPS.
+ * MD5 password support for CUPS (deprecated).
  *
- * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2005 by Easy Software Products.
  *
  * These coded instructions, statements, and computer programs are the
  * Include necessary headers...
  */
 
+#include <cups/cups.h>
 #include "http-private.h"
 #include "string-private.h"
 
 
 /*
  * 'httpMD5()' - Compute the MD5 sum of the username:group:password.
+ *
+ * @deprecated@
  */
 
 char *                                 /* O - MD5 sum */
@@ -31,7 +34,6 @@ httpMD5(const char *username,         /* I - User name */
         const char *passwd,            /* I - Password string */
        char       md5[33])             /* O - MD5 string */
 {
-  _cups_md5_state_t    state;          /* MD5 state info */
   unsigned char                sum[16];        /* Sum data */
   char                 line[256];      /* Line to sum */
 
@@ -41,15 +43,13 @@ httpMD5(const char *username,               /* I - User name */
   */
 
   snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd);
-  _cupsMD5Init(&state);
-  _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
-  _cupsMD5Finish(&state, sum);
+  cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum));
 
  /*
   * Return the sum...
   */
 
-  return (httpMD5String(sum, md5));
+  return ((char *)cupsHashString(sum, sizeof(sum), md5, 33));
 }
 
 
@@ -57,6 +57,8 @@ httpMD5(const char *username,         /* I - User name */
  * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password
  *                    with the server-supplied nonce value, method, and
  *                    request-uri.
+ *
+ * @deprecated@
  */
 
 char *                                 /* O - New sum */
@@ -65,7 +67,6 @@ httpMD5Final(const char *nonce,               /* I - Server nonce value */
             const char *resource,      /* I - Resource path */
              char       md5[33])       /* IO - MD5 sum */
 {
-  _cups_md5_state_t    state;          /* MD5 state info */
   unsigned char                sum[16];        /* Sum data */
   char                 line[1024];     /* Line of data */
   char                 a2[33];         /* Hash of method and resource */
@@ -76,9 +77,7 @@ httpMD5Final(const char *nonce,               /* I - Server nonce value */
   */
 
   snprintf(line, sizeof(line), "%s:%s", method, resource);
-  _cupsMD5Init(&state);
-  _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
-  _cupsMD5Finish(&state, sum);
+  cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum));
   httpMD5String(sum, a2);
 
  /*
@@ -88,17 +87,16 @@ httpMD5Final(const char *nonce,             /* I - Server nonce value */
   */
 
   snprintf(line, sizeof(line), "%s:%s:%s", md5, nonce, a2);
+  cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum));
 
-  _cupsMD5Init(&state);
-  _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
-  _cupsMD5Finish(&state, sum);
-
-  return (httpMD5String(sum, md5));
+  return ((char *)cupsHashString(sum, sizeof(sum), md5, 33));
 }
 
 
 /*
  * 'httpMD5String()' - Convert an MD5 sum to a character string.
+ *
+ * @deprecated@
  */
 
 char *                                 /* O - MD5 sum in hex */
@@ -106,23 +104,5 @@ httpMD5String(const unsigned char *sum,    /* I - MD5 sum data */
               char                md5[33])
                                        /* O - MD5 sum in hex */
 {
-  int          i;                      /* Looping var */
-  char         *md5ptr;                /* Pointer into MD5 string */
-  static const char hex[] = "0123456789abcdef";
-                                       /* Hex digits */
-
-
- /*
-  * Convert the MD5 sum to hexadecimal...
-  */
-
-  for (i = 16, md5ptr = md5; i > 0; i --, sum ++)
-  {
-    *md5ptr++ = hex[*sum >> 4];
-    *md5ptr++ = hex[*sum & 15];
-  }
-
-  *md5ptr = '\0';
-
-  return (md5);
+  return ((char *)cupsHashString(sum, 16, md5, 33));
 }
index 7b28ee47d841a66e86ed0a40c9cedafe06ce1c04..7cc006dbf468a496f62a5c26d8fc5215cfa5091f 100644 (file)
@@ -809,7 +809,6 @@ httpCredentialsString(
     CFStringRef                cf_name;        /* CF common name string */
     char               name[256];      /* Common name associated with cert */
     time_t             expiration;     /* Expiration date of cert */
-    _cups_md5_state_t  md5_state;      /* MD5 state */
     unsigned char      md5_digest[16]; /* MD5 result */
 
     if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL)
@@ -822,9 +821,7 @@ httpCredentialsString(
 
     expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970);
 
-    _cupsMD5Init(&md5_state);
-    _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
-    _cupsMD5Finish(&md5_state, md5_digest);
+    cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
 
     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
 
index 95606f5abb38e8ab2e74060cf6989479ef940ef5..7e9ae39df8e4010e935bb9fa8bf6d8f3af5fd021 100644 (file)
@@ -648,7 +648,6 @@ httpCredentialsString(
     char               name[256];      /* Common name associated with cert */
     size_t             namelen;        /* Length of name */
     time_t             expiration;     /* Expiration date of cert */
-    _cups_md5_state_t  md5_state;      /* MD5 state */
     unsigned char      md5_digest[16]; /* MD5 result */
 
     namelen = sizeof(name) - 1;
@@ -659,9 +658,7 @@ httpCredentialsString(
 
     expiration = gnutls_x509_crt_get_expiration_time(cert);
 
-    _cupsMD5Init(&md5_state);
-    _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
-    _cupsMD5Finish(&md5_state, md5_digest);
+    cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
 
     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
 
index 962ad6d1732d7dc2846f2566298f9e5a069746bd..ead461d1b38b806e0d5f4c39b48c969d2abb275a 100644 (file)
@@ -353,7 +353,6 @@ httpCredentialsString(
     SYSTEMTIME         systime;        /* System time */
     struct tm          tm;             /* UNIX date/time */
     time_t             expiration;     /* Expiration date of cert */
-    _cups_md5_state_t  md5_state;      /* MD5 state */
     unsigned char      md5_digest[16]; /* MD5 result */
 
     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
@@ -380,9 +379,7 @@ httpCredentialsString(
     else
       strlcpy(cert_name, "unknown", sizeof(cert_name));
 
-    _cupsMD5Init(&md5_state);
-    _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
-    _cupsMD5Finish(&md5_state, md5_digest);
+    cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
 
     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
 
index 5a000c050c1df7c5c7cdeb1b5ac698ae2182d1d3..3a00629aeb39206c5d5f233b6d66d446b65d2c4b 100644 (file)
@@ -71,6 +71,7 @@
 #    define _CUPS_API_2_0 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
 #    define _CUPS_API_2_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
 #    define _CUPS_API_2_2_4 AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+#    define _CUPS_API_2_3
 #  else
 #    define _CUPS_API_1_1_19
 #    define _CUPS_API_1_1_20
@@ -84,6 +85,7 @@
 #    define _CUPS_API_2_0
 #    define _CUPS_API_2_2
 #    define _CUPS_API_2_2_4
+#    define _CUPS_API_2_3
 #  endif /* __APPLE__ && !_CUPS_SOURCE */
 
 /*
index 4d6604651cb2a4290ee59d0f05d219b41d75a065..39041758c3cd3d8b524756aa185e78ec0d99ec25 100644 (file)
@@ -2369,17 +2369,27 @@ cupsdSendHeader(
       * requests when the request requires system group membership - then the
       * client knows the root certificate can/should be used.
       *
-      * Also, for macOS we also look for @AUTHKEY and add an "authkey"
-      * parameter as needed...
+      * Also, for macOS we also look for @AUTHKEY and add an "AuthRef key=foo"
+      * method as needed...
       */
 
       char     *name,                  /* Current user name */
                *auth_key;              /* Auth key buffer */
       size_t   auth_size;              /* Size of remaining buffer */
+      int      need_local = 1;         /* Do we need to list "Local" method? */
 
       auth_key  = auth_str + strlen(auth_str);
       auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str);
 
+#if defined(SO_PEERCRED) && defined(AF_LOCAL)
+      if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
+      {
+        strlcpy(auth_key, ", PeerCred", auth_size);
+        auth_key += 10;
+        auth_size -= 10;
+      }
+#endif /* SO_PEERCRED && AF_LOCAL */
+
       for (name = (char *)cupsArrayFirst(con->best->names);
            name;
           name = (char *)cupsArrayNext(con->best->names))
@@ -2387,7 +2397,8 @@ cupsdSendHeader(
 #ifdef HAVE_AUTHORIZATION_H
        if (!_cups_strncasecmp(name, "@AUTHKEY(", 9))
        {
-         snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9);
+         snprintf(auth_key, auth_size, ", AuthRef key=\"%s\"", name + 9);
+         need_local = 0;
          /* end parenthesis is stripped in conf.c */
          break;
         }
@@ -2397,16 +2408,18 @@ cupsdSendHeader(
        {
 #ifdef HAVE_AUTHORIZATION_H
          if (SystemGroupAuthKey)
-           snprintf(auth_key, auth_size,
-                    ", authkey=\"%s\"",
-                    SystemGroupAuthKey);
+           snprintf(auth_key, auth_size, ", AuthRef key=\"%s\"", SystemGroupAuthKey);
           else
 #else
-         strlcpy(auth_key, ", trc=\"y\"", auth_size);
+         strlcpy(auth_key, ", Local trc=\"y\"", auth_size);
 #endif /* HAVE_AUTHORIZATION_H */
+         need_local = 0;
          break;
        }
       }
+
+      if (need_local)
+       strlcpy(auth_key, ", Local", auth_size);
     }
 
     if (auth_str[0])