1 /* $OpenBSD: auth2.c,v 1.132 2014/07/15 15:54:14 millert 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>
51 #include "pathnames.h"
58 #include "monitor_wrap.h"
61 extern ServerOptions options
;
62 extern u_char
*session_id2
;
63 extern u_int session_id2_len
;
64 extern Buffer loginmsg
;
68 extern Authmethod method_none
;
69 extern Authmethod method_pubkey
;
70 extern Authmethod method_passwd
;
71 extern Authmethod method_kbdint
;
72 extern Authmethod method_hostbased
;
74 extern Authmethod method_gssapi
;
77 static int log_flag
= 0;
80 Authmethod
*authmethods
[] = {
94 static void input_service_request(int, u_int32_t
, void *);
95 static void input_userauth_request(int, u_int32_t
, void *);
98 static Authmethod
*authmethod_lookup(Authctxt
*, const char *);
99 static char *authmethods_get(Authctxt
*authctxt
);
101 #define MATCH_NONE 0 /* method or submethod mismatch */
102 #define MATCH_METHOD 1 /* method matches (no submethod specified) */
103 #define MATCH_BOTH 2 /* method and submethod match */
104 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
105 static int list_starts_with(const char *, const char *, const char *);
108 auth2_read_banner(void)
115 if ((fd
= open(options
.banner
, O_RDONLY
)) == -1)
117 if (fstat(fd
, &st
) == -1) {
121 if (st
.st_size
<= 0 || st
.st_size
> 1*1024*1024) {
126 len
= (size_t)st
.st_size
; /* truncate */
127 banner
= xmalloc(len
+ 1);
128 n
= atomicio(read
, fd
, banner
, len
);
141 userauth_send_banner(const char *msg
)
143 if (datafellows
& SSH_BUG_BANNER
)
146 packet_start(SSH2_MSG_USERAUTH_BANNER
);
147 packet_put_cstring(msg
);
148 packet_put_cstring(""); /* language, unused */
150 debug("%s: sent", __func__
);
154 userauth_banner(void)
158 if (options
.banner
== NULL
||
159 strcasecmp(options
.banner
, "none") == 0 ||
160 (datafellows
& SSH_BUG_BANNER
) != 0)
163 if ((banner
= PRIVSEP(auth2_read_banner())) == NULL
)
165 userauth_send_banner(banner
);
172 * loop until authctxt->success == TRUE
175 do_authentication2(Authctxt
*authctxt
)
177 dispatch_init(&dispatch_protocol_error
);
178 dispatch_set(SSH2_MSG_SERVICE_REQUEST
, &input_service_request
);
179 dispatch_run(DISPATCH_BLOCK
, &authctxt
->success
, authctxt
);
184 input_service_request(int type
, u_int32_t seq
, void *ctxt
)
186 Authctxt
*authctxt
= ctxt
;
189 char *service
= packet_get_cstring(&len
);
192 if (authctxt
== NULL
)
193 fatal("input_service_request: no authctxt");
195 if (strcmp(service
, "ssh-userauth") == 0) {
196 if (!authctxt
->success
) {
198 /* now we can handle user-auth requests */
199 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &input_userauth_request
);
202 /* XXX all other service requests are denied */
205 packet_start(SSH2_MSG_SERVICE_ACCEPT
);
206 packet_put_cstring(service
);
210 debug("bad service request %s", service
);
211 packet_disconnect("bad service request %s", service
);
218 input_userauth_request(int type
, u_int32_t seq
, void *ctxt
)
220 Authctxt
*authctxt
= ctxt
;
221 Authmethod
*m
= NULL
;
222 char *user
, *service
, *method
, *style
= NULL
;
223 int authenticated
= 0;
224 #ifdef HAVE_LOGIN_CAP
226 const char *from_host
, *from_ip
;
228 from_host
= get_canonical_hostname(options
.use_dns
);
229 from_ip
= get_remote_ipaddr();
232 if (authctxt
== NULL
)
233 fatal("input_userauth_request: no authctxt");
235 user
= packet_get_cstring(NULL
);
236 service
= packet_get_cstring(NULL
);
237 method
= packet_get_cstring(NULL
);
238 debug("userauth-request for user %s service %s method %s", user
, service
, method
);
240 logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s",
241 get_remote_ipaddr(), get_remote_port(), user
);
244 debug("attempt %d failures %d", authctxt
->attempt
, authctxt
->failures
);
246 if ((style
= strchr(user
, ':')) != NULL
)
249 if (authctxt
->attempt
++ == 0) {
250 /* setup auth context */
251 authctxt
->pw
= PRIVSEP(getpwnamallow(user
));
252 authctxt
->user
= xstrdup(user
);
253 if (authctxt
->pw
&& strcmp(service
, "ssh-connection")==0) {
255 debug2("input_userauth_request: setting up authctxt for %s", user
);
257 logit("input_userauth_request: invalid user %s", user
);
258 authctxt
->pw
= fakepw();
259 #ifdef SSH_AUDIT_EVENTS
260 PRIVSEP(audit_event(SSH_INVALID_USER
));
265 PRIVSEP(start_pam(authctxt
));
267 setproctitle("%s%s", authctxt
->valid
? user
: "unknown",
268 use_privsep
? " [net]" : "");
269 authctxt
->service
= xstrdup(service
);
270 authctxt
->style
= style
? xstrdup(style
) : NULL
;
272 mm_inform_authserv(service
, style
);
274 if (auth2_setup_methods_lists(authctxt
) != 0)
275 packet_disconnect("no authentication methods enabled");
276 } else if (strcmp(user
, authctxt
->user
) != 0 ||
277 strcmp(service
, authctxt
->service
) != 0) {
278 packet_disconnect("Change of username or service not allowed: "
279 "(%s,%s) -> (%s,%s)",
280 authctxt
->user
, authctxt
->service
, user
, service
);
283 #ifdef HAVE_LOGIN_CAP
284 if (authctxt
->pw
!= NULL
) {
285 lc
= login_getpwclass(authctxt
->pw
);
287 lc
= login_getclassbyname(NULL
, authctxt
->pw
);
288 if (!auth_hostok(lc
, from_host
, from_ip
)) {
289 logit("Denied connection for %.200s from %.200s [%.200s].",
290 authctxt
->pw
->pw_name
, from_host
, from_ip
);
291 packet_disconnect("Sorry, you are not allowed to connect.");
293 if (!auth_timeok(lc
, time(NULL
))) {
294 logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
295 authctxt
->pw
->pw_name
, from_host
);
296 packet_disconnect("Logins not available right now.");
301 #endif /* HAVE_LOGIN_CAP */
304 auth2_challenge_stop(authctxt
);
307 /* XXX move to auth2_gssapi_stop() */
308 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN
, NULL
);
309 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE
, NULL
);
312 authctxt
->postponed
= 0;
313 authctxt
->server_caused_failure
= 0;
315 /* try to authenticate user */
316 m
= authmethod_lookup(authctxt
, method
);
317 if (m
!= NULL
&& authctxt
->failures
< options
.max_authtries
) {
318 debug2("input_userauth_request: try method %s", method
);
319 authenticated
= m
->userauth(authctxt
);
321 userauth_finish(authctxt
, authenticated
, method
, NULL
);
329 userauth_finish(Authctxt
*authctxt
, int authenticated
, const char *method
,
330 const char *submethod
)
335 if (!authctxt
->valid
&& authenticated
)
336 fatal("INTERNAL ERROR: authenticated invalid user %s",
338 if (authenticated
&& authctxt
->postponed
)
339 fatal("INTERNAL ERROR: authenticated and postponed");
341 /* Special handling for root */
342 if (authenticated
&& authctxt
->pw
->pw_uid
== 0 &&
343 !auth_root_allowed(method
)) {
345 #ifdef SSH_AUDIT_EVENTS
346 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED
));
350 if (authenticated
&& options
.num_auth_methods
!= 0) {
351 if (!auth2_update_methods_lists(authctxt
, method
, submethod
)) {
357 /* Log before sending the reply */
358 auth_log(authctxt
, authenticated
, partial
, method
, submethod
);
360 if (authctxt
->postponed
)
364 if (options
.use_pam
&& authenticated
) {
365 if (!PRIVSEP(do_pam_account())) {
366 /* if PAM returned a message, send it to the user */
367 if (buffer_len(&loginmsg
) > 0) {
368 buffer_append(&loginmsg
, "\0", 1);
369 userauth_send_banner(buffer_ptr(&loginmsg
));
372 fatal("Access denied for user %s by PAM account "
373 "configuration", authctxt
->user
);
379 if (authenticated
&& cray_access_denied(authctxt
->user
)) {
381 fatal("Access denied for user %s.", authctxt
->user
);
385 if (authenticated
== 1) {
386 /* turn off userauth */
387 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &dispatch_protocol_ignore
);
388 packet_start(SSH2_MSG_USERAUTH_SUCCESS
);
391 /* now we can break out */
392 authctxt
->success
= 1;
395 /* Allow initial try of "none" auth without failure penalty */
396 if (!authctxt
->server_caused_failure
&&
397 (authctxt
->attempt
> 1 || strcmp(method
, "none") != 0))
398 authctxt
->failures
++;
399 if (authctxt
->failures
>= options
.max_authtries
) {
400 #ifdef SSH_AUDIT_EVENTS
401 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES
));
403 auth_maxtries_exceeded(authctxt
);
405 methods
= authmethods_get(authctxt
);
406 debug3("%s: failure partial=%d next methods=\"%s\"", __func__
,
408 packet_start(SSH2_MSG_USERAUTH_FAILURE
);
409 packet_put_cstring(methods
);
410 packet_put_char(partial
);
418 * Checks whether method is allowed by at least one AuthenticationMethods
419 * methods list. Returns 1 if allowed, or no methods lists configured.
423 auth2_method_allowed(Authctxt
*authctxt
, const char *method
,
424 const char *submethod
)
429 * NB. authctxt->num_auth_methods might be zero as a result of
430 * auth2_setup_methods_lists(), so check the configuration.
432 if (options
.num_auth_methods
== 0)
434 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
435 if (list_starts_with(authctxt
->auth_methods
[i
], method
,
436 submethod
) != MATCH_NONE
)
443 authmethods_get(Authctxt
*authctxt
)
450 for (i
= 0; authmethods
[i
] != NULL
; i
++) {
451 if (strcmp(authmethods
[i
]->name
, "none") == 0)
453 if (authmethods
[i
]->enabled
== NULL
||
454 *(authmethods
[i
]->enabled
) == 0)
456 if (!auth2_method_allowed(authctxt
, authmethods
[i
]->name
,
459 if (buffer_len(&b
) > 0)
460 buffer_append(&b
, ",", 1);
461 buffer_append(&b
, authmethods
[i
]->name
,
462 strlen(authmethods
[i
]->name
));
464 buffer_append(&b
, "\0", 1);
465 list
= xstrdup(buffer_ptr(&b
));
471 authmethod_lookup(Authctxt
*authctxt
, const char *name
)
476 for (i
= 0; authmethods
[i
] != NULL
; i
++)
477 if (authmethods
[i
]->enabled
!= NULL
&&
478 *(authmethods
[i
]->enabled
) != 0 &&
479 strcmp(name
, authmethods
[i
]->name
) == 0 &&
480 auth2_method_allowed(authctxt
,
481 authmethods
[i
]->name
, NULL
))
482 return authmethods
[i
];
483 debug2("Unrecognized authentication method name: %s",
484 name
? name
: "NULL");
489 * Check a comma-separated list of methods for validity. Is need_enable is
490 * non-zero, then also require that the methods are enabled.
491 * Returns 0 on success or -1 if the methods list is invalid.
494 auth2_methods_valid(const char *_methods
, int need_enable
)
496 char *methods
, *omethods
, *method
, *p
;
500 if (*_methods
== '\0') {
501 error("empty authentication method list");
504 omethods
= methods
= xstrdup(_methods
);
505 while ((method
= strsep(&methods
, ",")) != NULL
) {
506 for (found
= i
= 0; !found
&& authmethods
[i
] != NULL
; i
++) {
507 if ((p
= strchr(method
, ':')) != NULL
)
509 if (strcmp(method
, authmethods
[i
]->name
) != 0)
512 if (authmethods
[i
]->enabled
== NULL
||
513 *(authmethods
[i
]->enabled
) == 0) {
514 error("Disabled method \"%s\" in "
515 "AuthenticationMethods list \"%s\"",
524 error("Unknown authentication method \"%s\" in list",
536 * Prune the AuthenticationMethods supplied in the configuration, removing
537 * any methods lists that include disabled methods. Note that this might
538 * leave authctxt->num_auth_methods == 0, even when multiple required auth
539 * has been requested. For this reason, all tests for whether multiple is
540 * enabled should consult options.num_auth_methods directly.
543 auth2_setup_methods_lists(Authctxt
*authctxt
)
547 if (options
.num_auth_methods
== 0)
549 debug3("%s: checking methods", __func__
);
550 authctxt
->auth_methods
= xcalloc(options
.num_auth_methods
,
551 sizeof(*authctxt
->auth_methods
));
552 authctxt
->num_auth_methods
= 0;
553 for (i
= 0; i
< options
.num_auth_methods
; i
++) {
554 if (auth2_methods_valid(options
.auth_methods
[i
], 1) != 0) {
555 logit("Authentication methods list \"%s\" contains "
556 "disabled method, skipping",
557 options
.auth_methods
[i
]);
560 debug("authentication methods list %d: %s",
561 authctxt
->num_auth_methods
, options
.auth_methods
[i
]);
562 authctxt
->auth_methods
[authctxt
->num_auth_methods
++] =
563 xstrdup(options
.auth_methods
[i
]);
565 if (authctxt
->num_auth_methods
== 0) {
566 error("No AuthenticationMethods left after eliminating "
574 list_starts_with(const char *methods
, const char *method
,
575 const char *submethod
)
577 size_t l
= strlen(method
);
581 if (strncmp(methods
, method
, l
) != 0)
584 match
= MATCH_METHOD
;
587 return MATCH_PARTIAL
;
588 l
= strlen(submethod
);
590 if (strncmp(submethod
, p
, l
))
595 if (*p
!= ',' && *p
!= '\0')
601 * Remove method from the start of a comma-separated list of methods.
602 * Returns 0 if the list of methods did not start with that method or 1
606 remove_method(char **methods
, const char *method
, const char *submethod
)
608 char *omethods
= *methods
, *p
;
609 size_t l
= strlen(method
);
612 match
= list_starts_with(omethods
, method
, submethod
);
613 if (match
!= MATCH_METHOD
&& match
!= MATCH_BOTH
)
616 if (submethod
&& match
== MATCH_BOTH
)
617 p
+= 1 + strlen(submethod
); /* include colon */
620 *methods
= xstrdup(p
);
626 * Called after successful authentication. Will remove the successful method
627 * from the start of each list in which it occurs. If it was the last method
628 * in any list, then authentication is deemed successful.
629 * Returns 1 if the method completed any authentication list or 0 otherwise.
632 auth2_update_methods_lists(Authctxt
*authctxt
, const char *method
,
633 const char *submethod
)
637 debug3("%s: updating methods list after \"%s\"", __func__
, method
);
638 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
639 if (!remove_method(&(authctxt
->auth_methods
[i
]), method
,
643 if (*authctxt
->auth_methods
[i
] == '\0') {
644 debug2("authentication methods list %d complete", i
);
647 debug3("authentication methods list %d remaining: \"%s\"",
648 i
, authctxt
->auth_methods
[i
]);
650 /* This should not happen, but would be bad if it did */
652 fatal("%s: method not in AuthenticationMethods", __func__
);