version 1.29.2.2, 2003/04/03 23:27:12 |
version 1.29.2.3, 2003/09/16 21:20:26 |
|
|
#include "ssh2.h" |
#include "ssh2.h" |
#include "mpaux.h" |
#include "mpaux.h" |
|
|
|
#ifdef GSSAPI |
|
#include "ssh-gss.h" |
|
static Gssctxt *gsscontext = NULL; |
|
#endif |
|
|
/* Imports */ |
/* Imports */ |
extern ServerOptions options; |
extern ServerOptions options; |
extern u_int utmp_len; |
extern u_int utmp_len; |
|
|
u_int olen; |
u_int olen; |
} child_state; |
} child_state; |
|
|
/* Functions on the montior that answer unprivileged requests */ |
/* Functions on the monitor that answer unprivileged requests */ |
|
|
int mm_answer_moduli(int, Buffer *); |
int mm_answer_moduli(int, Buffer *); |
int mm_answer_sign(int, Buffer *); |
int mm_answer_sign(int, Buffer *); |
|
|
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 |
#ifdef GSSAPI |
int mm_answer_krb4(int, Buffer *); |
int mm_answer_gss_setup_ctx(int, Buffer *); |
|
int mm_answer_gss_accept_ctx(int, Buffer *); |
|
int mm_answer_gss_userok(int, Buffer *); |
#endif |
#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 char *hostbased_cuser = NULL; |
static char *hostbased_cuser = NULL; |
static char *hostbased_chost = NULL; |
static char *hostbased_chost = NULL; |
static char *auth_method = "unknown"; |
static char *auth_method = "unknown"; |
static int session_id2_len = 0; |
static u_int session_id2_len = 0; |
static u_char *session_id2 = NULL; |
static u_char *session_id2 = NULL; |
|
static pid_t monitor_child_pid; |
|
|
struct mon_table { |
struct mon_table { |
enum monitor_reqtype type; |
enum monitor_reqtype type; |
|
|
#endif |
#endif |
{MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, |
{MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, |
{MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, |
{MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, |
|
#ifdef GSSAPI |
|
{MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, |
|
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, |
|
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, |
|
#endif |
{0, 0, NULL} |
{0, 0, NULL} |
}; |
}; |
|
|
|
|
{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} |
}; |
}; |
|
|
|
|
return (authctxt); |
return (authctxt); |
} |
} |
|
|
|
static void |
|
monitor_set_child_handler(pid_t pid) |
|
{ |
|
monitor_child_pid = pid; |
|
} |
|
|
|
static void |
|
monitor_child_handler(int signal) |
|
{ |
|
kill(monitor_child_pid, signal); |
|
} |
|
|
void |
void |
monitor_child_postauth(struct monitor *pmonitor) |
monitor_child_postauth(struct monitor *pmonitor) |
{ |
{ |
|
monitor_set_child_handler(pmonitor->m_pid); |
|
signal(SIGHUP, &monitor_child_handler); |
|
signal(SIGTERM, &monitor_child_handler); |
|
|
if (compat20) { |
if (compat20) { |
mon_dispatch = mon_dispatch_postauth20; |
mon_dispatch = mon_dispatch_postauth20; |
|
|
|
|
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
|
|
} else { |
} else { |
mon_dispatch = mon_dispatch_postauth15; |
mon_dispatch = mon_dispatch_postauth15; |
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
|
|
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 = options.password_authentication && |
authctxt->valid && auth_password(authctxt, passwd); |
auth_password(authctxt, passwd); |
memset(passwd, 0, strlen(passwd)); |
memset(passwd, 0, strlen(passwd)); |
xfree(passwd); |
xfree(passwd); |
|
|
|
|
fail++; |
fail++; |
p = buffer_get_string(&b, NULL); |
p = buffer_get_string(&b, NULL); |
if (strcmp(authctxt->user, p) != 0) { |
if (strcmp(authctxt->user, p) != 0) { |
log("wrong user name passed to monitor: expected %s != %.100s", |
logit("wrong user name passed to monitor: expected %s != %.100s", |
authctxt->user, p); |
authctxt->user, p); |
fail++; |
fail++; |
} |
} |
|
|
fail++; |
fail++; |
p = buffer_get_string(&b, NULL); |
p = buffer_get_string(&b, NULL); |
if (strcmp(authctxt->user, p) != 0) { |
if (strcmp(authctxt->user, p) != 0) { |
log("wrong user name passed to monitor: expected %s != %.100s", |
logit("wrong user name passed to monitor: expected %s != %.100s", |
authctxt->user, p); |
authctxt->user, p); |
fail++; |
fail++; |
} |
} |
|
|
} |
} |
/* 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.use_dns), |
(struct sockaddr *)&from, fromlen); |
(struct sockaddr *)&from, fromlen); |
} |
} |
|
|
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 %ld", __func__, s->self, (long)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", __func__, s->tty, s->ptyfd); |
fatal_remove_cleanup(session_pty_cleanup2, (void *)s); |
fatal_remove_cleanup(session_pty_cleanup2, (void *)s); |
|
|
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 *pmonitor; |
|
|
Buffer m; |
Buffer m; |
u_char *blob, *p; |
u_char *blob, *p; |
u_int bloblen, plen; |
u_int bloblen, plen; |
|
u_int32_t seqnr, packets; |
|
u_int64_t blocks; |
|
|
debug3("%s: Waiting for new keys", __func__); |
debug3("%s: Waiting for new keys", __func__); |
|
|
|
|
xfree(blob); |
xfree(blob); |
|
|
/* Now get sequence numbers for the packets */ |
/* Now get sequence numbers for the packets */ |
packet_set_seqnr(MODE_OUT, buffer_get_int(&m)); |
seqnr = buffer_get_int(&m); |
packet_set_seqnr(MODE_IN, buffer_get_int(&m)); |
blocks = buffer_get_int64(&m); |
|
packets = buffer_get_int(&m); |
|
packet_set_state(MODE_OUT, seqnr, blocks, packets); |
|
seqnr = buffer_get_int(&m); |
|
blocks = buffer_get_int64(&m); |
|
packets = buffer_get_int(&m); |
|
packet_set_state(MODE_IN, seqnr, blocks, packets); |
|
|
skip: |
skip: |
/* Get the key context */ |
/* Get the key context */ |
|
|
mon->m_recvfd = pair[0]; |
mon->m_recvfd = pair[0]; |
mon->m_sendfd = pair[1]; |
mon->m_sendfd = pair[1]; |
} |
} |
|
|
|
#ifdef GSSAPI |
|
int |
|
mm_answer_gss_setup_ctx(int socket, Buffer *m) |
|
{ |
|
gss_OID_desc oid; |
|
OM_uint32 major; |
|
u_int len; |
|
|
|
oid.elements = buffer_get_string(m, &len); |
|
oid.length = len; |
|
|
|
major = ssh_gssapi_server_ctx(&gsscontext, &oid); |
|
|
|
xfree(oid.elements); |
|
|
|
buffer_clear(m); |
|
buffer_put_int(m, major); |
|
|
|
mm_request_send(socket,MONITOR_ANS_GSSSETUP, m); |
|
|
|
/* Now we have a context, enable the step */ |
|
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1); |
|
|
|
return (0); |
|
} |
|
|
|
int |
|
mm_answer_gss_accept_ctx(int socket, Buffer *m) |
|
{ |
|
gss_buffer_desc in; |
|
gss_buffer_desc out = GSS_C_EMPTY_BUFFER; |
|
OM_uint32 major,minor; |
|
OM_uint32 flags = 0; /* GSI needs this */ |
|
u_int len; |
|
|
|
in.value = buffer_get_string(m, &len); |
|
in.length = len; |
|
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); |
|
xfree(in.value); |
|
|
|
buffer_clear(m); |
|
buffer_put_int(m, major); |
|
buffer_put_string(m, out.value, out.length); |
|
buffer_put_int(m, flags); |
|
mm_request_send(socket, MONITOR_ANS_GSSSTEP, m); |
|
|
|
gss_release_buffer(&minor, &out); |
|
|
|
/* Complete - now we can do signing */ |
|
if (major==GSS_S_COMPLETE) { |
|
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); |
|
monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); |
|
} |
|
return (0); |
|
} |
|
|
|
int |
|
mm_answer_gss_userok(int socket, Buffer *m) |
|
{ |
|
int authenticated; |
|
|
|
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); |
|
|
|
buffer_clear(m); |
|
buffer_put_int(m, authenticated); |
|
|
|
debug3("%s: sending result %d", __func__, authenticated); |
|
mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m); |
|
|
|
auth_method="gssapi"; |
|
|
|
/* Monitor loop will terminate if authenticated */ |
|
return (authenticated); |
|
} |
|
#endif /* GSSAPI */ |