From 2ba728eb97f451219723c10d5826cfa268784e67 Mon Sep 17 00:00:00 2001
From: Darshit Shah <darnir@gmail.com>
Date: Tue, 16 Jul 2013 20:24:36 +0530
Subject: [PATCH] Fix Exit Status Codes when there are errors in Digest
 Authentication

---
 src/ChangeLog | 16 +++++++++++
 src/exits.c   |  4 +--
 src/http.c    | 92 ++++++++++++++++++++++++++++++++++++++++-------------------
 src/wget.h    |  2 +-
 4 files changed, 82 insertions(+), 32 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 0c4f352..0282e54 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,19 @@
+2013-07-16  Darshit Shah  <darnir@gmail.com>
+
+	* wget.h (err_t): Added new errors, ATTRMISSING and UNKNOWNATTR to
+	handle missing attributes and Unknown attribute values respectively in
+	HTTP Headers.
+	* exits.c (get_status_for_err): ATTRMISSING is a Protocol Error while
+	UNKNOWNATTR is a general error, presumably because of a feature that
+	is not yet implemented.
+	* http.c (gethttp): Call create_authorization_line () separately. In
+	case the auth_err flag has been set with an error, handle it and exit.
+	* http.c (http_loop): Handle the errors raised by the authentication
+	handlers.
+	* http.c (digest_authentication_encode): Set qop to NULL in case the
+	value of the qop / algorithm attribute is unknown to Wget. Set an
+	appropriate error too.
+
 2013-07-13  Giuseppe Scrivano  <gscrivano@gnu.org>
 
 	* http.c (digest_authentication_encode): Fix a crash when the algorithm
diff --git a/src/exits.c b/src/exits.c
index cea38d5..b8230f8 100644
--- a/src/exits.c
+++ b/src/exits.c
@@ -68,7 +68,7 @@ get_status_for_err (uerr_t err)
       return WGET_EXIT_SSL_AUTH_FAIL;
     case FTPLOGINC: case FTPLOGREFUSED: case AUTHFAILED:
       return WGET_EXIT_SERVER_AUTH_FAIL;
-    case HEOF: case HERR:
+    case HEOF: case HERR: case ATTRMISSING:
       return WGET_EXIT_PROTOCOL_ERROR;
     case WRONGCODE: case FTPPORTERR: case FTPSYSERR:
     case FTPNSFOD: case FTPUNKNOWNTYPE: case FTPSRVERR:
@@ -76,7 +76,7 @@ get_status_for_err (uerr_t err)
     case CONTNOTSUPPORTED: case RANGEERR: case RETRBADPATTERN:
     case PROXERR:
       return WGET_EXIT_SERVER_ERROR;
-    case URLERROR: case QUOTEXC: case SSLINITFAILED:
+    case URLERROR: case QUOTEXC: case SSLINITFAILED: case UNKNOWNATTR:
     default:
       return WGET_EXIT_UNKNOWN;
     }
diff --git a/src/http.c b/src/http.c
index b2a03c8..64929d7 100644
--- a/src/http.c
+++ b/src/http.c
@@ -146,6 +146,7 @@ struct request {
 };
 
 extern int numurls;
+uerr_t auth_err = RETROK;
 
 /* Create a new, empty request. Set the request's method and its
    arguments.  METHOD should be a literal string (or it should outlive
@@ -2377,28 +2378,38 @@ read_header:
           else if (!basic_auth_finished
                    || !BEGINS_WITH (www_authenticate, "Basic"))
             {
-              char *pth;
-              pth = url_full_path (u);
-              request_set_header (req, "Authorization",
-                                  create_authorization_line (www_authenticate,
-                                                             user, passwd,
-                                                             request_method (req),
-                                                             pth,
-                                                             &auth_finished),
-                                  rel_value);
-              if (BEGINS_WITH (www_authenticate, "NTLM"))
-                ntlm_seen = true;
-              else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
+              char *pth = url_full_path (u);
+              const char *value;
+
+              value =  create_authorization_line (www_authenticate,
+                                                  user, passwd,
+                                                  request_method (req),
+                                                  pth,
+                                                  &auth_finished);
+
+              if (auth_err == RETROK)
                 {
-                  /* Need to register this host as using basic auth,
-                   * so we automatically send creds next time. */
-                  register_basic_auth_host (u->host);
+                  request_set_header (req, "Authorization", value, rel_value);
+
+                  if (BEGINS_WITH (www_authenticate, "NTLM"))
+                    ntlm_seen = true;
+                  else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
+                    {
+                      /* Need to register this host as using basic auth,
+                       * so we automatically send creds next time. */
+                      register_basic_auth_host (u->host);
+                    }
+
+                  xfree (pth);
+                  xfree_null (message);
+                  resp_free (resp);
+                  xfree (head);
+                  goto retry_with_auth;
+                }
+              else
+                {
+                  /* Creating the Authorization header went wrong */
                 }
