[auth.h auth2-chall.c auth2.c monitor.c sshd_config.5]
     add submethod support to AuthenticationMethods; ok and freedback djm@
This commit is contained in:
Damien Miller 2013-04-23 15:18:10 +10:00
parent 4ce189d910
commit 91a55f28f3
6 changed files with 91 additions and 34 deletions

View File

@ -19,6 +19,9 @@
have included a style (e.g. "root:skey") when checking public key have included a style (e.g. "root:skey") when checking public key
signatures. Fixes public key and hostbased auth when the client specified signatures. Fixes public key and hostbased auth when the client specified
a style; ok markus@ a style; ok markus@
- markus@cvs.openbsd.org 2013/03/07 19:27:25
[auth.h auth2-chall.c auth2.c monitor.c sshd_config.5]
add submethod support to AuthenticationMethods; ok and freedback djm@
20130418 20130418
- (djm) [config.guess config.sub] Update to last versions before they switch - (djm) [config.guess config.sub] Update to last versions before they switch

5
auth.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.72 2012/12/02 20:34:09 djm Exp $ */ /* $OpenBSD: auth.h,v 1.73 2013/03/07 19:27:25 markus Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -157,8 +157,9 @@ void userauth_send_banner(const char *);
char *auth2_read_banner(void); char *auth2_read_banner(void);
int auth2_methods_valid(const char *, int); int auth2_methods_valid(const char *, int);
int auth2_update_methods_lists(Authctxt *, const char *); int auth2_update_methods_lists(Authctxt *, const char *, const char *);
int auth2_setup_methods_lists(Authctxt *); int auth2_setup_methods_lists(Authctxt *);
int auth2_method_allowed(Authctxt *, const char *, const char *);
void privsep_challenge_enable(void); void privsep_challenge_enable(void);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-chall.c,v 1.36 2012/12/03 00:14:06 djm Exp $ */ /* $OpenBSD: auth2-chall.c,v 1.37 2013/03/07 19:27:25 markus Exp $ */
/* /*
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Per Allansson. All rights reserved. * Copyright (c) 2001 Per Allansson. All rights reserved.
@ -155,7 +155,7 @@ kbdint_free(KbdintAuthctxt *kbdintctxt)
} }
/* get next device */ /* get next device */
static int static int
kbdint_next_device(KbdintAuthctxt *kbdintctxt) kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
{ {
size_t len; size_t len;
char *t; char *t;
@ -169,9 +169,13 @@ kbdint_next_device(KbdintAuthctxt *kbdintctxt)
if (len == 0) if (len == 0)
break; break;
for (i = 0; devices[i]; i++) for (i = 0; devices[i]; i++) {
if (!auth2_method_allowed(authctxt,
"keyboard-interactive", devices[i]->name))
continue;
if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0) if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
kbdintctxt->device = devices[i]; kbdintctxt->device = devices[i];
}
t = kbdintctxt->devices; t = kbdintctxt->devices;
kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL; kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
xfree(t); xfree(t);
@ -221,7 +225,7 @@ auth2_challenge_start(Authctxt *authctxt)
debug2("auth2_challenge_start: devices %s", debug2("auth2_challenge_start: devices %s",
kbdintctxt->devices ? kbdintctxt->devices : "<empty>"); kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
if (kbdint_next_device(kbdintctxt) == 0) { if (kbdint_next_device(authctxt, kbdintctxt) == 0) {
auth2_challenge_stop(authctxt); auth2_challenge_stop(authctxt);
return 0; return 0;
} }

76
auth2.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2.c,v 1.126 2012/12/02 20:34:09 djm Exp $ */ /* $OpenBSD: auth2.c,v 1.127 2013/03/07 19:27:25 markus Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -98,8 +98,12 @@ static void input_userauth_request(int, u_int32_t, void *);
/* helper */ /* helper */
static Authmethod *authmethod_lookup(Authctxt *, const char *); static Authmethod *authmethod_lookup(Authctxt *, const char *);
static char *authmethods_get(Authctxt *authctxt); static char *authmethods_get(Authctxt *authctxt);
static int method_allowed(Authctxt *, const char *);
static int list_starts_with(const char *, const char *); #define MATCH_NONE 0 /* method or submethod mismatch */
#define MATCH_METHOD 1 /* method matches (no submethod specified) */
#define MATCH_BOTH 2 /* method and submethod match */
#define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
static int list_starts_with(const char *, const char *, const char *);
char * char *
auth2_read_banner(void) auth2_read_banner(void)
@ -316,7 +320,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
} }
if (authenticated && options.num_auth_methods != 0) { if (authenticated && options.num_auth_methods != 0) {
if (!auth2_update_methods_lists(authctxt, method)) { if (!auth2_update_methods_lists(authctxt, method, submethod)) {
authenticated = 0; authenticated = 0;
partial = 1; partial = 1;
} }
@ -387,8 +391,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
* methods list. Returns 1 if allowed, or no methods lists configured. * methods list. Returns 1 if allowed, or no methods lists configured.
* 0 otherwise. * 0 otherwise.
*/ */
static int int
method_allowed(Authctxt *authctxt, const char *method) auth2_method_allowed(Authctxt *authctxt, const char *method,
const char *submethod)
{ {
u_int i; u_int i;
@ -399,7 +404,8 @@ method_allowed(Authctxt *authctxt, const char *method)
if (options.num_auth_methods == 0) if (options.num_auth_methods == 0)
return 1; return 1;
for (i = 0; i < authctxt->num_auth_methods; i++) { for (i = 0; i < authctxt->num_auth_methods; i++) {
if (list_starts_with(authctxt->auth_methods[i], method)) if (list_starts_with(authctxt->auth_methods[i], method,
submethod) != MATCH_NONE)
return 1; return 1;
} }
return 0; return 0;
@ -419,7 +425,8 @@ authmethods_get(Authctxt *authctxt)
if (authmethods[i]->enabled == NULL || if (authmethods[i]->enabled == NULL ||
*(authmethods[i]->enabled) == 0) *(authmethods[i]->enabled) == 0)
continue; continue;
if (!method_allowed(authctxt, authmethods[i]->name)) if (!auth2_method_allowed(authctxt, authmethods[i]->name,
NULL))
continue; continue;
if (buffer_len(&b) > 0) if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1); buffer_append(&b, ",", 1);
@ -442,7 +449,8 @@ authmethod_lookup(Authctxt *authctxt, const char *name)
if (authmethods[i]->enabled != NULL && if (authmethods[i]->enabled != NULL &&
*(authmethods[i]->enabled) != 0 && *(authmethods[i]->enabled) != 0 &&
strcmp(name, authmethods[i]->name) == 0 && strcmp(name, authmethods[i]->name) == 0 &&
method_allowed(authctxt, authmethods[i]->name)) auth2_method_allowed(authctxt,
authmethods[i]->name, NULL))
return authmethods[i]; return authmethods[i];
debug2("Unrecognized authentication method name: %s", debug2("Unrecognized authentication method name: %s",
name ? name : "NULL"); name ? name : "NULL");
@ -457,7 +465,7 @@ authmethod_lookup(Authctxt *authctxt, const char *name)
int int
auth2_methods_valid(const char *_methods, int need_enable) auth2_methods_valid(const char *_methods, int need_enable)
{ {
char *methods, *omethods, *method; char *methods, *omethods, *method, *p;
u_int i, found; u_int i, found;
int ret = -1; int ret = -1;
@ -468,6 +476,8 @@ auth2_methods_valid(const char *_methods, int need_enable)
omethods = methods = xstrdup(_methods); omethods = methods = xstrdup(_methods);
while ((method = strsep(&methods, ",")) != NULL) { while ((method = strsep(&methods, ",")) != NULL) {
for (found = i = 0; !found && authmethods[i] != NULL; i++) { for (found = i = 0; !found && authmethods[i] != NULL; i++) {
if ((p = strchr(method, ':')) != NULL)
*p = '\0';
if (strcmp(method, authmethods[i]->name) != 0) if (strcmp(method, authmethods[i]->name) != 0)
continue; continue;
if (need_enable) { if (need_enable) {
@ -533,15 +543,30 @@ auth2_setup_methods_lists(Authctxt *authctxt)
} }
static int static int
list_starts_with(const char *methods, const char *method) list_starts_with(const char *methods, const char *method,
const char *submethod)
{ {
size_t l = strlen(method); size_t l = strlen(method);
int match;
const char *p;
if (strncmp(methods, method, l) != 0) if (strncmp(methods, method, l) != 0)
return 0; return MATCH_NONE;
if (methods[l] != ',' && methods[l] != '\0') p = methods + l;
return 0; match = MATCH_METHOD;
return 1; if (*p == ':') {
if (!submethod)
return MATCH_PARTIAL;
l = strlen(submethod);
p += 1;
if (strncmp(submethod, p, l))
return MATCH_NONE;
p += l;
match = MATCH_BOTH;
}
if (*p != ',' && *p != '\0')
return MATCH_NONE;
return match;
} }
/* /*
@ -550,14 +575,21 @@ list_starts_with(const char *methods, const char *method)
* if it did. * if it did.
*/ */
static int static int
remove_method(char **methods, const char *method) remove_method(char **methods, const char *method, const char *submethod)
{ {
char *omethods = *methods; char *omethods = *methods, *p;
size_t l = strlen(method); size_t l = strlen(method);
int match;
if (!list_starts_with(omethods, method)) match = list_starts_with(omethods, method, submethod);
if (match != MATCH_METHOD && match != MATCH_BOTH)
return 0; return 0;
*methods = xstrdup(omethods + l + (omethods[l] == ',' ? 1 : 0)); p = omethods + l;
if (submethod && match == MATCH_BOTH)
p += 1 + strlen(submethod); /* include colon */
if (*p == ',')
p++;
*methods = xstrdup(p);
free(omethods); free(omethods);
return 1; return 1;
} }
@ -569,13 +601,15 @@ remove_method(char **methods, const char *method)
* Returns 1 if the method completed any authentication list or 0 otherwise. * Returns 1 if the method completed any authentication list or 0 otherwise.
*/ */
int int
auth2_update_methods_lists(Authctxt *authctxt, const char *method) auth2_update_methods_lists(Authctxt *authctxt, const char *method,
const char *submethod)
{ {
u_int i, found = 0; u_int i, found = 0;
debug3("%s: updating methods list after \"%s\"", __func__, method); debug3("%s: updating methods list after \"%s\"", __func__, method);
for (i = 0; i < authctxt->num_auth_methods; i++) { for (i = 0; i < authctxt->num_auth_methods; i++) {
if (!remove_method(&(authctxt->auth_methods[i]), method)) if (!remove_method(&(authctxt->auth_methods[i]), method,
submethod))
continue; continue;
found = 1; found = 1;
if (*authctxt->auth_methods[i] == '\0') { if (*authctxt->auth_methods[i] == '\0') {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.121 2013/03/07 00:19:59 djm Exp $ */ /* $OpenBSD: monitor.c,v 1.122 2013/03/07 19:27:25 markus Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -392,7 +392,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
"with SSH protocol 1"); "with SSH protocol 1");
if (authenticated && if (authenticated &&
!auth2_update_methods_lists(authctxt, !auth2_update_methods_lists(authctxt,
auth_method)) { auth_method, auth_submethod)) {
debug3("%s: method %s: partial", __func__, debug3("%s: method %s: partial", __func__,
auth_method); auth_method);
authenticated = 0; authenticated = 0;
@ -949,9 +949,10 @@ mm_answer_bsdauthrespond(int sock, Buffer *m)
debug3("%s: sending authenticated: %d", __func__, authok); debug3("%s: sending authenticated: %d", __func__, authok);
mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m); mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m);
if (compat20) if (compat20) {
auth_method = "keyboard-interactive"; /* XXX auth_submethod */ auth_method = "keyboard-interactive";
else auth_submethod = "bsdauth";
} else
auth_method = "bsdauth"; auth_method = "bsdauth";
return (authok != 0); return (authok != 0);

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd_config.5,v 1.156 2013/02/06 00:20:42 dtucker Exp $ .\" $OpenBSD: sshd_config.5,v 1.157 2013/03/07 19:27:25 markus Exp $
.Dd $Mdocdate: February 6 2013 $ .Dd $Mdocdate: March 7 2013 $
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -180,6 +180,20 @@ Only methods that are next in one or more lists are offered at each stage,
so for this example, it would not be possible to attempt password or so for this example, it would not be possible to attempt password or
keyboard-interactive authentication before public key. keyboard-interactive authentication before public key.
.Pp .Pp
For keyboard interactive authentication it is also possible to
restrict authentication to a specific device by appending a
colon followed by the device identifier
.Dq bsdauth ,
.Dq pam ,
or
.Dq skey ,
depending on the server configuration.
For example,
.Dq keyboard-interactive:bsdauth
would restrict keyboard interactive authentication to the
.Dq bsdauth
device.
.Pp
This option is only available for SSH protocol 2 and will yield a fatal This option is only available for SSH protocol 2 and will yield a fatal
error if enabled if protocol 1 is also enabled. error if enabled if protocol 1 is also enabled.
Note that each authentication method listed should also be explicitly enabled Note that each authentication method listed should also be explicitly enabled