auth2.c revision 69591
1160814Ssimon/* 2160814Ssimon * Copyright (c) 2000 Markus Friedl. All rights reserved. 3160814Ssimon * 4160814Ssimon * Redistribution and use in source and binary forms, with or without 5160814Ssimon * modification, are permitted provided that the following conditions 6337982Sjkim * are met: 7160814Ssimon * 1. Redistributions of source code must retain the above copyright 8160814Ssimon * notice, this list of conditions and the following disclaimer. 9160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright 10160814Ssimon * notice, this list of conditions and the following disclaimer in the 11160814Ssimon * documentation and/or other materials provided with the distribution. 12160814Ssimon * 13280297Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14160814Ssimon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15160814Ssimon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16160814Ssimon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17160814Ssimon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19160814Ssimon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20160814Ssimon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21160814Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22160814Ssimon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23160814Ssimon */ 24160814Ssimon 25160814Ssimon#include "includes.h" 26160814SsimonRCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); 27160814SsimonRCSID("$FreeBSD: head/crypto/openssh/auth2.c 69591 2000-12-05 02:55:12Z green $"); 28160814Ssimon 29160814Ssimon#include <openssl/dsa.h> 30160814Ssimon#include <openssl/rsa.h> 31160814Ssimon#include <openssl/evp.h> 32160814Ssimon 33160814Ssimon#include "xmalloc.h" 34160814Ssimon#include "rsa.h" 35160814Ssimon#include "ssh.h" 36160814Ssimon#include "pty.h" 37160814Ssimon#include "packet.h" 38160814Ssimon#include "buffer.h" 39160814Ssimon#include "servconf.h" 40160814Ssimon#include "compat.h" 41160814Ssimon#include "channels.h" 42160814Ssimon#include "bufaux.h" 43160814Ssimon#include "ssh2.h" 44160814Ssimon#include "auth.h" 45160814Ssimon#include "session.h" 46160814Ssimon#include "dispatch.h" 47160814Ssimon#include "auth.h" 48160814Ssimon#include "key.h" 49160814Ssimon#include "kex.h" 50160814Ssimon 51160814Ssimon#include "dsa.h" 52160814Ssimon#include "uidswap.h" 53160814Ssimon#include "auth-options.h" 54160814Ssimon 55160814Ssimon#ifdef HAVE_LOGIN_CAP 56160814Ssimon#include <login_cap.h> 57160814Ssimon#endif /* HAVE_LOGIN_CAP */ 58160814Ssimon 59160814Ssimon/* import */ 60160814Ssimonextern ServerOptions options; 61280297Sjkimextern unsigned char *session_id2; 62160814Ssimonextern int session_id2_len; 63160814Ssimon 64160814Ssimonstatic Authctxt *x_authctxt = NULL; 65160814Ssimonstatic int one = 1; 66160814Ssimon 67280297Sjkimtypedef struct Authmethod Authmethod; 68160814Ssimonstruct Authmethod { 69160814Ssimon char *name; 70160814Ssimon int (*userauth)(Authctxt *authctxt); 71160814Ssimon int *enabled; 72160814Ssimon}; 73160814Ssimon 74160814Ssimon/* protocol */ 75160814Ssimon 76160814Ssimonvoid input_service_request(int type, int plen, void *ctxt); 77160814Ssimonvoid input_userauth_request(int type, int plen, void *ctxt); 78160814Ssimonvoid protocol_error(int type, int plen, void *ctxt); 79280297Sjkim 80280297Sjkim 81280297Sjkim/* helper */ 82280297SjkimAuthmethod *authmethod_lookup(const char *name); 83280297Sjkimstruct passwd *pwcopy(struct passwd *pw); 84160814Ssimonint user_dsa_key_allowed(struct passwd *pw, Key *key); 85160814Ssimonchar *authmethods_get(void); 86280297Sjkim 87280297Sjkim/* auth */ 88280297Sjkimint userauth_none(Authctxt *authctxt); 89280297Sjkimint userauth_passwd(Authctxt *authctxt); 90280297Sjkimint userauth_pubkey(Authctxt *authctxt); 91280297Sjkimint userauth_kbdint(Authctxt *authctxt); 92280297Sjkim 93280297SjkimAuthmethod authmethods[] = { 94280297Sjkim {"none", 95280297Sjkim userauth_none, 96160814Ssimon &one}, 97160814Ssimon {"publickey", 98280297Sjkim userauth_pubkey, 99160814Ssimon &options.dsa_authentication}, 100160814Ssimon {"keyboard-interactive", 101160814Ssimon userauth_kbdint, 102160814Ssimon &options.kbd_interactive_authentication}, 103160814Ssimon {"password", 104160814Ssimon userauth_passwd, 105160814Ssimon &options.password_authentication}, 106160814Ssimon {NULL, NULL, NULL} 107160814Ssimon}; 108160814Ssimon 109160814Ssimon/* 110280297Sjkim * loop until authctxt->success == TRUE 111160814Ssimon */ 112160814Ssimon 113160814Ssimonvoid 114280297Sjkimdo_authentication2() 115280297Sjkim{ 116280297Sjkim Authctxt *authctxt = xmalloc(sizeof(*authctxt)); 117280297Sjkim memset(authctxt, 'a', sizeof(*authctxt)); 118160814Ssimon authctxt->valid = 0; 119280297Sjkim authctxt->attempt = 0; 120280297Sjkim authctxt->success = 0; 121280297Sjkim x_authctxt = authctxt; /*XXX*/ 122280297Sjkim 123280297Sjkim#ifdef KRB4 124280297Sjkim /* turn off kerberos, not supported by SSH2 */ 125280297Sjkim options.krb4_authentication = 0; 126280297Sjkim#endif 127280297Sjkim dispatch_init(&protocol_error); 128280297Sjkim dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 129280297Sjkim dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 130280297Sjkim do_authenticated2(); 131160814Ssimon} 132160814Ssimon 133280297Sjkimvoid 134280297Sjkimprotocol_error(int type, int plen, void *ctxt) 135280297Sjkim{ 136280297Sjkim log("auth: protocol error: type %d plen %d", type, plen); 137280297Sjkim packet_start(SSH2_MSG_UNIMPLEMENTED); 138280297Sjkim packet_put_int(0); 139160814Ssimon packet_send(); 140337982Sjkim packet_write_wait(); 141160814Ssimon} 142280297Sjkim 143280297Sjkimvoid 144280297Sjkiminput_service_request(int type, int plen, void *ctxt) 145280297Sjkim{ 146280297Sjkim Authctxt *authctxt = ctxt; 147280297Sjkim unsigned int len; 148280297Sjkim int accept = 0; 149280297Sjkim char *service = packet_get_string(&len); 150280297Sjkim packet_done(); 151280297Sjkim 152280297Sjkim if (authctxt == NULL) 153280297Sjkim fatal("input_service_request: no authctxt"); 154280297Sjkim 155160814Ssimon if (strcmp(service, "ssh-userauth") == 0) { 156160814Ssimon if (!authctxt->success) { 157280297Sjkim accept = 1; 158280297Sjkim /* now we can handle user-auth requests */ 159280297Sjkim dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 160160814Ssimon } 161337982Sjkim } 162337982Sjkim /* XXX all other service requests are denied */ 163337982Sjkim 164337982Sjkim if (accept) { 165337982Sjkim packet_start(SSH2_MSG_SERVICE_ACCEPT); 166280297Sjkim packet_put_cstring(service); 167280297Sjkim packet_send(); 168280297Sjkim packet_write_wait(); 169280297Sjkim } else { 170280297Sjkim debug("bad service request %s", service); 171280297Sjkim packet_disconnect("bad service request %s", service); 172280297Sjkim } 173280297Sjkim xfree(service); 174280297Sjkim} 175280297Sjkim 176280297Sjkimvoid 177280297Sjkiminput_userauth_request(int type, int plen, void *ctxt) 178280297Sjkim{ 179280297Sjkim Authctxt *authctxt = ctxt; 180280297Sjkim Authmethod *m = NULL; 181280297Sjkim int authenticated = 0; 182280297Sjkim char *user, *service, *method, *authmsg = NULL; 183280297Sjkim#ifdef HAVE_LOGIN_CAP 184160814Ssimon login_cap_t *lc; 185160814Ssimon#endif /* HAVE_LOGIN_CAP */ 186160814Ssimon#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) 187280297Sjkim const char *from_host, *from_ip; 188280297Sjkim 189280297Sjkim from_host = get_canonical_hostname(); 190280297Sjkim from_ip = get_remote_ipaddr(); 191280297Sjkim#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ 192280297Sjkim 193280297Sjkim if (authctxt == NULL) 194280297Sjkim fatal("input_userauth_request: no authctxt"); 195280297Sjkim if (authctxt->attempt++ >= AUTH_FAIL_MAX) 196160814Ssimon packet_disconnect("too many failed userauth_requests"); 197280297Sjkim 198280297Sjkim user = packet_get_string(NULL); 199280297Sjkim service = packet_get_string(NULL); 200280297Sjkim method = packet_get_string(NULL); 201280297Sjkim debug("userauth-request for user %s service %s method %s", user, service, method); 202160814Ssimon debug("attempt #%d", authctxt->attempt); 203280297Sjkim 204280297Sjkim if (authctxt->attempt == 1) { 205280297Sjkim /* setup auth context */ 206280297Sjkim struct passwd *pw = NULL; 207337982Sjkim setproctitle("%s", user); 208280297Sjkim pw = getpwnam(user); 209280297Sjkim if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { 210280297Sjkim authctxt->pw = pwcopy(pw); 211280297Sjkim authctxt->valid = 1; 212280297Sjkim debug2("input_userauth_request: setting up authctxt for %s", user); 213337982Sjkim#ifdef USE_PAM 214280297Sjkim start_pam(pw); 215280297Sjkim#endif 216280297Sjkim } else { 217280297Sjkim log("input_userauth_request: illegal user %s", user); 218280297Sjkim } 219280297Sjkim authctxt->user = xstrdup(user); 220280297Sjkim authctxt->service = xstrdup(service); 221280297Sjkim } else if (authctxt->valid) { 222280297Sjkim if (strcmp(user, authctxt->user) != 0 || 223280297Sjkim strcmp(service, authctxt->service) != 0) { 224280297Sjkim log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", 225280297Sjkim user, service, authctxt->user, authctxt->service); 226280297Sjkim authctxt->valid = 0; 227280297Sjkim } 228280297Sjkim } 229280297Sjkim 230280297Sjkim#ifdef HAVE_LOGIN_CAP 231280297Sjkim if (authctxt->pw != NULL) { 232280297Sjkim lc = login_getpwclass(authctxt->pw); 233160814Ssimon if (lc == NULL) 234280297Sjkim lc = login_getclassbyname(NULL, authctxt->pw); 235280297Sjkim if (!auth_hostok(lc, from_host, from_ip)) { 236280297Sjkim log("Denied connection for %.200s from %.200s [%.200s].", 237280297Sjkim authctxt->pw->pw_name, from_host, from_ip); 238280297Sjkim packet_disconnect("Sorry, you are not allowed to connect."); 239280297Sjkim } 240280297Sjkim if (!auth_timeok(lc, time(NULL))) { 241280297Sjkim log("LOGIN %.200s REFUSED (TIME) FROM %.200s", 242280297Sjkim authctxt->pw->pw_name, from_host); 243280297Sjkim packet_disconnect("Logins not available right now."); 244280297Sjkim } 245280297Sjkim login_close(lc); 246280297Sjkim lc = NULL; 247280297Sjkim } 248280297Sjkim#endif /* HAVE_LOGIN_CAP */ 249280297Sjkim#ifdef LOGIN_ACCESS 250160814Ssimon if (authctxt->pw != NULL && 251160814Ssimon !login_access(authctxt->pw->pw_name, from_host)) { 252280297Sjkim log("Denied connection for %.200s from %.200s [%.200s].", 253280297Sjkim authctxt->pw->pw_name, from_host, from_ip); 254160814Ssimon packet_disconnect("Sorry, you are not allowed to connect."); 255280297Sjkim } 256160814Ssimon#endif /* LOGIN_ACCESS */ 257280297Sjkim 258280297Sjkim m = authmethod_lookup(method); 259280297Sjkim if (m != NULL) { 260160814Ssimon debug2("input_userauth_request: try method %s", method); 261280297Sjkim authenticated = m->userauth(authctxt); 262280297Sjkim } else { 263280297Sjkim debug2("input_userauth_request: unsupported method %s", method); 264280297Sjkim } 265280297Sjkim if (!authctxt->valid && authenticated == 1) { 266280297Sjkim log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method); 267280297Sjkim authenticated = 0; 268280297Sjkim } 269280297Sjkim 270280297Sjkim /* Special handling for root */ 271280297Sjkim if (authenticated == 1 && 272280297Sjkim authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) { 273280297Sjkim authenticated = 0; 274280297Sjkim log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); 275280297Sjkim } 276280297Sjkim 277280297Sjkim#ifdef USE_PAM 278280297Sjkim if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) 279280297Sjkim authenticated = 0; 280280297Sjkim#endif /* USE_PAM */ 281280297Sjkim 282280297Sjkim /* Log before sending the reply */ 283280297Sjkim userauth_log(authctxt, authenticated, method); 284280297Sjkim userauth_reply(authctxt, authenticated); 285280297Sjkim 286280297Sjkim xfree(service); 287280297Sjkim xfree(user); 288280297Sjkim xfree(method); 289160814Ssimon} 290160814Ssimon 291280297Sjkim 292280297Sjkimvoid 293280297Sjkimuserauth_log(Authctxt *authctxt, int authenticated, char *method) 294280297Sjkim{ 295280297Sjkim void (*authlog) (const char *fmt,...) = verbose; 296280297Sjkim char *user = NULL, *authmsg = NULL; 297280297Sjkim 298280297Sjkim /* Raise logging level */ 299280297Sjkim if (authenticated == 1 || 300280297Sjkim !authctxt->valid || 301280297Sjkim authctxt->attempt >= AUTH_FAIL_LOG || 302280297Sjkim strcmp(method, "password") == 0) 303280297Sjkim authlog = log; 304160814Ssimon 305280297Sjkim if (authenticated == 1) { 306284283Sjkim authmsg = "Accepted"; 307284283Sjkim } else if (authenticated == 0) { 308280297Sjkim authmsg = "Failed"; 309280297Sjkim } else { 310280297Sjkim authmsg = "Postponed"; 311160814Ssimon } 312280297Sjkim 313280297Sjkim if (authctxt->valid) { 314280297Sjkim user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; 315280297Sjkim } else { 316280297Sjkim user = "NOUSER"; 317160814Ssimon } 318280297Sjkim 319280297Sjkim authlog("%s %s for %.200s from %.200s port %d ssh2", 320160814Ssimon authmsg, 321280297Sjkim method, 322160814Ssimon user, 323280297Sjkim get_remote_ipaddr(), 324280297Sjkim get_remote_port()); 325280297Sjkim} 326280297Sjkim 327160814Ssimonvoid 328280297Sjkimuserauth_reply(Authctxt *authctxt, int authenticated) 329280297Sjkim{ 330280297Sjkim /* XXX todo: check if multiple auth methods are needed */ 331280297Sjkim if (authenticated == 1) { 332160814Ssimon /* turn off userauth */ 333280297Sjkim dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); 334280297Sjkim packet_start(SSH2_MSG_USERAUTH_SUCCESS); 335280297Sjkim packet_send(); 336237657Sjkim packet_write_wait(); 337280297Sjkim /* now we can break out */ 338280297Sjkim authctxt->success = 1; 339280297Sjkim } else if (authenticated == 0) { 340280297Sjkim char *methods = authmethods_get(); 341280297Sjkim packet_start(SSH2_MSG_USERAUTH_FAILURE); 342280297Sjkim packet_put_cstring(methods); 343280297Sjkim packet_put_char(0); /* XXX partial success, unused */ 344280297Sjkim packet_send(); 345280297Sjkim packet_write_wait(); 346280297Sjkim xfree(methods); 347280297Sjkim } else { 348280297Sjkim /* do nothing, we did already send a reply */ 349280297Sjkim } 350280297Sjkim} 351280297Sjkim 352280297Sjkimint 353280297Sjkimuserauth_none(Authctxt *authctxt) 354280297Sjkim{ 355280297Sjkim /* disable method "none", only allowed one time */ 356280297Sjkim Authmethod *m = authmethod_lookup("none"); 357280297Sjkim if (m != NULL) 358280297Sjkim m->enabled = NULL; 359280297Sjkim packet_done(); 360280297Sjkim#ifdef USE_PAM 361280297Sjkim return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0; 362280297Sjkim#else /* !USE_PAM */ 363280297Sjkim return authctxt->valid ? auth_password(authctxt->pw, "") : 0; 364280297Sjkim#endif /* USE_PAM */ 365280297Sjkim} 366280297Sjkim 367280297Sjkimint 368280297Sjkimuserauth_passwd(Authctxt *authctxt) 369280297Sjkim{ 370280297Sjkim char *password; 371280297Sjkim int authenticated = 0; 372280297Sjkim int change; 373280297Sjkim unsigned int len; 374280297Sjkim change = packet_get_char(); 375280297Sjkim if (change) 376237657Sjkim log("password change not supported"); 377280297Sjkim password = packet_get_string(&len); 378280297Sjkim packet_done(); 379280297Sjkim if (authctxt->valid && 380280297Sjkim#ifdef USE_PAM 381280297Sjkim auth_pam_password(authctxt->pw, password) == 1 382280297Sjkim#else 383280297Sjkim auth_password(authctxt->pw, password) == 1 384280297Sjkim#endif 385280297Sjkim ) 386280297Sjkim authenticated = 1; 387280297Sjkim memset(password, 0, len); 388280297Sjkim xfree(password); 389280297Sjkim return authenticated; 390280297Sjkim} 391280297Sjkim 392280297Sjkimint 393280297Sjkimuserauth_kbdint(Authctxt *authctxt) 394280297Sjkim{ 395280297Sjkim int authenticated = 0; 396280297Sjkim char *lang = NULL; 397280297Sjkim char *devs = NULL; 398280297Sjkim 399280297Sjkim lang = packet_get_string(NULL); 400280297Sjkim devs = packet_get_string(NULL); 401280297Sjkim packet_done(); 402280297Sjkim 403280297Sjkim debug("keyboard-interactive language %s devs %s", lang, devs); 404280297Sjkim#ifdef SKEY 405280297Sjkim /* XXX hardcoded, we should look at devs */ 406280297Sjkim if (options.skey_authentication != 0) 407280297Sjkim authenticated = auth2_skey(authctxt); 408280297Sjkim#endif 409280297Sjkim xfree(lang); 410280297Sjkim xfree(devs); 411280297Sjkim return authenticated; 412280297Sjkim} 413280297Sjkim 414280297Sjkimint 415280297Sjkimuserauth_pubkey(Authctxt *authctxt) 416280297Sjkim{ 417280297Sjkim Buffer b; 418280297Sjkim Key *key; 419280297Sjkim char *pkalg, *pkblob, *sig; 420280297Sjkim unsigned int alen, blen, slen; 421280297Sjkim int have_sig; 422280297Sjkim int authenticated = 0; 423280297Sjkim 424237657Sjkim if (!authctxt->valid) { 425280297Sjkim debug2("userauth_pubkey: disabled because of invalid user"); 426280297Sjkim return 0; 427280297Sjkim } 428280297Sjkim have_sig = packet_get_char(); 429280297Sjkim pkalg = packet_get_string(&alen); 430280297Sjkim if (strcmp(pkalg, KEX_DSS) != 0) { 431280297Sjkim log("bad pkalg %s", pkalg); /*XXX*/ 432280297Sjkim xfree(pkalg); 433280297Sjkim return 0; 434280297Sjkim } 435237657Sjkim pkblob = packet_get_string(&blen); 436280297Sjkim key = dsa_key_from_blob(pkblob, blen); 437280297Sjkim if (key != NULL) { 438280297Sjkim if (have_sig) { 439280297Sjkim sig = packet_get_string(&slen); 440280297Sjkim packet_done(); 441280297Sjkim buffer_init(&b); 442280297Sjkim if (datafellows & SSH_OLD_SESSIONID) { 443280297Sjkim buffer_append(&b, session_id2, session_id2_len); 444280297Sjkim } else { 445280297Sjkim buffer_put_string(&b, session_id2, session_id2_len); 446280297Sjkim } 447280297Sjkim /* reconstruct packet */ 448280297Sjkim buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 449280297Sjkim buffer_put_cstring(&b, authctxt->user); 450280297Sjkim buffer_put_cstring(&b, 451237657Sjkim datafellows & SSH_BUG_PUBKEYAUTH ? 452280297Sjkim "ssh-userauth" : 453280297Sjkim authctxt->service); 454280297Sjkim buffer_put_cstring(&b, "publickey"); 455280297Sjkim buffer_put_char(&b, have_sig); 456280297Sjkim buffer_put_cstring(&b, KEX_DSS); 457280297Sjkim buffer_put_string(&b, pkblob, blen); 458280297Sjkim#ifdef DEBUG_DSS 459280297Sjkim buffer_dump(&b); 460160814Ssimon#endif 461280297Sjkim /* test for correct signature */ 462280297Sjkim if (user_dsa_key_allowed(authctxt->pw, key) && 463280297Sjkim dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 464280297Sjkim authenticated = 1; 465280297Sjkim buffer_clear(&b); 466280297Sjkim xfree(sig); 467280297Sjkim } else { 468280297Sjkim debug("test whether pkalg/pkblob are acceptable"); 469280297Sjkim packet_done(); 470280297Sjkim 471280297Sjkim /* XXX fake reply and always send PK_OK ? */ 472280297Sjkim /* 473280297Sjkim * XXX this allows testing whether a user is allowed 474160814Ssimon * to login: if you happen to have a valid pubkey this 475280297Sjkim * message is sent. the message is NEVER sent at all 476280297Sjkim * if a user is not allowed to login. is this an 477280297Sjkim * issue? -markus 478280297Sjkim */ 479280297Sjkim if (user_dsa_key_allowed(authctxt->pw, key)) { 480280297Sjkim packet_start(SSH2_MSG_USERAUTH_PK_OK); 481280297Sjkim packet_put_string(pkalg, alen); 482280297Sjkim packet_put_string(pkblob, blen); 483160814Ssimon packet_send(); 484280297Sjkim packet_write_wait(); 485280297Sjkim authenticated = -1; 486280297Sjkim } 487280297Sjkim } 488280297Sjkim if (authenticated != 1) 489280297Sjkim auth_clear_options(); 490280297Sjkim key_free(key); 491280297Sjkim } 492280297Sjkim xfree(pkalg); 493280297Sjkim xfree(pkblob); 494280297Sjkim return authenticated; 495280297Sjkim} 496280297Sjkim 497280297Sjkim/* get current user */ 498280297Sjkim 499280297Sjkimstruct passwd* 500280297Sjkimauth_get_user(void) 501280297Sjkim{ 502280297Sjkim return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 503280297Sjkim} 504280297Sjkim 505280297Sjkim#define DELIM "," 506280297Sjkim 507280297Sjkimchar * 508280297Sjkimauthmethods_get(void) 509280297Sjkim{ 510280297Sjkim Authmethod *method = NULL; 511280297Sjkim unsigned int size = 0; 512280297Sjkim char *list; 513280297Sjkim 514280297Sjkim for (method = authmethods; method->name != NULL; method++) { 515280297Sjkim if (strcmp(method->name, "none") == 0) 516280297Sjkim continue; 517280297Sjkim if (method->enabled != NULL && *(method->enabled) != 0) { 518160814Ssimon if (size != 0) 519280297Sjkim size += strlen(DELIM); 520280297Sjkim size += strlen(method->name); 521280297Sjkim } 522160814Ssimon } 523280297Sjkim size++; /* trailing '\0' */ 524160814Ssimon list = xmalloc(size); 525280297Sjkim list[0] = '\0'; 526280297Sjkim 527280297Sjkim for (method = authmethods; method->name != NULL; method++) { 528280297Sjkim if (strcmp(method->name, "none") == 0) 529280297Sjkim continue; 530280297Sjkim if (method->enabled != NULL && *(method->enabled) != 0) { 531280297Sjkim if (list[0] != '\0') 532280297Sjkim strlcat(list, DELIM, size); 533280297Sjkim strlcat(list, method->name, size); 534280297Sjkim } 535160814Ssimon } 536280297Sjkim return list; 537160814Ssimon} 538280297Sjkim 539280297SjkimAuthmethod * 540280297Sjkimauthmethod_lookup(const char *name) 541280297Sjkim{ 542280297Sjkim Authmethod *method = NULL; 543280297Sjkim if (name != NULL) 544280297Sjkim for (method = authmethods; method->name != NULL; method++) 545280297Sjkim if (method->enabled != NULL && 546280297Sjkim *(method->enabled) != 0 && 547280297Sjkim strcmp(name, method->name) == 0) 548280297Sjkim return method; 549280297Sjkim debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 550280297Sjkim return NULL; 551280297Sjkim} 552280297Sjkim 553280297Sjkim/* return 1 if user allows given key */ 554280297Sjkimint 555280297Sjkimuser_dsa_key_allowed(struct passwd *pw, Key *key) 556280297Sjkim{ 557280297Sjkim char line[8192], file[1024]; 558280297Sjkim int found_key = 0; 559280297Sjkim unsigned int bits = -1; 560280297Sjkim FILE *f; 561280297Sjkim unsigned long linenum = 0; 562280297Sjkim struct stat st; 563160814Ssimon Key *found; 564 565 if (pw == NULL) 566 return 0; 567 568 /* Temporarily use the user's uid. */ 569 temporarily_use_uid(pw->pw_uid); 570 571 /* The authorized keys. */ 572 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 573 SSH_USER_PERMITTED_KEYS2); 574 575 /* Fail quietly if file does not exist */ 576 if (stat(file, &st) < 0) { 577 /* Restore the privileged uid. */ 578 restore_uid(); 579 return 0; 580 } 581 /* Open the file containing the authorized keys. */ 582 f = fopen(file, "r"); 583 if (!f) { 584 /* Restore the privileged uid. */ 585 restore_uid(); 586 return 0; 587 } 588 if (options.strict_modes) { 589 int fail = 0; 590 char buf[1024]; 591 /* Check open file in order to avoid open/stat races */ 592 if (fstat(fileno(f), &st) < 0 || 593 (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 594 (st.st_mode & 022) != 0) { 595 snprintf(buf, sizeof buf, 596 "%s authentication refused for %.100s: " 597 "bad ownership or modes for '%s'.", 598 key_type(key), pw->pw_name, file); 599 fail = 1; 600 } else { 601 /* Check path to SSH_USER_PERMITTED_KEYS */ 602 int i; 603 static const char *check[] = { 604 "", SSH_USER_DIR, NULL 605 }; 606 for (i = 0; check[i]; i++) { 607 snprintf(line, sizeof line, "%.500s/%.100s", 608 pw->pw_dir, check[i]); 609 if (stat(line, &st) < 0 || 610 (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 611 (st.st_mode & 022) != 0) { 612 snprintf(buf, sizeof buf, 613 "%s authentication refused for %.100s: " 614 "bad ownership or modes for '%s'.", 615 key_type(key), pw->pw_name, line); 616 fail = 1; 617 break; 618 } 619 } 620 } 621 if (fail) { 622 fclose(f); 623 log("%s",buf); 624 restore_uid(); 625 return 0; 626 } 627 } 628 found_key = 0; 629 found = key_new(key->type); 630 631 while (fgets(line, sizeof(line), f)) { 632 char *cp, *options = NULL; 633 linenum++; 634 /* Skip leading whitespace, empty and comment lines. */ 635 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 636 ; 637 if (!*cp || *cp == '\n' || *cp == '#') 638 continue; 639 640 bits = key_read(found, &cp); 641 if (bits == 0) { 642 /* no key? check if there are options for this key */ 643 int quoted = 0; 644 options = cp; 645 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 646 if (*cp == '\\' && cp[1] == '"') 647 cp++; /* Skip both */ 648 else if (*cp == '"') 649 quoted = !quoted; 650 } 651 /* Skip remaining whitespace. */ 652 for (; *cp == ' ' || *cp == '\t'; cp++) 653 ; 654 bits = key_read(found, &cp); 655 if (bits == 0) { 656 /* still no key? advance to next line*/ 657 continue; 658 } 659 } 660 if (key_equal(found, key) && 661 auth_parse_options(pw, options, linenum) == 1) { 662 found_key = 1; 663 debug("matching key found: file %s, line %ld", 664 file, linenum); 665 break; 666 } 667 } 668 restore_uid(); 669 fclose(f); 670 key_free(found); 671 return found_key; 672} 673 674struct passwd * 675pwcopy(struct passwd *pw) 676{ 677 struct passwd *copy = xmalloc(sizeof(*copy)); 678 memset(copy, 0, sizeof(*copy)); 679 copy->pw_name = xstrdup(pw->pw_name); 680 copy->pw_passwd = xstrdup(pw->pw_passwd); 681 copy->pw_uid = pw->pw_uid; 682 copy->pw_gid = pw->pw_gid; 683 copy->pw_class = xstrdup(pw->pw_class); 684 copy->pw_dir = xstrdup(pw->pw_dir); 685 copy->pw_shell = xstrdup(pw->pw_shell); 686 copy->pw_expire = pw->pw_expire; 687 copy->pw_change = pw->pw_change; 688 return copy; 689} 690