From aed7759dda951ded900854410a644f63a2531f90 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 11 Jun 2012 16:18:46 +0100 Subject: [PATCH] Add --authenticate option Signed-off-by: David Woodhouse --- main.c | 54 ++++++++++++++++++++++++++++++++++-------------- openconnect.8.in | 21 +++++++++++++++++++ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/main.c b/main.c index 35ca377c..77de51a4 100644 --- a/main.c +++ b/main.c @@ -78,9 +78,11 @@ int background; int do_passphrase_from_fsid; int nocertcheck; int non_inter; +int cookieonly; enum { - OPT_AUTHGROUP = 0x100, + OPT_AUTHENTICATE = 0x100, + OPT_AUTHGROUP, OPT_BASEMTU, OPT_CAFILE, OPT_CONFIGFILE, @@ -143,6 +145,7 @@ static struct option long_options[] = { OPTION("cafile", 1, OPT_CAFILE), OPTION("config", 1, OPT_CONFIGFILE), OPTION("no-dtls", 0, OPT_NO_DTLS), + OPTION("authenticate", 0, OPT_AUTHENTICATE), OPTION("cookieonly", 0, OPT_COOKIEONLY), OPTION("printcookie", 0, OPT_PRINTCOOKIE), OPTION("quiet", 0, 'q'), @@ -244,6 +247,7 @@ static void usage(void) printf(" -v, --verbose %s\n", _("More output")); printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file")); printf(" --authgroup=GROUP %s\n", _("Choose authentication login selection")); + printf(" --authenticate %s\n", _("Authenticate only and print login info")); printf(" --cookieonly %s\n", _("Fetch webvpn cookie only; don't connect")); printf(" --printcookie %s\n", _("Print webvpn cookie before connecting")); printf(" --cafile=FILE %s\n", _("Cert file for server verification")); @@ -405,7 +409,6 @@ int main(int argc, char **argv) struct openconnect_info *vpninfo; struct utsname utsbuf; struct sigaction sa; - int cookieonly = 0; int use_syslog = 0; char *urlpath = NULL; char *proxy = getenv("https_proxy"); @@ -497,6 +500,9 @@ int main(int argc, char **argv) case OPT_PRINTCOOKIE: cookieonly = 2; break; + case OPT_AUTHENTICATE: + cookieonly = 3; + break; case OPT_COOKIE_ON_STDIN: read_stdin(&vpninfo->cookie); /* If the cookie is empty, ignore it */ @@ -743,7 +749,17 @@ int main(int argc, char **argv) exit(1); } - if (cookieonly) { + if (cookieonly == 3) { + /* --authenticate */ + printf("COOKIE='%s'\n", vpninfo->cookie); + printf("HOST='%s'\n", vpninfo->hostname); + if (vpninfo->peer_cert) { + char buf[41] = {0, }; + openconnect_get_cert_sha1(vpninfo, vpninfo->peer_cert, buf); + printf("FINGERPRINT='%s'\n", buf); + } + exit(0); + } else if (cookieonly) { printf("%s\n", vpninfo->cookie); if (cookieonly == 1) /* We use cookieonly=2 for 'print it and continue' */ @@ -850,6 +866,9 @@ void write_progress(void *_vpninfo, int level, const char *fmt, ...) FILE *outf = level ? stdout : stderr; va_list args; + if (cookieonly) + outf = stderr; + if (verbose >= level) { va_start(args, fmt); vfprintf(outf, fmt, args); @@ -926,13 +945,13 @@ static int validate_peer_cert(void *_vpninfo, OPENCONNECT_X509 *peer_cert, char *details; char *p; - printf(_("\nCertificate from VPN server \"%s\" failed verification.\n" + fprintf(stderr, _("\nCertificate from VPN server \"%s\" failed verification.\n" "Reason: %s\n"), vpninfo->hostname, reason); if (non_inter) return -EINVAL; - printf(_("Enter '%s' to accept, '%s' to abort; anything else to view: "), + fprintf(stderr, _("Enter '%s' to accept, '%s' to abort; anything else to view: "), _("yes"), _("no")); if (!fgets(buf, sizeof(buf), stdin)) return -EINVAL; @@ -977,13 +996,13 @@ static int process_auth_form(void *_vpninfo, char *p; if (form->banner) - puts(form->banner); + fprintf(stderr, "%s\n", form->banner); if (form->error) - puts(form->error); + fprintf(stderr, "%s\n", form->error); if (form->message) - puts(form->message); + fprintf(stderr, "%s\n", form->message); /* scan for select options first so they are displayed first */ for (opt = form->opts; opt; opt = opt->next) { @@ -1024,15 +1043,16 @@ static int process_auth_form(void *_vpninfo, _("User input required in non-interactive mode\n")); return -EINVAL; } - printf("%s [", opt->label); + fprintf(stderr, "%s [", opt->label); for (i = 0; i < select_opt->nr_choices; i++) { choice = &select_opt->choices[i]; if (i) - printf("|"); + fprintf(stderr, "|"); - printf("%s", choice->label); + fprintf(stderr, "%s", choice->label); } - printf("]:"); + fprintf(stderr, "]:"); + fflush(stderr); if (!fgets(response, sizeof(response), stdin) || !strlen(response)) return -EINVAL; @@ -1075,8 +1095,9 @@ static int process_auth_form(void *_vpninfo, if (!opt->value) return -ENOMEM; - printf("%s", opt->label); - + fprintf(stderr, "%s", opt->label); + fflush(stderr); + if (!fgets(opt->value, 80, stdin) || !strlen(opt->value)) return -EINVAL; @@ -1102,7 +1123,8 @@ static int process_auth_form(void *_vpninfo, if (!opt->value) return -ENOMEM; - printf("%s", opt->label); + fprintf(stderr, "%s", opt->label); + fflush(stderr); tcgetattr(0, &t); t.c_lflag &= ~ECHO; @@ -1112,7 +1134,7 @@ static int process_auth_form(void *_vpninfo, t.c_lflag |= ECHO; tcsetattr(0, TCSANOW, &t); - printf("\n"); + fprintf(stderr, "\n"); if (!p || !strlen(opt->value)) return -EINVAL; diff --git a/openconnect.8.in b/openconnect.8.in index 57ebc51e..6cd689d6 100644 --- a/openconnect.8.in +++ b/openconnect.8.in @@ -36,6 +36,7 @@ openconnect \- Connect to Cisco AnyConnect VPN .OP \-v,\-\-verbose .OP \-x,\-\-xmlconfig config .OP \-\-authgroup group +.OP \-\-authenticate .OP \-\-cookieonly .OP \-\-printcookie .OP \-\-cafile file @@ -244,6 +245,26 @@ XML config file .B \-\-authgroup=GROUP Choose authentication login selection .TP +.B \-\-authentiate +Authenticate only, and output the information needed to make the connection +a form which can be used to set shell environment variables. When invoked with +this option, openconnect will not make the connection, but if successful will +output something like the following to stdout: +.nf +.B COOKIE=3311180634@13561856@1339425499@B315A0E29D16C6FD92EE... +.B HOST=10.0.0.1 +.B FINGERPRINT=469bb424ec8835944d30bc77c77e8fc1d8e23a42 +.fi +Thus, you can invoke openconnect as a non-privileged user +.I (with access to the user's PKCS#11 tokens, etc.) +for authentication, and then invoke openconnect separately to make the actual +connection as root: +.nf +.B eval `openconnect --authenticate https://vpnserver.example.com`; +.B [ -n "$COOKIE" ] && echo "$COOKIE" | +.B \ \ sudo openconnect --cookie-on-stdin $HOST --servercert $FINGERPRINT +.fi +.TP .B \-\-cookieonly Fetch webvpn cookie only; don't connect .TP