X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=command.c;h=5b17f116d53c93956faf60f88d903b233b7e9b69;hp=7b3d6faf90849a92ecbafb98538f277cfef5b02a;hb=HEAD;hpb=d5e27e2a346da2f18188d317926a60687d082732 diff --git a/command.c b/command.c index 7b3d6faf..60c2aeba 100644 --- a/command.c +++ b/command.c @@ -6,14 +6,10 @@ #include #include #include -#include -#include #include -#include #include #include -#include "server.lsg.h" #include "para.h" #include "error.h" #include "lsu.h" @@ -22,12 +18,11 @@ #include "command.h" #include "string.h" #include "afh.h" -#include "afs.h" #include "net.h" #include "server.h" #include "list.h" -#include "send.h" #include "sched.h" +#include "send.h" #include "vss.h" #include "daemon.h" #include "fd.h" @@ -52,12 +47,14 @@ extern struct misc_meta_data *mmd; int send_afs_status(struct command_context *cc, int parser_friendly); static bool subcmd_should_die; +/* + * Don't call PARA_XXX_LOG() here as we might already hold the log mutex. See + * generic_signal_handler() for details. + */ static void command_handler_sighandler(int s) { - if (s != SIGTERM) - return; - PARA_EMERG_LOG("terminating on signal %d\n", SIGTERM); - subcmd_should_die = true; + if (s == SIGTERM) + subcmd_should_die = true; } /* @@ -83,7 +80,7 @@ static char *vss_status_tohuman(unsigned int flags) */ static char *vss_get_status_flags(unsigned int flags) { - char *msg = para_malloc(5 * sizeof(char)); + char *msg = alloc(5 * sizeof(char)); msg[0] = (flags & VSS_PLAYING)? 'P' : '_'; msg[1] = (flags & VSS_NOMORE)? 'O' : '_'; @@ -395,7 +392,6 @@ static int com_si(struct command_context *cc, "server_pid: %d\n" "afs_pid: %d\n" "connections (active/accepted/total): %u/%u/%u\n" - "current loglevel: %s\n" "supported audio formats: %s\n", ut, mmd->num_played, (int)getppid(), @@ -403,7 +399,6 @@ static int com_si(struct command_context *cc, mmd->active_connections, mmd->num_commands, mmd->num_connects, - ENUM_STRING_VAL(LOGLEVEL), AUDIO_FORMAT_HANDLERS ); mutex_unlock(mmd_mutex); @@ -512,6 +507,7 @@ static int com_stat(struct command_context *cc, struct lls_parse_result *lpr) * while we sleep. */ para_block_signal(SIGTERM); + para_block_signal(SIGUSR1); for (;;) { sigset_t set; /* @@ -543,8 +539,10 @@ static int com_stat(struct command_context *cc, struct lls_parse_result *lpr) * open a race window similar to the one described above. */ pselect(1, NULL, NULL, NULL, &ts, &set); - if (subcmd_should_die) + if (subcmd_should_die) { + PARA_EMERG_LOG("terminating on SIGTERM\n"); goto out; + } ret = -E_SERVER_CRASH; if (getppid() == 1) goto out; @@ -594,9 +592,56 @@ static int com_hup(__a_unused struct command_context *cc, } EXPORT_SERVER_CMD_HANDLER(hup); +static int com_ll(struct command_context *cc, struct lls_parse_result *lpr) +{ + unsigned ll, perms; + char *errctx; + const char *sev[] = {SEVERITIES}, *arg; + int ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx)); + + if (ret < 0) { + send_errctx(cc, errctx); + return ret; + } + if (lls_num_inputs(lpr) == 0) { /* reporting is an unprivileged op. */ + const char *severity; + mutex_lock(mmd_mutex); + severity = sev[mmd->loglevel]; + mutex_unlock(mmd_mutex); + return send_sb_va(&cc->scc, SBD_OUTPUT, "%s\n", severity); + } + /* + * Changing the loglevel changes the state of both the afs and the vss, + * so we require both AFS_WRITE and VSS_WRITE. + */ + perms = AFS_WRITE | VSS_WRITE; + if ((cc->u->perms & perms) != perms) + return -ERRNO_TO_PARA_ERROR(EPERM); + arg = lls_input(0, lpr); + for (ll = 0; ll < NUM_LOGLEVELS; ll++) + if (!strcmp(arg, sev[ll])) + break; + if (ll >= NUM_LOGLEVELS) + return -ERRNO_TO_PARA_ERROR(EINVAL); + PARA_INFO_LOG("new log level: %s\n", sev[ll]); + /* Ask the server and afs processes to adjust their log level. */ + mutex_lock(mmd_mutex); + mmd->loglevel = ll; + mutex_unlock(mmd_mutex); + return 1; +} +EXPORT_SERVER_CMD_HANDLER(ll); + static int com_term(__a_unused struct command_context *cc, __a_unused struct lls_parse_result *lpr) { + /* + * The server catches SIGTERM and propagates this signal to all its + * children. We are about to exit anyway, but we'd leak tons of memory + * if being terminated by the signal. So we ignore the signal here and + * terminate via the normal exit path, deallocating all memory. + */ + para_sigaction(SIGTERM, SIG_IGN); kill(getppid(), SIGTERM); return 1; } @@ -665,7 +710,7 @@ static int com_ff(struct command_context *cc, struct lls_parse_result *lpr) { long promille; int i, ret; - char c, *errctx; + char *errctx; ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx)); if (ret < 0) { @@ -673,21 +718,8 @@ static int com_ff(struct command_context *cc, struct lls_parse_result *lpr) return ret; } ret = para_atoi32(lls_input(0, lpr), &i); - if (ret < 0) { - if (ret != -E_ATOI_JUNK_AT_END) - return ret; - /* - * Compatibility code to keep the historic syntax (ff 30-) - * working. This can be removed after 0.7.0. - */ - ret = sscanf(lls_input(0, lpr), "%i%c", &i, &c); - if (ret <= 0) - return -E_COMMAND_SYNTAX; - if (ret > 1 && c == '-') { - PARA_WARNING_LOG("use of obsolete syntax\n"); - i = -i; - } - } + if (ret < 0) + return ret; mutex_lock(mmd_mutex); ret = -E_NO_AUDIO_FILE; if (!mmd->afd.afhi.chunks_total || !mmd->afd.afhi.seconds_total) @@ -745,14 +777,6 @@ out: } EXPORT_SERVER_CMD_HANDLER(jmp); -/* deprecated, does nothing */ -static int com_tasks(__a_unused struct command_context *cc, - __a_unused struct lls_parse_result *lpr) -{ - return 1; -} -EXPORT_SERVER_CMD_HANDLER(tasks); - static void reset_signals(void) { para_sigaction(SIGCHLD, SIG_IGN); @@ -762,7 +786,7 @@ static void reset_signals(void) } struct connection_features { - int dummy; /* none at the moment */ + bool sha256_requested; /* can be removed after 0.7.0 */ }; static int parse_auth_request(char *buf, int len, const struct user **u, @@ -788,10 +812,13 @@ static int parse_auth_request(char *buf, int len, const struct user **u, p++; create_argv(p, ",", &features); for (i = 0; features[i]; i++) { - if (strcmp(features[i], "sideband") == 0) - continue; - if (strcmp(features[i], "aes_ctr128") == 0) - continue; + /* + * ->sha256_requested can go away after 0.7.0 so that + * sha256 is used unconditionally, but we need to + * accept the feature request until 0.9.0. + */ + if (strcmp(features[i], "sha256") == 0) + cf->sha256_requested = true; else { ret = -E_BAD_FEATURE; goto out; @@ -829,13 +856,13 @@ static int run_command(struct command_context *cc, struct iovec *iov) } perms = server_command_perms[ret]; if ((perms & cc->u->perms) != perms) - return -E_PERM; + return -ERRNO_TO_PARA_ERROR(EPERM); lcmd = lls_cmd(ret, server_cmd_suite); end = iov->iov_base + iov->iov_len; for (i = 0; p < end; i++) p += strlen(p) + 1; argc = i; - argv = para_malloc((argc + 1) * sizeof(char *)); + argv = arr_alloc(argc + 1, sizeof(char *)); for (i = 0, p = iov->iov_base; p < end; i++) { argv[i] = para_strdup(p); p += strlen(p) + 1; @@ -889,8 +916,8 @@ int handle_connect(int fd) { int ret; unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN]; - unsigned char challenge_hash[HASH_SIZE]; - char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */; + unsigned char challenge_hash[HASH2_SIZE]; + char *command = NULL, *buf = alloc(HANDSHAKE_BUFSIZE) /* must be on the heap */; size_t numbytes; struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct; struct iovec iov; @@ -905,7 +932,7 @@ int handle_connect(int fd) /* send Welcome message */ ret = write_va_buffer(fd, "This is para_server, version " PACKAGE_VERSION ".\n" - "Features: sideband,aes_ctr128\n" + "Features: sha256\n" /* no longer announce this after 0.8.0 */ ); if (ret < 0) goto net_err; @@ -953,11 +980,19 @@ int handle_connect(int fd) * of the random data. */ ret = -E_BAD_AUTH; - if (numbytes != HASH_SIZE) - goto net_err; - hash_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash); - if (memcmp(challenge_hash, buf, HASH_SIZE)) - goto net_err; + if (cf.sha256_requested) { + if (numbytes != HASH2_SIZE) + goto net_err; + hash2_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash); + if (memcmp(challenge_hash, buf, HASH2_SIZE)) + goto net_err; + } else { /* old client. This can be removed after 0.7.0 */ + if (numbytes != HASH_SIZE) + goto net_err; + hash_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash); + if (memcmp(challenge_hash, buf, HASH_SIZE)) + goto net_err; + } /* auth successful */ alarm(0); PARA_INFO_LOG("good auth for %s\n", cc->u->name);