1 /* $OpenBSD: auth2.c,v 1.136 2016/05/02 08:49:03 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>
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 Authmethod
*authmethods
[] = {
91 static int input_service_request(int, u_int32_t
, void *);
92 static int input_userauth_request(int, u_int32_t
, void *);
95 static Authmethod
*authmethod_lookup(Authctxt
*, const char *);
96 static char *authmethods_get(Authctxt
*authctxt
);
98 #define MATCH_NONE 0 /* method or submethod mismatch */
99 #define MATCH_METHOD 1 /* method matches (no submethod specified) */
100 #define MATCH_BOTH 2 /* method and submethod match */
101 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
102 static int list_starts_with(const char *, const char *, const char *);
105 auth2_read_banner(void)
112 if ((fd
= open(options
.banner
, O_RDONLY
)) == -1)
114 if (fstat(fd
, &st
) == -1) {
118 if (st
.st_size
<= 0 || st
.st_size
> 1*1024*1024) {
123 len
= (size_t)st
.st_size
; /* truncate */
124 banner
= xmalloc(len
+ 1);
125 n
= atomicio(read
, fd
, banner
, len
);
138 userauth_send_banner(const char *msg
)
140 if (datafellows
& SSH_BUG_BANNER
)
143 packet_start(SSH2_MSG_USERAUTH_BANNER
);
144 packet_put_cstring(msg
);
145 packet_put_cstring(""); /* language, unused */
147 debug("%s: sent", __func__
);
151 userauth_banner(void)
155 if (options
.banner
== NULL
|| (datafellows
& SSH_BUG_BANNER
) != 0)
158 if ((banner
= PRIVSEP(auth2_read_banner())) == NULL
)
160 userauth_send_banner(banner
);
167 * loop until authctxt->success == TRUE
170 do_authentication2(Authctxt
*authctxt
)
172 dispatch_init(&dispatch_protocol_error
);
173 dispatch_set(SSH2_MSG_SERVICE_REQUEST
, &input_service_request
);
174 dispatch_run(DISPATCH_BLOCK
, &authctxt
->success
, authctxt
);
179 input_service_request(int type
, u_int32_t seq
, void *ctxt
)
181 Authctxt
*authctxt
= ctxt
;
184 char *service
= packet_get_cstring(&len
);
187 if (authctxt
== NULL
)
188 fatal("input_service_request: no authctxt");
190 if (strcmp(service
, "ssh-userauth") == 0) {
191 if (!authctxt
->success
) {
193 /* now we can handle user-auth requests */
194 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &input_userauth_request
);
197 /* XXX all other service requests are denied */
200 packet_start(SSH2_MSG_SERVICE_ACCEPT
);
201 packet_put_cstring(service
);
205 debug("bad service request %s", service
);
206 packet_disconnect("bad service request %s", service
);
214 input_userauth_request(int type
, u_int32_t seq
, void *ctxt
)
216 Authctxt
*authctxt
= ctxt
;
217 Authmethod
*m
= NULL
;
218 char *user
, *service
, *method
, *style
= NULL
;
219 int authenticated
= 0;
221 if (authctxt
== NULL
)
222 fatal("input_userauth_request: no authctxt");
224 user
= packet_get_cstring(NULL
);
225 service
= packet_get_cstring(NULL
);
226 method
= packet_get_cstring(NULL
);
227 debug("userauth-request for user %s service %s method %s", user
, service
, method
);
228 debug("attempt %d failures %d", authctxt
->attempt
, authctxt
->failures
);
230 if ((style
= strchr(user
, ':')) != NULL
)
233 if (authctxt
->attempt
++ == 0) {
234 /* setup auth context */
235 authctxt
->pw
= PRIVSEP(getpwnamallow(user
));
236 authctxt
->user
= xstrdup(user
);
237 if (authctxt
->pw
&& strcmp(service
, "ssh-connection")==0) {
239 debug2("input_userauth_request: setting up authctxt for %s", user
);
241 logit("input_userauth_request: invalid user %s", user
);
242 authctxt
->pw
= fakepw();
243 #ifdef SSH_AUDIT_EVENTS
244 PRIVSEP(audit_event(SSH_INVALID_USER
));
249 PRIVSEP(start_pam(authctxt
));
251 setproctitle("%s%s", authctxt
->valid
? user
: "unknown",
252 use_privsep
? " [net]" : "");
253 authctxt
->service
= xstrdup(service
);
254 authctxt
->style
= style
? xstrdup(style
) : NULL
;
256 mm_inform_authserv(service
, style
);
258 if (auth2_setup_methods_lists(authctxt
) != 0)
259 packet_disconnect("no authentication methods enabled");
260 } else if (strcmp(user
, authctxt
->user
) != 0 ||
261 strcmp(service
, authctxt
->service
) != 0) {
262 packet_disconnect("Change of username or service not allowed: "
263 "(%s,%s) -> (%s,%s)",
264 authctxt
->user
, authctxt
->service
, user
, service
);
267 auth2_challenge_stop(authctxt
);
270 /* XXX move to auth2_gssapi_stop() */
271 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN
, NULL
);
272 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE
, NULL
);
275 authctxt
->postponed
= 0;
276 authctxt
->server_caused_failure
= 0;
278 /* try to authenticate user */
279 m
= authmethod_lookup(authctxt
, method
);
280 if (m
!= NULL
&& authctxt
->failures
< options
.max_authtries
) {
281 debug2("input_userauth_request: try method %s", method
);
282 authenticated
= m
->userauth(authctxt
);
284 userauth_finish(authctxt
, authenticated
, method
, NULL
);
293 userauth_finish(Authctxt
*authctxt
, int authenticated
, const char *method
,
294 const char *submethod
)
299 if (!authctxt
->valid
&& authenticated
)
300 fatal("INTERNAL ERROR: authenticated invalid user %s",
302 if (authenticated
&& authctxt
->postponed
)
303 fatal("INTERNAL ERROR: authenticated and postponed");
305 /* Special handling for root */
306 if (authenticated
&& authctxt
->pw
->pw_uid
== 0 &&
307 !auth_root_allowed(method
)) {
309 #ifdef SSH_AUDIT_EVENTS
310 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED
));
314 if (authenticated
&& options
.num_auth_methods
!= 0) {
315 if (!auth2_update_methods_lists(authctxt
, method
, submethod
)) {
321 /* Log before sending the reply */
322 auth_log(authctxt
, authenticated
, partial
, method
, submethod
);
324 if (authctxt
->postponed
)
328 if (options
.use_pam
&& authenticated
) {
329 if (!PRIVSEP(do_pam_account())) {
330 /* if PAM returned a message, send it to the user */
331 if (buffer_len(&loginmsg
) > 0) {
332 buffer_append(&loginmsg
, "\0", 1);
333 userauth_send_banner(buffer_ptr(&loginmsg
));
336 fatal("Access denied for user %s by PAM account "
337 "configuration", authctxt
->user
);
343 if (authenticated
&& cray_access_denied(authctxt
->user
)) {
345 fatal("Access denied for user %s.", authctxt
->user
);
349 if (authenticated
== 1) {
350 /* turn off userauth */
351 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &dispatch_protocol_ignore
);
352 packet_start(SSH2_MSG_USERAUTH_SUCCESS
);
355 /* now we can break out */
356 authctxt
->success
= 1;
359 /* Allow initial try of "none" auth without failure penalty */
360 if (!partial
&& !authctxt
->server_caused_failure
&&
361 (authctxt
->attempt
> 1 || strcmp(method
, "none") != 0))
362 authctxt
->failures
++;
363 if (authctxt
->failures
>= options
.max_authtries
) {
364 #ifdef SSH_AUDIT_EVENTS
365 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES
));
367 auth_maxtries_exceeded(authctxt
);
369 methods
= authmethods_get(authctxt
);
370 debug3("%s: failure partial=%d next methods=\"%s\"", __func__
,
372 packet_start(SSH2_MSG_USERAUTH_FAILURE
);
373 packet_put_cstring(methods
);
374 packet_put_char(partial
);
382 * Checks whether method is allowed by at least one AuthenticationMethods
383 * methods list. Returns 1 if allowed, or no methods lists configured.
387 auth2_method_allowed(Authctxt
*authctxt
, const char *method
,
388 const char *submethod
)
393 * NB. authctxt->num_auth_methods might be zero as a result of
394 * auth2_setup_methods_lists(), so check the configuration.
396 if (options
.num_auth_methods
== 0)
398 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
399 if (list_starts_with(authctxt
->auth_methods
[i
], method
,
400 submethod
) != MATCH_NONE
)
407 authmethods_get(Authctxt
*authctxt
)
414 for (i
= 0; authmethods
[i
] != NULL
; i
++) {
415 if (strcmp(authmethods
[i
]->name
, "none") == 0)
417 if (authmethods
[i
]->enabled
== NULL
||
418 *(authmethods
[i
]->enabled
) == 0)
420 if (!auth2_method_allowed(authctxt
, authmethods
[i
]->name
,
423 if (buffer_len(&b
) > 0)
424 buffer_append(&b
, ",", 1);
425 buffer_append(&b
, authmethods
[i
]->name
,
426 strlen(authmethods
[i
]->name
));
428 if ((list
= sshbuf_dup_string(&b
)) == NULL
)
429 fatal("%s: sshbuf_dup_string failed", __func__
);
435 authmethod_lookup(Authctxt
*authctxt
, const char *name
)
440 for (i
= 0; authmethods
[i
] != NULL
; i
++)
441 if (authmethods
[i
]->enabled
!= NULL
&&
442 *(authmethods
[i
]->enabled
) != 0 &&
443 strcmp(name
, authmethods
[i
]->name
) == 0 &&
444 auth2_method_allowed(authctxt
,
445 authmethods
[i
]->name
, NULL
))
446 return authmethods
[i
];
447 debug2("Unrecognized authentication method name: %s",
448 name
? name
: "NULL");
453 * Check a comma-separated list of methods for validity. Is need_enable is
454 * non-zero, then also require that the methods are enabled.
455 * Returns 0 on success or -1 if the methods list is invalid.
458 auth2_methods_valid(const char *_methods
, int need_enable
)
460 char *methods
, *omethods
, *method
, *p
;
464 if (*_methods
== '\0') {
465 error("empty authentication method list");
468 omethods
= methods
= xstrdup(_methods
);
469 while ((method
= strsep(&methods
, ",")) != NULL
) {
470 for (found
= i
= 0; !found
&& authmethods
[i
] != NULL
; i
++) {
471 if ((p
= strchr(method
, ':')) != NULL
)
473 if (strcmp(method
, authmethods
[i
]->name
) != 0)
476 if (authmethods
[i
]->enabled
== NULL
||
477 *(authmethods
[i
]->enabled
) == 0) {
478 error("Disabled method \"%s\" in "
479 "AuthenticationMethods list \"%s\"",
488 error("Unknown authentication method \"%s\" in list",
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.
507 auth2_setup_methods_lists(Authctxt
*authctxt
)
511 if (options
.num_auth_methods
== 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
]);
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
]);
529 if (authctxt
->num_auth_methods
== 0) {
530 error("No AuthenticationMethods left after eliminating "
538 list_starts_with(const char *methods
, const char *method
,
539 const char *submethod
)
541 size_t l
= strlen(method
);
545 if (strncmp(methods
, method
, l
) != 0)
548 match
= MATCH_METHOD
;
551 return MATCH_PARTIAL
;
552 l
= strlen(submethod
);
554 if (strncmp(submethod
, p
, l
))
559 if (*p
!= ',' && *p
!= '\0')
565 * Remove method from the start of a comma-separated list of methods.
566 * Returns 0 if the list of methods did not start with that method or 1
570 remove_method(char **methods
, const char *method
, const char *submethod
)
572 char *omethods
= *methods
, *p
;
573 size_t l
= strlen(method
);
576 match
= list_starts_with(omethods
, method
, submethod
);
577 if (match
!= MATCH_METHOD
&& match
!= MATCH_BOTH
)
580 if (submethod
&& match
== MATCH_BOTH
)
581 p
+= 1 + strlen(submethod
); /* include colon */
584 *methods
= xstrdup(p
);
590 * Called after successful authentication. Will remove the successful method
591 * from the start of each list in which it occurs. If it was the last method
592 * in any list, then authentication is deemed successful.
593 * Returns 1 if the method completed any authentication list or 0 otherwise.
596 auth2_update_methods_lists(Authctxt
*authctxt
, const char *method
,
597 const char *submethod
)
601 debug3("%s: updating methods list after \"%s\"", __func__
, method
);
602 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
603 if (!remove_method(&(authctxt
->auth_methods
[i
]), method
,
607 if (*authctxt
->auth_methods
[i
] == '\0') {
608 debug2("authentication methods list %d complete", i
);
611 debug3("authentication methods list %d remaining: \"%s\"",
612 i
, authctxt
->auth_methods
[i
]);
614 /* This should not happen, but would be bad if it did */
616 fatal("%s: method not in AuthenticationMethods", __func__
);