1 /* $OpenBSD: auth2.c,v 1.119 2008/07/04 23:30:16 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"
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(const char *);
95 static char *authmethods_get(void);
98 auth2_read_banner(void)
105 if ((fd
= open(options
.banner
, O_RDONLY
)) == -1)
107 if (fstat(fd
, &st
) == -1) {
111 if (st
.st_size
> 1*1024*1024) {
116 len
= (size_t)st
.st_size
; /* truncate */
117 banner
= xmalloc(len
+ 1);
118 n
= atomicio(read
, fd
, banner
, len
);
131 userauth_send_banner(const char *msg
)
133 if (datafellows
& SSH_BUG_BANNER
)
136 packet_start(SSH2_MSG_USERAUTH_BANNER
);
137 packet_put_cstring(msg
);
138 packet_put_cstring(""); /* language, unused */
140 debug("%s: sent", __func__
);
144 userauth_banner(void)
148 if (options
.banner
== NULL
||
149 strcasecmp(options
.banner
, "none") == 0 ||
150 (datafellows
& SSH_BUG_BANNER
) != 0)
153 if ((banner
= PRIVSEP(auth2_read_banner())) == NULL
)
155 userauth_send_banner(banner
);
163 * loop until authctxt->success == TRUE
166 do_authentication2(Authctxt
*authctxt
)
168 dispatch_init(&dispatch_protocol_error
);
169 dispatch_set(SSH2_MSG_SERVICE_REQUEST
, &input_service_request
);
170 dispatch_run(DISPATCH_BLOCK
, &authctxt
->success
, authctxt
);
175 input_service_request(int type
, u_int32_t seq
, void *ctxt
)
177 Authctxt
*authctxt
= ctxt
;
180 char *service
= packet_get_string(&len
);
183 if (authctxt
== NULL
)
184 fatal("input_service_request: no authctxt");
186 if (strcmp(service
, "ssh-userauth") == 0) {
187 if (!authctxt
->success
) {
189 /* now we can handle user-auth requests */
190 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &input_userauth_request
);
193 /* XXX all other service requests are denied */
196 packet_start(SSH2_MSG_SERVICE_ACCEPT
);
197 packet_put_cstring(service
);
201 debug("bad service request %s", service
);
202 packet_disconnect("bad service request %s", service
);
209 input_userauth_request(int type
, u_int32_t seq
, void *ctxt
)
211 Authctxt
*authctxt
= ctxt
;
212 Authmethod
*m
= NULL
;
213 char *user
, *service
, *method
, *style
= NULL
;
214 int authenticated
= 0;
215 #ifdef HAVE_LOGIN_CAP
217 const char *from_host
, *from_ip
;
219 from_host
= get_canonical_hostname(options
.use_dns
);
220 from_ip
= get_remote_ipaddr();
223 if (authctxt
== NULL
)
224 fatal("input_userauth_request: no authctxt");
226 user
= packet_get_string(NULL
);
227 service
= packet_get_string(NULL
);
228 method
= packet_get_string(NULL
);
229 debug("userauth-request for user %s service %s method %s", user
, service
, method
);
230 debug("attempt %d failures %d", authctxt
->attempt
, authctxt
->failures
);
232 if ((style
= strchr(user
, ':')) != NULL
)
235 if (authctxt
->attempt
++ == 0) {
236 /* setup auth context */
237 authctxt
->pw
= PRIVSEP(getpwnamallow(user
));
238 authctxt
->user
= xstrdup(user
);
239 if (authctxt
->pw
&& strcmp(service
, "ssh-connection")==0) {
241 debug2("input_userauth_request: setting up authctxt for %s", user
);
243 logit("input_userauth_request: invalid user %s", user
);
244 authctxt
->pw
= fakepw();
245 #ifdef SSH_AUDIT_EVENTS
246 PRIVSEP(audit_event(SSH_INVALID_USER
));
251 PRIVSEP(start_pam(authctxt
));
253 setproctitle("%s%s", authctxt
->valid
? user
: "unknown",
254 use_privsep
? " [net]" : "");
255 authctxt
->service
= xstrdup(service
);
256 authctxt
->style
= style
? xstrdup(style
) : NULL
;
258 mm_inform_authserv(service
, style
);
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 #ifdef HAVE_LOGIN_CAP
268 if (authctxt
->pw
!= NULL
) {
269 lc
= login_getpwclass(authctxt
->pw
);
271 lc
= login_getclassbyname(NULL
, authctxt
->pw
);
272 if (!auth_hostok(lc
, from_host
, from_ip
)) {
273 logit("Denied connection for %.200s from %.200s [%.200s].",
274 authctxt
->pw
->pw_name
, from_host
, from_ip
);
275 packet_disconnect("Sorry, you are not allowed to connect.");
277 if (!auth_timeok(lc
, time(NULL
))) {
278 logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
279 authctxt
->pw
->pw_name
, from_host
);
280 packet_disconnect("Logins not available right now.");
285 #endif /* HAVE_LOGIN_CAP */
288 auth2_challenge_stop(authctxt
);
291 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN
, NULL
);
292 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE
, NULL
);
295 authctxt
->postponed
= 0;
297 /* try to authenticate user */
298 m
= authmethod_lookup(method
);
299 if (m
!= NULL
&& authctxt
->failures
< options
.max_authtries
) {
300 debug2("input_userauth_request: try method %s", method
);
301 authenticated
= m
->userauth(authctxt
);
303 userauth_finish(authctxt
, authenticated
, method
);
311 userauth_finish(Authctxt
*authctxt
, int authenticated
, char *method
)
315 if (!authctxt
->valid
&& authenticated
)
316 fatal("INTERNAL ERROR: authenticated invalid user %s",
319 /* Special handling for root */
320 if (authenticated
&& authctxt
->pw
->pw_uid
== 0 &&
321 !auth_root_allowed(method
)) {
323 #ifdef SSH_AUDIT_EVENTS
324 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED
));
329 if (options
.use_pam
&& authenticated
) {
330 if (!PRIVSEP(do_pam_account())) {
331 /* if PAM returned a message, send it to the user */
332 if (buffer_len(&loginmsg
) > 0) {
333 buffer_append(&loginmsg
, "\0", 1);
334 userauth_send_banner(buffer_ptr(&loginmsg
));
337 fatal("Access denied for user %s by PAM account "
338 "configuration", authctxt
->user
);
344 if (authenticated
&& cray_access_denied(authctxt
->user
)) {
346 fatal("Access denied for user %s.",authctxt
->user
);
350 /* Log before sending the reply */
351 auth_log(authctxt
, authenticated
, method
, " ssh2");
353 if (authctxt
->postponed
)
356 /* XXX todo: check if multiple auth methods are needed */
357 if (authenticated
== 1) {
358 /* turn off userauth */
359 dispatch_set(SSH2_MSG_USERAUTH_REQUEST
, &dispatch_protocol_ignore
);
360 packet_start(SSH2_MSG_USERAUTH_SUCCESS
);
363 /* now we can break out */
364 authctxt
->success
= 1;
367 /* Allow initial try of "none" auth without failure penalty */
368 if (authctxt
->attempt
> 1 || strcmp(method
, "none") != 0)
369 authctxt
->failures
++;
370 if (authctxt
->failures
>= options
.max_authtries
) {
371 #ifdef SSH_AUDIT_EVENTS
372 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES
));
374 packet_disconnect(AUTH_FAIL_MSG
, authctxt
->user
);
376 methods
= authmethods_get();
377 packet_start(SSH2_MSG_USERAUTH_FAILURE
);
378 packet_put_cstring(methods
);
379 packet_put_char(0); /* XXX partial success, unused */
387 authmethods_get(void)
394 for (i
= 0; authmethods
[i
] != NULL
; i
++) {
395 if (strcmp(authmethods
[i
]->name
, "none") == 0)
397 if (authmethods
[i
]->enabled
!= NULL
&&
398 *(authmethods
[i
]->enabled
) != 0) {
399 if (buffer_len(&b
) > 0)
400 buffer_append(&b
, ",", 1);
401 buffer_append(&b
, authmethods
[i
]->name
,
402 strlen(authmethods
[i
]->name
));
405 buffer_append(&b
, "\0", 1);
406 list
= xstrdup(buffer_ptr(&b
));
412 authmethod_lookup(const char *name
)
417 for (i
= 0; authmethods
[i
] != NULL
; i
++)
418 if (authmethods
[i
]->enabled
!= NULL
&&
419 *(authmethods
[i
]->enabled
) != 0 &&
420 strcmp(name
, authmethods
[i
]->name
) == 0)
421 return authmethods
[i
];
422 debug2("Unrecognized authentication method name: %s",
423 name
? name
: "NULL");