auth2.c revision 69591
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" 2669591SgreenRCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); 2765674SkrisRCSID("$FreeBSD: head/crypto/openssh/auth2.c 69591 2000-12-05 02:55:12Z 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 "servconf.h" 4060573Skris#include "compat.h" 4160573Skris#include "channels.h" 4260573Skris#include "bufaux.h" 4360573Skris#include "ssh2.h" 4460573Skris#include "auth.h" 4560573Skris#include "session.h" 4660573Skris#include "dispatch.h" 4760573Skris#include "auth.h" 4860573Skris#include "key.h" 4960573Skris#include "kex.h" 5060573Skris 5160573Skris#include "dsa.h" 5260573Skris#include "uidswap.h" 5365674Skris#include "auth-options.h" 5460573Skris 5568704Sgreen#ifdef HAVE_LOGIN_CAP 5668704Sgreen#include <login_cap.h> 5768704Sgreen#endif /* HAVE_LOGIN_CAP */ 5868704Sgreen 5960573Skris/* import */ 6060573Skrisextern ServerOptions options; 6160573Skrisextern unsigned char *session_id2; 6260573Skrisextern int session_id2_len; 6360573Skris 6469591Sgreenstatic Authctxt *x_authctxt = NULL; 6569591Sgreenstatic int one = 1; 6669591Sgreen 6769591Sgreentypedef struct Authmethod Authmethod; 6869591Sgreenstruct Authmethod { 6969591Sgreen char *name; 7069591Sgreen int (*userauth)(Authctxt *authctxt); 7169591Sgreen int *enabled; 7269591Sgreen}; 7369591Sgreen 7460573Skris/* protocol */ 7560573Skris 7669591Sgreenvoid input_service_request(int type, int plen, void *ctxt); 7769591Sgreenvoid input_userauth_request(int type, int plen, void *ctxt); 7869591Sgreenvoid protocol_error(int type, int plen, void *ctxt); 7960573Skris 8060573Skris 8160573Skris/* helper */ 8269591SgreenAuthmethod *authmethod_lookup(const char *name); 8369591Sgreenstruct passwd *pwcopy(struct passwd *pw); 8460573Skrisint user_dsa_key_allowed(struct passwd *pw, Key *key); 8569591Sgreenchar *authmethods_get(void); 8660573Skris 8769591Sgreen/* auth */ 8869591Sgreenint userauth_none(Authctxt *authctxt); 8969591Sgreenint userauth_passwd(Authctxt *authctxt); 9069591Sgreenint userauth_pubkey(Authctxt *authctxt); 9169591Sgreenint userauth_kbdint(Authctxt *authctxt); 9269591Sgreen 9369591SgreenAuthmethod authmethods[] = { 9469591Sgreen {"none", 9569591Sgreen userauth_none, 9669591Sgreen &one}, 9769591Sgreen {"publickey", 9869591Sgreen userauth_pubkey, 9969591Sgreen &options.dsa_authentication}, 10069591Sgreen {"keyboard-interactive", 10169591Sgreen userauth_kbdint, 10269591Sgreen &options.kbd_interactive_authentication}, 10369591Sgreen {"password", 10469591Sgreen userauth_passwd, 10569591Sgreen &options.password_authentication}, 10669591Sgreen {NULL, NULL, NULL} 10760573Skris}; 10860573Skris 10960573Skris/* 11069591Sgreen * loop until authctxt->success == TRUE 11160573Skris */ 11260573Skris 11360573Skrisvoid 11460573Skrisdo_authentication2() 11560573Skris{ 11669591Sgreen Authctxt *authctxt = xmalloc(sizeof(*authctxt)); 11769591Sgreen memset(authctxt, 'a', sizeof(*authctxt)); 11869591Sgreen authctxt->valid = 0; 11969591Sgreen authctxt->attempt = 0; 12069591Sgreen authctxt->success = 0; 12169591Sgreen x_authctxt = authctxt; /*XXX*/ 12269591Sgreen 12360573Skris#ifdef KRB4 12469591Sgreen /* turn off kerberos, not supported by SSH2 */ 12560576Skris options.krb4_authentication = 0; 12660573Skris#endif 12760573Skris dispatch_init(&protocol_error); 12860573Skris dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 12969591Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 13060573Skris do_authenticated2(); 13160573Skris} 13260573Skris 13360573Skrisvoid 13469591Sgreenprotocol_error(int type, int plen, void *ctxt) 13560573Skris{ 13660573Skris log("auth: protocol error: type %d plen %d", type, plen); 13760573Skris packet_start(SSH2_MSG_UNIMPLEMENTED); 13860573Skris packet_put_int(0); 13960573Skris packet_send(); 14060573Skris packet_write_wait(); 14160573Skris} 14260573Skris 14360573Skrisvoid 14469591Sgreeninput_service_request(int type, int plen, void *ctxt) 14560573Skris{ 14669591Sgreen Authctxt *authctxt = ctxt; 14760573Skris unsigned int len; 14860573Skris int accept = 0; 14960573Skris char *service = packet_get_string(&len); 15060573Skris packet_done(); 15160573Skris 15269591Sgreen if (authctxt == NULL) 15369591Sgreen fatal("input_service_request: no authctxt"); 15469591Sgreen 15560573Skris if (strcmp(service, "ssh-userauth") == 0) { 15669591Sgreen if (!authctxt->success) { 15760573Skris accept = 1; 15860573Skris /* now we can handle user-auth requests */ 15960573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 16060573Skris } 16160573Skris } 16260573Skris /* XXX all other service requests are denied */ 16360573Skris 16460573Skris if (accept) { 16560573Skris packet_start(SSH2_MSG_SERVICE_ACCEPT); 16660573Skris packet_put_cstring(service); 16760573Skris packet_send(); 16860573Skris packet_write_wait(); 16960573Skris } else { 17060573Skris debug("bad service request %s", service); 17160573Skris packet_disconnect("bad service request %s", service); 17260573Skris } 17360573Skris xfree(service); 17460573Skris} 17560573Skris 17660573Skrisvoid 17769591Sgreeninput_userauth_request(int type, int plen, void *ctxt) 17860573Skris{ 17969591Sgreen Authctxt *authctxt = ctxt; 18069591Sgreen Authmethod *m = NULL; 18160573Skris int authenticated = 0; 18265674Skris char *user, *service, *method, *authmsg = NULL; 18368704Sgreen#ifdef HAVE_LOGIN_CAP 18468704Sgreen login_cap_t *lc; 18568704Sgreen#endif /* HAVE_LOGIN_CAP */ 18668704Sgreen#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) 18768704Sgreen const char *from_host, *from_ip; 18860573Skris 18968704Sgreen from_host = get_canonical_hostname(); 19068704Sgreen from_ip = get_remote_ipaddr(); 19168704Sgreen#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ 19268704Sgreen 19369591Sgreen if (authctxt == NULL) 19469591Sgreen fatal("input_userauth_request: no authctxt"); 19569591Sgreen if (authctxt->attempt++ >= AUTH_FAIL_MAX) 19660573Skris packet_disconnect("too many failed userauth_requests"); 19760573Skris 19869591Sgreen user = packet_get_string(NULL); 19969591Sgreen service = packet_get_string(NULL); 20069591Sgreen method = packet_get_string(NULL); 20160573Skris debug("userauth-request for user %s service %s method %s", user, service, method); 20269591Sgreen debug("attempt #%d", authctxt->attempt); 20360573Skris 20469591Sgreen if (authctxt->attempt == 1) { 20569591Sgreen /* setup auth context */ 20669591Sgreen struct passwd *pw = NULL; 20769591Sgreen setproctitle("%s", user); 20869591Sgreen pw = getpwnam(user); 20969591Sgreen if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { 21069591Sgreen authctxt->pw = pwcopy(pw); 21169591Sgreen authctxt->valid = 1; 21269591Sgreen debug2("input_userauth_request: setting up authctxt for %s", user); 21369591Sgreen#ifdef USE_PAM 21469591Sgreen start_pam(pw); 21569591Sgreen#endif 21669591Sgreen } else { 21769591Sgreen log("input_userauth_request: illegal user %s", user); 21860573Skris } 21969591Sgreen authctxt->user = xstrdup(user); 22069591Sgreen authctxt->service = xstrdup(service); 22169591Sgreen } else if (authctxt->valid) { 22269591Sgreen if (strcmp(user, authctxt->user) != 0 || 22369591Sgreen strcmp(service, authctxt->service) != 0) { 22469591Sgreen log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", 22569591Sgreen user, service, authctxt->user, authctxt->service); 22669591Sgreen authctxt->valid = 0; 22769591Sgreen } 22860573Skris } 22960573Skris 23068704Sgreen#ifdef HAVE_LOGIN_CAP 23169591Sgreen if (authctxt->pw != NULL) { 23269591Sgreen lc = login_getpwclass(authctxt->pw); 23369591Sgreen if (lc == NULL) 23469591Sgreen lc = login_getclassbyname(NULL, authctxt->pw); 23569591Sgreen if (!auth_hostok(lc, from_host, from_ip)) { 23669591Sgreen log("Denied connection for %.200s from %.200s [%.200s].", 23769591Sgreen authctxt->pw->pw_name, from_host, from_ip); 23869591Sgreen packet_disconnect("Sorry, you are not allowed to connect."); 23969591Sgreen } 24069591Sgreen if (!auth_timeok(lc, time(NULL))) { 24169591Sgreen log("LOGIN %.200s REFUSED (TIME) FROM %.200s", 24269591Sgreen authctxt->pw->pw_name, from_host); 24369591Sgreen packet_disconnect("Logins not available right now."); 24469591Sgreen } 24569591Sgreen login_close(lc); 24669591Sgreen lc = NULL; 24768704Sgreen } 24868704Sgreen#endif /* HAVE_LOGIN_CAP */ 24968704Sgreen#ifdef LOGIN_ACCESS 25069591Sgreen if (authctxt->pw != NULL && 25169591Sgreen !login_access(authctxt->pw->pw_name, from_host)) { 25268704Sgreen log("Denied connection for %.200s from %.200s [%.200s].", 25369591Sgreen authctxt->pw->pw_name, from_host, from_ip); 25468704Sgreen packet_disconnect("Sorry, you are not allowed to connect."); 25568704Sgreen } 25668704Sgreen#endif /* LOGIN_ACCESS */ 25768704Sgreen 25869591Sgreen m = authmethod_lookup(method); 25969591Sgreen if (m != NULL) { 26069591Sgreen debug2("input_userauth_request: try method %s", method); 26169591Sgreen authenticated = m->userauth(authctxt); 26269591Sgreen } else { 26369591Sgreen debug2("input_userauth_request: unsupported method %s", method); 26469591Sgreen } 26569591Sgreen if (!authctxt->valid && authenticated == 1) { 26669591Sgreen log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method); 26769591Sgreen authenticated = 0; 26869591Sgreen } 26969591Sgreen 27069591Sgreen /* Special handling for root */ 27169591Sgreen if (authenticated == 1 && 27269591Sgreen authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) { 27369591Sgreen authenticated = 0; 27469591Sgreen log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); 27569591Sgreen } 27669591Sgreen 27769591Sgreen#ifdef USE_PAM 27869591Sgreen if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) 27969591Sgreen authenticated = 0; 28069591Sgreen#endif /* USE_PAM */ 28169591Sgreen 28269591Sgreen /* Log before sending the reply */ 28369591Sgreen userauth_log(authctxt, authenticated, method); 28469591Sgreen userauth_reply(authctxt, authenticated); 28569591Sgreen 28669591Sgreen xfree(service); 28769591Sgreen xfree(user); 28869591Sgreen xfree(method); 28969591Sgreen} 29069591Sgreen 29169591Sgreen 29269591Sgreenvoid 29369591Sgreenuserauth_log(Authctxt *authctxt, int authenticated, char *method) 29469591Sgreen{ 29569591Sgreen void (*authlog) (const char *fmt,...) = verbose; 29669591Sgreen char *user = NULL, *authmsg = NULL; 29769591Sgreen 29860573Skris /* Raise logging level */ 29960573Skris if (authenticated == 1 || 30069591Sgreen !authctxt->valid || 30169591Sgreen authctxt->attempt >= AUTH_FAIL_LOG || 30260573Skris strcmp(method, "password") == 0) 30360573Skris authlog = log; 30460573Skris 30560573Skris if (authenticated == 1) { 30660573Skris authmsg = "Accepted"; 30760573Skris } else if (authenticated == 0) { 30860573Skris authmsg = "Failed"; 30960573Skris } else { 31060573Skris authmsg = "Postponed"; 31160573Skris } 31269591Sgreen 31369591Sgreen if (authctxt->valid) { 31469591Sgreen user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; 31569591Sgreen } else { 31669591Sgreen user = "NOUSER"; 31769591Sgreen } 31869591Sgreen 31960573Skris authlog("%s %s for %.200s from %.200s port %d ssh2", 32069591Sgreen authmsg, 32169591Sgreen method, 32269591Sgreen user, 32369591Sgreen get_remote_ipaddr(), 32469591Sgreen get_remote_port()); 32569591Sgreen} 32660573Skris 32769591Sgreenvoid 32869591Sgreenuserauth_reply(Authctxt *authctxt, int authenticated) 32969591Sgreen{ 33060573Skris /* XXX todo: check if multiple auth methods are needed */ 33160573Skris if (authenticated == 1) { 33260573Skris /* turn off userauth */ 33360573Skris dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); 33460573Skris packet_start(SSH2_MSG_USERAUTH_SUCCESS); 33560573Skris packet_send(); 33660573Skris packet_write_wait(); 33760573Skris /* now we can break out */ 33869591Sgreen authctxt->success = 1; 33960573Skris } else if (authenticated == 0) { 34069591Sgreen char *methods = authmethods_get(); 34160573Skris packet_start(SSH2_MSG_USERAUTH_FAILURE); 34269591Sgreen packet_put_cstring(methods); 34369591Sgreen packet_put_char(0); /* XXX partial success, unused */ 34460573Skris packet_send(); 34560573Skris packet_write_wait(); 34669591Sgreen xfree(methods); 34769591Sgreen } else { 34869591Sgreen /* do nothing, we did already send a reply */ 34960573Skris } 35060573Skris} 35160573Skris 35260573Skrisint 35369591Sgreenuserauth_none(Authctxt *authctxt) 35460573Skris{ 35569591Sgreen /* disable method "none", only allowed one time */ 35669591Sgreen Authmethod *m = authmethod_lookup("none"); 35769591Sgreen if (m != NULL) 35869591Sgreen m->enabled = NULL; 35960573Skris packet_done(); 36069591Sgreen#ifdef USE_PAM 36169591Sgreen return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0; 36269591Sgreen#else /* !USE_PAM */ 36369591Sgreen return authctxt->valid ? auth_password(authctxt->pw, "") : 0; 36469591Sgreen#endif /* USE_PAM */ 36560573Skris} 36669591Sgreen 36760573Skrisint 36869591Sgreenuserauth_passwd(Authctxt *authctxt) 36960573Skris{ 37060573Skris char *password; 37160573Skris int authenticated = 0; 37260573Skris int change; 37360573Skris unsigned int len; 37460573Skris change = packet_get_char(); 37560573Skris if (change) 37660573Skris log("password change not supported"); 37760573Skris password = packet_get_string(&len); 37860573Skris packet_done(); 37969591Sgreen if (authctxt->valid && 38069591Sgreen#ifdef USE_PAM 38169591Sgreen auth_pam_password(authctxt->pw, password) == 1 38269591Sgreen#else 38369591Sgreen auth_password(authctxt->pw, password) == 1 38469591Sgreen#endif 38569591Sgreen ) 38660573Skris authenticated = 1; 38760573Skris memset(password, 0, len); 38860573Skris xfree(password); 38960573Skris return authenticated; 39060573Skris} 39169591Sgreen 39260573Skrisint 39369591Sgreenuserauth_kbdint(Authctxt *authctxt) 39460573Skris{ 39569591Sgreen int authenticated = 0; 39669591Sgreen char *lang = NULL; 39769591Sgreen char *devs = NULL; 39869591Sgreen 39969591Sgreen lang = packet_get_string(NULL); 40069591Sgreen devs = packet_get_string(NULL); 40169591Sgreen packet_done(); 40269591Sgreen 40369591Sgreen debug("keyboard-interactive language %s devs %s", lang, devs); 40469591Sgreen#ifdef SKEY 40569591Sgreen /* XXX hardcoded, we should look at devs */ 40669591Sgreen if (options.skey_authentication != 0) 40769591Sgreen authenticated = auth2_skey(authctxt); 40869591Sgreen#endif 40969591Sgreen xfree(lang); 41069591Sgreen xfree(devs); 41169591Sgreen return authenticated; 41269591Sgreen} 41369591Sgreen 41469591Sgreenint 41569591Sgreenuserauth_pubkey(Authctxt *authctxt) 41669591Sgreen{ 41760573Skris Buffer b; 41860573Skris Key *key; 41960573Skris char *pkalg, *pkblob, *sig; 42060573Skris unsigned int alen, blen, slen; 42160573Skris int have_sig; 42260573Skris int authenticated = 0; 42360573Skris 42469591Sgreen if (!authctxt->valid) { 42569591Sgreen debug2("userauth_pubkey: disabled because of invalid user"); 42660573Skris return 0; 42760573Skris } 42860573Skris have_sig = packet_get_char(); 42960573Skris pkalg = packet_get_string(&alen); 43060573Skris if (strcmp(pkalg, KEX_DSS) != 0) { 43169591Sgreen log("bad pkalg %s", pkalg); /*XXX*/ 43260573Skris xfree(pkalg); 43360573Skris return 0; 43460573Skris } 43560573Skris pkblob = packet_get_string(&blen); 43660573Skris key = dsa_key_from_blob(pkblob, blen); 43760573Skris if (key != NULL) { 43860573Skris if (have_sig) { 43960573Skris sig = packet_get_string(&slen); 44060573Skris packet_done(); 44160573Skris buffer_init(&b); 44269591Sgreen if (datafellows & SSH_OLD_SESSIONID) { 44369591Sgreen buffer_append(&b, session_id2, session_id2_len); 44469591Sgreen } else { 44565674Skris buffer_put_string(&b, session_id2, session_id2_len); 44665674Skris } 44765674Skris /* reconstruct packet */ 44860573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 44969591Sgreen buffer_put_cstring(&b, authctxt->user); 45065674Skris buffer_put_cstring(&b, 45165674Skris datafellows & SSH_BUG_PUBKEYAUTH ? 45265674Skris "ssh-userauth" : 45369591Sgreen authctxt->service); 45465674Skris buffer_put_cstring(&b, "publickey"); 45565674Skris buffer_put_char(&b, have_sig); 45665674Skris buffer_put_cstring(&b, KEX_DSS); 45765674Skris buffer_put_string(&b, pkblob, blen); 45860573Skris#ifdef DEBUG_DSS 45960573Skris buffer_dump(&b); 46060573Skris#endif 46160573Skris /* test for correct signature */ 46269591Sgreen if (user_dsa_key_allowed(authctxt->pw, key) && 46360573Skris dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 46460573Skris authenticated = 1; 46560573Skris buffer_clear(&b); 46660573Skris xfree(sig); 46760573Skris } else { 46869591Sgreen debug("test whether pkalg/pkblob are acceptable"); 46960573Skris packet_done(); 47069591Sgreen 47160573Skris /* XXX fake reply and always send PK_OK ? */ 47260573Skris /* 47360573Skris * XXX this allows testing whether a user is allowed 47460573Skris * to login: if you happen to have a valid pubkey this 47560573Skris * message is sent. the message is NEVER sent at all 47660573Skris * if a user is not allowed to login. is this an 47760573Skris * issue? -markus 47860573Skris */ 47969591Sgreen if (user_dsa_key_allowed(authctxt->pw, key)) { 48060573Skris packet_start(SSH2_MSG_USERAUTH_PK_OK); 48160573Skris packet_put_string(pkalg, alen); 48260573Skris packet_put_string(pkblob, blen); 48360573Skris packet_send(); 48460573Skris packet_write_wait(); 48560573Skris authenticated = -1; 48660573Skris } 48760573Skris } 48869591Sgreen if (authenticated != 1) 48969591Sgreen auth_clear_options(); 49060573Skris key_free(key); 49160573Skris } 49260573Skris xfree(pkalg); 49360573Skris xfree(pkblob); 49460573Skris return authenticated; 49560573Skris} 49660573Skris 49769591Sgreen/* get current user */ 49860573Skris 49960573Skrisstruct passwd* 50060573Skrisauth_get_user(void) 50160573Skris{ 50269591Sgreen return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 50360573Skris} 50460573Skris 50569591Sgreen#define DELIM "," 50669591Sgreen 50769591Sgreenchar * 50869591Sgreenauthmethods_get(void) 50960573Skris{ 51069591Sgreen Authmethod *method = NULL; 51169591Sgreen unsigned int size = 0; 51269591Sgreen char *list; 51360573Skris 51469591Sgreen for (method = authmethods; method->name != NULL; method++) { 51569591Sgreen if (strcmp(method->name, "none") == 0) 51669591Sgreen continue; 51769591Sgreen if (method->enabled != NULL && *(method->enabled) != 0) { 51869591Sgreen if (size != 0) 51969591Sgreen size += strlen(DELIM); 52069591Sgreen size += strlen(method->name); 52160573Skris } 52269591Sgreen } 52369591Sgreen size++; /* trailing '\0' */ 52469591Sgreen list = xmalloc(size); 52569591Sgreen list[0] = '\0'; 52669591Sgreen 52769591Sgreen for (method = authmethods; method->name != NULL; method++) { 52869591Sgreen if (strcmp(method->name, "none") == 0) 52969591Sgreen continue; 53069591Sgreen if (method->enabled != NULL && *(method->enabled) != 0) { 53169591Sgreen if (list[0] != '\0') 53269591Sgreen strlcat(list, DELIM, size); 53369591Sgreen strlcat(list, method->name, size); 53460573Skris } 53560573Skris } 53669591Sgreen return list; 53760573Skris} 53860573Skris 53969591SgreenAuthmethod * 54069591Sgreenauthmethod_lookup(const char *name) 54169591Sgreen{ 54269591Sgreen Authmethod *method = NULL; 54369591Sgreen if (name != NULL) 54469591Sgreen for (method = authmethods; method->name != NULL; method++) 54569591Sgreen if (method->enabled != NULL && 54669591Sgreen *(method->enabled) != 0 && 54769591Sgreen strcmp(name, method->name) == 0) 54869591Sgreen return method; 54969591Sgreen debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 55069591Sgreen return NULL; 55169591Sgreen} 55269591Sgreen 55360573Skris/* return 1 if user allows given key */ 55460573Skrisint 55560573Skrisuser_dsa_key_allowed(struct passwd *pw, Key *key) 55660573Skris{ 55760573Skris char line[8192], file[1024]; 55860573Skris int found_key = 0; 55960573Skris unsigned int bits = -1; 56060573Skris FILE *f; 56160573Skris unsigned long linenum = 0; 56260573Skris struct stat st; 56360573Skris Key *found; 56460573Skris 56569591Sgreen if (pw == NULL) 56669591Sgreen return 0; 56769591Sgreen 56860573Skris /* Temporarily use the user's uid. */ 56960573Skris temporarily_use_uid(pw->pw_uid); 57060573Skris 57160573Skris /* The authorized keys. */ 57260573Skris snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 57360573Skris SSH_USER_PERMITTED_KEYS2); 57460573Skris 57560573Skris /* Fail quietly if file does not exist */ 57660573Skris if (stat(file, &st) < 0) { 57760573Skris /* Restore the privileged uid. */ 57860573Skris restore_uid(); 57960573Skris return 0; 58060573Skris } 58160573Skris /* Open the file containing the authorized keys. */ 58260573Skris f = fopen(file, "r"); 58360573Skris if (!f) { 58460573Skris /* Restore the privileged uid. */ 58560573Skris restore_uid(); 58660573Skris return 0; 58760573Skris } 58860573Skris if (options.strict_modes) { 58960573Skris int fail = 0; 59060573Skris char buf[1024]; 59160573Skris /* Check open file in order to avoid open/stat races */ 59260573Skris if (fstat(fileno(f), &st) < 0 || 59360573Skris (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 59460573Skris (st.st_mode & 022) != 0) { 59569591Sgreen snprintf(buf, sizeof buf, 59669591Sgreen "%s authentication refused for %.100s: " 59769591Sgreen "bad ownership or modes for '%s'.", 59869591Sgreen key_type(key), pw->pw_name, file); 59960573Skris fail = 1; 60060573Skris } else { 60160573Skris /* Check path to SSH_USER_PERMITTED_KEYS */ 60260573Skris int i; 60360573Skris static const char *check[] = { 60460573Skris "", SSH_USER_DIR, NULL 60560573Skris }; 60660573Skris for (i = 0; check[i]; i++) { 60760573Skris snprintf(line, sizeof line, "%.500s/%.100s", 60860573Skris pw->pw_dir, check[i]); 60960573Skris if (stat(line, &st) < 0 || 61060573Skris (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 61160573Skris (st.st_mode & 022) != 0) { 61260573Skris snprintf(buf, sizeof buf, 61369591Sgreen "%s authentication refused for %.100s: " 61460573Skris "bad ownership or modes for '%s'.", 61569591Sgreen key_type(key), pw->pw_name, line); 61660573Skris fail = 1; 61760573Skris break; 61860573Skris } 61960573Skris } 62060573Skris } 62160573Skris if (fail) { 62260573Skris fclose(f); 62365674Skris log("%s",buf); 62460573Skris restore_uid(); 62560573Skris return 0; 62660573Skris } 62760573Skris } 62860573Skris found_key = 0; 62969591Sgreen found = key_new(key->type); 63060573Skris 63160573Skris while (fgets(line, sizeof(line), f)) { 63265674Skris char *cp, *options = NULL; 63360573Skris linenum++; 63460573Skris /* Skip leading whitespace, empty and comment lines. */ 63560573Skris for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 63660573Skris ; 63760573Skris if (!*cp || *cp == '\n' || *cp == '#') 63860573Skris continue; 63965674Skris 64060573Skris bits = key_read(found, &cp); 64165674Skris if (bits == 0) { 64265674Skris /* no key? check if there are options for this key */ 64365674Skris int quoted = 0; 64465674Skris options = cp; 64565674Skris for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 64665674Skris if (*cp == '\\' && cp[1] == '"') 64765674Skris cp++; /* Skip both */ 64865674Skris else if (*cp == '"') 64965674Skris quoted = !quoted; 65065674Skris } 65165674Skris /* Skip remaining whitespace. */ 65265674Skris for (; *cp == ' ' || *cp == '\t'; cp++) 65365674Skris ; 65465674Skris bits = key_read(found, &cp); 65565674Skris if (bits == 0) { 65665674Skris /* still no key? advance to next line*/ 65765674Skris continue; 65865674Skris } 65965674Skris } 66065674Skris if (key_equal(found, key) && 66165674Skris auth_parse_options(pw, options, linenum) == 1) { 66260573Skris found_key = 1; 66360573Skris debug("matching key found: file %s, line %ld", 66460573Skris file, linenum); 66560573Skris break; 66660573Skris } 66760573Skris } 66860573Skris restore_uid(); 66960573Skris fclose(f); 67060573Skris key_free(found); 67160573Skris return found_key; 67260573Skris} 67369591Sgreen 67469591Sgreenstruct passwd * 67569591Sgreenpwcopy(struct passwd *pw) 67669591Sgreen{ 67769591Sgreen struct passwd *copy = xmalloc(sizeof(*copy)); 67869591Sgreen memset(copy, 0, sizeof(*copy)); 67969591Sgreen copy->pw_name = xstrdup(pw->pw_name); 68069591Sgreen copy->pw_passwd = xstrdup(pw->pw_passwd); 68169591Sgreen copy->pw_uid = pw->pw_uid; 68269591Sgreen copy->pw_gid = pw->pw_gid; 68369591Sgreen copy->pw_class = xstrdup(pw->pw_class); 68469591Sgreen copy->pw_dir = xstrdup(pw->pw_dir); 68569591Sgreen copy->pw_shell = xstrdup(pw->pw_shell); 68669591Sgreen copy->pw_expire = pw->pw_expire; 68769591Sgreen copy->pw_change = pw->pw_change; 68869591Sgreen return copy; 68969591Sgreen} 690