From f68988980d72d837f49451068b98bc96d1a548fc Mon Sep 17 00:00:00 2001
From: lns <matzeton@googlemail.com>
Date: Sun, 26 Aug 2018 16:01:18 +0200
Subject: Introduced the protocol->jail binary packet. We are using a
 handler/callback functions to obtain additional information from the protocol
 handler and transmit it to the sandbox.

Signed-off-by: lns <matzeton@googlemail.com>
---
 src/protocol_ssh.c | 96 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 71 insertions(+), 25 deletions(-)

(limited to 'src/protocol_ssh.c')

diff --git a/src/protocol_ssh.c b/src/protocol_ssh.c
index 0af4986..9d2be46 100644
--- a/src/protocol_ssh.c
+++ b/src/protocol_ssh.c
@@ -53,6 +53,7 @@
 
 #include "protocol_ssh.h"
 #include "protocol.h"
+#include "jail_packet.h"
 #ifdef HAVE_SECCOMP
 #include "pseccomp.h"
 #endif
@@ -65,8 +66,6 @@
     LIBSSH_VERSION_MICRO < 3
 #pragma message "Unsupported libssh version < 0.7.3"
 #endif
-#define USER_LEN LOGIN_NAME_MAX
-#define PASS_LEN 80
 #define CACHE_MAX 32
 #define CACHE_TIME (60 * 20) /* max cache time 20 minutes */
 #define LOGIN_SUCCESS_PROB ((double)1/4) /* successful login probability */
@@ -86,6 +85,15 @@ typedef struct ssh_client {
     forward_ctx dst;
 } ssh_client;
 
+typedef struct ssh_userdata {
+    jail_packet_ctx *pkt_ctx;
+    ssh_client *client;
+    event_ctx *ev_ctx;
+    event_buf proto_read;
+    event_buf proto_fd;
+    event_buf proto_chan;
+} ssh_userdata;
+
 struct protocol_cbs potd_ssh_callbacks = {
     .on_listen = ssh_on_listen,
     .on_shutdown = ssh_on_shutdown
@@ -108,10 +116,11 @@ static void ssh_log_cb(int priority, const char *function, const char *buffer,
                        void *userdata);
 static void ssh_mainloop(ssh_data *arg)
     __attribute__((noreturn));
-static int authenticate(ssh_session session, ssh_login_cache *cache);
+static int authenticate(ssh_session session, ssh_login_cache *cache,
+                        jail_packet_ctx *pkt_ctx);
 static int auth_password(const char *user, const char *pass,
                          ssh_login_cache *cache);
-static int client_mainloop(ssh_client *arg);
+static int client_mainloop(ssh_client *arg, jail_packet_ctx *ctx);
 static int copy_fd_to_chan(socket_t fd, int revents, void *userdata);
 static int copy_chan_to_fd(ssh_session session, ssh_channel channel, void *data,
                            uint32_t len, int is_stderr, void *userdata);
@@ -432,6 +441,7 @@ static void ssh_mainloop(ssh_data *arg)
 {
     pthread_mutexattr_t shared;
     ssh_login_cache *cache = NULL;
+    jail_packet_ctx pkt_ctx = INIT_PKTCTX(NULL,NULL);
     size_t i;
     int s, auth = 0, shell = 0, is_child;
     ssh_session ses;
@@ -488,7 +498,7 @@ static void ssh_mainloop(ssh_data *arg)
         }
 
         /* proceed to authentication */
-        auth = authenticate(ses, cache);
+        auth = authenticate(ses, cache, &pkt_ctx);
         if (!auth) {
             W("SSH authentication error: %s", ssh_get_error(ses));
             goto failed;
@@ -551,7 +561,7 @@ static void ssh_mainloop(ssh_data *arg)
 
         data.chan = chan;
         data.dst = arg->ctx->dst;
-        if (client_mainloop(&data))
+        if (client_mainloop(&data, &pkt_ctx))
             W2("Client mainloop for fd %d failed",
                 ssh_bind_get_fd(arg->sshbind));
 
@@ -563,7 +573,8 @@ failed:
     }
 }
 
