]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 't/remove_sb_compat'
authorAndre Noll <maan@systemlinux.org>
Sat, 17 Aug 2013 11:57:32 +0000 (13:57 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 17 Aug 2013 12:06:35 +0000 (14:06 +0200)
This topic branch was cooking for over 4 months and should now be
ready for prime time. The patches break compatibility with earlier
versions, so we need to bump the version number real soon now.

72ffa7 client: Only start stdin task for addblob commands.
85a6ae Remove old stream cipher API.
d1407f Allow addblob commands to create output.
243e31 client: Remove client_recv_buffer().
277ed4 client: Remove sb-compatibility code.
36ba18 Reject non-sideband connections.
6ca50b blob: Avoid zero sized memcpy().
cf308c Fix typo in documentation of stdin_command().
fdb9d2 blob: Simplify fd2buf().

18 files changed:
NEWS
afs.c
aft.c
attribute.c
audiod.c
blob.c
client.c
client.h
client_common.c
command.c
command.h
crypt.c
crypt.h
crypt_common.c
error.h
gcrypt.c
para.h
sideband.h

diff --git a/NEWS b/NEWS
index 4127e38bcdf0434be750aed7da7fee83acad872e..a1cdf58eb86e172573f6dc446154961b41f8b0fe 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,13 @@
 ---------------------------------------------
-0.?.? (to be announced) "invertible validity"
+0.5.0 (to be announced) "invertible validity"
 ---------------------------------------------
 
+       - The sideband compatibility code has been removed, hence
+         sideband connections (introduced in 0.4.11) are now mandatory.
+       - Addblob commands can produce output.
+       - The stat command no longer sends garbage when para_server was
+         compiled against libgcrypt.
+
 --------------------------------------
 0.4.13 (2013-07-29) "spectral gravity"
 --------------------------------------
diff --git a/afs.c b/afs.c
index c87fdf78fb9bf60d413503f557cac34573b50edf..49ce13ebe1eec3dce17727af33bb51444f3a3108 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -565,10 +565,7 @@ int afs_cb_result_handler(struct osl_object *result, uint8_t band,
        assert(cc);
        if (!result->size)
                return 1;
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, result->data, result->size, band,
-                       true);
-       return sc_send_bin_buffer(&cc->scc, result->data, result->size);
+       return send_sb(&cc->scc, result->data, result->size, band, true);
 }
 
 static void com_select_callback(int fd, const struct osl_object *query)
@@ -1068,9 +1065,6 @@ int com_init(struct command_context *cc)
        }
        ret = send_callback_request(create_tables_callback, &query,
                afs_cb_result_handler, cc);
-       if (ret < 0 && !cc->use_sideband)
-               /* ignore return value */
-               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
diff --git a/aft.c b/aft.c
index a2883d4af1438ea9ab30e93a94ebc1a3ba5b1419..adc9a6f2ad92b212790feb59cc7e66aa12506307 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1876,12 +1876,8 @@ static int add_one_audio_file(const char *path, void *private_data)
        ret = 1;
        if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       send_ret = pad->cc->use_sideband?
-                               send_sb_va(&pad->cc->scc, SBD_OUTPUT,
-                                       "lazy-ignore: %s\n", path)
-                       :
-                               sc_send_va_buffer(&pad->cc->scc,
-                                       "lazy-ignore: %s\n", path);
+                       send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+                               "lazy-ignore: %s\n", path);
                goto out_free;
        }
        /* We still want to add this file. Compute its hash. */
@@ -1901,12 +1897,8 @@ static int add_one_audio_file(const char *path, void *private_data)
        ret = 1;
        if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) {
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       send_ret = pad->cc->use_sideband?
-                               send_sb_va(&pad->cc->scc, SBD_OUTPUT,
-                                       "%s exists, not forcing update\n", path)
-                       :
-                               sc_send_va_buffer(&pad->cc->scc,
-                                       "%s exists, not forcing update\n", path);
+                       send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+                               "%s exists, not forcing update\n", path);
                goto out_unmap;
        }
        /*
@@ -1923,12 +1915,8 @@ static int add_one_audio_file(const char *path, void *private_data)
        munmap(map.data, map.size);
        close(fd);
        if (pad->flags & ADD_FLAG_VERBOSE) {
-               send_ret = pad->cc->use_sideband?
-                       send_sb_va(&pad->cc->scc, SBD_OUTPUT,
-                               "adding %s\n", path)
-               :
-                       sc_send_va_buffer(&pad->cc->scc,
-                               "adding %s\n", path);
+               send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+                       "adding %s\n", path);
                if (send_ret < 0)
                        goto out_free;
        }
@@ -1943,14 +1931,8 @@ out_unmap:
        munmap(map.data, map.size);
 out_free:
        if (ret < 0 && send_ret >= 0)
-               send_ret = pad->cc->use_sideband?
-                       send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
-                               "failed to add %s (%s)\n", path,
-                               para_strerror(-ret))
-               :
-                       sc_send_va_buffer(&pad->cc->scc,
-                               "failed to add %s (%s)\n", path,
-                               para_strerror(-ret));
+               send_ret = send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
+                       "failed to add %s (%s)\n", path, para_strerror(-ret));
        free(obj.data);
        clear_afhi(afhi_ptr);
        /* Stop adding files only on send errors. */
@@ -1994,11 +1976,7 @@ int com_add(struct command_context *cc)
                char *path;
                ret = verify_path(cc->argv[i], &path);
                if (ret < 0) {
-                       ret = cc->use_sideband?
-                               send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
-                               cc->argv[i], para_strerror(-ret))
-                       :
-                               sc_send_va_buffer(&cc->scc, "%s: %s\n",
+                       ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
                                cc->argv[i], para_strerror(-ret));
                        if (ret < 0)
                                return ret;
@@ -2006,14 +1984,9 @@ int com_add(struct command_context *cc)
                }
                ret = stat(path, &statbuf);
                if (ret < 0) {
-                       ret = cc->use_sideband?
-                               send_sb_va(&cc->scc, SBD_ERROR_LOG,
-                                       "failed to stat %s (%s)\n", path,
-                                       strerror(errno))
-                               :
-                               sc_send_va_buffer(&cc->scc,
-                                       "failed to stat %s (%s)\n", path,
-                                       strerror(errno));
+                       ret = send_sb_va(&cc->scc, SBD_ERROR_LOG,
+                               "failed to stat %s (%s)\n", path,
+                               strerror(errno));
                        free(path);
                        if (ret < 0)
                                return ret;
@@ -2025,12 +1998,8 @@ int com_add(struct command_context *cc)
                else
                        ret = add_one_audio_file(path, &pad);
                if (ret < 0) {
-                       if (cc->use_sideband)
-                               send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
-                                       para_strerror(-ret));
-                       else
-                               sc_send_va_buffer(&cc->scc, "%s: %s\n", path,
-                                       para_strerror(-ret));
+                       send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
+                               para_strerror(-ret));
                        free(path);
                        return ret;
                }
