auth2.c revision 149753
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 149753 2005-09-03 07:04:25Z 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#ifdef USE_PAM 169124211Sdes if (options.use_pam) 170128460Sdes PRIVSEP(start_pam(authctxt)); 17169591Sgreen#endif 17269591Sgreen } else { 173137019Sdes logit("input_userauth_request: invalid user %s", user); 174124211Sdes authctxt->pw = fakepw(); 17598941Sdes#ifdef USE_PAM 176124211Sdes if (options.use_pam) 177128460Sdes PRIVSEP(start_pam(authctxt)); 17898941Sdes#endif 179147005Sdes#ifdef SSH_AUDIT_EVENTS 180147005Sdes PRIVSEP(audit_event(SSH_INVALID_USER)); 181147005Sdes#endif 18260573Skris } 183137019Sdes setproctitle("%s%s", authctxt->valid ? user : "unknown", 18498684Sdes use_privsep ? " [net]" : ""); 18569591Sgreen authctxt->service = xstrdup(service); 18692559Sdes authctxt->style = style ? xstrdup(style) : NULL; 18798684Sdes if (use_privsep) 18898684Sdes mm_inform_authserv(service, style); 18992559Sdes } else if (strcmp(user, authctxt->user) != 0 || 19092559Sdes strcmp(service, authctxt->service) != 0) { 19192559Sdes packet_disconnect("Change of username or service not allowed: " 19292559Sdes "(%s,%s) -> (%s,%s)", 19392559Sdes authctxt->user, authctxt->service, user, service); 19460573Skris } 19599053Sdes 19699053Sdes#ifdef HAVE_LOGIN_CAP 19799053Sdes if (authctxt->pw != NULL) { 19899053Sdes lc = login_getpwclass(authctxt->pw); 19999053Sdes if (lc == NULL) 20099053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 20199053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 202124211Sdes logit("Denied connection for %.200s from %.200s [%.200s].", 20399053Sdes authctxt->pw->pw_name, from_host, from_ip); 20499053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 20599053Sdes } 20699053Sdes if (!auth_timeok(lc, time(NULL))) { 207124211Sdes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 20899053Sdes authctxt->pw->pw_name, from_host); 20999053Sdes packet_disconnect("Logins not available right now."); 21099053Sdes } 21199053Sdes login_close(lc); 21299053Sdes lc = NULL; 21399053Sdes } 21499053Sdes#endif /* HAVE_LOGIN_CAP */ 21599053Sdes 21676262Sgreen /* reset state */ 21792559Sdes auth2_challenge_stop(authctxt); 218124211Sdes 219124211Sdes#ifdef GSSAPI 220124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 221124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 222124211Sdes#endif 223124211Sdes 22476262Sgreen authctxt->postponed = 0; 22568704Sgreen 22676262Sgreen /* try to authenticate user */ 22769591Sgreen m = authmethod_lookup(method); 22869591Sgreen if (m != NULL) { 22969591Sgreen debug2("input_userauth_request: try method %s", method); 23069591Sgreen authenticated = m->userauth(authctxt); 23169591Sgreen } 23276262Sgreen userauth_finish(authctxt, authenticated, method); 23369591Sgreen 23469591Sgreen xfree(service); 23569591Sgreen xfree(user); 23669591Sgreen xfree(method); 23769591Sgreen} 23869591Sgreen 23969591Sgreenvoid 24076262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 24169591Sgreen{ 24292559Sdes char *methods; 24392559Sdes 24476262Sgreen if (!authctxt->valid && authenticated) 24576262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 24676262Sgreen authctxt->user); 24769591Sgreen 24876262Sgreen /* Special handling for root */ 249113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 250147005Sdes !auth_root_allowed(method)) { 25176262Sgreen authenticated = 0; 252147005Sdes#ifdef SSH_AUDIT_EVENTS 253147005Sdes PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 254147005Sdes#endif 255147005Sdes } 25660573Skris 25798941Sdes#ifdef USE_PAM 258147005Sdes if (options.use_pam && authenticated) { 259147005Sdes if (!PRIVSEP(do_pam_account())) { 260147005Sdes /* if PAM returned a message, send it to the user */ 261147005Sdes if (buffer_len(&loginmsg) > 0) { 262147005Sdes buffer_append(&loginmsg, "\0", 1); 263147005Sdes userauth_send_banner(buffer_ptr(&loginmsg)); 264147005Sdes packet_write_wait(); 265147005Sdes } 266147005Sdes fatal("Access denied for user %s by PAM account " 267149753Sdes "configuration", authctxt->user); 268147005Sdes } 269147005Sdes } 270124211Sdes#endif 27198941Sdes 272106130Sdes#ifdef _UNICOS 273106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 274106130Sdes authenticated = 0; 275106130Sdes fatal("Access denied for user %s.",authctxt->user); 276106130Sdes } 277106130Sdes#endif /* _UNICOS */ 278106130Sdes 27976262Sgreen /* Log before sending the reply */ 28076262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 28169591Sgreen 28292559Sdes if (authctxt->postponed) 28392559Sdes return; 28492559Sdes 28592559Sdes /* XXX todo: check if multiple auth methods are needed */ 28692559Sdes if (authenticated == 1) { 28792559Sdes /* turn off userauth */ 28892559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 28992559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 29092559Sdes packet_send(); 29192559Sdes packet_write_wait(); 29292559Sdes /* now we can break out */ 29392559Sdes authctxt->success = 1; 29492559Sdes } else { 295147005Sdes if (authctxt->failures++ > options.max_authtries) { 296147005Sdes#ifdef SSH_AUDIT_EVENTS 297147005Sdes PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 298147005Sdes#endif 29992559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 300147005Sdes } 30192559Sdes methods = authmethods_get(); 30292559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 30392559Sdes packet_put_cstring(methods); 30492559Sdes packet_put_char(0); /* XXX partial success, unused */ 30592559Sdes packet_send(); 30692559Sdes packet_write_wait(); 30792559Sdes xfree(methods); 30892559Sdes } 30976262Sgreen} 31069591Sgreen 31169591Sgreen#define DELIM "," 31269591Sgreen 31392559Sdesstatic char * 31469591Sgreenauthmethods_get(void) 31560573Skris{ 31692559Sdes Buffer b; 31769591Sgreen char *list; 31898684Sdes int i; 31960573Skris 32092559Sdes buffer_init(&b); 32198684Sdes for (i = 0; authmethods[i] != NULL; i++) { 32298684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 32369591Sgreen continue; 32498684Sdes if (authmethods[i]->enabled != NULL && 32598684Sdes *(authmethods[i]->enabled) != 0) { 32692559Sdes if (buffer_len(&b) > 0) 32792559Sdes buffer_append(&b, ",", 1); 32898684Sdes buffer_append(&b, authmethods[i]->name, 32998684Sdes strlen(authmethods[i]->name)); 33060573Skris } 33169591Sgreen } 33292559Sdes buffer_append(&b, "\0", 1); 33392559Sdes list = xstrdup(buffer_ptr(&b)); 33492559Sdes buffer_free(&b); 33569591Sgreen return list; 33660573Skris} 33760573Skris 33892559Sdesstatic Authmethod * 33969591Sgreenauthmethod_lookup(const char *name) 34069591Sgreen{ 34198684Sdes int i; 34298684Sdes 34369591Sgreen if (name != NULL) 34498684Sdes for (i = 0; authmethods[i] != NULL; i++) 34598684Sdes if (authmethods[i]->enabled != NULL && 34698684Sdes *(authmethods[i]->enabled) != 0 && 34798684Sdes strcmp(name, authmethods[i]->name) == 0) 34898684Sdes return authmethods[i]; 34998684Sdes debug2("Unrecognized authentication method name: %s", 35098684Sdes name ? name : "NULL"); 35169591Sgreen return NULL; 35269591Sgreen} 353