1 /* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
52 #include "pathnames.h"
58 #include "monitor_wrap.h"
62 extern ServerOptions options
;
63 extern u_char
*session_id2
;
64 extern u_int session_id2_len
;
65 extern Buffer loginmsg
;
69 extern Authmethod method_none
;
70 extern Authmethod method_pubkey
;
71 extern Authmethod method_passwd
;
72 extern Authmethod method_kbdint
;
73 extern Authmethod method_hostbased
;
75 extern Authmethod method_gssapi
;
78 Authmethod
*authmethods
[] = {
92 static int input_service_request(int, u_int32_t
, struct ssh
*);
93 static int input_userauth_request(int, u_int32_t
, struct ssh
*);
96 static Authmethod
*authmethod_lookup(Authctxt
*, const char *);
97 static char *authmethods_get(Authctxt
*authctxt
);
99 #define MATCH_NONE 0 /* method or submethod mismatch */
100 #define MATCH_METHOD 1 /* method matches (no submethod specified) */
101 #define MATCH_BOTH 2 /* method and submethod match */
102 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
103 static int list_starts_with(const char *, const char *, const char *);
106 auth2_read_banner(void)
113 if ((fd
= open(options
.banner
, O_RDONLY
)) == -1)
115 if (fstat(fd
, &st
) == -1) {
119 if (st
.st_size
<= 0 || st
.st_size
> 1*1024*1024) {
124 len
= (size_t)st
.st_size
; /* truncate */
125 banner
= xmalloc(len
+ 1);
126 n
= atomicio(read
, fd
, banner
, len
);
139 userauth_send_banner(const char *msg
)
141 if (datafellows
& SSH_BUG_BANNER
)
144 packet_start(SSH2_MSG_USERAUTH_BANNER
);
145 packet_put_cstring(msg
);
146 packet_put_cstring(""); /* language, unused */
148 debug("%s: sent", __func__
);
152 userauth_banner(void)
156 if (options
.banner
== NULL
|| (datafellows
& SSH_BUG_BANNER
) != 0)
159 if ((banner
= PRIVSEP(auth2_read_banner())) == NULL
)
161 userauth_send_banner(banner
);
168 * loop until authctxt->success == TRUE
171 do_authentication2(Authctxt
*authctxt
)
173 struct ssh
*ssh
= active_state
; /* XXX */
174 ssh
->authctxt
= authctxt
; /* XXX move to caller */
175 ssh_dispatch_init(ssh
, &dispatch_protocol_error
);
176 ssh_dispatch_set(ssh
, SSH2_MSG_SERVICE_REQUEST
, &input_service_request
);
177 ssh_dispatch_run_fatal(ssh
, DISPATCH_BLOCK
, &authctxt
->success
);
178 ssh
->authctxt
= NULL
;
183 input_service_request(int type
, u_int32_t seq
, struct ssh
*ssh
)
185 Authctxt
*authctxt
= ssh
->authctxt
;
188 char *service
= packet_get_cstring(&len
);
191 if (authctxt
== NULL
)
192 fatal("input_service_request: no authctxt");
194 if (strcmp(service
, "ssh-userauth") == 0) {
195 if (!authctxt
->success
) {
197 /* now we can handle user-auth requests */
198 ssh_dispatch_set(ssh
, SSH2_MSG_USERAUTH_REQUEST
, &input_userauth_request
);
201 /* XXX all other service requests are denied */
204 packet_start(SSH2_MSG_SERVICE_ACCEPT
);
205 packet_put_cstring(service
);
209 debug("bad service request %s", service
);
210 packet_disconnect("bad service request %s", service
);
218 input_userauth_request(int type
, u_int32_t seq
, struct ssh
*ssh
)
220 Authctxt
*authctxt
= ssh
->authctxt
;
221 Authmethod
*m
= NULL
;
222 char *user
, *service
, *method
, *style
= NULL
;
223 int authenticated
= 0;
225 if (authctxt
== NULL
)
226 fatal("input_userauth_request: no authctxt");
228 user
= packet_get_cstring(NULL
);
229 service
= packet_get_cstring(NULL
);
230 method
= packet_get_cstring(NULL
);
231 debug("userauth-request for user %s service %s method %s", user
, service
, method
);
232 debug("attempt %d failures %d", authctxt
->attempt
, authctxt
->failures
);
234 if ((style
= strchr(user
, ':')) != NULL
)
237 if (authctxt
->attempt
++ == 0) {
238 /* setup auth context */
239 authctxt
->pw
= PRIVSEP(getpwnamallow(user
));
240 authctxt
->user
= xstrdup(user
);
241 if (authctxt
->pw
&& strcmp(service
, "ssh-connection")==0) {
243 debug2("%s: setting up authctxt for %s",
246 /* Invalid user, fake password information */
247 authctxt
->pw
= fakepw();
248 #ifdef SSH_AUDIT_EVENTS
249 PRIVSEP(audit_event(SSH_INVALID_USER
));
254 PRIVSEP(start_pam(authctxt
));
256 ssh_packet_set_log_preamble(ssh
, "%suser %s",
257 authctxt
->valid
? "authenticating " : "invalid ", user
);
258 setproctitle("%s%s", authctxt
->valid
? user
: "unknown",
259 use_privsep
? " [net]" : "");
260 authctxt
->service
= xstrdup(service
);
261 authctxt
->style
= style
? xstrdup(style
) : NULL
;
263 mm_inform_authserv(service
, style
);
265 if (auth2_setup_methods_lists(authctxt
) != 0)
266 packet_disconnect("no authentication methods enabled");
267 } else if (strcmp(user
, authctxt
->user
) != 0 ||
268 strcmp(service
, authctxt
->service
) != 0) {
269 packet_disconnect("Change of username or service not allowed: "
270 "(%s,%s) -> (%s,%s)",
271 authctxt
->user
, authctxt
->service
, user
, service
);
274 auth2_challenge_stop(ssh
);
277 /* XXX move to auth2_gssapi_stop() */
278 ssh_dispatch_set(ssh
, SSH2_MSG_USERAUTH_GSSAPI_TOKEN
, NULL
);
279 ssh_dispatch_set(ssh
, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE
, NULL
);
282 auth2_authctxt_reset_info(authctxt
);
283 authctxt
->postponed
= 0;
284 authctxt
->server_caused_failure
= 0;
286 /* try to authenticate user */
287 m
= authmethod_lookup(authctxt
, method
);
288 if (m
!= NULL
&& authctxt
->failures
< options
.max_authtries
) {
289 debug2("input_userauth_request: try method %s", method
);
290 authenticated
= m
->userauth(ssh
);
292 userauth_finish(ssh
, authenticated
, method
, NULL
);
301 userauth_finish(struct ssh
*ssh
, int authenticated
, const char *method
,
302 const char *submethod
)
304 Authctxt
*authctxt
= ssh
->authctxt
;
308 if (!authctxt
->valid
&& authenticated
)
309 fatal("INTERNAL ERROR: authenticated invalid user %s",
311 if (authenticated
&& authctxt
->postponed
)
312 fatal("INTERNAL ERROR: authenticated and postponed");
314 /* Special handling for root */
315 if (authenticated
&& authctxt
->pw
->pw_uid
== 0 &&
316 !auth_root_allowed(method
)) {
318 #ifdef SSH_AUDIT_EVENTS
319 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED
));
323 if (authenticated
&& options
.num_auth_methods
!= 0) {
324 if (!auth2_update_methods_lists(authctxt
, method
, submethod
)) {
330 /* Log before sending the reply */
331 auth_log(authctxt
, authenticated
, partial
, method
, submethod
);
333 /* Update information exposed to session */
334 if (authenticated
|| partial
)
335 auth2_update_session_info(authctxt
, method
, submethod
);
337 if (authctxt
->postponed
)
341 if (options
.use_pam
&& authenticated
) {
342 if (!PRIVSEP(do_pam_account())) {
343 /* if PAM returned a message, send it to the user */
344 if (buffer_len(&loginmsg
) > 0) {
345 buffer_append(&loginmsg
, "\0", 1);
346 userauth_send_banner(buffer_ptr(&loginmsg
));
349 fatal("Access denied for user %s by PAM account "
350 "configuration", authctxt
->user
);
356 if (authenticated
&& cray_access_denied(authctxt
->user
)) {
358 fatal("Access denied for user %s.", authctxt
->user
);
362 if (authenticated
== 1) {
363 /* turn off userauth */
364 ssh_dispatch_set(ssh
, SSH2_MSG_USERAUTH_REQUEST
, &dispatch_protocol_ignore
);
365 packet_start(SSH2_MSG_USERAUTH_SUCCESS
);
368 /* now we can break out */
369 authctxt
->success
= 1;
370 ssh_packet_set_log_preamble(ssh
, "user %s", authctxt
->user
);
373 /* Allow initial try of "none" auth without failure penalty */
374 if (!partial
&& !authctxt
->server_caused_failure
&&
375 (authctxt
->attempt
> 1 || strcmp(method
, "none") != 0))
376 authctxt
->failures
++;
377 if (authctxt
->failures
>= options
.max_authtries
) {
378 #ifdef SSH_AUDIT_EVENTS
379 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES
));
381 auth_maxtries_exceeded(authctxt
);
383 methods
= authmethods_get(authctxt
);
384 debug3("%s: failure partial=%d next methods=\"%s\"", __func__
,
386 packet_start(SSH2_MSG_USERAUTH_FAILURE
);
387 packet_put_cstring(methods
);
388 packet_put_char(partial
);
396 * Checks whether method is allowed by at least one AuthenticationMethods
397 * methods list. Returns 1 if allowed, or no methods lists configured.
401 auth2_method_allowed(Authctxt
*authctxt
, const char *method
,
402 const char *submethod
)
407 * NB. authctxt->num_auth_methods might be zero as a result of
408 * auth2_setup_methods_lists(), so check the configuration.
410 if (options
.num_auth_methods
== 0)
412 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
413 if (list_starts_with(authctxt
->auth_methods
[i
], method
,
414 submethod
) != MATCH_NONE
)
421 authmethods_get(Authctxt
*authctxt
)
428 for (i
= 0; authmethods
[i
] != NULL
; i
++) {
429 if (strcmp(authmethods
[i
]->name
, "none") == 0)
431 if (authmethods
[i
]->enabled
== NULL
||
432 *(authmethods
[i
]->enabled
) == 0)
434 if (!auth2_method_allowed(authctxt
, authmethods
[i
]->name
,
437 if (buffer_len(&b
) > 0)
438 buffer_append(&b
, ",", 1);
439 buffer_append(&b
, authmethods
[i
]->name
,
440 strlen(authmethods
[i
]->name
));
442 if ((list
= sshbuf_dup_string(&b
)) == NULL
)
443 fatal("%s: sshbuf_dup_string failed", __func__
);
449 authmethod_lookup(Authctxt
*authctxt
, const char *name
)
454 for (i
= 0; authmethods
[i
] != NULL
; i
++)
455 if (authmethods
[i
]->enabled
!= NULL
&&
456 *(authmethods
[i
]->enabled
) != 0 &&
457 strcmp(name
, authmethods
[i
]->name
) == 0 &&
458 auth2_method_allowed(authctxt
,
459 authmethods
[i
]->name
, NULL
))
460 return authmethods
[i
];
461 debug2("Unrecognized authentication method name: %s",
462 name
? name
: "NULL");
467 * Check a comma-separated list of methods for validity. Is need_enable is
468 * non-zero, then also require that the methods are enabled.
469 * Returns 0 on success or -1 if the methods list is invalid.
472 auth2_methods_valid(const char *_methods
, int need_enable
)
474 char *methods
, *omethods
, *method
, *p
;
478 if (*_methods
== '\0') {
479 error("empty authentication method list");
482 omethods
= methods
= xstrdup(_methods
);
483 while ((method
= strsep(&methods
, ",")) != NULL
) {
484 for (found
= i
= 0; !found
&& authmethods
[i
] != NULL
; i
++) {
485 if ((p
= strchr(method
, ':')) != NULL
)
487 if (strcmp(method
, authmethods
[i
]->name
) != 0)
490 if (authmethods
[i
]->enabled
== NULL
||
491 *(authmethods
[i
]->enabled
) == 0) {
492 error("Disabled method \"%s\" in "
493 "AuthenticationMethods list \"%s\"",
502 error("Unknown authentication method \"%s\" in list",
514 * Prune the AuthenticationMethods supplied in the configuration, removing
515 * any methods lists that include disabled methods. Note that this might
516 * leave authctxt->num_auth_methods == 0, even when multiple required auth
517 * has been requested. For this reason, all tests for whether multiple is
518 * enabled should consult options.num_auth_methods directly.
521 auth2_setup_methods_lists(Authctxt
*authctxt
)
525 if (options
.num_auth_methods
== 0)
527 debug3("%s: checking methods", __func__
);
528 authctxt
->auth_methods
= xcalloc(options
.num_auth_methods
,
529 sizeof(*authctxt
->auth_methods
));
530 authctxt
->num_auth_methods
= 0;
531 for (i
= 0; i
< options
.num_auth_methods
; i
++) {
532 if (auth2_methods_valid(options
.auth_methods
[i
], 1) != 0) {
533 logit("Authentication methods list \"%s\" contains "
534 "disabled method, skipping",
535 options
.auth_methods
[i
]);
538 debug("authentication methods list %d: %s",
539 authctxt
->num_auth_methods
, options
.auth_methods
[i
]);
540 authctxt
->auth_methods
[authctxt
->num_auth_methods
++] =
541 xstrdup(options
.auth_methods
[i
]);
543 if (authctxt
->num_auth_methods
== 0) {
544 error("No AuthenticationMethods left after eliminating "
552 list_starts_with(const char *methods
, const char *method
,
553 const char *submethod
)
555 size_t l
= strlen(method
);
559 if (strncmp(methods
, method
, l
) != 0)
562 match
= MATCH_METHOD
;
565 return MATCH_PARTIAL
;
566 l
= strlen(submethod
);
568 if (strncmp(submethod
, p
, l
))
573 if (*p
!= ',' && *p
!= '\0')
579 * Remove method from the start of a comma-separated list of methods.
580 * Returns 0 if the list of methods did not start with that method or 1
584 remove_method(char **methods
, const char *method
, const char *submethod
)
586 char *omethods
= *methods
, *p
;
587 size_t l
= strlen(method
);
590 match
= list_starts_with(omethods
, method
, submethod
);
591 if (match
!= MATCH_METHOD
&& match
!= MATCH_BOTH
)
594 if (submethod
&& match
== MATCH_BOTH
)
595 p
+= 1 + strlen(submethod
); /* include colon */
598 *methods
= xstrdup(p
);
604 * Called after successful authentication. Will remove the successful method
605 * from the start of each list in which it occurs. If it was the last method
606 * in any list, then authentication is deemed successful.
607 * Returns 1 if the method completed any authentication list or 0 otherwise.
610 auth2_update_methods_lists(Authctxt
*authctxt
, const char *method
,
611 const char *submethod
)
615 debug3("%s: updating methods list after \"%s\"", __func__
, method
);
616 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
617 if (!remove_method(&(authctxt
->auth_methods
[i
]), method
,
621 if (*authctxt
->auth_methods
[i
] == '\0') {
622 debug2("authentication methods list %d complete", i
);
625 debug3("authentication methods list %d remaining: \"%s\"",
626 i
, authctxt
->auth_methods
[i
]);
628 /* This should not happen, but would be bad if it did */
630 fatal("%s: method not in AuthenticationMethods", __func__
);
634 /* Reset method-specific information */
635 void auth2_authctxt_reset_info(Authctxt
*authctxt
)
637 sshkey_free(authctxt
->auth_method_key
);
638 free(authctxt
->auth_method_info
);
639 authctxt
->auth_method_key
= NULL
;
640 authctxt
->auth_method_info
= NULL
;
643 /* Record auth method-specific information for logs */
645 auth2_record_info(Authctxt
*authctxt
, const char *fmt
, ...)
650 free(authctxt
->auth_method_info
);
651 authctxt
->auth_method_info
= NULL
;
654 i
= vasprintf(&authctxt
->auth_method_info
, fmt
, ap
);
657 if (i
< 0 || authctxt
->auth_method_info
== NULL
)
658 fatal("%s: vasprintf failed", __func__
);
662 * Records a public key used in authentication. This is used for logging
663 * and to ensure that the same key is not subsequently accepted again for
664 * multiple authentication.
667 auth2_record_key(Authctxt
*authctxt
, int authenticated
,
668 const struct sshkey
*key
)
670 struct sshkey
**tmp
, *dup
;
673 if ((r
= sshkey_demote(key
, &dup
)) != 0)
674 fatal("%s: copy key: %s", __func__
, ssh_err(r
));
675 sshkey_free(authctxt
->auth_method_key
);
676 authctxt
->auth_method_key
= dup
;
681 /* If authenticated, make sure we don't accept this key again */
682 if ((r
= sshkey_demote(key
, &dup
)) != 0)
683 fatal("%s: copy key: %s", __func__
, ssh_err(r
));
684 if (authctxt
->nprev_keys
>= INT_MAX
||
685 (tmp
= recallocarray(authctxt
->prev_keys
, authctxt
->nprev_keys
,
686 authctxt
->nprev_keys
+ 1, sizeof(*authctxt
->prev_keys
))) == NULL
)
687 fatal("%s: reallocarray failed", __func__
);
688 authctxt
->prev_keys
= tmp
;
689 authctxt
->prev_keys
[authctxt
->nprev_keys
] = dup
;
690 authctxt
->nprev_keys
++;
694 /* Checks whether a key has already been previously used for authentication */
696 auth2_key_already_used(Authctxt
*authctxt
, const struct sshkey
*key
)
701 for (i
= 0; i
< authctxt
->nprev_keys
; i
++) {
702 if (sshkey_equal_public(key
, authctxt
->prev_keys
[i
])) {
703 fp
= sshkey_fingerprint(authctxt
->prev_keys
[i
],
704 options
.fingerprint_hash
, SSH_FP_DEFAULT
);
705 debug3("%s: key already used: %s %s", __func__
,
706 sshkey_type(authctxt
->prev_keys
[i
]),
707 fp
== NULL
? "UNKNOWN" : fp
);
716 * Updates authctxt->session_info with details of authentication. Should be
717 * whenever an authentication method succeeds.
720 auth2_update_session_info(Authctxt
*authctxt
, const char *method
,
721 const char *submethod
)
725 if (authctxt
->session_info
== NULL
) {
726 if ((authctxt
->session_info
= sshbuf_new()) == NULL
)
727 fatal("%s: sshbuf_new", __func__
);
730 /* Append method[/submethod] */
731 if ((r
= sshbuf_putf(authctxt
->session_info
, "%s%s%s",
732 method
, submethod
== NULL
? "" : "/",
733 submethod
== NULL
? "" : submethod
)) != 0)
734 fatal("%s: append method: %s", __func__
, ssh_err(r
));
736 /* Append key if present */
737 if (authctxt
->auth_method_key
!= NULL
) {
738 if ((r
= sshbuf_put_u8(authctxt
->session_info
, ' ')) != 0 ||
739 (r
= sshkey_format_text(authctxt
->auth_method_key
,
740 authctxt
->session_info
)) != 0)
741 fatal("%s: append key: %s", __func__
, ssh_err(r
));
744 if (authctxt
->auth_method_info
!= NULL
) {
745 /* Ensure no ambiguity here */
746 if (strchr(authctxt
->auth_method_info
, '\n') != NULL
)
747 fatal("%s: auth_method_info contains \\n", __func__
);
748 if ((r
= sshbuf_put_u8(authctxt
->session_info
, ' ')) != 0 ||
749 (r
= sshbuf_putf(authctxt
->session_info
, "%s",
750 authctxt
->auth_method_info
)) != 0) {
751 fatal("%s: append method info: %s",
752 __func__
, ssh_err(r
));
755 if ((r
= sshbuf_put_u8(authctxt
->session_info
, '\n')) != 0)
756 fatal("%s: append: %s", __func__
, ssh_err(r
));