Blame SOURCES/0089-lib-handle-access-denials-in-upload_file.patch

4b6aa8
From f7a5699843a9f96dbdd796da2f891989dbc0f5fd Mon Sep 17 00:00:00 2001
4b6aa8
From: Jakub Filak <jfilak@redhat.com>
4b6aa8
Date: Tue, 30 Sep 2014 01:43:08 +0200
4b6aa8
Subject: [LIBREPORT PATCH 89/93] lib: handle access denials in upload_file()
4b6aa8
4b6aa8
curl provides an error code which can be used to detect invalid
4b6aa8
credentials.
4b6aa8
4b6aa8
This patch adds a support for re-trying upload with new credentials.
4b6aa8
4b6aa8
Related to rhbz#1066486
4b6aa8
4b6aa8
Signed-off-by: Jakub Filak <jfilak@redhat.com>
4b6aa8
---
4b6aa8
 src/include/libreport_curl.h | 11 +++++++
4b6aa8
 src/lib/curl.c               | 70 +++++++++++++++++++++++++++++++++++++++++---
4b6aa8
 2 files changed, 77 insertions(+), 4 deletions(-)
4b6aa8
4b6aa8
diff --git a/src/include/libreport_curl.h b/src/include/libreport_curl.h
4b6aa8
index 7d6fa02..4b41ecc 100644
4b6aa8
--- a/src/include/libreport_curl.h
4b6aa8
+++ b/src/include/libreport_curl.h
4b6aa8
@@ -119,9 +119,20 @@ post_file_as_form(post_state_t *state,
4b6aa8
                      filename, POST_DATA_FROMFILE_AS_FORM_DATA);
4b6aa8
 }
4b6aa8
 
4b6aa8
+enum {
4b6aa8
+    UPLOAD_FILE_NOFLAGS = 0,
4b6aa8
+    UPLOAD_FILE_HANDLE_ACCESS_DENIALS = 1 << 0,
4b6aa8
+};
4b6aa8
+
4b6aa8
 #define upload_file libreport_upload_file
4b6aa8
 char *upload_file(const char *url, const char *filename);
4b6aa8
 
4b6aa8
+#define upload_file_ext libreport_upload_file_ext
4b6aa8
+char *upload_file_ext(post_state_t *post_state,
4b6aa8
+                const char *url,
4b6aa8
+                const char *filename,
4b6aa8
+                int flags);
4b6aa8
+
4b6aa8
 #ifdef __cplusplus
4b6aa8
 }
4b6aa8
 #endif
4b6aa8
diff --git a/src/lib/curl.c b/src/lib/curl.c
4b6aa8
index 5ca18dd..f7321b5 100644
4b6aa8
--- a/src/lib/curl.c
4b6aa8
+++ b/src/lib/curl.c
4b6aa8
@@ -17,6 +17,7 @@
4b6aa8
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
4b6aa8
 */
4b6aa8
 #include "internal_libreport.h"
4b6aa8
+#include "client.h"
4b6aa8
 #include "libreport_curl.h"
4b6aa8
 #include "proxies.h"
4b6aa8
 
