auth2.c revision 221420
1221420Sdes/* $OpenBSD: auth2.c,v 1.122 2010/08/31 09:58:37 djm Exp $ */ 260573Skris/* 360573Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 460573Skris * 560573Skris * Redistribution and use in source and binary forms, with or without 660573Skris * modification, are permitted provided that the following conditions 760573Skris * are met: 860573Skris * 1. Redistributions of source code must retain the above copyright 960573Skris * notice, this list of conditions and the following disclaimer. 1060573Skris * 2. Redistributions in binary form must reproduce the above copyright 1160573Skris * notice, this list of conditions and the following disclaimer in the 1260573Skris * documentation and/or other materials provided with the distribution. 1360573Skris * 1460573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1560573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1660573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1760573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1860573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1960573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2060573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2160573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2260573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2360573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2460573Skris */ 2565674Skris 2660573Skris#include "includes.h" 27162856Sdes__RCSID("$FreeBSD: head/crypto/openssh/auth2.c 221420 2011-05-04 07:34:44Z des $"); 2860573Skris 29162856Sdes#include <sys/types.h> 30181111Sdes#include <sys/stat.h> 31181111Sdes#include <sys/uio.h> 32162856Sdes 33181111Sdes#include <fcntl.h> 34162856Sdes#include <pwd.h> 35162856Sdes#include <stdarg.h> 36162856Sdes#include <string.h> 37181111Sdes#include <unistd.h> 38162856Sdes 39197679Sdes#include "atomicio.h" 40162856Sdes#include "xmalloc.h" 4176262Sgreen#include "ssh2.h" 4260573Skris#include "packet.h" 4376262Sgreen#include "log.h" 44162856Sdes#include "buffer.h" 4560573Skris#include "servconf.h" 4660573Skris#include "compat.h" 47162856Sdes#include "key.h" 48162856Sdes#include "hostfile.h" 4960573Skris#include "auth.h" 5060573Skris#include "dispatch.h" 5176262Sgreen#include "pathnames.h" 52147005Sdes#include "buffer.h" 53162856Sdes#include "canohost.h" 5460573Skris 55124211Sdes#ifdef GSSAPI 56124211Sdes#include "ssh-gss.h" 57124211Sdes#endif 58162856Sdes#include "monitor_wrap.h" 59124211Sdes 6060573Skris/* import */ 6160573Skrisextern ServerOptions options; 6276262Sgreenextern u_char *session_id2; 63124211Sdesextern u_int session_id2_len; 64147005Sdesextern Buffer loginmsg; 6560573Skris 6698684Sdes/* methods */ 6798684Sdes 6898684Sdesextern Authmethod method_none; 6998684Sdesextern Authmethod method_pubkey; 7098684Sdesextern Authmethod method_passwd; 7198684Sdesextern Authmethod method_kbdint; 7298684Sdesextern Authmethod method_hostbased; 73124211Sdes#ifdef GSSAPI 74124211Sdesextern Authmethod method_gssapi; 75124211Sdes#endif 76192595Sdes#ifdef JPAKE 77192595Sdesextern Authmethod method_jpake; 78192595Sdes#endif 7998684Sdes 8098684SdesAuthmethod *authmethods[] = { 8198684Sdes &method_none, 8298684Sdes &method_pubkey, 83124211Sdes#ifdef GSSAPI 84124211Sdes &method_gssapi, 85124211Sdes#endif 86192595Sdes#ifdef JPAKE 87192595Sdes &method_jpake, 88192595Sdes#endif 8998684Sdes &method_passwd, 9098684Sdes &method_kbdint, 9198684Sdes &method_hostbased, 9298684Sdes NULL 9369591Sgreen}; 9469591Sgreen 9560573Skris/* protocol */ 9660573Skris 9792559Sdesstatic void input_service_request(int, u_int32_t, void *); 9892559Sdesstatic void input_userauth_request(int, u_int32_t, void *); 9960573Skris 10060573Skris/* helper */ 10192559Sdesstatic Authmethod *authmethod_lookup(const char *); 10292559Sdesstatic char *authmethods_get(void); 10360573Skris 104181111Sdeschar * 105181111Sdesauth2_read_banner(void) 106181111Sdes{ 107181111Sdes struct stat st; 108181111Sdes char *banner = NULL; 109181111Sdes size_t len, n; 110181111Sdes int fd; 111181111Sdes 112181111Sdes if ((fd = open(options.banner, O_RDONLY)) == -1) 113181111Sdes return (NULL); 114181111Sdes if (fstat(fd, &st) == -1) { 115181111Sdes close(fd); 116181111Sdes return (NULL); 117181111Sdes } 118181111Sdes if (st.st_size > 1*1024*1024) { 119181111Sdes close(fd); 120181111Sdes return (NULL); 121181111Sdes } 122181111Sdes 123181111Sdes len = (size_t)st.st_size; /* truncate */ 124181111Sdes banner = xmalloc(len + 1); 125181111Sdes n = atomicio(read, fd, banner, len); 126181111Sdes close(fd); 127181111Sdes 128181111Sdes if (n != len) { 129181111Sdes xfree(banner); 130181111Sdes return (NULL); 131181111Sdes } 132181111Sdes banner[n] = '\0'; 133181111Sdes 134181111Sdes return (banner); 135181111Sdes} 136181111Sdes 137181111Sdesvoid 138181111Sdesuserauth_send_banner(const char *msg) 139181111Sdes{ 140181111Sdes if (datafellows & SSH_BUG_BANNER) 141181111Sdes return; 142181111Sdes 143181111Sdes packet_start(SSH2_MSG_USERAUTH_BANNER); 144181111Sdes packet_put_cstring(msg); 145181111Sdes packet_put_cstring(""); /* language, unused */ 146181111Sdes packet_send(); 147181111Sdes debug("%s: sent", __func__); 148181111Sdes} 149181111Sdes 150181111Sdesstatic void 151181111Sdesuserauth_banner(void) 152181111Sdes{ 153181111Sdes char *banner = NULL; 154181111Sdes 155181111Sdes if (options.banner == NULL || 156181111Sdes strcasecmp(options.banner, "none") == 0 || 157181111Sdes (datafellows & SSH_BUG_BANNER) != 0) 158181111Sdes return; 159181111Sdes 160181111Sdes if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 161181111Sdes goto done; 162181111Sdes userauth_send_banner(banner); 163181111Sdes 164181111Sdesdone: 165181111Sdes if (banner) 166181111Sdes xfree(banner); 167181111Sdes} 168181111Sdes 16960573Skris/* 17069591Sgreen * loop until authctxt->success == TRUE 17160573Skris */ 172126277Sdesvoid 173126277Sdesdo_authentication2(Authctxt *authctxt) 17460573Skris{ 17592559Sdes dispatch_init(&dispatch_protocol_error); 17660573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 17769591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 17860573Skris} 17960573Skris 180162856Sdes/*ARGSUSED*/ 18192559Sdesstatic void 18292559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 18360573Skris{ 18469591Sgreen Authctxt *authctxt = ctxt; 18576262Sgreen u_int len; 186106130Sdes int acceptit = 0; 187221420Sdes char *service = packet_get_cstring(&len); 18892559Sdes packet_check_eom(); 18960573Skris 19069591Sgreen if (authctxt == NULL) 19169591Sgreen fatal("input_service_request: no authctxt"); 19269591Sgreen 19360573Skris if (strcmp(service, "ssh-userauth") == 0) { 19469591Sgreen if (!authctxt->success) { 195106130Sdes acceptit = 1; 19660573Skris /* now we can handle user-auth requests */ 19760573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 19860573Skris } 19960573Skris } 20060573Skris /* XXX all other service requests are denied */ 20160573Skris 202106130Sdes if (acceptit) { 20360573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 20460573Skris packet_put_cstring(service); 20560573Skris packet_send(); 20660573Skris packet_write_wait(); 20760573Skris } else { 20860573Skris debug("bad service request %s", service); 20960573Skris packet_disconnect("bad service request %s", service); 21060573Skris } 21160573Skris xfree(service); 21260573Skris} 21360573Skris 214162856Sdes/*ARGSUSED*/ 21592559Sdesstatic void 21692559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 21760573Skris{ 21869591Sgreen Authctxt *authctxt = ctxt; 21969591Sgreen Authmethod *m = NULL; 22076262Sgreen char *user, *service, *method, *style = NULL; 22160573Skris int authenticated = 0; 22299053Sdes#ifdef HAVE_LOGIN_CAP 22399053Sdes login_cap_t *lc; 22499053Sdes const char *from_host, *from_ip; 22560573Skris 226124211Sdes from_host = get_canonical_hostname(options.use_dns); 22799053Sdes from_ip = get_remote_ipaddr(); 22899053Sdes#endif 22999053Sdes 23069591Sgreen if (authctxt == NULL) 23169591Sgreen fatal("input_userauth_request: no authctxt"); 23260573Skris 233221420Sdes user = packet_get_cstring(NULL); 234221420Sdes service = packet_get_cstring(NULL); 235221420Sdes method = packet_get_cstring(NULL); 23660573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 23776262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 23860573Skris 23976262Sgreen if ((style = strchr(user, ':')) != NULL) 24076262Sgreen *style++ = 0; 24176262Sgreen 24276262Sgreen if (authctxt->attempt++ == 0) { 24369591Sgreen /* setup auth context */ 24498684Sdes authctxt->pw = PRIVSEP(getpwnamallow(user)); 245128460Sdes authctxt->user = xstrdup(user); 24698684Sdes if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 24769591Sgreen authctxt->valid = 1; 24869591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 24969591Sgreen } else { 250137019Sdes logit("input_userauth_request: invalid user %s", user); 251124211Sdes authctxt->pw = fakepw(); 252147005Sdes#ifdef SSH_AUDIT_EVENTS 253147005Sdes PRIVSEP(audit_event(SSH_INVALID_USER)); 254147005Sdes#endif 25560573Skris } 256157019Sdes#ifdef USE_PAM 257157019Sdes if (options.use_pam) 258157019Sdes PRIVSEP(start_pam(authctxt)); 259157019Sdes#endif 260137019Sdes setproctitle("%s%s", authctxt->valid ? user : "unknown", 26198684Sdes use_privsep ? " [net]" : ""); 26269591Sgreen authctxt->service = xstrdup(service); 26392559Sdes authctxt->style = style ? xstrdup(style) : NULL; 26498684Sdes if (use_privsep) 26598684Sdes mm_inform_authserv(service, style); 266181111Sdes userauth_banner(); 26792559Sdes } else if (strcmp(user, authctxt->user) != 0 || 26892559Sdes strcmp(service, authctxt->service) != 0) { 26992559Sdes packet_disconnect("Change of username or service not allowed: " 27092559Sdes "(%s,%s) -> (%s,%s)", 27192559Sdes authctxt->user, authctxt->service, user, service); 27260573Skris } 27399053Sdes 27499053Sdes#ifdef HAVE_LOGIN_CAP 27599053Sdes if (authctxt->pw != NULL) { 27699053Sdes lc = login_getpwclass(authctxt->pw); 27799053Sdes if (lc == NULL) 27899053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 27999053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 280124211Sdes logit("Denied connection for %.200s from %.200s [%.200s].", 28199053Sdes authctxt->pw->pw_name, from_host, from_ip); 28299053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 28399053Sdes } 28499053Sdes if (!auth_timeok(lc, time(NULL))) { 285124211Sdes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 28699053Sdes authctxt->pw->pw_name, from_host); 28799053Sdes packet_disconnect("Logins not available right now."); 28899053Sdes } 28999053Sdes login_close(lc); 29099053Sdes lc = NULL; 29199053Sdes } 29299053Sdes#endif /* HAVE_LOGIN_CAP */ 29399053Sdes 29476262Sgreen /* reset state */ 29592559Sdes auth2_challenge_stop(authctxt); 296192595Sdes#ifdef JPAKE 297192595Sdes auth2_jpake_stop(authctxt); 298192595Sdes#endif 299124211Sdes 300124211Sdes#ifdef GSSAPI 301192595Sdes /* XXX move to auth2_gssapi_stop() */ 302124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 303124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 304124211Sdes#endif 305124211Sdes 30676262Sgreen authctxt->postponed = 0; 30768704Sgreen 30876262Sgreen /* try to authenticate user */ 30969591Sgreen m = authmethod_lookup(method); 310181111Sdes if (m != NULL && authctxt->failures < options.max_authtries) { 31169591Sgreen debug2("input_userauth_request: try method %s", method); 31269591Sgreen authenticated = m->userauth(authctxt); 31369591Sgreen } 31476262Sgreen userauth_finish(authctxt, authenticated, method); 31569591Sgreen 31669591Sgreen xfree(service); 31769591Sgreen xfree(user); 31869591Sgreen xfree(method); 31969591Sgreen} 32069591Sgreen 32169591Sgreenvoid 32276262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 32369591Sgreen{ 32492559Sdes char *methods; 32592559Sdes 32676262Sgreen if (!authctxt->valid && authenticated) 32776262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 32876262Sgreen authctxt->user); 32969591Sgreen 33076262Sgreen /* Special handling for root */ 331113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 332147005Sdes !auth_root_allowed(method)) { 33376262Sgreen authenticated = 0; 334147005Sdes#ifdef SSH_AUDIT_EVENTS 335147005Sdes PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 336147005Sdes#endif 337147005Sdes } 33860573Skris 33998941Sdes#ifdef USE_PAM 340147005Sdes if (options.use_pam && authenticated) { 341147005Sdes if (!PRIVSEP(do_pam_account())) { 342147005Sdes /* if PAM returned a message, send it to the user */ 343147005Sdes if (buffer_len(&loginmsg) > 0) { 344147005Sdes buffer_append(&loginmsg, "\0", 1); 345147005Sdes userauth_send_banner(buffer_ptr(&loginmsg)); 346147005Sdes packet_write_wait(); 347147005Sdes } 348147005Sdes fatal("Access denied for user %s by PAM account " 349149753Sdes "configuration", authctxt->user); 350147005Sdes } 351147005Sdes } 352124211Sdes#endif 35398941Sdes 354106130Sdes#ifdef _UNICOS 355106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 356106130Sdes authenticated = 0; 357106130Sdes fatal("Access denied for user %s.",authctxt->user); 358106130Sdes } 359106130Sdes#endif /* _UNICOS */ 360106130Sdes 36176262Sgreen /* Log before sending the reply */ 36276262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 36369591Sgreen 36492559Sdes if (authctxt->postponed) 36592559Sdes return; 36692559Sdes 36792559Sdes /* XXX todo: check if multiple auth methods are needed */ 36892559Sdes if (authenticated == 1) { 36992559Sdes /* turn off userauth */ 37092559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 37192559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 37292559Sdes packet_send(); 37392559Sdes packet_write_wait(); 37492559Sdes /* now we can break out */ 37592559Sdes authctxt->success = 1; 37692559Sdes } else { 377181111Sdes 378181111Sdes /* Allow initial try of "none" auth without failure penalty */ 379181111Sdes if (authctxt->attempt > 1 || strcmp(method, "none") != 0) 380181111Sdes authctxt->failures++; 381181111Sdes if (authctxt->failures >= options.max_authtries) { 382147005Sdes#ifdef SSH_AUDIT_EVENTS 383147005Sdes PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 384147005Sdes#endif 38592559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 386147005Sdes } 38792559Sdes methods = authmethods_get(); 38892559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 38992559Sdes packet_put_cstring(methods); 39092559Sdes packet_put_char(0); /* XXX partial success, unused */ 39192559Sdes packet_send(); 39292559Sdes packet_write_wait(); 39392559Sdes xfree(methods); 39492559Sdes } 39576262Sgreen} 39669591Sgreen 39792559Sdesstatic char * 39869591Sgreenauthmethods_get(void) 39960573Skris{ 40092559Sdes Buffer b; 40169591Sgreen char *list; 40298684Sdes int i; 40360573Skris 40492559Sdes buffer_init(&b); 40598684Sdes for (i = 0; authmethods[i] != NULL; i++) { 40698684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 40769591Sgreen continue; 40898684Sdes if (authmethods[i]->enabled != NULL && 40998684Sdes *(authmethods[i]->enabled) != 0) { 41092559Sdes if (buffer_len(&b) > 0) 41192559Sdes buffer_append(&b, ",", 1); 41298684Sdes buffer_append(&b, authmethods[i]->name, 41398684Sdes strlen(authmethods[i]->name)); 41460573Skris } 41569591Sgreen } 41692559Sdes buffer_append(&b, "\0", 1); 41792559Sdes list = xstrdup(buffer_ptr(&b)); 41892559Sdes buffer_free(&b); 41969591Sgreen return list; 42060573Skris} 42160573Skris 42292559Sdesstatic Authmethod * 42369591Sgreenauthmethod_lookup(const char *name) 42469591Sgreen{ 42598684Sdes int i; 42698684Sdes 42769591Sgreen if (name != NULL) 42898684Sdes for (i = 0; authmethods[i] != NULL; i++) 42998684Sdes if (authmethods[i]->enabled != NULL && 43098684Sdes *(authmethods[i]->enabled) != 0 && 43198684Sdes strcmp(name, authmethods[i]->name) == 0) 43298684Sdes return authmethods[i]; 43398684Sdes debug2("Unrecognized authentication method name: %s", 43498684Sdes name ? name : "NULL"); 43569591Sgreen return NULL; 43669591Sgreen} 437181111Sdes 438