index 96b54c99080deb62b0b593e62d6470306c601886..5a3861bed37ff9689ef171091b009db71df5ad28 100644 (file)
@@ -212,10 +212,7 @@ int com_lsatt(struct command_context *cc)
        if (ret < 0)
                send_strerror(cc, -ret);
        else if (ret == 0 && cc->argc > 1)
-               ret = cc->use_sideband?
-                       send_sb_va(&cc->scc, SBD_ERROR_LOG, "no matches\n")
-               :
-                       sc_send_va_buffer(&cc->scc, "no matches\n");
+               ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "no matches\n");
        return ret;
 }
 
index 8f2a72ac8700ee0699c19d78724cbe1d6ec61296..611e72d7d851a68f15053a03f21b93e01b1f9f2d 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1216,7 +1216,7 @@ static int status_post_select(struct sched *s, struct task *t)
                        close_stat_pipe();
                        goto out;
                }
-               if (st->ct->status != CL_RECEIVING)
+               if (st->ct->status != CL_EXECUTING)
                        goto out;
                ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
                if (ret <= 0) {
diff --git a/blob.c b/blob.c
index cd571d74e5d40f71286ef8dc19aca635778f9429..373d8d005cc1ea9e232f47f76e0c3794cd018538 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -311,12 +311,12 @@ static int com_rmblob(callback_function *f, struct command_context *cc)
                afs_cb_result_handler, cc);
 }
 
-static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
+static void com_addblob_callback(struct osl_table *table, int fd,
                const struct osl_object *query)
 {
        struct osl_object objs[NUM_BLOB_COLUMNS];
-       char *name = query->data;
-       size_t name_len = strlen(name) + 1;
+       char *name = query->data, *msg;
+       size_t name_len = strlen(name) + 1, msg_len;
        uint32_t id;
        unsigned num_rows;
        int ret;
@@ -344,6 +344,10 @@ static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
                if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND))
                        goto out;
                if (ret >= 0) { /* we already have a blob with this name */
+                       ret = osl(osl_get_object(table, row, BLOBCOL_ID, &obj));
+                       if (ret < 0)
+                               goto out;
+                       id = *(uint32_t *)obj.data;
                        obj.data = name + name_len;
                        obj.size = query->size - name_len;
                        ret = osl(osl_update_object(table, row, BLOBCOL_DEF, &obj));
@@ -377,81 +381,88 @@ static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
        afs_event(BLOB_ADD, NULL, table);
 out:
        if (ret < 0)
-               PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
+               msg_len = xasprintf(&msg, "could not add %s: %s\n", name,
+                       para_strerror(-ret));
+       else
+               msg_len = xasprintf(&msg, "added %s as id %u\n", name, id);
+       pass_buffer_as_shm(fd, SBD_OUTPUT, msg, msg_len);
+       free(msg);
 }
 
-/*
- * write input from fd to dynamically allocated buffer,
- * but maximal max_size byte.
- */
-static int fd2buf(struct stream_cipher_context *scc, unsigned max_size, struct osl_object *obj)
+/* Write input from fd to dynamically allocated buffer, but maximal 10M. */
+static int fd2buf(struct stream_cipher_context *scc, struct osl_object *obj)
 {
-       const size_t chunk_size = 1024;
-       size_t size = 2048, received = 0;
+       size_t max_size = 10 * 1024 * 1024;
        int ret;
-       char *buf = para_malloc(size);
+       struct iovec iov;
 
-       for (;;) {
-               ret = sc_recv_bin_buffer(scc, buf + received, chunk_size);
-               if (ret <= 0)
-                       break;
-               received += ret;
-               if (received + chunk_size >= size) {
-                       size *= 2;
-                       ret = -E_INPUT_TOO_LARGE;
-                       if (size > max_size)
-                               break;
-                       buf = para_realloc(buf, size);
-               }
+       obj->data = NULL;
+       obj->size = 0;
+again:
+       do {
+               ret = recv_sb(scc, SBD_BLOB_DATA, max_size, &iov);
+       } while (ret == 0);
+
+       if (ret < 0) {
+               free(obj->data);
+               obj->data = NULL;
+               obj->size = 0;
+               return ret;
        }
-       obj->data = buf;
-       obj->size = received;
-       if (ret < 0)
-               free(buf);
-       return ret;
+       if (iov.iov_len == 0) /* end of blob */
+               return 1;
+       if (!obj->data) {
+               obj->data = iov.iov_base;
+               obj->size = iov.iov_len;
+       } else {
+               obj->data = para_realloc(obj->data, obj->size + iov.iov_len);
+               memcpy(obj->data + obj->size, iov.iov_base, iov.iov_len);
+               obj->size += iov.iov_len;
+               free(iov.iov_base);
+               max_size -= iov.iov_len;
+       }
+       goto again;
+       return 1;
 }
 
 /*
  * Read data from a file descriptor, and send it to the afs process.
  *
- * \param scc crypt context containing the file descriptor to read data from.
+ * \param cc Contains the file descriptor to read data from.
  * \param arg_obj Pointer to the arguments to \a f.
  * \param f The callback function.
- * \param max_len Don't read more than that many bytes from stdin.
  * \param result_handler See \ref send_callback_request.
  * \param private_result_data See \ref send_callback_request.
  *
- * This function is used by commands that wish to let para_server store
- * arbitrary data specified by the user (for instance the add_blob family of
- * commands). First, at most \a max_len bytes are read and decrypted from the
- * file descriptor given by \a scc. The result is concatenated with the buffer
- * given by \a arg_obj, and the combined buffer is made available to the afs
- * process via the callback method. See \ref send_callback_request for details.
+ * This function is used by the addblob commands that instruct para_server to
+ * store arbitrary data in a blob table. Input data is read and decrypted from
+ * the file descriptor given by \a cc. This data is concatenated with the
+ * buffer given by \a arg_obj, and the combined buffer is made available to the
+ * afs process via the callback method. See \ref send_callback_request for
+ * details.
  *
  * \return Negative on errors, the return value of the underlying call to
  * send_callback_request() otherwise.
  */
 static int stdin_command(struct command_context *cc, struct osl_object *arg_obj,
-               callback_function *f, unsigned max_len,
-               callback_result_handler *result_handler,
+               callback_function *f, callback_result_handler *result_handler,
                void *private_result_data)
 {
        struct osl_object query, stdin_obj;
        int ret;
 
-       if (cc->use_sideband)
-               ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
-       else
-               ret = sc_send_buffer(&cc->scc, AWAITING_DATA_MSG);
+       ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
        if (ret < 0)
                return ret;
-       ret = fd2buf(&cc->scc, max_len, &stdin_obj);
+       ret = fd2buf(&cc->scc, &stdin_obj);
        if (ret < 0)
                return ret;
        query.size = arg_obj->size + stdin_obj.size;
        query.data = para_malloc(query.size);
        memcpy(query.data, arg_obj->data, arg_obj->size);
-       memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size);
+       if (stdin_obj.size > 0)
+               memcpy((char *)query.data + arg_obj->size, stdin_obj.data,
+                       stdin_obj.size);
        free(stdin_obj.data);
        ret = send_callback_request(f, &query, result_handler, private_result_data);
        free(query.data);
@@ -468,7 +479,7 @@ static int com_addblob(callback_function *f, struct command_context *cc)
                return -E_BLOB_SYNTAX;
        arg_obj.size = strlen(cc->argv[1]) + 1;
        arg_obj.data = (char *)cc->argv[1];
-       return stdin_command(cc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL);
+       return stdin_command(cc, &arg_obj, f, afs_cb_result_handler, cc);
 }
 
 /* FIXME: Print output to client, not to log file */
