X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=command.c;h=8fdb839a97be1e6c459f5911621fffa88d61410b;hp=17132e872fb265096fec0d57b9428e1bd78e387a;hb=05029e5af523f92849b4f691a15a963cb6a10e1f;hpb=337d7784b0f8bc30b1fa9af56ace503acd97d40d diff --git a/command.c b/command.c index 17132e87..8fdb839a 100644 --- a/command.c +++ b/command.c @@ -6,6 +6,7 @@ /** \file command.c Client authentication and server commands. */ +#include #include #include #include @@ -15,6 +16,8 @@ #include "para.h" #include "error.h" +#include "crypt.h" +#include "command.h" #include "server.cmdline.h" #include "string.h" #include "afh.h" @@ -37,13 +40,12 @@ /** Commands including options must be shorter than this. */ #define MAX_COMMAND_LEN 32768 -static RC4_KEY rc4_recv_key; -static RC4_KEY rc4_send_key; -static unsigned char rc4_buf[2 * RC4_KEY_LEN]; - extern int mmd_mutex; extern struct misc_meta_data *mmd; extern struct sender senders[]; +int send_afs_status(struct rc4_context *rc4c, int parser_friendly); + +const char *status_item_list[] = {STATUS_ITEM_ARRAY}; static void dummy(__a_unused int s) { @@ -171,17 +173,9 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman break; case SENDER_DENY: case SENDER_ALLOW: - if (argc != 4 && argc != 5) - return -E_COMMAND_SYNTAX; - if (!is_valid_ipv4_address(argv[3])) + if (argc != 4 || parse_cidr(argv[3], scd->host, + sizeof(scd->host), &scd->netmask) == NULL) return -E_COMMAND_SYNTAX; - scd->netmask = 32; - if (argc == 5) { - scd->netmask = atoi(argv[4]); - if (scd->netmask < 0 || scd->netmask > 32) - return -E_COMMAND_SYNTAX; - } - strncpy(scd->host, argv[3], sizeof(scd->host)); break; case SENDER_ADD: case SENDER_DELETE: @@ -194,7 +188,7 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman return 1; } -int com_sender(int fd, int argc, char * const * argv) +int com_sender(struct rc4_context *rc4c, int argc, char * const * argv) { int i, ret; struct sender_command_data scd; @@ -207,7 +201,7 @@ int com_sender(int fd, int argc, char * const * argv) free(msg); msg = tmp; } - ret = send_buffer(fd, msg); + ret = rc4_send_buffer(rc4c, msg); free(msg); return ret; } @@ -217,7 +211,7 @@ int com_sender(int fd, int argc, char * const * argv) if (scd.sender_num < 0) return ret; msg = senders[scd.sender_num].help(); - ret = send_buffer(fd, msg); + ret = rc4_send_buffer(rc4c, msg); free(msg); return ret; } @@ -236,7 +230,7 @@ int com_sender(int fd, int argc, char * const * argv) } /* server info */ -int com_si(int fd, int argc, __a_unused char * const * argv) +int com_si(struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { int i, ret; char *ut; @@ -253,7 +247,7 @@ int com_si(int fd, int argc, __a_unused char * const * argv) sender_list = para_strcat(sender_list, " "); } ut = uptime_str(); - ret = send_va_buffer(fd, "up: %s\nplayed: %u\n" + ret = rc4_send_va_buffer(rc4c, "up: %s\nplayed: %u\n" "server_pid: %d\n" "afs_pid: %d\n" "connections (active/accepted/total): %u/%u/%u\n" @@ -280,11 +274,11 @@ int com_si(int fd, int argc, __a_unused char * const * argv) } /* version */ -int com_version(int fd, int argc, __a_unused char * const * argv) +int com_version(struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; - return send_buffer(fd, VERSION_TEXT("server") + return rc4_send_buffer(rc4c, VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS ", " CC_VERSION "\n" ); @@ -346,7 +340,7 @@ static char *empty_status_items(int parser_friendly) #undef EMPTY_STATUS_ITEMS /* stat */ -int com_stat(int fd, int argc, char * const * argv) +int com_stat(struct rc4_context *rc4c, int argc, char * const * argv) { int i, ret; struct misc_meta_data tmp, *nmmd = &tmp; @@ -374,13 +368,14 @@ int com_stat(int fd, int argc, char * const * argv) parser_friendly = 1; continue; } + return -E_COMMAND_SYNTAX; } if (i != argc) return -E_COMMAND_SYNTAX; for (;;) { mmd_dup(nmmd); s = get_status(nmmd, parser_friendly); - ret = send_buffer(fd, s); + ret = rc4_send_buffer(rc4c, s); free(s); if (ret < 0) goto out; @@ -388,11 +383,11 @@ int com_stat(int fd, int argc, char * const * argv) static char *esi; if (!esi) esi = empty_status_items(parser_friendly); - ret = send_buffer(fd, esi); + ret = rc4_send_buffer(rc4c, esi); if (ret < 0) goto out; } else - send_afs_status(fd, parser_friendly); + send_afs_status(rc4c, parser_friendly); ret = 1; if (num > 0 && !--num) goto out; @@ -404,14 +399,14 @@ out: return ret; } -static int send_list_of_commands(int fd, struct server_command *cmd, +static int send_list_of_commands(struct rc4_context *rc4c, struct server_command *cmd, const char *handler) { int ret, i; for (i = 1; cmd->name; cmd++, i++) { char *perms = cmd_perms_itohuman(cmd->perms); - ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name, + ret = rc4_send_va_buffer(rc4c, "%s\t%s\t%s\t%s\n", cmd->name, handler, perms, cmd->description); @@ -444,7 +439,7 @@ static struct server_command *get_cmd_ptr(const char *name, char **handler) } /* help */ -int com_help(int fd, int argc, char * const * argv) +int com_help(struct rc4_context *rc4c, int argc, char * const * argv) { struct server_command *cmd; char *perms, *handler; @@ -452,9 +447,9 @@ int com_help(int fd, int argc, char * const * argv) if (argc < 2) { /* no argument given, print list of commands */ - if ((ret = send_list_of_commands(fd, server_cmds, "server")) < 0) + if ((ret = send_list_of_commands(rc4c, server_cmds, "server")) < 0) return ret; - return send_list_of_commands(fd, afs_cmds, "afs"); + return send_list_of_commands(rc4c, afs_cmds, "afs"); } /* argument given for help */ cmd = get_cmd_ptr(argv[1], &handler); @@ -463,7 +458,7 @@ int com_help(int fd, int argc, char * const * argv) return -E_BAD_CMD; } perms = cmd_perms_itohuman(cmd->perms); - ret = send_va_buffer(fd, + ret = rc4_send_va_buffer(rc4c, "%s - %s\n\n" "handler: %s\n" "permissions: %s\n" @@ -482,7 +477,7 @@ int com_help(int fd, int argc, char * const * argv) } /* hup */ -int com_hup(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_hup(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -491,7 +486,7 @@ int com_hup(__a_unused int fd, int argc, __a_unused char * const * argv) } /* term */ -int com_term(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_term(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -499,7 +494,7 @@ int com_term(__a_unused int fd, int argc, __a_unused char * const * argv) return 1; } -int com_play(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_play(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -512,7 +507,7 @@ int com_play(__a_unused int fd, int argc, __a_unused char * const * argv) } /* stop */ -int com_stop(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_stop(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -525,7 +520,7 @@ int com_stop(__a_unused int fd, int argc, __a_unused char * const * argv) } /* pause */ -int com_pause(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_pause(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -540,7 +535,7 @@ int com_pause(__a_unused int fd, int argc, __a_unused char * const * argv) } /* next */ -int com_next(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_next(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -552,7 +547,7 @@ int com_next(__a_unused int fd, int argc, __a_unused char * const * argv) } /* nomore */ -int com_nomore(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_nomore(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -564,7 +559,7 @@ int com_nomore(__a_unused int fd, int argc, __a_unused char * const * argv) } /* ff */ -int com_ff(__a_unused int fd, int argc, char * const * argv) +int com_ff(__a_unused struct rc4_context *rc4c, int argc, char * const * argv) { long promille; int ret, backwards = 0; @@ -603,7 +598,7 @@ out: } /* jmp */ -int com_jmp(__a_unused int fd, int argc, char * const * argv) +int com_jmp(__a_unused struct rc4_context *rc4c, int argc, char * const * argv) { long unsigned int i; int ret; @@ -657,32 +652,7 @@ static struct server_command *parse_cmd(const char *cmdstr) return get_cmd_ptr(buf, NULL); } -static void init_rc4_keys(void) -{ - int i; - - for (i = 0; i < 2 * RC4_KEY_LEN; i++) - rc4_buf[i] = para_random(256); - PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n", - (unsigned char) rc4_buf[0], - (unsigned char) rc4_buf[RC4_KEY_LEN]); - RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf); - RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN); -} - -static void rc4_recv(unsigned long len, const unsigned char *indata, - unsigned char *outdata, __a_unused void *private_data) -{ - RC4(&rc4_recv_key, len, indata, outdata); -} - -static void rc4_send(unsigned long len, const unsigned char *indata, - unsigned char *outdata, __a_unused void *private_data) -{ - RC4(&rc4_send_key, len, indata, outdata); -} - -static int read_command(int fd, char **result) +static int read_command(struct rc4_context *rc4c, char **result) { int ret; char buf[4096]; @@ -692,7 +662,7 @@ static int read_command(int fd, char **result) size_t numbytes; char *p; - ret = recv_buffer(fd, buf, sizeof(buf)); + ret = rc4_recv_buffer(rc4c, buf, sizeof(buf)); if (ret < 0) goto out; if (!ret) @@ -755,22 +725,22 @@ static void reset_signals(void) */ __noreturn void handle_connect(int fd, const char *peername) { - int ret, argc, use_rc4 = 0; + int ret, argc; char buf[4096]; - unsigned char crypt_buf[MAXLINE]; + unsigned char rand_buf[CHALLENGE_SIZE + 2 * RC4_KEY_LEN]; + unsigned char challenge_sha1[HASH_SIZE]; struct user *u; struct server_command *cmd = NULL; - long unsigned challenge_nr, chall_response; char **argv = NULL; char *p, *command = NULL; size_t numbytes; + struct rc4_context rc4c = {.fd = fd}; reset_signals(); /* we need a blocking fd here as recv() might return EAGAIN otherwise. */ ret = mark_fd_blocking(fd); if (ret < 0) goto err_out; - challenge_nr = random(); /* send Welcome message */ ret = send_va_buffer(fd, "This is para_server, version " PACKAGE_VERSION ".\n" ); @@ -780,65 +750,69 @@ __noreturn void handle_connect(int fd, const char *peername) ret = recv_buffer(fd, buf, sizeof(buf)); if (ret < 0) goto err_out; - if (ret <= 6) { - ret = -E_AUTH; + if (ret < 10) { + ret = -E_AUTH_REQUEST; goto err_out; } numbytes = ret; - ret = -E_AUTH; - if (strncmp(buf, "auth ", 5)) + ret = -E_AUTH_REQUEST; + if (strncmp(buf, AUTH_REQUEST_MSG, strlen(AUTH_REQUEST_MSG))) goto err_out; - - if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9)) - p = buf + 5; /* client version < 0.2.6 */ - else { - p = buf + 9; /* client version >= 0.2.6 */ - use_rc4 = 1; - } - PARA_DEBUG_LOG("received %s request for user %s\n", - use_rc4? "rc4" : "auth", p); + p = buf + strlen(AUTH_REQUEST_MSG); + PARA_DEBUG_LOG("received auth request for user %s\n", p); ret = -E_BAD_USER; u = lookup_user(p); - if (!u) - goto err_out; - ret = para_encrypt_challenge(u->rsa, challenge_nr, crypt_buf); - if (ret <= 0) - goto err_out; - numbytes = ret; - PARA_DEBUG_LOG("sending %zu byte challenge\n", numbytes); - /* We can't use send_buffer here since buf may contain null bytes */ - ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes); + if (u) { + get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); + ret = para_encrypt_buffer(u->rsa, rand_buf, sizeof(rand_buf), + (unsigned char *)buf); + if (ret < 0) + goto err_out; + numbytes = ret; + } else { + /* + * We don't want to reveal our user names, so we send a + * challenge to the client even if the user does not exist, and + * fail the authentication later. + */ + numbytes = 256; + get_random_bytes_or_die((unsigned char *)buf, numbytes); + } + PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n", + CHALLENGE_SIZE, numbytes); + ret = send_bin_buffer(fd, buf, numbytes); if (ret < 0) goto net_err; - /* recv decrypted number */ - ret = recv_buffer(fd, buf, sizeof(buf)); + /* recv challenge response */ + ret = recv_bin_buffer(fd, buf, HASH_SIZE); if (ret < 0) goto net_err; numbytes = ret; - ret = -E_AUTH; - if (!numbytes) + PARA_DEBUG_LOG("received %d bytes challenge response\n", ret); + ret = -E_BAD_USER; + if (!u) goto net_err; - if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1 - || chall_response != challenge_nr) - goto err_out; - /* auth successful, send 'Proceed' message */ - PARA_INFO_LOG("good auth for %s (%lu)\n", u->name, challenge_nr); - sprintf(buf, "%s", PROCEED_MSG); - if (use_rc4) { - init_rc4_keys(); - ret = para_encrypt_buffer(u->rsa, rc4_buf, 2 * RC4_KEY_LEN, - (unsigned char *)buf + PROCEED_MSG_LEN + 1); - if (ret <= 0) - goto err_out; - numbytes = ret + strlen(PROCEED_MSG) + 1; - } else - numbytes = strlen(buf); - ret = send_bin_buffer(fd, buf, numbytes); + /* + * The correct response is the sha1 of the first CHALLENGE_SIZE bytes + * of the random data. + */ + ret = -E_BAD_AUTH; + if (numbytes != HASH_SIZE) + goto net_err; + sha1_hash((char *)rand_buf, CHALLENGE_SIZE, challenge_sha1); + if (memcmp(challenge_sha1, buf, HASH_SIZE)) + goto net_err; + /* auth successful */ + alarm(0); + PARA_INFO_LOG("good auth for %s\n", u->name); + /* init rc4 keys with the second part of the random buffer */ + RC4_set_key(&rc4c.recv_key, RC4_KEY_LEN, rand_buf + CHALLENGE_SIZE); + RC4_set_key(&rc4c.send_key, RC4_KEY_LEN, rand_buf + CHALLENGE_SIZE + + RC4_KEY_LEN); + ret = rc4_send_buffer(&rc4c, PROCEED_MSG); if (ret < 0) goto net_err; - if (use_rc4) - enable_crypt(fd, rc4_recv, rc4_send, NULL); - ret = read_command(fd, &command); + ret = read_command(&rc4c, &command); if (ret == -E_COMMAND_SYNTAX) goto err_out; if (ret < 0) @@ -852,23 +826,25 @@ __noreturn void handle_connect(int fd, const char *peername) if (ret < 0) goto err_out; /* valid command and sufficient perms */ - alarm(0); - argc = split_args(command, &argv, "\n"); + ret = create_argv(command, "\n", &argv); + if (ret < 0) + goto err_out; + argc = ret; PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name, peername); - ret = cmd->handler(fd, argc, argv); + ret = cmd->handler(&rc4c, argc, argv); + free_argv(argv); mutex_lock(mmd_mutex); mmd->num_commands++; mutex_unlock(mmd_mutex); if (ret >= 0) goto out; err_out: - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(&rc4c, "%s\n", para_strerror(-ret)); net_err: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); out: free(command); - free(argv); mutex_lock(mmd_mutex); if (cmd && (cmd->perms & AFS_WRITE) && ret >= 0) mmd->events++;