auth2.c revision 157019
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" 26137019SdesRCSID("$OpenBSD: auth2.c,v 1.107 2004/07/28 09:40:29 markus Exp $"); 2799053SdesRCSID("$FreeBSD: head/crypto/openssh/auth2.c 157019 2006-03-22 20:41:37Z 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" 40147005Sdes#include "buffer.h" 4160573Skris 42124211Sdes#ifdef GSSAPI 43124211Sdes#include "ssh-gss.h" 44124211Sdes#endif 45124211Sdes 4660573Skris/* import */ 4760573Skrisextern ServerOptions options; 4876262Sgreenextern u_char *session_id2; 49124211Sdesextern u_int session_id2_len; 50147005Sdesextern Buffer loginmsg; 5160573Skris 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 *); 8460573Skris 8560573Skris/* 8669591Sgreen * loop until authctxt->success == TRUE 8760573Skris */ 8860573Skris 89126277Sdesvoid 90126277Sdesdo_authentication2(Authctxt *authctxt) 9160573Skris{ 9292559Sdes /* challenge-response is implemented via keyboard interactive */ 9392559Sdes if (options.challenge_response_authentication) 9476262Sgreen options.kbd_interactive_authentication = 1; 9576262Sgreen 9692559Sdes dispatch_init(&dispatch_protocol_error); 9760573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 9869591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 9960573Skris} 10060573Skris 10192559Sdesstatic void 10292559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 10360573Skris{ 10469591Sgreen Authctxt *authctxt = ctxt; 10576262Sgreen u_int len; 106106130Sdes int acceptit = 0; 10760573Skris char *service = packet_get_string(&len); 10892559Sdes packet_check_eom(); 10960573Skris 11069591Sgreen if (authctxt == NULL) 11169591Sgreen fatal("input_service_request: no authctxt"); 11269591Sgreen 11360573Skris if (strcmp(service, "ssh-userauth") == 0) { 11469591Sgreen if (!authctxt->success) { 115106130Sdes acceptit = 1; 11660573Skris /* now we can handle user-auth requests */ 11760573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 11860573Skris } 11960573Skris } 12060573Skris /* XXX all other service requests are denied */ 12160573Skris 122106130Sdes if (acceptit) { 12360573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 12460573Skris packet_put_cstring(service); 12560573Skris packet_send(); 12660573Skris packet_write_wait(); 12760573Skris } else { 12860573Skris debug("bad service request %s", service); 12960573Skris packet_disconnect("bad service request %s", service); 13060573Skris } 13160573Skris xfree(service); 13260573Skris} 13360573Skris 13492559Sdesstatic void 13592559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 13660573Skris{ 13769591Sgreen Authctxt *authctxt = ctxt; 13869591Sgreen Authmethod *m = NULL; 13976262Sgreen char *user, *service, *method, *style = NULL; 14060573Skris int authenticated = 0; 14199053Sdes#ifdef HAVE_LOGIN_CAP 14299053Sdes login_cap_t *lc; 14399053Sdes const char *from_host, *from_ip; 14460573Skris 145124211Sdes from_host = get_canonical_hostname(options.use_dns); 14699053Sdes from_ip = get_remote_ipaddr(); 14799053Sdes#endif 14899053Sdes 14969591Sgreen if (authctxt == NULL) 15069591Sgreen fatal("input_userauth_request: no authctxt"); 15160573Skris 15269591Sgreen user = packet_get_string(NULL); 15369591Sgreen service = packet_get_string(NULL); 15469591Sgreen method = packet_get_string(NULL); 15560573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 15676262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 15760573Skris 15876262Sgreen if ((style = strchr(user, ':')) != NULL) 15976262Sgreen *style++ = 0; 16076262Sgreen 16176262Sgreen if (authctxt->attempt++ == 0) { 16269591Sgreen /* setup auth context */ 16398684Sdes authctxt->pw = PRIVSEP(getpwnamallow(user)); 164128460Sdes authctxt->user = xstrdup(user); 16598684Sdes if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 16669591Sgreen authctxt->valid = 1; 16769591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 16869591Sgreen } else { 169137019Sdes logit("input_userauth_request: invalid user %s", user); 170124211Sdes authctxt->pw = fakepw(); 171147005Sdes#ifdef SSH_AUDIT_EVENTS 172147005Sdes PRIVSEP(audit_event(SSH_INVALID_USER)); 173147005Sdes#endif 17460573Skris } 175157019Sdes#ifdef USE_PAM 176157019Sdes if (options.use_pam) 177157019Sdes PRIVSEP(start_pam(authctxt)); 178157019Sdes#endif 179137019Sdes setproctitle("%s%s", authctxt->valid ? user : "unknown", 18098684Sdes use_privsep ? " [net]" : ""); 18169591Sgreen authctxt->service = xstrdup(service); 18292559Sdes authctxt->style = style ? xstrdup(style) : NULL; 18398684Sdes if (use_privsep) 18498684Sdes mm_inform_authserv(service, style); 18592559Sdes } else if (strcmp(user, authctxt->user) != 0 || 18692559Sdes strcmp(service, authctxt->service) != 0) { 18792559Sdes packet_disconnect("Change of username or service not allowed: " 18892559Sdes "(%s,%s) -> (%s,%s)", 18992559Sdes authctxt->user, authctxt->service, user, service); 19060573Skris } 19199053Sdes 19299053Sdes#ifdef HAVE_LOGIN_CAP 19399053Sdes if (authctxt->pw != NULL) { 19499053Sdes lc = login_getpwclass(authctxt->pw); 19599053Sdes if (lc == NULL) 19699053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 19799053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 198124211Sdes logit("Denied connection for %.200s from %.200s [%.200s].", 19999053Sdes authctxt->pw->pw_name, from_host, from_ip); 20099053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 20199053Sdes } 20299053Sdes if (!auth_timeok(lc, time(NULL))) { 203124211Sdes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 20499053Sdes authctxt->pw->pw_name, from_host); 20599053Sdes packet_disconnect("Logins not available right now."); 20699053Sdes } 20799053Sdes login_close(lc); 20899053Sdes lc = NULL; 20999053Sdes } 21099053Sdes#endif /* HAVE_LOGIN_CAP */ 21199053Sdes 21276262Sgreen /* reset state */ 21392559Sdes auth2_challenge_stop(authctxt); 214124211Sdes 215124211Sdes#ifdef GSSAPI 216124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 217124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 218124211Sdes#endif 219124211Sdes 22076262Sgreen authctxt->postponed = 0; 22168704Sgreen 22276262Sgreen /* try to authenticate user */ 22369591Sgreen m = authmethod_lookup(method); 22469591Sgreen if (m != NULL) { 22569591Sgreen debug2("input_userauth_request: try method %s", method); 22669591Sgreen authenticated = m->userauth(authctxt); 22769591Sgreen } 22876262Sgreen userauth_finish(authctxt, authenticated, method); 22969591Sgreen 23069591Sgreen xfree(service); 23169591Sgreen xfree(user); 23269591Sgreen xfree(method); 23369591Sgreen} 23469591Sgreen 23569591Sgreenvoid 23676262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 23769591Sgreen{ 23892559Sdes char *methods; 23992559Sdes 24076262Sgreen if (!authctxt->valid && authenticated) 24176262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 24276262Sgreen authctxt->user); 24369591Sgreen 24476262Sgreen /* Special handling for root */ 245113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 246147005Sdes !auth_root_allowed(method)) { 24776262Sgreen authenticated = 0; 248147005Sdes#ifdef SSH_AUDIT_EVENTS 249147005Sdes PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 250147005Sdes#endif 251147005Sdes } 25260573Skris 25398941Sdes#ifdef USE_PAM 254147005Sdes if (options.use_pam && authenticated) { 255147005Sdes if (!PRIVSEP(do_pam_account())) { 256147005Sdes /* if PAM returned a message, send it to the user */ 257147005Sdes if (buffer_len(&loginmsg) > 0) { 258147005Sdes buffer_append(&loginmsg, "\0", 1); 259147005Sdes userauth_send_banner(buffer_ptr(&loginmsg)); 260147005Sdes packet_write_wait(); 261147005Sdes } 262147005Sdes fatal("Access denied for user %s by PAM account " 263149753Sdes "configuration", authctxt->user); 264147005Sdes } 265147005Sdes } 266124211Sdes#endif 26798941Sdes 268106130Sdes#ifdef _UNICOS 269106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 270106130Sdes authenticated = 0; 271106130Sdes fatal("Access denied for user %s.",authctxt->user); 272106130Sdes } 273106130Sdes#endif /* _UNICOS */ 274106130Sdes 27576262Sgreen /* Log before sending the reply */ 27676262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 27769591Sgreen 27892559Sdes if (authctxt->postponed) 27992559Sdes return; 28092559Sdes 28192559Sdes /* XXX todo: check if multiple auth methods are needed */ 28292559Sdes if (authenticated == 1) { 28392559Sdes /* turn off userauth */ 28492559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 28592559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 28692559Sdes packet_send(); 28792559Sdes packet_write_wait(); 28892559Sdes /* now we can break out */ 28992559Sdes authctxt->success = 1; 29092559Sdes } else { 291147005Sdes if (authctxt->failures++ > options.max_authtries) { 292147005Sdes#ifdef SSH_AUDIT_EVENTS 293147005Sdes PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 294147005Sdes#endif 29592559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 296147005Sdes } 29792559Sdes methods = authmethods_get(); 29892559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 29992559Sdes packet_put_cstring(methods); 30092559Sdes packet_put_char(0); /* XXX partial success, unused */ 30192559Sdes packet_send(); 30292559Sdes packet_write_wait(); 30392559Sdes xfree(methods); 30492559Sdes } 30576262Sgreen} 30669591Sgreen 30769591Sgreen#define DELIM "," 30869591Sgreen 30992559Sdesstatic char * 31069591Sgreenauthmethods_get(void) 31160573Skris{ 31292559Sdes Buffer b; 31369591Sgreen char *list; 31498684Sdes int i; 31560573Skris 31692559Sdes buffer_init(&b); 31798684Sdes for (i = 0; authmethods[i] != NULL; i++) { 31898684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 31969591Sgreen continue; 32098684Sdes if (authmethods[i]->enabled != NULL && 32198684Sdes *(authmethods[i]->enabled) != 0) { 32292559Sdes if (buffer_len(&b) > 0) 32392559Sdes buffer_append(&b, ",", 1); 32498684Sdes buffer_append(&b, authmethods[i]->name, 32598684Sdes strlen(authmethods[i]->name)); 32660573Skris } 32769591Sgreen } 32892559Sdes buffer_append(&b, "\0", 1); 32992559Sdes list = xstrdup(buffer_ptr(&b)); 33092559Sdes buffer_free(&b); 33169591Sgreen return list; 33260573Skris} 33360573Skris 33492559Sdesstatic Authmethod * 33569591Sgreenauthmethod_lookup(const char *name) 33669591Sgreen{ 33798684Sdes int i; 33898684Sdes 33969591Sgreen if (name != NULL) 34098684Sdes for (i = 0; authmethods[i] != NULL; i++) 34198684Sdes if (authmethods[i]->enabled != NULL && 34298684Sdes *(authmethods[i]->enabled) != 0 && 34398684Sdes strcmp(name, authmethods[i]->name) == 0) 34498684Sdes return authmethods[i]; 34598684Sdes debug2("Unrecognized authentication method name: %s", 34698684Sdes name ? name : "NULL"); 34769591Sgreen return NULL; 34869591Sgreen} 349