From: Michael R Sweet Date: Fri, 14 Sep 2018 18:58:46 +0000 (-0400) Subject: Mirror Digest changes from master. X-Git-Tag: v2.2.9~21 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=commitdiff_plain;h=598bfaad438ac5254eea22c13dcc173275194def Mirror Digest changes from master. --- diff --git a/cups/auth.c b/cups/auth.c index 72f524385..a798bdbb3 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -119,9 +119,7 @@ cupsDoAuthentication( *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 */ + prompt[1024]; /* Prompt for user */ int localauth; /* Local authentication result */ _cups_globals_t *cg; /* Global data */ @@ -259,6 +257,7 @@ cupsDoAuthentication( httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass)); httpSetAuthString(http, "Basic", encode); + break; } else if (!_cups_strcasecmp(scheme, "Digest")) { @@ -266,57 +265,15 @@ cupsDoAuthentication( * 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 */ - digest[1024]; /* Digest auth data */ - - if (strcmp(nonce, http->nonce)) - { - strlcpy(http->nonce, nonce, sizeof(http->nonce)); - http->nonce_count = 1; - } - else - http->nonce_count ++; + char nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */ - cups_auth_param(schemedata, "opaque", opaque, sizeof(opaque)); + cups_auth_param(schemedata, "algorithm", http->algorithm, sizeof(http->algorithm)); + cups_auth_param(schemedata, "opaque", http->opaque, sizeof(http->opaque)); cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce)); - cups_auth_param(schemedata, "realm", realm, sizeof(realm)); - - for (i = 0; i < 64; i ++) - cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; - cnonce[64] = '\0'; - - if (cups_auth_param(schemedata, "algorithm", algorithm, sizeof(algorithm))) - { - /* - * Calculate and pass the RFC 2617/7616 WWW-Authenticate header... - */ - - if (!_httpDigest(kd, sizeof(kd), algorithm, cupsUser(), realm, strchr(http->userpass, ':') + 1, nonce, http->nonce_count, cnonce, "auth", method, resource)) - continue; - - 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 - { - /* - * Calculate and pass the old RFC 2069 WWW-Authenticate header... - */ - - if (!_httpDigest(kd, sizeof(kd), NULL, cupsUser(), realm, strchr(http->userpass, ':') + 1, nonce, http->nonce_count, NULL, NULL, method, resource)) - continue; - - snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, resource, kd); - } + cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); - httpSetAuthString(http, "Digest", digest); + if (_httpSetDigestAuthString(http, nonce, method, resource)) + break; } } diff --git a/cups/getputfile.c b/cups/getputfile.c index ae33bc599..60edbf83f 100644 --- a/cups/getputfile.c +++ b/cups/getputfile.c @@ -1,7 +1,7 @@ /* * Get/put file functions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -45,6 +45,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA http_status_t status; /* HTTP status from server */ char if_modified_since[HTTP_MAX_VALUE]; /* If-Modified-Since header */ + int new_auth = 0; /* Using new auth information? */ + int digest; /* Are we using Digest authentication? */ /* @@ -85,9 +87,33 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA } httpClearFields(http); - httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since); + digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + + if (digest && !new_auth) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); + } + +#ifdef HAVE_GSSAPI + if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) + { + /* + * Do not use cached Kerberos credentials since they will look like a + * "replay" attack... + */ + + _cupsSetNegotiateAuthString(http, "GET", resource); + } +#endif /* HAVE_GSSAPI */ + + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -102,6 +128,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA } } + new_auth = 0; + while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) @@ -116,6 +144,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; @@ -267,6 +297,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA int retries; /* Number of retries */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ + int new_auth = 0; /* Using new auth information? */ + int digest; /* Are we using Digest authentication? */ /* @@ -309,10 +341,34 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA http->authstring)); httpClearFields(http); - httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetExpect(http, HTTP_STATUS_CONTINUE); + digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + + if (digest && !new_auth) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource); + } + +#ifdef HAVE_GSSAPI + if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) + { + /* + * Do not use cached Kerberos credentials since they will look like a + * "replay" attack... + */ + + _cupsSetNegotiateAuthString(http, "PUT", resource); + } +#endif /* HAVE_GSSAPI */ + + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + if (httpPut(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -383,6 +439,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA DEBUG_printf(("2cupsPutFd: status=%d", status)); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -395,6 +453,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "PUT", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; diff --git a/cups/http-private.h b/cups/http-private.h index 84f487ff7..eeabaae22 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -367,6 +367,15 @@ struct _http_s /**** HTTP connection structure ****/ z_stream stream; /* (De)compression stream */ Bytef *sbuffer; /* (De)compression buffer */ # endif /* HAVE_LIBZ */ + + /**** New in CUPS 2.2.9 ****/ + char algorithm[65], /* Algorithm from WWW-Authenticate */ + nextnonce[HTTP_MAX_VALUE], + /* Next nonce value from Authentication-Info */ + opaque[HTTP_MAX_VALUE], + /* Opaque value from WWW-Authenticate */ + realm[HTTP_MAX_VALUE]; + /* Realm from WWW-Authenticate */ }; # endif /* !_HTTP_NO_PRIVATE */ @@ -432,7 +441,6 @@ extern http_tls_credentials_t _httpCreateCredentials(cups_array_t *credentials); extern char *_httpDecodeURI(char *dst, const char *src, size_t dstsize); -extern char *_httpDigest(char *buffer, size_t bufsize, const char *algorithm, const char *username, const char *realm, const char *password, const char *nonce, unsigned nc, const char *cnonce, const char *qop, const char *method, const char *resource); extern void _httpDisconnect(http_t *http); extern char *_httpEncodeURI(char *dst, const char *src, size_t dstsize); @@ -441,6 +449,7 @@ extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), void *context); +extern int _httpSetDigestAuthString(http_t *http, const char *nonce, const char *method, const char *resource); extern const char *_httpStatus(cups_lang_t *lang, http_status_t status); extern void _httpTLSInitialize(void); extern size_t _httpTLSPending(http_t *http); diff --git a/cups/http-support.c b/cups/http-support.c index 71d978cc5..739953b31 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -666,113 +666,6 @@ httpDecode64_2(char *out, /* I - String to write to */ } -/* - * '_httpDigest()' - Calculate a Digest authentication response using the - * appropriate RFC 2068/2617/7616 algorithm. - */ - -char * /* O - Response string */ -_httpDigest(char *buffer, /* I - Response buffer */ - size_t bufsize, /* I - Size of response buffer */ - const char *algorithm, /* I - algorithm value or `NULL` */ - const char *username, /* I - username value */ - const char *realm, /* I - realm value */ - const char *password, /* I - password value */ - const char *nonce, /* I - nonce value */ - unsigned nc, /* I - nc value */ - const char *cnonce, /* I - cnonce value or `NULL` */ - const char *qop, /* I - qop value */ - const char *method, /* I - HTTP method */ - const char *resource) /* I - HTTP resource path */ -{ - char ha1[65], /* Hash of username:realm:password */ - ha2[65], /* Hash of method:request-uri */ - temp[1024]; /* Temporary string */ - unsigned char hash[32]; /* Hash buffer */ - const char *hashalg; /* Hashing algorithm */ - size_t hashsize; /* Size of hash */ - - - DEBUG_printf(("2_httpDigest(buffer=%p, bufsize=" CUPS_LLFMT ", algorithm=\%s\", username=\"%s\", realm=\"%s\", password=\"%d chars\", nonce=\"%s\", nc=%u, cnonce=\"%s\", qop=\"%s\", method=\"%s\", resource=\"%s\")", buffer, CUPS_LLCAST bufsize, algorithm, username, realm, (int)strlen(password), nonce, nc, cnonce, qop, method, resource)); - - if (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... - */ - - *buffer = '\0'; - - return (NULL); - } - - /* - * Calculate digest value... - */ - - /* H(A1) = H(username:realm:password) */ - snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password); - 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)); - - /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ - snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, nonce, nc, cnonce, qop, ha2); - hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, buffer, bufsize); - } - else - { - /* - * Use old RFC 2069 Digest method... - */ - - /* H(A1) = H(username:realm:password) */ - snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password); - 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, buffer, bufsize); - } - - return (buffer); -} - - /* * 'httpEncode64()' - Base64-encode a string. * @@ -1409,6 +1302,152 @@ httpSeparateURI( } +/* + * '_httpSetDigestAuthString()' - Calculate a Digest authentication response + * using the appropriate RFC 2068/2617/7616 + * algorithm. + */ + +int /* O - 1 on success, 0 on failure */ +_httpSetDigestAuthString( + http_t *http, /* I - HTTP connection */ + const char *nonce, /* I - Nonce value */ + const char *method, /* I - HTTP method */ + const char *resource) /* I - HTTP resource path */ +{ + char kd[65], /* Final MD5/SHA-256 digest */ + ha1[65], /* Hash of username:realm:password */ + ha2[65], /* Hash of method:request-uri */ + username[HTTP_MAX_VALUE], + /* username:password */ + *password, /* Pointer to password */ + temp[1024], /* Temporary string */ + digest[1024]; /* Digest auth data */ + unsigned char hash[32]; /* Hash buffer */ + size_t hashsize; /* Size of hash */ + + + DEBUG_printf(("2_httpSetDigestAuthString(http=%p, nonce=\"%s\", method=\"%s\", resource=\"%s\")", http, nonce, method, resource)); + + if (nonce && *nonce && strcmp(nonce, http->nonce)) + { + strlcpy(http->nonce, nonce, sizeof(http->nonce)); + + if (nonce == http->nextnonce) + http->nextnonce[0] = '\0'; + + http->nonce_count = 1; + } + else + http->nonce_count ++; + + strlcpy(username, http->userpass, sizeof(username)); + if ((password = strchr(username, ':')) != NULL) + *password++ = '\0'; + else + return (0); + + if (http->algorithm[0]) + { + /* + * Follow RFC 2617/7616... + */ + + int i; /* Looping var */ + char cnonce[65]; /* cnonce value */ + const char *hashalg; /* Hashing algorithm */ + + for (i = 0; i < 64; i ++) + cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; + cnonce[64] = '\0'; + + if (!_cups_strcasecmp(http->algorithm, "MD5")) + { + /* + * RFC 2617 Digest with MD5 + */ + + hashalg = "md5"; + } + else if (!_cups_strcasecmp(http->algorithm, "SHA-256")) + { + /* + * RFC 7616 Digest with SHA-256 + */ + + hashalg = "sha2-256"; + } + else + { + /* + * Some other algorithm we don't support, skip this one... + */ + + return (0); + } + + /* + * Calculate digest value... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); + 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)); + + /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, http->nonce, http->nonce_count, cnonce, "auth", ha2); + 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 (http->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(), http->realm, http->nonce, http->algorithm, http->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\"", username, http->realm, http->nonce, http->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", username, http->realm, password); + 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, http->nonce, ha2); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, kd, sizeof(kd)); + + /* + * Pass the old RFC 2069 WWW-Authenticate header... + */ + + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, resource, kd); + } + + httpSetAuthString(http, "Digest", digest); + + return (1); +} + + /* * 'httpStateString()' - Return the string describing a HTTP state value. * diff --git a/cups/http.c b/cups/http.c index 76df91e04..bfebce6c0 100644 --- a/cups/http.c +++ b/cups/http.c @@ -106,7 +106,8 @@ static const char * const http_fields[] = "WWW-Authenticate", "Accept-Encoding", "Allow", - "Server" + "Server", + "Authentication-Info" }; @@ -2938,7 +2939,12 @@ _httpUpdate(http_t *http, /* I - HTTP connection */ httpSetCookie(http, value); } else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN) + { http_add_field(http, field, value, 1); + + if (field == HTTP_FIELD_AUTHENTICATION_INFO) + httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce)); + } #ifdef DEBUG else DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line)); diff --git a/cups/http.h b/cups/http.h index 156efeaa8..fec4dc5aa 100644 --- a/cups/http.h +++ b/cups/http.h @@ -181,6 +181,7 @@ typedef enum http_field_e /**** HTTP field names ****/ HTTP_FIELD_ACCEPT_ENCODING, /* Accepting-Encoding field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_ALLOW, /* Allow field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_SERVER, /* Server field @since CUPS 1.7/macOS 10.9@ */ + HTTP_FIELD_AUTHENTICATION_INFO, /* Authentication-Info field (@since CUPS 2.2.9) */ HTTP_FIELD_MAX /* Maximum field index */ } http_field_t; diff --git a/cups/request.c b/cups/request.c index 6cd527690..16c30e86a 100644 --- a/cups/request.c +++ b/cups/request.c @@ -686,6 +686,15 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + if (digest) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "POST", resource); + } + #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9)) { diff --git a/cups/testhttp.c b/cups/testhttp.c index ae4324505..7d8ec06d5 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -341,6 +341,7 @@ main(int argc, /* I - Number of command-line arguments */ if (!j) puts("PASS"); +#if 0 /* * _httpDigest() */ @@ -372,6 +373,7 @@ main(int argc, /* I - Number of command-line arguments */ } else puts("PASS"); +#endif /* 0 */ /* * httpGetHostname() @@ -631,6 +633,8 @@ main(int argc, /* I - Number of command-line arguments */ for (i = 1; i < argc; i ++) { + int new_auth; + if (!strcmp(argv[i], "-o")) { i ++; @@ -714,6 +718,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Checking file \"%s\"...\n", resource); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -726,9 +732,13 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "HEAD", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + if (httpHead(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -745,6 +755,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -757,6 +769,8 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "HEAD", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; @@ -805,6 +819,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, encoding ? encoding : "identity"); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -817,6 +833,9 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); @@ -838,6 +857,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -850,6 +871,8 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;