auth2.c revision 113911
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" 26113911SdesRCSID("$OpenBSD: auth2.c,v 1.96 2003/02/06 21:22:43 markus Exp $"); 2799053SdesRCSID("$FreeBSD: head/crypto/openssh/auth2.c 113911 2003-04-23 17:13:13Z 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 4160573Skris/* import */ 4260573Skrisextern ServerOptions options; 4376262Sgreenextern u_char *session_id2; 4460573Skrisextern int session_id2_len; 4560573Skris 4698684SdesAuthctxt *x_authctxt = NULL; 4769591Sgreen 4898684Sdes/* methods */ 4998684Sdes 5098684Sdesextern Authmethod method_none; 5198684Sdesextern Authmethod method_pubkey; 5298684Sdesextern Authmethod method_passwd; 5398684Sdesextern Authmethod method_kbdint; 5498684Sdesextern Authmethod method_hostbased; 5598684Sdes 5698684SdesAuthmethod *authmethods[] = { 5798684Sdes &method_none, 5898684Sdes &method_pubkey, 5998684Sdes &method_passwd, 6098684Sdes &method_kbdint, 6198684Sdes &method_hostbased, 6298684Sdes NULL 6369591Sgreen}; 6469591Sgreen 6560573Skris/* protocol */ 6660573Skris 6792559Sdesstatic void input_service_request(int, u_int32_t, void *); 6892559Sdesstatic void input_userauth_request(int, u_int32_t, void *); 6960573Skris 7060573Skris/* helper */ 7192559Sdesstatic Authmethod *authmethod_lookup(const char *); 7292559Sdesstatic char *authmethods_get(void); 7398684Sdesint user_key_allowed(struct passwd *, Key *); 7498684Sdesint hostbased_key_allowed(struct passwd *, const char *, char *, Key *); 7560573Skris 7660573Skris/* 7769591Sgreen * loop until authctxt->success == TRUE 7860573Skris */ 7960573Skris 8098684SdesAuthctxt * 8192559Sdesdo_authentication2(void) 8260573Skris{ 8376262Sgreen Authctxt *authctxt = authctxt_new(); 8476262Sgreen 8569591Sgreen x_authctxt = authctxt; /*XXX*/ 8669591Sgreen 8792559Sdes /* challenge-response is implemented via keyboard interactive */ 8892559Sdes if (options.challenge_response_authentication) 8976262Sgreen options.kbd_interactive_authentication = 1; 9098941Sdes if (options.pam_authentication_via_kbd_int) 9198941Sdes options.kbd_interactive_authentication = 1; 9298941Sdes if (use_privsep) 9398941Sdes options.pam_authentication_via_kbd_int = 0; 9476262Sgreen 9592559Sdes dispatch_init(&dispatch_protocol_error); 9660573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 9769591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 9898684Sdes 9998684Sdes return (authctxt); 10060573Skris} 10160573Skris 10292559Sdesstatic void 10392559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 10460573Skris{ 10569591Sgreen Authctxt *authctxt = ctxt; 10676262Sgreen u_int len; 107106130Sdes int acceptit = 0; 10860573Skris char *service = packet_get_string(&len); 10992559Sdes packet_check_eom(); 11060573Skris 11169591Sgreen if (authctxt == NULL) 11269591Sgreen fatal("input_service_request: no authctxt"); 11369591Sgreen 11460573Skris if (strcmp(service, "ssh-userauth") == 0) { 11569591Sgreen if (!authctxt->success) { 116106130Sdes acceptit = 1; 11760573Skris /* now we can handle user-auth requests */ 11860573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 11960573Skris } 12060573Skris } 12160573Skris /* XXX all other service requests are denied */ 12260573Skris 123106130Sdes if (acceptit) { 12460573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 12560573Skris packet_put_cstring(service); 12660573Skris packet_send(); 12760573Skris packet_write_wait(); 12860573Skris } else { 12960573Skris debug("bad service request %s", service); 13060573Skris packet_disconnect("bad service request %s", service); 13160573Skris } 13260573Skris xfree(service); 13360573Skris} 13460573Skris 13592559Sdesstatic void 13692559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 13760573Skris{ 13869591Sgreen Authctxt *authctxt = ctxt; 13969591Sgreen Authmethod *m = NULL; 14076262Sgreen char *user, *service, *method, *style = NULL; 14160573Skris int authenticated = 0; 14299053Sdes#ifdef HAVE_LOGIN_CAP 14399053Sdes login_cap_t *lc; 14499053Sdes const char *from_host, *from_ip; 14560573Skris 14699053Sdes from_host = get_canonical_hostname(options.verify_reverse_mapping); 14799053Sdes from_ip = get_remote_ipaddr(); 14899053Sdes#endif 14999053Sdes 15069591Sgreen if (authctxt == NULL) 15169591Sgreen fatal("input_userauth_request: no authctxt"); 15260573Skris 15369591Sgreen user = packet_get_string(NULL); 15469591Sgreen service = packet_get_string(NULL); 15569591Sgreen method = packet_get_string(NULL); 15660573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 15776262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 15860573Skris 15976262Sgreen if ((style = strchr(user, ':')) != NULL) 16076262Sgreen *style++ = 0; 16176262Sgreen 16276262Sgreen if (authctxt->attempt++ == 0) { 16369591Sgreen /* setup auth context */ 16498684Sdes authctxt->pw = PRIVSEP(getpwnamallow(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 16998941Sdes PRIVSEP(start_pam(authctxt->pw->pw_name)); 17069591Sgreen#endif 17169591Sgreen } else { 17269591Sgreen log("input_userauth_request: illegal user %s", user); 17398941Sdes#ifdef USE_PAM 17498941Sdes PRIVSEP(start_pam("NOUSER")); 17598941Sdes#endif 17660573Skris } 17798684Sdes setproctitle("%s%s", authctxt->pw ? user : "unknown", 17898684Sdes use_privsep ? " [net]" : ""); 17969591Sgreen authctxt->user = xstrdup(user); 18069591Sgreen authctxt->service = xstrdup(service); 18192559Sdes authctxt->style = style ? xstrdup(style) : NULL; 18298684Sdes if (use_privsep) 18398684Sdes mm_inform_authserv(service, style); 18492559Sdes } else if (strcmp(user, authctxt->user) != 0 || 18592559Sdes strcmp(service, authctxt->service) != 0) { 18692559Sdes packet_disconnect("Change of username or service not allowed: " 18792559Sdes "(%s,%s) -> (%s,%s)", 18892559Sdes authctxt->user, authctxt->service, user, service); 18960573Skris } 19099053Sdes 19199053Sdes#ifdef HAVE_LOGIN_CAP 19299053Sdes if (authctxt->pw != NULL) { 19399053Sdes lc = login_getpwclass(authctxt->pw); 19499053Sdes if (lc == NULL) 19599053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 19699053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 19799053Sdes log("Denied connection for %.200s from %.200s [%.200s].", 19899053Sdes authctxt->pw->pw_name, from_host, from_ip); 19999053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 20099053Sdes } 20199053Sdes if (!auth_timeok(lc, time(NULL))) { 20299053Sdes log("LOGIN %.200s REFUSED (TIME) FROM %.200s", 20399053Sdes authctxt->pw->pw_name, from_host); 20499053Sdes packet_disconnect("Logins not available right now."); 20599053Sdes } 20699053Sdes login_close(lc); 20799053Sdes lc = NULL; 20899053Sdes } 20999053Sdes#endif /* HAVE_LOGIN_CAP */ 21099053Sdes 21176262Sgreen /* reset state */ 21292559Sdes auth2_challenge_stop(authctxt); 21376262Sgreen authctxt->postponed = 0; 21468704Sgreen 21576262Sgreen /* try to authenticate user */ 21669591Sgreen m = authmethod_lookup(method); 21769591Sgreen if (m != NULL) { 21869591Sgreen debug2("input_userauth_request: try method %s", method); 21969591Sgreen authenticated = m->userauth(authctxt); 22069591Sgreen } 22176262Sgreen userauth_finish(authctxt, authenticated, method); 22269591Sgreen 22369591Sgreen xfree(service); 22469591Sgreen xfree(user); 22569591Sgreen xfree(method); 22669591Sgreen} 22769591Sgreen 22869591Sgreenvoid 22976262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 23069591Sgreen{ 23192559Sdes char *methods; 23292559Sdes 23376262Sgreen if (!authctxt->valid && authenticated) 23476262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 23576262Sgreen authctxt->user); 23669591Sgreen 23776262Sgreen /* Special handling for root */ 238113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 23976262Sgreen !auth_root_allowed(method)) 24076262Sgreen authenticated = 0; 24160573Skris 24298941Sdes#ifdef USE_PAM 24398941Sdes if (!use_privsep && authenticated && authctxt->user && 24498941Sdes !do_pam_account(authctxt->user, NULL)) 24598941Sdes authenticated = 0; 24698941Sdes#endif /* USE_PAM */ 24798941Sdes 248106130Sdes#ifdef _UNICOS 249106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 250106130Sdes authenticated = 0; 251106130Sdes fatal("Access denied for user %s.",authctxt->user); 252106130Sdes } 253106130Sdes#endif /* _UNICOS */ 254106130Sdes 25576262Sgreen /* Log before sending the reply */ 25676262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 25769591Sgreen 25892559Sdes if (authctxt->postponed) 25992559Sdes return; 26092559Sdes 26192559Sdes /* XXX todo: check if multiple auth methods are needed */ 26292559Sdes if (authenticated == 1) { 26392559Sdes /* turn off userauth */ 26492559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 26592559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 26692559Sdes packet_send(); 26792559Sdes packet_write_wait(); 26892559Sdes /* now we can break out */ 26992559Sdes authctxt->success = 1; 27092559Sdes } else { 27198941Sdes if (authctxt->failures++ > AUTH_FAIL_MAX) { 27292559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 27398941Sdes } 274106130Sdes#ifdef _UNICOS 275106130Sdes if (strcmp(method, "password") == 0) 276106130Sdes cray_login_failure(authctxt->user, IA_UDBERR); 277106130Sdes#endif /* _UNICOS */ 27892559Sdes methods = authmethods_get(); 27992559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 28092559Sdes packet_put_cstring(methods); 28192559Sdes packet_put_char(0); /* XXX partial success, unused */ 28292559Sdes packet_send(); 28392559Sdes packet_write_wait(); 28492559Sdes xfree(methods); 28592559Sdes } 28676262Sgreen} 28769591Sgreen 28869591Sgreen/* get current user */ 28960573Skris 29060573Skrisstruct passwd* 29160573Skrisauth_get_user(void) 29260573Skris{ 29369591Sgreen return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 29460573Skris} 29560573Skris 29669591Sgreen#define DELIM "," 29769591Sgreen 29892559Sdesstatic char * 29969591Sgreenauthmethods_get(void) 30060573Skris{ 30192559Sdes Buffer b; 30269591Sgreen char *list; 30398684Sdes int i; 30460573Skris 30592559Sdes buffer_init(&b); 30698684Sdes for (i = 0; authmethods[i] != NULL; i++) { 30798684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 30869591Sgreen continue; 30998684Sdes if (authmethods[i]->enabled != NULL && 31098684Sdes *(authmethods[i]->enabled) != 0) { 31192559Sdes if (buffer_len(&b) > 0) 31292559Sdes buffer_append(&b, ",", 1); 31398684Sdes buffer_append(&b, authmethods[i]->name, 31498684Sdes strlen(authmethods[i]->name)); 31560573Skris } 31669591Sgreen } 31792559Sdes buffer_append(&b, "\0", 1); 31892559Sdes list = xstrdup(buffer_ptr(&b)); 31992559Sdes buffer_free(&b); 32069591Sgreen return list; 32160573Skris} 32260573Skris 32392559Sdesstatic Authmethod * 32469591Sgreenauthmethod_lookup(const char *name) 32569591Sgreen{ 32698684Sdes int i; 32798684Sdes 32869591Sgreen if (name != NULL) 32998684Sdes for (i = 0; authmethods[i] != NULL; i++) 33098684Sdes if (authmethods[i]->enabled != NULL && 33198684Sdes *(authmethods[i]->enabled) != 0 && 33298684Sdes strcmp(name, authmethods[i]->name) == 0) 33398684Sdes return authmethods[i]; 33498684Sdes debug2("Unrecognized authentication method name: %s", 33598684Sdes name ? name : "NULL"); 33669591Sgreen return NULL; 33769591Sgreen} 338