index 2d6ef31f590bca1736d458cc61c4fbe67459641b..873edc163b3e5f5164307d647724cf6655ec0d5f 100644 (file)
--- a/client.c
+++ b/client.c
@@ -452,7 +452,7 @@ static int client_i9e_line_handler(char *line)
        ret = client_connect(ct, &sched, NULL, NULL);
        if (ret < 0)
                return ret;
-       i9e_attach_to_stdout(ct->btrn);
+       i9e_attach_to_stdout(ct->btrn[0]);
        return 1;
 }
 
@@ -528,26 +528,37 @@ __noreturn static void print_completions(void)
 
 #endif /* HAVE_READLINE */
 
-static int supervisor_post_select(struct sched *s, __a_unused struct task *t)
+struct supervisor_task {
+       bool stdout_task_started;
+       struct task task;
+};
+
+static int supervisor_post_select(struct sched *s, struct task *t)
 {
+       struct supervisor_task *svt = container_of(t, struct supervisor_task,
+               task);
+
        if (ct->task.error < 0)
                return ct->task.error;
+       if (!svt->stdout_task_started && ct->status == CL_EXECUTING) {
+               stdout_set_defaults(&sot);
+               register_task(s, &sot.task);
+               svt->stdout_task_started = true;
+               return 1;
+       }
        if (ct->status == CL_SENDING) {
                stdin_set_defaults(&sit);
                register_task(s, &sit.task);
                return -E_TASK_STARTED;
        }
-       if (ct->status == CL_RECEIVING) {
-               stdout_set_defaults(&sot);
-               register_task(s, &sot.task);
-               return -E_TASK_STARTED;
-       }
        return 0;
 }
 
-static struct task svt = {
-       .post_select = supervisor_post_select,
-       .status = "supervisor task"
+static struct supervisor_task supervisor_task = {
+       .task = {
+               .post_select = supervisor_post_select,
+               .status = "supervisor task"
+       }
 };
 
 /**
@@ -595,8 +606,8 @@ int main(int argc, char *argv[])
        if (ret < 0)
                goto out;
        sot.btrn = btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = "stdout", .parent = ct->btrn));
-       register_task(&sched, &svt);
+               EMBRACE(.name = "stdout", .parent = ct->btrn[0]));
+       register_task(&sched, &supervisor_task.task);
        ret = schedule(&sched);
        if (ret >= 0 && ct->task.error < 0) {
                switch(ct->task.error) {
index 92e14b15eabc686b95a077d0097598f99b3f97a6..6e438f7ed15179da1817aea1c738712e229d7223 100644 (file)
--- a/client.h
+++ b/client.h
@@ -20,12 +20,10 @@ enum {
        CL_SENT_CH_RESPONSE,
        /** Server accepts this authentication. */
        CL_RECEIVED_PROCEED,
-       /** Client sends the command. */
-       CL_SENT_COMMAND,
-       /** Server expects data. */
+       /** Command is executing. */
+       CL_EXECUTING,
+       /** Server is expecting data (addblob commands only). */
        CL_SENDING,
-       /** Client expects data. */
-       CL_RECEIVING,
 };
 
 /** Data specific to a client task. */
@@ -34,10 +32,10 @@ struct client_task {
        int status;
        /** The file descriptor and the session keys. */
        struct stream_cipher_context scc;
-       /** True if this connections uses the sideband API. */
-       bool use_sideband;
-       /** The sideband context, ignored if \a use_sideband is false. */
-       struct sb_context *sbc;
+       /** The sideband contexts for receiving/sending. */
+       struct sb_context *sbc[2];
+       /** The buffer tree nodes for receiving/sending. */
+       struct btr_node *btrn[2];
        /** The hash value of the decrypted challenge. */
        unsigned char *challenge_hash;
        /** The configuration (including the command). */
@@ -50,8 +48,6 @@ struct client_task {
        char *user;
        /** The client task structure. */
        struct task task;
-       /** The buffer tree node of the client task. */
-       struct btr_node *btrn;
        /** List of features supported by the server. */
        char **features;
 };
index 1ecba73068f04c4dbf43480f5ccf32a932e01279..c19b71218b59f62f1e6a75c1eee43ee332a65900 100644 (file)
@@ -49,7 +49,8 @@ void client_disconnect(struct client_task *ct)
        ct->scc.recv = NULL;
        sc_free(ct->scc.send);
        ct->scc.send = NULL;
-       btr_remove_node(&ct->btrn);
+       btr_remove_node(&ct->btrn[0]);
+       btr_remove_node(&ct->btrn[1]);
 }
 
 /**
@@ -69,7 +70,8 @@ void client_close(struct client_task *ct)
        free(ct->key_file);
        client_cmdline_parser_free(&ct->conf);
        free(ct->challenge_hash);
-       sb_free(ct->sbc);
+       sb_free(ct->sbc[0]);
+       sb_free(ct->sbc[1]);
        free(ct);
 }
 
@@ -91,7 +93,6 @@ static void client_pre_select(struct sched *s, struct task *t)
 {
        int ret;
        struct client_task *ct = container_of(t, struct client_task, task);
-       struct btr_node *btrn = ct->btrn;
 
        if (ct->scc.fd < 0)
                return;
@@ -99,7 +100,6 @@ static void client_pre_select(struct sched *s, struct task *t)
        case CL_CONNECTED:
        case CL_SENT_AUTH:
        case CL_SENT_CH_RESPONSE:
-       case CL_SENT_COMMAND:
                para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
                return;
 
@@ -109,76 +109,49 @@ static void client_pre_select(struct sched *s, struct task *t)
                para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
                return;
 
-       case CL_RECEIVING:
-               ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
-               if (ret != 0) {
+       case CL_SENDING:
+               if (ct->btrn[1]) {
+                       ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
                        if (ret < 0)
                                sched_min_delay(s);
-                       else
-                               para_fd_set(ct->scc.fd, &s->rfds,
-                                       &s->max_fileno);
+                       else if (ret > 0)
+                               para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
                }
-               return;
-       case CL_SENDING:
-               ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
-               if (ret != 0) {
+               /* fall though */
+       case CL_EXECUTING:
+               if (ct->btrn[0]) {
+                       ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
                        if (ret < 0)
                                sched_min_delay(s);
-                       else
-                               para_fd_set(ct->scc.fd, &s->wfds,
-                                       &s->max_fileno);
+                       else if (ret > 0)
+                               para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
                }
                return;
        }
 }
 
