summaryrefslogtreecommitdiff
path: root/auth2.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2013-05-07 10:06:42 +0100
committerColin Watson <cjwatson@debian.org>2013-05-07 10:06:42 +0100
commitecebda56da46a03dafff923d91c382f31faa9eec (patch)
tree449614b6c06a2622c74a609b31fcc46c60037c56 /auth2.c
parentc6a2c0334e45419875687d250aed9bea78480f2e (diff)
parentffc06452028ba78cd693d4ed43df8b60a10d6163 (diff)
merge 6.2p1; reorder additions to monitor.h for easier merging in future
Diffstat (limited to 'auth2.c')
-rw-r--r--auth2.c239
1 files changed, 212 insertions, 27 deletions
diff --git a/auth2.c b/auth2.c
index 4313e9f26..d25940036 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2.c,v 1.124 2011/12/07 05:44:38 djm Exp $ */ 1/* $OpenBSD: auth2.c,v 1.126 2012/12/02 20:34:09 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -98,8 +98,10 @@ static void input_service_request(int, u_int32_t, void *);
98static void input_userauth_request(int, u_int32_t, void *); 98static void input_userauth_request(int, u_int32_t, void *);
99 99
100/* helper */ 100/* helper */
101static Authmethod *authmethod_lookup(const char *); 101static Authmethod *authmethod_lookup(Authctxt *, const char *);
102static char *authmethods_get(void); 102static char *authmethods_get(Authctxt *authctxt);
103static int method_allowed(Authctxt *, const char *);
104static int list_starts_with(const char *, const char *);
103 105
104char * 106char *
105auth2_read_banner(void) 107auth2_read_banner(void)
@@ -257,6 +259,8 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
257 if (use_privsep) 259 if (use_privsep)
258 mm_inform_authserv(service, style); 260 mm_inform_authserv(service, style);
259 userauth_banner(); 261 userauth_banner();
262 if (auth2_setup_methods_lists(authctxt) != 0)
263 packet_disconnect("no authentication methods enabled");
260 } else if (strcmp(user, authctxt->user) != 0 || 264 } else if (strcmp(user, authctxt->user) != 0 ||
261 strcmp(service, authctxt->service) != 0) { 265 strcmp(service, authctxt->service) != 0) {
262 packet_disconnect("Change of username or service not allowed: " 266 packet_disconnect("Change of username or service not allowed: "
@@ -279,12 +283,12 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
279 authctxt->server_caused_failure = 0; 283 authctxt->server_caused_failure = 0;
280 284
281 /* try to authenticate user */ 285 /* try to authenticate user */
282 m = authmethod_lookup(method); 286 m = authmethod_lookup(authctxt, method);
283 if (m != NULL && authctxt->failures < options.max_authtries) { 287 if (m != NULL && authctxt->failures < options.max_authtries) {
284 debug2("input_userauth_request: try method %s", method); 288 debug2("input_userauth_request: try method %s", method);
285 authenticated = m->userauth(authctxt); 289 authenticated = m->userauth(authctxt);
286 } 290 }
287 userauth_finish(authctxt, authenticated, method); 291 userauth_finish(authctxt, authenticated, method, NULL);
288 292
289 xfree(service); 293 xfree(service);
290 xfree(user); 294 xfree(user);
@@ -292,13 +296,17 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
292} 296}
293 297
294void 298void
295userauth_finish(Authctxt *authctxt, int authenticated, char *method) 299userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
300 const char *submethod)
296{ 301{
297 char *methods; 302 char *methods;
303 int partial = 0;
298 304
299 if (!authctxt->valid && authenticated) 305 if (!authctxt->valid && authenticated)
300 fatal("INTERNAL ERROR: authenticated invalid user %s", 306 fatal("INTERNAL ERROR: authenticated invalid user %s",
301 authctxt->user); 307 authctxt->user);
308 if (authenticated && authctxt->postponed)
309 fatal("INTERNAL ERROR: authenticated and postponed");
302 310
303 /* Special handling for root */ 311 /* Special handling for root */
304 if (authenticated && authctxt->pw->pw_uid == 0 && 312 if (authenticated && authctxt->pw->pw_uid == 0 &&
@@ -309,6 +317,19 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
309#endif 317#endif
310 } 318 }
311 319
320 if (authenticated && options.num_auth_methods != 0) {
321 if (!auth2_update_methods_lists(authctxt, method)) {
322 authenticated = 0;
323 partial = 1;
324 }
325 }
326
327 /* Log before sending the reply */
328 auth_log(authctxt, authenticated, partial, method, submethod, " ssh2");
329
330 if (authctxt->postponed)
331 return;
332
312#ifdef USE_PAM 333#ifdef USE_PAM
313 if (options.use_pam && authenticated) { 334 if (options.use_pam && authenticated) {
314 if (!PRIVSEP(do_pam_account())) { 335 if (!PRIVSEP(do_pam_account())) {
@@ -327,17 +348,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
327#ifdef _UNICOS 348#ifdef _UNICOS
328 if (authenticated && cray_access_denied(authctxt->user)) { 349 if (authenticated && cray_access_denied(authctxt->user)) {
329 authenticated = 0; 350 authenticated = 0;
330 fatal("Access denied for user %s.",authctxt->user); 351 fatal("Access denied for user %s.", authctxt->user);
331 } 352 }
332#endif /* _UNICOS */ 353#endif /* _UNICOS */
333 354
334 /* Log before sending the reply */
335 auth_log(authctxt, authenticated, method, " ssh2");
336
337 if (authctxt->postponed)
338 return;
339
340 /* XXX todo: check if multiple auth methods are needed */
341 if (authenticated == 1) { 355 if (authenticated == 1) {
342 /* turn off userauth */ 356 /* turn off userauth */
343 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 357 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
@@ -358,34 +372,61 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
358#endif 372#endif
359 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 373 packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
360 } 374 }
361 methods = authmethods_get(); 375 methods = authmethods_get(authctxt);
376 debug3("%s: failure partial=%d next methods=\"%s\"", __func__,
377 partial, methods);
362 packet_start(SSH2_MSG_USERAUTH_FAILURE); 378 packet_start(SSH2_MSG_USERAUTH_FAILURE);
363 packet_put_cstring(methods); 379 packet_put_cstring(methods);
364 packet_put_char(0); /* XXX partial success, unused */ 380 packet_put_char(partial);
365 packet_send(); 381 packet_send();
366 packet_write_wait(); 382 packet_write_wait();
367 xfree(methods); 383 xfree(methods);
368 } 384 }
369} 385}
370 386
387/*
388 * Checks whether method is allowed by at least one AuthenticationMethods
389 * methods list. Returns 1 if allowed, or no methods lists configured.
390 * 0 otherwise.
391 */
392static int
393method_allowed(Authctxt *authctxt, const char *method)
394{
395 u_int i;
396
397 /*
398 * NB. authctxt->num_auth_methods might be zero as a result of
399 * auth2_setup_methods_lists(), so check the configuration.
400 */
401 if (options.num_auth_methods == 0)
402 return 1;
403 for (i = 0; i < authctxt->num_auth_methods; i++) {
404 if (list_starts_with(authctxt->auth_methods[i], method))
405 return 1;
406 }
407 return 0;
408}
409
371static char * 410static char *
372authmethods_get(void) 411authmethods_get(Authctxt *authctxt)
373{ 412{
374 Buffer b; 413 Buffer b;
375 char *list; 414 char *list;
376 int i; 415 u_int i;
377 416
378 buffer_init(&b); 417 buffer_init(&b);
379 for (i = 0; authmethods[i] != NULL; i++) { 418 for (i = 0; authmethods[i] != NULL; i++) {
380 if (strcmp(authmethods[i]->name, "none") == 0) 419 if (strcmp(authmethods[i]->name, "none") == 0)
381 continue; 420 continue;
382 if (authmethods[i]->enabled != NULL && 421 if (authmethods[i]->enabled == NULL ||
383 *(authmethods[i]->enabled) != 0) { 422 *(authmethods[i]->enabled) == 0)
384 if (buffer_len(&b) > 0) 423 continue;
385 buffer_append(&b, ",", 1); 424 if (!method_allowed(authctxt, authmethods[i]->name))
386 buffer_append(&b, authmethods[i]->name, 425 continue;
387 strlen(authmethods[i]->name)); 426 if (buffer_len(&b) > 0)
388 } 427 buffer_append(&b, ",", 1);
428 buffer_append(&b, authmethods[i]->name,
429 strlen(authmethods[i]->name));
389 } 430 }
390 buffer_append(&b, "\0", 1); 431 buffer_append(&b, "\0", 1);
391 list = xstrdup(buffer_ptr(&b)); 432 list = xstrdup(buffer_ptr(&b));
@@ -394,7 +435,7 @@ authmethods_get(void)
394} 435}
395 436
396static Authmethod * 437static Authmethod *
397authmethod_lookup(const char *name) 438authmethod_lookup(Authctxt *authctxt, const char *name)
398{ 439{
399 int i; 440 int i;
400 441
@@ -402,10 +443,154 @@ authmethod_lookup(const char *name)
402 for (i = 0; authmethods[i] != NULL; i++) 443 for (i = 0; authmethods[i] != NULL; i++)
403 if (authmethods[i]->enabled != NULL && 444 if (authmethods[i]->enabled != NULL &&
404 *(authmethods[i]->enabled) != 0 && 445 *(authmethods[i]->enabled) != 0 &&
405 strcmp(name, authmethods[i]->name) == 0) 446 strcmp(name, authmethods[i]->name) == 0 &&
447 method_allowed(authctxt, authmethods[i]->name))
406 return authmethods[i]; 448 return authmethods[i];
407 debug2("Unrecognized authentication method name: %s", 449 debug2("Unrecognized authentication method name: %s",
408 name ? name : "NULL"); 450 name ? name : "NULL");
409 return NULL; 451 return NULL;
410} 452}
411 453
454/*
455 * Check a comma-separated list of methods for validity. Is need_enable is
456 * non-zero, then also require that the methods are enabled.
457 * Returns 0 on success or -1 if the methods list is invalid.
458 */
459int
460auth2_methods_valid(const char *_methods, int need_enable)
461{
462 char *methods, *omethods, *method;
463 u_int i, found;
464 int ret = -1;
465
466 if (*_methods == '\0') {
467 error("empty authentication method list");
468 return -1;
469 }
470 omethods = methods = xstrdup(_methods);
471 while ((method = strsep(&methods, ",")) != NULL) {
472 for (found = i = 0; !found && authmethods[i] != NULL; i++) {
473 if (strcmp(method, authmethods[i]->name) != 0)
474 continue;
475 if (need_enable) {
476 if (authmethods[i]->enabled == NULL ||
477 *(authmethods[i]->enabled) == 0) {
478 error("Disabled method \"%s\" in "
479 "AuthenticationMethods list \"%s\"",
480 method, _methods);
481 goto out;
482 }
483 }
484 found = 1;
485 break;
486 }
487 if (!found) {
488 error("Unknown authentication method \"%s\" in list",
489 method);
490 goto out;
491 }
492 }
493 ret = 0;
494 out:
495 free(omethods);
496 return ret;
497}
498
499/*
500 * Prune the AuthenticationMethods supplied in the configuration, removing
501 * any methods lists that include disabled methods. Note that this might
502 * leave authctxt->num_auth_methods == 0, even when multiple required auth
503 * has been requested. For this reason, all tests for whether multiple is
504 * enabled should consult options.num_auth_methods directly.
505 */
506int
507auth2_setup_methods_lists(Authctxt *authctxt)
508{
509 u_int i;
510
511 if (options.num_auth_methods == 0)
512 return 0;
513 debug3("%s: checking methods", __func__);
514 authctxt->auth_methods = xcalloc(options.num_auth_methods,
515 sizeof(*authctxt->auth_methods));
516 authctxt->num_auth_methods = 0;
517 for (i = 0; i < options.num_auth_methods; i++) {
518 if (auth2_methods_valid(options.auth_methods[i], 1) != 0) {
519 logit("Authentication methods list \"%s\" contains "
520 "disabled method, skipping",
521 options.auth_methods[i]);
522 continue;
523 }
524 debug("authentication methods list %d: %s",
525 authctxt->num_auth_methods, options.auth_methods[i]);
526 authctxt->auth_methods[authctxt->num_auth_methods++] =
527 xstrdup(options.auth_methods[i]);
528 }
529 if (authctxt->num_auth_methods == 0) {
530 error("No AuthenticationMethods left after eliminating "
531 "disabled methods");
532 return -1;
533 }
534 return 0;
535}
536
537static int
538list_starts_with(const char *methods, const char *method)
539{
540 size_t l = strlen(method);
541
542 if (strncmp(methods, method, l) != 0)
543 return 0;
544 if (methods[l] != ',' && methods[l] != '\0')
545 return 0;
546 return 1;
547}
548
549/*
550 * Remove method from the start of a comma-separated list of methods.
551 * Returns 0 if the list of methods did not start with that method or 1
552 * if it did.
553 */
554static int
555remove_method(char **methods, const char *method)
556{
557 char *omethods = *methods;
558 size_t l = strlen(method);
559
560 if (!list_starts_with(omethods, method))
561 return 0;
562 *methods = xstrdup(omethods + l + (omethods[l] == ',' ? 1 : 0));
563 free(omethods);
564 return 1;
565}
566
567/*
568 * Called after successful authentication. Will remove the successful method
569 * from the start of each list in which it occurs. If it was the last method
570 * in any list, then authentication is deemed successful.
571 * Returns 1 if the method completed any authentication list or 0 otherwise.
572 */
573int
574auth2_update_methods_lists(Authctxt *authctxt, const char *method)
575{
576 u_int i, found = 0;
577
578 debug3("%s: updating methods list after \"%s\"", __func__, method);
579 for (i = 0; i < authctxt->num_auth_methods; i++) {
580 if (!remove_method(&(authctxt->auth_methods[i]), method))
581 continue;
582 found = 1;
583 if (*authctxt->auth_methods[i] == '\0') {
584 debug2("authentication methods list %d complete", i);
585 return 1;
586 }
587 debug3("authentication methods list %d remaining: \"%s\"",
588 i, authctxt->auth_methods[i]);
589 }
590 /* This should not happen, but would be bad if it did */
591 if (!found)
592 fatal("%s: method not in AuthenticationMethods", __func__);
593 return 0;
594}
595
596