auth2.c revision 124211
160573Skris/* 260573Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 360573Skris * 460573Skris * Redistribution and use in source and binary forms, with or without 560573Skris * modification, are permitted provided that the following conditions 660573Skris * are met: 760573Skris * 1. Redistributions of source code must retain the above copyright 860573Skris * notice, this list of conditions and the following disclaimer. 960573Skris * 2. Redistributions in binary form must reproduce the above copyright 1060573Skris * notice, this list of conditions and the following disclaimer in the 1160573Skris * documentation and/or other materials provided with the distribution. 1260573Skris * 1360573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1460573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1560573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1660573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1760573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1860573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1960573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2060573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2160573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2260573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2360573Skris */ 2465674Skris 2560573Skris#include "includes.h" 26124211SdesRCSID("$OpenBSD: auth2.c,v 1.102 2003/08/26 09:58:43 markus Exp $"); 2799053SdesRCSID("$FreeBSD: head/crypto/openssh/auth2.c 124211 2004-01-07 11:16:27Z des $"); 2860573Skris 29107860Sdes#include "canohost.h" 3076262Sgreen#include "ssh2.h" 3160573Skris#include "xmalloc.h" 3260573Skris#include "packet.h" 3376262Sgreen#include "log.h" 3460573Skris#include "servconf.h" 3560573Skris#include "compat.h" 3660573Skris#include "auth.h" 3760573Skris#include "dispatch.h" 3876262Sgreen#include "pathnames.h" 3998684Sdes#include "monitor_wrap.h" 4060573Skris 41124211Sdes#ifdef GSSAPI 42124211Sdes#include "ssh-gss.h" 43124211Sdes#endif 44124211Sdes 4560573Skris/* import */ 4660573Skrisextern ServerOptions options; 4776262Sgreenextern u_char *session_id2; 48124211Sdesextern u_int session_id2_len; 4960573Skris 5098684SdesAuthctxt *x_authctxt = NULL; 5169591Sgreen 5298684Sdes/* methods */ 5398684Sdes 5498684Sdesextern Authmethod method_none; 5598684Sdesextern Authmethod method_pubkey; 5698684Sdesextern Authmethod method_passwd; 5798684Sdesextern Authmethod method_kbdint; 5898684Sdesextern Authmethod method_hostbased; 59124211Sdes#ifdef GSSAPI 60124211Sdesextern Authmethod method_gssapi; 61124211Sdes#endif 6298684Sdes 6398684SdesAuthmethod *authmethods[] = { 6498684Sdes &method_none, 6598684Sdes &method_pubkey, 66124211Sdes#ifdef GSSAPI 67124211Sdes &method_gssapi, 68124211Sdes#endif 6998684Sdes &method_passwd, 7098684Sdes &method_kbdint, 7198684Sdes &method_hostbased, 7298684Sdes NULL 7369591Sgreen}; 7469591Sgreen 7560573Skris/* protocol */ 7660573Skris 7792559Sdesstatic void input_service_request(int, u_int32_t, void *); 7892559Sdesstatic void input_userauth_request(int, u_int32_t, void *); 7960573Skris 8060573Skris/* helper */ 8192559Sdesstatic Authmethod *authmethod_lookup(const char *); 8292559Sdesstatic char *authmethods_get(void); 8398684Sdesint user_key_allowed(struct passwd *, Key *); 8498684Sdesint hostbased_key_allowed(struct passwd *, const char *, char *, Key *); 8560573Skris 8660573Skris/* 8769591Sgreen * loop until authctxt->success == TRUE 8860573Skris */ 8960573Skris 9098684SdesAuthctxt * 9192559Sdesdo_authentication2(void) 9260573Skris{ 9376262Sgreen Authctxt *authctxt = authctxt_new(); 9476262Sgreen 9569591Sgreen x_authctxt = authctxt; /*XXX*/ 9669591Sgreen 9792559Sdes /* challenge-response is implemented via keyboard interactive */ 9892559Sdes if (options.challenge_response_authentication) 9976262Sgreen options.kbd_interactive_authentication = 1; 10076262Sgreen 10192559Sdes dispatch_init(&dispatch_protocol_error); 10260573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 10369591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 10498684Sdes 10598684Sdes return (authctxt); 10660573Skris} 10760573Skris 10892559Sdesstatic void 10992559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 11060573Skris{ 11169591Sgreen Authctxt *authctxt = ctxt; 11276262Sgreen u_int len; 113106130Sdes int acceptit = 0; 11460573Skris char *service = packet_get_string(&len); 11592559Sdes packet_check_eom(); 11660573Skris 11769591Sgreen if (authctxt == NULL) 11869591Sgreen fatal("input_service_request: no authctxt"); 11969591Sgreen 12060573Skris if (strcmp(service, "ssh-userauth") == 0) { 12169591Sgreen if (!authctxt->success) { 122106130Sdes acceptit = 1; 12360573Skris /* now we can handle user-auth requests */ 12460573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 12560573Skris } 12660573Skris } 12760573Skris /* XXX all other service requests are denied */ 12860573Skris 129106130Sdes if (acceptit) { 13060573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 13160573Skris packet_put_cstring(service); 13260573Skris packet_send(); 13360573Skris packet_write_wait(); 13460573Skris } else { 13560573Skris debug("bad service request %s", service); 13660573Skris packet_disconnect("bad service request %s", service); 13760573Skris } 13860573Skris xfree(service); 13960573Skris} 14060573Skris 14192559Sdesstatic void 14292559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 14360573Skris{ 14469591Sgreen Authctxt *authctxt = ctxt; 14569591Sgreen Authmethod *m = NULL; 14676262Sgreen char *user, *service, *method, *style = NULL; 14760573Skris int authenticated = 0; 14899053Sdes#ifdef HAVE_LOGIN_CAP 14999053Sdes login_cap_t *lc; 15099053Sdes const char *from_host, *from_ip; 15160573Skris 152124211Sdes from_host = get_canonical_hostname(options.use_dns); 15399053Sdes from_ip = get_remote_ipaddr(); 15499053Sdes#endif 15599053Sdes 15669591Sgreen if (authctxt == NULL) 15769591Sgreen fatal("input_userauth_request: no authctxt"); 15860573Skris 15969591Sgreen user = packet_get_string(NULL); 16069591Sgreen service = packet_get_string(NULL); 16169591Sgreen method = packet_get_string(NULL); 16260573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 16376262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 16460573Skris 16576262Sgreen if ((style = strchr(user, ':')) != NULL) 16676262Sgreen *style++ = 0; 16776262Sgreen 16876262Sgreen if (authctxt->attempt++ == 0) { 16969591Sgreen /* setup auth context */ 17098684Sdes authctxt->pw = PRIVSEP(getpwnamallow(user)); 17198684Sdes if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 17269591Sgreen authctxt->valid = 1; 17369591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 17469591Sgreen#ifdef USE_PAM 175124211Sdes if (options.use_pam) 176124211Sdes PRIVSEP(start_pam(authctxt->pw->pw_name)); 17769591Sgreen#endif 17869591Sgreen } else { 179124211Sdes logit("input_userauth_request: illegal user %s", user); 180124211Sdes authctxt->pw = fakepw(); 18198941Sdes#ifdef USE_PAM 182124211Sdes if (options.use_pam) 183124211Sdes PRIVSEP(start_pam(user)); 18498941Sdes#endif 18560573Skris } 18698684Sdes setproctitle("%s%s", authctxt->pw ? user : "unknown", 18798684Sdes use_privsep ? " [net]" : ""); 18869591Sgreen authctxt->user = xstrdup(user); 18969591Sgreen authctxt->service = xstrdup(service); 19092559Sdes authctxt->style = style ? xstrdup(style) : NULL; 19198684Sdes if (use_privsep) 19298684Sdes mm_inform_authserv(service, style); 19392559Sdes } else if (strcmp(user, authctxt->user) != 0 || 19492559Sdes strcmp(service, authctxt->service) != 0) { 19592559Sdes packet_disconnect("Change of username or service not allowed: " 19692559Sdes "(%s,%s) -> (%s,%s)", 19792559Sdes authctxt->user, authctxt->service, user, service); 19860573Skris } 19999053Sdes 20099053Sdes#ifdef HAVE_LOGIN_CAP 20199053Sdes if (authctxt->pw != NULL) { 20299053Sdes lc = login_getpwclass(authctxt->pw); 20399053Sdes if (lc == NULL) 20499053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 20599053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 206124211Sdes logit("Denied connection for %.200s from %.200s [%.200s].", 20799053Sdes authctxt->pw->pw_name, from_host, from_ip); 20899053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 20999053Sdes } 21099053Sdes if (!auth_timeok(lc, time(NULL))) { 211124211Sdes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 21299053Sdes authctxt->pw->pw_name, from_host); 21399053Sdes packet_disconnect("Logins not available right now."); 21499053Sdes } 21599053Sdes login_close(lc); 21699053Sdes lc = NULL; 21799053Sdes } 21899053Sdes#endif /* HAVE_LOGIN_CAP */ 21999053Sdes 22076262Sgreen /* reset state */ 22192559Sdes auth2_challenge_stop(authctxt); 222124211Sdes 223124211Sdes#ifdef GSSAPI 224124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 225124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 226124211Sdes#endif 227124211Sdes 22876262Sgreen authctxt->postponed = 0; 22968704Sgreen 23076262Sgreen /* try to authenticate user */ 23169591Sgreen m = authmethod_lookup(method); 23269591Sgreen if (m != NULL) { 23369591Sgreen debug2("input_userauth_request: try method %s", method); 23469591Sgreen authenticated = m->userauth(authctxt); 23569591Sgreen } 23676262Sgreen userauth_finish(authctxt, authenticated, method); 23769591Sgreen 23869591Sgreen xfree(service); 23969591Sgreen xfree(user); 24069591Sgreen xfree(method); 24169591Sgreen} 24269591Sgreen 24369591Sgreenvoid 24476262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 24569591Sgreen{ 24692559Sdes char *methods; 24792559Sdes 24876262Sgreen if (!authctxt->valid && authenticated) 24976262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 25076262Sgreen authctxt->user); 25169591Sgreen 25276262Sgreen /* Special handling for root */ 253113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 25476262Sgreen !auth_root_allowed(method)) 25576262Sgreen authenticated = 0; 25660573Skris 25798941Sdes#ifdef USE_PAM 258124211Sdes if (options.use_pam && authenticated && !PRIVSEP(do_pam_account())) 25998941Sdes authenticated = 0; 260124211Sdes#endif 26198941Sdes 262106130Sdes#ifdef _UNICOS 263106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 264106130Sdes authenticated = 0; 265106130Sdes fatal("Access denied for user %s.",authctxt->user); 266106130Sdes } 267106130Sdes#endif /* _UNICOS */ 268106130Sdes 26976262Sgreen /* Log before sending the reply */ 27076262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 27169591Sgreen 27292559Sdes if (authctxt->postponed) 27392559Sdes return; 27492559Sdes 27592559Sdes /* XXX todo: check if multiple auth methods are needed */ 27692559Sdes if (authenticated == 1) { 27792559Sdes /* turn off userauth */ 27892559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 27992559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 28092559Sdes packet_send(); 28192559Sdes packet_write_wait(); 28292559Sdes /* now we can break out */ 28392559Sdes authctxt->success = 1; 28492559Sdes } else { 285124211Sdes if (authctxt->failures++ > AUTH_FAIL_MAX) 28692559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 28792559Sdes methods = authmethods_get(); 28892559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 28992559Sdes packet_put_cstring(methods); 29092559Sdes packet_put_char(0); /* XXX partial success, unused */ 29192559Sdes packet_send(); 29292559Sdes packet_write_wait(); 29392559Sdes xfree(methods); 29492559Sdes } 29576262Sgreen} 29669591Sgreen 29769591Sgreen/* get current user */ 29860573Skris 29960573Skrisstruct passwd* 30060573Skrisauth_get_user(void) 30160573Skris{ 30269591Sgreen return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 30360573Skris} 30460573Skris 30569591Sgreen#define DELIM "," 30669591Sgreen 30792559Sdesstatic char * 30869591Sgreenauthmethods_get(void) 30960573Skris{ 31092559Sdes Buffer b; 31169591Sgreen char *list; 31298684Sdes int i; 31360573Skris 31492559Sdes buffer_init(&b); 31598684Sdes for (i = 0; authmethods[i] != NULL; i++) { 31698684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 31769591Sgreen continue; 31898684Sdes if (authmethods[i]->enabled != NULL && 31998684Sdes *(authmethods[i]->enabled) != 0) { 32092559Sdes if (buffer_len(&b) > 0) 32192559Sdes buffer_append(&b, ",", 1); 32298684Sdes buffer_append(&b, authmethods[i]->name, 32398684Sdes strlen(authmethods[i]->name)); 32460573Skris } 32569591Sgreen } 32692559Sdes buffer_append(&b, "\0", 1); 32792559Sdes list = xstrdup(buffer_ptr(&b)); 32892559Sdes buffer_free(&b); 32969591Sgreen return list; 33060573Skris} 33160573Skris 33292559Sdesstatic Authmethod * 33369591Sgreenauthmethod_lookup(const char *name) 33469591Sgreen{ 33598684Sdes int i; 33698684Sdes 33769591Sgreen if (name != NULL) 33898684Sdes for (i = 0; authmethods[i] != NULL; i++) 33998684Sdes if (authmethods[i]->enabled != NULL && 34098684Sdes *(authmethods[i]->enabled) != 0 && 34198684Sdes strcmp(name, authmethods[i]->name) == 0) 34298684Sdes return authmethods[i]; 34398684Sdes debug2("Unrecognized authentication method name: %s", 34498684Sdes name ? name : "NULL"); 34569591Sgreen return NULL; 34669591Sgreen} 347