-static int client_recv_buffer(struct client_task *ct, fd_set *rfds,
-               char *buf, size_t sz, size_t *n)
-{
-       int ret;
-
-       if (ct->status < CL_SENT_CH_RESPONSE)
-               return read_nonblock(ct->scc.fd, buf, sz, rfds, n);
-
-       *n = 0;
-       ret = sc_recv_buffer(&ct->scc, buf, sz);
-       /*
-        * sc_recv_buffer is used with blocking fds elsewhere, so it
-        * does not use the nonblock-API. Therefore we need to
-        * check for EOF and EAGAIN.
-        */
-       if (ret == 0)
-               return -E_SERVER_EOF;
-       if (ret == -ERRNO_TO_PARA_ERROR(EAGAIN))
-               return 0;
-       if (ret < 0)
-               return ret;
-       *n = ret;
-       return 0;
-}
-
-static int send_sb(struct client_task *ct, void *buf, size_t numbytes,
+static int send_sb(struct client_task *ct, int channel, void *buf, size_t numbytes,
                enum sb_designator band, bool dont_free)
 {
        int ret, fd = ct->scc.fd;
        struct iovec iov[2];
 
-       if (!ct->sbc) {
+       if (!ct->sbc[channel]) {
                struct sb_buffer sbb;
                sb_transformation trafo = ct->status < CL_RECEIVED_PROCEED?
                        NULL : sc_trafo;
                sbb = (typeof(sbb))SBB_INIT(band, buf, numbytes);
-               ct->sbc = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
+               ct->sbc[channel] = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
        }
-       ret = sb_get_send_buffers(ct->sbc, iov);
+       ret = sb_get_send_buffers(ct->sbc[channel], iov);
        ret = xwritev(fd, iov, ret);
        if (ret < 0) {
-               sb_free(ct->sbc);
-               ct->sbc = NULL;
+               sb_free(ct->sbc[channel]);
+               ct->sbc[channel] = NULL;
                return ret;
        }
-       if (sb_sent(ct->sbc, ret)) {
-               ct->sbc = NULL;
+       if (sb_sent(ct->sbc[channel], ret)) {
+               ct->sbc[channel] = NULL;
                return 1;
        }
        return 0;
@@ -201,21 +174,21 @@ static int recv_sb(struct client_task *ct, fd_set *rfds,
                trafo = sc_trafo;
                trafo_context = ct->scc.recv;
        }
-       if (!ct->sbc)
-               ct->sbc = sb_new_recv(0, trafo, trafo_context);
+       if (!ct->sbc[0])
+               ct->sbc[0] = sb_new_recv(0, trafo, trafo_context);
 again:
-       sb_get_recv_buffer(ct->sbc, &iov);
+       sb_get_recv_buffer(ct->sbc[0], &iov);
        ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, rfds, &n);
        if (ret < 0) {
-               sb_free(ct->sbc);
-               ct->sbc = NULL;
+               sb_free(ct->sbc[0]);
+               ct->sbc[0] = NULL;
                return ret;
        }
        if (n == 0)
                return 0;
-       if (!sb_received(ct->sbc, n, result))
+       if (!sb_received(ct->sbc[0], n, result))
                goto again;
-       ct->sbc = NULL;
+       ct->sbc[0] = NULL;
        return 1;
 }
 
@@ -251,10 +224,14 @@ static int dispatch_sbb(struct client_task *ct, struct sb_buffer *sbb)
                PARA_DEBUG_LOG("band: %s\n", designator[sbb->band]);
 
        switch (sbb->band) {
+       case SBD_AWAITING_DATA:
+               ct->status = CL_SENDING;
+               ret = 1;
+               goto out;
        case SBD_OUTPUT:
                if (iov_valid(&sbb->iov))
                        btr_add_output(sbb->iov.iov_base, sbb->iov.iov_len,
-                               ct->btrn);
+                               ct->btrn[0]);
                ret = 1;
                goto out;
        case SBD_DEBUG_LOG:
@@ -299,8 +276,8 @@ static int send_sb_command(struct client_task *ct)
        char *command, *p;
        size_t len = 0;
 
-       if (ct->sbc)
-               return send_sb(ct, NULL, 0, 0, false);
+       if (ct->sbc[1])
+               return send_sb(ct, 0, NULL, 0, 0, false);
 
        for (i = 0; i < ct->conf.inputs_num; i++)
                len += strlen(ct->conf.inputs[i]) + 1;
@@ -310,7 +287,7 @@ static int send_sb_command(struct client_task *ct)
                p += strlen(ct->conf.inputs[i]) + 1;
        }
        PARA_DEBUG_LOG("--> %s\n", command);
-       return send_sb(ct, command, len, SBD_COMMAND, false);
+       return send_sb(ct, 0, command, len, SBD_COMMAND, false);
 }
 
 /**
@@ -329,7 +306,6 @@ static int send_sb_command(struct client_task *ct)
 static int client_post_select(struct sched *s, struct task *t)
 {
        struct client_task *ct = container_of(t, struct client_task, task);
-       struct btr_node *btrn = ct->btrn;
        int ret = 0;
        size_t n;
        char buf[CLIENT_BUFSIZE];
@@ -341,20 +317,21 @@ static int client_post_select(struct sched *s, struct task *t)
                return 0;
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
-               ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
+               ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
                if (ret < 0 || n == 0)
                        goto out;
                ct->features = parse_features(buf);
+               if (!has_feature("sideband", ct)) {
+                       PARA_ERROR_LOG("server has no sideband support\n");
+                       ret = -E_INCOMPAT_FEAT;
+                       goto out;
+               }
                ct->status = CL_RECEIVED_WELCOME;
                return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
                        return 0;
-               if (has_feature("sideband", ct)) {
-                       ct->use_sideband = true;
-                       sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
-               } else
-                       sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+               sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
                PARA_INFO_LOG("--> %s\n", buf);
                ret = write_buffer(ct->scc.fd, buf);
                if (ret < 0)
@@ -369,35 +346,23 @@ static int client_post_select(struct sched *s, struct task *t)
                {
                /* decrypted challenge/session key buffer */
                unsigned char crypt_buf[1024];
-               /* the SHA1 of the decrypted challenge */
+               struct sb_buffer sbb;
 
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret <= 0)
-                               goto out;
-                       if (sbb.band != SBD_CHALLENGE) {
-                               ret = -E_BAD_BAND;
-                               free(sbb.iov.iov_base);
-                                       goto out;
-                       }
-                       n = sbb.iov.iov_len;
-                       PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
-                       ret = priv_decrypt(ct->key_file, crypt_buf,
-                               sbb.iov.iov_base, n);
+               ret = recv_sb(ct, &s->rfds, &sbb);
+               if (ret <= 0)
+                       goto out;
+               if (sbb.band != SBD_CHALLENGE) {
+                       ret = -E_BAD_BAND;
                        free(sbb.iov.iov_base);
-                       if (ret < 0)
-                               goto out;
-               } else {
-                       ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
-                       if (ret < 0 || n == 0)
-                               goto out;
-                       PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
-                       ret = priv_decrypt(ct->key_file, crypt_buf,
-                               (unsigned char *)buf, n);
-                       if (ret < 0)
                                goto out;
                }
