auth2.c revision 197679
11590Srgrimes/* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */ 21590Srgrimes/* 31590Srgrimes * Copyright (c) 2000 Markus Friedl. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 151590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 181590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 191590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 201590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 211590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 221590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 231590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 241590Srgrimes */ 251590Srgrimes 261590Srgrimes#include "includes.h" 271590Srgrimes__RCSID("$FreeBSD: head/crypto/openssh/auth2.c 197679 2009-10-01 17:12:52Z des $"); 281590Srgrimes 291590Srgrimes#include <sys/types.h> 301590Srgrimes#include <sys/stat.h> 311590Srgrimes#include <sys/uio.h> 321590Srgrimes 331590Srgrimes#include <fcntl.h> 341590Srgrimes#include <pwd.h> 3527919Scharnier#include <stdarg.h> 361590Srgrimes#include <string.h> 371590Srgrimes#include <unistd.h> 381590Srgrimes 391590Srgrimes#include "atomicio.h" 401590Srgrimes#include "xmalloc.h" 4129922Smarkm#include "ssh2.h" 421590Srgrimes#include "packet.h" 431590Srgrimes#include "log.h" 441590Srgrimes#include "buffer.h" 451590Srgrimes#include "servconf.h" 461590Srgrimes#include "compat.h" 4795621Smarkm#include "key.h" 4895621Smarkm#include "hostfile.h" 4995621Smarkm#include "auth.h" 501590Srgrimes#include "dispatch.h" 511590Srgrimes#include "pathnames.h" 521590Srgrimes#include "buffer.h" 531590Srgrimes#include "canohost.h" 541590Srgrimes 551590Srgrimes#ifdef GSSAPI 561590Srgrimes#include "ssh-gss.h" 571590Srgrimes#endif 581590Srgrimes#include "monitor_wrap.h" 598232Sdg 601590Srgrimes/* import */ 6127919Scharnierextern ServerOptions options; 621590Srgrimesextern u_char *session_id2; 631590Srgrimesextern u_int session_id2_len; 6440103Smarkmextern Buffer loginmsg; 651590Srgrimes 661590Srgrimes/* methods */ 671590Srgrimes 681590Srgrimesextern Authmethod method_none; 691590Srgrimesextern Authmethod method_pubkey; 701590Srgrimesextern Authmethod method_passwd; 711590Srgrimesextern Authmethod method_kbdint; 721590Srgrimesextern Authmethod method_hostbased; 731590Srgrimes#ifdef GSSAPI 741590Srgrimesextern Authmethod method_gssapi; 751590Srgrimes#endif 7657450Smarkm#ifdef JPAKE 7729922Smarkmextern Authmethod method_jpake; 781590Srgrimes#endif 7934897Smarkm 801590SrgrimesAuthmethod *authmethods[] = { 811590Srgrimes &method_none, 821590Srgrimes &method_pubkey, 831590Srgrimes#ifdef GSSAPI 841590Srgrimes &method_gssapi, 851590Srgrimes#endif 861590Srgrimes#ifdef JPAKE 871590Srgrimes &method_jpake, 881590Srgrimes#endif 891590Srgrimes &method_passwd, 901590Srgrimes &method_kbdint, 911590Srgrimes &method_hostbased, 921590Srgrimes NULL 931590Srgrimes}; 941590Srgrimes 951590Srgrimes/* protocol */ 961590Srgrimes 971590Srgrimesstatic void input_service_request(int, u_int32_t, void *); 9857232Sshinstatic void input_userauth_request(int, u_int32_t, void *); 991590Srgrimes 1001590Srgrimes/* helper */ 1011590Srgrimesstatic Authmethod *authmethod_lookup(const char *); 1021590Srgrimesstatic char *authmethods_get(void); 10395621Smarkm 1041590Srgrimeschar * 1059881Sacheauth2_read_banner(void) 10617284Spst{ 1071590Srgrimes struct stat st; 1081590Srgrimes char *banner = NULL; 1091590Srgrimes size_t len, n; 1101590Srgrimes int fd; 1111590Srgrimes 11292921Simp if ((fd = open(options.banner, O_RDONLY)) == -1) 11392921Simp return (NULL); 11492921Simp if (fstat(fd, &st) == -1) { 11592921Simp close(fd); 11692921Simp return (NULL); 11792921Simp } 11892921Simp if (st.st_size > 1*1024*1024) { 11992921Simp close(fd); 12095621Smarkm return (NULL); 12192921Simp } 12292921Simp 12392921Simp len = (size_t)st.st_size; /* truncate */ 12492921Simp banner = xmalloc(len + 1); 12592921Simp n = atomicio(read, fd, banner, len); 12692921Simp close(fd); 12792921Simp 12892921Simp if (n != len) { 12992921Simp xfree(banner); 1301590Srgrimes return (NULL); 1311590Srgrimes } 13293057Simp banner[n] = '\0'; 1331590Srgrimes 1341590Srgrimes return (banner); 1351590Srgrimes} 1361590Srgrimes 1371590Srgrimesvoid 1388232Sdguserauth_send_banner(const char *msg) 13947549Sbde{ 14040103Smarkm if (datafellows & SSH_BUG_BANNER) 14140103Smarkm return; 14240103Smarkm 14356590Sshin packet_start(SSH2_MSG_USERAUTH_BANNER); 14456590Sshin packet_put_cstring(msg); 1451590Srgrimes packet_put_cstring(""); /* language, unused */ 1468232Sdg packet_send(); 1471590Srgrimes debug("%s: sent", __func__); 14847549Sbde} 1491590Srgrimes 15029922Smarkmstatic void 1511590Srgrimesuserauth_banner(void) 1521590Srgrimes{ 1531590Srgrimes char *banner = NULL; 1541590Srgrimes 1551590Srgrimes if (options.banner == NULL || 1561590Srgrimes strcasecmp(options.banner, "none") == 0 || 1571590Srgrimes (datafellows & SSH_BUG_BANNER) != 0) 1581590Srgrimes return; 1591590Srgrimes 1601590Srgrimes if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 1611590Srgrimes goto done; 1621590Srgrimes userauth_send_banner(banner); 1631590Srgrimes 1641590Srgrimesdone: 16557232Sshin if (banner) 1661590Srgrimes xfree(banner); 16757232Sshin} 1681590Srgrimes 16924360Simp/* 1701590Srgrimes * loop until authctxt->success == TRUE 17157232Sshin */ 17257232Sshinvoid 17357232Sshindo_authentication2(Authctxt *authctxt) 17457232Sshin{ 17557232Sshin dispatch_init(&dispatch_protocol_error); 17657232Sshin dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 17757232Sshin dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 17857232Sshin} 1791590Srgrimes 1801590Srgrimes/*ARGSUSED*/ 1811590Srgrimesstatic void 1828232Sdginput_service_request(int type, u_int32_t seq, void *ctxt) 1838232Sdg{ 1848232Sdg Authctxt *authctxt = ctxt; 1851590Srgrimes u_int len; 1861590Srgrimes int acceptit = 0; 1871590Srgrimes char *service = packet_get_string(&len); 1881590Srgrimes packet_check_eom(); 1891590Srgrimes 1901590Srgrimes if (authctxt == NULL) 1911590Srgrimes fatal("input_service_request: no authctxt"); 1921590Srgrimes 1931590Srgrimes if (strcmp(service, "ssh-userauth") == 0) { 1941590Srgrimes if (!authctxt->success) { 1951590Srgrimes acceptit = 1; 1961590Srgrimes /* now we can handle user-auth requests */ 1971590Srgrimes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 1981590Srgrimes } 1991590Srgrimes } 2001590Srgrimes /* XXX all other service requests are denied */ 2011590Srgrimes 2021590Srgrimes if (acceptit) { 20347488Speter packet_start(SSH2_MSG_SERVICE_ACCEPT); 20447549Sbde packet_put_cstring(service); 20547549Sbde packet_send(); 20647488Speter packet_write_wait(); 20747488Speter } else { 2081590Srgrimes debug("bad service request %s", service); 2091590Srgrimes packet_disconnect("bad service request %s", service); 2101590Srgrimes } 2111590Srgrimes xfree(service); 2121590Srgrimes} 2131590Srgrimes 2141590Srgrimes/*ARGSUSED*/ 2151590Srgrimesstatic void 2161590Srgrimesinput_userauth_request(int type, u_int32_t seq, void *ctxt) 2171590Srgrimes{ 2181590Srgrimes Authctxt *authctxt = ctxt; 2191590Srgrimes Authmethod *m = NULL; 2201590Srgrimes char *user, *service, *method, *style = NULL; 2211590Srgrimes int authenticated = 0; 2221590Srgrimes#ifdef HAVE_LOGIN_CAP 2231590Srgrimes login_cap_t *lc; 2241590Srgrimes const char *from_host, *from_ip; 2251590Srgrimes 2261590Srgrimes from_host = get_canonical_hostname(options.use_dns); 2271590Srgrimes from_ip = get_remote_ipaddr(); 2281590Srgrimes#endif 2291590Srgrimes 2301590Srgrimes if (authctxt == NULL) 23134897Smarkm fatal("input_userauth_request: no authctxt"); 2321590Srgrimes 2331590Srgrimes user = packet_get_string(NULL); 23434897Smarkm service = packet_get_string(NULL); 2351590Srgrimes method = packet_get_string(NULL); 2361590Srgrimes debug("userauth-request for user %s service %s method %s", user, service, method); 23727919Scharnier debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 23827919Scharnier 2391590Srgrimes if ((style = strchr(user, ':')) != NULL) 2401590Srgrimes *style++ = 0; 24147488Speter 24247488Speter if (authctxt->attempt++ == 0) { 2431590Srgrimes /* setup auth context */ 2441590Srgrimes authctxt->pw = PRIVSEP(getpwnamallow(user)); 2451590Srgrimes authctxt->user = xstrdup(user); 24640103Smarkm if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 24740103Smarkm authctxt->valid = 1; 24840103Smarkm debug2("input_userauth_request: setting up authctxt for %s", user); 2491590Srgrimes } else { 2501590Srgrimes logit("input_userauth_request: invalid user %s", user); 2511590Srgrimes authctxt->pw = fakepw(); 2521590Srgrimes#ifdef SSH_AUDIT_EVENTS 25329922Smarkm PRIVSEP(audit_event(SSH_INVALID_USER)); 2541590Srgrimes#endif 2551590Srgrimes } 2561590Srgrimes#ifdef USE_PAM 2571590Srgrimes if (options.use_pam) 2581590Srgrimes PRIVSEP(start_pam(authctxt)); 2591590Srgrimes#endif 26027919Scharnier setproctitle("%s%s", authctxt->valid ? user : "unknown", 26127919Scharnier use_privsep ? " [net]" : ""); 2621590Srgrimes authctxt->service = xstrdup(service); 26317284Spst authctxt->style = style ? xstrdup(style) : NULL; 26417284Spst if (use_privsep) 26517284Spst mm_inform_authserv(service, style); 26617284Spst userauth_banner(); 26717284Spst } else if (strcmp(user, authctxt->user) != 0 || 2681590Srgrimes strcmp(service, authctxt->service) != 0) { 2691590Srgrimes packet_disconnect("Change of username or service not allowed: " 2701590Srgrimes "(%s,%s) -> (%s,%s)", 2711590Srgrimes authctxt->user, authctxt->service, user, service); 2721590Srgrimes } 2731590Srgrimes 2741590Srgrimes#ifdef HAVE_LOGIN_CAP 2751590Srgrimes if (authctxt->pw != NULL) { 2761590Srgrimes lc = login_getpwclass(authctxt->pw); 2771590Srgrimes if (lc == NULL) 2781590Srgrimes lc = login_getclassbyname(NULL, authctxt->pw); 2791590Srgrimes if (!auth_hostok(lc, from_host, from_ip)) { 2801590Srgrimes logit("Denied connection for %.200s from %.200s [%.200s].", 2811590Srgrimes authctxt->pw->pw_name, from_host, from_ip); 2821590Srgrimes packet_disconnect("Sorry, you are not allowed to connect."); 2831590Srgrimes } 2841590Srgrimes if (!auth_timeok(lc, time(NULL))) { 2851590Srgrimes logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 2861590Srgrimes authctxt->pw->pw_name, from_host); 2871590Srgrimes packet_disconnect("Logins not available right now."); 2881590Srgrimes } 28934897Smarkm login_close(lc); 2901590Srgrimes lc = NULL; 2911590Srgrimes } 2921590Srgrimes#endif /* HAVE_LOGIN_CAP */ 2931590Srgrimes 2941590Srgrimes /* reset state */ 2951590Srgrimes auth2_challenge_stop(authctxt); 2963113Sdfr#ifdef JPAKE 2971590Srgrimes auth2_jpake_stop(authctxt); 2981590Srgrimes#endif 29929922Smarkm 3003113Sdfr#ifdef GSSAPI 3011590Srgrimes /* XXX move to auth2_gssapi_stop() */ 3021590Srgrimes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3031590Srgrimes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 3041590Srgrimes#endif 30534897Smarkm 30634897Smarkm authctxt->postponed = 0; 30734897Smarkm 3081590Srgrimes /* try to authenticate user */ 30927919Scharnier m = authmethod_lookup(method); 31027919Scharnier if (m != NULL && authctxt->failures < options.max_authtries) { 3111590Srgrimes debug2("input_userauth_request: try method %s", method); 31229922Smarkm authenticated = m->userauth(authctxt); 3131590Srgrimes } 31429922Smarkm userauth_finish(authctxt, authenticated, method); 31534897Smarkm 31634897Smarkm xfree(service); 31734897Smarkm xfree(user); 31834897Smarkm xfree(method); 31934897Smarkm} 32034897Smarkm 32134897Smarkmvoid 32234897Smarkmuserauth_finish(Authctxt *authctxt, int authenticated, char *method) 32334897Smarkm{ 3241590Srgrimes char *methods; 3251590Srgrimes 3261590Srgrimes if (!authctxt->valid && authenticated) 32727919Scharnier fatal("INTERNAL ERROR: authenticated invalid user %s", 32827919Scharnier authctxt->user); 3291590Srgrimes 33056590Sshin /* Special handling for root */ 33157232Sshin if (authenticated && authctxt->pw->pw_uid == 0 && 3321590Srgrimes !auth_root_allowed(method)) { 3331590Srgrimes authenticated = 0; 33457232Sshin#ifdef SSH_AUDIT_EVENTS 3351590Srgrimes PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 3361590Srgrimes#endif 3371590Srgrimes } 3381590Srgrimes 3391590Srgrimes#ifdef USE_PAM 3401590Srgrimes if (options.use_pam && authenticated) { 3411590Srgrimes if (!PRIVSEP(do_pam_account())) { 34227919Scharnier /* if PAM returned a message, send it to the user */ 3438232Sdg if (buffer_len(&loginmsg) > 0) { 3448232Sdg buffer_append(&loginmsg, "\0", 1); 34527919Scharnier userauth_send_banner(buffer_ptr(&loginmsg)); 3468232Sdg packet_write_wait(); 34756590Sshin } 3481590Srgrimes fatal("Access denied for user %s by PAM account " 34956590Sshin "configuration", authctxt->user); 35056590Sshin } 35156590Sshin } 35256590Sshin#endif 35356590Sshin 35456590Sshin#ifdef _UNICOS 35556590Sshin if (authenticated && cray_access_denied(authctxt->user)) { 35656590Sshin authenticated = 0; 3571590Srgrimes fatal("Access denied for user %s.",authctxt->user); 3581590Srgrimes } 3591590Srgrimes#endif /* _UNICOS */ 3601590Srgrimes 3611590Srgrimes /* Log before sending the reply */ 3621590Srgrimes auth_log(authctxt, authenticated, method, " ssh2"); 3631590Srgrimes 3641590Srgrimes if (authctxt->postponed) 3651590Srgrimes return; 3661590Srgrimes 3671590Srgrimes /* XXX todo: check if multiple auth methods are needed */ 3681590Srgrimes if (authenticated == 1) { 3691590Srgrimes /* turn off userauth */ 3701590Srgrimes dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 37193057Simp packet_start(SSH2_MSG_USERAUTH_SUCCESS); 3721590Srgrimes packet_send(); 3731590Srgrimes packet_write_wait(); 3741590Srgrimes /* now we can break out */ 3751590Srgrimes authctxt->success = 1; 3761590Srgrimes } else { 3771590Srgrimes 3781590Srgrimes /* Allow initial try of "none" auth without failure penalty */ 3791590Srgrimes if (authctxt->attempt > 1 || strcmp(method, "none") != 0) 3801590Srgrimes authctxt->failures++; 3811590Srgrimes if (authctxt->failures >= options.max_authtries) { 3821590Srgrimes#ifdef SSH_AUDIT_EVENTS 3831590Srgrimes PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 3841590Srgrimes#endif 3851590Srgrimes packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 3861590Srgrimes } 3871590Srgrimes methods = authmethods_get(); 3881590Srgrimes packet_start(SSH2_MSG_USERAUTH_FAILURE); 3891590Srgrimes packet_put_cstring(methods); 3901590Srgrimes packet_put_char(0); /* XXX partial success, unused */ 39127919Scharnier packet_send(); 3921590Srgrimes packet_write_wait(); 3931590Srgrimes xfree(methods); 3941590Srgrimes } 3951590Srgrimes} 3961590Srgrimes 3971590Srgrimesstatic char * 3981590Srgrimesauthmethods_get(void) 3991590Srgrimes{ 4001590Srgrimes Buffer b; 4011590Srgrimes char *list; 4021590Srgrimes int i; 4031590Srgrimes 4041590Srgrimes buffer_init(&b); 4051590Srgrimes for (i = 0; authmethods[i] != NULL; i++) { 4061590Srgrimes if (strcmp(authmethods[i]->name, "none") == 0) 4071590Srgrimes continue; 4081590Srgrimes if (authmethods[i]->enabled != NULL && 4091590Srgrimes *(authmethods[i]->enabled) != 0) { 4101590Srgrimes if (buffer_len(&b) > 0) 4111590Srgrimes buffer_append(&b, ",", 1); 4121590Srgrimes buffer_append(&b, authmethods[i]->name, 4131590Srgrimes strlen(authmethods[i]->name)); 4141590Srgrimes } 4151590Srgrimes } 4161590Srgrimes buffer_append(&b, "\0", 1); 4171590Srgrimes list = xstrdup(buffer_ptr(&b)); 4181590Srgrimes buffer_free(&b); 4191590Srgrimes return list; 4201590Srgrimes} 42193057Simp 4221590Srgrimesstatic Authmethod * 4231590Srgrimesauthmethod_lookup(const char *name) 4241590Srgrimes{ 4251590Srgrimes int i; 4261590Srgrimes 4271590Srgrimes if (name != NULL) 4281590Srgrimes for (i = 0; authmethods[i] != NULL; i++) 4291590Srgrimes if (authmethods[i]->enabled != NULL && 43018286Sbde *(authmethods[i]->enabled) != 0 && 43193057Simp strcmp(name, authmethods[i]->name) == 0) 4321590Srgrimes return authmethods[i]; 4331590Srgrimes debug2("Unrecognized authentication method name: %s", 4341590Srgrimes name ? name : "NULL"); 4351590Srgrimes return NULL; 4361590Srgrimes} 4371590Srgrimes 4381590Srgrimes