Skip to content

Commit 96781b4

Browse files
selvanaircron2
authored andcommitted
Add an optional username-only flag for auth-user-pass
Specify "--auth-user-pass username-only" for openvpn to prompt for only username, not password. Prompt via management interface uses the usual ">PASSWORD 'Auth' " prompt with type "username" instead of "username/password". Internally, the password gets set as "[[BLANK]]" which is currently used as tag for blank password. Not compatible with --static-challenge or when username and password are inlined or read from a file. In such cases, the user hard-code a dummy password in the file instead. Change-Id: I788f76e6a70a9c20bca3367140d2741bd0551582 Signed-off-by: Selva Nair <selva.nair@gmail.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org> Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1548 Message-Id: <20260303142819.6123-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg35855.html Signed-off-by: Gert Doering <gert@greenie.muc.de> (cherry picked from commit dfbf80b)
1 parent b503997 commit 96781b4

File tree

12 files changed

+92
-15
lines changed

12 files changed

+92
-15
lines changed

doc/man-sections/client-options.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ configuration.
6868
auth-user-pass up
6969

7070
If ``up`` is present, it must be a file containing username/password on 2
71-
lines. If the password line is missing, OpenVPN will prompt for one.
71+
lines or a flag named :code:`username-only` to indicate no password
72+
should be prompted for. In the former case, if the password line is missing
73+
in the file, OpenVPN will prompt for one.
7274

7375
If ``up`` is omitted, username/password will be prompted from the
7476
console.
@@ -84,6 +86,20 @@ configuration.
8486
where password is optional, and will be prompted from the console if
8587
missing.
8688

89+
The :code:`username-only` flag is meant to be used with SSO authentication.
90+
In this case the user will be asked for a username but not password. Instead,
91+
a dummy password :code:`[[BLANK]]` is generated internally and submitted to
92+
the server. See management-notes.txt for how this option affects username/password
93+
prompt via the management interface. For the console, it simply eliminates
94+
the password prompt.
95+
96+
The :code:`username-only` flag cannot be used along with embedding username and/or
97+
password in the config file, or while reading them from an external file. In
98+
such cases, if only username is relevant and no password prompt is desired, a
99+
dummy password like 'no_passsword' should be embedded as well. This flag is also
100+
incompatible with the ``--static-challenge`` option and legacy ``dynamic challenge``
101+
protocol.
102+
87103
The server configuration must specify an ``--auth-user-pass-verify``
88104
script to verify the username/password provided by the client.
89105

doc/management-notes.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,19 @@ COMMAND -- password and username
304304
username "Auth" foo
305305
password "Auth" bar
306306

307+
Example 3:
308+
309+
>PASSWORD:Need 'Auth' username
310+
311+
OpenVPN needs a --auth-user-pass username. The
312+
management interface client should respond:
313+
314+
username "Auth" foo
315+
316+
In this case the user should not be prompted for a password.
317+
Support for such username-only prompting is conditional on the
318+
client announcing a version >= 4.
319+
307320
The username/password itself can be in quotes, and special
308321
characters such as double quote or backslash must be escaped,
309322
for example,
@@ -499,6 +512,7 @@ version. This was fixed starting version 4: clients should expect
499512
Minimum client version required for certain features is listed below:
500513
>PK_SIGN:[base64] -- version 2 or greater
501514
>PK_SIGN:[base64],[alg] -- version 3 or greater
515+
>PASSWORD:Need 'Auth' username -- version 4 or greater
502516

503517
COMMAND -- auth-retry
504518
---------------------

src/openvpn/init.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,10 +655,10 @@ init_query_passwords(const struct context *c)
655655
enable_auth_user_pass();
656656
#ifdef ENABLE_MANAGEMENT
657657
auth_user_pass_setup(c->options.auth_user_pass_file, c->options.auth_user_pass_file_inline,
658-
&c->options.sc_info);
658+
c->options.auth_user_pass_username_only, &c->options.sc_info);
659659
#else
660660
auth_user_pass_setup(c->options.auth_user_pass_file, c->options.auth_user_pass_file_inline,
661-
NULL);
661+
c->options.auth_user_pass_username_only, NULL);
662662
#endif
663663
}
664664
}
@@ -3383,6 +3383,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags)
33833383
}
33843384
to.auth_user_pass_file = options->auth_user_pass_file;
33853385
to.auth_user_pass_file_inline = options->auth_user_pass_file_inline;
3386+
to.auth_user_pass_username_only = options->auth_user_pass_username_only;
33863387
to.auth_token_generate = options->auth_token_generate;
33873388
to.auth_token_lifetime = options->auth_token_lifetime;
33883389
to.auth_token_renewal = options->auth_token_renewal;