+               n = sbb.iov.iov_len;
+               PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
+               ret = priv_decrypt(ct->key_file, crypt_buf,
+                       sbb.iov.iov_base, n);
+               free(sbb.iov.iov_base);
+               if (ret < 0)
+                       goto out;
                ct->challenge_hash = para_malloc(HASH_SIZE);
                hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
                ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
@@ -409,162 +374,100 @@ static int client_post_select(struct sched *s, struct task *t)
                return 0;
                }
        case CL_RECEIVED_CHALLENGE:
-               if (ct->use_sideband) {
-                       ret = send_sb(ct, ct->challenge_hash, HASH_SIZE,
-                               SBD_CHALLENGE_RESPONSE, false);
-                       if (ret != 0)
-                               ct->challenge_hash = NULL;
-                       if (ret <= 0)
-                               goto out;
-               } else {
-                       ret = write_all(ct->scc.fd, (char *)ct->challenge_hash, HASH_SIZE);
-                       if (ret < 0)
-                               goto out;
-               }
+               ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+                       SBD_CHALLENGE_RESPONSE, false);
+               if (ret != 0)
+                       ct->challenge_hash = NULL;
+               if (ret <= 0)
+                       goto out;
                ct->status = CL_SENT_CH_RESPONSE;
                goto out;
        case CL_SENT_CH_RESPONSE: /* read server response */
                {
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret <= 0)
-                               goto out;
-                       free(sbb.iov.iov_base);
-                       if (sbb.band != SBD_PROCEED)
-                               ret = -E_BAD_BAND;
-                       else
-                               ct->status = CL_RECEIVED_PROCEED;
-                       goto out;
-               }
-               ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
-               if (ret < 0 || n == 0)
-                       goto out;
-               /* check if server has sent "Proceed" message */
-               ret = -E_CLIENT_AUTH;
-               if (n < PROCEED_MSG_LEN)
-                       goto out;
-               if (!strstr(buf, PROCEED_MSG))
+               struct sb_buffer sbb;
+               ret = recv_sb(ct, &s->rfds, &sbb);
+               if (ret <= 0)
                        goto out;
-               ct->status = CL_RECEIVED_PROCEED;
-               return 0;
+               free(sbb.iov.iov_base);
+               if (sbb.band != SBD_PROCEED)
+                       ret = -E_BAD_BAND;
+               else
+                       ct->status = CL_RECEIVED_PROCEED;
+               goto out;
                }
        case CL_RECEIVED_PROCEED: /* concat args and send command */
                {
-               int i;
-               char *command = NULL;
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
                        return 0;
-               if (ct->use_sideband) {
-                       ret = send_sb_command(ct);
-                       if (ret <= 0)
-                               goto out;
-                       ct->status = CL_SENT_COMMAND;
-                       return 0;
-               }
-               for (i = 0; i < ct->conf.inputs_num; i++) {
-                       char *tmp = command;
-                       command = make_message("%s\n%s", command?
-                               command : "", ct->conf.inputs[i]);
-                       free(tmp);
-               }
-               command = para_strcat(command, EOC_MSG "\n");
-               PARA_DEBUG_LOG("--> %s\n", command);
-               ret = sc_send_buffer(&ct->scc, command);
-               free(command);
-               if (ret < 0)
+               ret = send_sb_command(ct);
+               if (ret <= 0)
                        goto out;
-               ct->status = CL_SENT_COMMAND;
+               ct->status = CL_EXECUTING;
                return 0;
                }
-       case CL_SENT_COMMAND:
-               {
-               char *buf2;
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret <= 0)
-                               goto out;
-                       if (sbb.band == SBD_AWAITING_DATA) {
-                               ct->status = CL_SENDING;
-                               free(sbb.iov.iov_base);
-                               goto out;
+       case CL_SENDING:
+               if (ct->btrn[1]) {
+                       char *buf2;
+                       size_t sz;
+                       ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
+                       if (ret == -E_BTR_EOF) {
+                               /* empty blob data packet indicates EOF */
+                               PARA_INFO_LOG("blob sent\n");
+                               ret = send_sb(ct, 1, NULL, 0, SBD_BLOB_DATA, true);
+                               if (ret >= 0)
+                                       ret = -E_BTR_EOF;
                        }
-                       ct->status = CL_RECEIVING;
-                       ret = dispatch_sbb(ct, &sbb);
-                       goto out;
-               }
-               /* can not use "buf" here because we need a malloced buffer */
-               buf2 = para_malloc(CLIENT_BUFSIZE);
-               ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
-               if (n > 0) {
-                       if (strstr(buf2, AWAITING_DATA_MSG)) {
-                               free(buf2);
-                               ct->status = CL_SENDING;
-                               return 0;
+                       if (ret < 0)
+                               goto close1;
+                       if (ret > 0 && FD_ISSET(ct->scc.fd, &s->wfds)) {
+                               sz = btr_next_buffer(ct->btrn[1], &buf2);
+                               assert(sz);
+                               ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
+                               if (ret < 0)
+                                       goto close1;
+                               if (ret > 0)
+                                       btr_consume(ct->btrn[1], sz);
                        }
-                       ct->status = CL_RECEIVING;
-                       btr_add_output(buf2, n, btrn);
-               } else
-                       free(buf2);
-               goto out;
                }
-       case CL_SENDING:
-               {
-               char *buf2;
-               size_t sz;
-               ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
-               if (ret < 0)
-                       goto out;
-               if (ret == 0)
-                       return 0;
-               if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return 0;
-               sz = btr_next_buffer(btrn, &buf2);
-               ret = sc_send_bin_buffer(&ct->scc, buf2, sz);
-               if (ret < 0)
-                       goto out;
-               btr_consume(btrn, sz);
-               return 0;
-               }
-       case CL_RECEIVING:
-               {
-               char *buf2;
-               ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
-               if (ret < 0)
-                       goto out;
-               if (ret == 0)
-                       return 0;
-               /*
-                * The FD_ISSET() is not strictly necessary, but is allows us
-                * to skip the malloc below if there is nothing to read anyway.
-                */
-               if (!FD_ISSET(ct->scc.fd, &s->rfds))
-                       return 0;
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret > 0)
-                               ret = dispatch_sbb(ct, &sbb);
-                       goto out;
+               /* fall though */
+       case CL_EXECUTING:
+               if (ct->btrn[0]) {
+                       ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
+                       if (ret < 0)
+                               goto close0;
+                       if (ret > 0 && FD_ISSET(ct->scc.fd, &s->rfds)) {
+                               struct sb_buffer sbb;
+                               ret = recv_sb(ct, &s->rfds, &sbb);
+                               if (ret < 0)
+                                       goto close0;
+                               if (ret > 0) {
+                                       ret = dispatch_sbb(ct, &sbb);
+                                       if (ret < 0)
+                                               goto close0;
+                               }
+                       }
                }
-               buf2 = para_malloc(CLIENT_BUFSIZE);
-               ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
-               if (n > 0) {
-                       buf2 = para_realloc(buf2, n);
-                       btr_add_output(buf2, n, btrn);
-               } else
-                       free(buf2);
+               ret = 0;
                goto out;
-               }
        }
