auth2.c revision 98941
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" 2698684SdesRCSID("$OpenBSD: auth2.c,v 1.93 2002/05/31 11:35:15 markus Exp $"); 2760573Skris 2876262Sgreen#include "ssh2.h" 2960573Skris#include "xmalloc.h" 3060573Skris#include "packet.h" 3176262Sgreen#include "log.h" 3260573Skris#include "servconf.h" 3360573Skris#include "compat.h" 3460573Skris#include "auth.h" 3560573Skris#include "dispatch.h" 3676262Sgreen#include "pathnames.h" 3798684Sdes#include "monitor_wrap.h" 3860573Skris 3960573Skris/* import */ 4060573Skrisextern ServerOptions options; 4176262Sgreenextern u_char *session_id2; 4260573Skrisextern int session_id2_len; 4360573Skris 4498684SdesAuthctxt *x_authctxt = NULL; 4569591Sgreen 4698684Sdes/* methods */ 4798684Sdes 4898684Sdesextern Authmethod method_none; 4998684Sdesextern Authmethod method_pubkey; 5098684Sdesextern Authmethod method_passwd; 5198684Sdesextern Authmethod method_kbdint; 5298684Sdesextern Authmethod method_hostbased; 5398684Sdes 5498684SdesAuthmethod *authmethods[] = { 5598684Sdes &method_none, 5698684Sdes &method_pubkey, 5798684Sdes &method_passwd, 5898684Sdes &method_kbdint, 5998684Sdes &method_hostbased, 6098684Sdes NULL 6169591Sgreen}; 6269591Sgreen 6360573Skris/* protocol */ 6460573Skris 6592559Sdesstatic void input_service_request(int, u_int32_t, void *); 6692559Sdesstatic void input_userauth_request(int, u_int32_t, void *); 6760573Skris 6860573Skris/* helper */ 6992559Sdesstatic Authmethod *authmethod_lookup(const char *); 7092559Sdesstatic char *authmethods_get(void); 7198684Sdesint user_key_allowed(struct passwd *, Key *); 7298684Sdesint hostbased_key_allowed(struct passwd *, const char *, char *, Key *); 7360573Skris 7460573Skris/* 7569591Sgreen * loop until authctxt->success == TRUE 7660573Skris */ 7760573Skris 7898684SdesAuthctxt * 7992559Sdesdo_authentication2(void) 8060573Skris{ 8176262Sgreen Authctxt *authctxt = authctxt_new(); 8276262Sgreen 8369591Sgreen x_authctxt = authctxt; /*XXX*/ 8469591Sgreen 8592559Sdes /* challenge-response is implemented via keyboard interactive */ 8692559Sdes if (options.challenge_response_authentication) 8776262Sgreen options.kbd_interactive_authentication = 1; 8898941Sdes if (options.pam_authentication_via_kbd_int) 8998941Sdes options.kbd_interactive_authentication = 1; 9098941Sdes if (use_privsep) 9198941Sdes options.pam_authentication_via_kbd_int = 0; 9276262Sgreen 9392559Sdes dispatch_init(&dispatch_protocol_error); 9460573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 9569591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 9698684Sdes 9798684Sdes return (authctxt); 9860573Skris} 9960573Skris 10092559Sdesstatic void 10192559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 10260573Skris{ 10369591Sgreen Authctxt *authctxt = ctxt; 10476262Sgreen u_int len; 10560573Skris int accept = 0; 10660573Skris char *service = packet_get_string(&len); 10792559Sdes packet_check_eom(); 10860573Skris 10969591Sgreen if (authctxt == NULL) 11069591Sgreen fatal("input_service_request: no authctxt"); 11169591Sgreen 11260573Skris if (strcmp(service, "ssh-userauth") == 0) { 11369591Sgreen if (!authctxt->success) { 11460573Skris accept = 1; 11560573Skris /* now we can handle user-auth requests */ 11660573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 11760573Skris } 11860573Skris } 11960573Skris /* XXX all other service requests are denied */ 12060573Skris 12160573Skris if (accept) { 12260573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 12360573Skris packet_put_cstring(service); 12460573Skris packet_send(); 12560573Skris packet_write_wait(); 12660573Skris } else { 12760573Skris debug("bad service request %s", service); 12860573Skris packet_disconnect("bad service request %s", service); 12960573Skris } 13060573Skris xfree(service); 13160573Skris} 13260573Skris 13392559Sdesstatic void 13492559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 13560573Skris{ 13669591Sgreen Authctxt *authctxt = ctxt; 13769591Sgreen Authmethod *m = NULL; 13876262Sgreen char *user, *service, *method, *style = NULL; 13960573Skris int authenticated = 0; 14060573Skris 14169591Sgreen if (authctxt == NULL) 14269591Sgreen fatal("input_userauth_request: no authctxt"); 14360573Skris 14469591Sgreen user = packet_get_string(NULL); 14569591Sgreen service = packet_get_string(NULL); 14669591Sgreen method = packet_get_string(NULL); 14760573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 14876262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 14960573Skris 15076262Sgreen if ((style = strchr(user, ':')) != NULL) 15176262Sgreen *style++ = 0; 15276262Sgreen 15376262Sgreen if (authctxt->attempt++ == 0) { 15469591Sgreen /* setup auth context */ 15598684Sdes authctxt->pw = PRIVSEP(getpwnamallow(user)); 15698684Sdes if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 15769591Sgreen authctxt->valid = 1; 15869591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 15969591Sgreen#ifdef USE_PAM 16098941Sdes PRIVSEP(start_pam(authctxt->pw->pw_name)); 16169591Sgreen#endif 16269591Sgreen } else { 16369591Sgreen log("input_userauth_request: illegal user %s", user); 16498941Sdes#ifdef USE_PAM 16598941Sdes PRIVSEP(start_pam("NOUSER")); 16698941Sdes#endif 16760573Skris } 16898684Sdes setproctitle("%s%s", authctxt->pw ? user : "unknown", 16998684Sdes use_privsep ? " [net]" : ""); 17069591Sgreen authctxt->user = xstrdup(user); 17169591Sgreen authctxt->service = xstrdup(service); 17292559Sdes authctxt->style = style ? xstrdup(style) : NULL; 17398684Sdes if (use_privsep) 17498684Sdes mm_inform_authserv(service, style); 17592559Sdes } else if (strcmp(user, authctxt->user) != 0 || 17692559Sdes strcmp(service, authctxt->service) != 0) { 17792559Sdes packet_disconnect("Change of username or service not allowed: " 17892559Sdes "(%s,%s) -> (%s,%s)", 17992559Sdes authctxt->user, authctxt->service, user, service); 18060573Skris } 18176262Sgreen /* reset state */ 18292559Sdes auth2_challenge_stop(authctxt); 18376262Sgreen authctxt->postponed = 0; 18468704Sgreen 18576262Sgreen /* try to authenticate user */ 18669591Sgreen m = authmethod_lookup(method); 18769591Sgreen if (m != NULL) { 18869591Sgreen debug2("input_userauth_request: try method %s", method); 18969591Sgreen authenticated = m->userauth(authctxt); 19069591Sgreen } 19176262Sgreen userauth_finish(authctxt, authenticated, method); 19269591Sgreen 19369591Sgreen xfree(service); 19469591Sgreen xfree(user); 19569591Sgreen xfree(method); 19669591Sgreen} 19769591Sgreen 19869591Sgreenvoid 19976262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 20069591Sgreen{ 20192559Sdes char *methods; 20292559Sdes 20376262Sgreen if (!authctxt->valid && authenticated) 20476262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 20576262Sgreen authctxt->user); 20669591Sgreen 20776262Sgreen /* Special handling for root */ 20876262Sgreen if (authenticated && authctxt->pw->pw_uid == 0 && 20976262Sgreen !auth_root_allowed(method)) 21076262Sgreen authenticated = 0; 21160573Skris 21298941Sdes#ifdef USE_PAM 21398941Sdes if (!use_privsep && authenticated && authctxt->user && 21498941Sdes !do_pam_account(authctxt->user, NULL)) 21598941Sdes authenticated = 0; 21698941Sdes#endif /* USE_PAM */ 21798941Sdes 21876262Sgreen /* Log before sending the reply */ 21976262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 22069591Sgreen 22192559Sdes if (authctxt->postponed) 22292559Sdes return; 22392559Sdes 22492559Sdes /* XXX todo: check if multiple auth methods are needed */ 22592559Sdes if (authenticated == 1) { 22692559Sdes /* turn off userauth */ 22792559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 22892559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 22992559Sdes packet_send(); 23092559Sdes packet_write_wait(); 23192559Sdes /* now we can break out */ 23292559Sdes authctxt->success = 1; 23392559Sdes } else { 23498941Sdes if (authctxt->failures++ > AUTH_FAIL_MAX) { 23598941Sdes#ifdef WITH_AIXAUTHENTICATE 23698941Sdes /* XXX: privsep */ 23798941Sdes loginfailed(authctxt->user, 23898941Sdes get_canonical_hostname(options.verify_reverse_mapping), 23998941Sdes "ssh"); 24098941Sdes#endif /* WITH_AIXAUTHENTICATE */ 24192559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 24298941Sdes } 24392559Sdes methods = authmethods_get(); 24492559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 24592559Sdes packet_put_cstring(methods); 24692559Sdes packet_put_char(0); /* XXX partial success, unused */ 24792559Sdes packet_send(); 24892559Sdes packet_write_wait(); 24992559Sdes xfree(methods); 25092559Sdes } 25176262Sgreen} 25269591Sgreen 25369591Sgreen/* get current user */ 25460573Skris 25560573Skrisstruct passwd* 25660573Skrisauth_get_user(void) 25760573Skris{ 25869591Sgreen return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 25960573Skris} 26060573Skris 26169591Sgreen#define DELIM "," 26269591Sgreen 26392559Sdesstatic char * 26469591Sgreenauthmethods_get(void) 26560573Skris{ 26692559Sdes Buffer b; 26769591Sgreen char *list; 26898684Sdes int i; 26960573Skris 27092559Sdes buffer_init(&b); 27198684Sdes for (i = 0; authmethods[i] != NULL; i++) { 27298684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 27369591Sgreen continue; 27498684Sdes if (authmethods[i]->enabled != NULL && 27598684Sdes *(authmethods[i]->enabled) != 0) { 27692559Sdes if (buffer_len(&b) > 0) 27792559Sdes buffer_append(&b, ",", 1); 27898684Sdes buffer_append(&b, authmethods[i]->name, 27998684Sdes strlen(authmethods[i]->name)); 28060573Skris } 28169591Sgreen } 28292559Sdes buffer_append(&b, "\0", 1); 28392559Sdes list = xstrdup(buffer_ptr(&b)); 28492559Sdes buffer_free(&b); 28569591Sgreen return list; 28660573Skris} 28760573Skris 28892559Sdesstatic Authmethod * 28969591Sgreenauthmethod_lookup(const char *name) 29069591Sgreen{ 29198684Sdes int i; 29298684Sdes 29369591Sgreen if (name != NULL) 29498684Sdes for (i = 0; authmethods[i] != NULL; i++) 29598684Sdes if (authmethods[i]->enabled != NULL && 29698684Sdes *(authmethods[i]->enabled) != 0 && 29798684Sdes strcmp(name, authmethods[i]->name) == 0) 29898684Sdes return authmethods[i]; 29998684Sdes debug2("Unrecognized authentication method name: %s", 30098684Sdes name ? name : "NULL"); 30169591Sgreen return NULL; 30269591Sgreen} 303