1 /* $NetBSD: auth2.c,v 1.12 2016/08/02 13:45:12 christos Exp $ */ 2 /* $OpenBSD: auth2.c,v 1.136 2016/05/02 08:49:03 djm Exp $ */ 3 /* 4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "includes.h" 28 __RCSID("$NetBSD: auth2.c,v 1.12 2016/08/02 13:45:12 christos Exp $"); 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/uio.h> 32 33 #include <fcntl.h> 34 #include <pwd.h> 35 #include <stdarg.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "atomicio.h" 40 #include "xmalloc.h" 41 #include "ssh2.h" 42 #include "packet.h" 43 #include "log.h" 44 #include "buffer.h" 45 #include "misc.h" 46 #include "servconf.h" 47 #include "compat.h" 48 #include "key.h" 49 #include "hostfile.h" 50 #include "auth.h" 51 #include "dispatch.h" 52 #include "pathnames.h" 53 #include "buffer.h" 54 #include "canohost.h" 55 #include "pfilter.h" 56 57 #ifdef GSSAPI 58 #include "ssh-gss.h" 59 #endif 60 61 #include "monitor_wrap.h" 62 63 /* import */ 64 extern ServerOptions options; 65 extern u_char *session_id2; 66 extern u_int session_id2_len; 67 extern Buffer loginmsg; 68 69 /* methods */ 70 71 extern Authmethod method_none; 72 extern Authmethod method_pubkey; 73 extern Authmethod method_passwd; 74 extern Authmethod method_kbdint; 75 extern Authmethod method_hostbased; 76 #ifdef KRB5 77 extern Authmethod method_kerberos; 78 #endif 79 #ifdef GSSAPI 80 extern Authmethod method_gssapi; 81 #endif 82 83 static int log_flag = 0; 84 85 Authmethod *authmethods[] = { 86 &method_none, 87 &method_pubkey, 88 #ifdef GSSAPI 89 &method_gssapi, 90 #endif 91 &method_passwd, 92 &method_kbdint, 93 &method_hostbased, 94 #ifdef KRB5 95 &method_kerberos, 96 #endif 97 NULL 98 }; 99 100 /* protocol */ 101 102 static int input_service_request(int, u_int32_t, void *); 103 static int input_userauth_request(int, u_int32_t, void *); 104 105 /* helper */ 106 static Authmethod *authmethod_lookup(Authctxt *, const char *); 107 static char *authmethods_get(Authctxt *authctxt); 108 109 #define MATCH_NONE 0 /* method or submethod mismatch */ 110 #define MATCH_METHOD 1 /* method matches (no submethod specified) */ 111 #define MATCH_BOTH 2 /* method and submethod match */ 112 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */ 113 static int list_starts_with(const char *, const char *, const char *); 114 115 char * 116 auth2_read_banner(void) 117 { 118 struct stat st; 119 char *banner = NULL; 120 size_t len, n; 121 int fd; 122 123 if ((fd = open(options.banner, O_RDONLY)) == -1) 124 return (NULL); 125 if (fstat(fd, &st) == -1) { 126 close(fd); 127 return (NULL); 128 } 129 if (st.st_size <= 0 || st.st_size > 1*1024*1024) { 130 close(fd); 131 return (NULL); 132 } 133 134 len = (size_t)st.st_size; /* truncate */ 135 banner = xmalloc(len + 1); 136 n = atomicio(read, fd, banner, len); 137 close(fd); 138 139 if (n != len) { 140 free(banner); 141 return (NULL); 142 } 143 banner[n] = '\0'; 144 145 return (banner); 146 } 147 148 static void 149 userauth_send_banner(const char *msg) 150 { 151 if (datafellows & SSH_BUG_BANNER) 152 return; 153 154 packet_start(SSH2_MSG_USERAUTH_BANNER); 155 packet_put_cstring(msg); 156 packet_put_cstring(""); /* language, unused */ 157 packet_send(); 158 debug("%s: sent", __func__); 159 } 160 161 static void 162 userauth_banner(void) 163 { 164 char *banner = NULL; 165 166 if (options.banner == NULL || (datafellows & SSH_BUG_BANNER) != 0) 167 return; 168 169 if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 170 goto done; 171 172 userauth_send_banner(banner); 173 done: 174 free(banner); 175 } 176 177 /* 178 * loop until authctxt->success == TRUE 179 */ 180 void 181 do_authentication2(Authctxt *authctxt) 182 { 183 dispatch_init(&dispatch_protocol_error); 184 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 185 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 186 } 187 188 /*ARGSUSED*/ 189 static int 190 input_service_request(int type, u_int32_t seq, void *ctxt) 191 { 192 Authctxt *authctxt = ctxt; 193 u_int len; 194 int acceptit = 0; 195 char *service = packet_get_cstring(&len); 196 packet_check_eom(); 197 198 if (authctxt == NULL) 199 fatal("input_service_request: no authctxt"); 200 201 if (strcmp(service, "ssh-userauth") == 0) { 202 if (!authctxt->success) { 203 acceptit = 1; 204 /* now we can handle user-auth requests */ 205 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 206 } 207 } 208 /* XXX all other service requests are denied */ 209 210 if (acceptit) { 211 packet_start(SSH2_MSG_SERVICE_ACCEPT); 212 packet_put_cstring(service); 213 packet_send(); 214 packet_write_wait(); 215 } else { 216 debug("bad service request %s", service); 217 packet_disconnect("bad service request %s", service); 218 } 219 free(service); 220 return 0; 221 } 222 223 /*ARGSUSED*/ 224 static int 225 input_userauth_request(int type, u_int32_t seq, void *ctxt) 226 { 227 Authctxt *authctxt = ctxt; 228 Authmethod *m = NULL; 229 char *user, *service, *method, *style = NULL; 230 int authenticated = 0; 231 struct ssh *ssh = active_state; /* XXX */ 232 233 if (authctxt == NULL) 234 fatal("input_userauth_request: no authctxt"); 235 236 user = packet_get_cstring(NULL); 237 service = packet_get_cstring(NULL); 238 method = packet_get_cstring(NULL); 239 debug("userauth-request for user %s service %s method %s", user, service, method); 240 if (!log_flag) { 241 logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", 242 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), user); 243 log_flag = 1; 244 } 245 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 246 247 if ((style = strchr(user, ':')) != NULL) 248 *style++ = 0; 249 250 if (authctxt->attempt++ == 0) { 251 /* setup auth context */ 252 authctxt->pw = PRIVSEP(getpwnamallow(user)); 253 authctxt->user = xstrdup(user); 254 if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 255 authctxt->valid = 1; 256 debug2("input_userauth_request: setting up authctxt for %s", user); 257 } else { 258 logit("input_userauth_request: invalid user %s", user); 259 authctxt->pw = fakepw(); 260 pfilter_notify(1); 261 } 262 #ifdef USE_PAM 263 if (options.use_pam) 264 PRIVSEP(start_pam(authctxt)); 265 #endif 266 setproctitle("%s%s", authctxt->valid ? user : "unknown", 267 use_privsep ? " [net]" : ""); 268 authctxt->service = xstrdup(service); 269 authctxt->style = style ? xstrdup(style) : NULL; 270 if (use_privsep) 271 mm_inform_authserv(service, style); 272 userauth_banner(); 273 if (auth2_setup_methods_lists(authctxt) != 0) 274 packet_disconnect("no authentication methods enabled"); 275 } else if (strcmp(user, authctxt->user) != 0 || 276 strcmp(service, authctxt->service) != 0) { 277 packet_disconnect("Change of username or service not allowed: " 278 "(%s,%s) -> (%s,%s)", 279 authctxt->user, authctxt->service, user, service); 280 } 281 /* reset state */ 282 auth2_challenge_stop(authctxt); 283 284 #ifdef GSSAPI 285 /* XXX move to auth2_gssapi_stop() */ 286 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 287 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 288 #endif 289 290 authctxt->postponed = 0; 291 authctxt->server_caused_failure = 0; 292 293 /* try to authenticate user */ 294 m = authmethod_lookup(authctxt, method); 295 if (m != NULL && authctxt->failures < options.max_authtries) { 296 debug2("input_userauth_request: try method %s", method); 297 authenticated = m->userauth(authctxt); 298 } 299 userauth_finish(authctxt, authenticated, method, NULL); 300 301 free(service); 302 free(user); 303 free(method); 304 return 0; 305 } 306 307 void 308 userauth_finish(Authctxt *authctxt, int authenticated, const char *method, 309 const char *submethod) 310 { 311 char *methods; 312 int partial = 0; 313 314 if (!authctxt->valid && authenticated) 315 fatal("INTERNAL ERROR: authenticated invalid user %s", 316 authctxt->user); 317 if (authenticated && authctxt->postponed) 318 fatal("INTERNAL ERROR: authenticated and postponed"); 319 320 /* Special handling for root */ 321 if (authenticated && authctxt->pw->pw_uid == 0 && 322 !auth_root_allowed(method)) { 323 authenticated = 0; 324 #ifdef SSH_AUDIT_EVENTS 325 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 326 #endif 327 } 328 329 #ifdef USE_PAM 330 if (options.use_pam && authenticated) { 331 if (!PRIVSEP(do_pam_account())) { 332 /* if PAM returned a message, send it to the user */ 333 if (buffer_len(&loginmsg) > 0) { 334 buffer_append(&loginmsg, "\0", 1); 335 userauth_send_banner((const char *)buffer_ptr(&loginmsg)); 336 packet_write_wait(); 337 } 338 fatal("Access denied for user %s by PAM account " 339 "configuration", authctxt->user); 340 } 341 } 342 #endif 343 344 if (authenticated && options.num_auth_methods != 0) { 345 if (!auth2_update_methods_lists(authctxt, method, submethod)) { 346 authenticated = 0; 347 partial = 1; 348 } 349 } 350 351 /* Log before sending the reply */ 352 auth_log(authctxt, authenticated, partial, method, submethod); 353 354 if (authctxt->postponed) 355 return; 356 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); 361 packet_send(); 362 packet_write_wait(); 363 /* now we can break out */ 364 authctxt->success = 1; 365 } else { 366 /* Allow initial try of "none" auth without failure penalty */ 367 if (!partial && !authctxt->server_caused_failure && 368 (authctxt->attempt > 1 || strcmp(method, "none") != 0)) 369 authctxt->failures++; 370 if (authctxt->failures >= options.max_authtries) 371 auth_maxtries_exceeded(authctxt); 372 methods = authmethods_get(authctxt); 373 debug3("%s: failure partial=%d next methods=\"%s\"", __func__, 374 partial, methods); 375 packet_start(SSH2_MSG_USERAUTH_FAILURE); 376 packet_put_cstring(methods); 377 packet_put_char(partial); 378 packet_send(); 379 packet_write_wait(); 380 free(methods); 381 } 382 } 383 384 /* 385 * Checks whether method is allowed by at least one AuthenticationMethods 386 * methods list. Returns 1 if allowed, or no methods lists configured. 387 * 0 otherwise. 388 */ 389 int 390 auth2_method_allowed(Authctxt *authctxt, const char *method, 391 const char *submethod) 392 { 393 u_int i; 394 395 /* 396 * NB. authctxt->num_auth_methods might be zero as a result of 397 * auth2_setup_methods_lists(), so check the configuration. 398 */ 399 if (options.num_auth_methods == 0) 400 return 1; 401 for (i = 0; i < authctxt->num_auth_methods; i++) { 402 if (list_starts_with(authctxt->auth_methods[i], method, 403 submethod) != MATCH_NONE) 404 return 1; 405 } 406 return 0; 407 } 408 409 static char * 410 authmethods_get(Authctxt *authctxt) 411 { 412 Buffer b; 413 char *list; 414 u_int i; 415 416 buffer_init(&b); 417 for (i = 0; authmethods[i] != NULL; i++) { 418 if (strcmp(authmethods[i]->name, "none") == 0) 419 continue; 420 if (authmethods[i]->enabled == NULL || 421 *(authmethods[i]->enabled) == 0) 422 continue; 423 if (!auth2_method_allowed(authctxt, authmethods[i]->name, 424 NULL)) 425 continue; 426 if (buffer_len(&b) > 0) 427 buffer_append(&b, ",", 1); 428 buffer_append(&b, authmethods[i]->name, 429 strlen(authmethods[i]->name)); 430 } 431 if ((list = sshbuf_dup_string(&b)) == NULL) 432 fatal("%s: sshbuf_dup_string failed", __func__); 433 buffer_free(&b); 434 return list; 435 } 436 437 static Authmethod * 438 authmethod_lookup(Authctxt *authctxt, const char *name) 439 { 440 int i; 441 442 if (name != NULL) 443 for (i = 0; authmethods[i] != NULL; i++) 444 if (authmethods[i]->enabled != NULL && 445 *(authmethods[i]->enabled) != 0 && 446 strcmp(name, authmethods[i]->name) == 0 && 447 auth2_method_allowed(authctxt, 448 authmethods[i]->name, NULL)) 449 return authmethods[i]; 450 debug2("Unrecognized authentication method name: %s", 451 name ? name : "NULL"); 452 return NULL; 453 } 454 455 /* 456 * Check a comma-separated list of methods for validity. Is need_enable is 457 * non-zero, then also require that the methods are enabled. 458 * Returns 0 on success or -1 if the methods list is invalid. 459 */ 460 int 461 auth2_methods_valid(const char *_methods, int need_enable) 462 { 463 char *methods, *omethods, *method, *p; 464 u_int i, found; 465 int ret = -1; 466 467 if (*_methods == '\0') { 468 error("empty authentication method list"); 469 return -1; 470 } 471 omethods = methods = xstrdup(_methods); 472 while ((method = strsep(&methods, ",")) != NULL) { 473 for (found = i = 0; !found && authmethods[i] != NULL; i++) { 474 if ((p = strchr(method, ':')) != NULL) 475 *p = '\0'; 476 if (strcmp(method, authmethods[i]->name) != 0) 477 continue; 478 if (need_enable) { 479 if (authmethods[i]->enabled == NULL || 480 *(authmethods[i]->enabled) == 0) { 481 error("Disabled method \"%s\" in " 482 "AuthenticationMethods list \"%s\"", 483 method, _methods); 484 goto out; 485 } 486 } 487 found = 1; 488 break; 489 } 490 if (!found) { 491 error("Unknown authentication method \"%s\" in list", 492 method); 493 goto out; 494 } 495 } 496 ret = 0; 497 out: 498 free(omethods); 499 return ret; 500 } 501 502 /* 503 * Prune the AuthenticationMethods supplied in the configuration, removing 504 * any methods lists that include disabled methods. Note that this might 505 * leave authctxt->num_auth_methods == 0, even when multiple required auth 506 * has been requested. For this reason, all tests for whether multiple is 507 * enabled should consult options.num_auth_methods directly. 508 */ 509 int 510 auth2_setup_methods_lists(Authctxt *authctxt) 511 { 512 u_int i; 513 514 if (options.num_auth_methods == 0) 515 return 0; 516 debug3("%s: checking methods", __func__); 517 authctxt->auth_methods = xcalloc(options.num_auth_methods, 518 sizeof(*authctxt->auth_methods)); 519 authctxt->num_auth_methods = 0; 520 for (i = 0; i < options.num_auth_methods; i++) { 521 if (auth2_methods_valid(options.auth_methods[i], 1) != 0) { 522 logit("Authentication methods list \"%s\" contains " 523 "disabled method, skipping", 524 options.auth_methods[i]); 525 continue; 526 } 527 debug("authentication methods list %d: %s", 528 authctxt->num_auth_methods, options.auth_methods[i]); 529 authctxt->auth_methods[authctxt->num_auth_methods++] = 530 xstrdup(options.auth_methods[i]); 531 } 532 if (authctxt->num_auth_methods == 0) { 533 error("No AuthenticationMethods left after eliminating " 534 "disabled methods"); 535 return -1; 536 } 537 return 0; 538 } 539 540 static int 541 list_starts_with(const char *methods, const char *method, 542 const char *submethod) 543 { 544 size_t l = strlen(method); 545 int match; 546 const char *p; 547 548 if (strncmp(methods, method, l) != 0) 549 return MATCH_NONE; 550 p = methods + l; 551 match = MATCH_METHOD; 552 if (*p == ':') { 553 if (!submethod) 554 return MATCH_PARTIAL; 555 l = strlen(submethod); 556 p += 1; 557 if (strncmp(submethod, p, l)) 558 return MATCH_NONE; 559 p += l; 560 match = MATCH_BOTH; 561 } 562 if (*p != ',' && *p != '\0') 563 return MATCH_NONE; 564 return match; 565 } 566 567 /* 568 * Remove method from the start of a comma-separated list of methods. 569 * Returns 0 if the list of methods did not start with that method or 1 570 * if it did. 571 */ 572 static int 573 remove_method(char **methods, const char *method, const char *submethod) 574 { 575 char *omethods = *methods, *p; 576 size_t l = strlen(method); 577 int match; 578 579 match = list_starts_with(omethods, method, submethod); 580 if (match != MATCH_METHOD && match != MATCH_BOTH) 581 return 0; 582 p = omethods + l; 583 if (submethod && match == MATCH_BOTH) 584 p += 1 + strlen(submethod); /* include colon */ 585 if (*p == ',') 586 p++; 587 *methods = xstrdup(p); 588 free(omethods); 589 return 1; 590 } 591 592 /* 593 * Called after successful authentication. Will remove the successful method 594 * from the start of each list in which it occurs. If it was the last method 595 * in any list, then authentication is deemed successful. 596 * Returns 1 if the method completed any authentication list or 0 otherwise. 597 */ 598 int 599 auth2_update_methods_lists(Authctxt *authctxt, const char *method, 600 const char *submethod) 601 { 602 u_int i, found = 0; 603 604 debug3("%s: updating methods list after \"%s\"", __func__, method); 605 for (i = 0; i < authctxt->num_auth_methods; i++) { 606 if (!remove_method(&(authctxt->auth_methods[i]), method, 607 submethod)) 608 continue; 609 found = 1; 610 if (*authctxt->auth_methods[i] == '\0') { 611 debug2("authentication methods list %d complete", i); 612 return 1; 613 } 614 debug3("authentication methods list %d remaining: \"%s\"", 615 i, authctxt->auth_methods[i]); 616 } 617 /* This should not happen, but would be bad if it did */ 618 if (!found) 619 fatal("%s: method not in AuthenticationMethods", __func__); 620 return 0; 621 } 622 623 624