Requiring multiple auth mechanisms
Scott Omar Burch
scott.burch at camberwind.com
Thu Apr 8 03:53:53 EST 2004
Jeff,
You might also want to look at the code for auth selection that was
written here:
http://sweb.cz/v_t_m/ (This individual also has written patches for
securid that work very well).
-Scott
Jefferson Ogata wrote:
> I looked around for a while, but couldn't find any code for requiring
> multiple authentication mechanisms in openssh. So I wrote an implemention.
>
> I thought at first I should change the PasswordAuthentication,
> PubkeyAuthentication, etc. keywords to allow no/yes/required. But
> there's some funky stuff in auth2.c with respect to keyboard interactive
> auth that would make this kind of gnarly, semantics-wise.
>
> I also thought about providing a new keyword to specify a list of
> required authentication mechanisms. But then you have to make sure those
> mechanisms are also enabled, and it's easy to write conflicting
> configurations. In addition, if a list of required auth mechs is given,
> then enabling mechanisms that are not required is pointless, because
> they won't be sufficient.
>
> So my final decision, for the sake of simplicity, was to add a
> "NumRequiredAuthMethods" keyword, which defaults to 1. If you set it to
> 2, the client must pass at least two of the enabled auth methods. I'm
> using the term "methods" here because I'm only counting general auth
> methods as defined in auth2.c's "authmethods" array, namely publickey,
> password, keyboard-interactive, and hostbased. So there may be multiple
> types of keyboard-interactive auth, but keyboard-interactive only counts
> as a single method.
>
> So, for example, if you have PasswordAuthentication and
> PubkeyAuthentication enabled, and set NumRequiredAuthMethods to 2, you
> will have to pass both types. But PAMAuthenticationViaKbdInt and
> ChallengeResponseAuthentication are the same authentication method
> (keyboard-interactive), so if you want to require 2 classes, you'll have
> to have at least one of the other methods enabled as well.
>
> I don't know much about some of the supported authentication types,
> particularly pam, so I'm not totally sure my approach makes sense for
> everyone's needs. My particular need was to require both public key and
> S/KEY factors so that one-time passwords can be combined with a strong
> electronic authenticator. I don't trust my users not to end up trojaned
> with a keylogger, so I need OTP, but I also want a public key in case
> someone loses his S/KEY cheat sheet.
>
> The attached patch is designed for Red Hat's openssh-3.1p1-14 SRPM (add
> as Patch14, use -p1 on patch line in %prep). It should work against
> openssh-3.8 with slight tweaks (authmethods changed in auth2.c). If
> people need a patch against 3.8, I can build it; just ask.
>
> I would really appreciate it if anyone with interest could vet this for
> stupid mistakes.
>
>
> ------------------------------------------------------------------------
>
> --- openssh-3.1p1/auth.h.multipleauth Wed Apr 7 11:34:32 2004
> +++ openssh-3.1p1/auth.h Wed Apr 7 11:34:15 2004
> @@ -51,6 +51,7 @@
> int valid;
> int attempt;
> int failures;
> + int passed;
> char *user;
> char *service;
> struct passwd *pw;
> --- openssh-3.1p1/auth2.c.multipleauth Wed Apr 7 12:55:00 2004
> +++ openssh-3.1p1/auth2.c Wed Apr 7 13:42:46 2004
> @@ -74,7 +74,7 @@
>
> /* helper */
> static Authmethod *authmethod_lookup(const char *);
> -static char *authmethods_get(void);
> +static char *authmethods_get(int);
> static int user_key_allowed(struct passwd *, Key *);
> static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
>
> @@ -229,6 +229,7 @@
> userauth_finish(Authctxt *authctxt, int authenticated, char *method)
> {
> char *methods;
> + int success = 0;
>
> if (!authctxt->valid && authenticated)
> fatal("INTERNAL ERROR: authenticated invalid user %s",
> @@ -251,15 +252,22 @@
> if (authctxt->postponed)
> return;
>
> - /* XXX todo: check if multiple auth methods are needed */
> + /* Check if enough auth methods have passed */
> if (authenticated == 1) {
> - /* turn off userauth */
> - dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
> - packet_start(SSH2_MSG_USERAUTH_SUCCESS);
> - packet_send();
> - packet_write_wait();
> - /* now we can break out */
> - authctxt->success = 1;
> + Authmethod *a;
> + int passed;
> + int k;
> +
> + for (a = authmethods, k = 1, passed = 0; a->name != NULL; a++, k <<= 1) {
> + if (strncmp (method, a->name, strlen (a->name)) == 0)
> + authctxt->passed |= k;
> + if (authctxt->passed & k)
> + ++passed;
> + }
> + if (passed < options.num_required_auth_methods) {
> + success = 1;
> + authenticated = 0;
> + }
> } else {
> if (authctxt->failures++ > AUTH_FAIL_MAX) {
> #ifdef WITH_AIXAUTHENTICATE
> @@ -269,10 +277,21 @@
> #endif /* WITH_AIXAUTHENTICATE */
> packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
> }
> - methods = authmethods_get();
> + }
> +
> + if (authenticated == 1) {
> + /* turn off userauth */
> + dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
> + packet_start(SSH2_MSG_USERAUTH_SUCCESS);
> + packet_send();
> + packet_write_wait();
> + /* now we can break out */
> + authctxt->success = 1;
> + } else {
> + methods = authmethods_get(authctxt->passed);
> packet_start(SSH2_MSG_USERAUTH_FAILURE);
> packet_put_cstring(methods);
> - packet_put_char(0); /* XXX partial success, unused */
> + packet_put_char(success);
> packet_send();
> packet_write_wait();
> xfree(methods);
> @@ -599,16 +618,19 @@
> #define DELIM ","
>
> static char *
> -authmethods_get(void)
> +authmethods_get(int passed)
> {
> Authmethod *method = NULL;
> Buffer b;
> char *list;
> + int k;
>
> buffer_init(&b);
> - for (method = authmethods; method->name != NULL; method++) {
> + for (method = authmethods, k = 1; method->name != NULL; method++, k <<= 1) {
> if (strcmp(method->name, "none") == 0)
> continue;
> + if (passed & k)
> + continue;
> if (method->enabled != NULL && *(method->enabled) != 0) {
> if (buffer_len(&b) > 0)
> buffer_append(&b, ",", 1);
> --- openssh-3.1p1/servconf.h.multipleauth Tue Mar 5 01:53:05 2002
> +++ openssh-3.1p1/servconf.h Wed Apr 7 12:53:38 2004
> @@ -95,6 +95,8 @@
> * authentication. */
> int kbd_interactive_authentication; /* If true, permit */
> int challenge_response_authentication;
> + int num_required_auth_methods; /* Minimum number of auth methods
> + * that must succeed. */
> int permit_empty_passwd; /* If false, do not permit empty
> * passwords. */
> int use_login; /* If true, login(1) is used */
> --- openssh-3.1p1/servconf.c.multipleauth Tue Feb 5 01:26:35 2002
> +++ openssh-3.1p1/servconf.c Wed Apr 7 11:42:21 2004
> @@ -89,6 +89,7 @@
> options->password_authentication = -1;
> options->kbd_interactive_authentication = -1;
> options->challenge_response_authentication = -1;
> + options->num_required_auth_methods = -1;
> options->permit_empty_passwd = -1;
> options->use_login = -1;
> options->allow_tcp_forwarding = -1;
> @@ -206,6 +207,8 @@
> options->kbd_interactive_authentication = 0;
> if (options->challenge_response_authentication == -1)
> options->challenge_response_authentication = 1;
> + if (options->num_required_auth_methods == -1)
> + options->num_required_auth_methods = 1;
> if (options->permit_empty_passwd == -1)
> options->permit_empty_passwd = 0;
> if (options->use_login == -1)
> @@ -255,6 +258,7 @@
> #ifdef AFS
> sAFSTokenPassing,
> #endif
> + sNumRequiredAuthMethods,
> sChallengeResponseAuthentication,
> sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
> sPrintMotd, sPrintLastLog, sIgnoreRhosts,
> @@ -310,6 +314,7 @@
> { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
> { "challengeresponseauthentication", sChallengeResponseAuthentication },
> { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
> + { "numrequiredauthmethods", sNumRequiredAuthMethods },
> { "checkmail", sDeprecated },
> { "listenaddress", sListenAddress },
> { "printmotd", sPrintMotd },
> @@ -644,6 +649,10 @@
> intptr = &options->challenge_response_authentication;
> goto parse_flag;
>
> + case sNumRequiredAuthMethods:
> + intptr = &options->num_required_auth_methods;
> + goto parse_int;
> +
> case sPrintMotd:
> intptr = &options->print_motd;
> goto parse_flag;
> --- openssh-3.1p1/sshd.8.multipleauth Tue Mar 5 01:38:59 2002
> +++ openssh-3.1p1/sshd.8 Wed Apr 7 12:37:34 2004
> @@ -680,6 +680,12 @@
> are refused if the number of unauthenticated connections reaches
> .Dq full
> (60).
> +.It Cm NumRequiredAuthMethods
> +Specifies how many authentication methods must succeed during ssh2
> +authentication. There are four potential methods: publickey, password,
> +keyboard-interactive, and hostbased. Setting this value to 2 or higher forces
> +the client to successfully authenticate in multiple ways, for example, using
> +both S/Key and publickey.
> .It Cm PAMAuthenticationViaKbdInt
> Specifies whether PAM challenge response authentication is allowed. This
> allows the use of most PAM challenge response authentication modules, but
> --- openssh-3.1p1/sshd_config.multipleauth Wed Apr 7 00:20:43 2004
> +++ openssh-3.1p1/sshd_config Wed Apr 7 12:39:23 2004
> @@ -60,6 +60,10 @@
> # Change to no to disable s/key passwords
> #ChallengeResponseAuthentication yes
>
> +# Change to require multiple authentication types, e.g. password and
> +# publickey.
> +#NumRequiredAuthMethods 1
> +
> # Kerberos options
> # KerberosAuthentication automatically enabled if keyfile exists
> #KerberosAuthentication yes
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev at mindrot.org
> http://www.mindrot.org/mailman/listinfo/openssh-unix-dev
More information about the openssh-unix-dev
mailing list