From: Andre Noll Date: Sun, 14 Jun 2009 20:50:11 +0000 (+0200) Subject: Make rc4 encryption/decryption more explicit. X-Git-Tag: v0.4.0~76^2~1 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=a9126f461792a84c760162ecb25100f1593d427d;p=paraslash.git Make rc4 encryption/decryption more explicit. The old code used a rather fancy way to (de)activate encryption on a per fd basis: In net.c there was an array of rc4 keys, indexed by fd. This is rather wastful because the array size is determined by the highest fd for which encryption is activated. It's also hard to comprehend and it's easy to get strange results if one forgets to deactivate the encryption after the fd is closed. This patch introduces a new structure, rc4_context, which consists of an fd and the needed rc4 keys. Users explicitly call the new rc4 variants of the receving/sending functions which take a pointer to a struct rc4_context instead of a file descriptor but are otherwise identical. Keep crypt simple! --- diff --git a/afs.c b/afs.c index 72e2490e..c89e3cec 100644 --- a/afs.c +++ b/afs.c @@ -8,9 +8,12 @@ #include #include +#include + #include "server.cmdline.h" #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@ -403,80 +406,6 @@ int string_compare(const struct osl_object *obj1, const struct osl_object *obj2) return strncmp(str1, str2, PARA_MIN(obj1->size, obj2->size)); } -/* - * write input from fd to dynamically allocated buffer, - * but maximal max_size byte. - */ -static int fd2buf(int fd, unsigned max_size, struct osl_object *obj) -{ - const size_t chunk_size = 1024; - size_t size = 2048, received = 0; - int ret; - char *buf = para_malloc(size); - - for (;;) { - ret = recv_bin_buffer(fd, 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 = buf; - obj->size = received; - if (ret < 0) - free(buf); - return ret; -} - -/** - * Read data from a file descriptor, and send it to the afs process. - * - * \param fd 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 from \a fd, 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. - * - * \return Negative on errors, the return value of the underlying call to - * send_callback_request() otherwise. - */ -int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f, - unsigned max_len, callback_result_handler *result_handler, - void *private_result_data) -{ - struct osl_object query, stdin_obj; - int ret; - - ret = send_buffer(fd, AWAITING_DATA_MSG); - if (ret < 0) - return ret; - ret = fd2buf(fd, max_len, &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); - free(stdin_obj.data); - ret = send_callback_request(f, &query, result_handler, private_result_data); - free(query.data); - return ret; -} - static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; @@ -652,21 +581,22 @@ out: * Result handler for sending data to the para_client process. * * \param result The data to be sent. - * \param fd_ptr Pointer to the file descriptor. + * \param private Pointer to rc4 context. * - * \return The return value of the underlying call to send_bin_buffer(). + * \return The return value of the underlying call to rc4_send_bin_buffer(). * - * \sa \ref callback_result_handler. + * \sa \ref callback_result_handler, \ref rc4_send_bin_buffer(). */ -int send_result(struct osl_object *result, void *fd_ptr) +int rc4_send_result(struct osl_object *result, void *private) { - int fd = *(int *)fd_ptr; + struct rc4_context *rc4c = private; + if (!result->size) return 1; - return send_bin_buffer(fd, result->data, result->size); + return rc4_send_bin_buffer(rc4c, result->data, result->size); } -int com_select(int fd, int argc, char * const * const argv) +int com_select(struct rc4_context *rc4c, int argc, char * const * const argv) { struct osl_object query; @@ -675,7 +605,7 @@ int com_select(int fd, int argc, char * const * const argv) query.data = argv[1]; query.size = strlen(argv[1]) + 1; return send_callback_request(com_select_callback, &query, - &send_result, &fd); + &rc4_send_result, rc4c); } static void init_admissible_files(char *arg) @@ -1096,7 +1026,7 @@ out: free(buf); } -int com_init(int fd, int argc, char * const * const argv) +int com_init(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; @@ -1121,9 +1051,10 @@ int com_init(int fd, int argc, char * const * const argv) return -E_BAD_TABLE_NAME; } } - ret = send_callback_request(create_tables_callback, &query, &send_result, &fd); + ret = send_callback_request(create_tables_callback, &query, + rc4_send_result, rc4c); if (ret < 0) - return send_va_buffer(fd, "%s\n", para_strerror(-ret)); + return rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -1141,7 +1072,7 @@ enum com_check_flags { CHECK_PLAYLISTS = 4 }; -int com_check(int fd, int argc, char * const * const argv) +int com_check(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@ -1173,17 +1104,20 @@ int com_check(int fd, int argc, char * const * const argv) if (!flags) flags = ~0U; if (flags & CHECK_AFT) { - ret = send_callback_request(aft_check_callback, NULL, send_result, &fd); + ret = send_callback_request(aft_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_PLAYLISTS) { - ret = send_callback_request(playlist_check_callback, NULL, send_result, &fd); + ret = send_callback_request(playlist_check_callback, + NULL, rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_MOODS) { - ret = send_callback_request(mood_check_callback, NULL, send_result, &fd); + ret = send_callback_request(mood_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } diff --git a/afs.cmd b/afs.cmd index 0af45113..31734046 100644 --- a/afs.cmd +++ b/afs.cmd @@ -3,7 +3,8 @@ SF: afs.c aft.c attribute.c HC: Prototypes for the commands of the audio file selector. CC: Array of commands for the audio file selector. AT: server_command -IN: para error string afh afs server list user_list +SI: openssl/rc4 +IN: para error crypt command string afh afs server list user_list SN: list of afs commands TM: mood lyr img pl --- @@ -94,7 +95,7 @@ H: -sa: sort by audio format. --- N: lsatt P: AFS_READ -D: List attributes +D: List attributes. U: lsatt [-i] [-l] [-r] [pattern] H: Print the list of all defined attributes which match the H: given pattern. If no pattern is given, the full list is @@ -257,7 +258,7 @@ H: loads the mood named 'foo'. --- T: add N: add@member@ -O: int com_add@member@(int fd, int argc, char * const * const argv); +O: int com_add@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Read data from stdin and add it as a blob to the @member@ table. U: add@member@ @member@_name @@ -270,7 +271,7 @@ H: given name already exists, its contents are replaced by the new data. --- T: cat N: cat@member@ -O: int com_cat@member@(int fd, int argc, char * const * const argv); +O: int com_cat@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ D: Dump the contents of a blob of type @member@ to stdout. U: cat@member@ @member@_name @@ -280,7 +281,7 @@ H: they were previously added. --- T: ls N: ls@member@ -O: int com_ls@member@(int fd, int argc, char * const * const argv); +O: int com_ls@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ D: List blobs of type @member@ matching a pattern. U: ls@member@ [-i] [-l] [-r] [pattern] @@ -300,7 +301,7 @@ H: -r Reverse sort order. --- T: rm N: rm@member@ -O: int com_rm@member@(int fd, int argc, char * const * const argv); +O: int com_rm@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Remove blob(s) of type @member@ from the @member@ table. U: rm@member@ pattern... @@ -309,7 +310,7 @@ H: any given pattern. --- T: mv N: mv@member@ -O: int com_mv@member@(int fd, int argc, char * const * const argv); +O: int com_mv@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Rename a blob of type @member@. U: mv@member@ old_@member@_name new_@member@_name diff --git a/afs.h b/afs.h index bcc36309..edeb348e 100644 --- a/afs.h +++ b/afs.h @@ -188,7 +188,7 @@ typedef void callback_function(int fd, const struct osl_object *); * \sa \ref send_callback_request(). */ typedef int callback_result_handler(struct osl_object *result, void *private); -int send_result(struct osl_object *result, void *fd_ptr); +int rc4_send_result(struct osl_object *result, void *private); int pass_buffer_as_shm(char *buf, size_t size, void *fd_ptr); __noreturn void afs_init(uint32_t cookie, int socket_fd); @@ -204,9 +204,6 @@ int send_option_arg_callback_request(struct osl_object *options, int send_standard_callback_request(int argc, char * const * const argv, callback_function *f, callback_result_handler *result_handler, void *private_result_data); -int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f, - unsigned max_len, callback_result_handler *result_handler, - void *private_result_data); int string_compare(const struct osl_object *obj1, const struct osl_object *obj2); int for_each_matching_row(struct pattern_match_data *pmd); diff --git a/aft.c b/aft.c index 20fa3a96..e5409244 100644 --- a/aft.c +++ b/aft.c @@ -7,8 +7,11 @@ /** \file aft.c Audio file table functions. */ #include /* readdir() */ +#include + #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include #include @@ -1409,7 +1412,7 @@ out: /* * TODO: flags -h (sort by hash) */ -int com_ls(int fd, int argc, char * const * const argv) +int com_ls(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, ret; unsigned flags = 0; @@ -1518,7 +1521,7 @@ int com_ls(int fd, int argc, char * const * const argv) opts.mode = mode; opts.num_patterns = argc - i; ret = send_option_arg_callback_request(&query, opts.num_patterns, - argv + i, com_ls_callback, send_result, &fd); + argv + i, com_ls_callback, rc4_send_result, rc4c); return ret; } @@ -1805,8 +1808,8 @@ out: /** Used by com_add(). */ struct private_add_data { - /** The socket file descriptor. */ - int fd; + /** The socket file descriptor, including rc4 keys. */ + struct rc4_context *rc4c; /** The given add flags. */ uint32_t flags; }; @@ -1861,7 +1864,8 @@ static int add_one_audio_file(const char *path, void *private_data) ret = 1; if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */ if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = send_va_buffer(pad->fd, "lazy-ignore: %s\n", path); + send_ret = rc4_send_va_buffer(pad->rc4c, + "lazy-ignore: %s\n", path); goto out_free; } /* We still want to add this file. Compute its hash. */ @@ -1881,7 +1885,7 @@ static int add_one_audio_file(const char *path, void *private_data) ret = 1; if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) { if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = send_va_buffer(pad->fd, + send_ret = rc4_send_va_buffer(pad->rc4c, "%s exists, not forcing update\n", path); goto out_unmap; } @@ -1899,13 +1903,13 @@ static int add_one_audio_file(const char *path, void *private_data) munmap(map.data, map.size); close(fd); if (pad->flags & ADD_FLAG_VERBOSE) { - send_ret = send_va_buffer(pad->fd, "adding %s\n", path); + send_ret = rc4_send_va_buffer(pad->rc4c, "adding %s\n", path); if (send_ret < 0) goto out_free; } save_add_callback_buffer(hash, path, afhi_ptr, pad->flags, format_num, &obj); /* Ask afs to consider this entry for adding. */ - ret = send_callback_request(com_add_callback, &obj, send_result, &pad->fd); + ret = send_callback_request(com_add_callback, &obj, rc4_send_result, pad->rc4c); goto out_free; out_unmap: @@ -1913,8 +1917,8 @@ out_unmap: munmap(map.data, map.size); out_free: if (ret < 0 && send_ret >= 0) - send_ret = send_va_buffer(pad->fd, "failed to add %s (%s)\n", path, - para_strerror(-ret)); + send_ret = rc4_send_va_buffer(pad->rc4c, + "failed to add %s (%s)\n", path, para_strerror(-ret)); free(obj.data); if (afhi_ptr) { free(afhi_ptr->chunk_table); @@ -1924,10 +1928,10 @@ out_free: return send_ret; } -int com_add(int fd, int argc, char * const * const argv) +int com_add(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, ret; - struct private_add_data pad = {.fd = fd, .flags = 0}; + struct private_add_data pad = {.rc4c = rc4c, .flags = 0}; struct stat statbuf; for (i = 1; i < argc; i++) { @@ -1961,7 +1965,7 @@ int com_add(int fd, int argc, char * const * const argv) char *path; ret = verify_path(argv[i], &path); if (ret < 0) { - ret = send_va_buffer(fd, "%s: %s\n", argv[i], + ret = rc4_send_va_buffer(rc4c, "%s: %s\n", argv[i], para_strerror(-ret)); if (ret < 0) return ret; @@ -1969,7 +1973,7 @@ int com_add(int fd, int argc, char * const * const argv) } ret = stat(path, &statbuf); if (ret < 0) { - ret = send_va_buffer(fd, "failed to stat %s (%s)\n", path, + ret = rc4_send_va_buffer(rc4c, "failed to stat %s (%s)\n", path, strerror(errno)); free(path); if (ret < 0) @@ -1982,7 +1986,7 @@ int com_add(int fd, int argc, char * const * const argv) else ret = add_one_audio_file(path, &pad); if (ret < 0) { - send_va_buffer(fd, "%s: %s\n", path, para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s: %s\n", path, para_strerror(-ret)); free(path); return ret; } @@ -2114,7 +2118,7 @@ static void com_touch_callback(int fd, const struct osl_object *query) free(tad.pb.buf); } -int com_touch(int fd, int argc, char * const * const argv) +int com_touch(struct rc4_context *rc4c, int argc, char * const * const argv) { struct com_touch_options cto = { .num_played = -1, @@ -2182,9 +2186,9 @@ int com_touch(int fd, int argc, char * const * const argv) if (i >= argc) return -E_AFT_SYNTAX; ret = send_option_arg_callback_request(&query, argc - i, - argv + i, com_touch_callback, send_result, &fd); + argv + i, com_touch_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -2266,7 +2270,7 @@ static void com_rm_callback(int fd, const struct osl_object *query) } /* TODO options: -r (recursive) */ -int com_rm(int fd, int argc, char * const * const argv) +int com_rm(struct rc4_context *rc4c, int argc, char * const * const argv) { uint32_t flags = 0; struct osl_object query = {.data = &flags, .size = sizeof(flags)}; @@ -2297,9 +2301,9 @@ int com_rm(int fd, int argc, char * const * const argv) if (i >= argc) return -E_AFT_SYNTAX; ret = send_option_arg_callback_request(&query, argc - i, argv + i, - com_rm_callback, send_result, &fd); + com_rm_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -2414,7 +2418,7 @@ out: free(cad.pb.buf); } -int com_cpsi(int fd, int argc, char * const * const argv) +int com_cpsi(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@ -2459,9 +2463,9 @@ int com_cpsi(int fd, int argc, char * const * const argv) if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */ flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags; ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_cpsi_callback, send_result, &fd); + com_cpsi_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } diff --git a/attribute.c b/attribute.c index 30c12f1c..ff284c3a 100644 --- a/attribute.c +++ b/attribute.c @@ -5,8 +5,12 @@ */ /** \file attribute.c Attribute handling functions. */ + +#include + #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@ -171,7 +175,7 @@ static void com_lsatt_callback(int fd, const struct osl_object *query) free(laad.pb.buf); } -int com_lsatt(int fd, int argc, char * const * const argv) +int com_lsatt(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; @@ -199,12 +203,12 @@ int com_lsatt(int fd, int argc, char * const * const argv) } } ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_lsatt_callback, send_result, &fd); + com_lsatt_callback, rc4_send_result, rc4c); if (!ret) { if (argc > 1) - ret = send_va_buffer(fd, "no matches\n"); + ret = rc4_send_va_buffer(rc4c, "no matches\n"); } else if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -272,7 +276,7 @@ out: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -int com_setatt(__a_unused int fd, int argc, char * const * const argv) +int com_setatt(__a_unused struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 3) return -E_ATTR_SYNTAX; @@ -353,16 +357,16 @@ out: free(pb.buf); } -int com_addatt(int fd, int argc, char * const * const argv) +int com_addatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc < 2) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_addatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -396,16 +400,16 @@ out: free(pb.buf); } -int com_mvatt(int fd, int argc, char * const * const argv) +int com_mvatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc != 3) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_mvatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -468,16 +472,16 @@ static void com_rmatt_callback(int fd, const struct osl_object *query) free(raad.pb.buf); } -int com_rmatt(int fd, int argc, char * const * const argv) +int com_rmatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc < 2) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_rmatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } diff --git a/audiod.c b/audiod.c index eb3b200a..4a88cc88 100644 --- a/audiod.c +++ b/audiod.c @@ -8,9 +8,11 @@ #include #include #include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "audiod.cmdline.h" #include "list.h" #include "sched.h" diff --git a/blob.c b/blob.c index dbabba22..5905c9ad 100644 --- a/blob.c +++ b/blob.c @@ -7,8 +7,11 @@ /** \file blob.c Macros and functions for blob handling. */ #include +#include + #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@ -116,7 +119,7 @@ static void com_lsblob_callback(struct osl_table *table, free(lbad.pb.buf); } -static int com_lsblob(callback_function *f, int fd, int argc, char * const * const argv) +static int com_lsblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { uint32_t flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; @@ -147,7 +150,7 @@ static int com_lsblob(callback_function *f, int fd, int argc, char * const * con // if (argc > i) // return -E_BLOB_SYNTAX; return send_option_arg_callback_request(&options, argc - i, - argv + i, f, send_result, &fd); + argv + i, f, rc4_send_result, rc4c); } static int cat_blob(struct osl_table *table, struct osl_row *row, @@ -180,12 +183,13 @@ static void com_catblob_callback(struct osl_table *table, int fd, for_each_matching_row(&pmd); } -static int com_catblob(callback_function *f, int fd, int argc, +static int com_catblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 2) return -E_BLOB_SYNTAX; - return send_standard_callback_request(argc - 1, argv + 1, f, send_result, &fd); + return send_standard_callback_request(argc - 1, argv + 1, f, + rc4_send_result, rc4c); } /** Used for removing rows from a blob table. */ @@ -248,13 +252,13 @@ out: free(rmbd.pb.buf); } -static int com_rmblob(callback_function *f, int fd, int argc, +static int com_rmblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 2) return -E_MOOD_SYNTAX; return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, - send_result, &fd); + rc4_send_result, rc4c); } static void com_addblob_callback(struct osl_table *table, __a_unused int fd, @@ -326,7 +330,82 @@ out: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -static int com_addblob(callback_function *f, int fd, int argc, +/* + * write input from fd to dynamically allocated buffer, + * but maximal max_size byte. + */ +static int fd2buf(struct rc4_context *rc4c, unsigned max_size, struct osl_object *obj) +{ + const size_t chunk_size = 1024; + size_t size = 2048, received = 0; + int ret; + char *buf = para_malloc(size); + + for (;;) { + ret = rc4_recv_bin_buffer(rc4c, 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 = buf; + obj->size = received; + if (ret < 0) + free(buf); + return ret; +} + +/* + * Read data from a file descriptor, and send it to the afs process. + * + * \param rc4c crypt context containing 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 rc4c. 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. + * + * \return Negative on errors, the return value of the underlying call to + * send_callback_request() otherwise. + */ +static int stdin_command(struct rc4_context *rc4c, struct osl_object *arg_obj, + callback_function *f, unsigned max_len, + callback_result_handler *result_handler, + void *private_result_data) +{ + struct osl_object query, stdin_obj; + int ret; + + ret = rc4_send_buffer(rc4c, AWAITING_DATA_MSG); + if (ret < 0) + return ret; + ret = fd2buf(rc4c, max_len, &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); + free(stdin_obj.data); + ret = send_callback_request(f, &query, result_handler, private_result_data); + free(query.data); + return ret; +} + +static int com_addblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { struct osl_object arg_obj; @@ -337,7 +416,7 @@ static int com_addblob(callback_function *f, int fd, int argc, return -E_BLOB_SYNTAX; arg_obj.size = strlen(argv[1]) + 1; arg_obj.data = (char *)argv[1]; - return stdin_command(fd, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL); + return stdin_command(rc4c, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL); } /* FIXME: Print output to client, not to log file */ @@ -363,7 +442,7 @@ out: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -static int com_mvblob(callback_function *f, __a_unused int fd, +static int com_mvblob(callback_function *f, __a_unused struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc != 3) @@ -377,9 +456,9 @@ static int com_mvblob(callback_function *f, __a_unused int fd, { \ return com_ ## cmd_name ## blob_callback(table_name ## _table, fd, query); \ } \ - int com_ ## cmd_name ## cmd_prefix(int fd, int argc, char * const * const argv) \ + int com_ ## cmd_name ## cmd_prefix(struct rc4_context *rc4c, int argc, char * const * const argv) \ { \ - return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, fd, argc, argv); \ + return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, rc4c, argc, argv); \ } static int blob_get_name_by_id(struct osl_table *table, uint32_t id, diff --git a/client.c b/client.c index 003c1e60..fef6ba4a 100644 --- a/client.c +++ b/client.c @@ -6,9 +6,12 @@ /** \file client.c the client program used to connect to para_server */ +#include + #include "para.h" #include "list.h" #include "sched.h" +#include "crypt.h" #include "client.cmdline.h" #include "string.h" #include "stdin.h" diff --git a/client.h b/client.h index c6d5c75d..fa965c35 100644 --- a/client.h +++ b/client.h @@ -41,8 +41,8 @@ enum { struct client_task { /** the state of the connection */ int status; - /** the file descriptor */ - int fd; + /** The file descriptor and the rc4 keys. */ + struct rc4_context rc4c; /** the configuration (including the command) */ struct client_args_info conf; /** the config file for client options */ @@ -51,10 +51,6 @@ struct client_task { char *key_file; /** paraslash user name */ char *user; - /** session key for receiving data */ - RC4_KEY rc4_recv_key; - /** session key for sending data */ - RC4_KEY rc4_send_key; /** the client task structure */ struct task task; /** the buffer used for handshake and receiving */ diff --git a/client_common.c b/client_common.c index deb3a26d..b1eaa78b 100644 --- a/client_common.c +++ b/client_common.c @@ -8,6 +8,7 @@ #include #include +#include #include "para.h" #include "error.h" @@ -22,33 +23,6 @@ #include "client.cmdline.h" #include "client.h" -/* - * Rc4-encrypt data before sending. - * - * \param len The number of bytes to encrypt. - * \param indata Pointer to the input data of length \a len to be encrypted. - * \param outdata Result-pointer that holds the encrypted data. - * \param private_data Contains the rc4 key. - */ -static void rc4_send(unsigned long len, const unsigned char *indata, - unsigned char *outdata, void *private_data) -{ - struct client_task *ct = private_data; - RC4(&ct->rc4_send_key, len, indata, outdata); -} - -/* - * Rc4-decrypt received data. - * - * Parameters are identical to those of rc4_send. - */ -static void rc4_recv(unsigned long len, const unsigned char *indata, - unsigned char *outdata, void *private_data) -{ - struct client_task *ct = private_data; - RC4(&ct->rc4_recv_key, len, indata, outdata); -} - /** * Close the connection to para_server and free all resources. * @@ -60,10 +34,8 @@ void client_close(struct client_task *ct) { if (!ct) return; - if (ct->fd >= 0) { - disable_crypt(ct->fd); - close(ct->fd); - } + if (ct->rc4c.fd >= 0) + close(ct->rc4c.fd); free(ct->buf); free(ct->user); free(ct->config_file); @@ -92,27 +64,27 @@ static void client_pre_select(struct sched *s, struct task *t) ct->check_r = 0; ct->check_w = 0; - if (ct->fd < 0) + if (ct->rc4c.fd < 0) return; switch (ct->status) { case CL_CONNECTED: case CL_SENT_AUTH: case CL_SENT_CH_RESPONSE: case CL_SENT_COMMAND: - para_fd_set(ct->fd, &s->rfds, &s->max_fileno); + para_fd_set(ct->rc4c.fd, &s->rfds, &s->max_fileno); ct->check_r = 1; return; case CL_RECEIVED_WELCOME: case CL_RECEIVED_CHALLENGE: case CL_RECEIVED_PROCEED: - para_fd_set(ct->fd, &s->wfds, &s->max_fileno); + para_fd_set(ct->rc4c.fd, &s->wfds, &s->max_fileno); ct->check_w = 1; return; case CL_RECEIVING: if (ct->loaded < CLIENT_BUFSIZE - 1) { - para_fd_set(ct->fd, &s->rfds, &s->max_fileno); + para_fd_set(ct->rc4c.fd, &s->rfds, &s->max_fileno); ct->check_r = 1; } return; @@ -121,7 +93,7 @@ static void client_pre_select(struct sched *s, struct task *t) return; if (*ct->in_loaded) { PARA_INFO_LOG("loaded: %zd\n", *ct->in_loaded); - para_fd_set(ct->fd, &s->wfds, &s->max_fileno); + para_fd_set(ct->rc4c.fd, &s->wfds, &s->max_fileno); ct->check_w = 1; } else { if (*ct->in_error) { @@ -136,8 +108,14 @@ static void client_pre_select(struct sched *s, struct task *t) static ssize_t client_recv_buffer(struct client_task *ct) { - ssize_t ret = recv_buffer(ct->fd, ct->buf + ct->loaded, - CLIENT_BUFSIZE - ct->loaded); + ssize_t ret; + + if (ct->status < CL_RECEIVED_PROCEED) + ret = recv_buffer(ct->rc4c.fd, ct->buf + ct->loaded, + CLIENT_BUFSIZE - ct->loaded); + else + ret = rc4_recv_buffer(&ct->rc4c, ct->buf + ct->loaded, + CLIENT_BUFSIZE - ct->loaded); if (!ret) return -E_SERVER_EOF; if (ret > 0) @@ -164,13 +142,13 @@ static void client_post_select(struct sched *s, struct task *t) struct client_task *ct = container_of(t, struct client_task, task); t->error = 0; - if (ct->fd < 0) + if (ct->rc4c.fd < 0) return; if (!ct->check_r && !ct->check_w) return; - if (ct->check_r && !FD_ISSET(ct->fd, &s->rfds)) + if (ct->check_r && !FD_ISSET(ct->rc4c.fd, &s->rfds)) return; - if (ct->check_w && !FD_ISSET(ct->fd, &s->wfds)) + if (ct->check_w && !FD_ISSET(ct->rc4c.fd, &s->wfds)) return; switch (ct->status) { case CL_CONNECTED: /* receive welcome message */ @@ -181,7 +159,7 @@ static void client_post_select(struct sched *s, struct task *t) case CL_RECEIVED_WELCOME: /* send auth command */ sprintf(ct->buf, "auth rc4 %s", ct->user); PARA_INFO_LOG("--> %s\n", ct->buf); - t->error = send_buffer(ct->fd, ct->buf); + t->error = send_buffer(ct->rc4c.fd, ct->buf); if (t->error >= 0) ct->status = CL_SENT_AUTH; return; @@ -204,7 +182,7 @@ static void client_post_select(struct sched *s, struct task *t) return; case CL_RECEIVED_CHALLENGE: /* send decrypted challenge */ PARA_INFO_LOG("--> %lu\n", ct->challenge_nr); - t->error = send_va_buffer(ct->fd, "%s%lu", CHALLENGE_RESPONSE_MSG, + 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; @@ -232,9 +210,8 @@ static void client_post_select(struct sched *s, struct task *t) bytes_received - PROCEED_MSG_LEN - 1); if (t->error < 0) return; - RC4_set_key(&ct->rc4_send_key, RC4_KEY_LEN, rc4_buf); - RC4_set_key(&ct->rc4_recv_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN); - enable_crypt(ct->fd, rc4_recv, rc4_send, ct); + 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); ct->status = CL_RECEIVED_PROCEED; return; } @@ -250,7 +227,7 @@ static void client_post_select(struct sched *s, struct task *t) } command = para_strcat(command, EOC_MSG "\n"); PARA_DEBUG_LOG("--> %s\n", command); - t->error = send_buffer(ct->fd, command); + t->error = rc4_send_buffer(&ct->rc4c, command); free(command); if (t->error > 0) ct->status = CL_SENT_COMMAND; @@ -268,7 +245,7 @@ static void client_post_select(struct sched *s, struct task *t) return; case CL_SENDING: /* FIXME: might block */ PARA_INFO_LOG("loaded: %zd\n", *ct->in_loaded); - t->error = send_bin_buffer(ct->fd, ct->inbuf, *ct->in_loaded); + t->error = rc4_send_bin_buffer(&ct->rc4c, ct->inbuf, *ct->in_loaded); if (t->error < 0) return; *ct->in_loaded = 0; @@ -284,14 +261,14 @@ static int client_connect(struct client_task *ct) { int ret; - ct->fd = -1; + ct->rc4c.fd = -1; ret = makesock(AF_UNSPEC, IPPROTO_TCP, 0, ct->conf.hostname_arg, ct->conf.server_port_arg); if (ret < 0) return ret; - ct->fd = ret; + ct->rc4c.fd = ret; ct->status = CL_CONNECTED; - ret = mark_fd_nonblocking(ct->fd); + ret = mark_fd_nonblocking(ct->rc4c.fd); if (ret < 0) goto err_out; ct->task.pre_select = client_pre_select; @@ -300,8 +277,8 @@ static int client_connect(struct client_task *ct) register_task(&ct->task); return 1; err_out: - close(ct->fd); - ct->fd = -1; + close(ct->rc4c.fd); + ct->rc4c.fd = -1; return ret; } @@ -329,7 +306,7 @@ int client_open(int argc, char *argv[], struct client_task **ct_ptr, ct->buf = para_malloc(CLIENT_BUFSIZE); *ct_ptr = ct; - ct->fd = -1; + ct->rc4c.fd = -1; ret = -E_CLIENT_SYNTAX; if (client_cmdline_parser(argc, argv, &ct->conf)) goto out; diff --git a/command.c b/command.c index ab765a1b..4b3a1552 100644 --- a/command.c +++ b/command.c @@ -14,6 +14,8 @@ #include "para.h" #include "error.h" +#include "crypt.h" +#include "command.h" #include "server.cmdline.h" #include "string.h" #include "afh.h" @@ -36,14 +38,19 @@ /** 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[]; +static void init_rc4_keys(struct rc4_context *rcc) +{ + get_random_bytes_or_die(rc4_buf, 2 * RC4_KEY_LEN); + RC4_set_key(&rcc->recv_key, RC4_KEY_LEN, rc4_buf); + RC4_set_key(&rcc->send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN); +} + static void dummy(__a_unused int s) { } @@ -208,7 +215,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; @@ -221,7 +228,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; } @@ -231,7 +238,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; } @@ -250,7 +257,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; @@ -267,7 +274,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" @@ -294,18 +301,18 @@ 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" ); } /* stat */ -int com_stat(int fd, int argc, char * const * argv) +int com_stat(struct rc4_context *rc4c, int argc, char * const * argv) { int ret, num = 0;/* status will be printed that many * times. num <= 0 means: print forever @@ -321,7 +328,7 @@ int com_stat(int fd, int argc, char * const * argv) mmd_dup(nmmd); s = get_status(nmmd); - ret = send_buffer(fd, s); + ret = rc4_send_buffer(rc4c, s); free(s); if (ret < 0) goto out; @@ -336,14 +343,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); @@ -376,7 +383,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; @@ -384,9 +391,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); @@ -395,7 +402,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" @@ -414,7 +421,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; @@ -423,7 +430,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; @@ -431,7 +438,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; @@ -444,7 +451,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; @@ -457,7 +464,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; @@ -472,7 +479,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; @@ -484,7 +491,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; @@ -496,7 +503,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; @@ -535,7 +542,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; @@ -589,29 +596,7 @@ static struct server_command *parse_cmd(const char *cmdstr) return get_cmd_ptr(buf, NULL); } -static void init_rc4_keys(void) -{ - get_random_bytes_or_die(rc4_buf, 2 * RC4_KEY_LEN); - 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]; @@ -621,7 +606,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) @@ -693,6 +678,7 @@ __noreturn void handle_connect(int fd, const char *peername) 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. */ @@ -747,7 +733,7 @@ __noreturn void handle_connect(int fd, const char *peername) /* auth successful, send 'Proceed' message */ PARA_INFO_LOG("good auth for %s (%lu)\n", u->name, challenge_nr); sprintf(buf, "%s", PROCEED_MSG); - init_rc4_keys(); + init_rc4_keys(&rc4c); /* Should we also encrypt the proceed message? */ ret = para_encrypt_buffer(u->rsa, rc4_buf, 2 * RC4_KEY_LEN, (unsigned char *)buf + PROCEED_MSG_LEN + 1); @@ -757,8 +743,7 @@ __noreturn void handle_connect(int fd, const char *peername) ret = send_bin_buffer(fd, buf, numbytes); if (ret < 0) goto net_err; - 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) @@ -776,14 +761,14 @@ __noreturn void handle_connect(int fd, const char *peername) argc = split_args(command, &argv, "\n"); 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); 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: diff --git a/command.h b/command.h new file mode 100644 index 00000000..347dd81c --- /dev/null +++ b/command.h @@ -0,0 +1,19 @@ +/** \file command.h The structure of server and afs commands. */ + +/** + * Defines one command of para_server. + */ +struct server_command { + /** The name of the command. */ + const char *name; + /** Pointer to the function that handles the command. */ + int (*handler)(struct rc4_context *, int, char * const * const); + /** The privileges a user must have to execute this command. */ + unsigned int perms; + /** One-line description of the command. */ + const char *description; + /** Summary of the command line options. */ + const char *usage; + /** The long help text. */ + const char *help; +}; diff --git a/command_util.sh b/command_util.sh index 62ad9663..44b4ee18 100755 --- a/command_util.sh +++ b/command_util.sh @@ -26,6 +26,12 @@ read_header() AT:) array_type="$value" ;; + SI:) + for i in $value; do + system_includes="$system_includes +#include <$i.h>" + done + ;; IN:) for i in $value; do includes="$includes @@ -198,7 +204,7 @@ dump_proto() echo '/**' echo " * $desc_txt" echo ' *' - echo ' * \param fd The file descriptor to send output to.' + echo ' * \param rc4c The rc4 crypt context.' if test $line_handler -eq 0; then echo ' * \param argc The number of arguments.' echo ' * \param argv The argument vector.' @@ -273,6 +279,7 @@ template_loop() com_c_file() { echo "/** \file $output_file.c $c_file_comment */" + echo "$system_includes" echo "$includes" echo "struct $array_type $array_name[] = {" while : ; do diff --git a/crypt.c b/crypt.c index 580974d7..679ba35d 100644 --- a/crypt.c +++ b/crypt.c @@ -6,13 +6,18 @@ /** \file crypt.c openssl-based RSA encryption/decryption routines */ +#include +#include +#include +#include +#include +#include + #include "para.h" #include "error.h" #include "string.h" #include "crypt.h" -#include -#include - +#include "fd.h" /** * Fill a buffer with random content. * @@ -218,3 +223,110 @@ int para_encrypt_challenge(RSA* rsa, long unsigned challenge_nr, return ret; } +/** + * Encrypt and send a buffer. + * + * \param rc4c The rc4 crypt 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 rc4_send_bin_buffer(struct rc4_context *rc4c, const char *buf, size_t len) +{ + int ret; + unsigned char *tmp; + + assert(len); + tmp = para_malloc(len); + RC4(&rc4c->send_key, len, (const unsigned char *)buf, tmp); + ret = write_all(rc4c->fd, (char *)tmp, &len); + free(tmp); + return ret; +} + +/** + * Encrypt and send a \p NULL-terminated buffer. + * + * \param rc4c The rc4 crypt context. + * \param buf The buffer to send. + * + * \return The return value of the underyling call to rc4_send_bin_buffer(). + */ +int rc4_send_buffer(struct rc4_context *rc4c, const char *buf) +{ + return rc4_send_bin_buffer(rc4c, buf, strlen(buf)); +} + +/** + * Format, encrypt and send a buffer. + * + * \param rc4c The rc4 crypt context. + * \param fmt A format string. + * + * \return The return value of the underyling call to rc4_send_buffer(). + */ +__printf_2_3 int rc4_send_va_buffer(struct rc4_context *rc4c, const char *fmt, ...) +{ + char *msg; + int ret; + + PARA_VSPRINTF(fmt, msg); + ret = rc4_send_buffer(rc4c, msg); + free(msg); + return ret; +} + +/** + * Receive a buffer and decrypt it. + * + * \param rc4c The rc4 crypt 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 rc4_recv_bin_buffer(struct rc4_context *rc4c, char *buf, size_t size) +{ + unsigned char *tmp = para_malloc(size); + ssize_t ret = recv(rc4c->fd, tmp, size, 0); + + if (ret > 0) + RC4(&rc4c->recv_key, ret, tmp, (unsigned char *)buf); + else if (ret < 0) + ret = -ERRNO_TO_PARA_ERROR(errno); + free(tmp); + return ret; +} + +/** + * Receive a buffer, decrypt it and write terminating NULL byte. + * + * \param rc4c The rc4 crypt 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 rc4c, + * 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 + * rc4_recv_bin_buffer(). + */ +int rc4_recv_buffer(struct rc4_context *rc4c, char *buf, size_t size) +{ + int n; + + assert(size); + n = rc4_recv_bin_buffer(rc4c, buf, size - 1); + if (n >= 0) + buf[n] = '\0'; + else + *buf = '\0'; + return n; +} diff --git a/crypt.h b/crypt.h index 1ed3985d..c430406f 100644 --- a/crypt.h +++ b/crypt.h @@ -21,6 +21,17 @@ void rsa_free(RSA *rsa); void get_random_bytes_or_die(unsigned char *buf, int num); void init_random_seed_or_die(void); +struct rc4_context { + int fd; + RC4_KEY recv_key; + RC4_KEY send_key; +}; +int rc4_send_bin_buffer(struct rc4_context *rc4c, const char *buf, size_t len); +int rc4_send_buffer(struct rc4_context *rc4c, const char *buf); +__printf_2_3 int rc4_send_va_buffer(struct rc4_context *rc4c, const char *fmt, ...); +int rc4_recv_bin_buffer(struct rc4_context *rcc, char *buf, size_t size); +int rc4_recv_buffer(struct rc4_context *rcc, char *buf, size_t size); + /** \cond used to distinguish between loading of private/public key */ #define LOAD_PUBLIC_KEY 0 #define LOAD_PRIVATE_KEY 1 diff --git a/grab_client.c b/grab_client.c index e419a723..ccfdb0c8 100644 --- a/grab_client.c +++ b/grab_client.c @@ -25,7 +25,6 @@ #include "error.h" #include "string.h" #include "fd.h" -#include "crypt.h" /** Grab clients that are not yet attached to a filter node. */ struct list_head inactive_grab_client_list; diff --git a/net.c b/net.c index 7207e528..f10afb71 100644 --- a/net.c +++ b/net.c @@ -27,71 +27,15 @@ #include #include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "net.h" #include "string.h" #include "fd.h" - -/** Information about one encrypted connection. */ -struct crypt_data { - /** Function used to decrypt received data. */ - crypt_function *recv; - /** Function used to encrypt data to be sent. */ - crypt_function *send; - /** - * Context-dependent data (crypt keys), passed verbatim to the above - * crypt functions. - */ - void *private_data; -}; -/** Array holding per fd crypt data. */ -static struct crypt_data *crypt_data_array; -/** Current size of the crypt data array. */ -static unsigned cda_size = 0; - -/** - * Activate encryption for one file descriptor. - * - * \param fd The file descriptor. - * \param recv_f The function used for decrypting received data. - * \param send_f The function used for encrypting before sending. - * \param private_data User data supplied by the caller. - */ -void enable_crypt(int fd, crypt_function *recv_f, crypt_function *send_f, - void *private_data) -{ - if (fd + 1 > cda_size) { - crypt_data_array = para_realloc(crypt_data_array, - (fd + 1) * sizeof(struct crypt_data)); - memset(crypt_data_array + cda_size, 0, - (fd + 1 - cda_size) * sizeof(struct crypt_data)); - cda_size = fd + 1; - } - crypt_data_array[fd].recv = recv_f; - crypt_data_array[fd].send = send_f; - crypt_data_array[fd].private_data = private_data; - PARA_INFO_LOG("rc4 encryption activated for fd %d\n", fd); -} - -/** - * Deactivate encryption for a given fd. - * - * \param fd The file descriptor. - * - * This must be called if and only if \p fd was activated via enable_crypt(). - */ -void disable_crypt(int fd) -{ - if (cda_size < fd + 1) - return; - crypt_data_array[fd].recv = NULL; - crypt_data_array[fd].send = NULL; - crypt_data_array[fd].private_data = NULL; -} - /** * Match string as a candidate IPv4 address. * @@ -487,41 +431,26 @@ struct in_addr extract_v4_addr(const struct sockaddr_storage *ss) } /** - * Encrypt and send a binary buffer. + * Send a binary buffer. * * \param fd The file descriptor. - * \param buf The buffer to be encrypted and sent. + * \param buf The buffer to be sent. * \param len The length of \a buf. * - * Check if encryption is available. If yes, encrypt the given buffer. Send - * out the buffer, encrypted or not, and try to resend the remaining part in - * case of short writes. + * Send out the buffer and try to resend the remaining part in case of short + * writes. * * \return Standard. */ int send_bin_buffer(int fd, const char *buf, size_t len) { - int ret; - crypt_function *cf = NULL; - if (!len) PARA_CRIT_LOG("len == 0\n"); - if (fd + 1 <= cda_size) - cf = crypt_data_array[fd].send; - if (cf) { - void *private = crypt_data_array[fd].private_data; - /* RC4 may write more than len to the output buffer */ - unsigned char *outbuf = para_malloc(ROUND_UP(len, 8)); - (*cf)(len, (unsigned char *)buf, outbuf, private); - ret = write_all(fd, (char *)outbuf, &len); - free(outbuf); - } else - ret = write_all(fd, buf, &len); - return ret; + return write_all(fd, buf, &len); } /** - * Encrypt and send null terminated buffer. + * Send a \p NULL-terminated buffer. * * \param fd The file descriptor. * \param buf The null-terminated buffer to be send. @@ -535,9 +464,8 @@ int send_buffer(int fd, const char *buf) return send_bin_buffer(fd, buf, strlen(buf)); } - /** - * Send and encrypt a buffer given by a format string. + * Send a buffer given by a format string. * * \param fd The file descriptor. * \param fmt A format string. @@ -556,51 +484,37 @@ __printf_2_3 int send_va_buffer(int fd, const char *fmt, ...) } /** - * Receive and decrypt. + * Receive data from a file descriptor. * * \param fd The file descriptor. - * \param buf The buffer to write the decrypted data to. + * \param buf The buffer to write the data to. * \param size The size of \a buf. * - * Receive at most \a size bytes from file descriptor \a fd. If encryption is - * available, decrypt the received buffer. + * Receive at most \a size bytes from file descriptor \a fd. * - * \return The number of bytes received on success, negative on errors. + * \return The number of bytes received on success, negative on errors, zero if + * the peer has performed an orderly shutdown. * - * \sa recv(2) + * \sa recv(2). */ __must_check int recv_bin_buffer(int fd, char *buf, size_t size) { ssize_t n; - crypt_function *cf = NULL; - - if (fd + 1 <= cda_size) - cf = crypt_data_array[fd].recv; - if (cf) { - unsigned char *tmp = para_malloc(size); - void *private = crypt_data_array[fd].private_data; - n = recv(fd, tmp, size, 0); - if (n > 0) { - size_t numbytes = n; - unsigned char *b = (unsigned char *)buf; - (*cf)(numbytes, tmp, b, private); - } - free(tmp); - } else - n = recv(fd, buf, size, 0); + + n = recv(fd, buf, size, 0); if (n == -1) return -ERRNO_TO_PARA_ERROR(errno); return n; } /** - * Receive, decrypt and write terminating NULL byte. + * Receive and write terminating NULL byte. * * \param fd The file descriptor. - * \param buf The buffer to write the decrypted data to. + * \param buf The buffer to write the data to. * \param size The size of \a buf. * - * Read and decrypt at most \a size - 1 bytes from file descriptor \a fd and + * Read at most \a size - 1 bytes from file descriptor \a fd and * write a NULL byte at the end of the received data. * * \return The return value of the underlying call to \a recv_bin_buffer(). diff --git a/net.h b/net.h index 11b1708f..b85403fd 100644 --- a/net.h +++ b/net.h @@ -78,15 +78,13 @@ extern int para_listen(unsigned l3type, unsigned l4type, unsigned short port); extern char *local_name(int sockfd); extern char *remote_name(int sockfd); -/** used to crypt the communication between para_server and para_client */ -typedef void crypt_function(unsigned long len, - const unsigned char *indata, unsigned char *outdata, void *private_data); - -int send_buffer(int, const char *); int send_bin_buffer(int, const char *, size_t); +int send_buffer(int, const char *); __printf_2_3 int send_va_buffer(int fd, const char *fmt, ...); -int recv_buffer(int fd, char *buf, size_t size); + int recv_bin_buffer(int fd, char *buf, size_t size); +int recv_buffer(int fd, char *buf, size_t size); + int para_accept(int, void *addr, socklen_t size); int create_local_socket(const char *name, struct sockaddr_un *unix_addr, mode_t mode); @@ -94,6 +92,3 @@ int create_remote_socket(const char *name); int recv_cred_buffer(int, char *, size_t); ssize_t send_cred_buffer(int, char*); int recv_pattern(int fd, const char *pattern, size_t bufsize); -void enable_crypt(int fd, crypt_function *recv_f, crypt_function *send_f, - void *private_data); -void disable_crypt(int fd); diff --git a/server.c b/server.c index 6c3373d3..8c617325 100644 --- a/server.c +++ b/server.c @@ -65,9 +65,11 @@ #include #include #include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "server.cmdline.h" #include "afh.h" #include "string.h" diff --git a/server.cmd b/server.cmd index a6b512fe..d574d2c8 100644 --- a/server.cmd +++ b/server.cmd @@ -3,7 +3,8 @@ SF: command.c HC: prototypes for the server command handlers CC: array of server commands AT: server_command -IN: para error string afh afs server list user_list +SI: openssl/rc4 +IN: para error crypt command string afh afs server list user_list SN: list of server commands --- N: ff diff --git a/server.h b/server.h index cf17c0ef..a814aff0 100644 --- a/server.h +++ b/server.h @@ -12,23 +12,6 @@ /** The maximum length of the host component in an URL */ #define MAX_HOSTLEN 256 -/** - * Defines one command of para_server. - */ -struct server_command { - /** The name of the command. */ - const char *name; - /** Pointer to the function that handles the command. */ - int (*handler)(int, int, char * const * const); - /** The privileges a user must have to execute this command. */ - unsigned int perms; - /** One-line description of the command. */ - const char *description; - /** Summary of the command line options. */ - const char *usage; - /** The long help text. */ - const char *help; -}; /** Holds the arguments for the para_server's sender command. */ struct sender_command_data{ diff --git a/user_list.c b/user_list.c index 63bfdfc2..840802b3 100644 --- a/user_list.c +++ b/user_list.c @@ -8,9 +8,11 @@ #include #include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "fd.h" #include "string.h" #include "list.h" diff --git a/user_list.h b/user_list.h index 5baceacc..e95747c4 100644 --- a/user_list.h +++ b/user_list.h @@ -6,8 +6,6 @@ /** \file user_list.h exported functions from user_list.c */ -#include "crypt.h" - /** * permission flags that can be set individually for any server command *