From 28afb072b162a675a6b7f52eea51b369b7b6f902 Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Fri, 22 Jul 2016 14:10:41 -0400 Subject: [PATCH v2] wget: Add --use-askpass support To: address@hidden Cc: address@hidden This adds the --use-askpass option which is disabled by default. --use-askpass will request the username and password for a given URL by executing the external program pointed to by the environment variable WGET_ASKPASS. If the environment variable is not set, SSH_ASKPASS is used. If neither environment variable are set, an error is returned. If an error occurs requesting the username or password, wget will exit. Signed-off-by: Liam R. Howlett --- ChangeLog | 15 ++++++++ doc/wget.texi | 5 +++ src/init.c | 5 +++ src/main.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/options.h | 2 ++ src/url.c | 6 ++++ src/url.h | 1 + 7 files changed, 145 insertions(+) diff --git a/ChangeLog b/ChangeLog index dca7846..368d7c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2016-07-25 Liam R. Howlett + + Add --use-askpass support + * doc/wget.texi: Add --use-askpass to documentation. + * src/init.c: initialize opt.use_use_askpass and opt.use_askpass. + * src/main.c: Update options & add spawn process of either + WGET_ANSPASS or SSH_ASKPASS. + * src/options.h: Addition of use_use_askpass boolean and use_askpass + string. + * src/url.c: Function scheme_leading_string to access the leading + string of a parsed url. + * src/url.h: Prototype for scheme_leading_string for returning the + leading string. + + 2016-06-09 Giuseppe Scrivano NEWS: update diff --git a/doc/wget.texi b/doc/wget.texi index 1e55e63..0ce9ecf 100644 --- a/doc/wget.texi +++ b/doc/wget.texi @@ -1154,6 +1154,11 @@ options for @sc{http} connections. Prompt for a password for each connection established. Cannot be specified when @samp{--password} is being used, because they are mutually exclusive. address@hidden --use-askpass +Prompt for a user and password using the program specified in the environment +variable WGET_ASKPASS. If WGET_ASKPASS is not set, then the program specified +in the environment SSH_ASKPASS is used. + @cindex iri support @cindex idn support @item --no-iri diff --git a/src/init.c b/src/init.c index d043d83..3d68d8e 100644 --- a/src/init.c +++ b/src/init.c @@ -322,6 +322,7 @@ static const struct { { "user", &opt.user, cmd_string }, { "useragent", NULL, cmd_spec_useragent }, { "useservertimestamps", &opt.useservertimestamps, cmd_boolean }, + { "useuseaskpass", &opt.use_use_askpass, cmd_boolean}, { "verbose", NULL, cmd_spec_verbose }, { "wait", &opt.wait, cmd_time }, { "waitretry", &opt.waitretry, cmd_time }, @@ -392,6 +393,10 @@ defaults (void) tmp = getenv ("no_proxy"); if (tmp) opt.no_proxy = sepstring (tmp); + opt.use_use_askpass = false; + opt.use_askpass = getenv ("WGET_ASKPASS"); + if (!opt.use_askpass) + opt.use_askpass = getenv("SSH_ASKPASS"); opt.prefer_family = prefer_none; opt.allow_cache = true; opt.if_modified_since = true; diff --git a/src/main.c b/src/main.c index e7d5c66..27f5d5c 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,7 @@ as that of the covered work. */ #include #include #include +#include #ifdef ENABLE_NLS # include #endif @@ -415,6 +416,7 @@ static struct cmdline_option option_data[] = { "unlink", 0, OPT_BOOLEAN, "unlink", -1 }, { "trust-server-names", 0, OPT_BOOLEAN, "trustservernames", -1 }, { "use-server-timestamps", 0, OPT_BOOLEAN, "useservertimestamps", -1 }, + { "use-askpass", 0, OPT_BOOLEAN, "useuseaskpass", -1 }, { "user", 0, OPT_VALUE, "user", -1 }, { "user-agent", 'U', OPT_VALUE, "useragent", -1 }, { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 }, @@ -691,6 +693,8 @@ Download:\n"), N_("\ --ask-password prompt for passwords\n"), N_("\ + --use-askpass Use WGET_ASKPASS for credential requests. Use SSH_ASKPASS if WGET_ASKPASS is not set.\n"), + N_("\ --no-iri turn off IRI support\n"), N_("\ --local-encoding=ENC use ENC as the local encoding for IRIs\n"), @@ -1019,6 +1023,99 @@ prompt_for_password (void) return getpass(""); } + +/* Execute external application WGET_ASKPASS or SSH_ASKPASS which is stored in opt.use_askpass + */ +void +run_use_askpass(char *question, char **answer) +{ + char tmp[1024]; + pid_t pid; + int status; + int com[2]; + char * const argv[] = {question, NULL}; + posix_spawn_file_actions_t fa; + + if (pipe(com) == -1) + { + fprintf(stderr, _("Cannot create pipe")); + exit (WGET_EXIT_GENERIC_ERROR); + } + + status = posix_spawn_file_actions_init(&fa); + if (status) + { + fprintf(stderr, "Error initializing spawn file actions for --use-askpass: %d", + status); + exit (WGET_EXIT_GENERIC_ERROR); + } + + status = posix_spawn_file_actions_adddup2(&fa, com[1], STDOUT_FILENO); + if (status) + { + fprintf(stderr, "Error setting spawn file actions for --use-askpass: %d", status); + exit (WGET_EXIT_GENERIC_ERROR); + } + + status = posix_spawnp(&pid, opt.use_askpass, &fa, NULL, argv, environ); + if (status) + { + fprintf(stderr, "Error spawning %s: %d", opt.use_askpass, status); + exit (WGET_EXIT_GENERIC_ERROR); + } + + /* Success */ + if (pid == 0) + { + /* Child */ + close(com[0]); + close(com[1]); + execlp(opt.use_askpass, question, (char*)NULL); + assert("Execlp failed!"); + } + else + { + close(com[1]); + unsigned int bytes = read(com[0], tmp, sizeof(tmp)); + if (!bytes) + { + fprintf(stderr, + _("Error reading response from --use-askpass %s %s\n"), + opt.use_askpass, question); + exit (WGET_EXIT_GENERIC_ERROR); + } + else if (bytes > 1) + *answer = strndup(tmp, bytes-1); + } +} + +/* set the user name and password*/ +void +use_askpass (struct url *u) +{ + static char question[1024]; + + if (u->user == NULL || u->user[0] == '\0') + { + sprintf(question, "Username for '%s%s': ", + scheme_leading_string(u->scheme), u->host); + /* Prompt for username */ + run_use_askpass(question, &u->user); + if (opt.recursive) + opt.user = strdup(u->user); + } + + if (u->passwd == NULL || u->passwd[0] == '\0') + { + sprintf(question, "Password for 'address@hidden': ", + scheme_leading_string(u->scheme), u->user, + u->host); + /* Prompt for password */ + run_use_askpass(question, &u->passwd); + if (opt.recursive) + opt.passwd = strdup(u->passwd); + } +} /* Function that prints the line argument while limiting it to at most line_length. prefix is printed on the first line and an appropriate number of spaces are added on subsequent @@ -1702,6 +1799,16 @@ for details.\n\n")); exit (WGET_EXIT_GENERIC_ERROR); } + if (opt.use_use_askpass) + { + /* can't request credentials until the URL is known. */ + if (opt.use_askpass == NULL || opt.use_askpass[0] == '\0') + { + fprintf(stderr, _("--use-askpass requires environment variable WGET_ASKPASS or SSH_ASKPASS to be set.\n")); + exit(WGET_EXIT_GENERIC_ERROR); + } + } + #ifdef USE_WATT32 if (opt.wdebug) dbug_init(); @@ -1920,6 +2027,10 @@ only if outputting to a regular file.\n")); } else { + if (opt.use_use_askpass) + { + use_askpass(url_parsed); + } if ((opt.recursive || opt.page_requisites) && ((url_scheme (*t) != SCHEME_FTP #ifdef HAVE_SSL diff --git a/src/options.h b/src/options.h index a8c494b..0bad59b 100644 --- a/src/options.h +++ b/src/options.h @@ -130,6 +130,8 @@ struct options char *user; /* Generic username */ char *passwd; /* Generic password */ bool ask_passwd; /* Ask for password? */ + bool use_use_askpass; /* Use [WGET|SSH]_ASKPASS infrastructure */ + char *use_askpass; /* value of [WGET|SSH]_ASKPASS */ bool always_rest; /* Always use REST. */ wgint start_pos; /* Start position of a download. */ diff --git a/src/url.c b/src/url.c index ec38d6f..c133d91 100644 --- a/src/url.c +++ b/src/url.c @@ -512,6 +512,12 @@ scheme_disable (enum url_scheme scheme) supported_schemes[scheme].flags |= scm_disabled; } +const char * +scheme_leading_string (enum url_scheme scheme) +{ + return supported_schemes[scheme].leading_string; +} + /* Skip the username and password, if present in the URL. The function should *not* be called with the complete URL, but with the portion after the scheme. diff --git a/src/url.h b/src/url.h index 7c77737..bf2e3f7 100644 --- a/src/url.h +++ b/src/url.h @@ -124,6 +124,7 @@ bool url_has_scheme (const char *); bool url_valid_scheme (const char *); int scheme_default_port (enum url_scheme); void scheme_disable (enum url_scheme); +const char *scheme_leading_string(enum url_scheme); char *url_string (const struct url *, enum url_auth_mode); char *url_file_name (const struct url *, char *); -- 1.9.1