Merge branch 'master' into next
[paraslash.git] / client_common.c
index b1eaa78b2db7563b699c6993509e738b12f665a8..b6bfde9a37f81143f9b2dec7e357907aa705c15f 100644 (file)
@@ -6,6 +6,7 @@
 
 /** \file client_common.c Common functions of para_client and para_audiod. */
 
+#include <regex.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <openssl/rc4.h>
@@ -22,6 +23,7 @@
 #include "string.h"
 #include "client.cmdline.h"
 #include "client.h"
+#include "hash.h"
 
 /**
  * Close the connection to para_server and free all resources.
@@ -110,7 +112,7 @@ static ssize_t client_recv_buffer(struct client_task *ct)
 {
        ssize_t ret;
 
-       if (ct->status < CL_RECEIVED_PROCEED)
+       if (ct->status < CL_SENT_CH_RESPONSE)
                ret = recv_buffer(ct->rc4c.fd, ct->buf + ct->loaded,
                        CLIENT_BUFSIZE - ct->loaded);
        else
@@ -121,7 +123,6 @@ static ssize_t client_recv_buffer(struct client_task *ct)
        if (ret > 0)
                ct->loaded += ret;
        return ret;
-
 }
 
 /**
@@ -153,66 +154,68 @@ static void client_post_select(struct sched *s, struct task *t)
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
                t->error = client_recv_buffer(ct);
-               if (t->error > 0)
-                       ct->status = CL_RECEIVED_WELCOME;
+               if (t->error < 0)
+                       goto err;
+               ct->status = CL_RECEIVED_WELCOME;
                return;
        case CL_RECEIVED_WELCOME: /* send auth command */
-               sprintf(ct->buf, "auth rc4 %s", ct->user);
+               sprintf(ct->buf, AUTH_REQUEST_MSG "%s", ct->user);
                PARA_INFO_LOG("--> %s\n", ct->buf);
                t->error = send_buffer(ct->rc4c.fd, ct->buf);
-               if (t->error >= 0)
-                       ct->status = CL_SENT_AUTH;
+               if (t->error < 0)
+                       goto err;
+               ct->status = CL_SENT_AUTH;
                return;
-       case CL_SENT_AUTH: /* receive challenge number */
+       case CL_SENT_AUTH: /* receive challenge and rc4 keys */
                ct->loaded = 0;
                t->error = client_recv_buffer(ct);
                if (t->error < 0)
-                       return;
-               if (t->error != 64) {
-                       t->error = -E_INVALID_CHALLENGE;
-                       PARA_ERROR_LOG("received the following: %s\n", ct->buf);
-                       return;
-               }
-               PARA_INFO_LOG("<-- [challenge]\n");
-               /* decrypt challenge number */
-               t->error = para_decrypt_challenge(ct->key_file, &ct->challenge_nr,
-                       (unsigned char *) ct->buf, 64);
-               if (t->error > 0)
-                       ct->status = CL_RECEIVED_CHALLENGE;
+                       goto err;
+               ct->loaded = t->error;
+               PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", ct->loaded);
+               ct->status = CL_RECEIVED_CHALLENGE;
                return;
