auth2.c revision 181111
1181111Sdes/* $OpenBSD: auth2.c,v 1.119 2008/07/04 23:30:16 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 181111 2008-08-01 02:48:36Z 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 39162856Sdes#include "xmalloc.h" 40181111Sdes#include "atomicio.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 7698684Sdes 7798684SdesAuthmethod *authmethods[] = { 7898684Sdes &method_none, 7998684Sdes &method_pubkey, 80124211Sdes#ifdef GSSAPI 81124211Sdes &method_gssapi, 82124211Sdes#endif 8398684Sdes &method_passwd, 8498684Sdes &method_kbdint, 8598684Sdes &method_hostbased, 8698684Sdes NULL 8769591Sgreen}; 8869591Sgreen 8960573Skris/* protocol */ 9060573Skris 9192559Sdesstatic void input_service_request(int, u_int32_t, void *); 9292559Sdesstatic void input_userauth_request(int, u_int32_t, void *); 9360573Skris 9460573Skris/* helper */ 9592559Sdesstatic Authmethod *authmethod_lookup(const char *); 9692559Sdesstatic char *authmethods_get(void); 9760573Skris 98181111Sdeschar * 99181111Sdesauth2_read_banner(void) 100181111Sdes{ 101181111Sdes struct stat st; 102181111Sdes char *banner = NULL; 103181111Sdes size_t len, n; 104181111Sdes int fd; 105181111Sdes 106181111Sdes if ((fd = open(options.banner, O_RDONLY)) == -1) 107181111Sdes return (NULL); 108181111Sdes if (fstat(fd, &st) == -1) { 109181111Sdes close(fd); 110181111Sdes return (NULL); 111181111Sdes } 112181111Sdes if (st.st_size > 1*1024*1024) { 113181111Sdes close(fd); 114181111Sdes return (NULL); 115181111Sdes } 116181111Sdes 117181111Sdes len = (size_t)st.st_size; /* truncate */ 118181111Sdes banner = xmalloc(len + 1); 119181111Sdes n = atomicio(read, fd, banner, len); 120181111Sdes close(fd); 121181111Sdes 122181111Sdes if (n != len) { 123181111Sdes xfree(banner); 124181111Sdes return (NULL); 125181111Sdes } 126181111Sdes banner[n] = '\0'; 127181111Sdes 128181111Sdes return (banner); 129181111Sdes} 130181111Sdes 131181111Sdesvoid 132181111Sdesuserauth_send_banner(const char *msg) 133181111Sdes{ 134181111Sdes if (datafellows & SSH_BUG_BANNER) 135181111Sdes return; 136181111Sdes 137181111Sdes packet_start(SSH2_MSG_USERAUTH_BANNER); 138181111Sdes packet_put_cstring(msg); 139181111Sdes packet_put_cstring(""); /* language, unused */ 140181111Sdes packet_send(); 141181111Sdes debug("%s: sent", __func__); 142181111Sdes} 143181111Sdes 144181111Sdesstatic void 145181111Sdesuserauth_banner(void) 146181111Sdes{ 147181111Sdes char *banner = NULL; 148181111Sdes 149181111Sdes if (options.banner == NULL || 150181111Sdes strcasecmp(options.banner, "none") == 0 || 151181111Sdes (datafellows & SSH_BUG_BANNER) != 0) 152181111Sdes return; 153181111Sdes 154181111Sdes if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 155181111Sdes goto done; 156181111Sdes userauth_send_banner(banner); 157181111Sdes 158181111Sdesdone: 159181111Sdes if (banner) 160181111Sdes xfree(banner); 161181111Sdes} 162181111Sdes 16360573Skris/* 16469591Sgreen * loop until authctxt->success == TRUE 16560573Skris */ 166126277Sdesvoid 167126277Sdesdo_authentication2(Authctxt *authctxt) 16860573Skris{ 16992559Sdes dispatch_init(&dispatch_protocol_error); 17060573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 17169591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 17260573Skris} 17360573Skris 174162856Sdes/*ARGSUSED*/ 17592559Sdesstatic void 17692559Sdesinput_service_request(int type, u_int32_t seq, void *ctxt) 17760573Skris{ 17869591Sgreen Authctxt *authctxt = ctxt; 17976262Sgreen u_int len; 180106130Sdes int acceptit = 0; 18160573Skris char *service = packet_get_string(&len); 18292559Sdes packet_check_eom(); 18360573Skris 18469591Sgreen if (authctxt == NULL) 18569591Sgreen fatal("input_service_request: no authctxt"); 18669591Sgreen 18760573Skris if (strcmp(service, "ssh-userauth") == 0) { 18869591Sgreen if (!authctxt->success) { 189106130Sdes acceptit = 1; 19060573Skris /* now we can handle user-auth requests */ 19160573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 19260573Skris } 19360573Skris } 19460573Skris /* XXX all other service requests are denied */ 19560573Skris 196106130Sdes if (acceptit) { 19760573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 19860573Skris packet_put_cstring(service); 19960573Skris packet_send(); 20060573Skris packet_write_wait(); 20160573Skris } else { 20260573Skris debug("bad service request %s", service); 20360573Skris packet_disconnect("bad service request %s", service); 20460573Skris } 20560573Skris xfree(service); 20660573Skris} 20760573Skris 208162856Sdes/*ARGSUSED*/ 20992559Sdesstatic void 21092559Sdesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 21160573Skris{ 21269591Sgreen Authctxt *authctxt = ctxt; 21369591Sgreen Authmethod *m = NULL; 21476262Sgreen char *user, *service, *method, *style = NULL; 21560573Skris int authenticated = 0; 21699053Sdes#ifdef HAVE_LOGIN_CAP 21799053Sdes login_cap_t *lc; 21899053Sdes const char *from_host, *from_ip; 21960573Skris 220124211Sdes from_host = get_canonical_hostname(options.use_dns); 22199053Sdes from_ip = get_remote_ipaddr(); 22299053Sdes#endif 22399053Sdes 22469591Sgreen if (authctxt == NULL) 22569591Sgreen fatal("input_userauth_request: no authctxt"); 22660573Skris 22769591Sgreen user = packet_get_string(NULL); 22869591Sgreen service = packet_get_string(NULL); 22969591Sgreen method = packet_get_string(NULL); 23060573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 23176262Sgreen debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 23260573Skris 23376262Sgreen if ((style = strchr(user, ':')) != NULL) 23476262Sgreen *style++ = 0; 23576262Sgreen 23676262Sgreen if (authctxt->attempt++ == 0) { 23769591Sgreen /* setup auth context */ 23898684Sdes authctxt->pw = PRIVSEP(getpwnamallow(user)); 239128460Sdes authctxt->user = xstrdup(user); 24098684Sdes if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 24169591Sgreen authctxt->valid = 1; 24269591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 24369591Sgreen } else { 244137019Sdes logit("input_userauth_request: invalid user %s", user); 245124211Sdes authctxt->pw = fakepw(); 246147005Sdes#ifdef SSH_AUDIT_EVENTS 247147005Sdes PRIVSEP(audit_event(SSH_INVALID_USER)); 248147005Sdes#endif 24960573Skris } 250157019Sdes#ifdef USE_PAM 251157019Sdes if (options.use_pam) 252157019Sdes PRIVSEP(start_pam(authctxt)); 253157019Sdes#endif 254137019Sdes setproctitle("%s%s", authctxt->valid ? user : "unknown", 25598684Sdes use_privsep ? " [net]" : ""); 25669591Sgreen authctxt->service = xstrdup(service); 25792559Sdes authctxt->style = style ? xstrdup(style) : NULL; 25898684Sdes if (use_privsep) 25998684Sdes mm_inform_authserv(service, style); 260181111Sdes userauth_banner(); 26192559Sdes } else if (strcmp(user, authctxt->user) != 0 || 26292559Sdes strcmp(service, authctxt->service) != 0) { 26392559Sdes packet_disconnect("Change of username or service not allowed: " 26492559Sdes "(%s,%s) -> (%s,%s)", 26592559Sdes authctxt->user, authctxt->service, user, service); 26660573Skris } 26799053Sdes 26899053Sdes#ifdef HAVE_LOGIN_CAP 26999053Sdes if (authctxt->pw != NULL) { 27099053Sdes lc = login_getpwclass(authctxt->pw); 27199053Sdes if (lc == NULL) 27299053Sdes lc = login_getclassbyname(NULL, authctxt->pw); 27399053Sdes if (!auth_hostok(lc, from_host, from_ip)) { 274124211Sdes logit("Denied connection for %.200s from %.200s [%.200s].", 27599053Sdes authctxt->pw->pw_name, from_host, from_ip); 27699053Sdes packet_disconnect("Sorry, you are not allowed to connect."); 27799053Sdes } 27899053Sdes if (!auth_timeok(lc, time(NULL))) { 279124211Sdes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 28099053Sdes authctxt->pw->pw_name, from_host); 28199053Sdes packet_disconnect("Logins not available right now."); 28299053Sdes } 28399053Sdes login_close(lc); 28499053Sdes lc = NULL; 28599053Sdes } 28699053Sdes#endif /* HAVE_LOGIN_CAP */ 28799053Sdes 28876262Sgreen /* reset state */ 28992559Sdes auth2_challenge_stop(authctxt); 290124211Sdes 291124211Sdes#ifdef GSSAPI 292124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 293124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 294124211Sdes#endif 295124211Sdes 29676262Sgreen authctxt->postponed = 0; 29768704Sgreen 29876262Sgreen /* try to authenticate user */ 29969591Sgreen m = authmethod_lookup(method); 300181111Sdes if (m != NULL && authctxt->failures < options.max_authtries) { 30169591Sgreen debug2("input_userauth_request: try method %s", method); 30269591Sgreen authenticated = m->userauth(authctxt); 30369591Sgreen } 30476262Sgreen userauth_finish(authctxt, authenticated, method); 30569591Sgreen 30669591Sgreen xfree(service); 30769591Sgreen xfree(user); 30869591Sgreen xfree(method); 30969591Sgreen} 31069591Sgreen 31169591Sgreenvoid 31276262Sgreenuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 31369591Sgreen{ 31492559Sdes char *methods; 31592559Sdes 31676262Sgreen if (!authctxt->valid && authenticated) 31776262Sgreen fatal("INTERNAL ERROR: authenticated invalid user %s", 31876262Sgreen authctxt->user); 31969591Sgreen 32076262Sgreen /* Special handling for root */ 321113911Sdes if (authenticated && authctxt->pw->pw_uid == 0 && 322147005Sdes !auth_root_allowed(method)) { 32376262Sgreen authenticated = 0; 324147005Sdes#ifdef SSH_AUDIT_EVENTS 325147005Sdes PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 326147005Sdes#endif 327147005Sdes } 32860573Skris 32998941Sdes#ifdef USE_PAM 330147005Sdes if (options.use_pam && authenticated) { 331147005Sdes if (!PRIVSEP(do_pam_account())) { 332147005Sdes /* if PAM returned a message, send it to the user */ 333147005Sdes if (buffer_len(&loginmsg) > 0) { 334147005Sdes buffer_append(&loginmsg, "\0", 1); 335147005Sdes userauth_send_banner(buffer_ptr(&loginmsg)); 336147005Sdes packet_write_wait(); 337147005Sdes } 338147005Sdes fatal("Access denied for user %s by PAM account " 339149753Sdes "configuration", authctxt->user); 340147005Sdes } 341147005Sdes } 342124211Sdes#endif 34398941Sdes 344106130Sdes#ifdef _UNICOS 345106130Sdes if (authenticated && cray_access_denied(authctxt->user)) { 346106130Sdes authenticated = 0; 347106130Sdes fatal("Access denied for user %s.",authctxt->user); 348106130Sdes } 349106130Sdes#endif /* _UNICOS */ 350106130Sdes 35176262Sgreen /* Log before sending the reply */ 35276262Sgreen auth_log(authctxt, authenticated, method, " ssh2"); 35369591Sgreen 35492559Sdes if (authctxt->postponed) 35592559Sdes return; 35692559Sdes 35792559Sdes /* XXX todo: check if multiple auth methods are needed */ 35892559Sdes if (authenticated == 1) { 35992559Sdes /* turn off userauth */ 36092559Sdes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 36192559Sdes packet_start(SSH2_MSG_USERAUTH_SUCCESS); 36292559Sdes packet_send(); 36392559Sdes packet_write_wait(); 36492559Sdes /* now we can break out */ 36592559Sdes authctxt->success = 1; 36692559Sdes } else { 367181111Sdes 368181111Sdes /* Allow initial try of "none" auth without failure penalty */ 369181111Sdes if (authctxt->attempt > 1 || strcmp(method, "none") != 0) 370181111Sdes authctxt->failures++; 371181111Sdes if (authctxt->failures >= options.max_authtries) { 372147005Sdes#ifdef SSH_AUDIT_EVENTS 373147005Sdes PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 374147005Sdes#endif 37592559Sdes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 376147005Sdes } 37792559Sdes methods = authmethods_get(); 37892559Sdes packet_start(SSH2_MSG_USERAUTH_FAILURE); 37992559Sdes packet_put_cstring(methods); 38092559Sdes packet_put_char(0); /* XXX partial success, unused */ 38192559Sdes packet_send(); 38292559Sdes packet_write_wait(); 38392559Sdes xfree(methods); 38492559Sdes } 38576262Sgreen} 38669591Sgreen 38792559Sdesstatic char * 38869591Sgreenauthmethods_get(void) 38960573Skris{ 39092559Sdes Buffer b; 39169591Sgreen char *list; 39298684Sdes int i; 39360573Skris 39492559Sdes buffer_init(&b); 39598684Sdes for (i = 0; authmethods[i] != NULL; i++) { 39698684Sdes if (strcmp(authmethods[i]->name, "none") == 0) 39769591Sgreen continue; 39898684Sdes if (authmethods[i]->enabled != NULL && 39998684Sdes *(authmethods[i]->enabled) != 0) { 40092559Sdes if (buffer_len(&b) > 0) 40192559Sdes buffer_append(&b, ",", 1); 40298684Sdes buffer_append(&b, authmethods[i]->name, 40398684Sdes strlen(authmethods[i]->name)); 40460573Skris } 40569591Sgreen } 40692559Sdes buffer_append(&b, "\0", 1); 40792559Sdes list = xstrdup(buffer_ptr(&b)); 40892559Sdes buffer_free(&b); 40969591Sgreen return list; 41060573Skris} 41160573Skris 41292559Sdesstatic Authmethod * 41369591Sgreenauthmethod_lookup(const char *name) 41469591Sgreen{ 41598684Sdes int i; 41698684Sdes 41769591Sgreen if (name != NULL) 41898684Sdes for (i = 0; authmethods[i] != NULL; i++) 41998684Sdes if (authmethods[i]->enabled != NULL && 42098684Sdes *(authmethods[i]->enabled) != 0 && 42198684Sdes strcmp(name, authmethods[i]->name) == 0) 42298684Sdes return authmethods[i]; 42398684Sdes debug2("Unrecognized authentication method name: %s", 42498684Sdes name ? name : "NULL"); 42569591Sgreen return NULL; 42669591Sgreen} 427181111Sdes 428