version 1.11.2.1, 2002/05/17 00:03:23 |
version 1.11.2.2, 2002/06/22 07:23:17 |
|
|
u_int ivinlen; |
u_int ivinlen; |
u_char *ivout; |
u_char *ivout; |
u_int ivoutlen; |
u_int ivoutlen; |
|
u_char *ssh1key; |
|
u_int ssh1keylen; |
int ssh1cipher; |
int ssh1cipher; |
int ssh1protoflags; |
int ssh1protoflags; |
u_char *input; |
u_char *input; |
|
|
static u_char *hostbased_cuser = NULL; |
static u_char *hostbased_cuser = NULL; |
static u_char *hostbased_chost = NULL; |
static u_char *hostbased_chost = NULL; |
static char *auth_method = "unknown"; |
static char *auth_method = "unknown"; |
|
static int session_id2_len = 0; |
|
static u_char *session_id2 = NULL; |
|
|
struct mon_table { |
struct mon_table { |
enum monitor_reqtype type; |
enum monitor_reqtype type; |
|
|
if (authenticated) { |
if (authenticated) { |
if (!(ent->flags & MON_AUTHDECIDE)) |
if (!(ent->flags & MON_AUTHDECIDE)) |
fatal("%s: unexpected authentication from %d", |
fatal("%s: unexpected authentication from %d", |
__FUNCTION__, ent->type); |
__func__, ent->type); |
if (authctxt->pw->pw_uid == 0 && |
if (authctxt->pw->pw_uid == 0 && |
!auth_root_allowed(auth_method)) |
!auth_root_allowed(auth_method)) |
authenticated = 0; |
authenticated = 0; |
|
|
} |
} |
|
|
if (!authctxt->valid) |
if (!authctxt->valid) |
fatal("%s: authenticated invalid user", __FUNCTION__); |
fatal("%s: authenticated invalid user", __func__); |
|
|
debug("%s: %s has been authenticated by privileged process", |
debug("%s: %s has been authenticated by privileged process", |
__FUNCTION__, authctxt->user); |
__func__, authctxt->user); |
|
|
mm_get_keystate(pmonitor); |
mm_get_keystate(pmonitor); |
|
|
|
|
void |
void |
monitor_sync(struct monitor *pmonitor) |
monitor_sync(struct monitor *pmonitor) |
{ |
{ |
/* The member allocation is not visible, so sync it */ |
if (options.compression) { |
mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); |
/* The member allocation is not visible, so sync it */ |
|
mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); |
|
} |
} |
} |
|
|
int |
int |
|
|
mm_request_receive(pmonitor->m_sendfd, &m); |
mm_request_receive(pmonitor->m_sendfd, &m); |
type = buffer_get_char(&m); |
type = buffer_get_char(&m); |
|
|
debug3("%s: checking request %d", __FUNCTION__, type); |
debug3("%s: checking request %d", __func__, type); |
|
|
while (ent->f != NULL) { |
while (ent->f != NULL) { |
if (ent->type == type) |
if (ent->type == type) |
|
|
|
|
if (ent->f != NULL) { |
if (ent->f != NULL) { |
if (!(ent->flags & MON_PERMIT)) |
if (!(ent->flags & MON_PERMIT)) |
fatal("%s: unpermitted request %d", __FUNCTION__, |
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); |
buffer_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) { |
debug2("%s: %d used once, disabling now", __FUNCTION__, |
debug2("%s: %d used once, disabling now", __func__, |
type); |
type); |
ent->flags &= ~MON_PERMIT; |
ent->flags &= ~MON_PERMIT; |
} |
} |
|
|
return ret; |
return ret; |
} |
} |
|
|
fatal("%s: unsupported request: %d", __FUNCTION__, type); |
fatal("%s: unsupported request: %d", __func__, type); |
|
|
/* NOTREACHED */ |
/* NOTREACHED */ |
return (-1); |
return (-1); |
|
|
max = buffer_get_int(m); |
max = buffer_get_int(m); |
|
|
debug3("%s: got parameters: %d %d %d", |
debug3("%s: got parameters: %d %d %d", |
__FUNCTION__, min, want, max); |
__func__, min, want, max); |
/* We need to check here, too, in case the child got corrupted */ |
/* We need to check here, too, in case the child got corrupted */ |
if (max < min || want < min || max < want) |
if (max < min || want < min || max < want) |
fatal("%s: bad parameters: %d %d %d", |
fatal("%s: bad parameters: %d %d %d", |
__FUNCTION__, min, want, max); |
__func__, min, want, max); |
|
|
buffer_clear(m); |
buffer_clear(m); |
|
|
|
|
u_int siglen, datlen; |
u_int siglen, datlen; |
int keyid; |
int keyid; |
|
|
debug3("%s", __FUNCTION__); |
debug3("%s", __func__); |
|
|
keyid = buffer_get_int(m); |
keyid = buffer_get_int(m); |
p = buffer_get_string(m, &datlen); |
p = buffer_get_string(m, &datlen); |
|
|
if (datlen != 20) |
if (datlen != 20) |
fatal("%s: data length incorrect: %d", __FUNCTION__, datlen); |
fatal("%s: data length incorrect: %d", __func__, datlen); |
|
|
|
/* save session id, it will be passed on the first call */ |
|
if (session_id2_len == 0) { |
|
session_id2_len = datlen; |
|
session_id2 = xmalloc(session_id2_len); |
|
memcpy(session_id2, p, session_id2_len); |
|
} |
|
|
if ((key = get_hostkey_by_index(keyid)) == NULL) |
if ((key = get_hostkey_by_index(keyid)) == NULL) |
fatal("%s: no hostkey from index %d", __FUNCTION__, keyid); |
fatal("%s: no hostkey from index %d", __func__, keyid); |
if (key_sign(key, &signature, &siglen, p, datlen) < 0) |
if (key_sign(key, &signature, &siglen, p, datlen) < 0) |
fatal("%s: key_sign failed", __FUNCTION__); |
fatal("%s: key_sign failed", __func__); |
|
|
debug3("%s: signature %p(%d)", __FUNCTION__, signature, siglen); |
debug3("%s: signature %p(%d)", __func__, signature, siglen); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_string(m, signature, siglen); |
buffer_put_string(m, signature, siglen); |
|
|
struct passwd *pwent; |
struct passwd *pwent; |
int allowed = 0; |
int allowed = 0; |
|
|
debug3("%s", __FUNCTION__); |
debug3("%s", __func__); |
|
|
if (authctxt->attempt++ != 0) |
if (authctxt->attempt++ != 0) |
fatal("%s: multiple attempts for getpwnam", __FUNCTION__); |
fatal("%s: multiple attempts for getpwnam", __func__); |
|
|
login = buffer_get_string(m, NULL); |
login = buffer_get_string(m, NULL); |
|
|
|
|
buffer_put_cstring(m, pwent->pw_shell); |
buffer_put_cstring(m, pwent->pw_shell); |
|
|
out: |
out: |
debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, allowed); |
debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed); |
mm_request_send(socket, MONITOR_ANS_PWNAM, m); |
mm_request_send(socket, MONITOR_ANS_PWNAM, m); |
|
|
/* For SSHv1 allow authentication now */ |
/* For SSHv1 allow authentication now */ |
|
|
authctxt->service = buffer_get_string(m, NULL); |
authctxt->service = buffer_get_string(m, NULL); |
authctxt->style = buffer_get_string(m, NULL); |
authctxt->style = buffer_get_string(m, NULL); |
debug3("%s: service=%s, style=%s", |
debug3("%s: service=%s, style=%s", |
__FUNCTION__, authctxt->service, authctxt->style); |
__func__, authctxt->service, authctxt->style); |
|
|
if (strlen(authctxt->style) == 0) { |
if (strlen(authctxt->style) == 0) { |
xfree(authctxt->style); |
xfree(authctxt->style); |
|
|
|
|
passwd = buffer_get_string(m, &plen); |
passwd = buffer_get_string(m, &plen); |
/* Only authenticate if the context is valid */ |
/* Only authenticate if the context is valid */ |
authenticated = authctxt->valid && auth_password(authctxt, passwd); |
authenticated = options.password_authentication && |
|
authctxt->valid && auth_password(authctxt, passwd); |
memset(passwd, 0, strlen(passwd)); |
memset(passwd, 0, strlen(passwd)); |
xfree(passwd); |
xfree(passwd); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, authenticated); |
buffer_put_int(m, authenticated); |
|
|
debug3("%s: sending result %d", __FUNCTION__, authenticated); |
debug3("%s: sending result %d", __func__, authenticated); |
mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); |
mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); |
|
|
call_count++; |
call_count++; |
|
|
if (res != -1) |
if (res != -1) |
buffer_put_cstring(m, prompts[0]); |
buffer_put_cstring(m, prompts[0]); |
|
|
debug3("%s: sending challenge res: %d", __FUNCTION__, res); |
debug3("%s: sending challenge res: %d", __func__, res); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); |
|
|
if (res != -1) { |
if (res != -1) { |
|
|
int authok; |
int authok; |
|
|
if (authctxt->as == 0) |
if (authctxt->as == 0) |
fatal("%s: no bsd auth session", __FUNCTION__); |
fatal("%s: no bsd auth session", __func__); |
|
|
response = buffer_get_string(m, NULL); |
response = buffer_get_string(m, NULL); |
authok = auth_userresponse(authctxt->as, response, 0); |
authok = options.challenge_response_authentication && |
|
auth_userresponse(authctxt->as, response, 0); |
authctxt->as = NULL; |
authctxt->as = NULL; |
debug3("%s: <%s> = <%d>", __FUNCTION__, response, authok); |
debug3("%s: <%s> = <%d>", __func__, response, authok); |
xfree(response); |
xfree(response); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, authok); |
buffer_put_int(m, authok); |
|
|
debug3("%s: sending authenticated: %d", __FUNCTION__, authok); |
debug3("%s: sending authenticated: %d", __func__, authok); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); |
|
|
auth_method = "bsdauth"; |
auth_method = "bsdauth"; |
|
|
if (res != -1) |
if (res != -1) |
buffer_put_cstring(m, challenge); |
buffer_put_cstring(m, challenge); |
|
|
debug3("%s: sending challenge res: %d", __FUNCTION__, res); |
debug3("%s: sending challenge res: %d", __func__, res); |
mm_request_send(socket, MONITOR_ANS_SKEYQUERY, m); |
mm_request_send(socket, MONITOR_ANS_SKEYQUERY, m); |
|
|
return (0); |
return (0); |
|
|
|
|
response = buffer_get_string(m, NULL); |
response = buffer_get_string(m, NULL); |
|
|
authok = (authctxt->valid && |
authok = (options.challenge_response_authentication && |
|
authctxt->valid && |
skey_haskey(authctxt->pw->pw_name) == 0 && |
skey_haskey(authctxt->pw->pw_name) == 0 && |
skey_passcheck(authctxt->pw->pw_name, response) != -1); |
skey_passcheck(authctxt->pw->pw_name, response) != -1); |
|
|
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, authok); |
buffer_put_int(m, authok); |
|
|
debug3("%s: sending authenticated: %d", __FUNCTION__, authok); |
debug3("%s: sending authenticated: %d", __func__, authok); |
mm_request_send(socket, MONITOR_ANS_SKEYRESPOND, m); |
mm_request_send(socket, MONITOR_ANS_SKEYRESPOND, m); |
|
|
auth_method = "skey"; |
auth_method = "skey"; |
|
|
mm_append_debug(Buffer *m) |
mm_append_debug(Buffer *m) |
{ |
{ |
if (auth_debug_init && buffer_len(&auth_debug)) { |
if (auth_debug_init && buffer_len(&auth_debug)) { |
debug3("%s: Appending debug messages for child", __FUNCTION__); |
debug3("%s: Appending debug messages for child", __func__); |
buffer_append(m, buffer_ptr(&auth_debug), |
buffer_append(m, buffer_ptr(&auth_debug), |
buffer_len(&auth_debug)); |
buffer_len(&auth_debug)); |
buffer_clear(&auth_debug); |
buffer_clear(&auth_debug); |
|
|
enum mm_keytype type = 0; |
enum mm_keytype type = 0; |
int allowed = 0; |
int allowed = 0; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
type = buffer_get_int(m); |
type = buffer_get_int(m); |
cuser = buffer_get_string(m, NULL); |
cuser = buffer_get_string(m, NULL); |
|
|
|
|
if ((compat20 && type == MM_RSAHOSTKEY) || |
if ((compat20 && type == MM_RSAHOSTKEY) || |
(!compat20 && type != MM_RSAHOSTKEY)) |
(!compat20 && type != MM_RSAHOSTKEY)) |
fatal("%s: key type and protocol mismatch", __FUNCTION__); |
fatal("%s: key type and protocol mismatch", __func__); |
|
|
debug3("%s: key_from_blob: %p", __FUNCTION__, key); |
debug3("%s: key_from_blob: %p", __func__, key); |
|
|
if (key != NULL && authctxt->pw != NULL) { |
if (key != NULL && authctxt->pw != NULL) { |
switch(type) { |
switch(type) { |
case MM_USERKEY: |
case MM_USERKEY: |
allowed = user_key_allowed(authctxt->pw, key); |
allowed = options.pubkey_authentication && |
|
user_key_allowed(authctxt->pw, key); |
break; |
break; |
case MM_HOSTKEY: |
case MM_HOSTKEY: |
allowed = hostbased_key_allowed(authctxt->pw, |
allowed = options.hostbased_authentication && |
|
hostbased_key_allowed(authctxt->pw, |
cuser, chost, key); |
cuser, chost, key); |
break; |
break; |
case MM_RSAHOSTKEY: |
case MM_RSAHOSTKEY: |
key->type = KEY_RSA1; /* XXX */ |
key->type = KEY_RSA1; /* XXX */ |
allowed = auth_rhosts_rsa_key_allowed(authctxt->pw, |
allowed = options.rhosts_rsa_authentication && |
|
auth_rhosts_rsa_key_allowed(authctxt->pw, |
cuser, chost, key); |
cuser, chost, key); |
break; |
break; |
default: |
default: |
fatal("%s: unknown key type %d", __FUNCTION__, type); |
fatal("%s: unknown key type %d", __func__, type); |
break; |
break; |
} |
} |
key_free(key); |
key_free(key); |
|
|
} |
} |
|
|
debug3("%s: key %p is %s", |
debug3("%s: key %p is %s", |
__FUNCTION__, key, allowed ? "allowed" : "disallowed"); |
__func__, key, allowed ? "allowed" : "disallowed"); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, allowed); |
buffer_put_int(m, allowed); |
|
|
u_char *p; |
u_char *p; |
u_int len; |
u_int len; |
int fail = 0; |
int fail = 0; |
int session_id2_len = 20 /*XXX should get from [net] */; |
|
|
|
buffer_init(&b); |
buffer_init(&b); |
buffer_append(&b, data, datalen); |
buffer_append(&b, data, datalen); |
|
|
if (datafellows & SSH_OLD_SESSIONID) { |
if (datafellows & SSH_OLD_SESSIONID) { |
|
p = buffer_ptr(&b); |
|
len = buffer_len(&b); |
|
if ((session_id2 == NULL) || |
|
(len < session_id2_len) || |
|
(memcmp(p, session_id2, session_id2_len) != 0)) |
|
fail++; |
buffer_consume(&b, session_id2_len); |
buffer_consume(&b, session_id2_len); |
} else { |
} else { |
xfree(buffer_get_string(&b, &len)); |
p = buffer_get_string(&b, &len); |
if (len != session_id2_len) |
if ((session_id2 == NULL) || |
|
(len != session_id2_len) || |
|
(memcmp(p, session_id2, session_id2_len) != 0)) |
fail++; |
fail++; |
|
xfree(p); |
} |
} |
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
fail++; |
fail++; |
|
|
u_char *p; |
u_char *p; |
u_int len; |
u_int len; |
int fail = 0; |
int fail = 0; |
int session_id2_len = 20 /*XXX should get from [net] */; |
|
|
|
buffer_init(&b); |
buffer_init(&b); |
buffer_append(&b, data, datalen); |
buffer_append(&b, data, datalen); |
|
|
xfree(buffer_get_string(&b, &len)); |
p = buffer_get_string(&b, &len); |
if (len != session_id2_len) |
if ((session_id2 == NULL) || |
|
(len != session_id2_len) || |
|
(memcmp(p, session_id2, session_id2_len) != 0)) |
fail++; |
fail++; |
|
xfree(p); |
|
|
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
fail++; |
fail++; |
p = buffer_get_string(&b, NULL); |
p = buffer_get_string(&b, NULL); |
|
|
|
|
if (hostbased_cuser == NULL || hostbased_chost == NULL || |
if (hostbased_cuser == NULL || hostbased_chost == NULL || |
!monitor_allowed_key(blob, bloblen)) |
!monitor_allowed_key(blob, bloblen)) |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
fatal("%s: bad key, not previously allowed", __func__); |
|
|
key = key_from_blob(blob, bloblen); |
key = key_from_blob(blob, bloblen); |
if (key == NULL) |
if (key == NULL) |
fatal("%s: bad public key blob", __FUNCTION__); |
fatal("%s: bad public key blob", __func__); |
|
|
switch (key_blobtype) { |
switch (key_blobtype) { |
case MM_USERKEY: |
case MM_USERKEY: |
|
|
break; |
break; |
} |
} |
if (!valid_data) |
if (!valid_data) |
fatal("%s: bad signature data blob", __FUNCTION__); |
fatal("%s: bad signature data blob", __func__); |
|
|
verified = key_verify(key, signature, signaturelen, data, datalen); |
verified = key_verify(key, signature, signaturelen, data, datalen); |
debug3("%s: key %p signature %s", |
debug3("%s: key %p signature %s", |
__FUNCTION__, key, verified ? "verified" : "unverified"); |
__func__, key, verified ? "verified" : "unverified"); |
|
|
key_free(key); |
key_free(key); |
xfree(blob); |
xfree(blob); |
|
|
buffer_put_int(m, verified); |
buffer_put_int(m, verified); |
mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m); |
mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m); |
|
|
auth_method = "publickey"; |
auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased"; |
|
|
return (verified); |
return (verified); |
} |
} |
|
|
static void |
static void |
mm_session_close(Session *s) |
mm_session_close(Session *s) |
{ |
{ |
debug3("%s: session %d pid %d", __FUNCTION__, s->self, s->pid); |
debug3("%s: session %d pid %d", __func__, s->self, s->pid); |
if (s->ttyfd != -1) { |
if (s->ttyfd != -1) { |
debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ptyfd); |
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); |
fatal_remove_cleanup(session_pty_cleanup2, (void *)s); |
fatal_remove_cleanup(session_pty_cleanup2, (void *)s); |
session_pty_cleanup2(s); |
session_pty_cleanup2(s); |
} |
} |
|
|
Session *s; |
Session *s; |
int res, fd0; |
int res, fd0; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
buffer_clear(m); |
buffer_clear(m); |
s = session_new(); |
s = session_new(); |
|
|
|
|
/* We need to trick ttyslot */ |
/* We need to trick ttyslot */ |
if (dup2(s->ttyfd, 0) == -1) |
if (dup2(s->ttyfd, 0) == -1) |
fatal("%s: dup2", __FUNCTION__); |
fatal("%s: dup2", __func__); |
|
|
mm_record_login(s, authctxt->pw); |
mm_record_login(s, authctxt->pw); |
|
|
|
|
|
|
/* make sure nothing uses fd 0 */ |
/* make sure nothing uses fd 0 */ |
if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) |
if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) |
fatal("%s: open(/dev/null): %s", __FUNCTION__, strerror(errno)); |
fatal("%s: open(/dev/null): %s", __func__, strerror(errno)); |
if (fd0 != 0) |
if (fd0 != 0) |
error("%s: fd0 %d != 0", __FUNCTION__, fd0); |
error("%s: fd0 %d != 0", __func__, fd0); |
|
|
/* slave is not needed */ |
/* slave is not needed */ |
close(s->ttyfd); |
close(s->ttyfd); |
|
|
/* no need to dup() because nobody closes ptyfd */ |
/* no need to dup() because nobody closes ptyfd */ |
s->ptymaster = s->ptyfd; |
s->ptymaster = s->ptyfd; |
|
|
debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ttyfd); |
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ttyfd); |
|
|
return (0); |
return (0); |
|
|
|
|
Session *s; |
Session *s; |
char *tty; |
char *tty; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
tty = buffer_get_string(m, NULL); |
tty = buffer_get_string(m, NULL); |
if ((s = session_by_tty(tty)) != NULL) |
if ((s = session_by_tty(tty)) != NULL) |
|
|
monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); |
|
|
if ((p = BN_new()) == NULL) |
if ((p = BN_new()) == NULL) |
fatal("%s: BN_new", __FUNCTION__); |
fatal("%s: BN_new", __func__); |
|
|
buffer_get_bignum2(m, p); |
buffer_get_bignum2(m, p); |
|
|
|
|
{ |
{ |
int i; |
int i; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
if (buffer_len(m) != 16) |
if (buffer_len(m) != 16) |
fatal("%s: bad ssh1 session id", __FUNCTION__); |
fatal("%s: bad ssh1 session id", __func__); |
for (i = 0; i < 16; i++) |
for (i = 0; i < 16; i++) |
session_id[i] = buffer_get_char(m); |
session_id[i] = buffer_get_char(m); |
|
|
|
|
u_int blen = 0; |
u_int blen = 0; |
int allowed = 0; |
int allowed = 0; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
if (authctxt->valid) { |
if (options.rsa_authentication && authctxt->valid) { |
if ((client_n = BN_new()) == NULL) |
if ((client_n = BN_new()) == NULL) |
fatal("%s: BN_new", __FUNCTION__); |
fatal("%s: BN_new", __func__); |
buffer_get_bignum2(m, client_n); |
buffer_get_bignum2(m, client_n); |
allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); |
allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); |
BN_clear_free(client_n); |
BN_clear_free(client_n); |
|
|
if (allowed && key != NULL) { |
if (allowed && key != NULL) { |
key->type = KEY_RSA; /* cheat for key_to_blob */ |
key->type = KEY_RSA; /* cheat for key_to_blob */ |
if (key_to_blob(key, &blob, &blen) == 0) |
if (key_to_blob(key, &blob, &blen) == 0) |
fatal("%s: key_to_blob failed", __FUNCTION__); |
fatal("%s: key_to_blob failed", __func__); |
buffer_put_string(m, blob, blen); |
buffer_put_string(m, blob, blen); |
|
|
/* Save temporarily for comparison in verify */ |
/* Save temporarily for comparison in verify */ |
|
|
u_char *blob; |
u_char *blob; |
u_int blen; |
u_int blen; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
if (!authctxt->valid) |
if (!authctxt->valid) |
fatal("%s: authctxt not valid", __FUNCTION__); |
fatal("%s: authctxt not valid", __func__); |
blob = buffer_get_string(m, &blen); |
blob = buffer_get_string(m, &blen); |
if (!monitor_allowed_key(blob, blen)) |
if (!monitor_allowed_key(blob, blen)) |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
fatal("%s: bad key, not previously allowed", __func__); |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
fatal("%s: key type mismatch", __FUNCTION__); |
fatal("%s: key type mismatch", __func__); |
if ((key = key_from_blob(blob, blen)) == NULL) |
if ((key = key_from_blob(blob, blen)) == NULL) |
fatal("%s: received bad key", __FUNCTION__); |
fatal("%s: received bad key", __func__); |
|
|
if (ssh1_challenge) |
if (ssh1_challenge) |
BN_clear_free(ssh1_challenge); |
BN_clear_free(ssh1_challenge); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_bignum2(m, ssh1_challenge); |
buffer_put_bignum2(m, ssh1_challenge); |
|
|
debug3("%s sending reply", __FUNCTION__); |
debug3("%s sending reply", __func__); |
mm_request_send(socket, MONITOR_ANS_RSACHALLENGE, m); |
mm_request_send(socket, MONITOR_ANS_RSACHALLENGE, m); |
|
|
monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1); |
|
|
u_int blen, len; |
u_int blen, len; |
int success; |
int success; |
|
|
debug3("%s entering", __FUNCTION__); |
debug3("%s entering", __func__); |
|
|
if (!authctxt->valid) |
if (!authctxt->valid) |
fatal("%s: authctxt not valid", __FUNCTION__); |
fatal("%s: authctxt not valid", __func__); |
if (ssh1_challenge == NULL) |
if (ssh1_challenge == NULL) |
fatal("%s: no ssh1_challenge", __FUNCTION__); |
fatal("%s: no ssh1_challenge", __func__); |
|
|
blob = buffer_get_string(m, &blen); |
blob = buffer_get_string(m, &blen); |
if (!monitor_allowed_key(blob, blen)) |
if (!monitor_allowed_key(blob, blen)) |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
fatal("%s: bad key, not previously allowed", __func__); |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
fatal("%s: key type mismatch: %d", __FUNCTION__, key_blobtype); |
fatal("%s: key type mismatch: %d", __func__, key_blobtype); |
if ((key = key_from_blob(blob, blen)) == NULL) |
if ((key = key_from_blob(blob, blen)) == NULL) |
fatal("%s: received bad key", __FUNCTION__); |
fatal("%s: received bad key", __func__); |
response = buffer_get_string(m, &len); |
response = buffer_get_string(m, &len); |
if (len != 16) |
if (len != 16) |
fatal("%s: received bad response to challenge", __FUNCTION__); |
fatal("%s: received bad response to challenge", __func__); |
success = auth_rsa_verify_response(key, ssh1_challenge, response); |
success = auth_rsa_verify_response(key, ssh1_challenge, response); |
|
|
key_free(key); |
key_free(key); |
|
|
extern struct monitor *pmonitor; |
extern struct monitor *pmonitor; |
int res, status; |
int res, status; |
|
|
debug3("%s: tearing down sessions", __FUNCTION__); |
debug3("%s: tearing down sessions", __func__); |
|
|
/* The child is terminating */ |
/* The child is terminating */ |
session_destroy_all(&mm_session_close); |
session_destroy_all(&mm_session_close); |
|
|
set_newkeys(MODE_IN); |
set_newkeys(MODE_IN); |
set_newkeys(MODE_OUT); |
set_newkeys(MODE_OUT); |
} else { |
} else { |
u_char key[SSH_SESSION_KEY_LENGTH]; |
|
|
|
memset(key, 'a', sizeof(key)); |
|
packet_set_protocol_flags(child_state.ssh1protoflags); |
packet_set_protocol_flags(child_state.ssh1protoflags); |
packet_set_encryption_key(key, SSH_SESSION_KEY_LENGTH, |
packet_set_encryption_key(child_state.ssh1key, |
child_state.ssh1cipher); |
child_state.ssh1keylen, child_state.ssh1cipher); |
|
xfree(child_state.ssh1key); |
} |
} |
|
|
|
/* for rc4 and other stateful ciphers */ |
packet_set_keycontext(MODE_OUT, child_state.keyout); |
packet_set_keycontext(MODE_OUT, child_state.keyout); |
xfree(child_state.keyout); |
xfree(child_state.keyout); |
packet_set_keycontext(MODE_IN, child_state.keyin); |
packet_set_keycontext(MODE_IN, child_state.keyin); |
|
|
sizeof(outgoing_stream)); |
sizeof(outgoing_stream)); |
|
|
/* Update with new address */ |
/* Update with new address */ |
mm_init_compression(pmonitor->m_zlib); |
if (options.compression) |
|
mm_init_compression(pmonitor->m_zlib); |
|
|
/* Network I/O buffers */ |
/* Network I/O buffers */ |
/* XXX inefficient for large buffers, need: buffer_init_from_string */ |
/* XXX inefficient for large buffers, need: buffer_init_from_string */ |
|
|
kex = xmalloc(sizeof(*kex)); |
kex = xmalloc(sizeof(*kex)); |
memset(kex, 0, sizeof(*kex)); |
memset(kex, 0, sizeof(*kex)); |
kex->session_id = buffer_get_string(m, &kex->session_id_len); |
kex->session_id = buffer_get_string(m, &kex->session_id_len); |
|
if ((session_id2 == NULL) || |
|
(kex->session_id_len != session_id2_len) || |
|
(memcmp(kex->session_id, session_id2, session_id2_len) != 0)) |
|
fatal("mm_get_get: internal error: bad session id"); |
kex->we_need = buffer_get_int(m); |
kex->we_need = buffer_get_int(m); |
kex->server = 1; |
kex->server = 1; |
kex->hostkey_type = buffer_get_int(m); |
kex->hostkey_type = buffer_get_int(m); |
|
|
u_char *blob, *p; |
u_char *blob, *p; |
u_int bloblen, plen; |
u_int bloblen, plen; |
|
|
debug3("%s: Waiting for new keys", __FUNCTION__); |
debug3("%s: Waiting for new keys", __func__); |
|
|
buffer_init(&m); |
buffer_init(&m); |
mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); |
mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); |
if (!compat20) { |
if (!compat20) { |
child_state.ssh1protoflags = buffer_get_int(&m); |
child_state.ssh1protoflags = buffer_get_int(&m); |
child_state.ssh1cipher = buffer_get_int(&m); |
child_state.ssh1cipher = buffer_get_int(&m); |
|
child_state.ssh1key = buffer_get_string(&m, |
|
&child_state.ssh1keylen); |
child_state.ivout = buffer_get_string(&m, |
child_state.ivout = buffer_get_string(&m, |
&child_state.ivoutlen); |
&child_state.ivoutlen); |
child_state.ivin = buffer_get_string(&m, &child_state.ivinlen); |
child_state.ivin = buffer_get_string(&m, &child_state.ivinlen); |
|
|
current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); |
current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); |
xfree(blob); |
xfree(blob); |
|
|
debug3("%s: Waiting for second key", __FUNCTION__); |
debug3("%s: Waiting for second key", __func__); |
blob = buffer_get_string(&m, &bloblen); |
blob = buffer_get_string(&m, &bloblen); |
current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); |
current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); |
xfree(blob); |
xfree(blob); |
|
|
child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen); |
child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen); |
child_state.keyin = buffer_get_string(&m, &child_state.keyinlen); |
child_state.keyin = buffer_get_string(&m, &child_state.keyinlen); |
|
|
debug3("%s: Getting compression state", __FUNCTION__); |
debug3("%s: Getting compression state", __func__); |
/* Get compression state */ |
/* Get compression state */ |
p = buffer_get_string(&m, &plen); |
p = buffer_get_string(&m, &plen); |
if (plen != sizeof(child_state.outgoing)) |
if (plen != sizeof(child_state.outgoing)) |
fatal("%s: bad request size", __FUNCTION__); |
fatal("%s: bad request size", __func__); |
memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing)); |
memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing)); |
xfree(p); |
xfree(p); |
|
|
p = buffer_get_string(&m, &plen); |
p = buffer_get_string(&m, &plen); |
if (plen != sizeof(child_state.incoming)) |
if (plen != sizeof(child_state.incoming)) |
fatal("%s: bad request size", __FUNCTION__); |
fatal("%s: bad request size", __func__); |
memcpy(&child_state.incoming, p, sizeof(child_state.incoming)); |
memcpy(&child_state.incoming, p, sizeof(child_state.incoming)); |
xfree(p); |
xfree(p); |
|
|
/* Network I/O buffers */ |
/* Network I/O buffers */ |
debug3("%s: Getting Network I/O buffers", __FUNCTION__); |
debug3("%s: Getting Network I/O buffers", __func__); |
child_state.input = buffer_get_string(&m, &child_state.ilen); |
child_state.input = buffer_get_string(&m, &child_state.ilen); |
child_state.output = buffer_get_string(&m, &child_state.olen); |
child_state.output = buffer_get_string(&m, &child_state.olen); |
|
|
|
|
monitor_socketpair(int *pair) |
monitor_socketpair(int *pair) |
{ |
{ |
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) |
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) |
fatal("%s: socketpair", __FUNCTION__); |
fatal("%s: socketpair", __func__); |
FD_CLOSEONEXEC(pair[0]); |
FD_CLOSEONEXEC(pair[0]); |
FD_CLOSEONEXEC(pair[1]); |
FD_CLOSEONEXEC(pair[1]); |
} |
} |
|
|
mon->m_sendfd = pair[1]; |
mon->m_sendfd = pair[1]; |
|
|
/* Used to share zlib space across processes */ |
/* Used to share zlib space across processes */ |
mon->m_zback = mm_create(NULL, MM_MEMSIZE); |
if (options.compression) { |
mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); |
mon->m_zback = mm_create(NULL, MM_MEMSIZE); |
|
mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); |
|
|
/* Compression needs to share state across borders */ |
/* Compression needs to share state across borders */ |
mm_init_compression(mon->m_zlib); |
mm_init_compression(mon->m_zlib); |
|
} |
|
|
return mon; |
return mon; |
} |
} |