*/
#include "includes.h"
-RCSID("$OpenBSD: monitor.c,v 1.6 2002/03/21 18:38:33 stevesk Exp $");
+RCSID("$OpenBSD: monitor.c,v 1.13 2002/06/04 19:53:40 markus Exp $");
#include <openssl/dh.h>
int mm_answer_moduli(int, Buffer *);
int mm_answer_sign(int, Buffer *);
int mm_answer_pwnamallow(int, Buffer *);
+int mm_answer_auth2_read_banner(int, Buffer *);
int mm_answer_authserv(int, Buffer *);
int mm_answer_authpassword(int, Buffer *);
int mm_answer_bsdauthquery(int, Buffer *);
int mm_answer_sesskey(int, Buffer *);
int mm_answer_sessid(int, Buffer *);
+#ifdef USE_PAM
+int mm_answer_pam_start(int, Buffer *);
+#endif
+
static Authctxt *authctxt;
static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */
static u_char *hostbased_cuser = NULL;
static u_char *hostbased_chost = NULL;
static char *auth_method = "unknown";
+static int session_id2_len = 0;
+static u_char *session_id2 = NULL;
struct mon_table {
enum monitor_reqtype type;
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
+ {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
{MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+#ifdef USE_PAM
+ {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+#endif
#ifdef BSD_AUTH
{MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
{MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},
{MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
{MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge},
{MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response},
+#ifdef USE_PAM
+ {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+#endif
#ifdef BSD_AUTH
{MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
{MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},
#ifdef SKEY
{MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
{MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+#endif
+#ifdef USE_PAM
+ {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
#endif
{0, 0, NULL}
};
}
Authctxt *
-monitor_child_preauth(struct monitor *monitor)
+monitor_child_preauth(struct monitor *pmonitor)
{
struct mon_table *ent;
int authenticated = 0;
/* The first few requests do not require asynchronous access */
while (!authenticated) {
- authenticated = monitor_read(monitor, mon_dispatch, &ent);
+ authenticated = monitor_read(pmonitor, mon_dispatch, &ent);
if (authenticated) {
if (!(ent->flags & MON_AUTHDECIDE))
fatal("%s: unexpected authentication from %d",
if (authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(auth_method))
authenticated = 0;
+#ifdef USE_PAM
+ if (!do_pam_account(authctxt->pw->pw_name, NULL))
+ authenticated = 0;
+#endif
}
if (ent->flags & MON_AUTHDECIDE) {
debug("%s: %s has been authenticated by privileged process",
__FUNCTION__, authctxt->user);
- mm_get_keystate(monitor);
+ mm_get_keystate(pmonitor);
return (authctxt);
}
void
-monitor_child_postauth(struct monitor *monitor)
+monitor_child_postauth(struct monitor *pmonitor)
{
if (compat20) {
mon_dispatch = mon_dispatch_postauth20;
}
for (;;)
- monitor_read(monitor, mon_dispatch, NULL);
+ monitor_read(pmonitor, mon_dispatch, NULL);
}
void
-monitor_sync(struct monitor *monitor)
+monitor_sync(struct monitor *pmonitor)
{
/* 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
-monitor_read(struct monitor *monitor, struct mon_table *ent,
+monitor_read(struct monitor *pmonitor, struct mon_table *ent,
struct mon_table **pent)
{
Buffer m;
buffer_init(&m);
- mm_request_receive(monitor->m_sendfd, &m);
+ mm_request_receive(pmonitor->m_sendfd, &m);
type = buffer_get_char(&m);
debug3("%s: checking request %d", __FUNCTION__, type);
if (!(ent->flags & MON_PERMIT))
fatal("%s: unpermitted request %d", __FUNCTION__,
type);
- ret = (*ent->f)(monitor->m_sendfd, &m);
+ ret = (*ent->f)(pmonitor->m_sendfd, &m);
buffer_free(&m);
/* The child may use this request only once, disable it */
return ret;
}
- fatal("%s: unsupported request: %d\n", __FUNCTION__, type);
+ fatal("%s: unsupported request: %d", __FUNCTION__, type);
/* NOTREACHED */
return (-1);
if (datlen != 20)
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)
fatal("%s: no hostkey from index %d", __FUNCTION__, keyid);
if (key_sign(key, &signature, &siglen, p, datlen) < 0)
/* For SSHv1 allow authentication now */
if (!compat20)
monitor_permit_authentications(1);
- else
+ else {
/* Allow service/style information on the auth context */
monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
+ }
+
+#ifdef USE_PAM
+ monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
+#endif
+
+ return (0);
+}
+
+int mm_answer_auth2_read_banner(int socket, Buffer *m)
+{
+ char *banner;
+
+ buffer_clear(m);
+ banner = auth2_read_banner();
+ buffer_put_cstring(m, banner != NULL ? banner : "");
+ mm_request_send(socket, MONITOR_ANS_AUTH2_READ_BANNER, m);
+ if (banner != NULL)
+ free(banner);
return (0);
}
passwd = buffer_get_string(m, &plen);
/* 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));
xfree(passwd);
fatal("%s: no bsd auth session", __FUNCTION__);
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;
debug3("%s: <%s> = <%d>", __FUNCTION__, response, authok);
xfree(response);
response = buffer_get_string(m, NULL);
- authok = (authctxt->valid &&
+ authok = (options.challenge_response_authentication &&
+ authctxt->valid &&
skey_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, response) != -1);
}
#endif
+#ifdef USE_PAM
+int
+mm_answer_pam_start(int socket, Buffer *m)
+{
+ char *user;
+
+ user = buffer_get_string(m, NULL);
+
+ start_pam(user);
+
+ xfree(user);
+
+ return (0);
+}
+#endif
+
static void
mm_append_debug(Buffer *m)
{
if (key != NULL && authctxt->pw != NULL) {
switch(type) {
case MM_USERKEY:
- allowed = user_key_allowed(authctxt->pw, key);
+ allowed = options.pubkey_authentication &&
+ user_key_allowed(authctxt->pw, key);
break;
case MM_HOSTKEY:
- allowed = hostbased_key_allowed(authctxt->pw,
+ allowed = options.hostbased_authentication &&
+ hostbased_key_allowed(authctxt->pw,
cuser, chost, key);
break;
case MM_RSAHOSTKEY:
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);
break;
default:
u_char *p;
u_int len;
int fail = 0;
- int session_id2_len = 20 /*XXX should get from [net] */;
buffer_init(&b);
buffer_append(&b, data, datalen);
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);
} else {
- xfree(buffer_get_string(&b, &len));
- if (len != session_id2_len)
+ p = buffer_get_string(&b, &len);
+ if ((session_id2 == NULL) ||
+ (len != session_id2_len) ||
+ (memcmp(p, session_id2, session_id2_len) != 0))
fail++;
+ xfree(p);
}
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
fail++;
u_char *p;
u_int len;
int fail = 0;
- int session_id2_len = 20 /*XXX should get from [net] */;
buffer_init(&b);
buffer_append(&b, data, datalen);
- xfree(buffer_get_string(&b, &len));
- if (len != session_id2_len)
+ p = buffer_get_string(&b, &len);
+ if ((session_id2 == NULL) ||
+ (len != session_id2_len) ||
+ (memcmp(p, session_id2, session_id2_len) != 0))
fail++;
+ xfree(p);
+
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
fail++;
p = buffer_get_string(&b, NULL);
data = buffer_get_string(m, &datalen);
if (hostbased_cuser == NULL || hostbased_chost == NULL ||
- monitor_allowed_key(blob, bloblen) == NULL)
+ !monitor_allowed_key(blob, bloblen))
fatal("%s: bad key, not previously allowed", __FUNCTION__);
key = key_from_blob(blob, bloblen);
buffer_put_int(m, verified);
mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m);
- auth_method = "publickey";
+ auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
return (verified);
}
int
mm_answer_pty(int socket, Buffer *m)
{
- extern struct monitor *monitor;
+ extern struct monitor *pmonitor;
Session *s;
int res, fd0;
goto error;
s->authctxt = authctxt;
s->pw = authctxt->pw;
- s->pid = monitor->m_pid;
+ s->pid = pmonitor->m_pid;
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
if (res == 0)
goto error;
debug3("%s entering", __FUNCTION__);
- if (authctxt->valid) {
+ if (options.rsa_authentication && authctxt->valid) {
if ((client_n = BN_new()) == NULL)
fatal("%s: BN_new", __FUNCTION__);
buffer_get_bignum2(m, client_n);
int
mm_answer_term(int socket, Buffer *req)
{
- extern struct monitor *monitor;
+ extern struct monitor *pmonitor;
int res, status;
debug3("%s: tearing down sessions", __FUNCTION__);
/* The child is terminating */
session_destroy_all(&mm_session_close);
- if (waitpid(monitor->m_pid, &status, 0) == -1)
- exit(1);
+ while (waitpid(pmonitor->m_pid, &status, 0) == -1)
+ if (errno != EINTR)
+ exit(1);
res = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
}
void
-monitor_apply_keystate(struct monitor *monitor)
+monitor_apply_keystate(struct monitor *pmonitor)
{
if (compat20) {
set_newkeys(MODE_IN);
sizeof(outgoing_stream));
/* Update with new address */
- mm_init_compression(monitor->m_zlib);
+ mm_init_compression(pmonitor->m_zlib);
/* Network I/O buffers */
/* XXX inefficient for large buffers, need: buffer_init_from_string */
kex = xmalloc(sizeof(*kex));
memset(kex, 0, sizeof(*kex));
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->server = 1;
kex->hostkey_type = buffer_get_int(m);
/* This function requries careful sanity checking */
void
-mm_get_keystate(struct monitor *monitor)
+mm_get_keystate(struct monitor *pmonitor)
{
Buffer m;
u_char *blob, *p;
debug3("%s: Waiting for new keys", __FUNCTION__);
buffer_init(&m);
- mm_request_receive_expect(monitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m);
+ mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m);
if (!compat20) {
child_state.ssh1protoflags = buffer_get_int(&m);
child_state.ssh1cipher = buffer_get_int(&m);
goto skip;
} else {
/* Get the Kex for rekeying */
- *monitor->m_pkex = mm_get_kex(&m);
+ *pmonitor->m_pkex = mm_get_kex(&m);
}
blob = buffer_get_string(&m, &bloblen);
static void
monitor_socketpair(int *pair)
{
+#ifdef HAVE_SOCKETPAIR
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
fatal("%s: socketpair", __FUNCTION__);
+#else
+ fatal("%s: UsePrivilegeSeparation=yes not supported",
+ __FUNCTION__);
+#endif
FD_CLOSEONEXEC(pair[0]);
FD_CLOSEONEXEC(pair[1]);
}