+close1:
+       PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret));
+       btr_remove_node(&ct->btrn[1]);
+       if (ct->btrn[0])
+               return 0;
+       goto out;
+close0:
+       PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret));
+       btr_remove_node(&ct->btrn[0]);
+       if (ct->btrn[1] && ct->status == CL_SENDING)
+               return 0;
 out:
-       if (ret < 0) {
-               if (!ct->use_sideband && ret != -E_SERVER_EOF &&
-                               ret != -E_BTR_EOF && ret != -E_EOF)
-                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-               btr_remove_node(&ct->btrn);
-       }
+       if (ret >= 0)
+               return 0;
+       btr_remove_node(&ct->btrn[0]);
+       btr_remove_node(&ct->btrn[1]);
+       if (ret != -E_SERVER_CMD_SUCCESS && ret != -E_SERVER_CMD_FAILURE)
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -598,8 +501,10 @@ int client_connect(struct client_task *ct, struct sched *s,
        if (ret < 0)
                goto err_out;
        ct->status = CL_CONNECTED;
-       ct->btrn = btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = "client", .parent = parent, .child = child));
+       ct->btrn[0] = btr_new_node(&(struct btr_node_description)
+               EMBRACE(.name = "client recv", .parent = NULL, .child = child));
+       ct->btrn[1] = btr_new_node(&(struct btr_node_description)
+               EMBRACE(.name = "client send", .parent = parent, .child = NULL));
        ct->task.pre_select = client_pre_select;
        ct->task.post_select = client_post_select;
        ct->task.error = 0;
index 41a58eac0517e15e44c964250578173708289e60..4bbf494c869b6938b596dbf9dcf45b9613fbf924 100644 (file)
--- a/command.c
+++ b/command.c
@@ -268,10 +268,7 @@ __printf_3_4 int send_sb_va(struct stream_cipher_context *scc, int band,
  */
 int send_strerror(struct command_context *cc, int err)
 {
-       return cc->use_sideband?
-               send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err))
-       :
-               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(err));
+       return send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err));
 }
 
 /**
@@ -338,23 +335,14 @@ static int com_sender(struct command_context *cc)
                        free(msg);
                        msg = tmp;
                }
-               if (cc->use_sideband)
-                       return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
-               ret = sc_send_buffer(&cc->scc, msg);
-               free(msg);
-               return ret;
+               return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
        }
        ret = check_sender_args(cc->argc, cc->argv, &scd);
        if (ret < 0) {
                if (scd.sender_num < 0)
                        return ret;
                msg = senders[scd.sender_num].help();
-               if (cc->use_sideband)
-                       return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT,
-                               false);
-               ret = sc_send_buffer(&cc->scc, msg);
-               free(msg);
-               return ret;
+               return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
        }
 
        switch (scd.cmd_num) {
@@ -418,11 +406,7 @@ static int com_si(struct command_context *cc)
        mutex_unlock(mmd_mutex);
        free(ut);
        free(sender_info);
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
-       ret = sc_send_bin_buffer(&cc->scc, msg, ret);
-       free(msg);
-       return ret;
+       return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
 }
 
 /* version */
@@ -434,9 +418,7 @@ static int com_version(struct command_context *cc)
        if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        len = xasprintf(&msg, "%s", version_text("server"));
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
-       return sc_send_bin_buffer(&cc->scc, msg, len);
+       return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
 }
 
 #define EMPTY_STATUS_ITEMS \
@@ -536,24 +518,13 @@ static int com_stat(struct command_context *cc)
        for (;;) {
                mmd_dup(nmmd);
                ret = get_status(nmmd, parser_friendly, &s);
-               if (cc->use_sideband)
-                       ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
-               else {
-                       ret = sc_send_bin_buffer(&cc->scc, s, ret);
-                       free(s);
-               }
+               ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
                if (ret < 0)
                        goto out;
                if (nmmd->vss_status_flags & VSS_NEXT) {
                        char *esi;
                        ret = empty_status_items(parser_friendly, &esi);
-                       if (cc->use_sideband)
-                               ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT,
-                                       false);
-                       else {
-                               ret = sc_send_bin_buffer(&cc->scc, esi, ret);
-                               free(esi);
-                       }
+                       ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, false);
                        if (ret < 0)
                                goto out;
                } else
@@ -573,7 +544,6 @@ out:
 static int send_list_of_commands(struct command_context *cc, struct server_command *cmd,
                const char *handler)
 {
-       int ret;
        char *msg = NULL;
 
        for (; cmd->name; cmd++) {
@@ -584,11 +554,7 @@ static int send_list_of_commands(struct command_context *cc, struct server_comma
                msg = para_strcat(msg, tmp);
                free(tmp);
        }
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
-       ret = sc_send_buffer(&cc->scc, msg);
-       free(msg);
-       return ret;
+       return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
 }
 
 /* returns string that must be freed by the caller */
@@ -644,11 +610,7 @@ static int com_help(struct command_context *cc)
        );
        free(perms);
        free(handler);
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
-       ret = sc_send_buffer(&cc->scc, buf);
-       free(buf);
-       return ret;
+       return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
 }
 
 /* hup */
@@ -810,58 +772,6 @@ static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
        return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
 }
 
-/*
- * Parse first string from *cmd and lookup in table of valid commands.
- * On error, NULL is returned.
- */
-static struct server_command *parse_cmd(const char *cmdstr)
-{
-       char buf[255];
-       int n = 0;
-
-       sscanf(cmdstr, "%200s%n", buf, &n);
-       if (!n)
-               return NULL;
-       buf[n] = '\0';
-       return get_cmd_ptr(buf, NULL);
-}
-
-static int read_command(struct stream_cipher_context *scc, char **result)
-{
-       int ret;
-       char buf[4096];
-       char *command = NULL;
-
-       for (;;) {
-               size_t numbytes;
-               char *p;
-
-               ret = sc_recv_buffer(scc, buf, sizeof(buf));
-               if (ret < 0)
-                       goto out;
-               if (!ret)
-                       break;
-               numbytes = ret;
-               ret = -E_COMMAND_SYNTAX;
-               if (command && numbytes + strlen(command) > MAX_COMMAND_LEN) /* DOS */
-                       goto out;
-               command = para_strcat(command, buf);
-               p = strstr(command, EOC_MSG);
-               if (p) {
-                       *p = '\0';
-                       break;
-               }
-       }
-       ret = command? 1 : -E_COMMAND_SYNTAX;
-out:
-       if (ret < 0)
-               free(command);
-       else
-               *result = command;
-       return ret;
-
-}
-
 static void reset_signals(void)
 {
        para_sigaction(SIGCHLD, SIG_IGN);
@@ -870,15 +780,14 @@ static void reset_signals(void)
        para_sigaction(SIGHUP, SIG_DFL);
 }
 
