Use sideband also for challenge response.
authorAndre Noll <maan@systemlinux.org>
Wed, 4 Jan 2012 20:47:55 +0000 (21:47 +0100)
committerAndre Noll <maan@systemlinux.org>
Sat, 5 May 2012 10:54:53 +0000 (12:54 +0200)
This changes server and client to exchange the challenge response
as a sideband packet if both ends support sideband connections. The
SBD_CHALLENGE_RESPONSE designator is used for this purpose. On the
client side the changes are less intrusive due to an additional
cleanup of the state handling.

During connection setup the client's idea of the state of
the connection is monitored in the ->status variable of struct
client_task. If the client is in the CL_SENT_AUTH state, it receives
the challenge and sends the hash of the decrypted challenge back to the
server. Either operation may fail, and it seems cleaner to separate
the two. So this patch adds the new state CL_RECEIVED_CHALLENGE. The
clients enters this state once it decrypted the received challenge.

client.h
client_common.c
command.c

index a423406..b841b7e 100644 (file)
--- a/client.h
+++ b/client.h
@@ -14,6 +14,8 @@ enum {
        CL_RECEIVED_WELCOME,
        /** Client sends the authentification request. */
        CL_SENT_AUTH,
+       /** Server sends encrypted challenge. */
+       CL_RECEIVED_CHALLENGE,
        /** Client solves the challenge and sends the result. */
        CL_SENT_CH_RESPONSE,
        /** Server accepts this authentication. */
@@ -36,6 +38,8 @@ struct client_task {
        bool use_sideband;
        /** The sideband context, ignored if \a use_sideband is false. */
        struct sb_context *sbc;
+       /** The hash value of the decrypted challenge. */
+       unsigned char *challenge_hash;
        /** The configuration (including the command). */
        struct client_args_info conf;
        /** The config file for client options. */
index f3cea05..eea14fa 100644 (file)
@@ -68,6 +68,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);
 }
 
@@ -103,6 +105,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;
 
@@ -297,7 +300,6 @@ 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];
 
                if (ct->use_sideband) {
                        struct sb_buffer sbb;
@@ -326,18 +328,31 @@ static void client_post_select(struct sched *s, struct task *t)
                        if (ret < 0)
                                goto out;
                }
-               hash_function((char *)crypt_buf, CHALLENGE_SIZE, challenge_hash);
+               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 */
                {
                ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
index 5790f11..5e13df6 100644 (file)
--- a/command.c
+++ b/command.c
@@ -934,22 +934,28 @@ __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;
-               buf = para_malloc(HANDSHAKE_BUFSIZE);
+               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;
        }
-       /* recv challenge response */
-       ret = recv_bin_buffer(fd, buf, HASH_SIZE);
-       if (ret < 0)
-               goto net_err;
-       numbytes = ret;
-       PARA_DEBUG_LOG("received %d bytes challenge response\n", ret);
+       PARA_DEBUG_LOG("received %zu bytes challenge response\n", numbytes);
        ret = -E_BAD_USER;
        if (!cc->u)
                goto net_err;