auth2.c revision 68704
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" 2665674SkrisRCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $"); 2765674SkrisRCSID("$FreeBSD: head/crypto/openssh/auth2.c 68704 2000-11-14 04:35:03Z green $"); 2860573Skris 2960573Skris#include <openssl/dsa.h> 3060573Skris#include <openssl/rsa.h> 3160573Skris#include <openssl/evp.h> 3260573Skris 3360573Skris#include "xmalloc.h" 3460573Skris#include "rsa.h" 3560573Skris#include "ssh.h" 3660573Skris#include "pty.h" 3760573Skris#include "packet.h" 3860573Skris#include "buffer.h" 3960573Skris#include "cipher.h" 4060573Skris#include "servconf.h" 4160573Skris#include "compat.h" 4260573Skris#include "channels.h" 4360573Skris#include "bufaux.h" 4460573Skris#include "ssh2.h" 4560573Skris#include "auth.h" 4660573Skris#include "session.h" 4760573Skris#include "dispatch.h" 4860573Skris#include "auth.h" 4960573Skris#include "key.h" 5060573Skris#include "kex.h" 5160573Skris 5260573Skris#include "dsa.h" 5360573Skris#include "uidswap.h" 5465674Skris#include "auth-options.h" 5560573Skris 5668704Sgreen#ifdef HAVE_LOGIN_CAP 5768704Sgreen#include <login_cap.h> 5868704Sgreen#endif /* HAVE_LOGIN_CAP */ 5968704Sgreen 6060573Skris/* import */ 6160573Skrisextern ServerOptions options; 6260573Skrisextern unsigned char *session_id2; 6360573Skrisextern int session_id2_len; 6460573Skris 6560573Skris/* protocol */ 6660573Skris 6760573Skrisvoid input_service_request(int type, int plen); 6860573Skrisvoid input_userauth_request(int type, int plen); 6960573Skrisvoid protocol_error(int type, int plen); 7060573Skris 7160573Skris/* auth */ 7260573Skrisint ssh2_auth_none(struct passwd *pw); 7360573Skrisint ssh2_auth_password(struct passwd *pw); 7465674Skrisint ssh2_auth_pubkey(struct passwd *pw, char *service); 7560573Skris 7660573Skris/* helper */ 7760573Skrisstruct passwd* auth_set_user(char *u, char *s); 7860573Skrisint user_dsa_key_allowed(struct passwd *pw, Key *key); 7960573Skris 8060573Skristypedef struct Authctxt Authctxt; 8160573Skrisstruct Authctxt { 8260573Skris char *user; 8360573Skris char *service; 8460573Skris struct passwd pw; 8560573Skris int valid; 8660573Skris}; 8760573Skrisstatic Authctxt *authctxt = NULL; 8860573Skrisstatic int userauth_success = 0; 8960573Skris 9060573Skris/* 9160573Skris * loop until userauth_success == TRUE 9260573Skris */ 9360573Skris 9460573Skrisvoid 9560573Skrisdo_authentication2() 9660573Skris{ 9760573Skris /* turn off skey/kerberos, not supported by SSH2 */ 9860573Skris#ifdef SKEY 9960573Skris options.skey_authentication = 0; 10060573Skris#endif 10160573Skris#ifdef KRB4 10260576Skris options.krb4_authentication = 0; 10360573Skris#endif 10460573Skris 10560573Skris dispatch_init(&protocol_error); 10660573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 10760573Skris dispatch_run(DISPATCH_BLOCK, &userauth_success); 10860573Skris do_authenticated2(); 10960573Skris} 11060573Skris 11160573Skrisvoid 11260573Skrisprotocol_error(int type, int plen) 11360573Skris{ 11460573Skris log("auth: protocol error: type %d plen %d", type, plen); 11560573Skris packet_start(SSH2_MSG_UNIMPLEMENTED); 11660573Skris packet_put_int(0); 11760573Skris packet_send(); 11860573Skris packet_write_wait(); 11960573Skris} 12060573Skris 12160573Skrisvoid 12260573Skrisinput_service_request(int type, int plen) 12360573Skris{ 12460573Skris unsigned int len; 12560573Skris int accept = 0; 12660573Skris char *service = packet_get_string(&len); 12760573Skris packet_done(); 12860573Skris 12960573Skris if (strcmp(service, "ssh-userauth") == 0) { 13060573Skris if (!userauth_success) { 13160573Skris accept = 1; 13260573Skris /* now we can handle user-auth requests */ 13360573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 13460573Skris } 13560573Skris } 13660573Skris /* XXX all other service requests are denied */ 13760573Skris 13860573Skris if (accept) { 13960573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 14060573Skris packet_put_cstring(service); 14160573Skris packet_send(); 14260573Skris packet_write_wait(); 14360573Skris } else { 14460573Skris debug("bad service request %s", service); 14560573Skris packet_disconnect("bad service request %s", service); 14660573Skris } 14760573Skris xfree(service); 14860573Skris} 14960573Skris 15060573Skrisvoid 15160573Skrisinput_userauth_request(int type, int plen) 15260573Skris{ 15360573Skris static void (*authlog) (const char *fmt,...) = verbose; 15460573Skris static int attempt = 0; 15565674Skris unsigned int len; 15660573Skris int authenticated = 0; 15765674Skris char *user, *service, *method, *authmsg = NULL; 15860573Skris struct passwd *pw; 15968704Sgreen#ifdef HAVE_LOGIN_CAP 16068704Sgreen login_cap_t *lc; 16168704Sgreen#endif /* HAVE_LOGIN_CAP */ 16268704Sgreen#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) 16368704Sgreen const char *from_host, *from_ip; 16460573Skris 16568704Sgreen from_host = get_canonical_hostname(); 16668704Sgreen from_ip = get_remote_ipaddr(); 16768704Sgreen#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ 16868704Sgreen 16960573Skris if (++attempt == AUTH_FAIL_MAX) 17060573Skris packet_disconnect("too many failed userauth_requests"); 17160573Skris 17260573Skris user = packet_get_string(&len); 17360573Skris service = packet_get_string(&len); 17460573Skris method = packet_get_string(&len); 17560573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 17660573Skris 17760573Skris /* XXX we only allow the ssh-connection service */ 17860573Skris pw = auth_set_user(user, service); 17960573Skris if (pw && strcmp(service, "ssh-connection")==0) { 18060573Skris if (strcmp(method, "none") == 0) { 18160573Skris authenticated = ssh2_auth_none(pw); 18260573Skris } else if (strcmp(method, "password") == 0) { 18360573Skris authenticated = ssh2_auth_password(pw); 18460573Skris } else if (strcmp(method, "publickey") == 0) { 18565674Skris authenticated = ssh2_auth_pubkey(pw, service); 18660573Skris } 18760573Skris } 18860573Skris if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { 18960573Skris authenticated = 0; 19060573Skris log("ROOT LOGIN REFUSED FROM %.200s", 19160573Skris get_canonical_hostname()); 19260573Skris } 19360573Skris 19468704Sgreen#ifdef HAVE_LOGIN_CAP 19568704Sgreen lc = login_getpwclass(pw); 19668704Sgreen if (lc == NULL) 19768704Sgreen lc = login_getclassbyname(NULL, pw); 19868704Sgreen if (!auth_hostok(lc, from_host, from_ip)) { 19968704Sgreen log("Denied connection for %.200s from %.200s [%.200s].", 20068704Sgreen pw->pw_name, from_host, from_ip); 20168704Sgreen packet_disconnect("Sorry, you are not allowed to connect."); 20268704Sgreen } 20368704Sgreen if (!auth_timeok(lc, time(NULL))) { 20468704Sgreen log("LOGIN %.200s REFUSED (TIME) FROM %.200s", 20568704Sgreen pw->pw_name, from_host); 20668704Sgreen packet_disconnect("Logins not available right now."); 20768704Sgreen } 20868704Sgreen login_close(lc); 20968704Sgreen#endif /* HAVE_LOGIN_CAP */ 21068704Sgreen#ifdef LOGIN_ACCESS 21168704Sgreen if (!login_access(pw->pw_name, from_host)) { 21268704Sgreen log("Denied connection for %.200s from %.200s [%.200s].", 21368704Sgreen pw->pw_name, from_host, from_ip); 21468704Sgreen packet_disconnect("Sorry, you are not allowed to connect."); 21568704Sgreen } 21668704Sgreen#endif /* LOGIN_ACCESS */ 21768704Sgreen 21860573Skris /* Raise logging level */ 21960573Skris if (authenticated == 1 || 22060573Skris attempt == AUTH_FAIL_LOG || 22160573Skris strcmp(method, "password") == 0) 22260573Skris authlog = log; 22360573Skris 22460573Skris /* Log before sending the reply */ 22560573Skris if (authenticated == 1) { 22660573Skris authmsg = "Accepted"; 22760573Skris } else if (authenticated == 0) { 22860573Skris authmsg = "Failed"; 22960573Skris } else { 23060573Skris authmsg = "Postponed"; 23160573Skris } 23260573Skris authlog("%s %s for %.200s from %.200s port %d ssh2", 23360573Skris authmsg, 23460573Skris method, 23560573Skris pw && pw->pw_uid == 0 ? "ROOT" : user, 23660573Skris get_remote_ipaddr(), 23760573Skris get_remote_port()); 23860573Skris 23960573Skris /* XXX todo: check if multiple auth methods are needed */ 24060573Skris if (authenticated == 1) { 24160573Skris /* turn off userauth */ 24260573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); 24360573Skris packet_start(SSH2_MSG_USERAUTH_SUCCESS); 24460573Skris packet_send(); 24560573Skris packet_write_wait(); 24660573Skris /* now we can break out */ 24760573Skris userauth_success = 1; 24860573Skris } else if (authenticated == 0) { 24960573Skris packet_start(SSH2_MSG_USERAUTH_FAILURE); 25060573Skris packet_put_cstring("publickey,password"); /* XXX dynamic */ 25160573Skris packet_put_char(0); /* XXX partial success, unused */ 25260573Skris packet_send(); 25360573Skris packet_write_wait(); 25460573Skris } 25560573Skris 25660573Skris xfree(service); 25760573Skris xfree(user); 25860573Skris xfree(method); 25960573Skris} 26060573Skris 26160573Skrisint 26260573Skrisssh2_auth_none(struct passwd *pw) 26360573Skris{ 26460573Skris packet_done(); 26560573Skris return auth_password(pw, ""); 26660573Skris} 26760573Skrisint 26860573Skrisssh2_auth_password(struct passwd *pw) 26960573Skris{ 27060573Skris char *password; 27160573Skris int authenticated = 0; 27260573Skris int change; 27360573Skris unsigned int len; 27460573Skris change = packet_get_char(); 27560573Skris if (change) 27660573Skris log("password change not supported"); 27760573Skris password = packet_get_string(&len); 27860573Skris packet_done(); 27960573Skris if (options.password_authentication && 28060573Skris auth_password(pw, password) == 1) 28160573Skris authenticated = 1; 28260573Skris memset(password, 0, len); 28360573Skris xfree(password); 28460573Skris return authenticated; 28560573Skris} 28660573Skrisint 28765674Skrisssh2_auth_pubkey(struct passwd *pw, char *service) 28860573Skris{ 28960573Skris Buffer b; 29060573Skris Key *key; 29160573Skris char *pkalg, *pkblob, *sig; 29260573Skris unsigned int alen, blen, slen; 29360573Skris int have_sig; 29460573Skris int authenticated = 0; 29560573Skris 29660573Skris if (options.dsa_authentication == 0) { 29760573Skris debug("pubkey auth disabled"); 29860573Skris return 0; 29960573Skris } 30060573Skris have_sig = packet_get_char(); 30160573Skris pkalg = packet_get_string(&alen); 30260573Skris if (strcmp(pkalg, KEX_DSS) != 0) { 30360573Skris xfree(pkalg); 30460573Skris log("bad pkalg %s", pkalg); /*XXX*/ 30560573Skris return 0; 30660573Skris } 30760573Skris pkblob = packet_get_string(&blen); 30860573Skris key = dsa_key_from_blob(pkblob, blen); 30960573Skris if (key != NULL) { 31060573Skris if (have_sig) { 31160573Skris sig = packet_get_string(&slen); 31260573Skris packet_done(); 31360573Skris buffer_init(&b); 31465674Skris if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) { 31565674Skris buffer_put_string(&b, session_id2, session_id2_len); 31665674Skris } else { 31765674Skris buffer_append(&b, session_id2, session_id2_len); 31865674Skris } 31965674Skris /* reconstruct packet */ 32060573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 32165674Skris buffer_put_cstring(&b, pw->pw_name); 32265674Skris buffer_put_cstring(&b, 32365674Skris datafellows & SSH_BUG_PUBKEYAUTH ? 32465674Skris "ssh-userauth" : 32565674Skris service); 32665674Skris buffer_put_cstring(&b, "publickey"); 32765674Skris buffer_put_char(&b, have_sig); 32865674Skris buffer_put_cstring(&b, KEX_DSS); 32965674Skris buffer_put_string(&b, pkblob, blen); 33060573Skris#ifdef DEBUG_DSS 33160573Skris buffer_dump(&b); 33260573Skris#endif 33360573Skris /* test for correct signature */ 33460573Skris if (user_dsa_key_allowed(pw, key) && 33560573Skris dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 33660573Skris authenticated = 1; 33760573Skris buffer_clear(&b); 33860573Skris xfree(sig); 33960573Skris } else { 34060573Skris packet_done(); 34160573Skris debug("test key..."); 34260573Skris /* test whether pkalg/pkblob are acceptable */ 34360573Skris /* XXX fake reply and always send PK_OK ? */ 34460573Skris /* 34560573Skris * XXX this allows testing whether a user is allowed 34660573Skris * to login: if you happen to have a valid pubkey this 34760573Skris * message is sent. the message is NEVER sent at all 34860573Skris * if a user is not allowed to login. is this an 34960573Skris * issue? -markus 35060573Skris */ 35160573Skris if (user_dsa_key_allowed(pw, key)) { 35260573Skris packet_start(SSH2_MSG_USERAUTH_PK_OK); 35360573Skris packet_put_string(pkalg, alen); 35460573Skris packet_put_string(pkblob, blen); 35560573Skris packet_send(); 35660573Skris packet_write_wait(); 35760573Skris authenticated = -1; 35860573Skris } 35960573Skris } 36060573Skris key_free(key); 36160573Skris } 36260573Skris xfree(pkalg); 36360573Skris xfree(pkblob); 36460573Skris return authenticated; 36560573Skris} 36660573Skris 36760573Skris/* set and get current user */ 36860573Skris 36960573Skrisstruct passwd* 37060573Skrisauth_get_user(void) 37160573Skris{ 37260573Skris return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; 37360573Skris} 37460573Skris 37560573Skrisstruct passwd* 37660573Skrisauth_set_user(char *u, char *s) 37760573Skris{ 37860573Skris struct passwd *pw, *copy; 37960573Skris 38060573Skris if (authctxt == NULL) { 38160573Skris authctxt = xmalloc(sizeof(*authctxt)); 38260573Skris authctxt->valid = 0; 38360573Skris authctxt->user = xstrdup(u); 38460573Skris authctxt->service = xstrdup(s); 38560573Skris setproctitle("%s", u); 38660573Skris pw = getpwnam(u); 38760573Skris if (!pw || !allowed_user(pw)) { 38860573Skris log("auth_set_user: illegal user %s", u); 38960573Skris return NULL; 39060573Skris } 39160573Skris copy = &authctxt->pw; 39260573Skris memset(copy, 0, sizeof(*copy)); 39360573Skris copy->pw_name = xstrdup(pw->pw_name); 39460573Skris copy->pw_passwd = xstrdup(pw->pw_passwd); 39560573Skris copy->pw_uid = pw->pw_uid; 39660573Skris copy->pw_gid = pw->pw_gid; 39765674Skris copy->pw_class = xstrdup(pw->pw_class); 39860573Skris copy->pw_dir = xstrdup(pw->pw_dir); 39960573Skris copy->pw_shell = xstrdup(pw->pw_shell); 40062179Sgreen copy->pw_class = xstrdup(pw->pw_class); 40162179Sgreen copy->pw_expire = pw->pw_expire; 40262179Sgreen copy->pw_change = pw->pw_change; 40360573Skris authctxt->valid = 1; 40460573Skris } else { 40560573Skris if (strcmp(u, authctxt->user) != 0 || 40660573Skris strcmp(s, authctxt->service) != 0) { 40760573Skris log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)", 40860573Skris u, s, authctxt->user, authctxt->service); 40960573Skris return NULL; 41060573Skris } 41160573Skris } 41260573Skris return auth_get_user(); 41360573Skris} 41460573Skris 41560573Skris/* return 1 if user allows given key */ 41660573Skrisint 41760573Skrisuser_dsa_key_allowed(struct passwd *pw, Key *key) 41860573Skris{ 41960573Skris char line[8192], file[1024]; 42060573Skris int found_key = 0; 42160573Skris unsigned int bits = -1; 42260573Skris FILE *f; 42360573Skris unsigned long linenum = 0; 42460573Skris struct stat st; 42560573Skris Key *found; 42660573Skris 42760573Skris /* Temporarily use the user's uid. */ 42860573Skris temporarily_use_uid(pw->pw_uid); 42960573Skris 43060573Skris /* The authorized keys. */ 43160573Skris snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 43260573Skris SSH_USER_PERMITTED_KEYS2); 43360573Skris 43460573Skris /* Fail quietly if file does not exist */ 43560573Skris if (stat(file, &st) < 0) { 43660573Skris /* Restore the privileged uid. */ 43760573Skris restore_uid(); 43860573Skris return 0; 43960573Skris } 44060573Skris /* Open the file containing the authorized keys. */ 44160573Skris f = fopen(file, "r"); 44260573Skris if (!f) { 44360573Skris /* Restore the privileged uid. */ 44460573Skris restore_uid(); 44560573Skris return 0; 44660573Skris } 44760573Skris if (options.strict_modes) { 44860573Skris int fail = 0; 44960573Skris char buf[1024]; 45060573Skris /* Check open file in order to avoid open/stat races */ 45160573Skris if (fstat(fileno(f), &st) < 0 || 45260573Skris (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 45360573Skris (st.st_mode & 022) != 0) { 45460573Skris snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: " 45560573Skris "bad ownership or modes for '%s'.", pw->pw_name, file); 45660573Skris fail = 1; 45760573Skris } else { 45860573Skris /* Check path to SSH_USER_PERMITTED_KEYS */ 45960573Skris int i; 46060573Skris static const char *check[] = { 46160573Skris "", SSH_USER_DIR, NULL 46260573Skris }; 46360573Skris for (i = 0; check[i]; i++) { 46460573Skris snprintf(line, sizeof line, "%.500s/%.100s", 46560573Skris pw->pw_dir, check[i]); 46660573Skris if (stat(line, &st) < 0 || 46760573Skris (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 46860573Skris (st.st_mode & 022) != 0) { 46960573Skris snprintf(buf, sizeof buf, 47060573Skris "DSA authentication refused for %.100s: " 47160573Skris "bad ownership or modes for '%s'.", 47260573Skris pw->pw_name, line); 47360573Skris fail = 1; 47460573Skris break; 47560573Skris } 47660573Skris } 47760573Skris } 47860573Skris if (fail) { 47960573Skris fclose(f); 48065674Skris log("%s",buf); 48160573Skris restore_uid(); 48260573Skris return 0; 48360573Skris } 48460573Skris } 48560573Skris found_key = 0; 48660573Skris found = key_new(KEY_DSA); 48760573Skris 48860573Skris while (fgets(line, sizeof(line), f)) { 48965674Skris char *cp, *options = NULL; 49060573Skris linenum++; 49160573Skris /* Skip leading whitespace, empty and comment lines. */ 49260573Skris for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 49360573Skris ; 49460573Skris if (!*cp || *cp == '\n' || *cp == '#') 49560573Skris continue; 49665674Skris 49760573Skris bits = key_read(found, &cp); 49865674Skris if (bits == 0) { 49965674Skris /* no key? check if there are options for this key */ 50065674Skris int quoted = 0; 50165674Skris options = cp; 50265674Skris for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 50365674Skris if (*cp == '\\' && cp[1] == '"') 50465674Skris cp++; /* Skip both */ 50565674Skris else if (*cp == '"') 50665674Skris quoted = !quoted; 50765674Skris } 50865674Skris /* Skip remaining whitespace. */ 50965674Skris for (; *cp == ' ' || *cp == '\t'; cp++) 51065674Skris ; 51165674Skris bits = key_read(found, &cp); 51265674Skris if (bits == 0) { 51365674Skris /* still no key? advance to next line*/ 51465674Skris continue; 51565674Skris } 51665674Skris } 51765674Skris if (key_equal(found, key) && 51865674Skris auth_parse_options(pw, options, linenum) == 1) { 51960573Skris found_key = 1; 52060573Skris debug("matching key found: file %s, line %ld", 52160573Skris file, linenum); 52260573Skris break; 52360573Skris } 52460573Skris } 52560573Skris restore_uid(); 52660573Skris fclose(f); 52760573Skris key_free(found); 52860573Skris return found_key; 52960573Skris} 530