1190cef3dSDag-Erling Smørgrav /* $OpenBSD: auth2.c,v 1.149 2018/07/11 18:53:29 markus Exp $ */ 2a04a10f8SKris Kennaway /* 3a04a10f8SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 4a04a10f8SKris Kennaway * 5a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 6a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 7a04a10f8SKris Kennaway * are met: 8a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 9a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 10a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 11a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 12a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 13a04a10f8SKris Kennaway * 14a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24a04a10f8SKris Kennaway */ 25c2d3a559SKris Kennaway 26a04a10f8SKris Kennaway #include "includes.h" 27333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$"); 28a04a10f8SKris Kennaway 29333ee039SDag-Erling Smørgrav #include <sys/types.h> 30d4af9e69SDag-Erling Smørgrav #include <sys/stat.h> 31d4af9e69SDag-Erling Smørgrav #include <sys/uio.h> 32333ee039SDag-Erling Smørgrav 33d4af9e69SDag-Erling Smørgrav #include <fcntl.h> 344f52dfbbSDag-Erling Smørgrav #include <limits.h> 35333ee039SDag-Erling Smørgrav #include <pwd.h> 36333ee039SDag-Erling Smørgrav #include <stdarg.h> 37333ee039SDag-Erling Smørgrav #include <string.h> 38d4af9e69SDag-Erling Smørgrav #include <unistd.h> 39333ee039SDag-Erling Smørgrav 40d4af9e69SDag-Erling Smørgrav #include "atomicio.h" 417aee6ffeSDag-Erling Smørgrav #include "xmalloc.h" 42333ee039SDag-Erling Smørgrav #include "ssh2.h" 43a04a10f8SKris Kennaway #include "packet.h" 44ca3176e7SBrian Feldman #include "log.h" 45190cef3dSDag-Erling Smørgrav #include "sshbuf.h" 46a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 47a04a10f8SKris Kennaway #include "servconf.h" 48a04a10f8SKris Kennaway #include "compat.h" 49190cef3dSDag-Erling Smørgrav #include "sshkey.h" 50333ee039SDag-Erling Smørgrav #include "hostfile.h" 51a04a10f8SKris Kennaway #include "auth.h" 52a04a10f8SKris Kennaway #include "dispatch.h" 53ca3176e7SBrian Feldman #include "pathnames.h" 54190cef3dSDag-Erling Smørgrav #include "sshbuf.h" 55190cef3dSDag-Erling Smørgrav #include "ssherr.h" 56b2af61ecSKurt Lidl #include "blacklist_client.h" 57a04a10f8SKris Kennaway 58cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 59cf2b5f3bSDag-Erling Smørgrav #include "ssh-gss.h" 60cf2b5f3bSDag-Erling Smørgrav #endif 61333ee039SDag-Erling Smørgrav #include "monitor_wrap.h" 624f52dfbbSDag-Erling Smørgrav #include "ssherr.h" 63190cef3dSDag-Erling Smørgrav #include "digest.h" 64cf2b5f3bSDag-Erling Smørgrav 65a04a10f8SKris Kennaway /* import */ 66a04a10f8SKris Kennaway extern ServerOptions options; 67ca3176e7SBrian Feldman extern u_char *session_id2; 68cf2b5f3bSDag-Erling Smørgrav extern u_int session_id2_len; 69190cef3dSDag-Erling Smørgrav extern struct sshbuf *loginmsg; 70a04a10f8SKris Kennaway 7180628bacSDag-Erling Smørgrav /* methods */ 7280628bacSDag-Erling Smørgrav 7380628bacSDag-Erling Smørgrav extern Authmethod method_none; 7480628bacSDag-Erling Smørgrav extern Authmethod method_pubkey; 7580628bacSDag-Erling Smørgrav extern Authmethod method_passwd; 7680628bacSDag-Erling Smørgrav extern Authmethod method_kbdint; 7780628bacSDag-Erling Smørgrav extern Authmethod method_hostbased; 78cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 79cf2b5f3bSDag-Erling Smørgrav extern Authmethod method_gssapi; 80cf2b5f3bSDag-Erling Smørgrav #endif 8180628bacSDag-Erling Smørgrav 8280628bacSDag-Erling Smørgrav Authmethod *authmethods[] = { 8380628bacSDag-Erling Smørgrav &method_none, 8480628bacSDag-Erling Smørgrav &method_pubkey, 85cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 86cf2b5f3bSDag-Erling Smørgrav &method_gssapi, 87cf2b5f3bSDag-Erling Smørgrav #endif 8880628bacSDag-Erling Smørgrav &method_passwd, 8980628bacSDag-Erling Smørgrav &method_kbdint, 9080628bacSDag-Erling Smørgrav &method_hostbased, 9180628bacSDag-Erling Smørgrav NULL 9209958426SBrian Feldman }; 9309958426SBrian Feldman 94a04a10f8SKris Kennaway /* protocol */ 95a04a10f8SKris Kennaway 964f52dfbbSDag-Erling Smørgrav static int input_service_request(int, u_int32_t, struct ssh *); 974f52dfbbSDag-Erling Smørgrav static int input_userauth_request(int, u_int32_t, struct ssh *); 98a04a10f8SKris Kennaway 99a04a10f8SKris Kennaway /* helper */ 1006888a9beSDag-Erling Smørgrav static Authmethod *authmethod_lookup(Authctxt *, const char *); 1016888a9beSDag-Erling Smørgrav static char *authmethods_get(Authctxt *authctxt); 102e4a9863fSDag-Erling Smørgrav 103e4a9863fSDag-Erling Smørgrav #define MATCH_NONE 0 /* method or submethod mismatch */ 104e4a9863fSDag-Erling Smørgrav #define MATCH_METHOD 1 /* method matches (no submethod specified) */ 105e4a9863fSDag-Erling Smørgrav #define MATCH_BOTH 2 /* method and submethod match */ 106e4a9863fSDag-Erling Smørgrav #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */ 107e4a9863fSDag-Erling Smørgrav static int list_starts_with(const char *, const char *, const char *); 108d4af9e69SDag-Erling Smørgrav 109d4af9e69SDag-Erling Smørgrav char * 110d4af9e69SDag-Erling Smørgrav auth2_read_banner(void) 111d4af9e69SDag-Erling Smørgrav { 112d4af9e69SDag-Erling Smørgrav struct stat st; 113d4af9e69SDag-Erling Smørgrav char *banner = NULL; 114d4af9e69SDag-Erling Smørgrav size_t len, n; 115d4af9e69SDag-Erling Smørgrav int fd; 116d4af9e69SDag-Erling Smørgrav 117d4af9e69SDag-Erling Smørgrav if ((fd = open(options.banner, O_RDONLY)) == -1) 118d4af9e69SDag-Erling Smørgrav return (NULL); 119d4af9e69SDag-Erling Smørgrav if (fstat(fd, &st) == -1) { 120d4af9e69SDag-Erling Smørgrav close(fd); 121d4af9e69SDag-Erling Smørgrav return (NULL); 122d4af9e69SDag-Erling Smørgrav } 123462c32cbSDag-Erling Smørgrav if (st.st_size <= 0 || st.st_size > 1*1024*1024) { 124d4af9e69SDag-Erling Smørgrav close(fd); 125d4af9e69SDag-Erling Smørgrav return (NULL); 126d4af9e69SDag-Erling Smørgrav } 127d4af9e69SDag-Erling Smørgrav 128d4af9e69SDag-Erling Smørgrav len = (size_t)st.st_size; /* truncate */ 129d4af9e69SDag-Erling Smørgrav banner = xmalloc(len + 1); 130d4af9e69SDag-Erling Smørgrav n = atomicio(read, fd, banner, len); 131d4af9e69SDag-Erling Smørgrav close(fd); 132d4af9e69SDag-Erling Smørgrav 133d4af9e69SDag-Erling Smørgrav if (n != len) { 134e4a9863fSDag-Erling Smørgrav free(banner); 135d4af9e69SDag-Erling Smørgrav return (NULL); 136d4af9e69SDag-Erling Smørgrav } 137d4af9e69SDag-Erling Smørgrav banner[n] = '\0'; 138d4af9e69SDag-Erling Smørgrav 139d4af9e69SDag-Erling Smørgrav return (banner); 140d4af9e69SDag-Erling Smørgrav } 141d4af9e69SDag-Erling Smørgrav 142d4af9e69SDag-Erling Smørgrav void 143d4af9e69SDag-Erling Smørgrav userauth_send_banner(const char *msg) 144d4af9e69SDag-Erling Smørgrav { 145d4af9e69SDag-Erling Smørgrav packet_start(SSH2_MSG_USERAUTH_BANNER); 146d4af9e69SDag-Erling Smørgrav packet_put_cstring(msg); 147d4af9e69SDag-Erling Smørgrav packet_put_cstring(""); /* language, unused */ 148d4af9e69SDag-Erling Smørgrav packet_send(); 149d4af9e69SDag-Erling Smørgrav debug("%s: sent", __func__); 150d4af9e69SDag-Erling Smørgrav } 151d4af9e69SDag-Erling Smørgrav 152d4af9e69SDag-Erling Smørgrav static void 153d4af9e69SDag-Erling Smørgrav userauth_banner(void) 154d4af9e69SDag-Erling Smørgrav { 155d4af9e69SDag-Erling Smørgrav char *banner = NULL; 156d4af9e69SDag-Erling Smørgrav 15747dd1d1bSDag-Erling Smørgrav if (options.banner == NULL) 158d4af9e69SDag-Erling Smørgrav return; 159d4af9e69SDag-Erling Smørgrav 160d4af9e69SDag-Erling Smørgrav if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 161d4af9e69SDag-Erling Smørgrav goto done; 162d4af9e69SDag-Erling Smørgrav userauth_send_banner(banner); 163d4af9e69SDag-Erling Smørgrav 164d4af9e69SDag-Erling Smørgrav done: 165e4a9863fSDag-Erling Smørgrav free(banner); 166d4af9e69SDag-Erling Smørgrav } 167a04a10f8SKris Kennaway 168a04a10f8SKris Kennaway /* 16909958426SBrian Feldman * loop until authctxt->success == TRUE 170a04a10f8SKris Kennaway */ 1711ec0d754SDag-Erling Smørgrav void 1721ec0d754SDag-Erling Smørgrav do_authentication2(Authctxt *authctxt) 173a04a10f8SKris Kennaway { 1744f52dfbbSDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 1754f52dfbbSDag-Erling Smørgrav ssh->authctxt = authctxt; /* XXX move to caller */ 1764f52dfbbSDag-Erling Smørgrav ssh_dispatch_init(ssh, &dispatch_protocol_error); 1774f52dfbbSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); 1784f52dfbbSDag-Erling Smørgrav ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); 1794f52dfbbSDag-Erling Smørgrav ssh->authctxt = NULL; 180a04a10f8SKris Kennaway } 181a04a10f8SKris Kennaway 182333ee039SDag-Erling Smørgrav /*ARGSUSED*/ 183bc5531deSDag-Erling Smørgrav static int 1844f52dfbbSDag-Erling Smørgrav input_service_request(int type, u_int32_t seq, struct ssh *ssh) 185a04a10f8SKris Kennaway { 1864f52dfbbSDag-Erling Smørgrav Authctxt *authctxt = ssh->authctxt; 187ca3176e7SBrian Feldman u_int len; 188f388f5efSDag-Erling Smørgrav int acceptit = 0; 1894a421b63SDag-Erling Smørgrav char *service = packet_get_cstring(&len); 190af12a3e7SDag-Erling Smørgrav packet_check_eom(); 191a04a10f8SKris Kennaway 19209958426SBrian Feldman if (authctxt == NULL) 19309958426SBrian Feldman fatal("input_service_request: no authctxt"); 19409958426SBrian Feldman 195a04a10f8SKris Kennaway if (strcmp(service, "ssh-userauth") == 0) { 19609958426SBrian Feldman if (!authctxt->success) { 197f388f5efSDag-Erling Smørgrav acceptit = 1; 198a04a10f8SKris Kennaway /* now we can handle user-auth requests */ 1994f52dfbbSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 200a04a10f8SKris Kennaway } 201a04a10f8SKris Kennaway } 202a04a10f8SKris Kennaway /* XXX all other service requests are denied */ 203a04a10f8SKris Kennaway 204f388f5efSDag-Erling Smørgrav if (acceptit) { 205a04a10f8SKris Kennaway packet_start(SSH2_MSG_SERVICE_ACCEPT); 206a04a10f8SKris Kennaway packet_put_cstring(service); 207a04a10f8SKris Kennaway packet_send(); 208a04a10f8SKris Kennaway packet_write_wait(); 209a04a10f8SKris Kennaway } else { 210a04a10f8SKris Kennaway debug("bad service request %s", service); 211a04a10f8SKris Kennaway packet_disconnect("bad service request %s", service); 212a04a10f8SKris Kennaway } 213e4a9863fSDag-Erling Smørgrav free(service); 214bc5531deSDag-Erling Smørgrav return 0; 215a04a10f8SKris Kennaway } 216a04a10f8SKris Kennaway 217190cef3dSDag-Erling Smørgrav #define MIN_FAIL_DELAY_SECONDS 0.005 218190cef3dSDag-Erling Smørgrav static double 219190cef3dSDag-Erling Smørgrav user_specific_delay(const char *user) 220190cef3dSDag-Erling Smørgrav { 221190cef3dSDag-Erling Smørgrav char b[512]; 222190cef3dSDag-Erling Smørgrav size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512); 223190cef3dSDag-Erling Smørgrav u_char *hash = xmalloc(len); 224190cef3dSDag-Erling Smørgrav double delay; 225190cef3dSDag-Erling Smørgrav 226190cef3dSDag-Erling Smørgrav (void)snprintf(b, sizeof b, "%llu%s", 227190cef3dSDag-Erling Smørgrav (unsigned long long)options.timing_secret, user); 228190cef3dSDag-Erling Smørgrav if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0) 229190cef3dSDag-Erling Smørgrav fatal("%s: ssh_digest_memory", __func__); 230190cef3dSDag-Erling Smørgrav /* 0-4.2 ms of delay */ 231190cef3dSDag-Erling Smørgrav delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000; 232190cef3dSDag-Erling Smørgrav freezero(hash, len); 233190cef3dSDag-Erling Smørgrav debug3("%s: user specific delay %0.3lfms", __func__, delay/1000); 234190cef3dSDag-Erling Smørgrav return MIN_FAIL_DELAY_SECONDS + delay; 235190cef3dSDag-Erling Smørgrav } 236190cef3dSDag-Erling Smørgrav 237190cef3dSDag-Erling Smørgrav static void 238190cef3dSDag-Erling Smørgrav ensure_minimum_time_since(double start, double seconds) 239190cef3dSDag-Erling Smørgrav { 240190cef3dSDag-Erling Smørgrav struct timespec ts; 241190cef3dSDag-Erling Smørgrav double elapsed = monotime_double() - start, req = seconds, remain; 242190cef3dSDag-Erling Smørgrav 243190cef3dSDag-Erling Smørgrav /* if we've already passed the requested time, scale up */ 244190cef3dSDag-Erling Smørgrav while ((remain = seconds - elapsed) < 0.0) 245190cef3dSDag-Erling Smørgrav seconds *= 2; 246190cef3dSDag-Erling Smørgrav 247190cef3dSDag-Erling Smørgrav ts.tv_sec = remain; 248190cef3dSDag-Erling Smørgrav ts.tv_nsec = (remain - ts.tv_sec) * 1000000000; 249190cef3dSDag-Erling Smørgrav debug3("%s: elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)", 250190cef3dSDag-Erling Smørgrav __func__, elapsed*1000, remain*1000, req*1000); 251190cef3dSDag-Erling Smørgrav nanosleep(&ts, NULL); 252190cef3dSDag-Erling Smørgrav } 253190cef3dSDag-Erling Smørgrav 254333ee039SDag-Erling Smørgrav /*ARGSUSED*/ 255bc5531deSDag-Erling Smørgrav static int 2564f52dfbbSDag-Erling Smørgrav input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) 257a04a10f8SKris Kennaway { 2584f52dfbbSDag-Erling Smørgrav Authctxt *authctxt = ssh->authctxt; 25909958426SBrian Feldman Authmethod *m = NULL; 260ca3176e7SBrian Feldman char *user, *service, *method, *style = NULL; 261a04a10f8SKris Kennaway int authenticated = 0; 262190cef3dSDag-Erling Smørgrav double tstart = monotime_double(); 2635b400a39SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 2645b400a39SDag-Erling Smørgrav login_cap_t *lc; 2655b400a39SDag-Erling Smørgrav const char *from_host, *from_ip; 2665b400a39SDag-Erling Smørgrav #endif 267d93a896eSDag-Erling Smørgrav 26809958426SBrian Feldman if (authctxt == NULL) 26909958426SBrian Feldman fatal("input_userauth_request: no authctxt"); 270a04a10f8SKris Kennaway 2714a421b63SDag-Erling Smørgrav user = packet_get_cstring(NULL); 2724a421b63SDag-Erling Smørgrav service = packet_get_cstring(NULL); 2734a421b63SDag-Erling Smørgrav method = packet_get_cstring(NULL); 274a04a10f8SKris Kennaway debug("userauth-request for user %s service %s method %s", user, service, method); 275ca3176e7SBrian Feldman debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 276a04a10f8SKris Kennaway 277ca3176e7SBrian Feldman if ((style = strchr(user, ':')) != NULL) 278ca3176e7SBrian Feldman *style++ = 0; 279ca3176e7SBrian Feldman 280ca3176e7SBrian Feldman if (authctxt->attempt++ == 0) { 28109958426SBrian Feldman /* setup auth context */ 28280628bacSDag-Erling Smørgrav authctxt->pw = PRIVSEP(getpwnamallow(user)); 2835962c0e9SDag-Erling Smørgrav authctxt->user = xstrdup(user); 28480628bacSDag-Erling Smørgrav if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 28509958426SBrian Feldman authctxt->valid = 1; 286d93a896eSDag-Erling Smørgrav debug2("%s: setting up authctxt for %s", 287d93a896eSDag-Erling Smørgrav __func__, user); 28809958426SBrian Feldman } else { 289d93a896eSDag-Erling Smørgrav /* Invalid user, fake password information */ 290cf2b5f3bSDag-Erling Smørgrav authctxt->pw = fakepw(); 291aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 292aa49c926SDag-Erling Smørgrav PRIVSEP(audit_event(SSH_INVALID_USER)); 293aa49c926SDag-Erling Smørgrav #endif 294a04a10f8SKris Kennaway } 295b74df5b2SDag-Erling Smørgrav #ifdef USE_PAM 296b74df5b2SDag-Erling Smørgrav if (options.use_pam) 297b74df5b2SDag-Erling Smørgrav PRIVSEP(start_pam(authctxt)); 298b74df5b2SDag-Erling Smørgrav #endif 299d93a896eSDag-Erling Smørgrav ssh_packet_set_log_preamble(ssh, "%suser %s", 300d93a896eSDag-Erling Smørgrav authctxt->valid ? "authenticating " : "invalid ", user); 30121e764dfSDag-Erling Smørgrav setproctitle("%s%s", authctxt->valid ? user : "unknown", 30280628bacSDag-Erling Smørgrav use_privsep ? " [net]" : ""); 30309958426SBrian Feldman authctxt->service = xstrdup(service); 304af12a3e7SDag-Erling Smørgrav authctxt->style = style ? xstrdup(style) : NULL; 30580628bacSDag-Erling Smørgrav if (use_privsep) 30680628bacSDag-Erling Smørgrav mm_inform_authserv(service, style); 307d4af9e69SDag-Erling Smørgrav userauth_banner(); 3086888a9beSDag-Erling Smørgrav if (auth2_setup_methods_lists(authctxt) != 0) 3096888a9beSDag-Erling Smørgrav packet_disconnect("no authentication methods enabled"); 310af12a3e7SDag-Erling Smørgrav } else if (strcmp(user, authctxt->user) != 0 || 31109958426SBrian Feldman strcmp(service, authctxt->service) != 0) { 312af12a3e7SDag-Erling Smørgrav packet_disconnect("Change of username or service not allowed: " 313af12a3e7SDag-Erling Smørgrav "(%s,%s) -> (%s,%s)", 314af12a3e7SDag-Erling Smørgrav authctxt->user, authctxt->service, user, service); 315a04a10f8SKris Kennaway } 3165b400a39SDag-Erling Smørgrav 3175b400a39SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 318076ad2f8SDag-Erling Smørgrav if (authctxt->pw != NULL && 319076ad2f8SDag-Erling Smørgrav (lc = login_getpwclass(authctxt->pw)) != NULL) { 320076ad2f8SDag-Erling Smørgrav logit("user %s login class %s", authctxt->pw->pw_name, 321076ad2f8SDag-Erling Smørgrav authctxt->pw->pw_class); 322076ad2f8SDag-Erling Smørgrav from_host = auth_get_canonical_hostname(ssh, options.use_dns); 323076ad2f8SDag-Erling Smørgrav from_ip = ssh_remote_ipaddr(ssh); 3245b400a39SDag-Erling Smørgrav if (!auth_hostok(lc, from_host, from_ip)) { 325cf2b5f3bSDag-Erling Smørgrav logit("Denied connection for %.200s from %.200s [%.200s].", 3265b400a39SDag-Erling Smørgrav authctxt->pw->pw_name, from_host, from_ip); 3275b400a39SDag-Erling Smørgrav packet_disconnect("Sorry, you are not allowed to connect."); 3285b400a39SDag-Erling Smørgrav } 3295b400a39SDag-Erling Smørgrav if (!auth_timeok(lc, time(NULL))) { 330cf2b5f3bSDag-Erling Smørgrav logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", 3315b400a39SDag-Erling Smørgrav authctxt->pw->pw_name, from_host); 3325b400a39SDag-Erling Smørgrav packet_disconnect("Logins not available right now."); 3335b400a39SDag-Erling Smørgrav } 3345b400a39SDag-Erling Smørgrav login_close(lc); 3355b400a39SDag-Erling Smørgrav } 3365b400a39SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */ 3375b400a39SDag-Erling Smørgrav 338ca3176e7SBrian Feldman /* reset state */ 3394f52dfbbSDag-Erling Smørgrav auth2_challenge_stop(ssh); 340cf2b5f3bSDag-Erling Smørgrav 341cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 342cce7d346SDag-Erling Smørgrav /* XXX move to auth2_gssapi_stop() */ 3434f52dfbbSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3444f52dfbbSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 345cf2b5f3bSDag-Erling Smørgrav #endif 346cf2b5f3bSDag-Erling Smørgrav 3474f52dfbbSDag-Erling Smørgrav auth2_authctxt_reset_info(authctxt); 348ca3176e7SBrian Feldman authctxt->postponed = 0; 349e146993eSDag-Erling Smørgrav authctxt->server_caused_failure = 0; 35003e72be8SBrian Feldman 351ca3176e7SBrian Feldman /* try to authenticate user */ 3526888a9beSDag-Erling Smørgrav m = authmethod_lookup(authctxt, method); 353d4af9e69SDag-Erling Smørgrav if (m != NULL && authctxt->failures < options.max_authtries) { 35409958426SBrian Feldman debug2("input_userauth_request: try method %s", method); 3554f52dfbbSDag-Erling Smørgrav authenticated = m->userauth(ssh); 35609958426SBrian Feldman } 357190cef3dSDag-Erling Smørgrav if (!authctxt->authenticated) 358190cef3dSDag-Erling Smørgrav ensure_minimum_time_since(tstart, 359190cef3dSDag-Erling Smørgrav user_specific_delay(authctxt->user)); 3604f52dfbbSDag-Erling Smørgrav userauth_finish(ssh, authenticated, method, NULL); 36109958426SBrian Feldman 362e4a9863fSDag-Erling Smørgrav free(service); 363e4a9863fSDag-Erling Smørgrav free(user); 364e4a9863fSDag-Erling Smørgrav free(method); 365bc5531deSDag-Erling Smørgrav return 0; 36609958426SBrian Feldman } 36709958426SBrian Feldman 368ca3176e7SBrian Feldman void 3694f52dfbbSDag-Erling Smørgrav userauth_finish(struct ssh *ssh, int authenticated, const char *method, 3706888a9beSDag-Erling Smørgrav const char *submethod) 371ca3176e7SBrian Feldman { 3724f52dfbbSDag-Erling Smørgrav Authctxt *authctxt = ssh->authctxt; 373af12a3e7SDag-Erling Smørgrav char *methods; 3746888a9beSDag-Erling Smørgrav int partial = 0; 375af12a3e7SDag-Erling Smørgrav 376ca3176e7SBrian Feldman if (!authctxt->valid && authenticated) 377ca3176e7SBrian Feldman fatal("INTERNAL ERROR: authenticated invalid user %s", 378ca3176e7SBrian Feldman authctxt->user); 3796888a9beSDag-Erling Smørgrav if (authenticated && authctxt->postponed) 3806888a9beSDag-Erling Smørgrav fatal("INTERNAL ERROR: authenticated and postponed"); 381ca3176e7SBrian Feldman 382ca3176e7SBrian Feldman /* Special handling for root */ 383e73e9afaSDag-Erling Smørgrav if (authenticated && authctxt->pw->pw_uid == 0 && 38447dd1d1bSDag-Erling Smørgrav !auth_root_allowed(ssh, method)) { 385ca3176e7SBrian Feldman authenticated = 0; 386aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 387aa49c926SDag-Erling Smørgrav PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); 388aa49c926SDag-Erling Smørgrav #endif 389aa49c926SDag-Erling Smørgrav } 390ca3176e7SBrian Feldman 3916888a9beSDag-Erling Smørgrav if (authenticated && options.num_auth_methods != 0) { 392e4a9863fSDag-Erling Smørgrav if (!auth2_update_methods_lists(authctxt, method, submethod)) { 3936888a9beSDag-Erling Smørgrav authenticated = 0; 3946888a9beSDag-Erling Smørgrav partial = 1; 3956888a9beSDag-Erling Smørgrav } 3966888a9beSDag-Erling Smørgrav } 3976888a9beSDag-Erling Smørgrav 3986888a9beSDag-Erling Smørgrav /* Log before sending the reply */ 399e4a9863fSDag-Erling Smørgrav auth_log(authctxt, authenticated, partial, method, submethod); 4006888a9beSDag-Erling Smørgrav 4014f52dfbbSDag-Erling Smørgrav /* Update information exposed to session */ 4024f52dfbbSDag-Erling Smørgrav if (authenticated || partial) 4034f52dfbbSDag-Erling Smørgrav auth2_update_session_info(authctxt, method, submethod); 4044f52dfbbSDag-Erling Smørgrav 4056888a9beSDag-Erling Smørgrav if (authctxt->postponed) 4066888a9beSDag-Erling Smørgrav return; 4076888a9beSDag-Erling Smørgrav 408989dd127SDag-Erling Smørgrav #ifdef USE_PAM 409aa49c926SDag-Erling Smørgrav if (options.use_pam && authenticated) { 410190cef3dSDag-Erling Smørgrav int r; 411190cef3dSDag-Erling Smørgrav 412aa49c926SDag-Erling Smørgrav if (!PRIVSEP(do_pam_account())) { 413aa49c926SDag-Erling Smørgrav /* if PAM returned a message, send it to the user */ 414190cef3dSDag-Erling Smørgrav if (sshbuf_len(loginmsg) > 0) { 415190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0) 416190cef3dSDag-Erling Smørgrav fatal("%s: buffer error: %s", 417190cef3dSDag-Erling Smørgrav __func__, ssh_err(r)); 418190cef3dSDag-Erling Smørgrav userauth_send_banner(sshbuf_ptr(loginmsg)); 419aa49c926SDag-Erling Smørgrav packet_write_wait(); 420aa49c926SDag-Erling Smørgrav } 421aa49c926SDag-Erling Smørgrav fatal("Access denied for user %s by PAM account " 422aa49c926SDag-Erling Smørgrav "configuration", authctxt->user); 423aa49c926SDag-Erling Smørgrav } 424aa49c926SDag-Erling Smørgrav } 425cf2b5f3bSDag-Erling Smørgrav #endif 426989dd127SDag-Erling Smørgrav 427af12a3e7SDag-Erling Smørgrav if (authenticated == 1) { 428af12a3e7SDag-Erling Smørgrav /* turn off userauth */ 4294f52dfbbSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 430af12a3e7SDag-Erling Smørgrav packet_start(SSH2_MSG_USERAUTH_SUCCESS); 431af12a3e7SDag-Erling Smørgrav packet_send(); 432af12a3e7SDag-Erling Smørgrav packet_write_wait(); 433af12a3e7SDag-Erling Smørgrav /* now we can break out */ 434af12a3e7SDag-Erling Smørgrav authctxt->success = 1; 435d93a896eSDag-Erling Smørgrav ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); 436af12a3e7SDag-Erling Smørgrav } else { 437d4af9e69SDag-Erling Smørgrav /* Allow initial try of "none" auth without failure penalty */ 438bc5531deSDag-Erling Smørgrav if (!partial && !authctxt->server_caused_failure && 439342b8b88SKurt Lidl (authctxt->attempt > 1 || strcmp(method, "none") != 0)) { 440d4af9e69SDag-Erling Smørgrav authctxt->failures++; 441342b8b88SKurt Lidl BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL, "ssh"); 442342b8b88SKurt Lidl } 443d4af9e69SDag-Erling Smørgrav if (authctxt->failures >= options.max_authtries) { 444aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 445aa49c926SDag-Erling Smørgrav PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 446aa49c926SDag-Erling Smørgrav #endif 447a0ee8cc6SDag-Erling Smørgrav auth_maxtries_exceeded(authctxt); 448aa49c926SDag-Erling Smørgrav } 4496888a9beSDag-Erling Smørgrav methods = authmethods_get(authctxt); 4506888a9beSDag-Erling Smørgrav debug3("%s: failure partial=%d next methods=\"%s\"", __func__, 4516888a9beSDag-Erling Smørgrav partial, methods); 452af12a3e7SDag-Erling Smørgrav packet_start(SSH2_MSG_USERAUTH_FAILURE); 453af12a3e7SDag-Erling Smørgrav packet_put_cstring(methods); 4546888a9beSDag-Erling Smørgrav packet_put_char(partial); 455af12a3e7SDag-Erling Smørgrav packet_send(); 456af12a3e7SDag-Erling Smørgrav packet_write_wait(); 457e4a9863fSDag-Erling Smørgrav free(methods); 458af12a3e7SDag-Erling Smørgrav } 459ca3176e7SBrian Feldman } 46009958426SBrian Feldman 4616888a9beSDag-Erling Smørgrav /* 4626888a9beSDag-Erling Smørgrav * Checks whether method is allowed by at least one AuthenticationMethods 4636888a9beSDag-Erling Smørgrav * methods list. Returns 1 if allowed, or no methods lists configured. 4646888a9beSDag-Erling Smørgrav * 0 otherwise. 4656888a9beSDag-Erling Smørgrav */ 466e4a9863fSDag-Erling Smørgrav int 467e4a9863fSDag-Erling Smørgrav auth2_method_allowed(Authctxt *authctxt, const char *method, 468e4a9863fSDag-Erling Smørgrav const char *submethod) 4696888a9beSDag-Erling Smørgrav { 4706888a9beSDag-Erling Smørgrav u_int i; 4716888a9beSDag-Erling Smørgrav 4726888a9beSDag-Erling Smørgrav /* 4736888a9beSDag-Erling Smørgrav * NB. authctxt->num_auth_methods might be zero as a result of 4746888a9beSDag-Erling Smørgrav * auth2_setup_methods_lists(), so check the configuration. 4756888a9beSDag-Erling Smørgrav */ 4766888a9beSDag-Erling Smørgrav if (options.num_auth_methods == 0) 4776888a9beSDag-Erling Smørgrav return 1; 4786888a9beSDag-Erling Smørgrav for (i = 0; i < authctxt->num_auth_methods; i++) { 479e4a9863fSDag-Erling Smørgrav if (list_starts_with(authctxt->auth_methods[i], method, 480e4a9863fSDag-Erling Smørgrav submethod) != MATCH_NONE) 4816888a9beSDag-Erling Smørgrav return 1; 4826888a9beSDag-Erling Smørgrav } 4836888a9beSDag-Erling Smørgrav return 0; 4846888a9beSDag-Erling Smørgrav } 4856888a9beSDag-Erling Smørgrav 486af12a3e7SDag-Erling Smørgrav static char * 4876888a9beSDag-Erling Smørgrav authmethods_get(Authctxt *authctxt) 488a04a10f8SKris Kennaway { 489190cef3dSDag-Erling Smørgrav struct sshbuf *b; 49009958426SBrian Feldman char *list; 491190cef3dSDag-Erling Smørgrav int i, r; 492a04a10f8SKris Kennaway 493190cef3dSDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) 494190cef3dSDag-Erling Smørgrav fatal("%s: sshbuf_new failed", __func__); 49580628bacSDag-Erling Smørgrav for (i = 0; authmethods[i] != NULL; i++) { 49680628bacSDag-Erling Smørgrav if (strcmp(authmethods[i]->name, "none") == 0) 49709958426SBrian Feldman continue; 4986888a9beSDag-Erling Smørgrav if (authmethods[i]->enabled == NULL || 4996888a9beSDag-Erling Smørgrav *(authmethods[i]->enabled) == 0) 5006888a9beSDag-Erling Smørgrav continue; 501e4a9863fSDag-Erling Smørgrav if (!auth2_method_allowed(authctxt, authmethods[i]->name, 502e4a9863fSDag-Erling Smørgrav NULL)) 5036888a9beSDag-Erling Smørgrav continue; 504190cef3dSDag-Erling Smørgrav if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "", 505190cef3dSDag-Erling Smørgrav authmethods[i]->name)) != 0) 506190cef3dSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r)); 50709958426SBrian Feldman } 508190cef3dSDag-Erling Smørgrav if ((list = sshbuf_dup_string(b)) == NULL) 509076ad2f8SDag-Erling Smørgrav fatal("%s: sshbuf_dup_string failed", __func__); 510190cef3dSDag-Erling Smørgrav sshbuf_free(b); 51109958426SBrian Feldman return list; 51209958426SBrian Feldman } 51309958426SBrian Feldman 514af12a3e7SDag-Erling Smørgrav static Authmethod * 5156888a9beSDag-Erling Smørgrav authmethod_lookup(Authctxt *authctxt, const char *name) 51609958426SBrian Feldman { 51780628bacSDag-Erling Smørgrav int i; 51880628bacSDag-Erling Smørgrav 51909958426SBrian Feldman if (name != NULL) 52080628bacSDag-Erling Smørgrav for (i = 0; authmethods[i] != NULL; i++) 52180628bacSDag-Erling Smørgrav if (authmethods[i]->enabled != NULL && 52280628bacSDag-Erling Smørgrav *(authmethods[i]->enabled) != 0 && 5236888a9beSDag-Erling Smørgrav strcmp(name, authmethods[i]->name) == 0 && 524e4a9863fSDag-Erling Smørgrav auth2_method_allowed(authctxt, 525e4a9863fSDag-Erling Smørgrav authmethods[i]->name, NULL)) 52680628bacSDag-Erling Smørgrav return authmethods[i]; 52780628bacSDag-Erling Smørgrav debug2("Unrecognized authentication method name: %s", 52880628bacSDag-Erling Smørgrav name ? name : "NULL"); 529a04a10f8SKris Kennaway return NULL; 530a04a10f8SKris Kennaway } 531d4af9e69SDag-Erling Smørgrav 5326888a9beSDag-Erling Smørgrav /* 5336888a9beSDag-Erling Smørgrav * Check a comma-separated list of methods for validity. Is need_enable is 5346888a9beSDag-Erling Smørgrav * non-zero, then also require that the methods are enabled. 5356888a9beSDag-Erling Smørgrav * Returns 0 on success or -1 if the methods list is invalid. 5366888a9beSDag-Erling Smørgrav */ 5376888a9beSDag-Erling Smørgrav int 5386888a9beSDag-Erling Smørgrav auth2_methods_valid(const char *_methods, int need_enable) 5396888a9beSDag-Erling Smørgrav { 540e4a9863fSDag-Erling Smørgrav char *methods, *omethods, *method, *p; 5416888a9beSDag-Erling Smørgrav u_int i, found; 5426888a9beSDag-Erling Smørgrav int ret = -1; 5436888a9beSDag-Erling Smørgrav 5446888a9beSDag-Erling Smørgrav if (*_methods == '\0') { 5456888a9beSDag-Erling Smørgrav error("empty authentication method list"); 5466888a9beSDag-Erling Smørgrav return -1; 5476888a9beSDag-Erling Smørgrav } 5486888a9beSDag-Erling Smørgrav omethods = methods = xstrdup(_methods); 5496888a9beSDag-Erling Smørgrav while ((method = strsep(&methods, ",")) != NULL) { 5506888a9beSDag-Erling Smørgrav for (found = i = 0; !found && authmethods[i] != NULL; i++) { 551e4a9863fSDag-Erling Smørgrav if ((p = strchr(method, ':')) != NULL) 552e4a9863fSDag-Erling Smørgrav *p = '\0'; 5536888a9beSDag-Erling Smørgrav if (strcmp(method, authmethods[i]->name) != 0) 5546888a9beSDag-Erling Smørgrav continue; 5556888a9beSDag-Erling Smørgrav if (need_enable) { 5566888a9beSDag-Erling Smørgrav if (authmethods[i]->enabled == NULL || 5576888a9beSDag-Erling Smørgrav *(authmethods[i]->enabled) == 0) { 5586888a9beSDag-Erling Smørgrav error("Disabled method \"%s\" in " 5596888a9beSDag-Erling Smørgrav "AuthenticationMethods list \"%s\"", 5606888a9beSDag-Erling Smørgrav method, _methods); 5616888a9beSDag-Erling Smørgrav goto out; 5626888a9beSDag-Erling Smørgrav } 5636888a9beSDag-Erling Smørgrav } 5646888a9beSDag-Erling Smørgrav found = 1; 5656888a9beSDag-Erling Smørgrav break; 5666888a9beSDag-Erling Smørgrav } 5676888a9beSDag-Erling Smørgrav if (!found) { 5686888a9beSDag-Erling Smørgrav error("Unknown authentication method \"%s\" in list", 5696888a9beSDag-Erling Smørgrav method); 5706888a9beSDag-Erling Smørgrav goto out; 5716888a9beSDag-Erling Smørgrav } 5726888a9beSDag-Erling Smørgrav } 5736888a9beSDag-Erling Smørgrav ret = 0; 5746888a9beSDag-Erling Smørgrav out: 5756888a9beSDag-Erling Smørgrav free(omethods); 5766888a9beSDag-Erling Smørgrav return ret; 5776888a9beSDag-Erling Smørgrav } 5786888a9beSDag-Erling Smørgrav 5796888a9beSDag-Erling Smørgrav /* 5806888a9beSDag-Erling Smørgrav * Prune the AuthenticationMethods supplied in the configuration, removing 5816888a9beSDag-Erling Smørgrav * any methods lists that include disabled methods. Note that this might 5826888a9beSDag-Erling Smørgrav * leave authctxt->num_auth_methods == 0, even when multiple required auth 5836888a9beSDag-Erling Smørgrav * has been requested. For this reason, all tests for whether multiple is 5846888a9beSDag-Erling Smørgrav * enabled should consult options.num_auth_methods directly. 5856888a9beSDag-Erling Smørgrav */ 5866888a9beSDag-Erling Smørgrav int 5876888a9beSDag-Erling Smørgrav auth2_setup_methods_lists(Authctxt *authctxt) 5886888a9beSDag-Erling Smørgrav { 5896888a9beSDag-Erling Smørgrav u_int i; 5906888a9beSDag-Erling Smørgrav 5916888a9beSDag-Erling Smørgrav if (options.num_auth_methods == 0) 5926888a9beSDag-Erling Smørgrav return 0; 5936888a9beSDag-Erling Smørgrav debug3("%s: checking methods", __func__); 5946888a9beSDag-Erling Smørgrav authctxt->auth_methods = xcalloc(options.num_auth_methods, 5956888a9beSDag-Erling Smørgrav sizeof(*authctxt->auth_methods)); 5966888a9beSDag-Erling Smørgrav authctxt->num_auth_methods = 0; 5976888a9beSDag-Erling Smørgrav for (i = 0; i < options.num_auth_methods; i++) { 5986888a9beSDag-Erling Smørgrav if (auth2_methods_valid(options.auth_methods[i], 1) != 0) { 5996888a9beSDag-Erling Smørgrav logit("Authentication methods list \"%s\" contains " 6006888a9beSDag-Erling Smørgrav "disabled method, skipping", 6016888a9beSDag-Erling Smørgrav options.auth_methods[i]); 6026888a9beSDag-Erling Smørgrav continue; 6036888a9beSDag-Erling Smørgrav } 6046888a9beSDag-Erling Smørgrav debug("authentication methods list %d: %s", 6056888a9beSDag-Erling Smørgrav authctxt->num_auth_methods, options.auth_methods[i]); 6066888a9beSDag-Erling Smørgrav authctxt->auth_methods[authctxt->num_auth_methods++] = 6076888a9beSDag-Erling Smørgrav xstrdup(options.auth_methods[i]); 6086888a9beSDag-Erling Smørgrav } 6096888a9beSDag-Erling Smørgrav if (authctxt->num_auth_methods == 0) { 6106888a9beSDag-Erling Smørgrav error("No AuthenticationMethods left after eliminating " 6116888a9beSDag-Erling Smørgrav "disabled methods"); 6126888a9beSDag-Erling Smørgrav return -1; 6136888a9beSDag-Erling Smørgrav } 6146888a9beSDag-Erling Smørgrav return 0; 6156888a9beSDag-Erling Smørgrav } 6166888a9beSDag-Erling Smørgrav 6176888a9beSDag-Erling Smørgrav static int 618e4a9863fSDag-Erling Smørgrav list_starts_with(const char *methods, const char *method, 619e4a9863fSDag-Erling Smørgrav const char *submethod) 6206888a9beSDag-Erling Smørgrav { 6216888a9beSDag-Erling Smørgrav size_t l = strlen(method); 622e4a9863fSDag-Erling Smørgrav int match; 623e4a9863fSDag-Erling Smørgrav const char *p; 6246888a9beSDag-Erling Smørgrav 6256888a9beSDag-Erling Smørgrav if (strncmp(methods, method, l) != 0) 626e4a9863fSDag-Erling Smørgrav return MATCH_NONE; 627e4a9863fSDag-Erling Smørgrav p = methods + l; 628e4a9863fSDag-Erling Smørgrav match = MATCH_METHOD; 629e4a9863fSDag-Erling Smørgrav if (*p == ':') { 630e4a9863fSDag-Erling Smørgrav if (!submethod) 631e4a9863fSDag-Erling Smørgrav return MATCH_PARTIAL; 632e4a9863fSDag-Erling Smørgrav l = strlen(submethod); 633e4a9863fSDag-Erling Smørgrav p += 1; 634e4a9863fSDag-Erling Smørgrav if (strncmp(submethod, p, l)) 635e4a9863fSDag-Erling Smørgrav return MATCH_NONE; 636e4a9863fSDag-Erling Smørgrav p += l; 637e4a9863fSDag-Erling Smørgrav match = MATCH_BOTH; 638e4a9863fSDag-Erling Smørgrav } 639e4a9863fSDag-Erling Smørgrav if (*p != ',' && *p != '\0') 640e4a9863fSDag-Erling Smørgrav return MATCH_NONE; 641e4a9863fSDag-Erling Smørgrav return match; 6426888a9beSDag-Erling Smørgrav } 6436888a9beSDag-Erling Smørgrav 6446888a9beSDag-Erling Smørgrav /* 6456888a9beSDag-Erling Smørgrav * Remove method from the start of a comma-separated list of methods. 6466888a9beSDag-Erling Smørgrav * Returns 0 if the list of methods did not start with that method or 1 6476888a9beSDag-Erling Smørgrav * if it did. 6486888a9beSDag-Erling Smørgrav */ 6496888a9beSDag-Erling Smørgrav static int 650e4a9863fSDag-Erling Smørgrav remove_method(char **methods, const char *method, const char *submethod) 6516888a9beSDag-Erling Smørgrav { 652e4a9863fSDag-Erling Smørgrav char *omethods = *methods, *p; 6536888a9beSDag-Erling Smørgrav size_t l = strlen(method); 654e4a9863fSDag-Erling Smørgrav int match; 6556888a9beSDag-Erling Smørgrav 656e4a9863fSDag-Erling Smørgrav match = list_starts_with(omethods, method, submethod); 657e4a9863fSDag-Erling Smørgrav if (match != MATCH_METHOD && match != MATCH_BOTH) 6586888a9beSDag-Erling Smørgrav return 0; 659e4a9863fSDag-Erling Smørgrav p = omethods + l; 660e4a9863fSDag-Erling Smørgrav if (submethod && match == MATCH_BOTH) 661e4a9863fSDag-Erling Smørgrav p += 1 + strlen(submethod); /* include colon */ 662e4a9863fSDag-Erling Smørgrav if (*p == ',') 663e4a9863fSDag-Erling Smørgrav p++; 664e4a9863fSDag-Erling Smørgrav *methods = xstrdup(p); 6656888a9beSDag-Erling Smørgrav free(omethods); 6666888a9beSDag-Erling Smørgrav return 1; 6676888a9beSDag-Erling Smørgrav } 6686888a9beSDag-Erling Smørgrav 6696888a9beSDag-Erling Smørgrav /* 6706888a9beSDag-Erling Smørgrav * Called after successful authentication. Will remove the successful method 6716888a9beSDag-Erling Smørgrav * from the start of each list in which it occurs. If it was the last method 6726888a9beSDag-Erling Smørgrav * in any list, then authentication is deemed successful. 6736888a9beSDag-Erling Smørgrav * Returns 1 if the method completed any authentication list or 0 otherwise. 6746888a9beSDag-Erling Smørgrav */ 6756888a9beSDag-Erling Smørgrav int 676e4a9863fSDag-Erling Smørgrav auth2_update_methods_lists(Authctxt *authctxt, const char *method, 677e4a9863fSDag-Erling Smørgrav const char *submethod) 6786888a9beSDag-Erling Smørgrav { 6796888a9beSDag-Erling Smørgrav u_int i, found = 0; 6806888a9beSDag-Erling Smørgrav 6816888a9beSDag-Erling Smørgrav debug3("%s: updating methods list after \"%s\"", __func__, method); 6826888a9beSDag-Erling Smørgrav for (i = 0; i < authctxt->num_auth_methods; i++) { 683e4a9863fSDag-Erling Smørgrav if (!remove_method(&(authctxt->auth_methods[i]), method, 684e4a9863fSDag-Erling Smørgrav submethod)) 6856888a9beSDag-Erling Smørgrav continue; 6866888a9beSDag-Erling Smørgrav found = 1; 6876888a9beSDag-Erling Smørgrav if (*authctxt->auth_methods[i] == '\0') { 6886888a9beSDag-Erling Smørgrav debug2("authentication methods list %d complete", i); 6896888a9beSDag-Erling Smørgrav return 1; 6906888a9beSDag-Erling Smørgrav } 6916888a9beSDag-Erling Smørgrav debug3("authentication methods list %d remaining: \"%s\"", 6926888a9beSDag-Erling Smørgrav i, authctxt->auth_methods[i]); 6936888a9beSDag-Erling Smørgrav } 6946888a9beSDag-Erling Smørgrav /* This should not happen, but would be bad if it did */ 6956888a9beSDag-Erling Smørgrav if (!found) 6966888a9beSDag-Erling Smørgrav fatal("%s: method not in AuthenticationMethods", __func__); 6976888a9beSDag-Erling Smørgrav return 0; 6986888a9beSDag-Erling Smørgrav } 6996888a9beSDag-Erling Smørgrav 7004f52dfbbSDag-Erling Smørgrav /* Reset method-specific information */ 7014f52dfbbSDag-Erling Smørgrav void auth2_authctxt_reset_info(Authctxt *authctxt) 7024f52dfbbSDag-Erling Smørgrav { 7034f52dfbbSDag-Erling Smørgrav sshkey_free(authctxt->auth_method_key); 7044f52dfbbSDag-Erling Smørgrav free(authctxt->auth_method_info); 7054f52dfbbSDag-Erling Smørgrav authctxt->auth_method_key = NULL; 7064f52dfbbSDag-Erling Smørgrav authctxt->auth_method_info = NULL; 7074f52dfbbSDag-Erling Smørgrav } 7084f52dfbbSDag-Erling Smørgrav 7094f52dfbbSDag-Erling Smørgrav /* Record auth method-specific information for logs */ 7104f52dfbbSDag-Erling Smørgrav void 7114f52dfbbSDag-Erling Smørgrav auth2_record_info(Authctxt *authctxt, const char *fmt, ...) 7124f52dfbbSDag-Erling Smørgrav { 7134f52dfbbSDag-Erling Smørgrav va_list ap; 7144f52dfbbSDag-Erling Smørgrav int i; 7154f52dfbbSDag-Erling Smørgrav 7164f52dfbbSDag-Erling Smørgrav free(authctxt->auth_method_info); 7174f52dfbbSDag-Erling Smørgrav authctxt->auth_method_info = NULL; 7184f52dfbbSDag-Erling Smørgrav 7194f52dfbbSDag-Erling Smørgrav va_start(ap, fmt); 7204f52dfbbSDag-Erling Smørgrav i = vasprintf(&authctxt->auth_method_info, fmt, ap); 7214f52dfbbSDag-Erling Smørgrav va_end(ap); 7224f52dfbbSDag-Erling Smørgrav 7234f52dfbbSDag-Erling Smørgrav if (i < 0 || authctxt->auth_method_info == NULL) 7244f52dfbbSDag-Erling Smørgrav fatal("%s: vasprintf failed", __func__); 7254f52dfbbSDag-Erling Smørgrav } 7264f52dfbbSDag-Erling Smørgrav 7274f52dfbbSDag-Erling Smørgrav /* 7284f52dfbbSDag-Erling Smørgrav * Records a public key used in authentication. This is used for logging 7294f52dfbbSDag-Erling Smørgrav * and to ensure that the same key is not subsequently accepted again for 7304f52dfbbSDag-Erling Smørgrav * multiple authentication. 7314f52dfbbSDag-Erling Smørgrav */ 7324f52dfbbSDag-Erling Smørgrav void 7334f52dfbbSDag-Erling Smørgrav auth2_record_key(Authctxt *authctxt, int authenticated, 7344f52dfbbSDag-Erling Smørgrav const struct sshkey *key) 7354f52dfbbSDag-Erling Smørgrav { 7364f52dfbbSDag-Erling Smørgrav struct sshkey **tmp, *dup; 7374f52dfbbSDag-Erling Smørgrav int r; 7384f52dfbbSDag-Erling Smørgrav 739*2a01feabSEd Maste if ((r = sshkey_from_private(key, &dup)) != 0) 7404f52dfbbSDag-Erling Smørgrav fatal("%s: copy key: %s", __func__, ssh_err(r)); 7414f52dfbbSDag-Erling Smørgrav sshkey_free(authctxt->auth_method_key); 7424f52dfbbSDag-Erling Smørgrav authctxt->auth_method_key = dup; 7434f52dfbbSDag-Erling Smørgrav 7444f52dfbbSDag-Erling Smørgrav if (!authenticated) 7454f52dfbbSDag-Erling Smørgrav return; 7464f52dfbbSDag-Erling Smørgrav 7474f52dfbbSDag-Erling Smørgrav /* If authenticated, make sure we don't accept this key again */ 748*2a01feabSEd Maste if ((r = sshkey_from_private(key, &dup)) != 0) 7494f52dfbbSDag-Erling Smørgrav fatal("%s: copy key: %s", __func__, ssh_err(r)); 7504f52dfbbSDag-Erling Smørgrav if (authctxt->nprev_keys >= INT_MAX || 7514f52dfbbSDag-Erling Smørgrav (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys, 7524f52dfbbSDag-Erling Smørgrav authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL) 7534f52dfbbSDag-Erling Smørgrav fatal("%s: reallocarray failed", __func__); 7544f52dfbbSDag-Erling Smørgrav authctxt->prev_keys = tmp; 7554f52dfbbSDag-Erling Smørgrav authctxt->prev_keys[authctxt->nprev_keys] = dup; 7564f52dfbbSDag-Erling Smørgrav authctxt->nprev_keys++; 7574f52dfbbSDag-Erling Smørgrav 7584f52dfbbSDag-Erling Smørgrav } 7594f52dfbbSDag-Erling Smørgrav 7604f52dfbbSDag-Erling Smørgrav /* Checks whether a key has already been previously used for authentication */ 7614f52dfbbSDag-Erling Smørgrav int 7624f52dfbbSDag-Erling Smørgrav auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key) 7634f52dfbbSDag-Erling Smørgrav { 7644f52dfbbSDag-Erling Smørgrav u_int i; 7654f52dfbbSDag-Erling Smørgrav char *fp; 7664f52dfbbSDag-Erling Smørgrav 7674f52dfbbSDag-Erling Smørgrav for (i = 0; i < authctxt->nprev_keys; i++) { 7684f52dfbbSDag-Erling Smørgrav if (sshkey_equal_public(key, authctxt->prev_keys[i])) { 7694f52dfbbSDag-Erling Smørgrav fp = sshkey_fingerprint(authctxt->prev_keys[i], 7704f52dfbbSDag-Erling Smørgrav options.fingerprint_hash, SSH_FP_DEFAULT); 7714f52dfbbSDag-Erling Smørgrav debug3("%s: key already used: %s %s", __func__, 7724f52dfbbSDag-Erling Smørgrav sshkey_type(authctxt->prev_keys[i]), 7734f52dfbbSDag-Erling Smørgrav fp == NULL ? "UNKNOWN" : fp); 7744f52dfbbSDag-Erling Smørgrav free(fp); 7754f52dfbbSDag-Erling Smørgrav return 1; 7764f52dfbbSDag-Erling Smørgrav } 7774f52dfbbSDag-Erling Smørgrav } 7784f52dfbbSDag-Erling Smørgrav return 0; 7794f52dfbbSDag-Erling Smørgrav } 7804f52dfbbSDag-Erling Smørgrav 7814f52dfbbSDag-Erling Smørgrav /* 7824f52dfbbSDag-Erling Smørgrav * Updates authctxt->session_info with details of authentication. Should be 7834f52dfbbSDag-Erling Smørgrav * whenever an authentication method succeeds. 7844f52dfbbSDag-Erling Smørgrav */ 7854f52dfbbSDag-Erling Smørgrav void 7864f52dfbbSDag-Erling Smørgrav auth2_update_session_info(Authctxt *authctxt, const char *method, 7874f52dfbbSDag-Erling Smørgrav const char *submethod) 7884f52dfbbSDag-Erling Smørgrav { 7894f52dfbbSDag-Erling Smørgrav int r; 7904f52dfbbSDag-Erling Smørgrav 7914f52dfbbSDag-Erling Smørgrav if (authctxt->session_info == NULL) { 7924f52dfbbSDag-Erling Smørgrav if ((authctxt->session_info = sshbuf_new()) == NULL) 7934f52dfbbSDag-Erling Smørgrav fatal("%s: sshbuf_new", __func__); 7944f52dfbbSDag-Erling Smørgrav } 7954f52dfbbSDag-Erling Smørgrav 7964f52dfbbSDag-Erling Smørgrav /* Append method[/submethod] */ 7974f52dfbbSDag-Erling Smørgrav if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s", 7984f52dfbbSDag-Erling Smørgrav method, submethod == NULL ? "" : "/", 7994f52dfbbSDag-Erling Smørgrav submethod == NULL ? "" : submethod)) != 0) 8004f52dfbbSDag-Erling Smørgrav fatal("%s: append method: %s", __func__, ssh_err(r)); 8014f52dfbbSDag-Erling Smørgrav 8024f52dfbbSDag-Erling Smørgrav /* Append key if present */ 8034f52dfbbSDag-Erling Smørgrav if (authctxt->auth_method_key != NULL) { 8044f52dfbbSDag-Erling Smørgrav if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || 8054f52dfbbSDag-Erling Smørgrav (r = sshkey_format_text(authctxt->auth_method_key, 8064f52dfbbSDag-Erling Smørgrav authctxt->session_info)) != 0) 8074f52dfbbSDag-Erling Smørgrav fatal("%s: append key: %s", __func__, ssh_err(r)); 8084f52dfbbSDag-Erling Smørgrav } 8094f52dfbbSDag-Erling Smørgrav 8104f52dfbbSDag-Erling Smørgrav if (authctxt->auth_method_info != NULL) { 8114f52dfbbSDag-Erling Smørgrav /* Ensure no ambiguity here */ 8124f52dfbbSDag-Erling Smørgrav if (strchr(authctxt->auth_method_info, '\n') != NULL) 8134f52dfbbSDag-Erling Smørgrav fatal("%s: auth_method_info contains \\n", __func__); 8144f52dfbbSDag-Erling Smørgrav if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || 8154f52dfbbSDag-Erling Smørgrav (r = sshbuf_putf(authctxt->session_info, "%s", 8164f52dfbbSDag-Erling Smørgrav authctxt->auth_method_info)) != 0) { 8174f52dfbbSDag-Erling Smørgrav fatal("%s: append method info: %s", 8184f52dfbbSDag-Erling Smørgrav __func__, ssh_err(r)); 8194f52dfbbSDag-Erling Smørgrav } 8204f52dfbbSDag-Erling Smørgrav } 8214f52dfbbSDag-Erling Smørgrav if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0) 8224f52dfbbSDag-Erling Smørgrav fatal("%s: append: %s", __func__, ssh_err(r)); 8234f52dfbbSDag-Erling Smørgrav } 8246888a9beSDag-Erling Smørgrav 825