-              xfree (pth);
-              xfree_null (message);
-              resp_free (resp);
-              xfree (head);
-              goto retry_with_auth;
             }
           else
             {
@@ -2406,12 +2417,14 @@ read_header:
                * give up. */
             }
         }
-      logputs (LOG_NOTQUIET, _("Authorization failed.\n"));
       request_free (req);
       xfree_null (message);
       resp_free (resp);
       xfree (head);
-      return AUTHFAILED;
+      if (auth_err == RETROK)
+        return AUTHFAILED;
+      else
+        return auth_err;
     }
   else /* statcode != HTTP_STATUS_UNAUTHORIZED */
     {
@@ -3133,12 +3146,23 @@ Spider mode enabled. Check if remote file exists.\n"));
           logputs (LOG_VERBOSE, "\n");
           logprintf (LOG_NOTQUIET, _("Cannot write to %s (%s).\n"),
                      quote (hstat.local_file), strerror (errno));
-        case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case AUTHFAILED:
-        case SSLINITFAILED: case CONTNOTSUPPORTED: case VERIFCERTERR:
-        case FILEBADFILE:
+        case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case SSLINITFAILED:
+        case CONTNOTSUPPORTED: case VERIFCERTERR: case FILEBADFILE:
+        case UNKNOWNATTR:
           /* Fatal errors just return from the function.  */
           ret = err;
           goto exit;
+        case ATTRMISSING:
+          /* A missing attribute in a Header is a fatal Protocol error. */
+          logputs (LOG_VERBOSE, "\n");
+          logprintf (LOG_NOTQUIET, _("Required attribute missing from Header receieved.\n"));
+          ret = err;
+          goto exit;
+        case AUTHFAILED:
+          logputs (LOG_VERBOSE, "\n");
+          logprintf (LOG_NOTQUIET, _("Username/Password Authentication Failed.\n"));
+          ret = err;
+          goto exit;
         case WARC_ERR:
           /* A fatal WARC error. */
           logputs (LOG_VERBOSE, "\n");
@@ -3717,15 +3741,24 @@ digest_authentication_encode (const char *au, const char *user,
   if (qop != NULL && strcmp(qop,"auth"))
     {
       logprintf (LOG_NOTQUIET, _("Unsupported quality of protection '%s'.\n"), qop);
-      user = NULL; /* force freeing mem and return */
+      qop = NULL; /* force freeing mem and return */
     }
-
-  if (algorithm != NULL && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
+  else if (algorithm != NULL && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
     {
       logprintf (LOG_NOTQUIET, _("Unsupported algorithm '%s'.\n"), algorithm);
-      user = NULL; /* force freeing mem and return */
+      qop = NULL; /* force freeing mem and return */
     }
 
+  if (!qop)
+    {
+      xfree_null (realm);
+      xfree_null (opaque);
+      xfree_null (nonce);
+      xfree_null (qop);
+      xfree_null (algorithm);
+      auth_err = UNKNOWNATTR;
+      return NULL;
+    }
   if (!realm || !nonce || !user || !passwd || !path || !method)
     {
       xfree_null (realm);
@@ -3733,6 +3766,7 @@ digest_authentication_encode (const char *au, const char *user,
       xfree_null (nonce);
       xfree_null (qop);
       xfree_null (algorithm);
+      auth_err = ATTRMISSING;
       return NULL;
     }
 
diff --git a/src/wget.h b/src/wget.h
index 14a1965..3c73947 100644
--- a/src/wget.h
+++ b/src/wget.h
@@ -357,7 +357,7 @@ typedef enum
   PROXERR,
   /* 50  */
   AUTHFAILED, QUOTEXC, WRITEFAILED, SSLINITFAILED, VERIFCERTERR,
-  UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED,
+  UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED, ATTRMISSING, UNKNOWNATTR,
 
   WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR
 } uerr_t;
-- 
1.8.3.3

