Merge branch 't/misc'
[paraslash.git] / command.c
index a8d479e..eb15875 100644 (file)
--- a/command.c
+++ b/command.c
@@ -6,10 +6,15 @@
 
 /** \file command.c Client authentication and server commands. */
 
+#include <netinet/in.h>
+#include <sys/socket.h>
 #include <regex.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <osl.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netdb.h>
 
 #include "para.h"
 #include "error.h"
@@ -779,14 +784,20 @@ static void reset_signals(void)
        para_sigaction(SIGHUP, SIG_DFL);
 }
 
-static int parse_auth_request(char *buf, int len, struct user **u)
+struct connection_features {
+       bool sideband_requested;
+       bool aes_ctr128_requested;
+};
+
+static int parse_auth_request(char *buf, int len, struct user **u,
+               struct connection_features *cf)
 {
        int ret;
        char *p, *username, **features = NULL;
        size_t auth_rq_len = strlen(AUTH_REQUEST_MSG);
-       bool sideband_requested = false;
 
        *u = NULL;
+       memset(cf, 0, sizeof(*cf));
        if (len < auth_rq_len + 2)
                return -E_AUTH_REQUEST;
        if (strncmp(buf, AUTH_REQUEST_MSG, auth_rq_len) != 0)
@@ -802,18 +813,15 @@ static int parse_auth_request(char *buf, int len, struct user **u)
                create_argv(p, ",", &features);
                for (i = 0; features[i]; i++) {
                        if (strcmp(features[i], "sideband") == 0)
-                               sideband_requested = true;
+                               cf->sideband_requested = true;
+                       else if (strcmp(features[i], "aes_ctr128") == 0)
+                               cf->aes_ctr128_requested = true;
                        else {
                                ret = -E_BAD_FEATURE;
                                goto out;
                        }
                }
        }
-       if (sideband_requested == false) { /* sideband is mandatory */
-               PARA_ERROR_LOG("client did not request sideband\n");
-               ret = -E_BAD_FEATURE;
-               goto out;
-       }
        PARA_DEBUG_LOG("received auth request for user %s\n", username);
        *u = lookup_user(username);
        ret = 1;
@@ -888,10 +896,11 @@ __noreturn void handle_connect(int fd, const char *peername)
        int ret;
        unsigned char rand_buf[CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
        unsigned char challenge_hash[HASH_SIZE];
-       char *p, *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
+       char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
        size_t numbytes;
        struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
        struct iovec iov;
+       struct connection_features cf;
 
        cc->scc.fd = fd;
        reset_signals();
@@ -902,7 +911,7 @@ __noreturn void handle_connect(int fd, const char *peername)
        /* send Welcome message */
        ret = write_va_buffer(fd, "This is para_server, version "
                PACKAGE_VERSION  ".\n"
-               "Features: sideband\n"
+               "Features: sideband,aes_ctr128\n"
        );
        if (ret < 0)
                goto net_err;
@@ -910,12 +919,14 @@ __noreturn void handle_connect(int fd, const char *peername)
        ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE);
        if (ret < 0)
                goto net_err;
-       ret = parse_auth_request(buf, ret, &cc->u);
+       ret = parse_auth_request(buf, ret, &cc->u, &cf);
        if (ret < 0)
                goto net_err;
-       p = buf + strlen(AUTH_REQUEST_MSG);
-       PARA_DEBUG_LOG("received auth request for user %s\n", p);
-       cc->u = lookup_user(p);
+       if (!cf.sideband_requested) { /* sideband is mandatory */
+               PARA_ERROR_LOG("client did not request sideband\n");
+               ret = -E_BAD_FEATURE;
+               goto net_err;
+       }
        if (cc->u) {
                get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
                ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
@@ -932,7 +943,7 @@ __noreturn void handle_connect(int fd, const char *peername)
                numbytes = 256;
                get_random_bytes_or_die((unsigned char *)buf, numbytes);
        }
-       PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
+       PARA_DEBUG_LOG("sending %u byte challenge + session key (%zu bytes)\n",
                CHALLENGE_SIZE, numbytes);
        ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
        buf = NULL;
@@ -962,8 +973,10 @@ __noreturn void handle_connect(int fd, const char *peername)
        alarm(0);
        PARA_INFO_LOG("good auth for %s\n", cc->u->name);
        /* init stream cipher keys with the second part of the random buffer */
-       cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
-       cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
+       cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN,
+               cf.aes_ctr128_requested);
+       cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
+               SESSION_KEY_LEN, cf.aes_ctr128_requested);
        ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
        if (ret < 0)
                goto net_err;