-static int parse_auth_request(char *buf, int len, struct user **u,
-               bool *use_sideband)
+static int parse_auth_request(char *buf, int len, struct user **u)
 {
        int ret;
        char *p, *username, **features = NULL;
        size_t auth_rq_len = strlen(AUTH_REQUEST_MSG);
+       bool sideband_requested = false;
 
        *u = NULL;
-       *use_sideband = false;
        if (len < auth_rq_len + 2)
                return -E_AUTH_REQUEST;
        if (strncmp(buf, AUTH_REQUEST_MSG, auth_rq_len) != 0)
@@ -894,15 +803,19 @@ 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)
-                               *use_sideband = true;
+                               sideband_requested = true;
                        else {
                                ret = -E_BAD_FEATURE;
                                goto out;
                        }
                }
        }
-       PARA_DEBUG_LOG("received auth request for user %s (sideband = %s)\n",
-               username, *use_sideband? "true" : "false");
+       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;
 out:
@@ -979,6 +892,7 @@ __noreturn void handle_connect(int fd, const char *peername)
        char *p, *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;
 
        cc->scc.fd = fd;
        reset_signals();
@@ -997,7 +911,7 @@ __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, &cc->use_sideband);
+       ret = parse_auth_request(buf, ret, &cc->u);
        if (ret < 0)
                goto net_err;
        p = buf + strlen(AUTH_REQUEST_MSG);
@@ -1021,28 +935,16 @@ __noreturn void handle_connect(int fd, const char *peername)
        }
        PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
                CHALLENGE_SIZE, numbytes);
-       if (cc->use_sideband) {
-               struct iovec iov;
-               ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
-               buf = NULL;
-               if (ret < 0)
-                       goto net_err;
-               ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
-                       HANDSHAKE_BUFSIZE, &iov);
-               if (ret < 0)
-                       goto net_err;
-               buf = iov.iov_base;
-               numbytes = iov.iov_len;
-       } else {
-               ret = write_all(fd, buf, numbytes);
-               if (ret < 0)
-                       goto net_err;
-               /* recv challenge response */
-               ret = recv_bin_buffer(fd, buf, HASH_SIZE);
-               if (ret < 0)
-                       goto net_err;
-               numbytes = ret;
-       }
+       ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
+       buf = NULL;
+       if (ret < 0)
+               goto net_err;
+       ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
+               HANDSHAKE_BUFSIZE, &iov);
+       if (ret < 0)
+               goto net_err;
+       buf = iov.iov_base;
+       numbytes = iov.iov_len;
        PARA_DEBUG_LOG("received %zu bytes challenge response\n", numbytes);
        ret = -E_BAD_USER;
        if (!cc->u)
@@ -1063,41 +965,16 @@ __noreturn void handle_connect(int fd, const char *peername)
        /* 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);
-       if (cc->use_sideband)
-               ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
-       else
-               ret = sc_send_buffer(&cc->scc, PROCEED_MSG);
+       ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
        if (ret < 0)
                goto net_err;
-       if (cc->use_sideband) {
-               struct iovec iov;
-               ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
-               if (ret < 0)
-                       goto net_err;
-               ret = parse_sb_command(cc, &iov);
-               if (ret < 0)
-                       goto err_out;
-               cc->argc = ret;
-       } else {
-               ret = read_command(&cc->scc, &command);
-               if (ret == -E_COMMAND_SYNTAX)
-                       goto err_out;
-               if (ret < 0)
-                       goto net_err;
-               ret = -E_BAD_CMD;
-               cc->cmd = parse_cmd(command);
-               if (!cc->cmd)
-                       goto err_out;
-               /* valid command, check permissions */
-               ret = check_perms(cc->u->perms, cc->cmd);
-               if (ret < 0)
-                       goto err_out;
-               /* valid command and sufficient perms */
-               ret = create_argv(command, "\n", &cc->argv);
-               if (ret < 0)
-                       goto err_out;
-               cc->argc = ret;
-       }
+       ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
+       if (ret < 0)
+               goto net_err;
+       ret = parse_sb_command(cc, &iov);
+       if (ret < 0)
+               goto err_out;
+       cc->argc = ret;
        PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name,
                cc->u->name, peername);
        ret = cc->cmd->handler(cc);
@@ -1108,7 +985,7 @@ __noreturn void handle_connect(int fd, const char *peername)
        if (ret >= 0)
                goto out;
 err_out:
-       if (send_strerror(cc, -ret) >= 0 && cc->use_sideband)
+       if (send_strerror(cc, -ret) >= 0)
                send_sb(&cc->scc, NULL, 0, SBD_EXIT__FAILURE, true);
 net_err:
        PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
@@ -1120,7 +997,7 @@ out:
                mmd->events++;
        mmd->active_connections--;
        mutex_unlock(mmd_mutex);
-       if (ret >= 0 && cc->use_sideband) {
+       if (ret >= 0) {
                ret = send_sb(&cc->scc, NULL, 0, SBD_EXIT__SUCCESS, true);
                if (ret < 0)
                        PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
index e4159e6bda00131bf4a1ef6b5a46627c9f7d88b1..6d2202071c6b849fe37a9a69c30c21d09ff80ef0 100644 (file)
--- a/command.h
+++ b/command.h
@@ -14,8 +14,6 @@ struct command_context {
        struct server_command *cmd;
        /** File descriptor and crypto keys. */
        struct stream_cipher_context scc;
-       /** Whether to use the sideband API for this command. */
-       bool use_sideband;
 };
 
 /**
diff --git a/crypt.c b/crypt.c
index 5c5333a9a15a43d2cecf5d3ed1774141c58b90cf..b8577dfc5ab164a5f0b382273aab1c8083a05ef1 100644 (file)
--- a/crypt.c
+++ b/crypt.c
@@ -283,40 +283,6 @@ void sc_free(struct stream_cipher *sc)
  */
 #define RC4_ALIGN 8
 
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t len)
-{
-       int ret;
-       unsigned char *tmp;
-       static unsigned char remainder[RC4_ALIGN];
-       size_t l1 = ROUND_DOWN(len, RC4_ALIGN), l2 = ROUND_UP(len, RC4_ALIGN);
-
-       assert(len);
-       tmp = para_malloc(l2);
-       RC4(&scc->send->key, l1, (const unsigned char *)buf, tmp);
-       if (len > l1) {
-               memcpy(remainder, buf + l1, len - l1);
-               RC4(&scc->send->key, len - l1, remainder, tmp + l1);
-       }
-       ret = xwrite(scc->fd, (char *)tmp, len);
-       free(tmp);
-       return ret;
-}
-
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t size)
-{
-       unsigned char *tmp = para_malloc(ROUND_UP(size, RC4_ALIGN));
-       ssize_t ret = recv(scc->fd, tmp, size, 0);
-
-       if (ret > 0)
-               RC4(&scc->recv->key, ret, tmp, (unsigned char *)buf);
-       else if (ret < 0)
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-       free(tmp);
-       return ret;
-}
-
 void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 {
        size_t len = src->iov_len, l1, l2;
diff --git a/crypt.h b/crypt.h
index 77806af6983895c13f3120f4f65c1c1d46b9b11d..1406197d0c6cd64c14cf1b30d8ef281417903638 100644 (file)
--- a/crypt.h
+++ b/crypt.h
@@ -165,75 +165,9 @@ _static_inline_ void sc_trafo(struct iovec *src, struct iovec *dst,
  */
 void sc_free(struct stream_cipher *sc);
 
-/**
- * Encrypt and send a buffer.
- *
- * \param scc The context.
- * \param buf The buffer to send.
- * \param len The size of \a buf in bytes.
- *
- * \return The return value of the underyling call to write_all().
- *
- * \sa \ref write_all(), RC4(3).
- */
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t len);
-
-/**
- * Encrypt and send a \p NULL-terminated buffer.
- *
- * \param scc The context.
- * \param buf The buffer to send.
- *
- * \return The return value of the underyling call to sc_send_bin_buffer().
- */
-int sc_send_buffer(struct stream_cipher_context *scc, char *buf);
-
-/**
- * Format, encrypt and send a buffer.
- *
- * \param scc The context.
- * \param fmt A format string.
- *
- * \return The return value of the underyling call to sc_send_buffer().
- */
-__printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
-               const char *fmt, ...);
-
-/**
- * Receive a buffer and decrypt it.
- *
- * \param scc The context.
- * \param buf The buffer to write the decrypted data to.
- * \param size The size of \a buf.
- *
- * \return The number of bytes received on success, negative on errors, zero if
- * the peer has performed an orderly shutdown.
- *
- * \sa recv(2), RC4(3).
- */
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t size);
-
-/**
- * Receive a buffer, decrypt it and write terminating NULL byte.
- *
- * \param scc The context.
- * \param buf The buffer to write the decrypted data to.
- * \param size The size of \a buf.
- *
- * Read at most \a size - 1 bytes from file descriptor given by \a scc, decrypt
- * the received data and write a NULL byte at the end of the decrypted data.
- *
- * \return The return value of the underlying call to \ref
- * sc_recv_bin_buffer().
- */
-int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size);
-
 /** Size of the hash value in bytes. */
 #define HASH_SIZE 20
 