-       case CL_RECEIVED_CHALLENGE: /* send decrypted challenge */
-               PARA_INFO_LOG("--> %lu\n", ct->challenge_nr);
-               t->error = send_va_buffer(ct->rc4c.fd, "%s%lu", CHALLENGE_RESPONSE_MSG,
-                       ct->challenge_nr);
-               if (t->error > 0)
-                       ct->status = CL_SENT_CH_RESPONSE;
+       case CL_RECEIVED_CHALLENGE:
+               {
+               /* decrypted challenge/rc4 buffer */
+               unsigned char crypt_buf[1024];
+               /* the SHA1 of the decrypted challenge */
+               unsigned char challenge_sha1[HASH_SIZE];
+
+               t->error = para_decrypt_buffer(ct->key_file, crypt_buf,
+                       (unsigned char *)ct->buf, ct->loaded);
+               if (t->error < 0)
+                       goto err;
+               sha1_hash((char *)crypt_buf, CHALLENGE_SIZE, challenge_sha1);
+               RC4_set_key(&ct->rc4c.send_key, RC4_KEY_LEN,
+                       crypt_buf + CHALLENGE_SIZE);
+               RC4_set_key(&ct->rc4c.recv_key, RC4_KEY_LEN,
+                       crypt_buf + CHALLENGE_SIZE + RC4_KEY_LEN);
+               hash_to_asc(challenge_sha1, ct->buf);
+               PARA_INFO_LOG("--> %s\n", ct->buf);
+               t->error = send_bin_buffer(ct->rc4c.fd, (char *)challenge_sha1,
+                       HASH_SIZE);
+               if (t->error < 0)
+                       goto err;
+               ct->status = CL_SENT_CH_RESPONSE;
                return;
+               }
        case CL_SENT_CH_RESPONSE: /* read server response */
                {
                size_t bytes_received;
-               unsigned char rc4_buf[2 * RC4_KEY_LEN] = "";
                ct->loaded = 0;
                t->error = client_recv_buffer(ct);
                if (t->error < 0)
-                       return;
+                       goto err;
                bytes_received = t->error;
-               PARA_DEBUG_LOG("++++ server info ++++\n%s\n++++ end of server "
-                       "info ++++\n", ct->buf);
-               /* check if server has sent "Proceed" message and the rc4 keys */
+               /* check if server has sent "Proceed" message */
                t->error = -E_CLIENT_AUTH;
-               if (bytes_received < PROCEED_MSG_LEN + 2 * RC4_KEY_LEN)
-                       return;
+               if (bytes_received < PROCEED_MSG_LEN)
+                       goto err;
                if (!strstr(ct->buf, PROCEED_MSG))
-                       return;
-               PARA_INFO_LOG("decrypting session key\n");
-               t->error = para_decrypt_buffer(ct->key_file, rc4_buf,
-                       (unsigned char *)ct->buf + PROCEED_MSG_LEN + 1,
-                       bytes_received - PROCEED_MSG_LEN - 1);
-               if (t->error < 0)
-                       return;
-               RC4_set_key(&ct->rc4c.send_key, RC4_KEY_LEN, rc4_buf);
-               RC4_set_key(&ct->rc4c.recv_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
+                       goto err;
                ct->status = CL_RECEIVED_PROCEED;
+               t->error = 0;
                return;
                }
        case CL_RECEIVED_PROCEED: /* concat args and send command */
@@ -229,31 +232,38 @@ static void client_post_select(struct sched *s, struct task *t)
                PARA_DEBUG_LOG("--> %s\n", command);
                t->error = rc4_send_buffer(&ct->rc4c, command);
                free(command);
-               if (t->error > 0)
-                       ct->status = CL_SENT_COMMAND;
+               if (t->error < 0)
+                       goto err;
+               ct->status = CL_SENT_COMMAND;
                return;
                }
        case CL_SENT_COMMAND:
                ct->loaded = 0;
                t->error = client_recv_buffer(ct);
                if (t->error < 0)
-                       return;
+                       goto err;
                if (strstr(ct->buf, AWAITING_DATA_MSG))
                        ct->status = CL_SENDING;
                else
                        ct->status = CL_RECEIVING;
                return;
-       case CL_SENDING: /* FIXME: might block */
+       case CL_SENDING:
                PARA_INFO_LOG("loaded: %zd\n", *ct->in_loaded);
-               t->error = rc4_send_bin_buffer(&ct->rc4c, ct->inbuf, *ct->in_loaded);
+               t->error = rc4_send_bin_buffer(&ct->rc4c, ct->inbuf,
+                       *ct->in_loaded);
                if (t->error < 0)
-                       return;
+                       goto err;
                *ct->in_loaded = 0;
                return;
        case CL_RECEIVING:
                t->error = client_recv_buffer(ct);
+               if (t->error < 0)
+                       goto err;
                return;
        }
+err:
+       if (t->error != -E_SERVER_EOF)
+               PARA_ERROR_LOG("%s\n", para_strerror(-t->error));
 }
 
 /* connect to para_server and register the client task */