X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=command.c;h=c1bbba9aef86d7fccc936d2230f591ce3eb734d4;hp=325f768604ef192ef986e47ca0b603de92938cbb;hb=2bb9fcbfa99cf30a6f46ba33fd95c0a456a225cc;hpb=c85690666e2ed2327e751b819970658d58479bfb diff --git a/command.c b/command.c index 325f7686..c1bbba9a 100644 --- a/command.c +++ b/command.c @@ -1,51 +1,44 @@ /* * Copyright (C) 1997-2007 Andre Noll * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Licensed under the GPL v2. For licencing details see COPYING. */ -/** \file command.c does client authentication and executes server commands */ +/** \file command.c Client authentication and server commands. */ + +#include +#include +#include +#include +#include -#include /* gettimeofday */ +#include "para.h" +#include "error.h" #include "server.cmdline.h" +#include "string.h" +#include "afh.h" #include "afs.h" #include "server.h" #include "vss.h" #include "send.h" #include "rc4.h" -#include -#include "error.h" #include "net.h" #include "daemon.h" -#include "string.h" #include "fd.h" +#include "list.h" #include "user_list.h" #include "server_command_list.h" +#include "afs_command_list.h" -/** commands including options must be shorter than this */ -#define MAX_COMMAND_LEN 4096 +/** 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 const char *status_item_list[NUM_STAT_ITEMS]; extern struct misc_meta_data *mmd; -extern struct audio_file_selector selectors[]; extern struct sender senders[]; -extern char *user_list; static void dummy(__a_unused int s) {} @@ -78,8 +71,8 @@ static char *cmd_perms_itohuman(unsigned int perms) { char *msg = para_malloc(5 * sizeof(char)); - msg[0] = perms & DB_READ? 'a' : '-'; - msg[1] = perms & DB_WRITE? 'A' : '-'; + msg[0] = perms & AFS_READ? 'a' : '-'; + msg[1] = perms & AFS_WRITE? 'A' : '-'; msg[2] = perms & VSS_READ? 'v' : '-'; msg[3] = perms & VSS_WRITE? 'V' : '-'; msg[4] = '\0'; @@ -101,93 +94,58 @@ static char *vss_get_status_flags(unsigned int flags) return msg; } -/* - * compute status bar string. Never returns NULL - */ -static char *get_sb_string(struct misc_meta_data *nmmd) -{ - char *base, *ret; - long long unsigned secs = 0, rsecs = 0, percent = 0; - - base = para_basename(nmmd->filename); - if (!base) - return para_strdup(""); - if (!base[0]) - return base; - if (nmmd->chunks_total) { - secs = (long long) nmmd->seconds_total * nmmd->chunks_sent - / nmmd->chunks_total; - rsecs = (long long) nmmd->seconds_total * - (nmmd->chunks_total - nmmd->chunks_sent) - / nmmd->chunks_total; - percent = 100 * ((nmmd->chunks_sent + 5) / 10) - / ((nmmd->chunks_total + 5) / 10); - } - ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s", - secs / 60, secs % 60, - rsecs / 60, rsecs % 60, - percent, - base - ); - free(base); - return ret; -} - static char *get_status(struct misc_meta_data *nmmd) { - char *bar, *ret, mtime[30] = ""; + char *ret, mtime[30] = ""; char *status, *flags; /* vss status info */ char *ut = uptime_str(); long offset = (nmmd->offset + 500) / 1000; struct timeval now; struct tm mtime_tm; - if (nmmd->audio_format >= 0) { - localtime_r(&nmmd->mtime, &mtime_tm); - strftime(mtime, 29, "%a %b %d %Y", &mtime_tm); - } /* report real status */ status = vss_status_tohuman(nmmd->vss_status_flags); flags = vss_get_status_flags(nmmd->vss_status_flags); - bar = para_basename(nmmd->filename); + if (nmmd->size) { /* parent currently has an audio file open */ + localtime_r(&nmmd->mtime, &mtime_tm); + strftime(mtime, 29, "%a %b %d %Y", &mtime_tm); + } gettimeofday(&now, NULL); ret = make_message( - "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n" - "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n" - "%s:%li\n" "%s:%s\n" "%s" "%s" - "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n", + "%s: %zu\n" /* file size */ + "%s: %s\n" /* mtime */ + "%s: %s\n" /* status */ + "%s: %s\n" /* status flags */ + "%s: %li\n" /* offset */ + "%s: %s\n" /* afs mode */ + "%s: %lu.%lu\n" /* stream start */ + "%s: %lu.%lu\n" /* current server time */ + "%s", /* afs status info */ status_item_list[SI_FILE_SIZE], nmmd->size / 1024, status_item_list[SI_MTIME], mtime, - status_item_list[SI_LENGTH], nmmd->seconds_total, - status_item_list[SI_NUM_PLAYED], nmmd->num_played, - - status_item_list[SI_STATUS_BAR], bar ? bar : "(none)", status_item_list[SI_STATUS], status, status_item_list[SI_STATUS_FLAGS], flags, - status_item_list[SI_SELECTOR], selectors[nmmd->selector_num].name, status_item_list[SI_OFFSET], offset, - status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format), - nmmd->selector_info, - nmmd->audio_file_info, + status_item_list[SI_AFS_MODE], mmd->afs_mode_string, - status_item_list[SI_UPTIME], ut, status_item_list[SI_STREAM_START], (long unsigned)nmmd->stream_start.tv_sec, (long unsigned)nmmd->stream_start.tv_usec, status_item_list[SI_CURRENT_TIME], (long unsigned)now.tv_sec, - (long unsigned)now.tv_usec + (long unsigned)now.tv_usec, + + nmmd->afd.verbose_ls_output ); - free(bar); free(flags); free(status); free(ut); return ret; } -static int check_sender_args(int argc, char **argv, struct sender_command_data *scd) +static int check_sender_args(int argc, char * const * argv, struct sender_command_data *scd) { int i; /* this has to match sender.h */ @@ -225,7 +183,7 @@ static int check_sender_args(int argc, char **argv, struct sender_command_data * case SENDER_ALLOW: if (argc != 4 && argc != 5) return -E_COMMAND_SYNTAX; - if (!inet_aton(argv[3], &scd->addr)) + if (!inet_pton(AF_INET, argv[3], &scd->addr)) return -E_COMMAND_SYNTAX; scd->netmask = 32; if (argc == 5) { @@ -238,7 +196,7 @@ static int check_sender_args(int argc, char **argv, struct sender_command_data * case SENDER_DELETE: if (argc != 4 && argc != 5) return -E_COMMAND_SYNTAX; - if (!inet_aton(argv[3], &scd->addr)) + if (!inet_pton(AF_INET, argv[3], &scd->addr)) return -E_COMMAND_SYNTAX; scd->port = -1; if (argc == 5) { @@ -253,7 +211,7 @@ static int check_sender_args(int argc, char **argv, struct sender_command_data * return 1; } -int com_sender(int fd, int argc, char **argv) +int com_sender(int fd, int argc, char * const * argv) { int i, ret; struct sender_command_data scd; @@ -295,19 +253,15 @@ int com_sender(int fd, int argc, char **argv) } /* server info */ -int com_si(int fd, int argc, __a_unused char **argv) +int com_si(int fd, int argc, __a_unused char * const * argv) { int i, ret; char *ut; - char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL; + char *sender_info = NULL, *sender_list = NULL; if (argc != 1) return -E_COMMAND_SYNTAX; mmd_lock(); - for (i = 0; selectors[i].name; i++) { - selector_string = para_strcat(selector_string, selectors[i].name); - selector_string = para_strcat(selector_string, " "); - } for (i = 0; senders[i].name; i++) { char *info = senders[i].info(); sender_info = para_strcat(sender_info, info); @@ -320,7 +274,6 @@ int com_si(int fd, int argc, __a_unused char **argv) "pid: %d\n" "connections (active/accepted/total): %u/%u/%u\n" "current loglevel: %i\n" - "supported audio file selectors: %s\n" "supported audio formats: %s\n" "supported senders: %s\n" "%s", @@ -330,21 +283,19 @@ int com_si(int fd, int argc, __a_unused char **argv) mmd->num_commands, mmd->num_connects, conf.loglevel_arg, - selector_string, supported_audio_formats(), sender_list, sender_info ); mmd_unlock(); free(ut); - free(selector_string); free(sender_list); free(sender_info); return ret; } /* version */ -int com_version(int fd, int argc, __a_unused char **argv) +int com_version(int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -354,63 +305,8 @@ int com_version(int fd, int argc, __a_unused char **argv) ); } -/* sc */ -int com_sc(int fd, int argc, char **argv) -{ - char *name = NULL; - int ret, old = 0, count = -1; /* print af change forever */ - - if (argc > 1) - count = atoi(argv[1]); -repeat: - mmd_lock(); - if (old != mmd->num_played) { - old = mmd->num_played; - name = para_strdup(mmd->filename); - } - mmd_unlock(); - if (name) { - ret = send_va_buffer(fd, "%s\n", name); - free(name); - name = NULL; - if (ret < 0) - return ret; - if (argc > 1 && !--count) - return 1; - } - usleep(500000); - goto repeat; -} - -/* sb */ -int com_sb(int fd, int argc, char **argv) -{ - char *sb; - int ret, nr = -1; /* status bar will be printed that many - * times. Negative value means: print - * forever - */ - if (argc > 1) - nr = atoi(argv[1]); - while (nr) { - mmd_lock(); - sb = get_sb_string(mmd); - mmd_unlock(); - ret = send_va_buffer(fd, "%s\n", sb); - free(sb); - if (ret < 0) - return ret; - if (nr == 1) - return 1; - usleep(500000); - if (nr > 0) - nr--; - } - return 1; -} - /* stat */ -int com_stat(int fd, int argc, char **argv) +int com_stat(int fd, int argc, char * const * argv) { int ret, num = 0;/* status will be printed that many * times. num <= 0 means: print forever @@ -459,32 +355,29 @@ static int send_list_of_commands(int fd, struct server_command *cmd, return 1; } -/* always returns string that must be freed by the caller in handler */ -static struct server_command *get_cmd_ptr(char *name, char **handler) +/* returns string that must be freed by the caller */ +static struct server_command *get_cmd_ptr(const char *name, char **handler) { struct server_command *cmd; for (cmd = server_cmds; cmd->name; cmd++) if (!strcmp(cmd->name, name)) { if (handler) - *handler = para_strdup("para_server"); /* server commands */ + *handler = para_strdup("server"); /* server commands */ return cmd; } - /* not found, look for commands supported by the current selector */ - mmd_lock(); - if (handler) - *handler = make_message("the %s selector", - selectors[mmd->selector_num].name); - cmd = selectors[mmd->selector_num].cmd_list; - mmd_unlock(); - for (; cmd->name; cmd++) - if (!strcmp(cmd->name, name)) + /* not found, look for commands supported by afs */ + for (cmd = afs_cmds; cmd->name; cmd++) + if (!strcmp(cmd->name, name)) { + if (handler) + *handler = para_strdup("afs"); return cmd; + } return NULL; } /* help */ -int com_help(int fd, int argc, char **argv) +int com_help(int fd, int argc, char * const * argv) { struct server_command *cmd; char *perms, *handler; @@ -494,13 +387,7 @@ int com_help(int fd, int argc, char **argv) /* no argument given, print list of commands */ if ((ret = send_list_of_commands(fd, server_cmds, "server")) < 0) return ret; - mmd_lock(); - handler = para_strdup(selectors[mmd->selector_num].name); - cmd = selectors[mmd->selector_num].cmd_list; - mmd_unlock(); - ret = send_list_of_commands(fd, cmd, handler); - free(handler); - return ret; + return send_list_of_commands(fd, afs_cmds, "afs"); } /* argument given for help */ cmd = get_cmd_ptr(argv[1], &handler); @@ -528,7 +415,7 @@ int com_help(int fd, int argc, char **argv) } /* hup */ -int com_hup(__a_unused int fd, int argc, __a_unused char **argv) +int com_hup(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -537,7 +424,7 @@ int com_hup(__a_unused int fd, int argc, __a_unused char **argv) } /* term */ -int com_term(__a_unused int fd, int argc, __a_unused char **argv) +int com_term(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -545,7 +432,7 @@ int com_term(__a_unused int fd, int argc, __a_unused char **argv) return 1; } -int com_play(__a_unused int fd, int argc, __a_unused char **argv) +int com_play(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -558,7 +445,7 @@ int com_play(__a_unused int fd, int argc, __a_unused char **argv) } /* stop */ -int com_stop(__a_unused int fd, int argc, __a_unused char **argv) +int com_stop(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -571,46 +458,22 @@ int com_stop(__a_unused int fd, int argc, __a_unused char **argv) } /* pause */ -int com_pause(__a_unused int fd, int argc, __a_unused char **argv) +int com_pause(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; mmd_lock(); - if (!vss_paused()) + if (!vss_paused() && !vss_stopped()) { mmd->events++; - mmd->new_vss_status_flags &= ~VSS_PLAYING; - mmd->new_vss_status_flags &= ~VSS_NEXT; + mmd->new_vss_status_flags &= ~VSS_PLAYING; + mmd->new_vss_status_flags &= ~VSS_NEXT; + } mmd_unlock(); return 1; } -int com_chs(int fd, int argc, char **argv) -{ - int i, ret; - - if (argc == 1) { - char *selector; - mmd_lock(); - selector = para_strdup(selectors[mmd->selector_num].name); - mmd_unlock(); - ret = send_va_buffer(fd, "%s\n", selector); - free(selector); - return ret; - } - for (i = 0; selectors[i].name; i++) { - if (strcmp(selectors[i].name, argv[1])) - continue; - mmd_lock(); - mmd->selector_change = i; - mmd->events++; - mmd_unlock(); - return 1; - } - return -E_BAD_SELECTOR; -} - /* next */ -int com_next(__a_unused int fd, int argc, __a_unused char **argv) +int com_next(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -622,7 +485,7 @@ int com_next(__a_unused int fd, int argc, __a_unused char **argv) } /* nomore */ -int com_nomore(__a_unused int fd, int argc, __a_unused char **argv) +int com_nomore(__a_unused int fd, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@ -634,7 +497,7 @@ int com_nomore(__a_unused int fd, int argc, __a_unused char **argv) } /* ff */ -int com_ff(__a_unused int fd, int argc, char **argv) +int com_ff(__a_unused int fd, int argc, char * const * argv) { long promille; int ret, backwards = 0; @@ -649,20 +512,20 @@ int com_ff(__a_unused int fd, int argc, char **argv) backwards = 1; /* jmp backwards */ mmd_lock(); ret = -E_NO_AUDIO_FILE; - if (!mmd->chunks_total || !mmd->seconds_total) + if (!mmd->afd.afhi.chunks_total || !mmd->afd.afhi.seconds_total) goto out; - promille = (1000 * mmd->current_chunk) / mmd->chunks_total; + promille = (1000 * mmd->current_chunk) / mmd->afd.afhi.chunks_total; if (backwards) - promille -= 1000 * i / mmd->seconds_total; + promille -= 1000 * i / mmd->afd.afhi.seconds_total; else - promille += 1000 * i / mmd->seconds_total; + promille += 1000 * i / mmd->afd.afhi.seconds_total; if (promille < 0) promille = 0; if (promille > 1000) { mmd->new_vss_status_flags |= VSS_NEXT; goto out; } - mmd->repos_request = (mmd->chunks_total * promille) / 1000; + mmd->repos_request = (mmd->afd.afhi.chunks_total * promille) / 1000; mmd->new_vss_status_flags |= VSS_REPOS; mmd->new_vss_status_flags &= ~VSS_NEXT; mmd->events++; @@ -673,7 +536,7 @@ out: } /* jmp */ -int com_jmp(__a_unused int fd, int argc, char **argv) +int com_jmp(__a_unused int fd, int argc, char * const * argv) { long unsigned int i; int ret; @@ -684,12 +547,12 @@ int com_jmp(__a_unused int fd, int argc, char **argv) return -E_COMMAND_SYNTAX; mmd_lock(); ret = -E_NO_AUDIO_FILE; - if (!mmd->chunks_total) + if (!mmd->afd.afhi.chunks_total) goto out; if (i > 100) i = 100; PARA_INFO_LOG("jumping to %lu%%\n", i); - mmd->repos_request = (mmd->chunks_total * i + 50)/ 100; + mmd->repos_request = (mmd->afd.afhi.chunks_total * i + 50)/ 100; PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n", mmd->chunks_sent, mmd->offset); mmd->new_vss_status_flags |= VSS_REPOS; @@ -727,17 +590,12 @@ static struct server_command *parse_cmd(const char *cmdstr) return get_cmd_ptr(buf, NULL); } -static long int para_rand(long unsigned max) -{ - return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0))); -} - static void init_rc4_keys(void) { int i; for (i = 0; i < 2 * RC4_KEY_LEN; i++) - rc4_buf[i] = para_rand(256); + 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]); @@ -757,6 +615,42 @@ static void rc4_send(unsigned long len, const unsigned char *indata, RC4(&rc4_send_key, len, indata, outdata); } +static int read_command(int fd, char **result) +{ + int ret; + char buf[4096]; + char *command = NULL; + + for (;;) { + size_t numbytes; + char *p; + + ret = recv_buffer(fd, buf, sizeof(buf)); + if (ret < 0) + goto out; + if (!ret) + break; + numbytes = ret; + ret = -E_COMMAND_SYNTAX; + if (command && numbytes + strlen(command) > MAX_COMMAND_LEN) /* DOS */ + goto out; + command = para_strcat(command, buf); + p = strstr(command, EOC_MSG); + if (p) { + *p = '\0'; + break; + } + } + ret = command? 1 : -E_COMMAND_SYNTAX; +out: + if (ret < 0) + free(command); + else + *result = command; + return ret; + +} + /** * perform user authentication and execute a command * @@ -775,12 +669,10 @@ static void rc4_send(unsigned long len, const unsigned char *indata, * encrypted with its RSA public key. From this point on, * all transfers are crypted with this session key. * - * Next it is checked if the peer supplied a valid server - * command or a command for the audio file selector currently - * in use. If yes, and if the user has sufficient - * permissions to execute that command, the function calls - * the corresponding command handler which does argument - * checking and further processing. + * Next it is checked if the peer supplied a valid server command or a command + * for the audio file selector. If yes, and if the user has sufficient + * permissions to execute that command, the function calls the corresponding + * command handler which does argument checking and further processing. * * In order to cope with a DOS attacks, a timeout is set up * which terminates the function if the connection was not @@ -790,7 +682,7 @@ static void rc4_send(unsigned long len, const unsigned char *indata, */ int handle_connect(int fd, struct sockaddr_in *addr) { - int numbytes, ret, argc, use_rc4 = 0; + int ret, argc, use_rc4 = 0; char buf[4096]; unsigned char crypt_buf[MAXLINE]; struct user *u; @@ -798,6 +690,7 @@ int handle_connect(int fd, struct sockaddr_in *addr) long unsigned challenge_nr, chall_response; char **argv = NULL; char *p, *command = NULL; + size_t numbytes; signal(SIGCHLD, SIG_IGN); signal(SIGINT, SIG_DFL); @@ -840,23 +733,23 @@ int handle_connect(int fd, struct sockaddr_in *addr) if (ret <= 0) goto err_out; numbytes = ret; - PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes); + 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 (ret < 0) goto err_out; /* recv decrypted number */ - numbytes = recv_buffer(fd, buf, sizeof(buf)); - ret = numbytes; + ret = recv_buffer(fd, buf, sizeof(buf)); if (ret < 0) goto err_out; + numbytes = ret; ret = -E_AUTH; if (!numbytes) goto err_out; if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1 || chall_response != challenge_nr) goto err_out; - /* auth successful. Send 'Proceed' message */ + /* 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) { @@ -873,24 +766,12 @@ int handle_connect(int fd, struct sockaddr_in *addr) goto err_out; if (use_rc4) enable_crypt(fd, rc4_recv, rc4_send, NULL); - /* read command */ - while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) { -// PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes); - ret = -E_COMMAND_SYNTAX; - if (command && numbytes + strlen(command) > MAX_COMMAND_LEN) /* DOS */ - goto err_out; - command = para_strcat(command, buf); - if ((p = strstr(command, EOC_MSG))) { - *p = '\0'; - break; - } - } - ret = numbytes; + ret = read_command(fd, &command); if (ret < 0) goto err_out; ret = -E_BAD_CMD; - /* parse command */ - if (!(cmd = parse_cmd(command))) + cmd = parse_cmd(command); + if (!cmd) goto err_out; /* valid command, check permissions */ ret = check_perms(u->perms, cmd); @@ -910,16 +791,15 @@ int handle_connect(int fd, struct sockaddr_in *addr) goto out; } err_out: - if (ret != -E_SEND && ret != -E_RECV) { - PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret)); + PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret)); + if (ret != -E_SEND && ret != -E_RECV) send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret)); - } ret = EXIT_FAILURE; out: free(command); free(argv); mmd_lock(); - if (cmd && (cmd->perms & DB_WRITE) && ret >= 0) + if (cmd && (cmd->perms & AFS_WRITE) && ret >= 0) mmd->events++; mmd->active_connections--; mmd_unlock();