diff options
Diffstat (limited to 'auth2.c')
-rw-r--r-- | auth2.c | 131 |
1 files changed, 79 insertions, 52 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2.c,v 1.149 2018/07/11 18:53:29 markus Exp $ */ | 1 | /* $OpenBSD: auth2.c,v 1.155 2019/03/25 22:34:52 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -35,6 +35,7 @@ | |||
35 | #include <stdarg.h> | 35 | #include <stdarg.h> |
36 | #include <string.h> | 36 | #include <string.h> |
37 | #include <unistd.h> | 37 | #include <unistd.h> |
38 | #include <time.h> | ||
38 | 39 | ||
39 | #include "atomicio.h" | 40 | #include "atomicio.h" |
40 | #include "xmalloc.h" | 41 | #include "xmalloc.h" |
@@ -139,18 +140,21 @@ auth2_read_banner(void) | |||
139 | return (banner); | 140 | return (banner); |
140 | } | 141 | } |
141 | 142 | ||
142 | void | 143 | static void |
143 | userauth_send_banner(const char *msg) | 144 | userauth_send_banner(struct ssh *ssh, const char *msg) |
144 | { | 145 | { |
145 | packet_start(SSH2_MSG_USERAUTH_BANNER); | 146 | int r; |
146 | packet_put_cstring(msg); | 147 | |
147 | packet_put_cstring(""); /* language, unused */ | 148 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_BANNER)) != 0 || |
148 | packet_send(); | 149 | (r = sshpkt_put_cstring(ssh, msg)) != 0 || |
150 | (r = sshpkt_put_cstring(ssh, "")) != 0 || /* language, unused */ | ||
151 | (r = sshpkt_send(ssh)) != 0) | ||
152 | fatal("%s: %s", __func__, ssh_err(r)); | ||
149 | debug("%s: sent", __func__); | 153 | debug("%s: sent", __func__); |
150 | } | 154 | } |
151 | 155 | ||
152 | static void | 156 | static void |
153 | userauth_banner(void) | 157 | userauth_banner(struct ssh *ssh) |
154 | { | 158 | { |
155 | char *banner = NULL; | 159 | char *banner = NULL; |
156 | 160 | ||
@@ -159,7 +163,7 @@ userauth_banner(void) | |||
159 | 163 | ||
160 | if ((banner = PRIVSEP(auth2_read_banner())) == NULL) | 164 | if ((banner = PRIVSEP(auth2_read_banner())) == NULL) |
161 | goto done; | 165 | goto done; |
162 | userauth_send_banner(banner); | 166 | userauth_send_banner(ssh, banner); |
163 | 167 | ||
164 | done: | 168 | done: |
165 | free(banner); | 169 | free(banner); |
@@ -169,10 +173,10 @@ done: | |||
169 | * loop until authctxt->success == TRUE | 173 | * loop until authctxt->success == TRUE |
170 | */ | 174 | */ |
171 | void | 175 | void |
172 | do_authentication2(Authctxt *authctxt) | 176 | do_authentication2(struct ssh *ssh) |
173 | { | 177 | { |
174 | struct ssh *ssh = active_state; /* XXX */ | 178 | Authctxt *authctxt = ssh->authctxt; |
175 | ssh->authctxt = authctxt; /* XXX move to caller */ | 179 | |
176 | ssh_dispatch_init(ssh, &dispatch_protocol_error); | 180 | ssh_dispatch_init(ssh, &dispatch_protocol_error); |
177 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); | 181 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); |
178 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); | 182 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); |
@@ -184,10 +188,12 @@ static int | |||
184 | input_service_request(int type, u_int32_t seq, struct ssh *ssh) | 188 | input_service_request(int type, u_int32_t seq, struct ssh *ssh) |
185 | { | 189 | { |
186 | Authctxt *authctxt = ssh->authctxt; | 190 | Authctxt *authctxt = ssh->authctxt; |
187 | u_int len; | 191 | char *service = NULL; |
188 | int acceptit = 0; | 192 | int r, acceptit = 0; |
189 | char *service = packet_get_cstring(&len); | 193 | |
190 | packet_check_eom(); | 194 | if ((r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || |
195 | (r = sshpkt_get_end(ssh)) != 0) | ||
196 | goto out; | ||
191 | 197 | ||
192 | if (authctxt == NULL) | 198 | if (authctxt == NULL) |
193 | fatal("input_service_request: no authctxt"); | 199 | fatal("input_service_request: no authctxt"); |
@@ -196,20 +202,24 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh) | |||
196 | if (!authctxt->success) { | 202 | if (!authctxt->success) { |
197 | acceptit = 1; | 203 | acceptit = 1; |
198 | /* now we can handle user-auth requests */ | 204 | /* now we can handle user-auth requests */ |
199 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); | 205 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, |
206 | &input_userauth_request); | ||
200 | } | 207 | } |
201 | } | 208 | } |
202 | /* XXX all other service requests are denied */ | 209 | /* XXX all other service requests are denied */ |
203 | 210 | ||
204 | if (acceptit) { | 211 | if (acceptit) { |
205 | packet_start(SSH2_MSG_SERVICE_ACCEPT); | 212 | if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_ACCEPT)) != 0 || |
206 | packet_put_cstring(service); | 213 | (r = sshpkt_put_cstring(ssh, service)) != 0 || |
207 | packet_send(); | 214 | (r = sshpkt_send(ssh)) != 0 || |
208 | packet_write_wait(); | 215 | (r = ssh_packet_write_wait(ssh)) != 0) |
216 | goto out; | ||
209 | } else { | 217 | } else { |
210 | debug("bad service request %s", service); | 218 | debug("bad service request %s", service); |
211 | packet_disconnect("bad service request %s", service); | 219 | ssh_packet_disconnect(ssh, "bad service request %s", service); |
212 | } | 220 | } |
221 | r = 0; | ||
222 | out: | ||
213 | free(service); | 223 | free(service); |
214 | return 0; | 224 | return 0; |
215 | } | 225 | } |
@@ -257,16 +267,17 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
257 | { | 267 | { |
258 | Authctxt *authctxt = ssh->authctxt; | 268 | Authctxt *authctxt = ssh->authctxt; |
259 | Authmethod *m = NULL; | 269 | Authmethod *m = NULL; |
260 | char *user, *service, *method, *style = NULL, *role = NULL; | 270 | char *user = NULL, *service = NULL, *method = NULL, *style = NULL, *role = NULL; |
261 | int authenticated = 0; | 271 | int r, authenticated = 0; |
262 | double tstart = monotime_double(); | 272 | double tstart = monotime_double(); |
263 | 273 | ||
264 | if (authctxt == NULL) | 274 | if (authctxt == NULL) |
265 | fatal("input_userauth_request: no authctxt"); | 275 | fatal("input_userauth_request: no authctxt"); |
266 | 276 | ||
267 | user = packet_get_cstring(NULL); | 277 | if ((r = sshpkt_get_cstring(ssh, &user, NULL)) != 0 || |
268 | service = packet_get_cstring(NULL); | 278 | (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || |
269 | method = packet_get_cstring(NULL); | 279 | (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) |
280 | goto out; | ||
270 | debug("userauth-request for user %s service %s method %s", user, service, method); | 281 | debug("userauth-request for user %s service %s method %s", user, service, method); |
271 | debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); | 282 | debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); |
272 | 283 | ||
@@ -280,7 +291,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
280 | 291 | ||
281 | if (authctxt->attempt++ == 0) { | 292 | if (authctxt->attempt++ == 0) { |
282 | /* setup auth context */ | 293 | /* setup auth context */ |
283 | authctxt->pw = PRIVSEP(getpwnamallow(user)); | 294 | authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); |
284 | authctxt->user = xstrdup(user); | 295 | authctxt->user = xstrdup(user); |
285 | if (authctxt->pw && strcmp(service, "ssh-connection")==0) { | 296 | if (authctxt->pw && strcmp(service, "ssh-connection")==0) { |
286 | authctxt->valid = 1; | 297 | authctxt->valid = 1; |
@@ -290,12 +301,12 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
290 | /* Invalid user, fake password information */ | 301 | /* Invalid user, fake password information */ |
291 | authctxt->pw = fakepw(); | 302 | authctxt->pw = fakepw(); |
292 | #ifdef SSH_AUDIT_EVENTS | 303 | #ifdef SSH_AUDIT_EVENTS |
293 | PRIVSEP(audit_event(SSH_INVALID_USER)); | 304 | PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); |
294 | #endif | 305 | #endif |
295 | } | 306 | } |
296 | #ifdef USE_PAM | 307 | #ifdef USE_PAM |
297 | if (options.use_pam) | 308 | if (options.use_pam) |
298 | PRIVSEP(start_pam(authctxt)); | 309 | PRIVSEP(start_pam(ssh)); |
299 | #endif | 310 | #endif |
300 | ssh_packet_set_log_preamble(ssh, "%suser %s", | 311 | ssh_packet_set_log_preamble(ssh, "%suser %s", |
301 | authctxt->valid ? "authenticating " : "invalid ", user); | 312 | authctxt->valid ? "authenticating " : "invalid ", user); |
@@ -306,13 +317,14 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
306 | authctxt->role = role ? xstrdup(role) : NULL; | 317 | authctxt->role = role ? xstrdup(role) : NULL; |
307 | if (use_privsep) | 318 | if (use_privsep) |
308 | mm_inform_authserv(service, style, role); | 319 | mm_inform_authserv(service, style, role); |
309 | userauth_banner(); | 320 | userauth_banner(ssh); |
310 | if (auth2_setup_methods_lists(authctxt) != 0) | 321 | if (auth2_setup_methods_lists(authctxt) != 0) |
311 | packet_disconnect("no authentication methods enabled"); | 322 | ssh_packet_disconnect(ssh, |
323 | "no authentication methods enabled"); | ||
312 | } else if (strcmp(user, authctxt->user) != 0 || | 324 | } else if (strcmp(user, authctxt->user) != 0 || |
313 | strcmp(service, authctxt->service) != 0) { | 325 | strcmp(service, authctxt->service) != 0) { |
314 | packet_disconnect("Change of username or service not allowed: " | 326 | ssh_packet_disconnect(ssh, "Change of username or service " |
315 | "(%s,%s) -> (%s,%s)", | 327 | "not allowed: (%s,%s) -> (%s,%s)", |
316 | authctxt->user, authctxt->service, user, service); | 328 | authctxt->user, authctxt->service, user, service); |
317 | } | 329 | } |
318 | /* reset state */ | 330 | /* reset state */ |
@@ -338,11 +350,12 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
338 | ensure_minimum_time_since(tstart, | 350 | ensure_minimum_time_since(tstart, |
339 | user_specific_delay(authctxt->user)); | 351 | user_specific_delay(authctxt->user)); |
340 | userauth_finish(ssh, authenticated, method, NULL); | 352 | userauth_finish(ssh, authenticated, method, NULL); |
341 | 353 | r = 0; | |
354 | out: | ||
342 | free(service); | 355 | free(service); |
343 | free(user); | 356 | free(user); |
344 | free(method); | 357 | free(method); |
345 | return 0; | 358 | return r; |
346 | } | 359 | } |
347 | 360 | ||
348 | void | 361 | void |
@@ -351,7 +364,7 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
351 | { | 364 | { |
352 | Authctxt *authctxt = ssh->authctxt; | 365 | Authctxt *authctxt = ssh->authctxt; |
353 | char *methods; | 366 | char *methods; |
354 | int partial = 0; | 367 | int r, partial = 0; |
355 | 368 | ||
356 | if (!authctxt->valid && authenticated) | 369 | if (!authctxt->valid && authenticated) |
357 | fatal("INTERNAL ERROR: authenticated invalid user %s", | 370 | fatal("INTERNAL ERROR: authenticated invalid user %s", |
@@ -364,7 +377,7 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
364 | !auth_root_allowed(ssh, method)) { | 377 | !auth_root_allowed(ssh, method)) { |
365 | authenticated = 0; | 378 | authenticated = 0; |
366 | #ifdef SSH_AUDIT_EVENTS | 379 | #ifdef SSH_AUDIT_EVENTS |
367 | PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); | 380 | PRIVSEP(audit_event(ssh, SSH_LOGIN_ROOT_DENIED)); |
368 | #endif | 381 | #endif |
369 | } | 382 | } |
370 | 383 | ||
@@ -376,7 +389,7 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
376 | } | 389 | } |
377 | 390 | ||
378 | /* Log before sending the reply */ | 391 | /* Log before sending the reply */ |
379 | auth_log(authctxt, authenticated, partial, method, submethod); | 392 | auth_log(ssh, authenticated, partial, method, submethod); |
380 | 393 | ||
381 | /* Update information exposed to session */ | 394 | /* Update information exposed to session */ |
382 | if (authenticated || partial) | 395 | if (authenticated || partial) |
@@ -395,8 +408,11 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
395 | if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0) | 408 | if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0) |
396 | fatal("%s: buffer error: %s", | 409 | fatal("%s: buffer error: %s", |
397 | __func__, ssh_err(r)); | 410 | __func__, ssh_err(r)); |
398 | userauth_send_banner(sshbuf_ptr(loginmsg)); | 411 | userauth_send_banner(ssh, sshbuf_ptr(loginmsg)); |
399 | packet_write_wait(); | 412 | if ((r = ssh_packet_write_wait(ssh)) != 0) { |
413 | sshpkt_fatal(ssh, r, | ||
414 | "%s: send PAM banner", __func__); | ||
415 | } | ||
400 | } | 416 | } |
401 | fatal("Access denied for user %s by PAM account " | 417 | fatal("Access denied for user %s by PAM account " |
402 | "configuration", authctxt->user); | 418 | "configuration", authctxt->user); |
@@ -406,10 +422,12 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
406 | 422 | ||
407 | if (authenticated == 1) { | 423 | if (authenticated == 1) { |
408 | /* turn off userauth */ | 424 | /* turn off userauth */ |
409 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); | 425 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, |
410 | packet_start(SSH2_MSG_USERAUTH_SUCCESS); | 426 | &dispatch_protocol_ignore); |
411 | packet_send(); | 427 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_SUCCESS)) != 0 || |
412 | packet_write_wait(); | 428 | (r = sshpkt_send(ssh)) != 0 || |
429 | (r = ssh_packet_write_wait(ssh)) != 0) | ||
430 | fatal("%s: %s", __func__, ssh_err(r)); | ||
413 | /* now we can break out */ | 431 | /* now we can break out */ |
414 | authctxt->success = 1; | 432 | authctxt->success = 1; |
415 | ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); | 433 | ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); |
@@ -420,18 +438,19 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
420 | authctxt->failures++; | 438 | authctxt->failures++; |
421 | if (authctxt->failures >= options.max_authtries) { | 439 | if (authctxt->failures >= options.max_authtries) { |
422 | #ifdef SSH_AUDIT_EVENTS | 440 | #ifdef SSH_AUDIT_EVENTS |
423 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); | 441 | PRIVSEP(audit_event(ssh, SSH_LOGIN_EXCEED_MAXTRIES)); |
424 | #endif | 442 | #endif |
425 | auth_maxtries_exceeded(authctxt); | 443 | auth_maxtries_exceeded(ssh); |
426 | } | 444 | } |
427 | methods = authmethods_get(authctxt); | 445 | methods = authmethods_get(authctxt); |
428 | debug3("%s: failure partial=%d next methods=\"%s\"", __func__, | 446 | debug3("%s: failure partial=%d next methods=\"%s\"", __func__, |
429 | partial, methods); | 447 | partial, methods); |
430 | packet_start(SSH2_MSG_USERAUTH_FAILURE); | 448 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_FAILURE)) != 0 || |
431 | packet_put_cstring(methods); | 449 | (r = sshpkt_put_cstring(ssh, methods)) != 0 || |
432 | packet_put_char(partial); | 450 | (r = sshpkt_put_u8(ssh, partial)) != 0 || |
433 | packet_send(); | 451 | (r = sshpkt_send(ssh)) != 0 || |
434 | packet_write_wait(); | 452 | (r = ssh_packet_write_wait(ssh)) != 0) |
453 | fatal("%s: %s", __func__, ssh_err(r)); | ||
435 | free(methods); | 454 | free(methods); |
436 | } | 455 | } |
437 | } | 456 | } |
@@ -566,6 +585,14 @@ auth2_setup_methods_lists(Authctxt *authctxt) | |||
566 | { | 585 | { |
567 | u_int i; | 586 | u_int i; |
568 | 587 | ||
588 | /* First, normalise away the "any" pseudo-method */ | ||
589 | if (options.num_auth_methods == 1 && | ||
590 | strcmp(options.auth_methods[0], "any") == 0) { | ||
591 | free(options.auth_methods[0]); | ||
592 | options.auth_methods[0] = NULL; | ||
593 | options.num_auth_methods = 0; | ||
594 | } | ||
595 | |||
569 | if (options.num_auth_methods == 0) | 596 | if (options.num_auth_methods == 0) |
570 | return 0; | 597 | return 0; |
571 | debug3("%s: checking methods", __func__); | 598 | debug3("%s: checking methods", __func__); |