version 1.9.2.5, 2003/04/03 22:35:17 |
version 1.10, 2002/05/12 23:53:45 |
|
|
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; |
|
|
int mm_answer_sesskey(int, Buffer *); |
int mm_answer_sesskey(int, Buffer *); |
int mm_answer_sessid(int, Buffer *); |
int mm_answer_sessid(int, Buffer *); |
|
|
#ifdef KRB4 |
|
int mm_answer_krb4(int, Buffer *); |
|
#endif |
|
#ifdef KRB5 |
|
int mm_answer_krb5(int, Buffer *); |
|
#endif |
|
|
|
static Authctxt *authctxt; |
static Authctxt *authctxt; |
static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ |
static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ |
|
|
|
|
static u_char *key_blob = NULL; |
static u_char *key_blob = NULL; |
static u_int key_bloblen = 0; |
static u_int key_bloblen = 0; |
static int key_blobtype = MM_NOKEY; |
static int key_blobtype = MM_NOKEY; |
static char *hostbased_cuser = NULL; |
static u_char *hostbased_cuser = NULL; |
static 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; |
|
|
{MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, |
{MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, |
{MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, |
{MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, |
#endif |
#endif |
#ifdef KRB4 |
|
{MONITOR_REQ_KRB4, MON_ONCE|MON_AUTH, mm_answer_krb4}, |
|
#endif |
|
#ifdef KRB5 |
|
{MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5}, |
|
#endif |
|
{0, 0, NULL} |
{0, 0, NULL} |
}; |
}; |
|
|
|
|
} |
} |
|
|
Authctxt * |
Authctxt * |
monitor_child_preauth(struct monitor *pmonitor) |
monitor_child_preauth(struct monitor *monitor) |
{ |
{ |
struct mon_table *ent; |
struct mon_table *ent; |
int authenticated = 0; |
int authenticated = 0; |
|
|
|
|
/* The first few requests do not require asynchronous access */ |
/* The first few requests do not require asynchronous access */ |
while (!authenticated) { |
while (!authenticated) { |
authenticated = monitor_read(pmonitor, mon_dispatch, &ent); |
authenticated = monitor_read(monitor, mon_dispatch, &ent); |
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", |
__func__, ent->type); |
__FUNCTION__, 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", __func__); |
fatal("%s: authenticated invalid user", __FUNCTION__); |
|
|
debug("%s: %s has been authenticated by privileged process", |
debug("%s: %s has been authenticated by privileged process", |
__func__, authctxt->user); |
__FUNCTION__, authctxt->user); |
|
|
mm_get_keystate(pmonitor); |
mm_get_keystate(monitor); |
|
|
return (authctxt); |
return (authctxt); |
} |
} |
|
|
void |
void |
monitor_child_postauth(struct monitor *pmonitor) |
monitor_child_postauth(struct monitor *monitor) |
{ |
{ |
if (compat20) { |
if (compat20) { |
mon_dispatch = mon_dispatch_postauth20; |
mon_dispatch = mon_dispatch_postauth20; |
|
|
} |
} |
|
|
for (;;) |
for (;;) |
monitor_read(pmonitor, mon_dispatch, NULL); |
monitor_read(monitor, mon_dispatch, NULL); |
} |
} |
|
|
void |
void |
monitor_sync(struct monitor *pmonitor) |
monitor_sync(struct monitor *monitor) |
{ |
{ |
if (options.compression) { |
/* The member allocation is not visible, so sync it */ |
/* The member allocation is not visible, so sync it */ |
mm_share_sync(&monitor->m_zlib, &monitor->m_zback); |
mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); |
|
} |
|
} |
} |
|
|
int |
int |
monitor_read(struct monitor *pmonitor, struct mon_table *ent, |
monitor_read(struct monitor *monitor, struct mon_table *ent, |
struct mon_table **pent) |
struct mon_table **pent) |
{ |
{ |
Buffer m; |
Buffer m; |
|
|
|
|
buffer_init(&m); |
buffer_init(&m); |
|
|
mm_request_receive(pmonitor->m_sendfd, &m); |
mm_request_receive(monitor->m_sendfd, &m); |
type = buffer_get_char(&m); |
type = buffer_get_char(&m); |
|
|
debug3("%s: checking request %d", __func__, type); |
debug3("%s: checking request %d", __FUNCTION__, 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", __func__, |
fatal("%s: unpermitted request %d", __FUNCTION__, |
type); |
type); |
ret = (*ent->f)(pmonitor->m_sendfd, &m); |
ret = (*ent->f)(monitor->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", __func__, |
debug2("%s: %d used once, disabling now", __FUNCTION__, |
type); |
type); |
ent->flags &= ~MON_PERMIT; |
ent->flags &= ~MON_PERMIT; |
} |
} |
|
|
return ret; |
return ret; |
} |
} |
|
|
fatal("%s: unsupported request: %d", __func__, type); |
fatal("%s: unsupported request: %d", __FUNCTION__, 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", |
__func__, min, want, max); |
__FUNCTION__, 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", |
__func__, min, want, max); |
__FUNCTION__, min, want, max); |
|
|
buffer_clear(m); |
buffer_clear(m); |
|
|
|
|
u_int siglen, datlen; |
u_int siglen, datlen; |
int keyid; |
int keyid; |
|
|
debug3("%s", __func__); |
debug3("%s", __FUNCTION__); |
|
|
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: %u", __func__, datlen); |
fatal("%s: data length incorrect: %d", __FUNCTION__, 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", __func__, keyid); |
fatal("%s: no hostkey from index %d", __FUNCTION__, keyid); |
if (key_sign(key, &signature, &siglen, p, datlen) < 0) |
if (key_sign(key, &signature, &siglen, p, datlen) < 0) |
fatal("%s: key_sign failed", __func__); |
fatal("%s: key_sign failed", __FUNCTION__); |
|
|
debug3("%s: signature %p(%u)", __func__, signature, siglen); |
debug3("%s: signature %p(%d)", __FUNCTION__, 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", __func__); |
debug3("%s", __FUNCTION__); |
|
|
if (authctxt->attempt++ != 0) |
if (authctxt->attempt++ != 0) |
fatal("%s: multiple attempts for getpwnam", __func__); |
fatal("%s: multiple attempts for getpwnam", __FUNCTION__); |
|
|
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", __func__, allowed); |
debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, 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 */ |
|
|
mm_request_send(socket, MONITOR_ANS_AUTH2_READ_BANNER, m); |
mm_request_send(socket, MONITOR_ANS_AUTH2_READ_BANNER, m); |
|
|
if (banner != NULL) |
if (banner != NULL) |
xfree(banner); |
free(banner); |
|
|
return (0); |
return (0); |
} |
} |
|
|
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", |
__func__, authctxt->service, authctxt->style); |
__FUNCTION__, authctxt->service, authctxt->style); |
|
|
if (strlen(authctxt->style) == 0) { |
if (strlen(authctxt->style) == 0) { |
xfree(authctxt->style); |
xfree(authctxt->style); |
|
|
{ |
{ |
static int call_count; |
static int call_count; |
char *passwd; |
char *passwd; |
int authenticated; |
int authenticated, plen; |
u_int plen; |
|
|
|
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 = options.password_authentication && |
authenticated = authctxt->valid && auth_password(authctxt, passwd); |
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", __func__, authenticated); |
debug3("%s: sending result %d", __FUNCTION__, authenticated); |
mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); |
mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); |
|
|
call_count++; |
call_count++; |
|
|
u_int numprompts; |
u_int numprompts; |
u_int *echo_on; |
u_int *echo_on; |
char **prompts; |
char **prompts; |
u_int success; |
int res; |
|
|
success = bsdauth_query(authctxt, &name, &infotxt, &numprompts, |
res = bsdauth_query(authctxt, &name, &infotxt, &numprompts, |
&prompts, &echo_on) < 0 ? 0 : 1; |
&prompts, &echo_on); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, success); |
buffer_put_int(m, res); |
if (success) |
if (res != -1) |
buffer_put_cstring(m, prompts[0]); |
buffer_put_cstring(m, prompts[0]); |
|
|
debug3("%s: sending challenge success: %u", __func__, success); |
debug3("%s: sending challenge res: %d", __FUNCTION__, res); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); |
|
|
if (success) { |
if (res != -1) { |
xfree(name); |
xfree(name); |
xfree(infotxt); |
xfree(infotxt); |
xfree(prompts); |
xfree(prompts); |
|
|
int authok; |
int authok; |
|
|
if (authctxt->as == 0) |
if (authctxt->as == 0) |
fatal("%s: no bsd auth session", __func__); |
fatal("%s: no bsd auth session", __FUNCTION__); |
|
|
response = buffer_get_string(m, NULL); |
response = buffer_get_string(m, NULL); |
authok = options.challenge_response_authentication && |
authok = 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>", __FUNCTION__, 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", __func__, authok); |
debug3("%s: sending authenticated: %d", __FUNCTION__, authok); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); |
mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); |
|
|
auth_method = "bsdauth"; |
auth_method = "bsdauth"; |
|
|
{ |
{ |
struct skey skey; |
struct skey skey; |
char challenge[1024]; |
char challenge[1024]; |
u_int success; |
int res; |
|
|
success = skeychallenge(&skey, authctxt->user, challenge) < 0 ? 0 : 1; |
res = skeychallenge(&skey, authctxt->user, challenge); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, success); |
buffer_put_int(m, res); |
if (success) |
if (res != -1) |
buffer_put_cstring(m, challenge); |
buffer_put_cstring(m, challenge); |
|
|
debug3("%s: sending challenge success: %u", __func__, success); |
debug3("%s: sending challenge res: %d", __FUNCTION__, 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 = (options.challenge_response_authentication && |
authok = (authctxt->valid && |
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", __func__, authok); |
debug3("%s: sending authenticated: %d", __FUNCTION__, 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", __func__); |
debug3("%s: Appending debug messages for child", __FUNCTION__); |
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); |
|
|
mm_answer_keyallowed(int socket, Buffer *m) |
mm_answer_keyallowed(int socket, Buffer *m) |
{ |
{ |
Key *key; |
Key *key; |
char *cuser, *chost; |
u_char *cuser, *chost, *blob; |
u_char *blob; |
|
u_int bloblen; |
u_int bloblen; |
enum mm_keytype type = 0; |
enum mm_keytype type = 0; |
int allowed = 0; |
int allowed = 0; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
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", __func__); |
fatal("%s: key type and protocol mismatch", __FUNCTION__); |
|
|
debug3("%s: key_from_blob: %p", __func__, key); |
debug3("%s: key_from_blob: %p", __FUNCTION__, key); |
|
|
if (key != NULL && authctxt->pw != NULL) { |
if (key != NULL && authctxt->pw != NULL) { |
switch(type) { |
switch(type) { |
case MM_USERKEY: |
case MM_USERKEY: |
allowed = options.pubkey_authentication && |
allowed = user_key_allowed(authctxt->pw, key); |
user_key_allowed(authctxt->pw, key); |
|
break; |
break; |
case MM_HOSTKEY: |
case MM_HOSTKEY: |
allowed = options.hostbased_authentication && |
allowed = hostbased_key_allowed(authctxt->pw, |
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 = options.rhosts_rsa_authentication && |
allowed = auth_rhosts_rsa_key_allowed(authctxt->pw, |
auth_rhosts_rsa_key_allowed(authctxt->pw, |
|
cuser, chost, key); |
cuser, chost, key); |
break; |
break; |
default: |
default: |
fatal("%s: unknown key type %d", __func__, type); |
fatal("%s: unknown key type %d", __FUNCTION__, type); |
break; |
break; |
} |
} |
} |
|
if (key != NULL) |
|
key_free(key); |
key_free(key); |
|
} |
|
|
/* clear temporarily storage (used by verify) */ |
/* clear temporarily storage (used by verify) */ |
monitor_reset_key_state(); |
monitor_reset_key_state(); |
|
|
} |
} |
|
|
debug3("%s: key %p is %s", |
debug3("%s: key %p is %s", |
__func__, key, allowed ? "allowed" : "disallowed"); |
__FUNCTION__, key, allowed ? "allowed" : "disallowed"); |
|
|
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, allowed); |
buffer_put_int(m, allowed); |
buffer_put_int(m, forced_command != NULL); |
|
|
|
mm_append_debug(m); |
mm_append_debug(m); |
|
|
|
|
monitor_valid_userblob(u_char *data, u_int datalen) |
monitor_valid_userblob(u_char *data, u_int datalen) |
{ |
{ |
Buffer b; |
Buffer b; |
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 { |
p = buffer_get_string(&b, &len); |
xfree(buffer_get_string(&b, &len)); |
if ((session_id2 == NULL) || |
if (len != session_id2_len) |
(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++; |
|
|
} |
} |
|
|
static int |
static int |
monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, |
monitor_valid_hostbasedblob(u_char *data, u_int datalen, u_char *cuser, |
char *chost) |
u_char *chost) |
{ |
{ |
Buffer b; |
Buffer b; |
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); |
|
|
p = buffer_get_string(&b, &len); |
xfree(buffer_get_string(&b, &len)); |
if ((session_id2 == NULL) || |
if (len != session_id2_len) |
(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", __func__); |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
|
|
key = key_from_blob(blob, bloblen); |
key = key_from_blob(blob, bloblen); |
if (key == NULL) |
if (key == NULL) |
fatal("%s: bad public key blob", __func__); |
fatal("%s: bad public key blob", __FUNCTION__); |
|
|
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", __func__); |
fatal("%s: bad signature data blob", __FUNCTION__); |
|
|
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", |
__func__, key, verified ? "verified" : "unverified"); |
__FUNCTION__, key, verified ? "verified" : "unverified"); |
|
|
key_free(key); |
key_free(key); |
xfree(blob); |
xfree(blob); |
xfree(signature); |
xfree(signature); |
xfree(data); |
xfree(data); |
|
|
auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased"; |
|
|
|
monitor_reset_key_state(); |
monitor_reset_key_state(); |
|
|
buffer_clear(m); |
buffer_clear(m); |
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"; |
|
|
return (verified); |
return (verified); |
} |
} |
|
|
|
|
* the address be 0.0.0.0. |
* the address be 0.0.0.0. |
*/ |
*/ |
memset(&from, 0, sizeof(from)); |
memset(&from, 0, sizeof(from)); |
fromlen = sizeof(from); |
|
if (packet_connection_is_on_socket()) { |
if (packet_connection_is_on_socket()) { |
|
fromlen = sizeof(from); |
if (getpeername(packet_get_connection_in(), |
if (getpeername(packet_get_connection_in(), |
(struct sockaddr *) & from, &fromlen) < 0) { |
(struct sockaddr *) & from, &fromlen) < 0) { |
debug("getpeername: %.100s", strerror(errno)); |
debug("getpeername: %.100s", strerror(errno)); |
|
|
/* Record that there was a login on that tty from the remote host. */ |
/* Record that there was a login on that tty from the remote host. */ |
record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, |
record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, |
get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), |
get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), |
(struct sockaddr *)&from, fromlen); |
(struct sockaddr *)&from); |
} |
} |
|
|
static void |
static void |
mm_session_close(Session *s) |
mm_session_close(Session *s) |
{ |
{ |
debug3("%s: session %d pid %d", __func__, s->self, s->pid); |
debug3("%s: session %d pid %d", __FUNCTION__, s->self, s->pid); |
if (s->ttyfd != -1) { |
if (s->ttyfd != -1) { |
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); |
debug3("%s: tty %s ptyfd %d", __FUNCTION__, 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); |
} |
} |
|
|
int |
int |
mm_answer_pty(int socket, Buffer *m) |
mm_answer_pty(int socket, Buffer *m) |
{ |
{ |
extern struct monitor *pmonitor; |
extern struct monitor *monitor; |
Session *s; |
Session *s; |
int res, fd0; |
int res, fd0; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
buffer_clear(m); |
buffer_clear(m); |
s = session_new(); |
s = session_new(); |
|
|
goto error; |
goto error; |
s->authctxt = authctxt; |
s->authctxt = authctxt; |
s->pw = authctxt->pw; |
s->pw = authctxt->pw; |
s->pid = pmonitor->m_pid; |
s->pid = monitor->m_pid; |
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); |
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); |
if (res == 0) |
if (res == 0) |
goto error; |
goto error; |
|
|
|
|
/* 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", __func__); |
fatal("%s: dup2", __FUNCTION__); |
|
|
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", __func__, strerror(errno)); |
fatal("%s: open(/dev/null): %s", __FUNCTION__, strerror(errno)); |
if (fd0 != 0) |
if (fd0 != 0) |
error("%s: fd0 %d != 0", __func__, fd0); |
error("%s: fd0 %d != 0", __FUNCTION__, 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", __func__, s->tty, s->ttyfd); |
debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ttyfd); |
|
|
return (0); |
return (0); |
|
|
|
|
Session *s; |
Session *s; |
char *tty; |
char *tty; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
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", __func__); |
fatal("%s: BN_new", __FUNCTION__); |
|
|
buffer_get_bignum2(m, p); |
buffer_get_bignum2(m, p); |
|
|
|
|
{ |
{ |
int i; |
int i; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
if (buffer_len(m) != 16) |
if (buffer_len(m) != 16) |
fatal("%s: bad ssh1 session id", __func__); |
fatal("%s: bad ssh1 session id", __FUNCTION__); |
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", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
if (options.rsa_authentication && authctxt->valid) { |
if (authctxt->valid) { |
if ((client_n = BN_new()) == NULL) |
if ((client_n = BN_new()) == NULL) |
fatal("%s: BN_new", __func__); |
fatal("%s: BN_new", __FUNCTION__); |
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); |
} |
} |
buffer_clear(m); |
buffer_clear(m); |
buffer_put_int(m, allowed); |
buffer_put_int(m, allowed); |
buffer_put_int(m, forced_command != NULL); |
|
|
|
/* clear temporarily storage (used by generate challenge) */ |
/* clear temporarily storage (used by generate challenge) */ |
monitor_reset_key_state(); |
monitor_reset_key_state(); |
|
|
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", __func__); |
fatal("%s: key_to_blob failed", __FUNCTION__); |
buffer_put_string(m, blob, blen); |
buffer_put_string(m, blob, blen); |
|
|
/* Save temporarily for comparison in verify */ |
/* Save temporarily for comparison in verify */ |
key_blob = blob; |
key_blob = blob; |
key_bloblen = blen; |
key_bloblen = blen; |
key_blobtype = MM_RSAUSERKEY; |
key_blobtype = MM_RSAUSERKEY; |
} |
|
if (key != NULL) |
|
key_free(key); |
key_free(key); |
|
} |
|
|
mm_append_debug(m); |
mm_append_debug(m); |
|
|
|
|
u_char *blob; |
u_char *blob; |
u_int blen; |
u_int blen; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
if (!authctxt->valid) |
if (!authctxt->valid) |
fatal("%s: authctxt not valid", __func__); |
fatal("%s: authctxt not valid", __FUNCTION__); |
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", __func__); |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
fatal("%s: key type mismatch", __func__); |
fatal("%s: key type mismatch", __FUNCTION__); |
if ((key = key_from_blob(blob, blen)) == NULL) |
if ((key = key_from_blob(blob, blen)) == NULL) |
fatal("%s: received bad key", __func__); |
fatal("%s: received bad key", __FUNCTION__); |
|
|
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", __func__); |
debug3("%s sending reply", __FUNCTION__); |
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); |
|
|
xfree(blob); |
|
key_free(key); |
|
return (0); |
return (0); |
} |
} |
|
|
|
|
u_int blen, len; |
u_int blen, len; |
int success; |
int success; |
|
|
debug3("%s entering", __func__); |
debug3("%s entering", __FUNCTION__); |
|
|
if (!authctxt->valid) |
if (!authctxt->valid) |
fatal("%s: authctxt not valid", __func__); |
fatal("%s: authctxt not valid", __FUNCTION__); |
if (ssh1_challenge == NULL) |
if (ssh1_challenge == NULL) |
fatal("%s: no ssh1_challenge", __func__); |
fatal("%s: no ssh1_challenge", __FUNCTION__); |
|
|
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", __func__); |
fatal("%s: bad key, not previously allowed", __FUNCTION__); |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) |
fatal("%s: key type mismatch: %d", __func__, key_blobtype); |
fatal("%s: key type mismatch: %d", __FUNCTION__, key_blobtype); |
if ((key = key_from_blob(blob, blen)) == NULL) |
if ((key = key_from_blob(blob, blen)) == NULL) |
fatal("%s: received bad key", __func__); |
fatal("%s: received bad key", __FUNCTION__); |
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", __func__); |
fatal("%s: received bad response to challenge", __FUNCTION__); |
success = auth_rsa_verify_response(key, ssh1_challenge, response); |
success = auth_rsa_verify_response(key, ssh1_challenge, response); |
|
|
xfree(blob); |
|
key_free(key); |
key_free(key); |
xfree(response); |
xfree(response); |
|
|
|
|
return (success); |
return (success); |
} |
} |
|
|
#ifdef KRB4 |
|
int |
int |
mm_answer_krb4(int socket, Buffer *m) |
|
{ |
|
KTEXT_ST auth, reply; |
|
char *client, *p; |
|
int success; |
|
u_int alen; |
|
|
|
reply.length = auth.length = 0; |
|
|
|
p = buffer_get_string(m, &alen); |
|
if (alen >= MAX_KTXT_LEN) |
|
fatal("%s: auth too large", __func__); |
|
memcpy(auth.dat, p, alen); |
|
auth.length = alen; |
|
memset(p, 0, alen); |
|
xfree(p); |
|
|
|
success = options.kerberos_authentication && |
|
authctxt->valid && |
|
auth_krb4(authctxt, &auth, &client, &reply); |
|
|
|
memset(auth.dat, 0, alen); |
|
buffer_clear(m); |
|
buffer_put_int(m, success); |
|
|
|
if (success) { |
|
buffer_put_cstring(m, client); |
|
buffer_put_string(m, reply.dat, reply.length); |
|
if (client) |
|
xfree(client); |
|
if (reply.length) |
|
memset(reply.dat, 0, reply.length); |
|
} |
|
|
|
debug3("%s: sending result %d", __func__, success); |
|
mm_request_send(socket, MONITOR_ANS_KRB4, m); |
|
|
|
auth_method = "kerberos"; |
|
|
|
/* Causes monitor loop to terminate if authenticated */ |
|
return (success); |
|
} |
|
#endif |
|
|
|
#ifdef KRB5 |
|
int |
|
mm_answer_krb5(int socket, Buffer *m) |
|
{ |
|
krb5_data tkt, reply; |
|
char *client_user; |
|
u_int len; |
|
int success; |
|
|
|
/* use temporary var to avoid size issues on 64bit arch */ |
|
tkt.data = buffer_get_string(m, &len); |
|
tkt.length = len; |
|
|
|
success = options.kerberos_authentication && |
|
authctxt->valid && |
|
auth_krb5(authctxt, &tkt, &client_user, &reply); |
|
|
|
if (tkt.length) |
|
xfree(tkt.data); |
|
|
|
buffer_clear(m); |
|
buffer_put_int(m, success); |
|
|
|
if (success) { |
|
buffer_put_cstring(m, client_user); |
|
buffer_put_string(m, reply.data, reply.length); |
|
if (client_user) |
|
xfree(client_user); |
|
if (reply.length) |
|
xfree(reply.data); |
|
} |
|
mm_request_send(socket, MONITOR_ANS_KRB5, m); |
|
|
|
return success; |
|
} |
|
#endif |
|
|
|
int |
|
mm_answer_term(int socket, Buffer *req) |
mm_answer_term(int socket, Buffer *req) |
{ |
{ |
extern struct monitor *pmonitor; |
extern struct monitor *monitor; |
int res, status; |
int res, status; |
|
|
debug3("%s: tearing down sessions", __func__); |
debug3("%s: tearing down sessions", __FUNCTION__); |
|
|
/* The child is terminating */ |
/* The child is terminating */ |
session_destroy_all(&mm_session_close); |
session_destroy_all(&mm_session_close); |
|
|
while (waitpid(pmonitor->m_pid, &status, 0) == -1) |
while (waitpid(monitor->m_pid, &status, 0) == -1) |
if (errno != EINTR) |
if (errno != EINTR) |
exit(1); |
exit(1); |
|
|
|
|
} |
} |
|
|
void |
void |
monitor_apply_keystate(struct monitor *pmonitor) |
monitor_apply_keystate(struct monitor *monitor) |
{ |
{ |
if (compat20) { |
if (compat20) { |
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(child_state.ssh1key, |
packet_set_encryption_key(key, SSH_SESSION_KEY_LENGTH, |
child_state.ssh1keylen, child_state.ssh1cipher); |
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 */ |
if (options.compression) |
mm_init_compression(monitor->m_zlib); |
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->kex[KEX_DH_GRP1_SHA1] = kexdh_server; |
|
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
|
kex->server = 1; |
kex->server = 1; |
kex->hostkey_type = buffer_get_int(m); |
kex->hostkey_type = buffer_get_int(m); |
kex->kex_type = buffer_get_int(m); |
kex->kex_type = buffer_get_int(m); |
|
|
/* This function requries careful sanity checking */ |
/* This function requries careful sanity checking */ |
|
|
void |
void |
mm_get_keystate(struct monitor *pmonitor) |
mm_get_keystate(struct monitor *monitor) |
{ |
{ |
Buffer m; |
Buffer m; |
u_char *blob, *p; |
u_char *blob, *p; |
u_int bloblen, plen; |
u_int bloblen, plen; |
|
|
debug3("%s: Waiting for new keys", __func__); |
debug3("%s: Waiting for new keys", __FUNCTION__); |
|
|
buffer_init(&m); |
buffer_init(&m); |
mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); |
mm_request_receive_expect(monitor->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); |
goto skip; |
goto skip; |
} else { |
} else { |
/* Get the Kex for rekeying */ |
/* Get the Kex for rekeying */ |
*pmonitor->m_pkex = mm_get_kex(&m); |
*monitor->m_pkex = mm_get_kex(&m); |
} |
} |
|
|
blob = buffer_get_string(&m, &bloblen); |
blob = buffer_get_string(&m, &bloblen); |
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", __func__); |
debug3("%s: Waiting for second key", __FUNCTION__); |
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", __func__); |
debug3("%s: Getting compression state", __FUNCTION__); |
/* 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", __func__); |
fatal("%s: bad request size", __FUNCTION__); |
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", __func__); |
fatal("%s: bad request size", __FUNCTION__); |
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", __func__); |
debug3("%s: Getting Network I/O buffers", __FUNCTION__); |
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); |
|
|
|
|
void * |
void * |
mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) |
mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) |
{ |
{ |
size_t len = (size_t) size * ncount; |
|
void *address; |
void *address; |
|
|
if (len == 0 || ncount > SIZE_T_MAX / size) |
address = mm_malloc(mm, size * ncount); |
fatal("%s: mm_zalloc(%u, %u)", __func__, ncount, size); |
|
|
|
address = mm_malloc(mm, len); |
|
|
|
return (address); |
return (address); |
} |
} |
|
|
|
|
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", __func__); |
fatal("%s: socketpair", __FUNCTION__); |
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 */ |
if (options.compression) { |
mon->m_zback = mm_create(NULL, MM_MEMSIZE); |
mon->m_zback = mm_create(NULL, MM_MEMSIZE); |
mon->m_zlib = mm_create(mon->m_zback, 20 * 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; |
} |
} |