4b6aa8
@@ -586,6 +587,15 @@ post(post_state_t *state,
4b6aa8
  */
4b6aa8
 char *upload_file(const char *url, const char *filename)
4b6aa8
 {
4b6aa8
+    post_state_t *state = new_post_state(POST_WANT_ERROR_MSG);
4b6aa8
+    char *retval = upload_file_ext(state, url, filename, UPLOAD_FILE_NOFLAGS);
4b6aa8
+    free_post_state(state);
4b6aa8
+
4b6aa8
+    return retval;
4b6aa8
+}
4b6aa8
+
4b6aa8
+char *upload_file_ext(post_state_t *state, const char *url, const char *filename, int flags)
4b6aa8
+{
4b6aa8
     /* we don't want to print the whole url as it may contain password
4b6aa8
      * rhbz#856960
4b6aa8
      * there can be '@' in the login or password so let's try to find the
4b6aa8
@@ -597,8 +607,6 @@ char *upload_file(const char *url, const char *filename)
4b6aa8
     else
4b6aa8
         clean_url = url;
4b6aa8
 
4b6aa8
-    log(_("Sending %s to %s"), filename, clean_url);
4b6aa8
-
4b6aa8
     char *whole_url;
4b6aa8
     unsigned len = strlen(url);
4b6aa8
     if (len > 0 && url[len-1] == '/')
4b6aa8
@@ -606,7 +614,25 @@ char *upload_file(const char *url, const char *filename)
4b6aa8
     else
4b6aa8
         whole_url = xstrdup(url);
4b6aa8
 
4b6aa8
-    post_state_t *state = new_post_state(POST_WANT_ERROR_MSG);
4b6aa8
+
4b6aa8
+    const char *username_bck = state->username;
4b6aa8
+    const char *password_bck = state->password;
4b6aa8
+    char *username = NULL;
4b6aa8
+    char *password = NULL;
4b6aa8
+
4b6aa8
+    /* work around bug in libssh2(curl with scp://)
4b6aa8
+     * libssh2_aget_disconnect() calls close(0)
4b6aa8
+     * https://bugzilla.redhat.com/show_bug.cgi?id=1147717
4b6aa8
+     */
4b6aa8
+    int stdin_bck = dup(0);
4b6aa8
+
4b6aa8
+    /*
4b6aa8
+     * Well, goto seems to be the most elegant syntax form here :(
4b6aa8
+     * This label is used to re-try the upload with an updated credentials.
4b6aa8
+     */
4b6aa8
+  do_post:
4b6aa8
+
4b6aa8
+    log(_("Sending %s to %s"), filename, clean_url);
4b6aa8
     post(state,
4b6aa8
                 whole_url,
4b6aa8
                 /*content_type:*/ "application/octet-stream",
4b6aa8
@@ -615,6 +641,8 @@ char *upload_file(const char *url, const char *filename)
4b6aa8
                 POST_DATA_FROMFILE_PUT
4b6aa8
     );
4b6aa8
 
4b6aa8
+    dup2(stdin_bck, 0);
4b6aa8
+
4b6aa8
     int error = (state->curl_result != 0);
4b6aa8
     if (error)
4b6aa8
     {
4b6aa8
@@ -623,6 +651,34 @@ char *upload_file(const char *url, const char *filename)
4b6aa8
         else
4b6aa8
             /* for example, when source file can't be opened */
4b6aa8
             error_msg("Error while uploading");
4b6aa8
+
4b6aa8
+        if ((flags & UPLOAD_FILE_HANDLE_ACCESS_DENIALS) &&
4b6aa8
+                (state->curl_result == CURLE_LOGIN_DENIED
4b6aa8
+                 || state->curl_result == CURLE_REMOTE_ACCESS_DENIED))
4b6aa8
+        {
4b6aa8
+            char *msg = xasprintf(_("Please enter user name for '%s':"), clean_url);
4b6aa8
+            free(username);
4b6aa8
+            username = ask(msg);
4b6aa8
+            free(msg);
4b6aa8
+            if (username != NULL && username[0] != '\0')
4b6aa8
+            {
4b6aa8
+                msg = xasprintf(_("Please enter password for '%s':"), username);
4b6aa8
+                free(password);
4b6aa8
+                password = ask_password(msg);
4b6aa8
+                free(msg);
4b6aa8
+                /* What about empty password? */
4b6aa8
+                if (password != NULL && password[0] != '\0')
4b6aa8
+                {
4b6aa8
+                    state->username = username;
4b6aa8
+                    state->password = password;
4b6aa8
+                    /*
4b6aa8
+                     * Re-try with new credentials
4b6aa8
+                     */
4b6aa8
+                    goto do_post;
4b6aa8
+                }
4b6aa8
+            }
4b6aa8
+        }
4b6aa8
+
4b6aa8
         free(whole_url);
4b6aa8
         whole_url = NULL;
4b6aa8
     }
4b6aa8
@@ -632,7 +688,13 @@ char *upload_file(const char *url, const char *filename)
4b6aa8
         log(_("Successfully sent %s to %s"), filename, clean_url);
4b6aa8
     }
4b6aa8
 
4b6aa8
-    free_post_state(state);
4b6aa8
+    close(stdin_bck);
4b6aa8
+
4b6aa8
+    free(password);
4b6aa8
+    free(username);
4b6aa8
+
4b6aa8
+    state->username = username_bck;
4b6aa8
+    state->password = password_bck;
4b6aa8
 
4b6aa8
     return whole_url;
4b6aa8
 }
4b6aa8
-- 
4b6aa8
1.8.3.1
4b6aa8