diff options
author | Colin Watson <cjwatson@debian.org> | 2017-10-04 11:23:58 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2017-10-05 23:58:12 +0100 |
commit | 0556ea972b15607b7e13ff31bc05840881c91dd3 (patch) | |
tree | d6b8d48062d0278b5ae0eeff42d0e9afa9f26860 /auth2.c | |
parent | db2122d97eb1ecdd8d99b7bf79b0dd2b5addfd92 (diff) | |
parent | 801a62eedaaf47b20dbf4b426dc3e084bf0c8d49 (diff) |
New upstream release (7.6p1)
Diffstat (limited to 'auth2.c')
-rw-r--r-- | auth2.c | 173 |
1 files changed, 153 insertions, 20 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2.c,v 1.137 2017/02/03 23:05:57 djm Exp $ */ | 1 | /* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -30,6 +30,7 @@ | |||
30 | #include <sys/uio.h> | 30 | #include <sys/uio.h> |
31 | 31 | ||
32 | #include <fcntl.h> | 32 | #include <fcntl.h> |
33 | #include <limits.h> | ||
33 | #include <pwd.h> | 34 | #include <pwd.h> |
34 | #include <stdarg.h> | 35 | #include <stdarg.h> |
35 | #include <string.h> | 36 | #include <string.h> |
@@ -55,6 +56,7 @@ | |||
55 | #include "ssh-gss.h" | 56 | #include "ssh-gss.h" |
56 | #endif | 57 | #endif |
57 | #include "monitor_wrap.h" | 58 | #include "monitor_wrap.h" |
59 | #include "ssherr.h" | ||
58 | 60 | ||
59 | /* import */ | 61 | /* import */ |
60 | extern ServerOptions options; | 62 | extern ServerOptions options; |
@@ -89,8 +91,8 @@ Authmethod *authmethods[] = { | |||
89 | 91 | ||
90 | /* protocol */ | 92 | /* protocol */ |
91 | 93 | ||
92 | static int input_service_request(int, u_int32_t, void *); | 94 | static int input_service_request(int, u_int32_t, struct ssh *); |
93 | static int input_userauth_request(int, u_int32_t, void *); | 95 | static int input_userauth_request(int, u_int32_t, struct ssh *); |
94 | 96 | ||
95 | /* helper */ | 97 | /* helper */ |
96 | static Authmethod *authmethod_lookup(Authctxt *, const char *); | 98 | static Authmethod *authmethod_lookup(Authctxt *, const char *); |
@@ -170,16 +172,19 @@ done: | |||
170 | void | 172 | void |
171 | do_authentication2(Authctxt *authctxt) | 173 | do_authentication2(Authctxt *authctxt) |
172 | { | 174 | { |
173 | dispatch_init(&dispatch_protocol_error); | 175 | struct ssh *ssh = active_state; /* XXX */ |
174 | dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); | 176 | ssh->authctxt = authctxt; /* XXX move to caller */ |
175 | dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); | 177 | ssh_dispatch_init(ssh, &dispatch_protocol_error); |
178 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); | ||
179 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); | ||
180 | ssh->authctxt = NULL; | ||
176 | } | 181 | } |
177 | 182 | ||
178 | /*ARGSUSED*/ | 183 | /*ARGSUSED*/ |
179 | static int | 184 | static int |
180 | input_service_request(int type, u_int32_t seq, void *ctxt) | 185 | input_service_request(int type, u_int32_t seq, struct ssh *ssh) |
181 | { | 186 | { |
182 | Authctxt *authctxt = ctxt; | 187 | Authctxt *authctxt = ssh->authctxt; |
183 | u_int len; | 188 | u_int len; |
184 | int acceptit = 0; | 189 | int acceptit = 0; |
185 | char *service = packet_get_cstring(&len); | 190 | char *service = packet_get_cstring(&len); |
@@ -192,7 +197,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt) | |||
192 | if (!authctxt->success) { | 197 | if (!authctxt->success) { |
193 | acceptit = 1; | 198 | acceptit = 1; |
194 | /* now we can handle user-auth requests */ | 199 | /* now we can handle user-auth requests */ |
195 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); | 200 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); |
196 | } | 201 | } |
197 | } | 202 | } |
198 | /* XXX all other service requests are denied */ | 203 | /* XXX all other service requests are denied */ |
@@ -212,10 +217,9 @@ input_service_request(int type, u_int32_t seq, void *ctxt) | |||
212 | 217 | ||
213 | /*ARGSUSED*/ | 218 | /*ARGSUSED*/ |
214 | static int | 219 | static int |
215 | input_userauth_request(int type, u_int32_t seq, void *ctxt) | 220 | input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) |
216 | { | 221 | { |
217 | struct ssh *ssh = active_state; /* XXX */ | 222 | Authctxt *authctxt = ssh->authctxt; |
218 | Authctxt *authctxt = ctxt; | ||
219 | Authmethod *m = NULL; | 223 | Authmethod *m = NULL; |
220 | char *user, *service, *method, *style = NULL, *role = NULL; | 224 | char *user, *service, *method, *style = NULL, *role = NULL; |
221 | int authenticated = 0; | 225 | int authenticated = 0; |
@@ -275,14 +279,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
275 | authctxt->user, authctxt->service, user, service); | 279 | authctxt->user, authctxt->service, user, service); |
276 | } | 280 | } |
277 | /* reset state */ | 281 | /* reset state */ |
278 | auth2_challenge_stop(authctxt); | 282 | auth2_challenge_stop(ssh); |
279 | 283 | ||
280 | #ifdef GSSAPI | 284 | #ifdef GSSAPI |
281 | /* XXX move to auth2_gssapi_stop() */ | 285 | /* XXX move to auth2_gssapi_stop() */ |
282 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | 286 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); |
283 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); | 287 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); |
284 | #endif | 288 | #endif |
285 | 289 | ||
290 | auth2_authctxt_reset_info(authctxt); | ||
286 | authctxt->postponed = 0; | 291 | authctxt->postponed = 0; |
287 | authctxt->server_caused_failure = 0; | 292 | authctxt->server_caused_failure = 0; |
288 | 293 | ||
@@ -290,9 +295,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
290 | m = authmethod_lookup(authctxt, method); | 295 | m = authmethod_lookup(authctxt, method); |
291 | if (m != NULL && authctxt->failures < options.max_authtries) { | 296 | if (m != NULL && authctxt->failures < options.max_authtries) { |
292 | debug2("input_userauth_request: try method %s", method); | 297 | debug2("input_userauth_request: try method %s", method); |
293 | authenticated = m->userauth(authctxt); | 298 | authenticated = m->userauth(ssh); |
294 | } | 299 | } |
295 | userauth_finish(authctxt, authenticated, method, NULL); | 300 | userauth_finish(ssh, authenticated, method, NULL); |
296 | 301 | ||
297 | free(service); | 302 | free(service); |
298 | free(user); | 303 | free(user); |
@@ -301,10 +306,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
301 | } | 306 | } |
302 | 307 | ||
303 | void | 308 | void |
304 | userauth_finish(Authctxt *authctxt, int authenticated, const char *method, | 309 | userauth_finish(struct ssh *ssh, int authenticated, const char *method, |
305 | const char *submethod) | 310 | const char *submethod) |
306 | { | 311 | { |
307 | struct ssh *ssh = active_state; /* XXX */ | 312 | Authctxt *authctxt = ssh->authctxt; |
308 | char *methods; | 313 | char *methods; |
309 | int partial = 0; | 314 | int partial = 0; |
310 | 315 | ||
@@ -333,6 +338,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, | |||
333 | /* Log before sending the reply */ | 338 | /* Log before sending the reply */ |
334 | auth_log(authctxt, authenticated, partial, method, submethod); | 339 | auth_log(authctxt, authenticated, partial, method, submethod); |
335 | 340 | ||
341 | /* Update information exposed to session */ | ||
342 | if (authenticated || partial) | ||
343 | auth2_update_session_info(authctxt, method, submethod); | ||
344 | |||
336 | if (authctxt->postponed) | 345 | if (authctxt->postponed) |
337 | return; | 346 | return; |
338 | 347 | ||
@@ -360,7 +369,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, | |||
360 | 369 | ||
361 | if (authenticated == 1) { | 370 | if (authenticated == 1) { |
362 | /* turn off userauth */ | 371 | /* turn off userauth */ |
363 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); | 372 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); |
364 | packet_start(SSH2_MSG_USERAUTH_SUCCESS); | 373 | packet_start(SSH2_MSG_USERAUTH_SUCCESS); |
365 | packet_send(); | 374 | packet_send(); |
366 | packet_write_wait(); | 375 | packet_write_wait(); |
@@ -630,4 +639,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method, | |||
630 | return 0; | 639 | return 0; |
631 | } | 640 | } |
632 | 641 | ||
642 | /* Reset method-specific information */ | ||
643 | void auth2_authctxt_reset_info(Authctxt *authctxt) | ||
644 | { | ||
645 | sshkey_free(authctxt->auth_method_key); | ||
646 | free(authctxt->auth_method_info); | ||
647 | authctxt->auth_method_key = NULL; | ||
648 | authctxt->auth_method_info = NULL; | ||
649 | } | ||
650 | |||
651 | /* Record auth method-specific information for logs */ | ||
652 | void | ||
653 | auth2_record_info(Authctxt *authctxt, const char *fmt, ...) | ||
654 | { | ||
655 | va_list ap; | ||
656 | int i; | ||
657 | |||
658 | free(authctxt->auth_method_info); | ||
659 | authctxt->auth_method_info = NULL; | ||
660 | |||
661 | va_start(ap, fmt); | ||
662 | i = vasprintf(&authctxt->auth_method_info, fmt, ap); | ||
663 | va_end(ap); | ||
664 | |||
665 | if (i < 0 || authctxt->auth_method_info == NULL) | ||
666 | fatal("%s: vasprintf failed", __func__); | ||
667 | } | ||
668 | |||
669 | /* | ||
670 | * Records a public key used in authentication. This is used for logging | ||
671 | * and to ensure that the same key is not subsequently accepted again for | ||
672 | * multiple authentication. | ||
673 | */ | ||
674 | void | ||
675 | auth2_record_key(Authctxt *authctxt, int authenticated, | ||
676 | const struct sshkey *key) | ||
677 | { | ||
678 | struct sshkey **tmp, *dup; | ||
679 | int r; | ||
680 | |||
681 | if ((r = sshkey_demote(key, &dup)) != 0) | ||
682 | fatal("%s: copy key: %s", __func__, ssh_err(r)); | ||
683 | sshkey_free(authctxt->auth_method_key); | ||
684 | authctxt->auth_method_key = dup; | ||
685 | |||
686 | if (!authenticated) | ||
687 | return; | ||
688 | |||
689 | /* If authenticated, make sure we don't accept this key again */ | ||
690 | if ((r = sshkey_demote(key, &dup)) != 0) | ||
691 | fatal("%s: copy key: %s", __func__, ssh_err(r)); | ||
692 | if (authctxt->nprev_keys >= INT_MAX || | ||
693 | (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys, | ||
694 | authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL) | ||
695 | fatal("%s: reallocarray failed", __func__); | ||
696 | authctxt->prev_keys = tmp; | ||
697 | authctxt->prev_keys[authctxt->nprev_keys] = dup; | ||
698 | authctxt->nprev_keys++; | ||
699 | |||
700 | } | ||
701 | |||
702 | /* Checks whether a key has already been previously used for authentication */ | ||
703 | int | ||
704 | auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key) | ||
705 | { | ||
706 | u_int i; | ||
707 | char *fp; | ||
708 | |||
709 | for (i = 0; i < authctxt->nprev_keys; i++) { | ||
710 | if (sshkey_equal_public(key, authctxt->prev_keys[i])) { | ||
711 | fp = sshkey_fingerprint(authctxt->prev_keys[i], | ||
712 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
713 | debug3("%s: key already used: %s %s", __func__, | ||
714 | sshkey_type(authctxt->prev_keys[i]), | ||
715 | fp == NULL ? "UNKNOWN" : fp); | ||
716 | free(fp); | ||
717 | return 1; | ||
718 | } | ||
719 | } | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * Updates authctxt->session_info with details of authentication. Should be | ||
725 | * whenever an authentication method succeeds. | ||
726 | */ | ||
727 | void | ||
728 | auth2_update_session_info(Authctxt *authctxt, const char *method, | ||
729 | const char *submethod) | ||
730 | { | ||
731 | int r; | ||
732 | |||
733 | if (authctxt->session_info == NULL) { | ||
734 | if ((authctxt->session_info = sshbuf_new()) == NULL) | ||
735 | fatal("%s: sshbuf_new", __func__); | ||
736 | } | ||
737 | |||
738 | /* Append method[/submethod] */ | ||
739 | if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s", | ||
740 | method, submethod == NULL ? "" : "/", | ||
741 | submethod == NULL ? "" : submethod)) != 0) | ||
742 | fatal("%s: append method: %s", __func__, ssh_err(r)); | ||
743 | |||
744 | /* Append key if present */ | ||
745 | if (authctxt->auth_method_key != NULL) { | ||
746 | if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || | ||
747 | (r = sshkey_format_text(authctxt->auth_method_key, | ||
748 | authctxt->session_info)) != 0) | ||
749 | fatal("%s: append key: %s", __func__, ssh_err(r)); | ||
750 | } | ||
751 | |||
752 | if (authctxt->auth_method_info != NULL) { | ||
753 | /* Ensure no ambiguity here */ | ||
754 | if (strchr(authctxt->auth_method_info, '\n') != NULL) | ||
755 | fatal("%s: auth_method_info contains \\n", __func__); | ||
756 | if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || | ||
757 | (r = sshbuf_putf(authctxt->session_info, "%s", | ||
758 | authctxt->auth_method_info)) != 0) { | ||
759 | fatal("%s: append method info: %s", | ||
760 | __func__, ssh_err(r)); | ||
761 | } | ||
762 | } | ||
763 | if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0) | ||
764 | fatal("%s: append: %s", __func__, ssh_err(r)); | ||
765 | } | ||
633 | 766 | ||