src/openvpn/manage.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@
5858
#define MANAGEMENT_ECHO_FLAGS 0
5959
#endif
6060

61-
/* tag for blank username/password */
62-
static const char blank_up[] = "[[BLANK]]";
63-
6461
/*
6562
* Management client versions indicating feature support in client.
6663
* Append new values as needed but do not change exisiting ones.
@@ -70,6 +67,7 @@ enum mcv
7067
MCV_DEFAULT = 1,
7168
MCV_PKSIGN = 2,
7269
MCV_PKSIGN_ALG = 3,
70+
MCV_USERNAME_ONLY = 4,
7371
};
7472

7573
struct management *management; /* GLOBAL */
@@ -740,6 +738,13 @@ man_up_finalize(struct management *man)
740738
{
741739
switch (man->connection.up_query_mode)
742740
{
741+
case UP_QUERY_USERNAME:
742+
if (strlen(man->connection.up_query.username))
743+
{
744+
man->connection.up_query.defined = true;
745+
}
746+
break;
747+
743748
case UP_QUERY_USER_PASS:
744749
if (!strlen(man->connection.up_query.username))
745750
{
@@ -794,7 +799,9 @@ static void
794799
man_query_username(struct management *man, const char *type, const char *string)
795800
{
796801
const bool needed =
797-
((man->connection.up_query_mode == UP_QUERY_USER_PASS) && man->connection.up_query_type);
802+
((man->connection.up_query_mode == UP_QUERY_USER_PASS
803+
|| man->connection.up_query_mode == UP_QUERY_USERNAME)
804+
&& man->connection.up_query_type);
798805
man_query_user_pass(man, type, string, needed, "username", man->connection.up_query.username,
799806
USER_PASS_LEN);
800807
}
@@ -3558,6 +3565,12 @@ management_query_user_pass(struct management *man, struct user_pass *up, const c
35583565
prefix = "PASSWORD";
35593566
alert_type = "password";
35603567
}
3568+
else if ((man->connection.client_version >= MCV_USERNAME_ONLY) && (flags & GET_USER_PASS_USERNAME_ONLY))
3569+
{
3570+
up_query_mode = UP_QUERY_USERNAME;
3571+
prefix = "PASSWORD";
3572+
alert_type = "username";
3573+
}
35613574
else
35623575
{
35633576
up_query_mode = UP_QUERY_USER_PASS;

src/openvpn/manage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ struct man_settings
264264
#define UP_QUERY_PASS 2
265265
#define UP_QUERY_NEED_OK 3
266266
#define UP_QUERY_NEED_STR 4
267+
#define UP_QUERY_USERNAME 5
267268

268269
/* states */
269270
#define MS_INITIAL 0 /* all sockets are closed */

src/openvpn/misc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix
215215
{
216216
msg(M_WARN, "Note: previous '%s' credentials failed", prefix);
217217
}
218-
219218
#ifdef ENABLE_MANAGEMENT
220219
/*
221220
* Get username/password from management interface?
@@ -389,7 +388,7 @@ get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix
389388
query_user_add(BSTR(&user_prompt), up->username, USER_PASS_LEN, true);
390389
}
391390

392-
if (password_from_stdin)
391+
if (password_from_stdin && !(flags & GET_USER_PASS_USERNAME_ONLY))
393392
{
394393
query_user_add(BSTR(&pass_prompt), up->password, USER_PASS_LEN, false);
395394
}
@@ -451,6 +450,12 @@ get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix
451450
}
452451
}
453452

453+
/* Use tag for blank password if we are not prompting for one */
454+
if (flags & GET_USER_PASS_USERNAME_ONLY)
455+
{
456+
strncpy(up->password, blank_up, sizeof(up->password));
457+
}
458+
454459
string_mod(up->username, CC_PRINT, CC_CRLF, 0);
455460
string_mod(up->password, CC_PRINT, CC_CRLF, 0);
456461

src/openvpn/misc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const char **make_extended_arg_array(char **p, bool is_inline, struct gc_arena *
4848
* Get and store a username/password
4949
*/
5050

51+
/* tag for blank username/password */
52+
static const char blank_up[] = "[[BLANK]]";
53+
5154
struct user_pass
5255
{
5356
bool defined;
@@ -123,6 +126,8 @@ struct static_challenge_info
123126
#define GET_USER_PASS_INLINE_CREDS (1 << 10)
124127
/** indicates password and response should be concatenated */
125128
#define GET_USER_PASS_STATIC_CHALLENGE_CONCAT (1 << 11)
129+
/** indicate that only username should be prompted for auth-user-pass */
130+
#define GET_USER_PASS_USERNAME_ONLY (1 << 12)
126131

127132
/**
128133
* Retrieves the user credentials from various sources depending on the flags.

src/openvpn/options.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,8 @@ static const char usage_message[] =
511511
" up is a file containing the username on the first line,\n"
512512
" and a password on the second. If either the password or both\n"
513513
" the username and the password are omitted OpenVPN will prompt\n"
514-
" for them from console.\n"
514+
" for them from console. If [up] is 'username-only', only username\n"
515+
" will be prompted for from console or management interface.\n"
515516
"--pull : Accept certain config file options from the peer as if they\n"
516517
" were part of the local config file. Must be specified\n"
517518
" when connecting to a '--mode server' remote host.\n"
@@ -3939,6 +3940,12 @@ options_postprocess_mutate(struct options *o, struct env_set *es)
39393940
{
39403941
o->auth_token_renewal = o->renegotiate_seconds;
39413942
}
3943+
#if ENABLE_MANAGEMENT
3944+
if (o->auth_user_pass_username_only && o->sc_info.challenge_text)
3945+
{
3946+
msg(M_USAGE, "'auth-user-pass username-only' cannot be used with static challenge");
3947+
}
3948+
#endif
39423949
pre_connect_save(o);
39433950
}
39443951

@@ -7742,7 +7749,13 @@ add_option(struct options *options, char *p[], bool is_inline, const char *file,
77427749
else if (streq(p[0], "auth-user-pass") && !p[2])
77437750
{
77447751
VERIFY_PERMISSION(OPT_P_GENERAL | OPT_P_INLINE);
7745-
if (p[1])
7752+
options->auth_user_pass_username_only = false;
7753+
if (p[1] && streq(p[1], "username-only"))
7754+
{
7755+
options->auth_user_pass_username_only = true;
7756+
options->auth_user_pass_file = "stdin";
7757+
}
7758+
else if (p[1])
77467759
{
77477760
options->auth_user_pass_file = p[1];
77487761
options->auth_user_pass_file_inline = is_inline;

src/openvpn/options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ struct options
557557
unsigned int push_update_options_found; /* tracks which option types have been reset in current PUSH_UPDATE sequence */
558558
const char *auth_user_pass_file;
559559
bool auth_user_pass_file_inline;
560+
bool auth_user_pass_username_only;
560561
struct options_pre_connect *pre_connect;
561562

562563
int scheduled_exit_interval;

src/openvpn/ssl.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,19 @@ enable_auth_user_pass(void)
290290
}
291291

292292
void
293-
auth_user_pass_setup(const char *auth_file, bool is_inline, const struct static_challenge_info *sci)
293+
auth_user_pass_setup(const char *auth_file, bool is_inline, bool username_only,
294+
const struct static_challenge_info *sci)
294295
{
295296
unsigned int flags = GET_USER_PASS_MANAGEMENT;
296297

297298
if (is_inline)
298299
{
299300
flags |= GET_USER_PASS_INLINE_CREDS;
300301
}
302+
if (username_only)
303+
{
304+
flags |= GET_USER_PASS_USERNAME_ONLY;
305+
}
301306

302307
if (!auth_user_pass.defined && !auth_token.defined)
303308
{
@@ -2099,10 +2104,12 @@ key_method_2_write(struct buffer *buf, struct tls_multi *multi, struct tls_sessi
20992104
{
21002105
#ifdef ENABLE_MANAGEMENT
21012106
auth_user_pass_setup(session->opt->auth_user_pass_file,
2102-
session->opt->auth_user_pass_file_inline, session->opt->sci);
2107+
session->opt->auth_user_pass_file_inline,
2108+
session->opt->auth_user_pass_username_only, session->opt->sci);
21032109
#else
21042110
auth_user_pass_setup(session->opt->auth_user_pass_file,
2105-
session->opt->auth_user_pass_file_inline, NULL);
2111+
session->opt->auth_user_pass_file_inline,
2112+
session->opt->auth_user_pass_username_only, NULL);
21062113
#endif
21072114
struct user_pass *up = &auth_user_pass;
21082115

0 commit comments

Comments
 (0)