---------------------------------------------
-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"
--------------------------------------
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)
}
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;
}
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. */
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;
}
/*
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;
}
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. */
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;
}
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;
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;
}
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;
}
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) {
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;
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));
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);
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 */
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;
}
#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"
+ }
};
/**
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) {
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. */
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). */
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;
};
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]);
}
/**
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);
}
{
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;
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;
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;
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;
}
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:
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;
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);
}
/**
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];
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)
{
/* 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);
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;
}
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;
*/
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));
}
/**
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) {
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 */
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 \
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
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++) {
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 */
);
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 */
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);
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)
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:
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();
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);
}
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)
/* 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);
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));
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));
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;
};
/**
*/
#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;
*/
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.
*
}
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;
-}
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 \
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"), \
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;
/** 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);
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