version 1.182, 2018/07/09 21:35:50 |
version 1.183, 2018/07/09 21:53:45 |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "ssh.h" |
#include "ssh.h" |
#include "key.h" |
#include "key.h" |
#include "buffer.h" |
#include "sshbuf.h" |
#include "hostfile.h" |
#include "hostfile.h" |
#include "auth.h" |
#include "auth.h" |
#include "cipher.h" |
#include "cipher.h" |
|
|
|
|
/* Functions on the monitor that answer unprivileged requests */ |
/* Functions on the monitor that answer unprivileged requests */ |
|
|
int mm_answer_moduli(int, Buffer *); |
int mm_answer_moduli(int, struct sshbuf *); |
int mm_answer_sign(int, Buffer *); |
int mm_answer_sign(int, struct sshbuf *); |
int mm_answer_pwnamallow(int, Buffer *); |
int mm_answer_pwnamallow(int, struct sshbuf *); |
int mm_answer_auth2_read_banner(int, Buffer *); |
int mm_answer_auth2_read_banner(int, struct sshbuf *); |
int mm_answer_authserv(int, Buffer *); |
int mm_answer_authserv(int, struct sshbuf *); |
int mm_answer_authpassword(int, Buffer *); |
int mm_answer_authpassword(int, struct sshbuf *); |
int mm_answer_bsdauthquery(int, Buffer *); |
int mm_answer_bsdauthquery(int, struct sshbuf *); |
int mm_answer_bsdauthrespond(int, Buffer *); |
int mm_answer_bsdauthrespond(int, struct sshbuf *); |
int mm_answer_skeyquery(int, Buffer *); |
int mm_answer_skeyquery(int, struct sshbuf *); |
int mm_answer_skeyrespond(int, Buffer *); |
int mm_answer_skeyrespond(int, struct sshbuf *); |
int mm_answer_keyallowed(int, Buffer *); |
int mm_answer_keyallowed(int, struct sshbuf *); |
int mm_answer_keyverify(int, Buffer *); |
int mm_answer_keyverify(int, struct sshbuf *); |
int mm_answer_pty(int, Buffer *); |
int mm_answer_pty(int, struct sshbuf *); |
int mm_answer_pty_cleanup(int, Buffer *); |
int mm_answer_pty_cleanup(int, struct sshbuf *); |
int mm_answer_term(int, Buffer *); |
int mm_answer_term(int, struct sshbuf *); |
int mm_answer_rsa_keyallowed(int, Buffer *); |
int mm_answer_rsa_keyallowed(int, struct sshbuf *); |
int mm_answer_rsa_challenge(int, Buffer *); |
int mm_answer_rsa_challenge(int, struct sshbuf *); |
int mm_answer_rsa_response(int, Buffer *); |
int mm_answer_rsa_response(int, struct sshbuf *); |
int mm_answer_sesskey(int, Buffer *); |
int mm_answer_sesskey(int, struct sshbuf *); |
int mm_answer_sessid(int, Buffer *); |
int mm_answer_sessid(int, struct sshbuf *); |
|
|
#ifdef GSSAPI |
#ifdef GSSAPI |
int mm_answer_gss_setup_ctx(int, Buffer *); |
int mm_answer_gss_setup_ctx(int, struct sshbuf *); |
int mm_answer_gss_accept_ctx(int, Buffer *); |
int mm_answer_gss_accept_ctx(int, struct sshbuf *); |
int mm_answer_gss_userok(int, Buffer *); |
int mm_answer_gss_userok(int, struct sshbuf *); |
int mm_answer_gss_checkmic(int, Buffer *); |
int mm_answer_gss_checkmic(int, struct sshbuf *); |
#endif |
#endif |
|
|
static int monitor_read_log(struct monitor *); |
static int monitor_read_log(struct monitor *); |
|
|
|
|
/* local state for key verify */ |
/* local state for key verify */ |
static u_char *key_blob = NULL; |
static u_char *key_blob = NULL; |
static u_int key_bloblen = 0; |
static size_t key_bloblen = 0; |
static int key_blobtype = MM_NOKEY; |
static int key_blobtype = MM_NOKEY; |
static struct sshauthopt *key_opts = NULL; |
static struct sshauthopt *key_opts = NULL; |
static char *hostbased_cuser = NULL; |
static char *hostbased_cuser = NULL; |
|
|
struct mon_table { |
struct mon_table { |
enum monitor_reqtype type; |
enum monitor_reqtype type; |
int flags; |
int flags; |
int (*f)(int, Buffer *); |
int (*f)(int, struct sshbuf *); |
}; |
}; |
|
|
#define MON_ISAUTH 0x0004 /* Required for Authentication */ |
#define MON_ISAUTH 0x0004 /* Required for Authentication */ |
|
|
static int |
static int |
monitor_read_log(struct monitor *pmonitor) |
monitor_read_log(struct monitor *pmonitor) |
{ |
{ |
Buffer logmsg; |
struct sshbuf *logmsg; |
u_int len, level; |
u_int len, level; |
char *msg; |
char *msg; |
|
u_char *p; |
|
int r; |
|
|
buffer_init(&logmsg); |
if ((logmsg = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new", __func__); |
|
|
/* Read length */ |
/* Read length */ |
buffer_append_space(&logmsg, 4); |
if ((r = sshbuf_reserve(logmsg, 4, &p)) != 0) |
if (atomicio(read, pmonitor->m_log_recvfd, |
fatal("%s: reserve: %s", __func__, ssh_err(r)); |
buffer_ptr(&logmsg), buffer_len(&logmsg)) != buffer_len(&logmsg)) { |
if (atomicio(read, pmonitor->m_log_recvfd, p, 4) != 4) { |
if (errno == EPIPE) { |
if (errno == EPIPE) { |
buffer_free(&logmsg); |
sshbuf_free(logmsg); |
debug("%s: child log fd closed", __func__); |
debug("%s: child log fd closed", __func__); |
close(pmonitor->m_log_recvfd); |
close(pmonitor->m_log_recvfd); |
pmonitor->m_log_recvfd = -1; |
pmonitor->m_log_recvfd = -1; |
|
|
} |
} |
fatal("%s: log fd read: %s", __func__, strerror(errno)); |
fatal("%s: log fd read: %s", __func__, strerror(errno)); |
} |
} |
len = buffer_get_int(&logmsg); |
if ((r = sshbuf_get_u32(logmsg, &len)) != 0) |
|
fatal("%s: get len: %s", __func__, ssh_err(r)); |
if (len <= 4 || len > 8192) |
if (len <= 4 || len > 8192) |
fatal("%s: invalid log message length %u", __func__, len); |
fatal("%s: invalid log message length %u", __func__, len); |
|
|
/* Read severity, message */ |
/* Read severity, message */ |
buffer_clear(&logmsg); |
sshbuf_reset(logmsg); |
buffer_append_space(&logmsg, len); |
if ((r = sshbuf_reserve(logmsg, len, &p)) != 0) |
if (atomicio(read, pmonitor->m_log_recvfd, |
fatal("%s: reserve: %s", __func__, ssh_err(r)); |
buffer_ptr(&logmsg), buffer_len(&logmsg)) != buffer_len(&logmsg)) |
if (atomicio(read, pmonitor->m_log_recvfd, p, len) != len) |
fatal("%s: log fd read: %s", __func__, strerror(errno)); |
fatal("%s: log fd read: %s", __func__, strerror(errno)); |
|
if ((r = sshbuf_get_u32(logmsg, &level)) != 0 || |
|
(r = sshbuf_get_cstring(logmsg, &msg, NULL)) != 0) |
|
fatal("%s: decode: %s", __func__, ssh_err(r)); |
|
|
/* Log it */ |
/* Log it */ |
level = buffer_get_int(&logmsg); |
|
msg = buffer_get_string(&logmsg, NULL); |
|
if (log_level_name(level) == NULL) |
if (log_level_name(level) == NULL) |
fatal("%s: invalid log level %u (corrupted message?)", |
fatal("%s: invalid log level %u (corrupted message?)", |
__func__, level); |
__func__, level); |
do_log2(level, "%s [preauth]", msg); |
do_log2(level, "%s [preauth]", msg); |
|
|
buffer_free(&logmsg); |
sshbuf_free(logmsg); |
free(msg); |
free(msg); |
|
|
return 0; |
return 0; |
|
|
monitor_read(struct monitor *pmonitor, struct mon_table *ent, |
monitor_read(struct monitor *pmonitor, struct mon_table *ent, |
struct mon_table **pent) |
struct mon_table **pent) |
{ |
{ |
Buffer m; |
struct sshbuf *m; |
int ret; |
int r, ret; |
u_char type; |
u_char type; |
struct pollfd pfd[2]; |
struct pollfd pfd[2]; |
|
|
|
|
break; /* Continues below */ |
break; /* Continues below */ |
} |
} |
|
|
buffer_init(&m); |
if ((m = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new", __func__); |
|
|
mm_request_receive(pmonitor->m_sendfd, &m); |
mm_request_receive(pmonitor->m_sendfd, m); |
type = buffer_get_char(&m); |
if ((r = sshbuf_get_u8(m, &type)) != 0) |
|
fatal("%s: decode: %s", __func__, ssh_err(r)); |
|
|
debug3("%s: checking request %d", __func__, type); |
debug3("%s: checking request %d", __func__, type); |
|
|
|
|
if (!(ent->flags & MON_PERMIT)) |
if (!(ent->flags & MON_PERMIT)) |
fatal("%s: unpermitted request %d", __func__, |
fatal("%s: unpermitted request %d", __func__, |
type); |
type); |
ret = (*ent->f)(pmonitor->m_sendfd, &m); |
ret = (*ent->f)(pmonitor->m_sendfd, m); |
buffer_free(&m); |
sshbuf_free(m); |
|
|
/* The child may use this request only once, disable it */ |
/* The child may use this request only once, disable it */ |
if (ent->flags & MON_ONCE) { |
if (ent->flags & MON_ONCE) { |
|
|
|
|
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
int |
int |
mm_answer_moduli(int sock, Buffer *m) |
mm_answer_moduli(int sock, struct sshbuf *m) |
{ |
{ |
DH *dh; |
DH *dh; |
int min, want, max; |
int r; |
|
u_int min, want, max; |
|
|
min = buffer_get_int(m); |
if ((r = sshbuf_get_u32(m, &min)) != 0 || |
want = buffer_get_int(m); |
(r = sshbuf_get_u32(m, &want)) != 0 || |
max = buffer_get_int(m); |
(r = sshbuf_get_u32(m, &max)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
debug3("%s: got parameters: %d %d %d", |
debug3("%s: got parameters: %d %d %d", |
__func__, min, want, max); |
__func__, min, want, max); |
|
|
fatal("%s: bad parameters: %d %d %d", |
fatal("%s: bad parameters: %d %d %d", |
__func__, min, want, max); |
__func__, min, want, max); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
|
|
dh = choose_dh(min, want, max); |
dh = choose_dh(min, want, max); |
if (dh == NULL) { |
if (dh == NULL) { |
buffer_put_char(m, 0); |
if ((r = sshbuf_put_u8(m, 0)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
return (0); |
return (0); |
} else { |
} else { |
/* Send first bignum */ |
/* Send first bignum */ |
buffer_put_char(m, 1); |
if ((r = sshbuf_put_u8(m, 1)) != 0 || |
buffer_put_bignum2(m, dh->p); |
(r = sshbuf_put_bignum2(m, dh->p)) != 0 || |
buffer_put_bignum2(m, dh->g); |
(r = sshbuf_put_bignum2(m, dh->g)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
DH_free(dh); |
DH_free(dh); |
} |
} |
|
|
#endif |
#endif |
|
|
int |
int |
mm_answer_sign(int sock, Buffer *m) |
mm_answer_sign(int sock, struct sshbuf *m) |
{ |
{ |
struct ssh *ssh = active_state; /* XXX */ |
struct ssh *ssh = active_state; /* XXX */ |
extern int auth_sock; /* XXX move to state struct? */ |
extern int auth_sock; /* XXX move to state struct? */ |
|
|
/* Retrieves the password entry and also checks if the user is permitted */ |
/* Retrieves the password entry and also checks if the user is permitted */ |
|
|
int |
int |
mm_answer_pwnamallow(int sock, Buffer *m) |
mm_answer_pwnamallow(int sock, struct sshbuf *m) |
{ |
{ |
struct ssh *ssh = active_state; /* XXX */ |
struct ssh *ssh = active_state; /* XXX */ |
char *username; |
char *username; |
struct passwd *pwent; |
struct passwd *pwent; |
int allowed = 0; |
int r, allowed = 0; |
u_int i; |
u_int i; |
|
|
debug3("%s", __func__); |
debug3("%s", __func__); |
|
|
if (authctxt->attempt++ != 0) |
if (authctxt->attempt++ != 0) |
fatal("%s: multiple attempts for getpwnam", __func__); |
fatal("%s: multiple attempts for getpwnam", __func__); |
|
|
username = buffer_get_string(m, NULL); |
if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
pwent = getpwnamallow(username); |
pwent = getpwnamallow(username); |
|
|
|
|
setproctitle("%s [priv]", pwent ? username : "unknown"); |
setproctitle("%s [priv]", pwent ? username : "unknown"); |
free(username); |
free(username); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
|
|
if (pwent == NULL) { |
if (pwent == NULL) { |
buffer_put_char(m, 0); |
if ((r = sshbuf_put_u8(m, 0)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
authctxt->pw = fakepw(); |
authctxt->pw = fakepw(); |
goto out; |
goto out; |
} |
} |
|
|
authctxt->pw = pwent; |
authctxt->pw = pwent; |
authctxt->valid = 1; |
authctxt->valid = 1; |
|
|
buffer_put_char(m, 1); |
/* XXX don't sent pwent to unpriv; send fake class/dir/shell too */ |
buffer_put_string(m, pwent, sizeof(struct passwd)); |
if ((r = sshbuf_put_u8(m, 1)) != 0 || |
buffer_put_cstring(m, pwent->pw_name); |
(r = sshbuf_put_string(m, pwent, sizeof(*pwent))) != 0 || |
buffer_put_cstring(m, "*"); |
(r = sshbuf_put_cstring(m, pwent->pw_name)) != 0 || |
buffer_put_cstring(m, pwent->pw_gecos); |
(r = sshbuf_put_cstring(m, "*")) != 0 || |
buffer_put_cstring(m, pwent->pw_class); |
(r = sshbuf_put_cstring(m, pwent->pw_gecos)) != 0 || |
buffer_put_cstring(m, pwent->pw_dir); |
(r = sshbuf_put_cstring(m, pwent->pw_class)) != 0 || |
buffer_put_cstring(m, pwent->pw_shell); |
(r = sshbuf_put_cstring(m, pwent->pw_dir)) != 0 || |
|
(r = sshbuf_put_cstring(m, pwent->pw_shell)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
out: |
out: |
ssh_packet_set_log_preamble(ssh, "%suser %s", |
ssh_packet_set_log_preamble(ssh, "%suser %s", |
authctxt->valid ? "authenticating" : "invalid ", authctxt->user); |
authctxt->valid ? "authenticating" : "invalid ", authctxt->user); |
buffer_put_string(m, &options, sizeof(options)); |
if ((r = sshbuf_put_string(m, &options, sizeof(options))) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
#define M_CP_STROPT(x) do { \ |
#define M_CP_STROPT(x) do { \ |
if (options.x != NULL) \ |
if (options.x != NULL) { \ |
buffer_put_cstring(m, options.x); \ |
if ((r = sshbuf_put_cstring(m, options.x)) != 0) \ |
|
fatal("%s: buffer error: %s", \ |
|
__func__, ssh_err(r)); \ |
|
} \ |
} while (0) |
} while (0) |
#define M_CP_STRARRAYOPT(x, nx) do { \ |
#define M_CP_STRARRAYOPT(x, nx) do { \ |
for (i = 0; i < options.nx; i++) \ |
for (i = 0; i < options.nx; i++) { \ |
buffer_put_cstring(m, options.x[i]); \ |
if ((r = sshbuf_put_cstring(m, options.x[i])) != 0) \ |
|
fatal("%s: buffer error: %s", \ |
|
__func__, ssh_err(r)); \ |
|
} \ |
} while (0) |
} while (0) |
/* See comment in servconf.h */ |
/* See comment in servconf.h */ |
COPY_MATCH_STRING_OPTS(); |
COPY_MATCH_STRING_OPTS(); |
|
|
return (0); |
return (0); |
} |
} |
|
|
int mm_answer_auth2_read_banner(int sock, Buffer *m) |
int mm_answer_auth2_read_banner(int sock, struct sshbuf *m) |
{ |
{ |
char *banner; |
char *banner; |
|
int r; |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
banner = auth2_read_banner(); |
banner = auth2_read_banner(); |
buffer_put_cstring(m, banner != NULL ? banner : ""); |
if ((r = sshbuf_put_cstring(m, banner != NULL ? banner : "")) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m); |
mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m); |
free(banner); |
free(banner); |
|
|
|
|
} |
} |
|
|
int |
int |
mm_answer_authserv(int sock, Buffer *m) |
mm_answer_authserv(int sock, struct sshbuf *m) |
{ |
{ |
|
int r; |
|
|
monitor_permit_authentications(1); |
monitor_permit_authentications(1); |
|
|
authctxt->service = buffer_get_string(m, NULL); |
if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 || |
authctxt->style = buffer_get_string(m, NULL); |
(r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
debug3("%s: service=%s, style=%s", |
debug3("%s: service=%s, style=%s", |
__func__, authctxt->service, authctxt->style); |
__func__, authctxt->service, authctxt->style); |
|
|
|
|
} |
} |
|
|
int |
int |
mm_answer_authpassword(int sock, Buffer *m) |
mm_answer_authpassword(int sock, struct sshbuf *m) |
{ |
{ |
struct ssh *ssh = active_state; /* XXX */ |
struct ssh *ssh = active_state; /* XXX */ |
static int call_count; |
static int call_count; |
char *passwd; |
char *passwd; |
int authenticated; |
int r, authenticated; |
u_int plen; |
size_t plen; |
|
|
if (!options.password_authentication) |
if (!options.password_authentication) |
fatal("%s: password authentication not enabled", __func__); |
fatal("%s: password authentication not enabled", __func__); |
passwd = buffer_get_string(m, &plen); |
if ((r = sshbuf_get_cstring(m, &passwd, &plen)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
/* Only authenticate if the context is valid */ |
/* Only authenticate if the context is valid */ |
authenticated = options.password_authentication && |
authenticated = options.password_authentication && |
auth_password(ssh, passwd); |
auth_password(ssh, passwd); |
explicit_bzero(passwd, strlen(passwd)); |
explicit_bzero(passwd, plen); |
free(passwd); |
free(passwd); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, authenticated); |
if ((r = sshbuf_put_u32(m, authenticated)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
debug3("%s: sending result %d", __func__, authenticated); |
debug3("%s: sending result %d", __func__, authenticated); |
mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m); |
mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m); |
|
|
} |
} |
|
|
int |
int |
mm_answer_bsdauthquery(int sock, Buffer *m) |
mm_answer_bsdauthquery(int sock, struct sshbuf *m) |
{ |
{ |
char *name, *infotxt; |
char *name, *infotxt; |
u_int numprompts; |
u_int numprompts, *echo_on, success; |
u_int *echo_on; |
|
char **prompts; |
char **prompts; |
u_int success; |
int r; |
|
|
if (!options.kbd_interactive_authentication) |
if (!options.kbd_interactive_authentication) |
fatal("%s: kbd-int authentication not enabled", __func__); |
fatal("%s: kbd-int authentication not enabled", __func__); |
success = bsdauth_query(authctxt, &name, &infotxt, &numprompts, |
success = bsdauth_query(authctxt, &name, &infotxt, &numprompts, |
&prompts, &echo_on) < 0 ? 0 : 1; |
&prompts, &echo_on) < 0 ? 0 : 1; |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, success); |
if ((r = sshbuf_put_u32(m, success)) != 0) |
if (success) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
buffer_put_cstring(m, prompts[0]); |
if (success) { |
|
if ((r = sshbuf_put_cstring(m, prompts[0])) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
} |
|
|
debug3("%s: sending challenge success: %u", __func__, success); |
debug3("%s: sending challenge success: %u", __func__, success); |
mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m); |
mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m); |
|
|
} |
} |
|
|
int |
int |
mm_answer_bsdauthrespond(int sock, Buffer *m) |
mm_answer_bsdauthrespond(int sock, struct sshbuf *m) |
{ |
{ |
char *response; |
char *response; |
int authok; |
int r, authok; |
|
|
if (!options.kbd_interactive_authentication) |
if (!options.kbd_interactive_authentication) |
fatal("%s: kbd-int authentication not enabled", __func__); |
fatal("%s: kbd-int authentication not enabled", __func__); |
if (authctxt->as == NULL) |
if (authctxt->as == NULL) |
fatal("%s: no bsd auth session", __func__); |
fatal("%s: no bsd auth session", __func__); |
|
|
response = buffer_get_string(m, NULL); |
if ((r = sshbuf_get_cstring(m, &response, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
authok = options.challenge_response_authentication && |
authok = options.challenge_response_authentication && |
auth_userresponse(authctxt->as, response, 0); |
auth_userresponse(authctxt->as, response, 0); |
authctxt->as = NULL; |
authctxt->as = NULL; |
debug3("%s: <%s> = <%d>", __func__, response, authok); |
debug3("%s: <%s> = <%d>", __func__, response, authok); |
free(response); |
free(response); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, authok); |
if ((r = sshbuf_put_u32(m, authok)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
debug3("%s: sending authenticated: %d", __func__, authok); |
debug3("%s: sending authenticated: %d", __func__, authok); |
mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m); |
mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m); |
|
|
} |
} |
|
|
int |
int |
mm_answer_keyallowed(int sock, Buffer *m) |
mm_answer_keyallowed(int sock, struct sshbuf *m) |
{ |
{ |
struct ssh *ssh = active_state; /* XXX */ |
struct ssh *ssh = active_state; /* XXX */ |
struct sshkey *key; |
struct sshkey *key = NULL; |
char *cuser, *chost; |
char *cuser, *chost; |
u_char *blob; |
u_int pubkey_auth_attempt; |
u_int bloblen, pubkey_auth_attempt; |
|
enum mm_keytype type = 0; |
enum mm_keytype type = 0; |
int r, allowed = 0; |
int r, allowed = 0; |
struct sshauthopt *opts = NULL; |
struct sshauthopt *opts = NULL; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __func__); |
type = buffer_get_int(m); |
if ((r = sshbuf_get_u32(m, &type)) != 0 || |
cuser = buffer_get_string(m, NULL); |
(r = sshbuf_get_cstring(m, &cuser, NULL)) != 0 || |
chost = buffer_get_string(m, NULL); |
(r = sshbuf_get_cstring(m, &chost, NULL)) != 0 || |
blob = buffer_get_string(m, &bloblen); |
(r = sshkey_froms(m, &key)) != 0 || |
pubkey_auth_attempt = buffer_get_int(m); |
(r = sshbuf_get_u32(m, &pubkey_auth_attempt)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
key = key_from_blob(blob, bloblen); |
|
|
|
debug3("%s: key_from_blob: %p", __func__, key); |
debug3("%s: key_from_blob: %p", __func__, key); |
|
|
if (key != NULL && authctxt->valid) { |
if (key != NULL && authctxt->valid) { |
|
|
allowed ? "allowed" : "not allowed"); |
allowed ? "allowed" : "not allowed"); |
|
|
auth2_record_key(authctxt, 0, key); |
auth2_record_key(authctxt, 0, key); |
sshkey_free(key); |
|
|
|
/* clear temporarily storage (used by verify) */ |
/* clear temporarily storage (used by verify) */ |
monitor_reset_key_state(); |
monitor_reset_key_state(); |
|
|
if (allowed) { |
if (allowed) { |
/* Save temporarily for comparison in verify */ |
/* Save temporarily for comparison in verify */ |
key_blob = blob; |
if ((r = sshkey_to_blob(key, &key_blob, &key_bloblen)) != 0) |
key_bloblen = bloblen; |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
key_blobtype = type; |
key_blobtype = type; |
key_opts = opts; |
key_opts = opts; |
hostbased_cuser = cuser; |
hostbased_cuser = cuser; |
|
|
} else { |
} else { |
/* Log failed attempt */ |
/* Log failed attempt */ |
auth_log(authctxt, 0, 0, auth_method, NULL); |
auth_log(authctxt, 0, 0, auth_method, NULL); |
free(blob); |
|
free(cuser); |
free(cuser); |
free(chost); |
free(chost); |
} |
} |
|
sshkey_free(key); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, allowed); |
if ((r = sshbuf_put_u32(m, allowed)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0) |
if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0) |
fatal("%s: sshauthopt_serialise: %s", __func__, ssh_err(r)); |
fatal("%s: sshauthopt_serialise: %s", __func__, ssh_err(r)); |
mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); |
mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); |
|
|
static int |
static int |
monitor_valid_userblob(u_char *data, u_int datalen) |
monitor_valid_userblob(u_char *data, u_int datalen) |
{ |
{ |
Buffer b; |
struct sshbuf *b; |
u_char *p; |
const u_char *p; |
char *userstyle, *cp; |
char *userstyle, *cp; |
u_int len; |
size_t len; |
int fail = 0; |
u_char type; |
|
int r, fail = 0; |
|
|
buffer_init(&b); |
if ((b = sshbuf_new()) == NULL) |
buffer_append(&b, data, datalen); |
fatal("%s: sshbuf_new", __func__); |
|
if ((r = sshbuf_put(b, data, datalen)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
if (datafellows & SSH_OLD_SESSIONID) { |
if (datafellows & SSH_OLD_SESSIONID) { |
p = buffer_ptr(&b); |
p = sshbuf_ptr(b); |
len = buffer_len(&b); |
len = sshbuf_len(b); |
if ((session_id2 == NULL) || |
if ((session_id2 == NULL) || |
(len < session_id2_len) || |
(len < session_id2_len) || |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
fail++; |
fail++; |
buffer_consume(&b, session_id2_len); |
if ((r = sshbuf_consume(b, session_id2_len)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
} else { |
} else { |
p = buffer_get_string(&b, &len); |
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if ((session_id2 == NULL) || |
if ((session_id2 == NULL) || |
(len != session_id2_len) || |
(len != session_id2_len) || |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
fail++; |
fail++; |
free(p); |
|
} |
} |
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
if ((r = sshbuf_get_u8(b, &type)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (type != SSH2_MSG_USERAUTH_REQUEST) |
fail++; |
fail++; |
cp = buffer_get_cstring(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
xasprintf(&userstyle, "%s%s%s", authctxt->user, |
xasprintf(&userstyle, "%s%s%s", authctxt->user, |
authctxt->style ? ":" : "", |
authctxt->style ? ":" : "", |
authctxt->style ? authctxt->style : ""); |
authctxt->style ? authctxt->style : ""); |
|
|
} |
} |
free(userstyle); |
free(userstyle); |
free(cp); |
free(cp); |
buffer_skip_string(&b); |
if ((r = sshbuf_skip_string(b)) != 0 || /* service */ |
cp = buffer_get_cstring(&b, NULL); |
(r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (strcmp("publickey", cp) != 0) |
if (strcmp("publickey", cp) != 0) |
fail++; |
fail++; |
free(cp); |
free(cp); |
if (!buffer_get_char(&b)) |
if ((r = sshbuf_get_u8(b, &type)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (type == 0) |
fail++; |
fail++; |
buffer_skip_string(&b); |
if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */ |
buffer_skip_string(&b); |
(r = sshbuf_skip_string(b)) != 0) /* pkblob */ |
if (buffer_len(&b) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (sshbuf_len(b) != 0) |
fail++; |
fail++; |
buffer_free(&b); |
sshbuf_free(b); |
return (fail == 0); |
return (fail == 0); |
} |
} |
|
|
|
|
monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, |
monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, |
char *chost) |
char *chost) |
{ |
{ |
Buffer b; |
struct sshbuf *b; |
char *p, *userstyle; |
const u_char *p; |
u_int len; |
char *cp, *userstyle; |
int fail = 0; |
size_t len; |
|
int r, fail = 0; |
|
u_char type; |
|
|
buffer_init(&b); |
if ((b = sshbuf_new()) == NULL) |
buffer_append(&b, data, datalen); |
fatal("%s: sshbuf_new", __func__); |
|
if ((r = sshbuf_put(b, data, datalen)) != 0 || |
|
(r = sshbuf_get_string_direct(b, &p, &len)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
p = buffer_get_string(&b, &len); |
|
if ((session_id2 == NULL) || |
if ((session_id2 == NULL) || |
(len != session_id2_len) || |
(len != session_id2_len) || |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) |
fail++; |
fail++; |
free(p); |
|
|
|
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
if ((r = sshbuf_get_u8(b, &type)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (type != SSH2_MSG_USERAUTH_REQUEST) |
fail++; |
fail++; |
p = buffer_get_cstring(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
xasprintf(&userstyle, "%s%s%s", authctxt->user, |
xasprintf(&userstyle, "%s%s%s", authctxt->user, |
authctxt->style ? ":" : "", |
authctxt->style ? ":" : "", |
authctxt->style ? authctxt->style : ""); |
authctxt->style ? authctxt->style : ""); |
if (strcmp(userstyle, p) != 0) { |
if (strcmp(userstyle, cp) != 0) { |
logit("wrong user name passed to monitor: expected %s != %.100s", |
logit("wrong user name passed to monitor: " |
userstyle, p); |
"expected %s != %.100s", userstyle, cp); |
fail++; |
fail++; |
} |
} |
free(userstyle); |
free(userstyle); |
free(p); |
free(cp); |
buffer_skip_string(&b); /* service */ |
if ((r = sshbuf_skip_string(b)) != 0 || /* service */ |
p = buffer_get_cstring(&b, NULL); |
(r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
if (strcmp(p, "hostbased") != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (strcmp(cp, "hostbased") != 0) |
fail++; |
fail++; |
free(p); |
free(cp); |
buffer_skip_string(&b); /* pkalg */ |
if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */ |
buffer_skip_string(&b); /* pkblob */ |
(r = sshbuf_skip_string(b)) != 0) /* pkblob */ |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
/* verify client host, strip trailing dot if necessary */ |
/* verify client host, strip trailing dot if necessary */ |
p = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
if (((len = strlen(p)) > 0) && p[len - 1] == '.') |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
p[len - 1] = '\0'; |
if (((len = strlen(cp)) > 0) && cp[len - 1] == '.') |
if (strcmp(p, chost) != 0) |
cp[len - 1] = '\0'; |
|
if (strcmp(cp, chost) != 0) |
fail++; |
fail++; |
free(p); |
free(cp); |
|
|
/* verify client user */ |
/* verify client user */ |
p = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) |
if (strcmp(p, cuser) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (strcmp(cp, cuser) != 0) |
fail++; |
fail++; |
free(p); |
free(cp); |
|
|
if (buffer_len(&b) != 0) |
if (sshbuf_len(b) != 0) |
fail++; |
fail++; |
buffer_free(&b); |
sshbuf_free(b); |
return (fail == 0); |
return (fail == 0); |
} |
} |
|
|
|
|
} |
} |
|
|
int |
int |
mm_answer_pty(int sock, Buffer *m) |
mm_answer_pty(int sock, struct sshbuf *m) |
{ |
{ |
extern struct monitor *pmonitor; |
extern struct monitor *pmonitor; |
Session *s; |
Session *s; |
int res, fd0; |
int r, res, fd0; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __func__); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
s = session_new(); |
s = session_new(); |
if (s == NULL) |
if (s == NULL) |
goto error; |
goto error; |
|
|
goto error; |
goto error; |
pty_setowner(authctxt->pw, s->tty); |
pty_setowner(authctxt->pw, s->tty); |
|
|
buffer_put_int(m, 1); |
if ((r = sshbuf_put_u32(m, 1)) != 0 || |
buffer_put_cstring(m, s->tty); |
(r = sshbuf_put_cstring(m, s->tty)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
/* We need to trick ttyslot */ |
/* We need to trick ttyslot */ |
if (dup2(s->ttyfd, 0) == -1) |
if (dup2(s->ttyfd, 0) == -1) |
|
|
close(0); |
close(0); |
|
|
/* send messages generated by record_login */ |
/* send messages generated by record_login */ |
buffer_put_string(m, buffer_ptr(loginmsg), buffer_len(loginmsg)); |
if ((r = sshbuf_put_stringb(m, loginmsg)) != 0) |
buffer_clear(loginmsg); |
fatal("%s: put login message: %s", __func__, ssh_err(r)); |
|
sshbuf_reset(loginmsg); |
|
|
mm_request_send(sock, MONITOR_ANS_PTY, m); |
mm_request_send(sock, MONITOR_ANS_PTY, m); |
|
|
|
|
error: |
error: |
if (s != NULL) |
if (s != NULL) |
mm_session_close(s); |
mm_session_close(s); |
buffer_put_int(m, 0); |
if ((r = sshbuf_put_u32(m, 0)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
mm_request_send(sock, MONITOR_ANS_PTY, m); |
mm_request_send(sock, MONITOR_ANS_PTY, m); |
return (0); |
return (0); |
} |
} |
|
|
int |
int |
mm_answer_pty_cleanup(int sock, Buffer *m) |
mm_answer_pty_cleanup(int sock, struct sshbuf *m) |
{ |
{ |
Session *s; |
Session *s; |
char *tty; |
char *tty; |
|
int r; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __func__); |
|
|
tty = buffer_get_string(m, NULL); |
if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if ((s = session_by_tty(tty)) != NULL) |
if ((s = session_by_tty(tty)) != NULL) |
mm_session_close(s); |
mm_session_close(s); |
buffer_clear(m); |
sshbuf_reset(m); |
free(tty); |
free(tty); |
return (0); |
return (0); |
} |
} |
|
|
int |
int |
mm_answer_term(int sock, Buffer *req) |
mm_answer_term(int sock, struct sshbuf *req) |
{ |
{ |
struct ssh *ssh = active_state; /* XXX */ |
struct ssh *ssh = active_state; /* XXX */ |
extern struct monitor *pmonitor; |
extern struct monitor *pmonitor; |
|
|
|
|
#ifdef GSSAPI |
#ifdef GSSAPI |
int |
int |
mm_answer_gss_setup_ctx(int sock, Buffer *m) |
mm_answer_gss_setup_ctx(int sock, struct sshbuf *m) |
{ |
{ |
gss_OID_desc goid; |
gss_OID_desc goid; |
OM_uint32 major; |
OM_uint32 major; |
u_int len; |
size_t len; |
|
int r; |
|
|
if (!options.gss_authentication) |
if (!options.gss_authentication) |
fatal("%s: GSSAPI authentication not enabled", __func__); |
fatal("%s: GSSAPI authentication not enabled", __func__); |
|
|
goid.elements = buffer_get_string(m, &len); |
if ((r = sshbuf_get_string(m, &goid.elements, &len)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
goid.length = len; |
goid.length = len; |
|
|
major = ssh_gssapi_server_ctx(&gsscontext, &goid); |
major = ssh_gssapi_server_ctx(&gsscontext, &goid); |
|
|
free(goid.elements); |
free(goid.elements); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, major); |
if ((r = sshbuf_put_u32(m, major)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
mm_request_send(sock, MONITOR_ANS_GSSSETUP, m); |
mm_request_send(sock, MONITOR_ANS_GSSSETUP, m); |
|
|
|
|
} |
} |
|
|
int |
int |
mm_answer_gss_accept_ctx(int sock, Buffer *m) |
mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) |
{ |
{ |
gss_buffer_desc in; |
gss_buffer_desc in; |
gss_buffer_desc out = GSS_C_EMPTY_BUFFER; |
gss_buffer_desc out = GSS_C_EMPTY_BUFFER; |
OM_uint32 major, minor; |
OM_uint32 major, minor; |
OM_uint32 flags = 0; /* GSI needs this */ |
OM_uint32 flags = 0; /* GSI needs this */ |
u_int len; |
int r; |
|
|
if (!options.gss_authentication) |
if (!options.gss_authentication) |
fatal("%s: GSSAPI authentication not enabled", __func__); |
fatal("%s: GSSAPI authentication not enabled", __func__); |
|
|
in.value = buffer_get_string(m, &len); |
if ((r = sshbuf_get_string(m, &in.value, &in.length)) != 0) |
in.length = len; |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); |
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); |
free(in.value); |
free(in.value); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, major); |
if ((r = sshbuf_put_u32(m, major)) != 0 || |
buffer_put_string(m, out.value, out.length); |
(r = sshbuf_put_string(m, out.value, out.length)) != 0 || |
buffer_put_int(m, flags); |
(r = sshbuf_put_u32(m, flags)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); |
mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); |
|
|
gss_release_buffer(&minor, &out); |
gss_release_buffer(&minor, &out); |
|
|
} |
} |
|
|
int |
int |
mm_answer_gss_checkmic(int sock, Buffer *m) |
mm_answer_gss_checkmic(int sock, struct sshbuf *m) |
{ |
{ |
gss_buffer_desc gssbuf, mic; |
gss_buffer_desc gssbuf, mic; |
OM_uint32 ret; |
OM_uint32 ret; |
u_int len; |
|
|
|
if (!options.gss_authentication) |
if (!options.gss_authentication) |
fatal("%s: GSSAPI authentication not enabled", __func__); |
fatal("%s: GSSAPI authentication not enabled", __func__); |
|
|
gssbuf.value = buffer_get_string(m, &len); |
if ((r = sshbuf_get_string(m, &gssbuf.value, &gssbuf.length)) != 0 || |
gssbuf.length = len; |
(r = sshbuf_get_string(m, &mic.value, &mic.length)) != 0) |
mic.value = buffer_get_string(m, &len); |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
mic.length = len; |
|
|
|
ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); |
ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); |
|
|
free(gssbuf.value); |
free(gssbuf.value); |
free(mic.value); |
free(mic.value); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, ret); |
if ((r = sshbuf_put_u32(m, ret)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m); |
mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m); |
|
|
|
|
} |
} |
|
|
int |
int |
mm_answer_gss_userok(int sock, Buffer *m) |
mm_answer_gss_userok(int sock, struct sshbuf *m) |
{ |
{ |
int authenticated; |
int authenticated; |
const char *displayname; |
const char *displayname; |
|
|
|
|
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); |
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); |
|
|
buffer_clear(m); |
sshbuf_reset(m); |
buffer_put_int(m, authenticated); |
if ((r = sshbuf_put_u32(m, authenticated)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
debug3("%s: sending result %d", __func__, authenticated); |
debug3("%s: sending result %d", __func__, authenticated); |
mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); |
mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); |