1*50a69bb5SSascha Wildner /* $OpenBSD: monitor.c,v 1.228 2021/08/11 05:20:17 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright 2002 Niels Provos <provos@citi.umich.edu> 418de8d7fSPeter Avalos * Copyright 2002 Markus Friedl <markus@openbsd.org> 518de8d7fSPeter Avalos * All rights reserved. 618de8d7fSPeter Avalos * 718de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 818de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 918de8d7fSPeter Avalos * are met: 1018de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 1118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1218de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1318de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1418de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1518de8d7fSPeter Avalos * 1618de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1718de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1818de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1918de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2018de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2118de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2218de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2318de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2418de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2518de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2618de8d7fSPeter Avalos */ 2718de8d7fSPeter Avalos 2818de8d7fSPeter Avalos #include "includes.h" 2918de8d7fSPeter Avalos 3018de8d7fSPeter Avalos #include <sys/types.h> 3118de8d7fSPeter Avalos #include <sys/socket.h> 3218de8d7fSPeter Avalos #include <sys/wait.h> 3318de8d7fSPeter Avalos 3418de8d7fSPeter Avalos #include <errno.h> 3518de8d7fSPeter Avalos #include <fcntl.h> 36e9778795SPeter Avalos #include <limits.h> 3718de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 3818de8d7fSPeter Avalos #include <paths.h> 3918de8d7fSPeter Avalos #endif 4018de8d7fSPeter Avalos #include <pwd.h> 4118de8d7fSPeter Avalos #include <signal.h> 42e9778795SPeter Avalos #ifdef HAVE_STDINT_H 43e9778795SPeter Avalos # include <stdint.h> 44e9778795SPeter Avalos #endif 4518de8d7fSPeter Avalos #include <stdlib.h> 4618de8d7fSPeter Avalos #include <string.h> 4736e94dc5SPeter Avalos #include <stdarg.h> 4836e94dc5SPeter Avalos #include <stdio.h> 4918de8d7fSPeter Avalos #include <unistd.h> 501c188a7fSPeter Avalos #ifdef HAVE_POLL_H 511c188a7fSPeter Avalos #include <poll.h> 521c188a7fSPeter Avalos #else 531c188a7fSPeter Avalos # ifdef HAVE_SYS_POLL_H 541c188a7fSPeter Avalos # include <sys/poll.h> 551c188a7fSPeter Avalos # endif 561c188a7fSPeter Avalos #endif 5718de8d7fSPeter Avalos 5836e94dc5SPeter Avalos #ifdef WITH_OPENSSL 5918de8d7fSPeter Avalos #include <openssl/dh.h> 6036e94dc5SPeter Avalos #endif 6118de8d7fSPeter Avalos 62664f4763Szrj #include "openbsd-compat/sys-tree.h" 6318de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h" 64664f4763Szrj #include "openbsd-compat/openssl-compat.h" 65664f4763Szrj 661c188a7fSPeter Avalos #include "atomicio.h" 6718de8d7fSPeter Avalos #include "xmalloc.h" 6818de8d7fSPeter Avalos #include "ssh.h" 69664f4763Szrj #include "sshkey.h" 70664f4763Szrj #include "sshbuf.h" 7118de8d7fSPeter Avalos #include "hostfile.h" 7218de8d7fSPeter Avalos #include "auth.h" 7318de8d7fSPeter Avalos #include "cipher.h" 7418de8d7fSPeter Avalos #include "kex.h" 7518de8d7fSPeter Avalos #include "dh.h" 76e9778795SPeter Avalos #include "auth-pam.h" 7718de8d7fSPeter Avalos #include "packet.h" 7818de8d7fSPeter Avalos #include "auth-options.h" 7918de8d7fSPeter Avalos #include "sshpty.h" 8018de8d7fSPeter Avalos #include "channels.h" 8118de8d7fSPeter Avalos #include "session.h" 8218de8d7fSPeter Avalos #include "sshlogin.h" 8318de8d7fSPeter Avalos #include "canohost.h" 8418de8d7fSPeter Avalos #include "log.h" 8536e94dc5SPeter Avalos #include "misc.h" 8618de8d7fSPeter Avalos #include "servconf.h" 8718de8d7fSPeter Avalos #include "monitor.h" 8818de8d7fSPeter Avalos #ifdef GSSAPI 8918de8d7fSPeter Avalos #include "ssh-gss.h" 9018de8d7fSPeter Avalos #endif 9118de8d7fSPeter Avalos #include "monitor_wrap.h" 9218de8d7fSPeter Avalos #include "monitor_fdpass.h" 9318de8d7fSPeter Avalos #include "compat.h" 9418de8d7fSPeter Avalos #include "ssh2.h" 9536e94dc5SPeter Avalos #include "authfd.h" 96e9778795SPeter Avalos #include "match.h" 97e9778795SPeter Avalos #include "ssherr.h" 980cbfa66cSDaniel Fojt #include "sk-api.h" 9918de8d7fSPeter Avalos 10018de8d7fSPeter Avalos #ifdef GSSAPI 10118de8d7fSPeter Avalos static Gssctxt *gsscontext = NULL; 10218de8d7fSPeter Avalos #endif 10318de8d7fSPeter Avalos 10418de8d7fSPeter Avalos /* Imports */ 10518de8d7fSPeter Avalos extern ServerOptions options; 10618de8d7fSPeter Avalos extern u_int utmp_len; 107664f4763Szrj extern struct sshbuf *loginmsg; 108664f4763Szrj extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ 10918de8d7fSPeter Avalos 11018de8d7fSPeter Avalos /* State exported from the child */ 111e9778795SPeter Avalos static struct sshbuf *child_state; 11218de8d7fSPeter Avalos 11318de8d7fSPeter Avalos /* Functions on the monitor that answer unprivileged requests */ 11418de8d7fSPeter Avalos 115664f4763Szrj int mm_answer_moduli(struct ssh *, int, struct sshbuf *); 116664f4763Szrj int mm_answer_sign(struct ssh *, int, struct sshbuf *); 117664f4763Szrj int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *); 118664f4763Szrj int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *); 119664f4763Szrj int mm_answer_authserv(struct ssh *, int, struct sshbuf *); 120664f4763Szrj int mm_answer_authpassword(struct ssh *, int, struct sshbuf *); 121664f4763Szrj int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *); 122664f4763Szrj int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *); 123664f4763Szrj int mm_answer_keyallowed(struct ssh *, int, struct sshbuf *); 124664f4763Szrj int mm_answer_keyverify(struct ssh *, int, struct sshbuf *); 125664f4763Szrj int mm_answer_pty(struct ssh *, int, struct sshbuf *); 126664f4763Szrj int mm_answer_pty_cleanup(struct ssh *, int, struct sshbuf *); 127664f4763Szrj int mm_answer_term(struct ssh *, int, struct sshbuf *); 128664f4763Szrj int mm_answer_rsa_keyallowed(struct ssh *, int, struct sshbuf *); 129664f4763Szrj int mm_answer_rsa_challenge(struct ssh *, int, struct sshbuf *); 130664f4763Szrj int mm_answer_rsa_response(struct ssh *, int, struct sshbuf *); 131664f4763Szrj int mm_answer_sesskey(struct ssh *, int, struct sshbuf *); 132664f4763Szrj int mm_answer_sessid(struct ssh *, int, struct sshbuf *); 13318de8d7fSPeter Avalos 13418de8d7fSPeter Avalos #ifdef USE_PAM 135664f4763Szrj int mm_answer_pam_start(struct ssh *, int, struct sshbuf *); 136664f4763Szrj int mm_answer_pam_account(struct ssh *, int, struct sshbuf *); 137664f4763Szrj int mm_answer_pam_init_ctx(struct ssh *, int, struct sshbuf *); 138664f4763Szrj int mm_answer_pam_query(struct ssh *, int, struct sshbuf *); 139664f4763Szrj int mm_answer_pam_respond(struct ssh *, int, struct sshbuf *); 140664f4763Szrj int mm_answer_pam_free_ctx(struct ssh *, int, struct sshbuf *); 14118de8d7fSPeter Avalos #endif 14218de8d7fSPeter Avalos 14318de8d7fSPeter Avalos #ifdef GSSAPI 144664f4763Szrj int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); 145664f4763Szrj int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *); 146664f4763Szrj int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); 147664f4763Szrj int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); 14818de8d7fSPeter Avalos #endif 14918de8d7fSPeter Avalos 15018de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 151664f4763Szrj int mm_answer_audit_event(struct ssh *, int, struct sshbuf *); 152664f4763Szrj int mm_answer_audit_command(struct ssh *, int, struct sshbuf *); 15318de8d7fSPeter Avalos #endif 15418de8d7fSPeter Avalos 15518de8d7fSPeter Avalos static Authctxt *authctxt; 15636e94dc5SPeter Avalos 15718de8d7fSPeter Avalos /* local state for key verify */ 15818de8d7fSPeter Avalos static u_char *key_blob = NULL; 159664f4763Szrj static size_t key_bloblen = 0; 160*50a69bb5SSascha Wildner static u_int key_blobtype = MM_NOKEY; 161664f4763Szrj static struct sshauthopt *key_opts = NULL; 16218de8d7fSPeter Avalos static char *hostbased_cuser = NULL; 16318de8d7fSPeter Avalos static char *hostbased_chost = NULL; 16418de8d7fSPeter Avalos static char *auth_method = "unknown"; 16536e94dc5SPeter Avalos static char *auth_submethod = NULL; 16618de8d7fSPeter Avalos static u_int session_id2_len = 0; 16718de8d7fSPeter Avalos static u_char *session_id2 = NULL; 16818de8d7fSPeter Avalos static pid_t monitor_child_pid; 16918de8d7fSPeter Avalos 17018de8d7fSPeter Avalos struct mon_table { 17118de8d7fSPeter Avalos enum monitor_reqtype type; 17218de8d7fSPeter Avalos int flags; 173664f4763Szrj int (*f)(struct ssh *, int, struct sshbuf *); 17418de8d7fSPeter Avalos }; 17518de8d7fSPeter Avalos 17618de8d7fSPeter Avalos #define MON_ISAUTH 0x0004 /* Required for Authentication */ 17718de8d7fSPeter Avalos #define MON_AUTHDECIDE 0x0008 /* Decides Authentication */ 17818de8d7fSPeter Avalos #define MON_ONCE 0x0010 /* Disable after calling */ 17918de8d7fSPeter Avalos #define MON_ALOG 0x0020 /* Log auth attempt without authenticating */ 18018de8d7fSPeter Avalos 18118de8d7fSPeter Avalos #define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE) 18218de8d7fSPeter Avalos 18318de8d7fSPeter Avalos #define MON_PERMIT 0x1000 /* Request is permitted */ 18418de8d7fSPeter Avalos 185664f4763Szrj static int monitor_read(struct ssh *, struct monitor *, struct mon_table *, 186664f4763Szrj struct mon_table **); 187664f4763Szrj static int monitor_read_log(struct monitor *); 188664f4763Szrj 18918de8d7fSPeter Avalos struct mon_table mon_dispatch_proto20[] = { 19036e94dc5SPeter Avalos #ifdef WITH_OPENSSL 19118de8d7fSPeter Avalos {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, 19236e94dc5SPeter Avalos #endif 19318de8d7fSPeter Avalos {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, 19418de8d7fSPeter Avalos {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, 19518de8d7fSPeter Avalos {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, 19618de8d7fSPeter Avalos {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, 19718de8d7fSPeter Avalos {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, 19818de8d7fSPeter Avalos #ifdef USE_PAM 19918de8d7fSPeter Avalos {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, 20018de8d7fSPeter Avalos {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, 201ce74bacaSMatthew Dillon {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx}, 202ce74bacaSMatthew Dillon {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query}, 203ce74bacaSMatthew Dillon {MONITOR_REQ_PAM_RESPOND, MON_ONCE, mm_answer_pam_respond}, 20418de8d7fSPeter Avalos {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, 20518de8d7fSPeter Avalos #endif 20618de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 20718de8d7fSPeter Avalos {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, 20818de8d7fSPeter Avalos #endif 20918de8d7fSPeter Avalos #ifdef BSD_AUTH 21018de8d7fSPeter Avalos {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, 21118de8d7fSPeter Avalos {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond}, 21218de8d7fSPeter Avalos #endif 21318de8d7fSPeter Avalos {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, 21418de8d7fSPeter Avalos {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, 21518de8d7fSPeter Avalos #ifdef GSSAPI 21618de8d7fSPeter Avalos {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, 217ce74bacaSMatthew Dillon {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, 218ce74bacaSMatthew Dillon {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, 219ce74bacaSMatthew Dillon {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, 22018de8d7fSPeter Avalos #endif 22118de8d7fSPeter Avalos {0, 0, NULL} 22218de8d7fSPeter Avalos }; 22318de8d7fSPeter Avalos 22418de8d7fSPeter Avalos struct mon_table mon_dispatch_postauth20[] = { 22536e94dc5SPeter Avalos #ifdef WITH_OPENSSL 22618de8d7fSPeter Avalos {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 22736e94dc5SPeter Avalos #endif 22818de8d7fSPeter Avalos {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 22918de8d7fSPeter Avalos {MONITOR_REQ_PTY, 0, mm_answer_pty}, 23018de8d7fSPeter Avalos {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, 23118de8d7fSPeter Avalos {MONITOR_REQ_TERM, 0, mm_answer_term}, 23218de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 23318de8d7fSPeter Avalos {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, 23418de8d7fSPeter Avalos {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, 23518de8d7fSPeter Avalos #endif 23618de8d7fSPeter Avalos {0, 0, NULL} 23718de8d7fSPeter Avalos }; 23818de8d7fSPeter Avalos 23918de8d7fSPeter Avalos struct mon_table *mon_dispatch; 24018de8d7fSPeter Avalos 24118de8d7fSPeter Avalos /* Specifies if a certain message is allowed at the moment */ 24218de8d7fSPeter Avalos static void 24318de8d7fSPeter Avalos monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit) 24418de8d7fSPeter Avalos { 24518de8d7fSPeter Avalos while (ent->f != NULL) { 24618de8d7fSPeter Avalos if (ent->type == type) { 24718de8d7fSPeter Avalos ent->flags &= ~MON_PERMIT; 24818de8d7fSPeter Avalos ent->flags |= permit ? MON_PERMIT : 0; 24918de8d7fSPeter Avalos return; 25018de8d7fSPeter Avalos } 25118de8d7fSPeter Avalos ent++; 25218de8d7fSPeter Avalos } 25318de8d7fSPeter Avalos } 25418de8d7fSPeter Avalos 25518de8d7fSPeter Avalos static void 25618de8d7fSPeter Avalos monitor_permit_authentications(int permit) 25718de8d7fSPeter Avalos { 25818de8d7fSPeter Avalos struct mon_table *ent = mon_dispatch; 25918de8d7fSPeter Avalos 26018de8d7fSPeter Avalos while (ent->f != NULL) { 26118de8d7fSPeter Avalos if (ent->flags & MON_AUTH) { 26218de8d7fSPeter Avalos ent->flags &= ~MON_PERMIT; 26318de8d7fSPeter Avalos ent->flags |= permit ? MON_PERMIT : 0; 26418de8d7fSPeter Avalos } 26518de8d7fSPeter Avalos ent++; 26618de8d7fSPeter Avalos } 26718de8d7fSPeter Avalos } 26818de8d7fSPeter Avalos 26918de8d7fSPeter Avalos void 270664f4763Szrj monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) 27118de8d7fSPeter Avalos { 27218de8d7fSPeter Avalos struct mon_table *ent; 27336e94dc5SPeter Avalos int authenticated = 0, partial = 0; 27418de8d7fSPeter Avalos 27518de8d7fSPeter Avalos debug3("preauth child monitor started"); 27618de8d7fSPeter Avalos 277664f4763Szrj if (pmonitor->m_recvfd >= 0) 2781c188a7fSPeter Avalos close(pmonitor->m_recvfd); 279664f4763Szrj if (pmonitor->m_log_sendfd >= 0) 2801c188a7fSPeter Avalos close(pmonitor->m_log_sendfd); 2811c188a7fSPeter Avalos pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; 2821c188a7fSPeter Avalos 283664f4763Szrj authctxt = (Authctxt *)ssh->authctxt; 28418de8d7fSPeter Avalos memset(authctxt, 0, sizeof(*authctxt)); 285664f4763Szrj ssh->authctxt = authctxt; 28618de8d7fSPeter Avalos 287664f4763Szrj authctxt->loginmsg = loginmsg; 28818de8d7fSPeter Avalos 28918de8d7fSPeter Avalos mon_dispatch = mon_dispatch_proto20; 29018de8d7fSPeter Avalos /* Permit requests for moduli and signatures */ 29118de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 29218de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 29318de8d7fSPeter Avalos 29418de8d7fSPeter Avalos /* The first few requests do not require asynchronous access */ 29518de8d7fSPeter Avalos while (!authenticated) { 29636e94dc5SPeter Avalos partial = 0; 29718de8d7fSPeter Avalos auth_method = "unknown"; 29836e94dc5SPeter Avalos auth_submethod = NULL; 299ce74bacaSMatthew Dillon auth2_authctxt_reset_info(authctxt); 300ce74bacaSMatthew Dillon 301664f4763Szrj authenticated = (monitor_read(ssh, pmonitor, 302664f4763Szrj mon_dispatch, &ent) == 1); 30336e94dc5SPeter Avalos 30436e94dc5SPeter Avalos /* Special handling for multiple required authentications */ 30536e94dc5SPeter Avalos if (options.num_auth_methods != 0) { 30636e94dc5SPeter Avalos if (authenticated && 30736e94dc5SPeter Avalos !auth2_update_methods_lists(authctxt, 30836e94dc5SPeter Avalos auth_method, auth_submethod)) { 309*50a69bb5SSascha Wildner debug3_f("method %s: partial", auth_method); 31036e94dc5SPeter Avalos authenticated = 0; 31136e94dc5SPeter Avalos partial = 1; 31236e94dc5SPeter Avalos } 31336e94dc5SPeter Avalos } 31436e94dc5SPeter Avalos 31518de8d7fSPeter Avalos if (authenticated) { 31618de8d7fSPeter Avalos if (!(ent->flags & MON_AUTHDECIDE)) 317*50a69bb5SSascha Wildner fatal_f("unexpected authentication from %d", 318*50a69bb5SSascha Wildner ent->type); 31918de8d7fSPeter Avalos if (authctxt->pw->pw_uid == 0 && 320664f4763Szrj !auth_root_allowed(ssh, auth_method)) 32118de8d7fSPeter Avalos authenticated = 0; 32218de8d7fSPeter Avalos #ifdef USE_PAM 32318de8d7fSPeter Avalos /* PAM needs to perform account checks after auth */ 32418de8d7fSPeter Avalos if (options.use_pam && authenticated) { 325664f4763Szrj struct sshbuf *m; 32618de8d7fSPeter Avalos 327664f4763Szrj if ((m = sshbuf_new()) == NULL) 328664f4763Szrj fatal("%s: sshbuf_new failed", 329664f4763Szrj __func__); 33018de8d7fSPeter Avalos mm_request_receive_expect(pmonitor->m_sendfd, 331664f4763Szrj MONITOR_REQ_PAM_ACCOUNT, m); 332664f4763Szrj authenticated = mm_answer_pam_account( 333664f4763Szrj ssh, pmonitor->m_sendfd, m); 334664f4763Szrj sshbuf_free(m); 33518de8d7fSPeter Avalos } 33618de8d7fSPeter Avalos #endif 33718de8d7fSPeter Avalos } 33818de8d7fSPeter Avalos if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) { 339664f4763Szrj auth_log(ssh, authenticated, partial, 34036e94dc5SPeter Avalos auth_method, auth_submethod); 341e9778795SPeter Avalos if (!partial && !authenticated) 34218de8d7fSPeter Avalos authctxt->failures++; 343ce74bacaSMatthew Dillon if (authenticated || partial) { 344ce74bacaSMatthew Dillon auth2_update_session_info(authctxt, 345ce74bacaSMatthew Dillon auth_method, auth_submethod); 346ce74bacaSMatthew Dillon } 34718de8d7fSPeter Avalos } 348cb5eb4f1SPeter Avalos } 3491c188a7fSPeter Avalos 35018de8d7fSPeter Avalos if (!authctxt->valid) 351*50a69bb5SSascha Wildner fatal_f("authenticated invalid user"); 35218de8d7fSPeter Avalos if (strcmp(auth_method, "unknown") == 0) 353*50a69bb5SSascha Wildner fatal_f("authentication method name unknown"); 35418de8d7fSPeter Avalos 355*50a69bb5SSascha Wildner debug_f("user %s authenticated by privileged process", authctxt->user); 356664f4763Szrj ssh->authctxt = NULL; 357ce74bacaSMatthew Dillon ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); 35818de8d7fSPeter Avalos 359664f4763Szrj mm_get_keystate(ssh, pmonitor); 3601c188a7fSPeter Avalos 36136e94dc5SPeter Avalos /* Drain any buffered messages from the child */ 36236e94dc5SPeter Avalos while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) 36336e94dc5SPeter Avalos ; 36436e94dc5SPeter Avalos 365664f4763Szrj if (pmonitor->m_recvfd >= 0) 366664f4763Szrj close(pmonitor->m_recvfd); 367664f4763Szrj if (pmonitor->m_log_sendfd >= 0) 368664f4763Szrj close(pmonitor->m_log_sendfd); 3691c188a7fSPeter Avalos pmonitor->m_sendfd = pmonitor->m_log_recvfd = -1; 37018de8d7fSPeter Avalos } 37118de8d7fSPeter Avalos 37218de8d7fSPeter Avalos static void 37318de8d7fSPeter Avalos monitor_set_child_handler(pid_t pid) 37418de8d7fSPeter Avalos { 37518de8d7fSPeter Avalos monitor_child_pid = pid; 37618de8d7fSPeter Avalos } 37718de8d7fSPeter Avalos 37818de8d7fSPeter Avalos static void 37918de8d7fSPeter Avalos monitor_child_handler(int sig) 38018de8d7fSPeter Avalos { 38118de8d7fSPeter Avalos kill(monitor_child_pid, sig); 38218de8d7fSPeter Avalos } 38318de8d7fSPeter Avalos 38418de8d7fSPeter Avalos void 385664f4763Szrj monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) 38618de8d7fSPeter Avalos { 3871c188a7fSPeter Avalos close(pmonitor->m_recvfd); 3881c188a7fSPeter Avalos pmonitor->m_recvfd = -1; 3891c188a7fSPeter Avalos 39018de8d7fSPeter Avalos monitor_set_child_handler(pmonitor->m_pid); 3910cbfa66cSDaniel Fojt ssh_signal(SIGHUP, &monitor_child_handler); 3920cbfa66cSDaniel Fojt ssh_signal(SIGTERM, &monitor_child_handler); 3930cbfa66cSDaniel Fojt ssh_signal(SIGINT, &monitor_child_handler); 39436e94dc5SPeter Avalos #ifdef SIGXFSZ 3950cbfa66cSDaniel Fojt ssh_signal(SIGXFSZ, SIG_IGN); 39636e94dc5SPeter Avalos #endif 39718de8d7fSPeter Avalos 39818de8d7fSPeter Avalos mon_dispatch = mon_dispatch_postauth20; 39918de8d7fSPeter Avalos 40018de8d7fSPeter Avalos /* Permit requests for moduli and signatures */ 40118de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 40218de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 40318de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 404ce74bacaSMatthew Dillon 405664f4763Szrj if (auth_opts->permit_pty_flag) { 40618de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); 40718de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); 40818de8d7fSPeter Avalos } 40918de8d7fSPeter Avalos 41018de8d7fSPeter Avalos for (;;) 411664f4763Szrj monitor_read(ssh, pmonitor, mon_dispatch, NULL); 41218de8d7fSPeter Avalos } 41318de8d7fSPeter Avalos 4141c188a7fSPeter Avalos static int 4151c188a7fSPeter Avalos monitor_read_log(struct monitor *pmonitor) 4161c188a7fSPeter Avalos { 417664f4763Szrj struct sshbuf *logmsg; 418*50a69bb5SSascha Wildner u_int len, level, forced; 4191c188a7fSPeter Avalos char *msg; 420664f4763Szrj u_char *p; 421664f4763Szrj int r; 4221c188a7fSPeter Avalos 423664f4763Szrj if ((logmsg = sshbuf_new()) == NULL) 424*50a69bb5SSascha Wildner fatal_f("sshbuf_new"); 4251c188a7fSPeter Avalos 4261c188a7fSPeter Avalos /* Read length */ 427664f4763Szrj if ((r = sshbuf_reserve(logmsg, 4, &p)) != 0) 428*50a69bb5SSascha Wildner fatal_fr(r, "reserve len"); 429664f4763Szrj if (atomicio(read, pmonitor->m_log_recvfd, p, 4) != 4) { 4301c188a7fSPeter Avalos if (errno == EPIPE) { 431664f4763Szrj sshbuf_free(logmsg); 432*50a69bb5SSascha Wildner debug_f("child log fd closed"); 4331c188a7fSPeter Avalos close(pmonitor->m_log_recvfd); 4341c188a7fSPeter Avalos pmonitor->m_log_recvfd = -1; 4351c188a7fSPeter Avalos return -1; 4361c188a7fSPeter Avalos } 437*50a69bb5SSascha Wildner fatal_f("log fd read: %s", strerror(errno)); 4381c188a7fSPeter Avalos } 439664f4763Szrj if ((r = sshbuf_get_u32(logmsg, &len)) != 0) 440*50a69bb5SSascha Wildner fatal_fr(r, "parse len"); 4411c188a7fSPeter Avalos if (len <= 4 || len > 8192) 442*50a69bb5SSascha Wildner fatal_f("invalid log message length %u", len); 4431c188a7fSPeter Avalos 4441c188a7fSPeter Avalos /* Read severity, message */ 445664f4763Szrj sshbuf_reset(logmsg); 446664f4763Szrj if ((r = sshbuf_reserve(logmsg, len, &p)) != 0) 447*50a69bb5SSascha Wildner fatal_fr(r, "reserve msg"); 448664f4763Szrj if (atomicio(read, pmonitor->m_log_recvfd, p, len) != len) 449*50a69bb5SSascha Wildner fatal_f("log fd read: %s", strerror(errno)); 450664f4763Szrj if ((r = sshbuf_get_u32(logmsg, &level)) != 0 || 451*50a69bb5SSascha Wildner (r = sshbuf_get_u32(logmsg, &forced)) != 0 || 452664f4763Szrj (r = sshbuf_get_cstring(logmsg, &msg, NULL)) != 0) 453*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 4541c188a7fSPeter Avalos 4551c188a7fSPeter Avalos /* Log it */ 4561c188a7fSPeter Avalos if (log_level_name(level) == NULL) 457*50a69bb5SSascha Wildner fatal_f("invalid log level %u (corrupted message?)", level); 458*50a69bb5SSascha Wildner sshlogdirect(level, forced, "%s [preauth]", msg); 4591c188a7fSPeter Avalos 460664f4763Szrj sshbuf_free(logmsg); 46136e94dc5SPeter Avalos free(msg); 4621c188a7fSPeter Avalos 4631c188a7fSPeter Avalos return 0; 4641c188a7fSPeter Avalos } 4651c188a7fSPeter Avalos 466664f4763Szrj static int 467664f4763Szrj monitor_read(struct ssh *ssh, struct monitor *pmonitor, struct mon_table *ent, 46818de8d7fSPeter Avalos struct mon_table **pent) 46918de8d7fSPeter Avalos { 470664f4763Szrj struct sshbuf *m; 471664f4763Szrj int r, ret; 47218de8d7fSPeter Avalos u_char type; 4731c188a7fSPeter Avalos struct pollfd pfd[2]; 4741c188a7fSPeter Avalos 4751c188a7fSPeter Avalos for (;;) { 47636e94dc5SPeter Avalos memset(&pfd, 0, sizeof(pfd)); 4771c188a7fSPeter Avalos pfd[0].fd = pmonitor->m_sendfd; 4781c188a7fSPeter Avalos pfd[0].events = POLLIN; 4791c188a7fSPeter Avalos pfd[1].fd = pmonitor->m_log_recvfd; 4801c188a7fSPeter Avalos pfd[1].events = pfd[1].fd == -1 ? 0 : POLLIN; 4811c188a7fSPeter Avalos if (poll(pfd, pfd[1].fd == -1 ? 1 : 2, -1) == -1) { 4821c188a7fSPeter Avalos if (errno == EINTR || errno == EAGAIN) 4831c188a7fSPeter Avalos continue; 484*50a69bb5SSascha Wildner fatal_f("poll: %s", strerror(errno)); 4851c188a7fSPeter Avalos } 4861c188a7fSPeter Avalos if (pfd[1].revents) { 4871c188a7fSPeter Avalos /* 4881c188a7fSPeter Avalos * Drain all log messages before processing next 4891c188a7fSPeter Avalos * monitor request. 4901c188a7fSPeter Avalos */ 4911c188a7fSPeter Avalos monitor_read_log(pmonitor); 4921c188a7fSPeter Avalos continue; 4931c188a7fSPeter Avalos } 4941c188a7fSPeter Avalos if (pfd[0].revents) 4951c188a7fSPeter Avalos break; /* Continues below */ 4961c188a7fSPeter Avalos } 49718de8d7fSPeter Avalos 498664f4763Szrj if ((m = sshbuf_new()) == NULL) 499*50a69bb5SSascha Wildner fatal_f("sshbuf_new"); 50018de8d7fSPeter Avalos 501664f4763Szrj mm_request_receive(pmonitor->m_sendfd, m); 502664f4763Szrj if ((r = sshbuf_get_u8(m, &type)) != 0) 503*50a69bb5SSascha Wildner fatal_fr(r, "parse type"); 50418de8d7fSPeter Avalos 505*50a69bb5SSascha Wildner debug3_f("checking request %d", type); 50618de8d7fSPeter Avalos 50718de8d7fSPeter Avalos while (ent->f != NULL) { 50818de8d7fSPeter Avalos if (ent->type == type) 50918de8d7fSPeter Avalos break; 51018de8d7fSPeter Avalos ent++; 51118de8d7fSPeter Avalos } 51218de8d7fSPeter Avalos 51318de8d7fSPeter Avalos if (ent->f != NULL) { 51418de8d7fSPeter Avalos if (!(ent->flags & MON_PERMIT)) 515*50a69bb5SSascha Wildner fatal_f("unpermitted request %d", type); 516664f4763Szrj ret = (*ent->f)(ssh, pmonitor->m_sendfd, m); 517664f4763Szrj sshbuf_free(m); 51818de8d7fSPeter Avalos 51918de8d7fSPeter Avalos /* The child may use this request only once, disable it */ 52018de8d7fSPeter Avalos if (ent->flags & MON_ONCE) { 521*50a69bb5SSascha Wildner debug2_f("%d used once, disabling now", type); 52218de8d7fSPeter Avalos ent->flags &= ~MON_PERMIT; 52318de8d7fSPeter Avalos } 52418de8d7fSPeter Avalos 52518de8d7fSPeter Avalos if (pent != NULL) 52618de8d7fSPeter Avalos *pent = ent; 52718de8d7fSPeter Avalos 52818de8d7fSPeter Avalos return ret; 52918de8d7fSPeter Avalos } 53018de8d7fSPeter Avalos 531*50a69bb5SSascha Wildner fatal_f("unsupported request: %d", type); 53218de8d7fSPeter Avalos 53318de8d7fSPeter Avalos /* NOTREACHED */ 53418de8d7fSPeter Avalos return (-1); 53518de8d7fSPeter Avalos } 53618de8d7fSPeter Avalos 53718de8d7fSPeter Avalos /* allowed key state */ 53818de8d7fSPeter Avalos static int 5390cbfa66cSDaniel Fojt monitor_allowed_key(const u_char *blob, u_int bloblen) 54018de8d7fSPeter Avalos { 54118de8d7fSPeter Avalos /* make sure key is allowed */ 54218de8d7fSPeter Avalos if (key_blob == NULL || key_bloblen != bloblen || 543856ea928SPeter Avalos timingsafe_bcmp(key_blob, blob, key_bloblen)) 54418de8d7fSPeter Avalos return (0); 54518de8d7fSPeter Avalos return (1); 54618de8d7fSPeter Avalos } 54718de8d7fSPeter Avalos 54818de8d7fSPeter Avalos static void 54918de8d7fSPeter Avalos monitor_reset_key_state(void) 55018de8d7fSPeter Avalos { 55118de8d7fSPeter Avalos /* reset state */ 55236e94dc5SPeter Avalos free(key_blob); 55336e94dc5SPeter Avalos free(hostbased_cuser); 55436e94dc5SPeter Avalos free(hostbased_chost); 555664f4763Szrj sshauthopt_free(key_opts); 55618de8d7fSPeter Avalos key_blob = NULL; 55718de8d7fSPeter Avalos key_bloblen = 0; 55818de8d7fSPeter Avalos key_blobtype = MM_NOKEY; 559664f4763Szrj key_opts = NULL; 56018de8d7fSPeter Avalos hostbased_cuser = NULL; 56118de8d7fSPeter Avalos hostbased_chost = NULL; 56218de8d7fSPeter Avalos } 56318de8d7fSPeter Avalos 56436e94dc5SPeter Avalos #ifdef WITH_OPENSSL 56518de8d7fSPeter Avalos int 566664f4763Szrj mm_answer_moduli(struct ssh *ssh, int sock, struct sshbuf *m) 56718de8d7fSPeter Avalos { 56818de8d7fSPeter Avalos DH *dh; 569664f4763Szrj const BIGNUM *dh_p, *dh_g; 570664f4763Szrj int r; 571664f4763Szrj u_int min, want, max; 57218de8d7fSPeter Avalos 573664f4763Szrj if ((r = sshbuf_get_u32(m, &min)) != 0 || 574664f4763Szrj (r = sshbuf_get_u32(m, &want)) != 0 || 575664f4763Szrj (r = sshbuf_get_u32(m, &max)) != 0) 576*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 57718de8d7fSPeter Avalos 578*50a69bb5SSascha Wildner debug3_f("got parameters: %d %d %d", min, want, max); 57918de8d7fSPeter Avalos /* We need to check here, too, in case the child got corrupted */ 58018de8d7fSPeter Avalos if (max < min || want < min || max < want) 581*50a69bb5SSascha Wildner fatal_f("bad parameters: %d %d %d", min, want, max); 58218de8d7fSPeter Avalos 583664f4763Szrj sshbuf_reset(m); 58418de8d7fSPeter Avalos 58518de8d7fSPeter Avalos dh = choose_dh(min, want, max); 58618de8d7fSPeter Avalos if (dh == NULL) { 587664f4763Szrj if ((r = sshbuf_put_u8(m, 0)) != 0) 588*50a69bb5SSascha Wildner fatal_fr(r, "assemble empty"); 58918de8d7fSPeter Avalos return (0); 59018de8d7fSPeter Avalos } else { 59118de8d7fSPeter Avalos /* Send first bignum */ 592664f4763Szrj DH_get0_pqg(dh, &dh_p, NULL, &dh_g); 593664f4763Szrj if ((r = sshbuf_put_u8(m, 1)) != 0 || 594664f4763Szrj (r = sshbuf_put_bignum2(m, dh_p)) != 0 || 595664f4763Szrj (r = sshbuf_put_bignum2(m, dh_g)) != 0) 596*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 59718de8d7fSPeter Avalos 59818de8d7fSPeter Avalos DH_free(dh); 59918de8d7fSPeter Avalos } 60018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_MODULI, m); 60118de8d7fSPeter Avalos return (0); 60218de8d7fSPeter Avalos } 60336e94dc5SPeter Avalos #endif 60436e94dc5SPeter Avalos 60518de8d7fSPeter Avalos int 606664f4763Szrj mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) 60718de8d7fSPeter Avalos { 608e9778795SPeter Avalos extern int auth_sock; /* XXX move to state struct? */ 609e9778795SPeter Avalos struct sshkey *key; 610e9778795SPeter Avalos struct sshbuf *sigbuf = NULL; 611e9778795SPeter Avalos u_char *p = NULL, *signature = NULL; 612e9778795SPeter Avalos char *alg = NULL; 613e9778795SPeter Avalos size_t datlen, siglen, alglen; 614e9778795SPeter Avalos int r, is_proof = 0; 615664f4763Szrj u_int keyid, compat; 616e9778795SPeter Avalos const char proof_req[] = "hostkeys-prove-00@openssh.com"; 61718de8d7fSPeter Avalos 618*50a69bb5SSascha Wildner debug3_f("entering"); 61918de8d7fSPeter Avalos 620e9778795SPeter Avalos if ((r = sshbuf_get_u32(m, &keyid)) != 0 || 621e9778795SPeter Avalos (r = sshbuf_get_string(m, &p, &datlen)) != 0 || 622664f4763Szrj (r = sshbuf_get_cstring(m, &alg, &alglen)) != 0 || 623664f4763Szrj (r = sshbuf_get_u32(m, &compat)) != 0) 624*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 625e9778795SPeter Avalos if (keyid > INT_MAX) 626*50a69bb5SSascha Wildner fatal_f("invalid key ID"); 62718de8d7fSPeter Avalos 62818de8d7fSPeter Avalos /* 6299f304aafSPeter Avalos * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), 6309f304aafSPeter Avalos * SHA384 (48 bytes) and SHA512 (64 bytes). 631e9778795SPeter Avalos * 632e9778795SPeter Avalos * Otherwise, verify the signature request is for a hostkey 633e9778795SPeter Avalos * proof. 634e9778795SPeter Avalos * 635e9778795SPeter Avalos * XXX perform similar check for KEX signature requests too? 636e9778795SPeter Avalos * it's not trivial, since what is signed is the hash, rather 637e9778795SPeter Avalos * than the full kex structure... 63818de8d7fSPeter Avalos */ 639e9778795SPeter Avalos if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) { 640e9778795SPeter Avalos /* 641e9778795SPeter Avalos * Construct expected hostkey proof and compare it to what 642e9778795SPeter Avalos * the client sent us. 643e9778795SPeter Avalos */ 644e9778795SPeter Avalos if (session_id2_len == 0) /* hostkeys is never first */ 645*50a69bb5SSascha Wildner fatal_f("bad data length: %zu", datlen); 646e9778795SPeter Avalos if ((key = get_hostkey_public_by_index(keyid, ssh)) == NULL) 647*50a69bb5SSascha Wildner fatal_f("no hostkey for index %d", keyid); 648e9778795SPeter Avalos if ((sigbuf = sshbuf_new()) == NULL) 649*50a69bb5SSascha Wildner fatal_f("sshbuf_new"); 650e9778795SPeter Avalos if ((r = sshbuf_put_cstring(sigbuf, proof_req)) != 0 || 651e9778795SPeter Avalos (r = sshbuf_put_string(sigbuf, session_id2, 652e9778795SPeter Avalos session_id2_len)) != 0 || 653e9778795SPeter Avalos (r = sshkey_puts(key, sigbuf)) != 0) 654*50a69bb5SSascha Wildner fatal_fr(r, "assemble private key proof"); 655e9778795SPeter Avalos if (datlen != sshbuf_len(sigbuf) || 656e9778795SPeter Avalos memcmp(p, sshbuf_ptr(sigbuf), sshbuf_len(sigbuf)) != 0) 657*50a69bb5SSascha Wildner fatal_f("bad data length: %zu, hostkey proof len %zu", 658*50a69bb5SSascha Wildner datlen, sshbuf_len(sigbuf)); 659e9778795SPeter Avalos sshbuf_free(sigbuf); 660e9778795SPeter Avalos is_proof = 1; 661e9778795SPeter Avalos } 66218de8d7fSPeter Avalos 66318de8d7fSPeter Avalos /* save session id, it will be passed on the first call */ 66418de8d7fSPeter Avalos if (session_id2_len == 0) { 66518de8d7fSPeter Avalos session_id2_len = datlen; 66618de8d7fSPeter Avalos session_id2 = xmalloc(session_id2_len); 66718de8d7fSPeter Avalos memcpy(session_id2, p, session_id2_len); 66818de8d7fSPeter Avalos } 66918de8d7fSPeter Avalos 67036e94dc5SPeter Avalos if ((key = get_hostkey_by_index(keyid)) != NULL) { 671e9778795SPeter Avalos if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, 672*50a69bb5SSascha Wildner options.sk_provider, NULL, compat)) != 0) 673*50a69bb5SSascha Wildner fatal_fr(r, "sign"); 674e9778795SPeter Avalos } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && 675e9778795SPeter Avalos auth_sock > 0) { 676e9778795SPeter Avalos if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, 677*50a69bb5SSascha Wildner p, datlen, alg, compat)) != 0) 678*50a69bb5SSascha Wildner fatal_fr(r, "agent sign"); 67936e94dc5SPeter Avalos } else 680*50a69bb5SSascha Wildner fatal_f("no hostkey from index %d", keyid); 68118de8d7fSPeter Avalos 682*50a69bb5SSascha Wildner debug3_f("%s %s signature len=%zu", alg, 683*50a69bb5SSascha Wildner is_proof ? "hostkey proof" : "KEX", siglen); 68418de8d7fSPeter Avalos 685e9778795SPeter Avalos sshbuf_reset(m); 686e9778795SPeter Avalos if ((r = sshbuf_put_string(m, signature, siglen)) != 0) 687*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 68818de8d7fSPeter Avalos 689e9778795SPeter Avalos free(alg); 69036e94dc5SPeter Avalos free(p); 69136e94dc5SPeter Avalos free(signature); 69218de8d7fSPeter Avalos 69318de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_SIGN, m); 69418de8d7fSPeter Avalos 69518de8d7fSPeter Avalos /* Turn on permissions for getpwnam */ 69618de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); 69718de8d7fSPeter Avalos 69818de8d7fSPeter Avalos return (0); 69918de8d7fSPeter Avalos } 70018de8d7fSPeter Avalos 701*50a69bb5SSascha Wildner #define PUTPW(b, id) \ 702*50a69bb5SSascha Wildner do { \ 703*50a69bb5SSascha Wildner if ((r = sshbuf_put_string(b, \ 704*50a69bb5SSascha Wildner &pwent->id, sizeof(pwent->id))) != 0) \ 705*50a69bb5SSascha Wildner fatal_fr(r, "assemble %s", #id); \ 706*50a69bb5SSascha Wildner } while (0) 70718de8d7fSPeter Avalos 708*50a69bb5SSascha Wildner /* Retrieves the password entry and also checks if the user is permitted */ 70918de8d7fSPeter Avalos int 710664f4763Szrj mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m) 71118de8d7fSPeter Avalos { 71218de8d7fSPeter Avalos char *username; 71318de8d7fSPeter Avalos struct passwd *pwent; 714664f4763Szrj int r, allowed = 0; 7151c188a7fSPeter Avalos u_int i; 71618de8d7fSPeter Avalos 717*50a69bb5SSascha Wildner debug3_f("entering"); 71818de8d7fSPeter Avalos 71918de8d7fSPeter Avalos if (authctxt->attempt++ != 0) 720*50a69bb5SSascha Wildner fatal_f("multiple attempts for getpwnam"); 72118de8d7fSPeter Avalos 722664f4763Szrj if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) 723*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 72418de8d7fSPeter Avalos 725664f4763Szrj pwent = getpwnamallow(ssh, username); 72618de8d7fSPeter Avalos 72718de8d7fSPeter Avalos authctxt->user = xstrdup(username); 72818de8d7fSPeter Avalos setproctitle("%s [priv]", pwent ? username : "unknown"); 72936e94dc5SPeter Avalos free(username); 73018de8d7fSPeter Avalos 731664f4763Szrj sshbuf_reset(m); 73218de8d7fSPeter Avalos 73318de8d7fSPeter Avalos if (pwent == NULL) { 734664f4763Szrj if ((r = sshbuf_put_u8(m, 0)) != 0) 735*50a69bb5SSascha Wildner fatal_fr(r, "assemble fakepw"); 73618de8d7fSPeter Avalos authctxt->pw = fakepw(); 73718de8d7fSPeter Avalos goto out; 73818de8d7fSPeter Avalos } 73918de8d7fSPeter Avalos 74018de8d7fSPeter Avalos allowed = 1; 74118de8d7fSPeter Avalos authctxt->pw = pwent; 74218de8d7fSPeter Avalos authctxt->valid = 1; 74318de8d7fSPeter Avalos 744*50a69bb5SSascha Wildner /* XXX send fake class/dir/shell, etc. */ 745*50a69bb5SSascha Wildner if ((r = sshbuf_put_u8(m, 1)) != 0) 746*50a69bb5SSascha Wildner fatal_fr(r, "assemble ok"); 747*50a69bb5SSascha Wildner PUTPW(m, pw_uid); 748*50a69bb5SSascha Wildner PUTPW(m, pw_gid); 749*50a69bb5SSascha Wildner #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE 750*50a69bb5SSascha Wildner PUTPW(m, pw_change); 751*50a69bb5SSascha Wildner #endif 752*50a69bb5SSascha Wildner #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE 753*50a69bb5SSascha Wildner PUTPW(m, pw_expire); 754*50a69bb5SSascha Wildner #endif 755*50a69bb5SSascha Wildner if ((r = sshbuf_put_cstring(m, pwent->pw_name)) != 0 || 756664f4763Szrj (r = sshbuf_put_cstring(m, "*")) != 0 || 75736e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS 758664f4763Szrj (r = sshbuf_put_cstring(m, pwent->pw_gecos)) != 0 || 75936e94dc5SPeter Avalos #endif 76036e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS 761664f4763Szrj (r = sshbuf_put_cstring(m, pwent->pw_class)) != 0 || 76218de8d7fSPeter Avalos #endif 763664f4763Szrj (r = sshbuf_put_cstring(m, pwent->pw_dir)) != 0 || 764664f4763Szrj (r = sshbuf_put_cstring(m, pwent->pw_shell)) != 0) 765*50a69bb5SSascha Wildner fatal_fr(r, "assemble pw"); 76618de8d7fSPeter Avalos 76718de8d7fSPeter Avalos out: 768ce74bacaSMatthew Dillon ssh_packet_set_log_preamble(ssh, "%suser %s", 769ce74bacaSMatthew Dillon authctxt->valid ? "authenticating" : "invalid ", authctxt->user); 770664f4763Szrj if ((r = sshbuf_put_string(m, &options, sizeof(options))) != 0) 771*50a69bb5SSascha Wildner fatal_fr(r, "assemble options"); 7721c188a7fSPeter Avalos 7731c188a7fSPeter Avalos #define M_CP_STROPT(x) do { \ 774*50a69bb5SSascha Wildner if (options.x != NULL && \ 775*50a69bb5SSascha Wildner (r = sshbuf_put_cstring(m, options.x)) != 0) \ 776*50a69bb5SSascha Wildner fatal_fr(r, "assemble %s", #x); \ 7771c188a7fSPeter Avalos } while (0) 7781c188a7fSPeter Avalos #define M_CP_STRARRAYOPT(x, nx) do { \ 779664f4763Szrj for (i = 0; i < options.nx; i++) { \ 780664f4763Szrj if ((r = sshbuf_put_cstring(m, options.x[i])) != 0) \ 781*50a69bb5SSascha Wildner fatal_fr(r, "assemble %s", #x); \ 782664f4763Szrj } \ 7831c188a7fSPeter Avalos } while (0) 7841c188a7fSPeter Avalos /* See comment in servconf.h */ 7851c188a7fSPeter Avalos COPY_MATCH_STRING_OPTS(); 7861c188a7fSPeter Avalos #undef M_CP_STROPT 7871c188a7fSPeter Avalos #undef M_CP_STRARRAYOPT 7881c188a7fSPeter Avalos 78936e94dc5SPeter Avalos /* Create valid auth method lists */ 790ce74bacaSMatthew Dillon if (auth2_setup_methods_lists(authctxt) != 0) { 79136e94dc5SPeter Avalos /* 79236e94dc5SPeter Avalos * The monitor will continue long enough to let the child 79336e94dc5SPeter Avalos * run to it's packet_disconnect(), but it must not allow any 79436e94dc5SPeter Avalos * authentication to succeed. 79536e94dc5SPeter Avalos */ 796*50a69bb5SSascha Wildner debug_f("no valid authentication method lists"); 79736e94dc5SPeter Avalos } 79836e94dc5SPeter Avalos 799*50a69bb5SSascha Wildner debug3_f("sending MONITOR_ANS_PWNAM: %d", allowed); 80018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PWNAM, m); 80118de8d7fSPeter Avalos 80218de8d7fSPeter Avalos /* Allow service/style information on the auth context */ 80318de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); 80418de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); 805ce74bacaSMatthew Dillon 80618de8d7fSPeter Avalos #ifdef USE_PAM 80718de8d7fSPeter Avalos if (options.use_pam) 80818de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1); 80918de8d7fSPeter Avalos #endif 81018de8d7fSPeter Avalos 81118de8d7fSPeter Avalos return (0); 81218de8d7fSPeter Avalos } 81318de8d7fSPeter Avalos 814664f4763Szrj int mm_answer_auth2_read_banner(struct ssh *ssh, int sock, struct sshbuf *m) 81518de8d7fSPeter Avalos { 81618de8d7fSPeter Avalos char *banner; 817664f4763Szrj int r; 81818de8d7fSPeter Avalos 819664f4763Szrj sshbuf_reset(m); 82018de8d7fSPeter Avalos banner = auth2_read_banner(); 821664f4763Szrj if ((r = sshbuf_put_cstring(m, banner != NULL ? banner : "")) != 0) 822*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 82318de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m); 82436e94dc5SPeter Avalos free(banner); 82518de8d7fSPeter Avalos 82618de8d7fSPeter Avalos return (0); 82718de8d7fSPeter Avalos } 82818de8d7fSPeter Avalos 82918de8d7fSPeter Avalos int 830664f4763Szrj mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m) 83118de8d7fSPeter Avalos { 832664f4763Szrj int r; 833664f4763Szrj 83418de8d7fSPeter Avalos monitor_permit_authentications(1); 83518de8d7fSPeter Avalos 836664f4763Szrj if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 || 837664f4763Szrj (r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0) 838*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 839*50a69bb5SSascha Wildner debug3_f("service=%s, style=%s", authctxt->service, authctxt->style); 84018de8d7fSPeter Avalos 84118de8d7fSPeter Avalos if (strlen(authctxt->style) == 0) { 84236e94dc5SPeter Avalos free(authctxt->style); 84318de8d7fSPeter Avalos authctxt->style = NULL; 84418de8d7fSPeter Avalos } 84518de8d7fSPeter Avalos 84618de8d7fSPeter Avalos return (0); 84718de8d7fSPeter Avalos } 84818de8d7fSPeter Avalos 849664f4763Szrj /* 850664f4763Szrj * Check that the key type appears in the supplied pattern list, ignoring 851664f4763Szrj * mismatches in the signature algorithm. (Signature algorithm checks are 852664f4763Szrj * performed in the unprivileged authentication code). 853664f4763Szrj * Returns 1 on success, 0 otherwise. 854664f4763Szrj */ 855664f4763Szrj static int 856664f4763Szrj key_base_type_match(const char *method, const struct sshkey *key, 857664f4763Szrj const char *list) 858664f4763Szrj { 859664f4763Szrj char *s, *l, *ol = xstrdup(list); 860664f4763Szrj int found = 0; 861664f4763Szrj 862664f4763Szrj l = ol; 863664f4763Szrj for ((s = strsep(&l, ",")); s && *s != '\0'; (s = strsep(&l, ","))) { 864664f4763Szrj if (sshkey_type_from_name(s) == key->type) { 865664f4763Szrj found = 1; 866664f4763Szrj break; 867664f4763Szrj } 868664f4763Szrj } 869664f4763Szrj if (!found) { 870664f4763Szrj error("%s key type %s is not in permitted list %s", method, 871664f4763Szrj sshkey_ssh_name(key), list); 872664f4763Szrj } 873664f4763Szrj 874664f4763Szrj free(ol); 875664f4763Szrj return found; 876664f4763Szrj } 877664f4763Szrj 87818de8d7fSPeter Avalos int 879664f4763Szrj mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m) 88018de8d7fSPeter Avalos { 88118de8d7fSPeter Avalos static int call_count; 88218de8d7fSPeter Avalos char *passwd; 883664f4763Szrj int r, authenticated; 884664f4763Szrj size_t plen; 88518de8d7fSPeter Avalos 886ce74bacaSMatthew Dillon if (!options.password_authentication) 887*50a69bb5SSascha Wildner fatal_f("password authentication not enabled"); 888664f4763Szrj if ((r = sshbuf_get_cstring(m, &passwd, &plen)) != 0) 889*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 89018de8d7fSPeter Avalos /* Only authenticate if the context is valid */ 89118de8d7fSPeter Avalos authenticated = options.password_authentication && 892664f4763Szrj auth_password(ssh, passwd); 8930cbfa66cSDaniel Fojt freezero(passwd, plen); 89418de8d7fSPeter Avalos 895664f4763Szrj sshbuf_reset(m); 896664f4763Szrj if ((r = sshbuf_put_u32(m, authenticated)) != 0) 897*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 898e9778795SPeter Avalos #ifdef USE_PAM 899664f4763Szrj if ((r = sshbuf_put_u32(m, sshpam_get_maxtries_reached())) != 0) 900*50a69bb5SSascha Wildner fatal_fr(r, "assemble PAM"); 901e9778795SPeter Avalos #endif 90218de8d7fSPeter Avalos 90318de8d7fSPeter Avalos debug3("%s: sending result %d", __func__, authenticated); 904*50a69bb5SSascha Wildner debug3_f("sending result %d", authenticated); 90518de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m); 90618de8d7fSPeter Avalos 90718de8d7fSPeter Avalos call_count++; 90818de8d7fSPeter Avalos if (plen == 0 && call_count == 1) 90918de8d7fSPeter Avalos auth_method = "none"; 91018de8d7fSPeter Avalos else 91118de8d7fSPeter Avalos auth_method = "password"; 91218de8d7fSPeter Avalos 91318de8d7fSPeter Avalos /* Causes monitor loop to terminate if authenticated */ 91418de8d7fSPeter Avalos return (authenticated); 91518de8d7fSPeter Avalos } 91618de8d7fSPeter Avalos 91718de8d7fSPeter Avalos #ifdef BSD_AUTH 91818de8d7fSPeter Avalos int 919664f4763Szrj mm_answer_bsdauthquery(struct ssh *ssh, int sock, struct sshbuf *m) 92018de8d7fSPeter Avalos { 92118de8d7fSPeter Avalos char *name, *infotxt; 922664f4763Szrj u_int numprompts, *echo_on, success; 92318de8d7fSPeter Avalos char **prompts; 924664f4763Szrj int r; 92518de8d7fSPeter Avalos 926ce74bacaSMatthew Dillon if (!options.kbd_interactive_authentication) 927*50a69bb5SSascha Wildner fatal_f("kbd-int authentication not enabled"); 92818de8d7fSPeter Avalos success = bsdauth_query(authctxt, &name, &infotxt, &numprompts, 92918de8d7fSPeter Avalos &prompts, &echo_on) < 0 ? 0 : 1; 93018de8d7fSPeter Avalos 931664f4763Szrj sshbuf_reset(m); 932664f4763Szrj if ((r = sshbuf_put_u32(m, success)) != 0) 933*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 934664f4763Szrj if (success) { 935664f4763Szrj if ((r = sshbuf_put_cstring(m, prompts[0])) != 0) 936*50a69bb5SSascha Wildner fatal_fr(r, "assemble prompt"); 937664f4763Szrj } 93818de8d7fSPeter Avalos 939*50a69bb5SSascha Wildner debug3_f("sending challenge success: %u", success); 94018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m); 94118de8d7fSPeter Avalos 94218de8d7fSPeter Avalos if (success) { 94336e94dc5SPeter Avalos free(name); 94436e94dc5SPeter Avalos free(infotxt); 94536e94dc5SPeter Avalos free(prompts); 94636e94dc5SPeter Avalos free(echo_on); 94718de8d7fSPeter Avalos } 94818de8d7fSPeter Avalos 94918de8d7fSPeter Avalos return (0); 95018de8d7fSPeter Avalos } 95118de8d7fSPeter Avalos 95218de8d7fSPeter Avalos int 953664f4763Szrj mm_answer_bsdauthrespond(struct ssh *ssh, int sock, struct sshbuf *m) 95418de8d7fSPeter Avalos { 95518de8d7fSPeter Avalos char *response; 956664f4763Szrj int r, authok; 95718de8d7fSPeter Avalos 958ce74bacaSMatthew Dillon if (!options.kbd_interactive_authentication) 959*50a69bb5SSascha Wildner fatal_f("kbd-int authentication not enabled"); 960e9778795SPeter Avalos if (authctxt->as == NULL) 961*50a69bb5SSascha Wildner fatal_f("no bsd auth session"); 96218de8d7fSPeter Avalos 963664f4763Szrj if ((r = sshbuf_get_cstring(m, &response, NULL)) != 0) 964*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 965*50a69bb5SSascha Wildner authok = options.kbd_interactive_authentication && 96618de8d7fSPeter Avalos auth_userresponse(authctxt->as, response, 0); 96718de8d7fSPeter Avalos authctxt->as = NULL; 968*50a69bb5SSascha Wildner debug3_f("<%s> = <%d>", response, authok); 96936e94dc5SPeter Avalos free(response); 97018de8d7fSPeter Avalos 971664f4763Szrj sshbuf_reset(m); 972664f4763Szrj if ((r = sshbuf_put_u32(m, authok)) != 0) 973*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 97418de8d7fSPeter Avalos 975*50a69bb5SSascha Wildner debug3_f("sending authenticated: %d", authok); 97618de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m); 97718de8d7fSPeter Avalos 97836e94dc5SPeter Avalos auth_method = "keyboard-interactive"; 97936e94dc5SPeter Avalos auth_submethod = "bsdauth"; 98018de8d7fSPeter Avalos 98118de8d7fSPeter Avalos return (authok != 0); 98218de8d7fSPeter Avalos } 98318de8d7fSPeter Avalos #endif 98418de8d7fSPeter Avalos 98518de8d7fSPeter Avalos #ifdef USE_PAM 98618de8d7fSPeter Avalos int 987664f4763Szrj mm_answer_pam_start(struct ssh *ssh, int sock, struct sshbuf *m) 98818de8d7fSPeter Avalos { 98918de8d7fSPeter Avalos if (!options.use_pam) 99018de8d7fSPeter Avalos fatal("UsePAM not set, but ended up in %s anyway", __func__); 99118de8d7fSPeter Avalos 992664f4763Szrj start_pam(ssh); 99318de8d7fSPeter Avalos 99418de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PAM_ACCOUNT, 1); 995ce74bacaSMatthew Dillon if (options.kbd_interactive_authentication) 996ce74bacaSMatthew Dillon monitor_permit(mon_dispatch, MONITOR_REQ_PAM_INIT_CTX, 1); 99718de8d7fSPeter Avalos 99818de8d7fSPeter Avalos return (0); 99918de8d7fSPeter Avalos } 100018de8d7fSPeter Avalos 100118de8d7fSPeter Avalos int 1002664f4763Szrj mm_answer_pam_account(struct ssh *ssh, int sock, struct sshbuf *m) 100318de8d7fSPeter Avalos { 100418de8d7fSPeter Avalos u_int ret; 1005664f4763Szrj int r; 100618de8d7fSPeter Avalos 100718de8d7fSPeter Avalos if (!options.use_pam) 1008ce74bacaSMatthew Dillon fatal("%s: PAM not enabled", __func__); 100918de8d7fSPeter Avalos 101018de8d7fSPeter Avalos ret = do_pam_account(); 101118de8d7fSPeter Avalos 1012664f4763Szrj if ((r = sshbuf_put_u32(m, ret)) != 0 || 1013664f4763Szrj (r = sshbuf_put_stringb(m, loginmsg)) != 0) 1014664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 101518de8d7fSPeter Avalos 101618de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PAM_ACCOUNT, m); 101718de8d7fSPeter Avalos 101818de8d7fSPeter Avalos return (ret); 101918de8d7fSPeter Avalos } 102018de8d7fSPeter Avalos 102118de8d7fSPeter Avalos static void *sshpam_ctxt, *sshpam_authok; 102218de8d7fSPeter Avalos extern KbdintDevice sshpam_device; 102318de8d7fSPeter Avalos 102418de8d7fSPeter Avalos int 1025664f4763Szrj mm_answer_pam_init_ctx(struct ssh *ssh, int sock, struct sshbuf *m) 102618de8d7fSPeter Avalos { 1027664f4763Szrj u_int ok = 0; 1028664f4763Szrj int r; 1029664f4763Szrj 103018de8d7fSPeter Avalos debug3("%s", __func__); 1031ce74bacaSMatthew Dillon if (!options.kbd_interactive_authentication) 1032ce74bacaSMatthew Dillon fatal("%s: kbd-int authentication not enabled", __func__); 1033ce74bacaSMatthew Dillon if (sshpam_ctxt != NULL) 1034ce74bacaSMatthew Dillon fatal("%s: already called", __func__); 103518de8d7fSPeter Avalos sshpam_ctxt = (sshpam_device.init_ctx)(authctxt); 103618de8d7fSPeter Avalos sshpam_authok = NULL; 1037664f4763Szrj sshbuf_reset(m); 103818de8d7fSPeter Avalos if (sshpam_ctxt != NULL) { 103918de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1); 1040ce74bacaSMatthew Dillon monitor_permit(mon_dispatch, MONITOR_REQ_PAM_QUERY, 1); 1041664f4763Szrj ok = 1; 104218de8d7fSPeter Avalos } 1043664f4763Szrj if ((r = sshbuf_put_u32(m, ok)) != 0) 1044664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 104518de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m); 104618de8d7fSPeter Avalos return (0); 104718de8d7fSPeter Avalos } 104818de8d7fSPeter Avalos 104918de8d7fSPeter Avalos int 1050664f4763Szrj mm_answer_pam_query(struct ssh *ssh, int sock, struct sshbuf *m) 105118de8d7fSPeter Avalos { 1052856ea928SPeter Avalos char *name = NULL, *info = NULL, **prompts = NULL; 1053856ea928SPeter Avalos u_int i, num = 0, *echo_on = 0; 1054664f4763Szrj int r, ret; 105518de8d7fSPeter Avalos 105618de8d7fSPeter Avalos debug3("%s", __func__); 105718de8d7fSPeter Avalos sshpam_authok = NULL; 1058ce74bacaSMatthew Dillon if (sshpam_ctxt == NULL) 1059ce74bacaSMatthew Dillon fatal("%s: no context", __func__); 1060ce74bacaSMatthew Dillon ret = (sshpam_device.query)(sshpam_ctxt, &name, &info, 1061ce74bacaSMatthew Dillon &num, &prompts, &echo_on); 106218de8d7fSPeter Avalos if (ret == 0 && num == 0) 106318de8d7fSPeter Avalos sshpam_authok = sshpam_ctxt; 106418de8d7fSPeter Avalos if (num > 1 || name == NULL || info == NULL) 1065ce74bacaSMatthew Dillon fatal("sshpam_device.query failed"); 1066ce74bacaSMatthew Dillon monitor_permit(mon_dispatch, MONITOR_REQ_PAM_RESPOND, 1); 1067664f4763Szrj sshbuf_reset(m); 1068664f4763Szrj if ((r = sshbuf_put_u32(m, ret)) != 0 || 1069664f4763Szrj (r = sshbuf_put_cstring(m, name)) != 0 || 1070664f4763Szrj (r = sshbuf_put_cstring(m, info)) != 0 || 1071664f4763Szrj (r = sshbuf_put_u32(m, sshpam_get_maxtries_reached())) != 0 || 1072664f4763Szrj (r = sshbuf_put_u32(m, num)) != 0) 1073664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 107436e94dc5SPeter Avalos free(name); 107536e94dc5SPeter Avalos free(info); 107618de8d7fSPeter Avalos for (i = 0; i < num; ++i) { 1077664f4763Szrj if ((r = sshbuf_put_cstring(m, prompts[i])) != 0 || 1078664f4763Szrj (r = sshbuf_put_u32(m, echo_on[i])) != 0) 1079664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 108036e94dc5SPeter Avalos free(prompts[i]); 108118de8d7fSPeter Avalos } 108236e94dc5SPeter Avalos free(prompts); 108336e94dc5SPeter Avalos free(echo_on); 108436e94dc5SPeter Avalos auth_method = "keyboard-interactive"; 108536e94dc5SPeter Avalos auth_submethod = "pam"; 108618de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m); 108718de8d7fSPeter Avalos return (0); 108818de8d7fSPeter Avalos } 108918de8d7fSPeter Avalos 109018de8d7fSPeter Avalos int 1091664f4763Szrj mm_answer_pam_respond(struct ssh *ssh, int sock, struct sshbuf *m) 109218de8d7fSPeter Avalos { 109318de8d7fSPeter Avalos char **resp; 109418de8d7fSPeter Avalos u_int i, num; 1095664f4763Szrj int r, ret; 109618de8d7fSPeter Avalos 109718de8d7fSPeter Avalos debug3("%s", __func__); 1098ce74bacaSMatthew Dillon if (sshpam_ctxt == NULL) 1099ce74bacaSMatthew Dillon fatal("%s: no context", __func__); 110018de8d7fSPeter Avalos sshpam_authok = NULL; 1101664f4763Szrj if ((r = sshbuf_get_u32(m, &num)) != 0) 1102664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 110318de8d7fSPeter Avalos if (num > 0) { 110418de8d7fSPeter Avalos resp = xcalloc(num, sizeof(char *)); 1105664f4763Szrj for (i = 0; i < num; ++i) { 1106664f4763Szrj if ((r = sshbuf_get_cstring(m, &(resp[i]), NULL)) != 0) 1107664f4763Szrj fatal("%s: buffer error: %s", 1108664f4763Szrj __func__, ssh_err(r)); 1109664f4763Szrj } 111018de8d7fSPeter Avalos ret = (sshpam_device.respond)(sshpam_ctxt, num, resp); 111118de8d7fSPeter Avalos for (i = 0; i < num; ++i) 111236e94dc5SPeter Avalos free(resp[i]); 111336e94dc5SPeter Avalos free(resp); 111418de8d7fSPeter Avalos } else { 111518de8d7fSPeter Avalos ret = (sshpam_device.respond)(sshpam_ctxt, num, NULL); 111618de8d7fSPeter Avalos } 1117664f4763Szrj sshbuf_reset(m); 1118664f4763Szrj if ((r = sshbuf_put_u32(m, ret)) != 0) 1119664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 112018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PAM_RESPOND, m); 112136e94dc5SPeter Avalos auth_method = "keyboard-interactive"; 112236e94dc5SPeter Avalos auth_submethod = "pam"; 112318de8d7fSPeter Avalos if (ret == 0) 112418de8d7fSPeter Avalos sshpam_authok = sshpam_ctxt; 112518de8d7fSPeter Avalos return (0); 112618de8d7fSPeter Avalos } 112718de8d7fSPeter Avalos 112818de8d7fSPeter Avalos int 1129664f4763Szrj mm_answer_pam_free_ctx(struct ssh *ssh, int sock, struct sshbuf *m) 113018de8d7fSPeter Avalos { 1131e9778795SPeter Avalos int r = sshpam_authok != NULL && sshpam_authok == sshpam_ctxt; 113218de8d7fSPeter Avalos 113318de8d7fSPeter Avalos debug3("%s", __func__); 1134ce74bacaSMatthew Dillon if (sshpam_ctxt == NULL) 1135ce74bacaSMatthew Dillon fatal("%s: no context", __func__); 113618de8d7fSPeter Avalos (sshpam_device.free_ctx)(sshpam_ctxt); 1137e9778795SPeter Avalos sshpam_ctxt = sshpam_authok = NULL; 1138664f4763Szrj sshbuf_reset(m); 113918de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m); 1140ce74bacaSMatthew Dillon /* Allow another attempt */ 1141ce74bacaSMatthew Dillon monitor_permit(mon_dispatch, MONITOR_REQ_PAM_INIT_CTX, 1); 114236e94dc5SPeter Avalos auth_method = "keyboard-interactive"; 114336e94dc5SPeter Avalos auth_submethod = "pam"; 1144e9778795SPeter Avalos return r; 114518de8d7fSPeter Avalos } 114618de8d7fSPeter Avalos #endif 114718de8d7fSPeter Avalos 114818de8d7fSPeter Avalos int 1149664f4763Szrj mm_answer_keyallowed(struct ssh *ssh, int sock, struct sshbuf *m) 115018de8d7fSPeter Avalos { 1151664f4763Szrj struct sshkey *key = NULL; 115218de8d7fSPeter Avalos char *cuser, *chost; 1153664f4763Szrj u_int pubkey_auth_attempt; 1154*50a69bb5SSascha Wildner u_int type = 0; 1155664f4763Szrj int r, allowed = 0; 1156664f4763Szrj struct sshauthopt *opts = NULL; 115718de8d7fSPeter Avalos 1158*50a69bb5SSascha Wildner debug3_f("entering"); 1159664f4763Szrj if ((r = sshbuf_get_u32(m, &type)) != 0 || 1160664f4763Szrj (r = sshbuf_get_cstring(m, &cuser, NULL)) != 0 || 1161664f4763Szrj (r = sshbuf_get_cstring(m, &chost, NULL)) != 0 || 1162664f4763Szrj (r = sshkey_froms(m, &key)) != 0 || 1163664f4763Szrj (r = sshbuf_get_u32(m, &pubkey_auth_attempt)) != 0) 1164*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 116518de8d7fSPeter Avalos 116618de8d7fSPeter Avalos if (key != NULL && authctxt->valid) { 1167e9778795SPeter Avalos /* These should not make it past the privsep child */ 1168664f4763Szrj if (sshkey_type_plain(key->type) == KEY_RSA && 1169*50a69bb5SSascha Wildner (ssh->compat & SSH_BUG_RSASIGMD5) != 0) 1170*50a69bb5SSascha Wildner fatal_f("passed a SSH_BUG_RSASIGMD5 key"); 1171e9778795SPeter Avalos 117218de8d7fSPeter Avalos switch (type) { 117318de8d7fSPeter Avalos case MM_USERKEY: 117418de8d7fSPeter Avalos auth_method = "publickey"; 1175664f4763Szrj if (!options.pubkey_authentication) 1176664f4763Szrj break; 1177664f4763Szrj if (auth2_key_already_used(authctxt, key)) 1178664f4763Szrj break; 1179664f4763Szrj if (!key_base_type_match(auth_method, key, 1180*50a69bb5SSascha Wildner options.pubkey_accepted_algos)) 1181664f4763Szrj break; 1182664f4763Szrj allowed = user_key_allowed(ssh, authctxt->pw, key, 1183664f4763Szrj pubkey_auth_attempt, &opts); 118418de8d7fSPeter Avalos break; 118518de8d7fSPeter Avalos case MM_HOSTKEY: 1186664f4763Szrj auth_method = "hostbased"; 1187664f4763Szrj if (!options.hostbased_authentication) 1188664f4763Szrj break; 1189664f4763Szrj if (auth2_key_already_used(authctxt, key)) 1190664f4763Szrj break; 1191664f4763Szrj if (!key_base_type_match(auth_method, key, 1192*50a69bb5SSascha Wildner options.hostbased_accepted_algos)) 1193664f4763Szrj break; 1194664f4763Szrj allowed = hostbased_key_allowed(ssh, authctxt->pw, 119518de8d7fSPeter Avalos cuser, chost, key); 1196ce74bacaSMatthew Dillon auth2_record_info(authctxt, 119736e94dc5SPeter Avalos "client user \"%.100s\", client host \"%.100s\"", 119836e94dc5SPeter Avalos cuser, chost); 119918de8d7fSPeter Avalos break; 120018de8d7fSPeter Avalos default: 1201*50a69bb5SSascha Wildner fatal_f("unknown key type %u", type); 120218de8d7fSPeter Avalos break; 120318de8d7fSPeter Avalos } 120418de8d7fSPeter Avalos } 1205e9778795SPeter Avalos 1206*50a69bb5SSascha Wildner debug3_f("%s authentication%s: %s key is %s", auth_method, 1207*50a69bb5SSascha Wildner pubkey_auth_attempt ? "" : " test", 1208664f4763Szrj (key == NULL || !authctxt->valid) ? "invalid" : sshkey_type(key), 1209664f4763Szrj allowed ? "allowed" : "not allowed"); 1210e9778795SPeter Avalos 1211ce74bacaSMatthew Dillon auth2_record_key(authctxt, 0, key); 121218de8d7fSPeter Avalos 121318de8d7fSPeter Avalos /* clear temporarily storage (used by verify) */ 121418de8d7fSPeter Avalos monitor_reset_key_state(); 121518de8d7fSPeter Avalos 121618de8d7fSPeter Avalos if (allowed) { 121718de8d7fSPeter Avalos /* Save temporarily for comparison in verify */ 1218664f4763Szrj if ((r = sshkey_to_blob(key, &key_blob, &key_bloblen)) != 0) 1219*50a69bb5SSascha Wildner fatal_fr(r, "sshkey_to_blob"); 122018de8d7fSPeter Avalos key_blobtype = type; 1221664f4763Szrj key_opts = opts; 122218de8d7fSPeter Avalos hostbased_cuser = cuser; 122318de8d7fSPeter Avalos hostbased_chost = chost; 122418de8d7fSPeter Avalos } else { 122518de8d7fSPeter Avalos /* Log failed attempt */ 1226664f4763Szrj auth_log(ssh, 0, 0, auth_method, NULL); 122736e94dc5SPeter Avalos free(cuser); 122836e94dc5SPeter Avalos free(chost); 122918de8d7fSPeter Avalos } 1230664f4763Szrj sshkey_free(key); 123118de8d7fSPeter Avalos 1232664f4763Szrj sshbuf_reset(m); 1233664f4763Szrj if ((r = sshbuf_put_u32(m, allowed)) != 0) 1234*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 1235664f4763Szrj if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0) 1236*50a69bb5SSascha Wildner fatal_fr(r, "sshauthopt_serialise"); 123718de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); 123818de8d7fSPeter Avalos 1239664f4763Szrj if (!allowed) 1240664f4763Szrj sshauthopt_free(opts); 1241664f4763Szrj 124218de8d7fSPeter Avalos return (0); 124318de8d7fSPeter Avalos } 124418de8d7fSPeter Avalos 124518de8d7fSPeter Avalos static int 1246*50a69bb5SSascha Wildner monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen) 124718de8d7fSPeter Avalos { 1248664f4763Szrj struct sshbuf *b; 1249664f4763Szrj const u_char *p; 1250e9778795SPeter Avalos char *userstyle, *cp; 1251664f4763Szrj size_t len; 1252664f4763Szrj u_char type; 1253664f4763Szrj int r, fail = 0; 125418de8d7fSPeter Avalos 12550cbfa66cSDaniel Fojt if ((b = sshbuf_from(data, datalen)) == NULL) 1256*50a69bb5SSascha Wildner fatal_f("sshbuf_from"); 125718de8d7fSPeter Avalos 1258*50a69bb5SSascha Wildner if (ssh->compat & SSH_OLD_SESSIONID) { 1259664f4763Szrj p = sshbuf_ptr(b); 1260664f4763Szrj len = sshbuf_len(b); 126118de8d7fSPeter Avalos if ((session_id2 == NULL) || 126218de8d7fSPeter Avalos (len < session_id2_len) || 1263856ea928SPeter Avalos (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) 126418de8d7fSPeter Avalos fail++; 1265664f4763Szrj if ((r = sshbuf_consume(b, session_id2_len)) != 0) 1266*50a69bb5SSascha Wildner fatal_fr(r, "consume"); 126718de8d7fSPeter Avalos } else { 1268664f4763Szrj if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) 1269*50a69bb5SSascha Wildner fatal_fr(r, "parse sessionid"); 127018de8d7fSPeter Avalos if ((session_id2 == NULL) || 127118de8d7fSPeter Avalos (len != session_id2_len) || 1272856ea928SPeter Avalos (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) 127318de8d7fSPeter Avalos fail++; 127418de8d7fSPeter Avalos } 1275664f4763Szrj if ((r = sshbuf_get_u8(b, &type)) != 0) 1276*50a69bb5SSascha Wildner fatal_fr(r, "parse type"); 1277664f4763Szrj if (type != SSH2_MSG_USERAUTH_REQUEST) 127818de8d7fSPeter Avalos fail++; 1279664f4763Szrj if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1280*50a69bb5SSascha Wildner fatal_fr(r, "parse userstyle"); 128136e94dc5SPeter Avalos xasprintf(&userstyle, "%s%s%s", authctxt->user, 128236e94dc5SPeter Avalos authctxt->style ? ":" : "", 128336e94dc5SPeter Avalos authctxt->style ? authctxt->style : ""); 1284e9778795SPeter Avalos if (strcmp(userstyle, cp) != 0) { 1285e9778795SPeter Avalos logit("wrong user name passed to monitor: " 1286e9778795SPeter Avalos "expected %s != %.100s", userstyle, cp); 128718de8d7fSPeter Avalos fail++; 128818de8d7fSPeter Avalos } 128936e94dc5SPeter Avalos free(userstyle); 1290e9778795SPeter Avalos free(cp); 1291664f4763Szrj if ((r = sshbuf_skip_string(b)) != 0 || /* service */ 1292664f4763Szrj (r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1293*50a69bb5SSascha Wildner fatal_fr(r, "parse method"); 1294e9778795SPeter Avalos if (strcmp("publickey", cp) != 0) 129518de8d7fSPeter Avalos fail++; 1296e9778795SPeter Avalos free(cp); 1297664f4763Szrj if ((r = sshbuf_get_u8(b, &type)) != 0) 1298*50a69bb5SSascha Wildner fatal_fr(r, "parse pktype"); 1299664f4763Szrj if (type == 0) 130018de8d7fSPeter Avalos fail++; 1301664f4763Szrj if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */ 1302664f4763Szrj (r = sshbuf_skip_string(b)) != 0) /* pkblob */ 1303*50a69bb5SSascha Wildner fatal_fr(r, "parse pk"); 1304664f4763Szrj if (sshbuf_len(b) != 0) 130518de8d7fSPeter Avalos fail++; 1306664f4763Szrj sshbuf_free(b); 130718de8d7fSPeter Avalos return (fail == 0); 130818de8d7fSPeter Avalos } 130918de8d7fSPeter Avalos 131018de8d7fSPeter Avalos static int 13110cbfa66cSDaniel Fojt monitor_valid_hostbasedblob(const u_char *data, u_int datalen, 13120cbfa66cSDaniel Fojt const char *cuser, const char *chost) 131318de8d7fSPeter Avalos { 1314664f4763Szrj struct sshbuf *b; 1315664f4763Szrj const u_char *p; 1316664f4763Szrj char *cp, *userstyle; 1317664f4763Szrj size_t len; 1318664f4763Szrj int r, fail = 0; 1319664f4763Szrj u_char type; 132018de8d7fSPeter Avalos 13210cbfa66cSDaniel Fojt if ((b = sshbuf_from(data, datalen)) == NULL) 1322*50a69bb5SSascha Wildner fatal_f("sshbuf_new"); 13230cbfa66cSDaniel Fojt if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) 1324*50a69bb5SSascha Wildner fatal_fr(r, "parse sessionid"); 132518de8d7fSPeter Avalos 132618de8d7fSPeter Avalos if ((session_id2 == NULL) || 132718de8d7fSPeter Avalos (len != session_id2_len) || 1328856ea928SPeter Avalos (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) 132918de8d7fSPeter Avalos fail++; 133018de8d7fSPeter Avalos 1331664f4763Szrj if ((r = sshbuf_get_u8(b, &type)) != 0) 1332*50a69bb5SSascha Wildner fatal_fr(r, "parse type"); 1333664f4763Szrj if (type != SSH2_MSG_USERAUTH_REQUEST) 133418de8d7fSPeter Avalos fail++; 1335664f4763Szrj if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1336*50a69bb5SSascha Wildner fatal_fr(r, "parse userstyle"); 133736e94dc5SPeter Avalos xasprintf(&userstyle, "%s%s%s", authctxt->user, 133836e94dc5SPeter Avalos authctxt->style ? ":" : "", 133936e94dc5SPeter Avalos authctxt->style ? authctxt->style : ""); 1340664f4763Szrj if (strcmp(userstyle, cp) != 0) { 1341664f4763Szrj logit("wrong user name passed to monitor: " 1342664f4763Szrj "expected %s != %.100s", userstyle, cp); 134318de8d7fSPeter Avalos fail++; 134418de8d7fSPeter Avalos } 134536e94dc5SPeter Avalos free(userstyle); 1346664f4763Szrj free(cp); 1347664f4763Szrj if ((r = sshbuf_skip_string(b)) != 0 || /* service */ 1348664f4763Szrj (r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1349*50a69bb5SSascha Wildner fatal_fr(r, "parse method"); 1350664f4763Szrj if (strcmp(cp, "hostbased") != 0) 135118de8d7fSPeter Avalos fail++; 1352664f4763Szrj free(cp); 1353664f4763Szrj if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */ 1354664f4763Szrj (r = sshbuf_skip_string(b)) != 0) /* pkblob */ 1355*50a69bb5SSascha Wildner fatal_fr(r, "parse pk"); 135618de8d7fSPeter Avalos 135718de8d7fSPeter Avalos /* verify client host, strip trailing dot if necessary */ 1358664f4763Szrj if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1359*50a69bb5SSascha Wildner fatal_fr(r, "parse host"); 1360664f4763Szrj if (((len = strlen(cp)) > 0) && cp[len - 1] == '.') 1361664f4763Szrj cp[len - 1] = '\0'; 1362664f4763Szrj if (strcmp(cp, chost) != 0) 136318de8d7fSPeter Avalos fail++; 1364664f4763Szrj free(cp); 136518de8d7fSPeter Avalos 136618de8d7fSPeter Avalos /* verify client user */ 1367664f4763Szrj if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) 1368*50a69bb5SSascha Wildner fatal_fr(r, "parse ruser"); 1369664f4763Szrj if (strcmp(cp, cuser) != 0) 137018de8d7fSPeter Avalos fail++; 1371664f4763Szrj free(cp); 137218de8d7fSPeter Avalos 1373664f4763Szrj if (sshbuf_len(b) != 0) 137418de8d7fSPeter Avalos fail++; 1375664f4763Szrj sshbuf_free(b); 137618de8d7fSPeter Avalos return (fail == 0); 137718de8d7fSPeter Avalos } 137818de8d7fSPeter Avalos 137918de8d7fSPeter Avalos int 1380664f4763Szrj mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) 138118de8d7fSPeter Avalos { 1382ce74bacaSMatthew Dillon struct sshkey *key; 13830cbfa66cSDaniel Fojt const u_char *signature, *data, *blob; 13840cbfa66cSDaniel Fojt char *sigalg = NULL, *fp = NULL; 1385ce74bacaSMatthew Dillon size_t signaturelen, datalen, bloblen; 1386*50a69bb5SSascha Wildner int r, ret, req_presence = 0, req_verify = 0, valid_data = 0; 1387*50a69bb5SSascha Wildner int encoded_ret; 13880cbfa66cSDaniel Fojt struct sshkey_sig_details *sig_details = NULL; 138918de8d7fSPeter Avalos 13900cbfa66cSDaniel Fojt if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 || 13910cbfa66cSDaniel Fojt (r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 || 13920cbfa66cSDaniel Fojt (r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 || 1393664f4763Szrj (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) 1394*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 139518de8d7fSPeter Avalos 139618de8d7fSPeter Avalos if (hostbased_cuser == NULL || hostbased_chost == NULL || 139718de8d7fSPeter Avalos !monitor_allowed_key(blob, bloblen)) 1398*50a69bb5SSascha Wildner fatal_f("bad key, not previously allowed"); 139918de8d7fSPeter Avalos 1400664f4763Szrj /* Empty signature algorithm means NULL. */ 1401664f4763Szrj if (*sigalg == '\0') { 1402664f4763Szrj free(sigalg); 1403664f4763Szrj sigalg = NULL; 1404664f4763Szrj } 1405664f4763Szrj 1406ce74bacaSMatthew Dillon /* XXX use sshkey_froms here; need to change key_blob, etc. */ 1407ce74bacaSMatthew Dillon if ((r = sshkey_from_blob(blob, bloblen, &key)) != 0) 1408*50a69bb5SSascha Wildner fatal_fr(r, "parse key"); 140918de8d7fSPeter Avalos 141018de8d7fSPeter Avalos switch (key_blobtype) { 141118de8d7fSPeter Avalos case MM_USERKEY: 1412*50a69bb5SSascha Wildner valid_data = monitor_valid_userblob(ssh, data, datalen); 1413ce74bacaSMatthew Dillon auth_method = "publickey"; 141418de8d7fSPeter Avalos break; 141518de8d7fSPeter Avalos case MM_HOSTKEY: 141618de8d7fSPeter Avalos valid_data = monitor_valid_hostbasedblob(data, datalen, 141718de8d7fSPeter Avalos hostbased_cuser, hostbased_chost); 1418ce74bacaSMatthew Dillon auth_method = "hostbased"; 141918de8d7fSPeter Avalos break; 142018de8d7fSPeter Avalos default: 142118de8d7fSPeter Avalos valid_data = 0; 142218de8d7fSPeter Avalos break; 142318de8d7fSPeter Avalos } 142418de8d7fSPeter Avalos if (!valid_data) 1425*50a69bb5SSascha Wildner fatal_f("bad %s signature data blob", 1426*50a69bb5SSascha Wildner key_blobtype == MM_USERKEY ? "userkey" : 1427*50a69bb5SSascha Wildner (key_blobtype == MM_HOSTKEY ? "hostkey" : "unknown")); 142818de8d7fSPeter Avalos 14290cbfa66cSDaniel Fojt if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 14300cbfa66cSDaniel Fojt SSH_FP_DEFAULT)) == NULL) 1431*50a69bb5SSascha Wildner fatal_f("sshkey_fingerprint failed"); 1432e9778795SPeter Avalos 14330cbfa66cSDaniel Fojt ret = sshkey_verify(key, signature, signaturelen, data, datalen, 14340cbfa66cSDaniel Fojt sigalg, ssh->compat, &sig_details); 1435*50a69bb5SSascha Wildner debug3_f("%s %s signature %s%s%s", auth_method, sshkey_type(key), 14360cbfa66cSDaniel Fojt (ret == 0) ? "verified" : "unverified", 14370cbfa66cSDaniel Fojt (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); 14380cbfa66cSDaniel Fojt 14390cbfa66cSDaniel Fojt if (ret == 0 && key_blobtype == MM_USERKEY && sig_details != NULL) { 14400cbfa66cSDaniel Fojt req_presence = (options.pubkey_auth_options & 14410cbfa66cSDaniel Fojt PUBKEYAUTH_TOUCH_REQUIRED) || 14420cbfa66cSDaniel Fojt !key_opts->no_require_user_presence; 14430cbfa66cSDaniel Fojt if (req_presence && 14440cbfa66cSDaniel Fojt (sig_details->sk_flags & SSH_SK_USER_PRESENCE_REQD) == 0) { 14450cbfa66cSDaniel Fojt error("public key %s %s signature for %s%s from %.128s " 14460cbfa66cSDaniel Fojt "port %d rejected: user presence " 14470cbfa66cSDaniel Fojt "(authenticator touch) requirement not met ", 14480cbfa66cSDaniel Fojt sshkey_type(key), fp, 14490cbfa66cSDaniel Fojt authctxt->valid ? "" : "invalid user ", 14500cbfa66cSDaniel Fojt authctxt->user, ssh_remote_ipaddr(ssh), 14510cbfa66cSDaniel Fojt ssh_remote_port(ssh)); 14520cbfa66cSDaniel Fojt ret = SSH_ERR_SIGNATURE_INVALID; 14530cbfa66cSDaniel Fojt } 1454*50a69bb5SSascha Wildner req_verify = (options.pubkey_auth_options & 1455*50a69bb5SSascha Wildner PUBKEYAUTH_VERIFY_REQUIRED) || key_opts->require_verify; 1456*50a69bb5SSascha Wildner if (req_verify && 1457*50a69bb5SSascha Wildner (sig_details->sk_flags & SSH_SK_USER_VERIFICATION_REQD) == 0) { 1458*50a69bb5SSascha Wildner error("public key %s %s signature for %s%s from %.128s " 1459*50a69bb5SSascha Wildner "port %d rejected: user verification requirement " 1460*50a69bb5SSascha Wildner "not met ", sshkey_type(key), fp, 1461*50a69bb5SSascha Wildner authctxt->valid ? "" : "invalid user ", 1462*50a69bb5SSascha Wildner authctxt->user, ssh_remote_ipaddr(ssh), 1463*50a69bb5SSascha Wildner ssh_remote_port(ssh)); 1464*50a69bb5SSascha Wildner ret = SSH_ERR_SIGNATURE_INVALID; 1465*50a69bb5SSascha Wildner } 14660cbfa66cSDaniel Fojt } 14670cbfa66cSDaniel Fojt auth2_record_key(authctxt, ret == 0, key); 146818de8d7fSPeter Avalos 1469664f4763Szrj if (key_blobtype == MM_USERKEY) 1470664f4763Szrj auth_activate_options(ssh, key_opts); 147118de8d7fSPeter Avalos monitor_reset_key_state(); 147218de8d7fSPeter Avalos 1473ce74bacaSMatthew Dillon sshbuf_reset(m); 1474ce74bacaSMatthew Dillon 1475ce74bacaSMatthew Dillon /* encode ret != 0 as positive integer, since we're sending u32 */ 1476ce74bacaSMatthew Dillon encoded_ret = (ret != 0); 14770cbfa66cSDaniel Fojt if ((r = sshbuf_put_u32(m, encoded_ret)) != 0 || 14780cbfa66cSDaniel Fojt (r = sshbuf_put_u8(m, sig_details != NULL)) != 0) 1479*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 14800cbfa66cSDaniel Fojt if (sig_details != NULL) { 14810cbfa66cSDaniel Fojt if ((r = sshbuf_put_u32(m, sig_details->sk_counter)) != 0 || 14820cbfa66cSDaniel Fojt (r = sshbuf_put_u8(m, sig_details->sk_flags)) != 0) 1483*50a69bb5SSascha Wildner fatal_fr(r, "assemble sk"); 14840cbfa66cSDaniel Fojt } 14850cbfa66cSDaniel Fojt sshkey_sig_details_free(sig_details); 148618de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m); 148718de8d7fSPeter Avalos 14880cbfa66cSDaniel Fojt free(sigalg); 14890cbfa66cSDaniel Fojt free(fp); 14900cbfa66cSDaniel Fojt sshkey_free(key); 14910cbfa66cSDaniel Fojt 1492ce74bacaSMatthew Dillon return ret == 0; 149318de8d7fSPeter Avalos } 149418de8d7fSPeter Avalos 149518de8d7fSPeter Avalos static void 1496664f4763Szrj mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw) 149718de8d7fSPeter Avalos { 149818de8d7fSPeter Avalos socklen_t fromlen; 149918de8d7fSPeter Avalos struct sockaddr_storage from; 150018de8d7fSPeter Avalos 150118de8d7fSPeter Avalos /* 150218de8d7fSPeter Avalos * Get IP address of client. If the connection is not a socket, let 150318de8d7fSPeter Avalos * the address be 0.0.0.0. 150418de8d7fSPeter Avalos */ 150518de8d7fSPeter Avalos memset(&from, 0, sizeof(from)); 150618de8d7fSPeter Avalos fromlen = sizeof(from); 1507664f4763Szrj if (ssh_packet_connection_is_on_socket(ssh)) { 1508664f4763Szrj if (getpeername(ssh_packet_get_connection_in(ssh), 15090cbfa66cSDaniel Fojt (struct sockaddr *)&from, &fromlen) == -1) { 151018de8d7fSPeter Avalos debug("getpeername: %.100s", strerror(errno)); 151118de8d7fSPeter Avalos cleanup_exit(255); 151218de8d7fSPeter Avalos } 151318de8d7fSPeter Avalos } 151418de8d7fSPeter Avalos /* Record that there was a login on that tty from the remote host. */ 151518de8d7fSPeter Avalos record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, 1516e9778795SPeter Avalos session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), 151718de8d7fSPeter Avalos (struct sockaddr *)&from, fromlen); 151818de8d7fSPeter Avalos } 151918de8d7fSPeter Avalos 152018de8d7fSPeter Avalos static void 152118de8d7fSPeter Avalos mm_session_close(Session *s) 152218de8d7fSPeter Avalos { 1523*50a69bb5SSascha Wildner debug3_f("session %d pid %ld", s->self, (long)s->pid); 152418de8d7fSPeter Avalos if (s->ttyfd != -1) { 1525*50a69bb5SSascha Wildner debug3_f("tty %s ptyfd %d", s->tty, s->ptyfd); 152618de8d7fSPeter Avalos session_pty_cleanup2(s); 152718de8d7fSPeter Avalos } 152818de8d7fSPeter Avalos session_unused(s->self); 152918de8d7fSPeter Avalos } 153018de8d7fSPeter Avalos 153118de8d7fSPeter Avalos int 1532664f4763Szrj mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) 153318de8d7fSPeter Avalos { 153418de8d7fSPeter Avalos extern struct monitor *pmonitor; 153518de8d7fSPeter Avalos Session *s; 1536664f4763Szrj int r, res, fd0; 153718de8d7fSPeter Avalos 1538*50a69bb5SSascha Wildner debug3_f("entering"); 153918de8d7fSPeter Avalos 1540664f4763Szrj sshbuf_reset(m); 154118de8d7fSPeter Avalos s = session_new(); 154218de8d7fSPeter Avalos if (s == NULL) 154318de8d7fSPeter Avalos goto error; 154418de8d7fSPeter Avalos s->authctxt = authctxt; 154518de8d7fSPeter Avalos s->pw = authctxt->pw; 154618de8d7fSPeter Avalos s->pid = pmonitor->m_pid; 154718de8d7fSPeter Avalos res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); 154818de8d7fSPeter Avalos if (res == 0) 154918de8d7fSPeter Avalos goto error; 155018de8d7fSPeter Avalos pty_setowner(authctxt->pw, s->tty); 155118de8d7fSPeter Avalos 1552664f4763Szrj if ((r = sshbuf_put_u32(m, 1)) != 0 || 1553664f4763Szrj (r = sshbuf_put_cstring(m, s->tty)) != 0) 1554*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 155518de8d7fSPeter Avalos 155618de8d7fSPeter Avalos /* We need to trick ttyslot */ 155718de8d7fSPeter Avalos if (dup2(s->ttyfd, 0) == -1) 1558*50a69bb5SSascha Wildner fatal_f("dup2"); 155918de8d7fSPeter Avalos 1560664f4763Szrj mm_record_login(ssh, s, authctxt->pw); 156118de8d7fSPeter Avalos 156218de8d7fSPeter Avalos /* Now we can close the file descriptor again */ 156318de8d7fSPeter Avalos close(0); 156418de8d7fSPeter Avalos 156518de8d7fSPeter Avalos /* send messages generated by record_login */ 1566664f4763Szrj if ((r = sshbuf_put_stringb(m, loginmsg)) != 0) 1567*50a69bb5SSascha Wildner fatal_fr(r, "assemble loginmsg"); 1568664f4763Szrj sshbuf_reset(loginmsg); 156918de8d7fSPeter Avalos 157018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PTY, m); 157118de8d7fSPeter Avalos 157218de8d7fSPeter Avalos if (mm_send_fd(sock, s->ptyfd) == -1 || 157318de8d7fSPeter Avalos mm_send_fd(sock, s->ttyfd) == -1) 1574*50a69bb5SSascha Wildner fatal_f("send fds failed"); 157518de8d7fSPeter Avalos 157618de8d7fSPeter Avalos /* make sure nothing uses fd 0 */ 15770cbfa66cSDaniel Fojt if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1578*50a69bb5SSascha Wildner fatal_f("open(/dev/null): %s", strerror(errno)); 157918de8d7fSPeter Avalos if (fd0 != 0) 1580*50a69bb5SSascha Wildner error_f("fd0 %d != 0", fd0); 158118de8d7fSPeter Avalos 1582*50a69bb5SSascha Wildner /* slave side of pty is not needed */ 158318de8d7fSPeter Avalos close(s->ttyfd); 158418de8d7fSPeter Avalos s->ttyfd = s->ptyfd; 158518de8d7fSPeter Avalos /* no need to dup() because nobody closes ptyfd */ 158618de8d7fSPeter Avalos s->ptymaster = s->ptyfd; 158718de8d7fSPeter Avalos 1588*50a69bb5SSascha Wildner debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd); 158918de8d7fSPeter Avalos 159018de8d7fSPeter Avalos return (0); 159118de8d7fSPeter Avalos 159218de8d7fSPeter Avalos error: 159318de8d7fSPeter Avalos if (s != NULL) 159418de8d7fSPeter Avalos mm_session_close(s); 1595664f4763Szrj if ((r = sshbuf_put_u32(m, 0)) != 0) 1596*50a69bb5SSascha Wildner fatal_fr(r, "assemble 0"); 159718de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_PTY, m); 159818de8d7fSPeter Avalos return (0); 159918de8d7fSPeter Avalos } 160018de8d7fSPeter Avalos 160118de8d7fSPeter Avalos int 1602664f4763Szrj mm_answer_pty_cleanup(struct ssh *ssh, int sock, struct sshbuf *m) 160318de8d7fSPeter Avalos { 160418de8d7fSPeter Avalos Session *s; 160518de8d7fSPeter Avalos char *tty; 1606664f4763Szrj int r; 160718de8d7fSPeter Avalos 1608*50a69bb5SSascha Wildner debug3_f("entering"); 160918de8d7fSPeter Avalos 1610664f4763Szrj if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) 1611*50a69bb5SSascha Wildner fatal_fr(r, "parse tty"); 161218de8d7fSPeter Avalos if ((s = session_by_tty(tty)) != NULL) 161318de8d7fSPeter Avalos mm_session_close(s); 1614664f4763Szrj sshbuf_reset(m); 161536e94dc5SPeter Avalos free(tty); 161618de8d7fSPeter Avalos return (0); 161718de8d7fSPeter Avalos } 161818de8d7fSPeter Avalos 161918de8d7fSPeter Avalos int 1620664f4763Szrj mm_answer_term(struct ssh *ssh, int sock, struct sshbuf *req) 162118de8d7fSPeter Avalos { 162218de8d7fSPeter Avalos extern struct monitor *pmonitor; 162318de8d7fSPeter Avalos int res, status; 162418de8d7fSPeter Avalos 1625*50a69bb5SSascha Wildner debug3_f("tearing down sessions"); 162618de8d7fSPeter Avalos 162718de8d7fSPeter Avalos /* The child is terminating */ 1628ce74bacaSMatthew Dillon session_destroy_all(ssh, &mm_session_close); 162918de8d7fSPeter Avalos 163018de8d7fSPeter Avalos #ifdef USE_PAM 163118de8d7fSPeter Avalos if (options.use_pam) 163218de8d7fSPeter Avalos sshpam_cleanup(); 163318de8d7fSPeter Avalos #endif 163418de8d7fSPeter Avalos 163518de8d7fSPeter Avalos while (waitpid(pmonitor->m_pid, &status, 0) == -1) 163618de8d7fSPeter Avalos if (errno != EINTR) 163718de8d7fSPeter Avalos exit(1); 163818de8d7fSPeter Avalos 163918de8d7fSPeter Avalos res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; 164018de8d7fSPeter Avalos 164118de8d7fSPeter Avalos /* Terminate process */ 164218de8d7fSPeter Avalos exit(res); 164318de8d7fSPeter Avalos } 164418de8d7fSPeter Avalos 164518de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 164618de8d7fSPeter Avalos /* Report that an audit event occurred */ 164718de8d7fSPeter Avalos int 1648664f4763Szrj mm_answer_audit_event(struct ssh *ssh, int socket, struct sshbuf *m) 164918de8d7fSPeter Avalos { 1650664f4763Szrj u_int n; 165118de8d7fSPeter Avalos ssh_audit_event_t event; 1652664f4763Szrj int r; 165318de8d7fSPeter Avalos 165418de8d7fSPeter Avalos debug3("%s entering", __func__); 165518de8d7fSPeter Avalos 1656664f4763Szrj if ((r = sshbuf_get_u32(m, &n)) != 0) 1657664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 1658664f4763Szrj event = (ssh_audit_event_t)n; 165918de8d7fSPeter Avalos switch (event) { 166018de8d7fSPeter Avalos case SSH_AUTH_FAIL_PUBKEY: 166118de8d7fSPeter Avalos case SSH_AUTH_FAIL_HOSTBASED: 166218de8d7fSPeter Avalos case SSH_AUTH_FAIL_GSSAPI: 166318de8d7fSPeter Avalos case SSH_LOGIN_EXCEED_MAXTRIES: 166418de8d7fSPeter Avalos case SSH_LOGIN_ROOT_DENIED: 166518de8d7fSPeter Avalos case SSH_CONNECTION_CLOSE: 166618de8d7fSPeter Avalos case SSH_INVALID_USER: 1667664f4763Szrj audit_event(ssh, event); 166818de8d7fSPeter Avalos break; 166918de8d7fSPeter Avalos default: 167018de8d7fSPeter Avalos fatal("Audit event type %d not permitted", event); 167118de8d7fSPeter Avalos } 167218de8d7fSPeter Avalos 167318de8d7fSPeter Avalos return (0); 167418de8d7fSPeter Avalos } 167518de8d7fSPeter Avalos 167618de8d7fSPeter Avalos int 1677664f4763Szrj mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m) 167818de8d7fSPeter Avalos { 167918de8d7fSPeter Avalos char *cmd; 1680664f4763Szrj int r; 168118de8d7fSPeter Avalos 168218de8d7fSPeter Avalos debug3("%s entering", __func__); 1683664f4763Szrj if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) 1684664f4763Szrj fatal("%s: buffer error: %s", __func__, ssh_err(r)); 168518de8d7fSPeter Avalos /* sanity check command, if so how? */ 168618de8d7fSPeter Avalos audit_run_command(cmd); 168736e94dc5SPeter Avalos free(cmd); 168818de8d7fSPeter Avalos return (0); 168918de8d7fSPeter Avalos } 169018de8d7fSPeter Avalos #endif /* SSH_AUDIT_EVENTS */ 169118de8d7fSPeter Avalos 169218de8d7fSPeter Avalos void 1693664f4763Szrj monitor_clear_keystate(struct ssh *ssh, struct monitor *pmonitor) 1694ce74bacaSMatthew Dillon { 1695ce74bacaSMatthew Dillon ssh_clear_newkeys(ssh, MODE_IN); 1696ce74bacaSMatthew Dillon ssh_clear_newkeys(ssh, MODE_OUT); 1697ce74bacaSMatthew Dillon sshbuf_free(child_state); 1698ce74bacaSMatthew Dillon child_state = NULL; 1699ce74bacaSMatthew Dillon } 1700ce74bacaSMatthew Dillon 1701ce74bacaSMatthew Dillon void 1702664f4763Szrj monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) 170318de8d7fSPeter Avalos { 1704e9778795SPeter Avalos struct kex *kex; 1705e9778795SPeter Avalos int r; 170618de8d7fSPeter Avalos 1707*50a69bb5SSascha Wildner debug3_f("packet_set_state"); 1708e9778795SPeter Avalos if ((r = ssh_packet_set_state(ssh, child_state)) != 0) 1709*50a69bb5SSascha Wildner fatal_fr(r, "packet_set_state"); 1710e9778795SPeter Avalos sshbuf_free(child_state); 1711e9778795SPeter Avalos child_state = NULL; 1712*50a69bb5SSascha Wildner if ((kex = ssh->kex) == NULL) 1713*50a69bb5SSascha Wildner fatal_f("internal error: ssh->kex == NULL"); 1714*50a69bb5SSascha Wildner if (session_id2_len != sshbuf_len(ssh->kex->session_id)) { 1715*50a69bb5SSascha Wildner fatal_f("incorrect session id length %zu (expected %u)", 1716*50a69bb5SSascha Wildner sshbuf_len(ssh->kex->session_id), session_id2_len); 1717*50a69bb5SSascha Wildner } 1718*50a69bb5SSascha Wildner if (memcmp(sshbuf_ptr(ssh->kex->session_id), session_id2, 1719*50a69bb5SSascha Wildner session_id2_len) != 0) 1720*50a69bb5SSascha Wildner fatal_f("session ID mismatch"); 1721e9778795SPeter Avalos /* XXX set callbacks */ 172236e94dc5SPeter Avalos #ifdef WITH_OPENSSL 1723664f4763Szrj kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 1724664f4763Szrj kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 1725664f4763Szrj kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; 1726664f4763Szrj kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; 1727664f4763Szrj kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; 172818de8d7fSPeter Avalos kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 172918de8d7fSPeter Avalos kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1730e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 1731664f4763Szrj kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 173236e94dc5SPeter Avalos # endif 1733e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 1734664f4763Szrj kex->kex[KEX_C25519_SHA256] = kex_gen_server; 1735*50a69bb5SSascha Wildner kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; 1736856ea928SPeter Avalos kex->load_host_public_key=&get_hostkey_public_by_type; 1737856ea928SPeter Avalos kex->load_host_private_key=&get_hostkey_private_by_type; 173818de8d7fSPeter Avalos kex->host_key_index=&get_hostkey_index; 173936e94dc5SPeter Avalos kex->sign = sshd_hostkey_sign; 1740e9778795SPeter Avalos } 174118de8d7fSPeter Avalos 17420cbfa66cSDaniel Fojt /* This function requires careful sanity checking */ 174318de8d7fSPeter Avalos 174418de8d7fSPeter Avalos void 1745664f4763Szrj mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) 174618de8d7fSPeter Avalos { 1747*50a69bb5SSascha Wildner debug3_f("Waiting for new keys"); 174818de8d7fSPeter Avalos 1749e9778795SPeter Avalos if ((child_state = sshbuf_new()) == NULL) 1750*50a69bb5SSascha Wildner fatal_f("sshbuf_new failed"); 1751e9778795SPeter Avalos mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, 1752e9778795SPeter Avalos child_state); 1753*50a69bb5SSascha Wildner debug3_f("GOT new keys"); 175418de8d7fSPeter Avalos } 175518de8d7fSPeter Avalos 175618de8d7fSPeter Avalos 175718de8d7fSPeter Avalos /* XXX */ 175818de8d7fSPeter Avalos 175918de8d7fSPeter Avalos #define FD_CLOSEONEXEC(x) do { \ 17601c188a7fSPeter Avalos if (fcntl(x, F_SETFD, FD_CLOEXEC) == -1) \ 176118de8d7fSPeter Avalos fatal("fcntl(%d, F_SETFD)", x); \ 176218de8d7fSPeter Avalos } while (0) 176318de8d7fSPeter Avalos 176418de8d7fSPeter Avalos static void 17651c188a7fSPeter Avalos monitor_openfds(struct monitor *mon, int do_logfds) 176618de8d7fSPeter Avalos { 17671c188a7fSPeter Avalos int pair[2]; 1768ce74bacaSMatthew Dillon #ifdef SO_ZEROIZE 1769ce74bacaSMatthew Dillon int on = 1; 1770ce74bacaSMatthew Dillon #endif 17711c188a7fSPeter Avalos 177218de8d7fSPeter Avalos if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) 1773*50a69bb5SSascha Wildner fatal_f("socketpair: %s", strerror(errno)); 1774ce74bacaSMatthew Dillon #ifdef SO_ZEROIZE 17750cbfa66cSDaniel Fojt if (setsockopt(pair[0], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) == -1) 1776ce74bacaSMatthew Dillon error("setsockopt SO_ZEROIZE(0): %.100s", strerror(errno)); 17770cbfa66cSDaniel Fojt if (setsockopt(pair[1], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) == -1) 1778ce74bacaSMatthew Dillon error("setsockopt SO_ZEROIZE(1): %.100s", strerror(errno)); 1779ce74bacaSMatthew Dillon #endif 178018de8d7fSPeter Avalos FD_CLOSEONEXEC(pair[0]); 178118de8d7fSPeter Avalos FD_CLOSEONEXEC(pair[1]); 17821c188a7fSPeter Avalos mon->m_recvfd = pair[0]; 17831c188a7fSPeter Avalos mon->m_sendfd = pair[1]; 17841c188a7fSPeter Avalos 17851c188a7fSPeter Avalos if (do_logfds) { 17861c188a7fSPeter Avalos if (pipe(pair) == -1) 1787*50a69bb5SSascha Wildner fatal_f("pipe: %s", strerror(errno)); 17881c188a7fSPeter Avalos FD_CLOSEONEXEC(pair[0]); 17891c188a7fSPeter Avalos FD_CLOSEONEXEC(pair[1]); 17901c188a7fSPeter Avalos mon->m_log_recvfd = pair[0]; 17911c188a7fSPeter Avalos mon->m_log_sendfd = pair[1]; 17921c188a7fSPeter Avalos } else 17931c188a7fSPeter Avalos mon->m_log_recvfd = mon->m_log_sendfd = -1; 179418de8d7fSPeter Avalos } 179518de8d7fSPeter Avalos 179618de8d7fSPeter Avalos #define MM_MEMSIZE 65536 179718de8d7fSPeter Avalos 179818de8d7fSPeter Avalos struct monitor * 179918de8d7fSPeter Avalos monitor_init(void) 180018de8d7fSPeter Avalos { 180118de8d7fSPeter Avalos struct monitor *mon; 180218de8d7fSPeter Avalos 180318de8d7fSPeter Avalos mon = xcalloc(1, sizeof(*mon)); 18041c188a7fSPeter Avalos monitor_openfds(mon, 1); 180518de8d7fSPeter Avalos 180618de8d7fSPeter Avalos return mon; 180718de8d7fSPeter Avalos } 180818de8d7fSPeter Avalos 180918de8d7fSPeter Avalos void 181018de8d7fSPeter Avalos monitor_reinit(struct monitor *mon) 181118de8d7fSPeter Avalos { 18121c188a7fSPeter Avalos monitor_openfds(mon, 0); 181318de8d7fSPeter Avalos } 181418de8d7fSPeter Avalos 181518de8d7fSPeter Avalos #ifdef GSSAPI 181618de8d7fSPeter Avalos int 1817664f4763Szrj mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) 181818de8d7fSPeter Avalos { 181918de8d7fSPeter Avalos gss_OID_desc goid; 182018de8d7fSPeter Avalos OM_uint32 major; 1821664f4763Szrj size_t len; 1822664f4763Szrj u_char *p; 1823664f4763Szrj int r; 182418de8d7fSPeter Avalos 1825ce74bacaSMatthew Dillon if (!options.gss_authentication) 1826*50a69bb5SSascha Wildner fatal_f("GSSAPI authentication not enabled"); 1827ce74bacaSMatthew Dillon 1828664f4763Szrj if ((r = sshbuf_get_string(m, &p, &len)) != 0) 1829*50a69bb5SSascha Wildner fatal_fr(r, "parse"); 1830664f4763Szrj goid.elements = p; 183118de8d7fSPeter Avalos goid.length = len; 183218de8d7fSPeter Avalos 183318de8d7fSPeter Avalos major = ssh_gssapi_server_ctx(&gsscontext, &goid); 183418de8d7fSPeter Avalos 183536e94dc5SPeter Avalos free(goid.elements); 183618de8d7fSPeter Avalos 1837664f4763Szrj sshbuf_reset(m); 1838664f4763Szrj if ((r = sshbuf_put_u32(m, major)) != 0) 1839*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 184018de8d7fSPeter Avalos 184118de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_GSSSETUP, m); 184218de8d7fSPeter Avalos 184318de8d7fSPeter Avalos /* Now we have a context, enable the step */ 184418de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1); 184518de8d7fSPeter Avalos 184618de8d7fSPeter Avalos return (0); 184718de8d7fSPeter Avalos } 184818de8d7fSPeter Avalos 184918de8d7fSPeter Avalos int 1850664f4763Szrj mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) 185118de8d7fSPeter Avalos { 185218de8d7fSPeter Avalos gss_buffer_desc in; 185318de8d7fSPeter Avalos gss_buffer_desc out = GSS_C_EMPTY_BUFFER; 185418de8d7fSPeter Avalos OM_uint32 major, minor; 185518de8d7fSPeter Avalos OM_uint32 flags = 0; /* GSI needs this */ 1856664f4763Szrj int r; 185718de8d7fSPeter Avalos 1858ce74bacaSMatthew Dillon if (!options.gss_authentication) 1859*50a69bb5SSascha Wildner fatal_f("GSSAPI authentication not enabled"); 1860ce74bacaSMatthew Dillon 1861664f4763Szrj if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) 1862*50a69bb5SSascha Wildner fatal_fr(r, "ssh_gssapi_get_buffer_desc"); 186318de8d7fSPeter Avalos major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); 186436e94dc5SPeter Avalos free(in.value); 186518de8d7fSPeter Avalos 1866664f4763Szrj sshbuf_reset(m); 1867664f4763Szrj if ((r = sshbuf_put_u32(m, major)) != 0 || 1868664f4763Szrj (r = sshbuf_put_string(m, out.value, out.length)) != 0 || 1869664f4763Szrj (r = sshbuf_put_u32(m, flags)) != 0) 1870*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 187118de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); 187218de8d7fSPeter Avalos 187318de8d7fSPeter Avalos gss_release_buffer(&minor, &out); 187418de8d7fSPeter Avalos 187518de8d7fSPeter Avalos if (major == GSS_S_COMPLETE) { 187618de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 187718de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 187818de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 187918de8d7fSPeter Avalos } 188018de8d7fSPeter Avalos return (0); 188118de8d7fSPeter Avalos } 188218de8d7fSPeter Avalos 188318de8d7fSPeter Avalos int 1884664f4763Szrj mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) 188518de8d7fSPeter Avalos { 188618de8d7fSPeter Avalos gss_buffer_desc gssbuf, mic; 188718de8d7fSPeter Avalos OM_uint32 ret; 1888664f4763Szrj int r; 188918de8d7fSPeter Avalos 1890ce74bacaSMatthew Dillon if (!options.gss_authentication) 1891*50a69bb5SSascha Wildner fatal_f("GSSAPI authentication not enabled"); 1892ce74bacaSMatthew Dillon 1893664f4763Szrj if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || 1894664f4763Szrj (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) 1895*50a69bb5SSascha Wildner fatal_fr(r, "ssh_gssapi_get_buffer_desc"); 189618de8d7fSPeter Avalos 189718de8d7fSPeter Avalos ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); 189818de8d7fSPeter Avalos 189936e94dc5SPeter Avalos free(gssbuf.value); 190036e94dc5SPeter Avalos free(mic.value); 190118de8d7fSPeter Avalos 1902664f4763Szrj sshbuf_reset(m); 1903664f4763Szrj if ((r = sshbuf_put_u32(m, ret)) != 0) 1904*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 190518de8d7fSPeter Avalos 190618de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m); 190718de8d7fSPeter Avalos 190818de8d7fSPeter Avalos if (!GSS_ERROR(ret)) 190918de8d7fSPeter Avalos monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 191018de8d7fSPeter Avalos 191118de8d7fSPeter Avalos return (0); 191218de8d7fSPeter Avalos } 191318de8d7fSPeter Avalos 191418de8d7fSPeter Avalos int 1915664f4763Szrj mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) 191618de8d7fSPeter Avalos { 1917664f4763Szrj int r, authenticated; 1918ce74bacaSMatthew Dillon const char *displayname; 1919ce74bacaSMatthew Dillon 1920ce74bacaSMatthew Dillon if (!options.gss_authentication) 1921*50a69bb5SSascha Wildner fatal_f("GSSAPI authentication not enabled"); 192218de8d7fSPeter Avalos 192318de8d7fSPeter Avalos authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 192418de8d7fSPeter Avalos 1925664f4763Szrj sshbuf_reset(m); 1926664f4763Szrj if ((r = sshbuf_put_u32(m, authenticated)) != 0) 1927*50a69bb5SSascha Wildner fatal_fr(r, "assemble"); 192818de8d7fSPeter Avalos 1929*50a69bb5SSascha Wildner debug3_f("sending result %d", authenticated); 193018de8d7fSPeter Avalos mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); 193118de8d7fSPeter Avalos 193218de8d7fSPeter Avalos auth_method = "gssapi-with-mic"; 193318de8d7fSPeter Avalos 1934ce74bacaSMatthew Dillon if ((displayname = ssh_gssapi_displayname()) != NULL) 1935ce74bacaSMatthew Dillon auth2_record_info(authctxt, "%s", displayname); 1936ce74bacaSMatthew Dillon 193718de8d7fSPeter Avalos /* Monitor loop will terminate if authenticated */ 193818de8d7fSPeter Avalos return (authenticated); 193918de8d7fSPeter Avalos } 194018de8d7fSPeter Avalos #endif /* GSSAPI */ 1941cb5eb4f1SPeter Avalos 1942