-static int authenticate(ssh_session session, ssh_login_cache *cache)
+static int authenticate(ssh_session session, ssh_login_cache *cache,
+                        jail_packet_ctx *pkt_ctx)
 {
     ssh_message message;
     ssh_key pubkey;
@@ -588,6 +599,8 @@ static int authenticate(ssh_session session, ssh_login_cache *cache)
                         if (auth_password(ssh_message_auth_user(message),
                             ssh_message_auth_password(message), cache))
                         {
+                            pkt_ctx->user = strdup(ssh_message_auth_user(message));
+                            pkt_ctx->pass = strdup(ssh_message_auth_password(message));
                             ssh_message_auth_reply_success(message,0);
                             ssh_message_free(message);
                             return 1;
@@ -737,13 +750,16 @@ static int auth_password(const char *user, const char *pass,
     return got_auth;
 }
 
-static int client_mainloop(ssh_client *data)
+static int client_mainloop(ssh_client *data, jail_packet_ctx *pkt_ctx)
 {
     ssh_channel chan = data->chan;
     ssh_session session = ssh_channel_get_session(chan);
+    ssh_userdata userdata = { pkt_ctx, data, NULL,
+                              EMPTY_BUF, EMPTY_BUF, EMPTY_BUF };
     ssh_event event;
     short events;
     forward_ctx *ctx = &data->dst;
+    struct event_ctx *ev_ctx;
 
     if (fwd_connect_sock(ctx, NULL)) {
         E_STRERR("Connection to %s:%s",
@@ -752,7 +768,25 @@ static int client_mainloop(ssh_client *data)
         return 1;
     }
 
-    ssh_channel_cb.userdata = &ctx->sock.fd;
+    ev_ctx = jail_client_handshake(ctx->sock.fd, pkt_ctx);
+    if (!ev_ctx) {
+        ssh_channel_close(chan);
+        return 1;
+    }
+
+    pkt_ctx->connection.client_fd = pkt_ctx->writeback_buf.fd =
+        userdata.proto_read.fd = ctx->sock.fd;
+    if (jail_client_data(ev_ctx, &userdata.proto_read,
+                         &userdata.proto_chan, pkt_ctx))
+    {
+        ssh_channel_close(chan);
+        event_free(&ev_ctx);
+        return 1;
+    }
+    pkt_ctx->ev_readloop = 0;
+
+    userdata.ev_ctx = ev_ctx;
+    ssh_channel_cb.userdata = &userdata;
     ssh_callbacks_init(&ssh_channel_cb);
     ssh_set_channel_callbacks(chan, &ssh_channel_cb);
 
@@ -761,14 +795,19 @@ static int client_mainloop(ssh_client *data)
 
     if (event == NULL) {
         E2("%s", "Couldn't get a event");
+        event_free(&ev_ctx);
         return 1;
     }
-    if (ssh_event_add_fd(event, ctx->sock.fd, events, copy_fd_to_chan, chan) != SSH_OK) {
+    if (ssh_event_add_fd(event, ctx->sock.fd, events, copy_fd_to_chan,
+        &userdata) != SSH_OK)
+    {
         E2("Couldn't add fd %d to the event queue", ctx->sock.fd);
+        event_free(&ev_ctx);
         return 1;
     }
     if (ssh_event_add_session(event, session) != SSH_OK) {
         E2("%s", "Couldn't add the session to the event");
+        event_free(&ev_ctx);
         return 1;
     }
 
@@ -780,26 +819,34 @@ static int client_mainloop(ssh_client *data)
     ssh_event_remove_fd(event, ctx->sock.fd);
     ssh_event_remove_session(event, session);
     ssh_event_free(event);
+    event_free(&ev_ctx);
+
     return 0;
 }
 
 static int copy_fd_to_chan(socket_t fd, int revents, void *userdata)
 {
-    ssh_channel chan = (ssh_channel)userdata;
-    char buf[BUFSIZ];
-    int sz = 0;
+    ssh_userdata *sudata = (ssh_userdata *) userdata;
+    ssh_channel chan = sudata->client->chan;
+    ssize_t sz = 0;
+    int written;
 
-    if(!chan) {
+    if (!chan) {
         close(fd);
         return -1;
     }
-    if(revents & POLLIN) {
-        sz = read(fd, buf, BUFSIZ);
-        if(sz > 0) {
-            ssh_channel_write(chan, buf, sz);
+    if (revents & POLLIN) {
+        sz = event_buf_read(&sudata->proto_read);
+        if (sz > 0 &&
+            !jail_client_data(sudata->ev_ctx, &sudata->proto_read,
+                             &sudata->proto_chan, sudata->pkt_ctx))
+        {
+            written = ssh_channel_write(chan, sudata->proto_chan.buf,
+                                        sudata->proto_chan.buf_used);
+            event_buf_discard(&sudata->proto_chan, written);
         }
     }
-    if(revents & POLLHUP || sz <= 0) {
+    if (revents & POLLHUP || sz <= 0) {
         ssh_channel_close(chan);
         sz = -1;
     }
@@ -814,23 +861,22 @@ static int copy_chan_to_fd(ssh_session session,
                            int is_stderr,
                            void *userdata)
 {
-    int fd = *(int*) userdata;
-    int sz;
+    ssh_userdata *sudata = (ssh_userdata *) userdata;
 
     (void) session;
     (void) is_stderr;
 
-    sz = write(fd, data, len);
-    if (sz <= 0)
+    if (jail_client_send(sudata->pkt_ctx, data, len))
         ssh_channel_close(channel);
 
-    return sz;
+    return len;
 }
 
 static void chan_close(ssh_session session, ssh_channel channel,
                        void *userdata)
 {
-    int fd = *(int*) userdata;
+    ssh_userdata *sudata = (ssh_userdata *) userdata;
+    int fd = sudata->proto_read.fd;
 
     (void) session;
     (void) channel;
-- 
cgit v1.2.3