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"
57 #include "monitor_wrap.h"
60 extern ServerOptions options
;
61 extern u_char
*session_id2
;
62 extern u_int session_id2_len
;
63 extern Buffer loginmsg
;
67 extern Authmethod method_none
;
68 extern Authmethod method_pubkey
;
69 extern Authmethod method_passwd
;
70 extern Authmethod method_kbdint
;
71 extern Authmethod method_hostbased
;
73 extern Authmethod method_gssapi
;
76 Authmethod
*authmethods
[] = {
90 static void input_service_request(int, u_int32_t
, void *);
91 static void input_userauth_request(int, u_int32_t
, void *);
94 static Authmethod
*authmethod_lookup(Authctxt
*, const char *);
95 static char *authmethods_get(Authctxt
*authctxt
);
97 #define MATCH_NONE 0 /* method or submethod mismatch */
98 #define MATCH_METHOD 1 /* method matches (no submethod specified) */
99 #define MATCH_BOTH 2 /* method and submethod match */
100 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
101 static int list_starts_with(const char *, const char *, const char *);
104 auth2_read_banner(void)
111 if ((fd
= open(options
.banner
, O_RDONLY
)) == -1)
113 if (fstat(fd
, &st
) == -1) {
117 if (st
.st_size
<= 0 || st
.st_size
> 1*1024*1024) {
122 len
= (size_t)st
.st_size
; /* truncate */
123 banner
= xmalloc(len
+ 1);
124 n
= atomicio(read
, fd
, banner
, len
);
137 userauth_send_banner(const char *msg
)
139 if (datafellows
& SSH_BUG_BANNER
)
142 packet_start(SSH2_MSG_USERAUTH_BANNER
);
143 packet_put_cstring(msg
);
144 packet_put_cstring(""); /* language, unused */
146 debug("%s: sent", __func__
);
150 userauth_banner(void)
154 if (options
.banner
== NULL
||
155 strcasecmp(options
.banner
, "none") == 0 ||
156 (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 dispatch_init(&dispatch_protocol_error
);
174 dispatch_set(SSH2_MSG_SERVICE_REQUEST
, &input_service_request
);
175 dispatch_run(DISPATCH_BLOCK
, &authctxt
->success
, authctxt
);
180 input_service_request(int type
, u_int32_t seq
, void *ctxt
)
182 Authctxt
*authctxt
= ctxt
;
185 char *service
= packet_get_cstring(&len
);
188 if (authctxt
== NULL
)
189 fatal("input_service_request: no authctxt");
191 if (strcmp(service
, "ssh-userauth") == 0) {
192 if (!authctxt
->success
) {
194 /* now we can handle user-auth requests */
195 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &input_userauth_request
);
198 /* XXX all other service requests are denied */
201 packet_start(SSH2_MSG_SERVICE_ACCEPT
);
202 packet_put_cstring(service
);
206 debug("bad service request %s", service
);
207 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
);
292 userauth_finish(Authctxt
*authctxt
, int authenticated
, const char *method
,
293 const char *submethod
)
298 if (!authctxt
->valid
&& authenticated
)
299 fatal("INTERNAL ERROR: authenticated invalid user %s",
301 if (authenticated
&& authctxt
->postponed
)
302 fatal("INTERNAL ERROR: authenticated and postponed");
304 /* Special handling for root */
305 if (authenticated
&& authctxt
->pw
->pw_uid
== 0 &&
306 !auth_root_allowed(method
)) {
308 #ifdef SSH_AUDIT_EVENTS
309 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED
));
313 if (authenticated
&& options
.num_auth_methods
!= 0) {
314 if (!auth2_update_methods_lists(authctxt
, method
, submethod
)) {
320 /* Log before sending the reply */
321 auth_log(authctxt
, authenticated
, partial
, method
, submethod
);
323 if (authctxt
->postponed
)
327 if (options
.use_pam
&& authenticated
) {
328 if (!PRIVSEP(do_pam_account())) {
329 /* if PAM returned a message, send it to the user */
330 if (buffer_len(&loginmsg
) > 0) {
331 buffer_append(&loginmsg
, "\0", 1);
332 userauth_send_banner(buffer_ptr(&loginmsg
));
335 fatal("Access denied for user %s by PAM account "
336 "configuration", authctxt
->user
);
342 if (authenticated
&& cray_access_denied(authctxt
->user
)) {
344 fatal("Access denied for user %s.", authctxt
->user
);
348 if (authenticated
== 1) {
349 /* turn off userauth */
350 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &dispatch_protocol_ignore
);
351 packet_start(SSH2_MSG_USERAUTH_SUCCESS
);
354 /* now we can break out */
355 authctxt
->success
= 1;
358 /* Allow initial try of "none" auth without failure penalty */
359 if (!authctxt
->server_caused_failure
&&
360 (authctxt
->attempt
> 1 || strcmp(method
, "none") != 0))
361 authctxt
->failures
++;
362 if (authctxt
->failures
>= options
.max_authtries
) {
363 #ifdef SSH_AUDIT_EVENTS
364 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES
));
366 auth_maxtries_exceeded(authctxt
);
368 methods
= authmethods_get(authctxt
);
369 debug3("%s: failure partial=%d next methods=\"%s\"", __func__
,
371 packet_start(SSH2_MSG_USERAUTH_FAILURE
);
372 packet_put_cstring(methods
);
373 packet_put_char(partial
);
381 * Checks whether method is allowed by at least one AuthenticationMethods
382 * methods list. Returns 1 if allowed, or no methods lists configured.
386 auth2_method_allowed(Authctxt
*authctxt
, const char *method
,
387 const char *submethod
)
392 * NB. authctxt->num_auth_methods might be zero as a result of
393 * auth2_setup_methods_lists(), so check the configuration.
395 if (options
.num_auth_methods
== 0)
397 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
398 if (list_starts_with(authctxt
->auth_methods
[i
], method
,
399 submethod
) != MATCH_NONE
)
406 authmethods_get(Authctxt
*authctxt
)
413 for (i
= 0; authmethods
[i
] != NULL
; i
++) {
414 if (strcmp(authmethods
[i
]->name
, "none") == 0)
416 if (authmethods
[i
]->enabled
== NULL
||
417 *(authmethods
[i
]->enabled
) == 0)
419 if (!auth2_method_allowed(authctxt
, authmethods
[i
]->name
,
422 if (buffer_len(&b
) > 0)
423 buffer_append(&b
, ",", 1);
424 buffer_append(&b
, authmethods
[i
]->name
,
425 strlen(authmethods
[i
]->name
));
427 buffer_append(&b
, "\0", 1);
428 list
= xstrdup(buffer_ptr(&b
));
434 authmethod_lookup(Authctxt
*authctxt
, const char *name
)
439 for (i
= 0; authmethods
[i
] != NULL
; i
++)
440 if (authmethods
[i
]->enabled
!= NULL
&&
441 *(authmethods
[i
]->enabled
) != 0 &&
442 strcmp(name
, authmethods
[i
]->name
) == 0 &&
443 auth2_method_allowed(authctxt
,
444 authmethods
[i
]->name
, NULL
))
445 return authmethods
[i
];
446 debug2("Unrecognized authentication method name: %s",
447 name
? name
: "NULL");
452 * Check a comma-separated list of methods for validity. Is need_enable is
453 * non-zero, then also require that the methods are enabled.
454 * Returns 0 on success or -1 if the methods list is invalid.
457 auth2_methods_valid(const char *_methods
, int need_enable
)
459 char *methods
, *omethods
, *method
, *p
;
463 if (*_methods
== '\0') {
464 error("empty authentication method list");
467 omethods
= methods
= xstrdup(_methods
);
468 while ((method
= strsep(&methods
, ",")) != NULL
) {
469 for (found
= i
= 0; !found
&& authmethods
[i
] != NULL
; i
++) {
470 if ((p
= strchr(method
, ':')) != NULL
)
472 if (strcmp(method
, authmethods
[i
]->name
) != 0)
475 if (authmethods
[i
]->enabled
== NULL
||
476 *(authmethods
[i
]->enabled
) == 0) {
477 error("Disabled method \"%s\" in "
478 "AuthenticationMethods list \"%s\"",
487 error("Unknown authentication method \"%s\" in list",
499 * Prune the AuthenticationMethods supplied in the configuration, removing
500 * any methods lists that include disabled methods. Note that this might
501 * leave authctxt->num_auth_methods == 0, even when multiple required auth
502 * has been requested. For this reason, all tests for whether multiple is
503 * enabled should consult options.num_auth_methods directly.
506 auth2_setup_methods_lists(Authctxt
*authctxt
)
510 if (options
.num_auth_methods
== 0)
512 debug3("%s: checking methods", __func__
);
513 authctxt
->auth_methods
= xcalloc(options
.num_auth_methods
,
514 sizeof(*authctxt
->auth_methods
));
515 authctxt
->num_auth_methods
= 0;
516 for (i
= 0; i
< options
.num_auth_methods
; i
++) {
517 if (auth2_methods_valid(options
.auth_methods
[i
], 1) != 0) {
518 logit("Authentication methods list \"%s\" contains "
519 "disabled method, skipping",
520 options
.auth_methods
[i
]);
523 debug("authentication methods list %d: %s",
524 authctxt
->num_auth_methods
, options
.auth_methods
[i
]);
525 authctxt
->auth_methods
[authctxt
->num_auth_methods
++] =
526 xstrdup(options
.auth_methods
[i
]);
528 if (authctxt
->num_auth_methods
== 0) {
529 error("No AuthenticationMethods left after eliminating "
537 list_starts_with(const char *methods
, const char *method
,
538 const char *submethod
)
540 size_t l
= strlen(method
);
544 if (strncmp(methods
, method
, l
) != 0)
547 match
= MATCH_METHOD
;
550 return MATCH_PARTIAL
;
551 l
= strlen(submethod
);
553 if (strncmp(submethod
, p
, l
))
558 if (*p
!= ',' && *p
!= '\0')
564 * Remove method from the start of a comma-separated list of methods.
565 * Returns 0 if the list of methods did not start with that method or 1
569 remove_method(char **methods
, const char *method
, const char *submethod
)
571 char *omethods
= *methods
, *p
;
572 size_t l
= strlen(method
);
575 match
= list_starts_with(omethods
, method
, submethod
);
576 if (match
!= MATCH_METHOD
&& match
!= MATCH_BOTH
)
579 if (submethod
&& match
== MATCH_BOTH
)
580 p
+= 1 + strlen(submethod
); /* include colon */
583 *methods
= xstrdup(p
);
589 * Called after successful authentication. Will remove the successful method
590 * from the start of each list in which it occurs. If it was the last method
591 * in any list, then authentication is deemed successful.
592 * Returns 1 if the method completed any authentication list or 0 otherwise.
595 auth2_update_methods_lists(Authctxt
*authctxt
, const char *method
,
596 const char *submethod
)
600 debug3("%s: updating methods list after \"%s\"", __func__
, method
);
601 for (i
= 0; i
< authctxt
->num_auth_methods
; i
++) {
602 if (!remove_method(&(authctxt
->auth_methods
[i
]), method
,
606 if (*authctxt
->auth_methods
[i
] == '\0') {
607 debug2("authentication methods list %d complete", i
);
610 debug3("authentication methods list %d remaining: \"%s\"",
611 i
, authctxt
->auth_methods
[i
]);
613 /* This should not happen, but would be bad if it did */
615 fatal("%s: method not in AuthenticationMethods", __func__
);