-
 /**
  * Compute the hash of the given input data.
  *
index cd9500ab39f3a89cd4ee70da64d0d7e72ff7c84f..6c71d7e3716829d90485894bc261ee867589d7bf 100644 (file)
@@ -321,41 +321,3 @@ int hash_compare(unsigned char *h1, unsigned char *h2)
        }
        return 0;
 }
-
-int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size)
-{
-       int n;
-
-       assert(size);
-       n = sc_recv_bin_buffer(scc, buf, size - 1);
-       if (n >= 0)
-               buf[n] = '\0';
-       else
-               *buf = '\0';
-       return n;
-}
-
-int sc_send_buffer(struct stream_cipher_context *scc, char *buf)
-{
-       size_t len = strlen(buf);
-       int ret = sc_send_bin_buffer(scc, buf, len);
-
-       if (ret < 0 || ret == len)
-               return ret;
-       return -E_SHORT_WRITE;
-}
-
-__printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
-               const char *fmt, ...)
-{
-       char *msg;
-       int ret;
-       va_list ap;
-
-       va_start(ap, fmt);
-       ret = xvasprintf(&msg, fmt, ap);
-       va_end(ap);
-       ret = sc_send_bin_buffer(scc, msg, ret);
-       free(msg);
-       return ret;
-}
diff --git a/error.h b/error.h
index ef54ef27707e262a09c7b638c8264cec549b2c1e..51ace98315ed6140ec8bbde35c1c36d5649c3d46 100644 (file)
--- a/error.h
+++ b/error.h
@@ -301,6 +301,7 @@ extern const char **para_errlist[];
        PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
        PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \
        PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \
+       PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \
 
 
 #define NET_ERRORS \
@@ -464,7 +465,7 @@ extern const char **para_errlist[];
        PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
        PARA_ERROR(SERVER_CRASH, "para_server crashed -- can not live without it"), \
        PARA_ERROR(BAD_USER, "auth request for invalid user"), \
-       PARA_ERROR(BAD_FEATURE, "request for unknown or invalid feature"), \
+       PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
        PARA_ERROR(BAD_AUTH, "authentication failure"), \
 
 
index b4718ec0f8c7910dbdbb3c451adeaa790e24e0d2..2736a6c769835823b39820b0291069f1ca80a534 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -937,39 +937,6 @@ void sc_free(struct stream_cipher *sc)
        free(sc);
 }
 
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t size)
-{
-       gcry_error_t gret;
-       int ret;
-       unsigned char *tmp = para_malloc(size);
-
-       assert(size);
-       gret = gcry_cipher_encrypt(scc->send->handle, tmp, size,
-               (unsigned char *)buf, size);
-       assert(gret == 0);
-       ret = xwrite(scc->fd, (char *)tmp, size);
-       free(tmp);
-       return ret;
-}
-
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
-               size_t size)
-{
-       gcry_error_t gret;
-       ssize_t ret = recv(scc->fd, buf, size, 0);
-
-       if (ret < 0)
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-       if (ret <= 0)
-               return ret;
-       /* perform in-place encryption */
-       gret = gcry_cipher_encrypt(scc->recv->handle, (unsigned char *)buf, ret,
-               NULL, 0);
-       assert(gret == 0);
-       return ret;
-}
-
 void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 {
        gcry_cipher_hd_t handle = sc->handle;
diff --git a/para.h b/para.h
index 4de4af4a23dd0f0a6e225279f9e72423a027adc4..6655d35672f410ebff1a5678841e9fee967c7996 100644 (file)
--- a/para.h
+++ b/para.h
@@ -82,14 +82,6 @@ extern __printf_2_3 void (*para_log)(int, const char*, ...);
 
 /** Sent by para_client to initiate the authentication procedure. */
 #define AUTH_REQUEST_MSG "auth rsa "
-/** Sent by para_server for commands that expect a data file. */
-#define AWAITING_DATA_MSG "\nAwaiting Data."
-/** Sent by para_server if authentication was successful. */
-#define PROCEED_MSG "Proceed."
-/** Length of the \p PROCEED_MSG string. */
-#define PROCEED_MSG_LEN strlen(PROCEED_MSG)
-/** Sent by para_client to indicate the end of the command line. */
-#define EOC_MSG "\nEnd of Command."
 
 /* exec */
 int para_exec_cmdline_pid(pid_t *pid, const char *cmdline, int *fds);
index 50daaa608f9b7cb507f07ea394cc522d4ed7a6f6..20e195b364b3d8bffcce3df4cd2c48f9e6afe4a8 100644 (file)
@@ -58,6 +58,8 @@
        DESIGNATOR(EXIT__SUCCESS), \
        /* Command failed. */ \
        DESIGNATOR(EXIT__FAILURE), \
+       /* The next chunk of the blob (addblob commands only) */ \
+       DESIGNATOR(BLOB_DATA), \
 
 /** Just prefix with \p SBD_. */
 #define DESIGNATOR(x) SBD_ ## x