X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=client_common.c;h=78b232dbd043caf1dc0ee6ba58b3437000e0d86a;hp=e34ed641401c7b91f612e8e5922c0fbd19baa0ac;hb=3f1510c31beb5c053d2f6c510f04a1e7466fce65;hpb=e151dbb79eac16326585ec0a33cf48029f5f22f4 diff --git a/client_common.c b/client_common.c index e34ed641..78b232db 100644 --- a/client_common.c +++ b/client_common.c @@ -17,6 +17,7 @@ #include "crypt.h" #include "net.h" #include "fd.h" +#include "sideband.h" #include "string.h" #include "client.cmdline.h" #include "client.h" @@ -47,8 +48,7 @@ void client_disconnect(struct client_task *ct) ct->scc.recv = NULL; sc_free(ct->scc.send); ct->scc.send = NULL; - btr_free_node(ct->btrn); - ct->btrn = NULL; + btr_remove_node(&ct->btrn); } /** @@ -67,6 +67,8 @@ void client_close(struct client_task *ct) free(ct->config_file); free(ct->key_file); client_cmdline_parser_free(&ct->conf); + free(ct->challenge_hash); + sb_free(ct->sbc); free(ct); } @@ -102,6 +104,7 @@ static void client_pre_select(struct sched *s, struct task *t) case CL_RECEIVED_WELCOME: case CL_RECEIVED_PROCEED: + case CL_RECEIVED_CHALLENGE: para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno); return; @@ -153,6 +156,69 @@ static int client_recv_buffer(struct client_task *ct, fd_set *rfds, return 0; } +static int send_sb(struct client_task *ct, 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) { + 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); + } + ret = sb_get_send_buffers(ct->sbc, iov); + ret = xwritev(fd, iov, ret); + if (ret < 0) { + sb_free(ct->sbc); + ct->sbc = NULL; + return ret; + } + if (sb_sent(ct->sbc, ret)) { + ct->sbc = NULL; + return 1; + } + return 0; +} + +static int recv_sb(struct client_task *ct, fd_set *rfds, + struct sb_buffer *result) +{ + int ret; + size_t n; + sb_transformation trafo; + void *trafo_context; + struct iovec iov; + + if (!FD_ISSET(ct->scc.fd, rfds)) + return 0; + if (ct->status < CL_SENT_CH_RESPONSE) + trafo = trafo_context = NULL; + else { + trafo = sc_trafo; + trafo_context = ct->scc.recv; + } + if (!ct->sbc) + ct->sbc = sb_new_recv(0, trafo, trafo_context); +again: + sb_get_recv_buffer(ct->sbc, &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; + return ret; + } + if (n == 0) + return 0; + if (!sb_received(ct->sbc, n, result)) + goto again; + ct->sbc = NULL; + return 1; +} + + static char **parse_features(char *buf) { int i; @@ -173,11 +239,79 @@ static char **parse_features(char *buf) return features; } +static int dispatch_sbb(struct client_task *ct, struct sb_buffer *sbb) +{ + int ret; + const char *designator[] = {SB_DESIGNATORS_ARRAY}; + + if (!sbb) + return 0; + if (sbb->band < NUM_SB_DESIGNATORS) + PARA_DEBUG_LOG("band: %s\n", designator[sbb->band]); + + switch (sbb->band) { + case SBD_OUTPUT: + if (iov_valid(&sbb->iov)) + btr_add_output(sbb->iov.iov_base, sbb->iov.iov_len, + ct->btrn); + ret = 1; + goto out; + case SBD_DEBUG_LOG: + case SBD_INFO_LOG: + case SBD_NOTICE_LOG: + case SBD_WARNING_LOG: + case SBD_ERROR_LOG: + case SBD_CRIT_LOG: + case SBD_EMERG_LOG: + if (iov_valid(&sbb->iov)) { + int ll = sbb->band - SBD_DEBUG_LOG; + para_log(ll, "remote: %s", (char *)sbb->iov.iov_base); + } + ret = 1; + goto deallocate; + case SBD_EXIT__SUCCESS: + ret = -E_SERVER_CMD_SUCCESS; + goto deallocate; + case SBD_EXIT__FAILURE: + ret = -E_SERVER_CMD_FAILURE; + goto deallocate; + default: + PARA_ERROR_LOG("invalid band %d\n", sbb->band); + ret = -E_BAD_BAND; + goto deallocate; + } +deallocate: + free(sbb->iov.iov_base); +out: + sbb->iov.iov_base = NULL; + return ret; +} + static bool has_feature(const char *feature, struct client_task *ct) { return find_arg(feature, ct->features) >= 0? true : false; } +static int send_sb_command(struct client_task *ct) +{ + int i; + char *command, *p; + size_t len = 0; + + if (ct->sbc) + return send_sb(ct, NULL, 0, 0, false); + + for (i = 0; i < ct->conf.inputs_num; i++) + len += strlen(ct->conf.inputs[i]) + 1; + p = command = para_malloc(len); + for (i = 0; i < ct->conf.inputs_num; i++) { + strcpy(p, ct->conf.inputs[i]); + p += strlen(ct->conf.inputs[i]) + 1; + } + PARA_DEBUG_LOG("--> %s\n", command); + return send_sb(ct, command, len, SBD_COMMAND, false); +} + /** * The post select hook for client commands. * @@ -199,7 +333,9 @@ static void client_post_select(struct sched *s, struct task *t) size_t n; char buf[CLIENT_BUFSIZE]; - t->error = 0; + ret = task_get_notification(t); + if (ret < 0) + goto out; if (ct->scc.fd < 0) return; switch (ct->status) { @@ -233,30 +369,73 @@ static void 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 */ - unsigned char challenge_hash[HASH_SIZE]; - 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; - hash_function((char *)crypt_buf, CHALLENGE_SIZE, challenge_hash); + 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); + 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; + } + 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); ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN); - hash_to_asc(challenge_hash, buf); + hash_to_asc(ct->challenge_hash, buf); PARA_INFO_LOG("--> %s\n", buf); - ret = write_all(ct->scc.fd, (char *)challenge_hash, HASH_SIZE); - if (ret < 0) - goto out; - ct->status = CL_SENT_CH_RESPONSE; + ct->status = CL_RECEIVED_CHALLENGE; return; } + 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; + } + 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; @@ -275,6 +454,13 @@ static void client_post_select(struct sched *s, struct task *t) char *command = NULL; if (!FD_ISSET(ct->scc.fd, &s->wfds)) return; + if (ct->use_sideband) { + ret = send_sb_command(ct); + if (ret <= 0) + goto out; + ct->status = CL_SENT_COMMAND; + return; + } for (i = 0; i < ct->conf.inputs_num; i++) { char *tmp = command; command = make_message("%s\n%s", command? @@ -293,6 +479,20 @@ static void client_post_select(struct sched *s, struct task *t) 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; + } + 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); @@ -340,6 +540,13 @@ static void client_post_select(struct sched *s, struct task *t) */ if (!FD_ISSET(ct->scc.fd, &s->rfds)) return; + 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; + } buf2 = para_malloc(CLIENT_BUFSIZE); ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n); if (n > 0) { @@ -353,9 +560,10 @@ static void client_post_select(struct sched *s, struct task *t) out: t->error = ret; if (ret < 0) { - if (ret != -E_SERVER_EOF && ret != -E_BTR_EOF) + if (!ct->use_sideband && ret != -E_SERVER_EOF && + ret != -E_BTR_EOF && ret != -E_EOF) PARA_ERROR_LOG("%s\n", para_strerror(-t->error)); - btr_remove_node(btrn); + btr_remove_node(&ct->btrn); } }