1a04a10f8SKris Kennaway /* 2a04a10f8SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 3a04a10f8SKris Kennaway * 4a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 5a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 6a04a10f8SKris Kennaway * are met: 7a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 8a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 9a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 10a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 11a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 12a04a10f8SKris Kennaway * 13a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23a04a10f8SKris Kennaway */ 24c2d3a559SKris Kennaway 25a04a10f8SKris Kennaway #include "includes.h" 2609958426SBrian Feldman RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); 27c2d3a559SKris Kennaway RCSID("$FreeBSD$"); 28a04a10f8SKris Kennaway 29a04a10f8SKris Kennaway #include <openssl/dsa.h> 30a04a10f8SKris Kennaway #include <openssl/rsa.h> 31a04a10f8SKris Kennaway #include <openssl/evp.h> 32a04a10f8SKris Kennaway 33a04a10f8SKris Kennaway #include "xmalloc.h" 34a04a10f8SKris Kennaway #include "rsa.h" 35a04a10f8SKris Kennaway #include "ssh.h" 36a04a10f8SKris Kennaway #include "pty.h" 37a04a10f8SKris Kennaway #include "packet.h" 38a04a10f8SKris Kennaway #include "buffer.h" 39a04a10f8SKris Kennaway #include "servconf.h" 40a04a10f8SKris Kennaway #include "compat.h" 41a04a10f8SKris Kennaway #include "channels.h" 42a04a10f8SKris Kennaway #include "bufaux.h" 43a04a10f8SKris Kennaway #include "ssh2.h" 44a04a10f8SKris Kennaway #include "auth.h" 45a04a10f8SKris Kennaway #include "session.h" 46a04a10f8SKris Kennaway #include "dispatch.h" 47a04a10f8SKris Kennaway #include "auth.h" 48a04a10f8SKris Kennaway #include "key.h" 49a04a10f8SKris Kennaway #include "kex.h" 50a04a10f8SKris Kennaway 51a04a10f8SKris Kennaway #include "dsa.h" 52a04a10f8SKris Kennaway #include "uidswap.h" 53c2d3a559SKris Kennaway #include "auth-options.h" 54a04a10f8SKris Kennaway 5503e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP 5603e72be8SBrian Feldman #include <login_cap.h> 5703e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP */ 5803e72be8SBrian Feldman 59a04a10f8SKris Kennaway /* import */ 60a04a10f8SKris Kennaway extern ServerOptions options; 61a04a10f8SKris Kennaway extern unsigned char *session_id2; 62a04a10f8SKris Kennaway extern int session_id2_len; 63a04a10f8SKris Kennaway 6409958426SBrian Feldman static Authctxt *x_authctxt = NULL; 6509958426SBrian Feldman static int one = 1; 6609958426SBrian Feldman 6709958426SBrian Feldman typedef struct Authmethod Authmethod; 6809958426SBrian Feldman struct Authmethod { 6909958426SBrian Feldman char *name; 7009958426SBrian Feldman int (*userauth)(Authctxt *authctxt); 7109958426SBrian Feldman int *enabled; 7209958426SBrian Feldman }; 7309958426SBrian Feldman 74a04a10f8SKris Kennaway /* protocol */ 75a04a10f8SKris Kennaway 7609958426SBrian Feldman void input_service_request(int type, int plen, void *ctxt); 7709958426SBrian Feldman void input_userauth_request(int type, int plen, void *ctxt); 7809958426SBrian Feldman void protocol_error(int type, int plen, void *ctxt); 79a04a10f8SKris Kennaway 80a04a10f8SKris Kennaway 81a04a10f8SKris Kennaway /* helper */ 8209958426SBrian Feldman Authmethod *authmethod_lookup(const char *name); 8309958426SBrian Feldman struct passwd *pwcopy(struct passwd *pw); 84a04a10f8SKris Kennaway int user_dsa_key_allowed(struct passwd *pw, Key *key); 8509958426SBrian Feldman char *authmethods_get(void); 86a04a10f8SKris Kennaway 8709958426SBrian Feldman /* auth */ 8809958426SBrian Feldman int userauth_none(Authctxt *authctxt); 8909958426SBrian Feldman int userauth_passwd(Authctxt *authctxt); 9009958426SBrian Feldman int userauth_pubkey(Authctxt *authctxt); 9109958426SBrian Feldman int userauth_kbdint(Authctxt *authctxt); 9209958426SBrian Feldman 9309958426SBrian Feldman Authmethod authmethods[] = { 9409958426SBrian Feldman {"none", 9509958426SBrian Feldman userauth_none, 9609958426SBrian Feldman &one}, 9709958426SBrian Feldman {"publickey", 9809958426SBrian Feldman userauth_pubkey, 9909958426SBrian Feldman &options.dsa_authentication}, 10009958426SBrian Feldman {"keyboard-interactive", 10109958426SBrian Feldman userauth_kbdint, 10209958426SBrian Feldman &options.kbd_interactive_authentication}, 10309958426SBrian Feldman {"password", 10409958426SBrian Feldman userauth_passwd, 10509958426SBrian Feldman &options.password_authentication}, 10609958426SBrian Feldman {NULL, NULL, NULL} 107a04a10f8SKris Kennaway }; 108a04a10f8SKris Kennaway 109a04a10f8SKris Kennaway /* 11009958426SBrian Feldman * loop until authctxt->success == TRUE 111a04a10f8SKris Kennaway */ 112a04a10f8SKris Kennaway 113a04a10f8SKris Kennaway void 114a04a10f8SKris Kennaway do_authentication2() 115a04a10f8SKris Kennaway { 11609958426SBrian Feldman Authctxt *authctxt = xmalloc(sizeof(*authctxt)); 11709958426SBrian Feldman memset(authctxt, 'a', sizeof(*authctxt)); 11809958426SBrian Feldman authctxt->valid = 0; 11909958426SBrian Feldman authctxt->attempt = 0; 12009958426SBrian Feldman authctxt->success = 0; 12109958426SBrian Feldman x_authctxt = authctxt; /*XXX*/ 12209958426SBrian Feldman 123a04a10f8SKris Kennaway #ifdef KRB4 12409958426SBrian Feldman /* turn off kerberos, not supported by SSH2 */ 125e8aafc91SKris Kennaway options.krb4_authentication = 0; 126a04a10f8SKris Kennaway #endif 127a04a10f8SKris Kennaway dispatch_init(&protocol_error); 128a04a10f8SKris Kennaway dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 12909958426SBrian Feldman dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 130a04a10f8SKris Kennaway do_authenticated2(); 131a04a10f8SKris Kennaway } 132a04a10f8SKris Kennaway 133a04a10f8SKris Kennaway void 13409958426SBrian Feldman protocol_error(int type, int plen, void *ctxt) 135a04a10f8SKris Kennaway { 136a04a10f8SKris Kennaway log("auth: protocol error: type %d plen %d", type, plen); 137a04a10f8SKris Kennaway packet_start(SSH2_MSG_UNIMPLEMENTED); 138a04a10f8SKris Kennaway packet_put_int(0); 139a04a10f8SKris Kennaway packet_send(); 140a04a10f8SKris Kennaway packet_write_wait(); 141a04a10f8SKris Kennaway } 142a04a10f8SKris Kennaway 143a04a10f8SKris Kennaway void 14409958426SBrian Feldman input_service_request(int type, int plen, void *ctxt) 145a04a10f8SKris Kennaway { 14609958426SBrian Feldman Authctxt *authctxt = ctxt; 147a04a10f8SKris Kennaway unsigned int len; 148a04a10f8SKris Kennaway int accept = 0; 149a04a10f8SKris Kennaway char *service = packet_get_string(&len); 150a04a10f8SKris Kennaway packet_done(); 151a04a10f8SKris Kennaway 15209958426SBrian Feldman if (authctxt == NULL) 15309958426SBrian Feldman fatal("input_service_request: no authctxt"); 15409958426SBrian Feldman 155a04a10f8SKris Kennaway if (strcmp(service, "ssh-userauth") == 0) { 15609958426SBrian Feldman if (!authctxt->success) { 157a04a10f8SKris Kennaway accept = 1; 158a04a10f8SKris Kennaway /* now we can handle user-auth requests */ 159a04a10f8SKris Kennaway dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 160a04a10f8SKris Kennaway } 161a04a10f8SKris Kennaway } 162a04a10f8SKris Kennaway /* XXX all other service requests are denied */ 163a04a10f8SKris Kennaway 164a04a10f8SKris Kennaway if (accept) { 165a04a10f8SKris Kennaway packet_start(SSH2_MSG_SERVICE_ACCEPT); 166a04a10f8SKris Kennaway packet_put_cstring(service); 167a04a10f8SKris Kennaway packet_send(); 168a04a10f8SKris Kennaway packet_write_wait(); 169a04a10f8SKris Kennaway } else { 170a04a10f8SKris Kennaway debug("bad service request %s", service); 171a04a10f8SKris Kennaway packet_disconnect("bad service request %s", service); 172a04a10f8SKris Kennaway } 173a04a10f8SKris Kennaway xfree(service); 174a04a10f8SKris Kennaway } 175a04a10f8SKris Kennaway 176a04a10f8SKris Kennaway void 17709958426SBrian Feldman input_userauth_request(int type, int plen, void *ctxt) 178a04a10f8SKris Kennaway { 17909958426SBrian Feldman Authctxt *authctxt = ctxt; 18009958426SBrian Feldman Authmethod *m = NULL; 181a04a10f8SKris Kennaway int authenticated = 0; 182c2d3a559SKris Kennaway char *user, *service, *method, *authmsg = NULL; 18303e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP 18403e72be8SBrian Feldman login_cap_t *lc; 18503e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP */ 18603e72be8SBrian Feldman #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) 18703e72be8SBrian Feldman const char *from_host, *from_ip; 18803e72be8SBrian Feldman 18903e72be8SBrian Feldman from_host = get_canonical_hostname(); 19003e72be8SBrian Feldman from_ip = get_remote_ipaddr(); 19103e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ 192a04a10f8SKris Kennaway 19309958426SBrian Feldman if (authctxt == NULL) 19409958426SBrian Feldman fatal("input_userauth_request: no authctxt"); 19509958426SBrian Feldman if (authctxt->attempt++ >= AUTH_FAIL_MAX) 196a04a10f8SKris Kennaway packet_disconnect("too many failed userauth_requests"); 197a04a10f8SKris Kennaway 19809958426SBrian Feldman user = packet_get_string(NULL); 19909958426SBrian Feldman service = packet_get_string(NULL); 20009958426SBrian Feldman method = packet_get_string(NULL); 201a04a10f8SKris Kennaway debug("userauth-request for user %s service %s method %s", user, service, method); 20209958426SBrian Feldman debug("attempt #%d", authctxt->attempt); 203a04a10f8SKris Kennaway 20409958426SBrian Feldman if (authctxt->attempt == 1) { 20509958426SBrian Feldman /* setup auth context */ 20609958426SBrian Feldman struct passwd *pw = NULL; 20709958426SBrian Feldman setproctitle("%s", user); 20809958426SBrian Feldman pw = getpwnam(user); 20909958426SBrian Feldman if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { 21009958426SBrian Feldman authctxt->pw = pwcopy(pw); 21109958426SBrian Feldman authctxt->valid = 1; 21209958426SBrian Feldman debug2("input_userauth_request: setting up authctxt for %s", user); 21309958426SBrian Feldman #ifdef USE_PAM 21409958426SBrian Feldman start_pam(pw); 21509958426SBrian Feldman #endif 21609958426SBrian Feldman } else { 21709958426SBrian Feldman log("input_userauth_request: illegal user %s", user); 218a04a10f8SKris Kennaway } 21909958426SBrian Feldman authctxt->user = xstrdup(user); 22009958426SBrian Feldman authctxt->service = xstrdup(service); 22109958426SBrian Feldman } else if (authctxt->valid) { 22209958426SBrian Feldman if (strcmp(user, authctxt->user) != 0 || 22309958426SBrian Feldman strcmp(service, authctxt->service) != 0) { 22409958426SBrian Feldman log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", 22509958426SBrian Feldman user, service, authctxt->user, authctxt->service); 22609958426SBrian Feldman authctxt->valid = 0; 227a04a10f8SKris Kennaway } 228a04a10f8SKris Kennaway } 229a04a10f8SKris Kennaway 23003e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP 23109958426SBrian Feldman if (authctxt->pw != NULL) { 23209958426SBrian Feldman lc = login_getpwclass(authctxt->pw); 23303e72be8SBrian Feldman if (lc == NULL) 23409958426SBrian Feldman lc = login_getclassbyname(NULL, authctxt->pw); 23503e72be8SBrian Feldman if (!auth_hostok(lc, from_host, from_ip)) { 23603e72be8SBrian Feldman log("Denied connection for %.200s from %.200s [%.200s].", 23709958426SBrian Feldman authctxt->pw->pw_name, from_host, from_ip); 23803e72be8SBrian Feldman packet_disconnect("Sorry, you are not allowed to connect."); 23903e72be8SBrian Feldman } 24003e72be8SBrian Feldman if (!auth_timeok(lc, time(NULL))) { 24103e72be8SBrian Feldman log("LOGIN %.200s REFUSED (TIME) FROM %.200s", 24209958426SBrian Feldman authctxt->pw->pw_name, from_host); 24303e72be8SBrian Feldman packet_disconnect("Logins not available right now."); 24403e72be8SBrian Feldman } 24503e72be8SBrian Feldman login_close(lc); 24609958426SBrian Feldman lc = NULL; 24709958426SBrian Feldman } 24803e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP */ 24903e72be8SBrian Feldman #ifdef LOGIN_ACCESS 25009958426SBrian Feldman if (authctxt->pw != NULL && 25109958426SBrian Feldman !login_access(authctxt->pw->pw_name, from_host)) { 25203e72be8SBrian Feldman log("Denied connection for %.200s from %.200s [%.200s].", 25309958426SBrian Feldman authctxt->pw->pw_name, from_host, from_ip); 25403e72be8SBrian Feldman packet_disconnect("Sorry, you are not allowed to connect."); 25503e72be8SBrian Feldman } 25603e72be8SBrian Feldman #endif /* LOGIN_ACCESS */ 25703e72be8SBrian Feldman 25809958426SBrian Feldman m = authmethod_lookup(method); 25909958426SBrian Feldman if (m != NULL) { 26009958426SBrian Feldman debug2("input_userauth_request: try method %s", method); 26109958426SBrian Feldman authenticated = m->userauth(authctxt); 26209958426SBrian Feldman } else { 26309958426SBrian Feldman debug2("input_userauth_request: unsupported method %s", method); 26409958426SBrian Feldman } 26509958426SBrian Feldman if (!authctxt->valid && authenticated == 1) { 26609958426SBrian Feldman log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method); 26709958426SBrian Feldman authenticated = 0; 26809958426SBrian Feldman } 26909958426SBrian Feldman 27009958426SBrian Feldman /* Special handling for root */ 27109958426SBrian Feldman if (authenticated == 1 && 27209958426SBrian Feldman authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) { 27309958426SBrian Feldman authenticated = 0; 27409958426SBrian Feldman log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); 27509958426SBrian Feldman } 27609958426SBrian Feldman 27709958426SBrian Feldman #ifdef USE_PAM 27809958426SBrian Feldman if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) 27909958426SBrian Feldman authenticated = 0; 28009958426SBrian Feldman #endif /* USE_PAM */ 28109958426SBrian Feldman 28209958426SBrian Feldman /* Log before sending the reply */ 28309958426SBrian Feldman userauth_log(authctxt, authenticated, method); 28409958426SBrian Feldman userauth_reply(authctxt, authenticated); 28509958426SBrian Feldman 28609958426SBrian Feldman xfree(service); 28709958426SBrian Feldman xfree(user); 28809958426SBrian Feldman xfree(method); 28909958426SBrian Feldman } 29009958426SBrian Feldman 29109958426SBrian Feldman 29209958426SBrian Feldman void 29309958426SBrian Feldman userauth_log(Authctxt *authctxt, int authenticated, char *method) 29409958426SBrian Feldman { 29509958426SBrian Feldman void (*authlog) (const char *fmt,...) = verbose; 29609958426SBrian Feldman char *user = NULL, *authmsg = NULL; 29709958426SBrian Feldman 298a04a10f8SKris Kennaway /* Raise logging level */ 299a04a10f8SKris Kennaway if (authenticated == 1 || 30009958426SBrian Feldman !authctxt->valid || 30109958426SBrian Feldman authctxt->attempt >= AUTH_FAIL_LOG || 302a04a10f8SKris Kennaway strcmp(method, "password") == 0) 303a04a10f8SKris Kennaway authlog = log; 304a04a10f8SKris Kennaway 305a04a10f8SKris Kennaway if (authenticated == 1) { 306a04a10f8SKris Kennaway authmsg = "Accepted"; 307a04a10f8SKris Kennaway } else if (authenticated == 0) { 308a04a10f8SKris Kennaway authmsg = "Failed"; 309a04a10f8SKris Kennaway } else { 310a04a10f8SKris Kennaway authmsg = "Postponed"; 311a04a10f8SKris Kennaway } 31209958426SBrian Feldman 31309958426SBrian Feldman if (authctxt->valid) { 31409958426SBrian Feldman user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; 31509958426SBrian Feldman } else { 31609958426SBrian Feldman user = "NOUSER"; 31709958426SBrian Feldman } 31809958426SBrian Feldman 319a04a10f8SKris Kennaway authlog("%s %s for %.200s from %.200s port %d ssh2", 320a04a10f8SKris Kennaway authmsg, 321a04a10f8SKris Kennaway method, 32209958426SBrian Feldman user, 323a04a10f8SKris Kennaway get_remote_ipaddr(), 324a04a10f8SKris Kennaway get_remote_port()); 32509958426SBrian Feldman } 326a04a10f8SKris Kennaway 32709958426SBrian Feldman void 32809958426SBrian Feldman userauth_reply(Authctxt *authctxt, int authenticated) 32909958426SBrian Feldman { 330a04a10f8SKris Kennaway /* XXX todo: check if multiple auth methods are needed */ 331a04a10f8SKris Kennaway if (authenticated == 1) { 332a04a10f8SKris Kennaway /* turn off userauth */ 333a04a10f8SKris Kennaway dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); 334a04a10f8SKris Kennaway packet_start(SSH2_MSG_USERAUTH_SUCCESS); 335a04a10f8SKris Kennaway packet_send(); 336a04a10f8SKris Kennaway packet_write_wait(); 337a04a10f8SKris Kennaway /* now we can break out */ 33809958426SBrian Feldman authctxt->success = 1; 339a04a10f8SKris Kennaway } else if (authenticated == 0) { 34009958426SBrian Feldman char *methods = authmethods_get(); 341a04a10f8SKris Kennaway packet_start(SSH2_MSG_USERAUTH_FAILURE); 34209958426SBrian Feldman packet_put_cstring(methods); 343a04a10f8SKris Kennaway packet_put_char(0); /* XXX partial success, unused */ 344a04a10f8SKris Kennaway packet_send(); 345a04a10f8SKris Kennaway packet_write_wait(); 34609958426SBrian Feldman xfree(methods); 34709958426SBrian Feldman } else { 34809958426SBrian Feldman /* do nothing, we did already send a reply */ 349a04a10f8SKris Kennaway } 350a04a10f8SKris Kennaway } 351a04a10f8SKris Kennaway 352a04a10f8SKris Kennaway int 35309958426SBrian Feldman userauth_none(Authctxt *authctxt) 354a04a10f8SKris Kennaway { 35509958426SBrian Feldman /* disable method "none", only allowed one time */ 35609958426SBrian Feldman Authmethod *m = authmethod_lookup("none"); 35709958426SBrian Feldman if (m != NULL) 35809958426SBrian Feldman m->enabled = NULL; 359a04a10f8SKris Kennaway packet_done(); 36009958426SBrian Feldman #ifdef USE_PAM 36109958426SBrian Feldman return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0; 36209958426SBrian Feldman #else /* !USE_PAM */ 36309958426SBrian Feldman return authctxt->valid ? auth_password(authctxt->pw, "") : 0; 36409958426SBrian Feldman #endif /* USE_PAM */ 365a04a10f8SKris Kennaway } 36609958426SBrian Feldman 367a04a10f8SKris Kennaway int 36809958426SBrian Feldman userauth_passwd(Authctxt *authctxt) 369a04a10f8SKris Kennaway { 370a04a10f8SKris Kennaway char *password; 371a04a10f8SKris Kennaway int authenticated = 0; 372a04a10f8SKris Kennaway int change; 373a04a10f8SKris Kennaway unsigned int len; 374a04a10f8SKris Kennaway change = packet_get_char(); 375a04a10f8SKris Kennaway if (change) 376a04a10f8SKris Kennaway log("password change not supported"); 377a04a10f8SKris Kennaway password = packet_get_string(&len); 378a04a10f8SKris Kennaway packet_done(); 37909958426SBrian Feldman if (authctxt->valid && 38009958426SBrian Feldman #ifdef USE_PAM 38109958426SBrian Feldman auth_pam_password(authctxt->pw, password) == 1 38209958426SBrian Feldman #else 38309958426SBrian Feldman auth_password(authctxt->pw, password) == 1 38409958426SBrian Feldman #endif 38509958426SBrian Feldman ) 386a04a10f8SKris Kennaway authenticated = 1; 387a04a10f8SKris Kennaway memset(password, 0, len); 388a04a10f8SKris Kennaway xfree(password); 389a04a10f8SKris Kennaway return authenticated; 390a04a10f8SKris Kennaway } 39109958426SBrian Feldman 392a04a10f8SKris Kennaway int 39309958426SBrian Feldman userauth_kbdint(Authctxt *authctxt) 39409958426SBrian Feldman { 39509958426SBrian Feldman int authenticated = 0; 39609958426SBrian Feldman char *lang = NULL; 39709958426SBrian Feldman char *devs = NULL; 39809958426SBrian Feldman 39909958426SBrian Feldman lang = packet_get_string(NULL); 40009958426SBrian Feldman devs = packet_get_string(NULL); 40109958426SBrian Feldman packet_done(); 40209958426SBrian Feldman 40309958426SBrian Feldman debug("keyboard-interactive language %s devs %s", lang, devs); 40409958426SBrian Feldman #ifdef SKEY 40509958426SBrian Feldman /* XXX hardcoded, we should look at devs */ 40609958426SBrian Feldman if (options.skey_authentication != 0) 40709958426SBrian Feldman authenticated = auth2_skey(authctxt); 40809958426SBrian Feldman #endif 40909958426SBrian Feldman xfree(lang); 41009958426SBrian Feldman xfree(devs); 41109958426SBrian Feldman return authenticated; 41209958426SBrian Feldman } 41309958426SBrian Feldman 41409958426SBrian Feldman int 41509958426SBrian Feldman userauth_pubkey(Authctxt *authctxt) 416a04a10f8SKris Kennaway { 417a04a10f8SKris Kennaway Buffer b; 418a04a10f8SKris Kennaway Key *key; 419a04a10f8SKris Kennaway char *pkalg, *pkblob, *sig; 420a04a10f8SKris Kennaway unsigned int alen, blen, slen; 421a04a10f8SKris Kennaway int have_sig; 422a04a10f8SKris Kennaway int authenticated = 0; 423a04a10f8SKris Kennaway 42409958426SBrian Feldman if (!authctxt->valid) { 42509958426SBrian Feldman debug2("userauth_pubkey: disabled because of invalid user"); 426a04a10f8SKris Kennaway return 0; 427a04a10f8SKris Kennaway } 428a04a10f8SKris Kennaway have_sig = packet_get_char(); 429a04a10f8SKris Kennaway pkalg = packet_get_string(&alen); 430a04a10f8SKris Kennaway if (strcmp(pkalg, KEX_DSS) != 0) { 431a04a10f8SKris Kennaway log("bad pkalg %s", pkalg); /*XXX*/ 43209958426SBrian Feldman xfree(pkalg); 433a04a10f8SKris Kennaway return 0; 434a04a10f8SKris Kennaway } 435a04a10f8SKris Kennaway pkblob = packet_get_string(&blen); 436a04a10f8SKris Kennaway key = dsa_key_from_blob(pkblob, blen); 437a04a10f8SKris Kennaway if (key != NULL) { 438a04a10f8SKris Kennaway if (have_sig) { 439a04a10f8SKris Kennaway sig = packet_get_string(&slen); 440a04a10f8SKris Kennaway packet_done(); 441a04a10f8SKris Kennaway buffer_init(&b); 44209958426SBrian Feldman if (datafellows & SSH_OLD_SESSIONID) { 443a04a10f8SKris Kennaway buffer_append(&b, session_id2, session_id2_len); 44409958426SBrian Feldman } else { 44509958426SBrian Feldman buffer_put_string(&b, session_id2, session_id2_len); 446c2d3a559SKris Kennaway } 447c2d3a559SKris Kennaway /* reconstruct packet */ 448a04a10f8SKris Kennaway buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 44909958426SBrian Feldman buffer_put_cstring(&b, authctxt->user); 450c2d3a559SKris Kennaway buffer_put_cstring(&b, 451c2d3a559SKris Kennaway datafellows & SSH_BUG_PUBKEYAUTH ? 452c2d3a559SKris Kennaway "ssh-userauth" : 45309958426SBrian Feldman authctxt->service); 454c2d3a559SKris Kennaway buffer_put_cstring(&b, "publickey"); 455c2d3a559SKris Kennaway buffer_put_char(&b, have_sig); 456c2d3a559SKris Kennaway buffer_put_cstring(&b, KEX_DSS); 457c2d3a559SKris Kennaway buffer_put_string(&b, pkblob, blen); 458a04a10f8SKris Kennaway #ifdef DEBUG_DSS 459a04a10f8SKris Kennaway buffer_dump(&b); 460a04a10f8SKris Kennaway #endif 461a04a10f8SKris Kennaway /* test for correct signature */ 46209958426SBrian Feldman if (user_dsa_key_allowed(authctxt->pw, key) && 463a04a10f8SKris Kennaway dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 464a04a10f8SKris Kennaway authenticated = 1; 465a04a10f8SKris Kennaway buffer_clear(&b); 466a04a10f8SKris Kennaway xfree(sig); 467a04a10f8SKris Kennaway } else { 46809958426SBrian Feldman debug("test whether pkalg/pkblob are acceptable"); 469a04a10f8SKris Kennaway packet_done(); 47009958426SBrian Feldman 471a04a10f8SKris Kennaway /* XXX fake reply and always send PK_OK ? */ 472a04a10f8SKris Kennaway /* 473a04a10f8SKris Kennaway * XXX this allows testing whether a user is allowed 474a04a10f8SKris Kennaway * to login: if you happen to have a valid pubkey this 475a04a10f8SKris Kennaway * message is sent. the message is NEVER sent at all 476a04a10f8SKris Kennaway * if a user is not allowed to login. is this an 477a04a10f8SKris Kennaway * issue? -markus 478a04a10f8SKris Kennaway */ 47909958426SBrian Feldman if (user_dsa_key_allowed(authctxt->pw, key)) { 480a04a10f8SKris Kennaway packet_start(SSH2_MSG_USERAUTH_PK_OK); 481a04a10f8SKris Kennaway packet_put_string(pkalg, alen); 482a04a10f8SKris Kennaway packet_put_string(pkblob, blen); 483a04a10f8SKris Kennaway packet_send(); 484a04a10f8SKris Kennaway packet_write_wait(); 485a04a10f8SKris Kennaway authenticated = -1; 486a04a10f8SKris Kennaway } 487a04a10f8SKris Kennaway } 48809958426SBrian Feldman if (authenticated != 1) 48909958426SBrian Feldman auth_clear_options(); 490a04a10f8SKris Kennaway key_free(key); 491a04a10f8SKris Kennaway } 492a04a10f8SKris Kennaway xfree(pkalg); 493a04a10f8SKris Kennaway xfree(pkblob); 494a04a10f8SKris Kennaway return authenticated; 495a04a10f8SKris Kennaway } 496a04a10f8SKris Kennaway 49709958426SBrian Feldman /* get current user */ 498a04a10f8SKris Kennaway 499a04a10f8SKris Kennaway struct passwd* 500a04a10f8SKris Kennaway auth_get_user(void) 501a04a10f8SKris Kennaway { 50209958426SBrian Feldman return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 503a04a10f8SKris Kennaway } 504a04a10f8SKris Kennaway 50509958426SBrian Feldman #define DELIM "," 50609958426SBrian Feldman 50709958426SBrian Feldman char * 50809958426SBrian Feldman authmethods_get(void) 509a04a10f8SKris Kennaway { 51009958426SBrian Feldman Authmethod *method = NULL; 51109958426SBrian Feldman unsigned int size = 0; 51209958426SBrian Feldman char *list; 513a04a10f8SKris Kennaway 51409958426SBrian Feldman for (method = authmethods; method->name != NULL; method++) { 51509958426SBrian Feldman if (strcmp(method->name, "none") == 0) 51609958426SBrian Feldman continue; 51709958426SBrian Feldman if (method->enabled != NULL && *(method->enabled) != 0) { 51809958426SBrian Feldman if (size != 0) 51909958426SBrian Feldman size += strlen(DELIM); 52009958426SBrian Feldman size += strlen(method->name); 52109958426SBrian Feldman } 52209958426SBrian Feldman } 52309958426SBrian Feldman size++; /* trailing '\0' */ 52409958426SBrian Feldman list = xmalloc(size); 52509958426SBrian Feldman list[0] = '\0'; 52609958426SBrian Feldman 52709958426SBrian Feldman for (method = authmethods; method->name != NULL; method++) { 52809958426SBrian Feldman if (strcmp(method->name, "none") == 0) 52909958426SBrian Feldman continue; 53009958426SBrian Feldman if (method->enabled != NULL && *(method->enabled) != 0) { 53109958426SBrian Feldman if (list[0] != '\0') 53209958426SBrian Feldman strlcat(list, DELIM, size); 53309958426SBrian Feldman strlcat(list, method->name, size); 53409958426SBrian Feldman } 53509958426SBrian Feldman } 53609958426SBrian Feldman return list; 53709958426SBrian Feldman } 53809958426SBrian Feldman 53909958426SBrian Feldman Authmethod * 54009958426SBrian Feldman authmethod_lookup(const char *name) 54109958426SBrian Feldman { 54209958426SBrian Feldman Authmethod *method = NULL; 54309958426SBrian Feldman if (name != NULL) 54409958426SBrian Feldman for (method = authmethods; method->name != NULL; method++) 54509958426SBrian Feldman if (method->enabled != NULL && 54609958426SBrian Feldman *(method->enabled) != 0 && 54709958426SBrian Feldman strcmp(name, method->name) == 0) 54809958426SBrian Feldman return method; 54909958426SBrian Feldman debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 550a04a10f8SKris Kennaway return NULL; 551a04a10f8SKris Kennaway } 552a04a10f8SKris Kennaway 553a04a10f8SKris Kennaway /* return 1 if user allows given key */ 554a04a10f8SKris Kennaway int 555a04a10f8SKris Kennaway user_dsa_key_allowed(struct passwd *pw, Key *key) 556a04a10f8SKris Kennaway { 557a04a10f8SKris Kennaway char line[8192], file[1024]; 558a04a10f8SKris Kennaway int found_key = 0; 559a04a10f8SKris Kennaway unsigned int bits = -1; 560a04a10f8SKris Kennaway FILE *f; 561a04a10f8SKris Kennaway unsigned long linenum = 0; 562a04a10f8SKris Kennaway struct stat st; 563a04a10f8SKris Kennaway Key *found; 564a04a10f8SKris Kennaway 56509958426SBrian Feldman if (pw == NULL) 56609958426SBrian Feldman return 0; 56709958426SBrian Feldman 568a04a10f8SKris Kennaway /* Temporarily use the user's uid. */ 569a04a10f8SKris Kennaway temporarily_use_uid(pw->pw_uid); 570a04a10f8SKris Kennaway 571a04a10f8SKris Kennaway /* The authorized keys. */ 572a04a10f8SKris Kennaway snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 573a04a10f8SKris Kennaway SSH_USER_PERMITTED_KEYS2); 574a04a10f8SKris Kennaway 575a04a10f8SKris Kennaway /* Fail quietly if file does not exist */ 576a04a10f8SKris Kennaway if (stat(file, &st) < 0) { 577a04a10f8SKris Kennaway /* Restore the privileged uid. */ 578a04a10f8SKris Kennaway restore_uid(); 579a04a10f8SKris Kennaway return 0; 580a04a10f8SKris Kennaway } 581a04a10f8SKris Kennaway /* Open the file containing the authorized keys. */ 582a04a10f8SKris Kennaway f = fopen(file, "r"); 583a04a10f8SKris Kennaway if (!f) { 584a04a10f8SKris Kennaway /* Restore the privileged uid. */ 585a04a10f8SKris Kennaway restore_uid(); 586a04a10f8SKris Kennaway return 0; 587a04a10f8SKris Kennaway } 588a04a10f8SKris Kennaway if (options.strict_modes) { 589a04a10f8SKris Kennaway int fail = 0; 590a04a10f8SKris Kennaway char buf[1024]; 591a04a10f8SKris Kennaway /* Check open file in order to avoid open/stat races */ 592a04a10f8SKris Kennaway if (fstat(fileno(f), &st) < 0 || 593a04a10f8SKris Kennaway (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 594a04a10f8SKris Kennaway (st.st_mode & 022) != 0) { 59509958426SBrian Feldman snprintf(buf, sizeof buf, 59609958426SBrian Feldman "%s authentication refused for %.100s: " 59709958426SBrian Feldman "bad ownership or modes for '%s'.", 59809958426SBrian Feldman key_type(key), pw->pw_name, file); 599a04a10f8SKris Kennaway fail = 1; 600a04a10f8SKris Kennaway } else { 601a04a10f8SKris Kennaway /* Check path to SSH_USER_PERMITTED_KEYS */ 602a04a10f8SKris Kennaway int i; 603a04a10f8SKris Kennaway static const char *check[] = { 604a04a10f8SKris Kennaway "", SSH_USER_DIR, NULL 605a04a10f8SKris Kennaway }; 606a04a10f8SKris Kennaway for (i = 0; check[i]; i++) { 607a04a10f8SKris Kennaway snprintf(line, sizeof line, "%.500s/%.100s", 608a04a10f8SKris Kennaway pw->pw_dir, check[i]); 609a04a10f8SKris Kennaway if (stat(line, &st) < 0 || 610a04a10f8SKris Kennaway (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 611a04a10f8SKris Kennaway (st.st_mode & 022) != 0) { 612a04a10f8SKris Kennaway snprintf(buf, sizeof buf, 61309958426SBrian Feldman "%s authentication refused for %.100s: " 614a04a10f8SKris Kennaway "bad ownership or modes for '%s'.", 61509958426SBrian Feldman key_type(key), pw->pw_name, line); 616a04a10f8SKris Kennaway fail = 1; 617a04a10f8SKris Kennaway break; 618a04a10f8SKris Kennaway } 619a04a10f8SKris Kennaway } 620a04a10f8SKris Kennaway } 621a04a10f8SKris Kennaway if (fail) { 622a04a10f8SKris Kennaway fclose(f); 623c2d3a559SKris Kennaway log("%s",buf); 624a04a10f8SKris Kennaway restore_uid(); 625a04a10f8SKris Kennaway return 0; 626a04a10f8SKris Kennaway } 627a04a10f8SKris Kennaway } 628a04a10f8SKris Kennaway found_key = 0; 62909958426SBrian Feldman found = key_new(key->type); 630a04a10f8SKris Kennaway 631a04a10f8SKris Kennaway while (fgets(line, sizeof(line), f)) { 632c2d3a559SKris Kennaway char *cp, *options = NULL; 633a04a10f8SKris Kennaway linenum++; 634a04a10f8SKris Kennaway /* Skip leading whitespace, empty and comment lines. */ 635a04a10f8SKris Kennaway for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 636a04a10f8SKris Kennaway ; 637a04a10f8SKris Kennaway if (!*cp || *cp == '\n' || *cp == '#') 638a04a10f8SKris Kennaway continue; 639c2d3a559SKris Kennaway 640a04a10f8SKris Kennaway bits = key_read(found, &cp); 641c2d3a559SKris Kennaway if (bits == 0) { 642c2d3a559SKris Kennaway /* no key? check if there are options for this key */ 643c2d3a559SKris Kennaway int quoted = 0; 644c2d3a559SKris Kennaway options = cp; 645c2d3a559SKris Kennaway for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 646c2d3a559SKris Kennaway if (*cp == '\\' && cp[1] == '"') 647c2d3a559SKris Kennaway cp++; /* Skip both */ 648c2d3a559SKris Kennaway else if (*cp == '"') 649c2d3a559SKris Kennaway quoted = !quoted; 650c2d3a559SKris Kennaway } 651c2d3a559SKris Kennaway /* Skip remaining whitespace. */ 652c2d3a559SKris Kennaway for (; *cp == ' ' || *cp == '\t'; cp++) 653c2d3a559SKris Kennaway ; 654c2d3a559SKris Kennaway bits = key_read(found, &cp); 655c2d3a559SKris Kennaway if (bits == 0) { 656c2d3a559SKris Kennaway /* still no key? advance to next line*/ 657a04a10f8SKris Kennaway continue; 658c2d3a559SKris Kennaway } 659c2d3a559SKris Kennaway } 660c2d3a559SKris Kennaway if (key_equal(found, key) && 661c2d3a559SKris Kennaway auth_parse_options(pw, options, linenum) == 1) { 662a04a10f8SKris Kennaway found_key = 1; 663a04a10f8SKris Kennaway debug("matching key found: file %s, line %ld", 664a04a10f8SKris Kennaway file, linenum); 665a04a10f8SKris Kennaway break; 666a04a10f8SKris Kennaway } 667a04a10f8SKris Kennaway } 668a04a10f8SKris Kennaway restore_uid(); 669a04a10f8SKris Kennaway fclose(f); 670a04a10f8SKris Kennaway key_free(found); 671a04a10f8SKris Kennaway return found_key; 672a04a10f8SKris Kennaway } 67309958426SBrian Feldman 67409958426SBrian Feldman struct passwd * 67509958426SBrian Feldman pwcopy(struct passwd *pw) 67609958426SBrian Feldman { 67709958426SBrian Feldman struct passwd *copy = xmalloc(sizeof(*copy)); 67809958426SBrian Feldman memset(copy, 0, sizeof(*copy)); 67909958426SBrian Feldman copy->pw_name = xstrdup(pw->pw_name); 68009958426SBrian Feldman copy->pw_passwd = xstrdup(pw->pw_passwd); 68109958426SBrian Feldman copy->pw_uid = pw->pw_uid; 68209958426SBrian Feldman copy->pw_gid = pw->pw_gid; 68309958426SBrian Feldman copy->pw_class = xstrdup(pw->pw_class); 68409958426SBrian Feldman copy->pw_dir = xstrdup(pw->pw_dir); 68509958426SBrian Feldman copy->pw_shell = xstrdup(pw->pw_shell); 68609958426SBrian Feldman copy->pw_expire = pw->pw_expire; 68709958426SBrian Feldman copy->pw_change = pw->pw_change; 68809958426SBrian Feldman return copy; 68909958426SBrian Feldman } 690