[PATCH v2 1/2] option to choose form field for token code, and to append to password

Dan Lenski dlenski at gmail.com
Sun Dec 20 22:47:45 PST 2015


bugfixes from previous version:
* memory leak for password+tokencode concat
* retval should be -ENOMEM, not +ENOMEM
* no need for a separate OPT_TOKEN_APPEND

see http://news.gmane.org/gmane.network.vpn.openconnect.devel/2922

Signed-off-by: Dan Lenski <dlenski at gmail.com>
---
 auth-common.c          | 36 ++++++++++++++++++++++++++++++------
 auth.c                 | 19 ++++++++++++++++---
 library.c              |  5 +++--
 main.c                 | 19 +++++++++++++++++--
 openconnect-internal.h |  2 ++
 openconnect.h          |  1 +
 6 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/auth-common.c b/auth-common.c
index 848f882..7cf5c93 100644
--- a/auth-common.c
+++ b/auth-common.c
@@ -142,6 +142,8 @@ int do_gen_tokencode(struct openconnect_info *vpninfo,
 		     struct oc_auth_form *form)
 {
 	struct oc_form_opt *opt;
+	char *password_plus=NULL;
+	int ret;
 
 	for (opt = form->opts; ; opt = opt->next) {
 		/* this form might not have anything for us to do */
@@ -149,25 +151,47 @@ int do_gen_tokencode(struct openconnect_info *vpninfo,
 			return 0;
 		if (opt->type == OC_FORM_OPT_TOKEN)
 			break;
+		else if (opt->type == OC_FORM_OPT_PASSWORD_PLUS_TOKEN) {
+			/* opt->_value already contains a password, which we need
+			   to save and prepend afterward generating tokencode */
+			password_plus = opt->_value;
+			break;
+		}
 	}
 
 	switch (vpninfo->token_mode) {
 #ifdef HAVE_LIBSTOKEN
 	case OC_TOKEN_MODE_STOKEN:
-		return do_gen_stoken_code(vpninfo, form, opt);
+		ret = do_gen_stoken_code(vpninfo, form, opt);
+		break;
 #endif
 	case OC_TOKEN_MODE_TOTP:
-		return do_gen_totp_code(vpninfo, form, opt);
-
+		ret = do_gen_totp_code(vpninfo, form, opt);
+		break;
 	case OC_TOKEN_MODE_HOTP:
-		return do_gen_hotp_code(vpninfo, form, opt);
+		ret = do_gen_hotp_code(vpninfo, form, opt);
+		break;
 #ifdef HAVE_LIBPCSCLITE
 	case OC_TOKEN_MODE_YUBIOATH:
-		return do_gen_yubikey_code(vpninfo, form, opt);
+		ret = do_gen_yubikey_code(vpninfo, form, opt);
+		break;
 #endif
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+
+	if (ret==0 && password_plus) {
+		/* opt->_value now contains token code only, and we need to
+		   prepend the saved password */
+		if ( (password_plus = realloc(password_plus, strlen(password_plus) + strlen(opt->_value) + 1)) == NULL )
+			ret = -ENOMEM;
+		else {
+			strcat(password_plus, opt->_value);
+			free(opt->_value);
+			opt->_value = password_plus;
+		}
+	}
+	return ret;
 }
 
 int can_gen_tokencode(struct openconnect_info *vpninfo,
diff --git a/auth.c b/auth.c
index 7aee802..617d8b2 100644
--- a/auth.c
+++ b/auth.c
@@ -220,10 +220,12 @@ static int parse_form(struct openconnect_info *vpninfo, struct oc_auth_form *for
 		} else if (!strcmp(input_type, "text")) {
 			opt->type = OC_FORM_OPT_TEXT;
 		} else if (!strcmp(input_type, "password")) {
-			if (!cstp_can_gen_tokencode(vpninfo, form, opt))
-				opt->type = OC_FORM_OPT_TOKEN;
-			else
+			if (cstp_can_gen_tokencode(vpninfo, form, opt))
 				opt->type = OC_FORM_OPT_PASSWORD;
+			else if (vpninfo->token_append)
+				opt->type = OC_FORM_OPT_PASSWORD_PLUS_TOKEN;
+			else
+				opt->type = OC_FORM_OPT_TOKEN;
 		} else {
 			vpn_progress(vpninfo, PRG_INFO,
 				     _("Unknown input type %s in form\n"),
@@ -880,13 +882,24 @@ static int cstp_can_gen_tokencode(struct openconnect_info *vpninfo,
 
 #ifdef HAVE_LIBSTOKEN
 	if (vpninfo->token_mode == OC_TOKEN_MODE_STOKEN) {
+		if (vpninfo->token_field) {
+			if (strcmp(opt->name, vpninfo->token_field))
+				return -EINVAL;
+		}
+		else
 		if (strcmp(opt->name, "password") &&
 		    strcmp(opt->name, "answer"))
 			return -EINVAL;
 		return can_gen_stoken_code(vpninfo, form, opt);
 	}
 #endif
+
 	/* Otherwise it's an OATH token of some kind. */
+	if (vpninfo->token_field) {
+		if (strcmp(opt->name, vpninfo->token_field))
+			return -EINVAL;
+	}
+	else
 	if (strcmp(opt->name, "secondary_password"))
 		return -EINVAL;
 
diff --git a/library.c b/library.c
index cc50eac..e5e5bf6 100644
--- a/library.c
+++ b/library.c
@@ -939,7 +939,8 @@ void nuke_opt_values(struct oc_form_opt *opt)
 {
 	for (; opt; opt = opt->next) {
 		if (opt->type == OC_FORM_OPT_TEXT ||
-		    opt->type == OC_FORM_OPT_PASSWORD) {
+		    opt->type == OC_FORM_OPT_PASSWORD ||
+			opt->type == OC_FORM_OPT_PASSWORD_PLUS_TOKEN) {
 			free(opt->_value);
 			opt->_value = NULL;
 		}
@@ -976,7 +977,7 @@ retry:
 		opt->flags &= ~OC_FORM_OPT_IGNORE;
 
 		if (!auth_choice ||
-		    (opt->type != OC_FORM_OPT_TEXT && opt->type != OC_FORM_OPT_PASSWORD))
+		    (opt->type != OC_FORM_OPT_TEXT && opt->type != OC_FORM_OPT_PASSWORD && opt->type != OC_FORM_OPT_PASSWORD_PLUS_TOKEN))
 			continue;
 
 		if (auth_choice->noaaa ||
diff --git a/main.c b/main.c
index f853afe..eaec9ee 100644
--- a/main.c
+++ b/main.c
@@ -181,6 +181,7 @@ enum {
 	OPT_DTLS_LOCAL_PORT,
 	OPT_TOKEN_MODE,
 	OPT_TOKEN_SECRET,
+	OPT_TOKEN_FIELD,
 	OPT_OS,
 	OPT_TIMESTAMP,
 	OPT_PFS,
@@ -260,6 +261,7 @@ static const struct option long_options[] = {
 	OPTION("dtls-local-port", 1, OPT_DTLS_LOCAL_PORT),
 	OPTION("token-mode", 1, OPT_TOKEN_MODE),
 	OPTION("token-secret", 1, OPT_TOKEN_SECRET),
+	OPTION("token-field", 1, OPT_TOKEN_FIELD),
 	OPTION("os", 1, OPT_OS),
 	OPTION("no-xmlpost", 0, OPT_NO_XMLPOST),
 	OPTION("dump-http-traffic", 0, OPT_DUMP_HTTP),
@@ -802,6 +804,7 @@ static void usage(void)
 	printf("      --non-inter                 %s\n", _("Do not expect user input; exit if it is required"));
 	printf("      --passwd-on-stdin           %s\n", _("Read password from standard input"));
 	printf("      --token-mode=MODE           %s\n", _("Software token type: rsa, totp or hotp"));
+	printf("      --token-field=[+]FIELD      %s\n", _("Form field for token code (with +, code is appended to password)"));
 	printf("      --token-secret=STRING       %s\n", _("Software token secret"));
 #ifndef HAVE_LIBSTOKEN
 	printf("                                  %s\n", _("(NOTE: libstoken (RSA SecurID) disabled in this build)"));
@@ -980,6 +983,8 @@ int main(int argc, char **argv)
 	char *config_arg;
 	char *config_filename;
 	char *token_str = NULL;
+	char *token_field = NULL;
+	int token_append = 0;
 	oc_token_mode_t token_mode = OC_TOKEN_MODE_NONE;
 	int reconnect_timeout = 300;
 	int ret;
@@ -1336,6 +1341,13 @@ int main(int argc, char **argv)
 		case OPT_TOKEN_SECRET:
 			token_str = keep_config_arg();
 			break;
+		case OPT_TOKEN_FIELD:
+			token_field = keep_config_arg();
+			if (token_field[0]=='+') {
+				token_append = 1;
+				token_field++;
+			}
+			break;
 		case OPT_OS:
 			if (openconnect_set_reported_os(vpninfo, config_arg)) {
 				fprintf(stderr, _("Invalid OS identity \"%s\"\n"),
@@ -1392,8 +1404,11 @@ int main(int argc, char **argv)
 #endif
 	}
 
-	if (token_mode != OC_TOKEN_MODE_NONE)
+	if (token_mode != OC_TOKEN_MODE_NONE) {
 		init_token(vpninfo, token_mode, token_str);
+		vpninfo->token_field = token_field;
+		vpninfo->token_append = token_append;
+	}
 
 	if (proxy && openconnect_set_http_proxy(vpninfo, strdup(proxy)))
 		exit(1);
@@ -1916,7 +1931,7 @@ static int process_auth_form_cb(void *_vpninfo,
 				goto err;
 			empty = 0;
 
-		} else if (opt->type == OC_FORM_OPT_PASSWORD) {
+		} else if (opt->type == OC_FORM_OPT_PASSWORD || opt->type == OC_FORM_OPT_PASSWORD_PLUS_TOKEN) {
 			if (password &&
 			    !strcmp(opt->name, "password")) {
 				opt->_value = password;
diff --git a/openconnect-internal.h b/openconnect-internal.h
index b7a2b0e..dacdb3f 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -409,6 +409,8 @@ struct openconnect_info {
 	int token_bypassed;
 	int token_tries;
 	time_t token_time;
+	char *token_field;
+	int token_append;
 #ifdef HAVE_LIBSTOKEN
 	struct stoken_ctx *stoken_ctx;
 	char *stoken_pin;
diff --git a/openconnect.h b/openconnect.h
index 2bd8505..cad1518 100644
--- a/openconnect.h
+++ b/openconnect.h
@@ -153,6 +153,7 @@
 #define OC_FORM_OPT_SELECT	3
 #define OC_FORM_OPT_HIDDEN	4
 #define OC_FORM_OPT_TOKEN	5
+#define OC_FORM_OPT_PASSWORD_PLUS_TOKEN	6
 
 #define OC_FORM_RESULT_ERR		-1
 #define OC_FORM_RESULT_OK		0
-- 
2.5.0




More information about the openconnect-devel mailing list