2 * Copyright (C) 1997-2006 Andre Noll <maan@systemlinux.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
19 /** \file command.c does client authentication and executes server commands */
21 #include <sys/time.h> /* gettimeofday */
23 #include "server.cmdline.h"
29 #include <openssl/rc4.h>
35 static RC4_KEY rc4_recv_key;
36 static RC4_KEY rc4_send_key;
37 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
39 extern const char *status_item_list[NUM_STAT_ITEMS];
40 extern struct misc_meta_data *mmd;
41 extern struct audio_file_selector selectors[];
42 extern struct sender senders[];
43 extern char *user_list;
44 struct sockaddr_in *in_addr;
46 static int com_si(int, int, char **);
47 static int com_version(int, int, char **);
48 static int com_sb(int, int, char **);
49 static int com_sc(int, int, char **);
50 static int com_stat(int, int, char **);
51 static int com_help(int, int, char **);
52 static int com_hup(int, int, char **);
53 static int com_term(int, int, char **);
54 static int com_play(int, int, char **);
55 static int com_stop(int, int, char **);
56 static int com_pause(int, int, char **);
57 static int com_next(int, int, char **);
58 static int com_nomore(int, int, char **);
59 static int com_chs(int, int, char **);
60 static int com_ff(int, int, char **);
61 static int com_jmp(int, int, char **);
62 static int com_sender(int, int, char **);
65 /* commands that are handled by the server itself */
66 static struct server_command cmd_struct[] = {
70 .perms = DB_READ | DB_WRITE,
71 .description = "change the current audio file selector",
72 .synopsis = "chs [new_selector]",
74 "Shutdown the current selector and activate new_selector. If no\n"
75 "argument was given, print the name of the current selector.\n"
81 .perms = AFS_READ | AFS_WRITE,
82 .description = "jmp amount of time forwards or backwards "
83 "in current audio file",
84 .synopsis = "ff n[-]",
87 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
88 "\tand enqueue a request to jump n seconds forwards or backwards\n"
89 "\tin the current audio file.\n"
95 "\tjumps 30 seconds backwards.\n"
103 .description = "print help text",
104 .synopsis = "help [command]",
107 "Without any arguments, help prints a list of availible commands. When\n"
108 "issued with a command name as first argument, print out a description\n"
109 "for that command.\n"
117 .description = "force reload of config file and log file",
121 "After rereading the config file, a signal is sent to all children\n"
122 "which forces them to close/reopen the log file.\n"
129 .perms = AFS_READ | AFS_WRITE,
130 .description = "jmp to given position in current audio file",
131 .synopsis = "jmp [n]",
134 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
135 "\tand enqueue a request to jump to n% of the current audio file,\n"
136 "\twhere 0 <= n <= 100.\n"
143 .perms = AFS_READ | AFS_WRITE,
144 .description = "skip rest of current audio file",
148 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
149 "\tplaying, change audio file immediately. Equivalent to stop\n"
150 "\tif paused, NOP if stopped.\n"
157 .handler = com_nomore,
158 .perms = AFS_READ | AFS_WRITE,
159 .description = "stop playing after current audio file",
160 .synopsis = "nomore",
163 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
164 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
165 "the 'N' (next audio file) bit being set.\n"
167 "Use this command instead of stop if you don't like\n"
174 .handler = com_pause,
175 .perms = AFS_READ | AFS_WRITE,
176 .description = "pause current audio file",
180 "\tClear the 'P' (playing) bit of the afs status flags.\n"
187 .perms = AFS_READ | AFS_WRITE,
188 .description = "start playing or resume playing when paused",
192 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
193 "\tresults in starting/continuing to stream.\n"
201 .description = "print status bar for current audio file",
202 .synopsis = "sb [n]",
205 "Without any arguments, sb continuously prints a status bar of the form\n"
207 " 12:34 [56:12] (56%) filename\n"
209 "indicating playing time, remaining time, percentage and the name of\n"
210 "the file beeing streamed. Use the optional number n to let stat exit\n"
211 "after having displayed the status bar n times.\n"
218 .description = "print name of audio file whenever it changes",
219 .synopsis = "sc [n]",
222 "\tsc prints exactly one line (the filename of the audio file\n"
223 "\tbeing played) whenever the audio file changes. Stops after\n"
224 "\tn iterations, or never if n is not specified.\n"
229 .handler = com_sender,
230 .perms = AFS_READ | AFS_WRITE,
231 .description = "control paraslash internal senders",
232 .synopsis = "sender [s cmd [arguments]]",
235 "send command cmd to sender s. cmd may be one of the following:\n"
236 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
237 "support each command. Try e.g. 'para_client sender http help' for\n"
238 "more information about the http sender. If no argument is given,\n"
239 "print out a list of all senders that are compiled in.\n"
246 .description = "print server info",
249 "Print server uptime and other information.\n"
256 .description = "print status info for current audio file",
257 .synopsis = "stat [n]",
260 "\tWithout any arguments, stat continuously prints status messages\n"
261 "\tof the audio file being streamed. Use the optional number n\n"
262 "\tto let stat exit after having displayed status n times.\n"
269 .perms = AFS_READ | AFS_WRITE,
270 .description = "stop playing",
274 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
281 .perms = AFS_READ | AFS_WRITE,
282 .description = "terminate para_server",
286 "Shuts down the server. Instead of this command, you can also send\n"
287 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
292 .handler = com_version,
294 .description = "print server's version",
295 .synopsis = "version",
297 "Show version and other info\n"
299 /* this indicates the end of the list. Do not touch. */
305 static void dummy(__a_unused int s)
308 static void mmd_dup(struct misc_meta_data *new_mmd)
316 * compute human readable string containing
317 * afs_status for given integer value
319 static char *afs_status_tohuman(unsigned int flags)
321 if (flags & AFS_PLAYING)
322 return para_strdup("playing");
323 else if (flags & AFS_NEXT)
324 return para_strdup("stopped");
326 return para_strdup("paused");
330 * return human readable permission string. Never returns NULL.
332 char *cmd_perms_itohuman(unsigned int perms)
334 char *msg = para_malloc(7 * sizeof(char));
336 msg[0] = perms & DB_READ? 'd' : '-';
337 msg[1] = perms & DB_WRITE? 'D' : '-';
338 msg[2] = perms & AFS_READ? 'a' : '-';
339 msg[3] = perms & AFS_WRITE? 'A' : '-';
345 * Never returns NULL.
347 static char *afs_get_status_flags(unsigned int flags)
349 char *msg = para_malloc(5 * sizeof(char));
351 msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
352 msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
353 msg[2] = (flags & AFS_NEXT)? 'N' : '_';
354 msg[3] = (flags & AFS_REPOS)? 'R' : '_';
360 * compute status bar string. Never returns NULL
362 char *get_sb_string(struct misc_meta_data *nmmd)
365 long long unsigned secs = 0, rsecs = 0, percent = 0;
367 base = para_basename(nmmd->filename);
369 return para_strdup("");
372 if (nmmd->chunks_total) {
373 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
374 / nmmd->chunks_total;
375 rsecs = (long long) nmmd->seconds_total *
376 (nmmd->chunks_total - nmmd->chunks_sent)
377 / nmmd->chunks_total;
378 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
379 / ((nmmd->chunks_total + 5) / 10);
381 ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
382 secs / 60, secs % 60,
383 rsecs / 60, rsecs % 60,
391 static char *get_status(struct misc_meta_data *nmmd)
393 char *bar, *ret, mtime[30] = "";
394 char *status, *flags; /* afs status info */
395 char *ut = uptime_str();
396 long offset = (nmmd->offset + 500) / 1000;
400 if (nmmd->audio_format >= 0) {
401 localtime_r(&nmmd->mtime, &mtime_tm);
402 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
404 /* report real status */
405 status = afs_status_tohuman(nmmd->afs_status_flags);
406 flags = afs_get_status_flags(nmmd->afs_status_flags);
407 bar = para_basename(nmmd->filename);
408 gettimeofday(&now, NULL);
410 "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n"
411 "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n"
412 "%s:%li\n" "%s:%s\n" "%s" "%s"
413 "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n",
414 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
415 status_item_list[SI_MTIME], mtime,
416 status_item_list[SI_LENGTH], nmmd->seconds_total,
417 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
419 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
420 status_item_list[SI_STATUS], status,
421 status_item_list[SI_STATUS_FLAGS], flags,
422 status_item_list[SI_SELECTOR], selectors[nmmd->selector_num].name,
424 status_item_list[SI_OFFSET], offset,
425 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
427 nmmd->audio_file_info,
429 status_item_list[SI_UPTIME], ut,
430 status_item_list[SI_STREAM_START],
431 (long unsigned)nmmd->stream_start.tv_sec,
432 (long unsigned)nmmd->stream_start.tv_usec,
433 status_item_list[SI_CURRENT_TIME],
434 (long unsigned)now.tv_sec,
435 (long unsigned)now.tv_usec
445 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
448 /* this has to match sender.h */
449 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
451 scd->sender_num = -1;
453 return -E_COMMAND_SYNTAX;
454 for (i = 0; senders[i].name; i++)
455 if (!strcmp(senders[i].name, argv[1]))
457 PARA_DEBUG_LOG("%d:%s\n", argc, argv[1]);
458 if (!senders[i].name)
459 return -E_COMMAND_SYNTAX;
461 for (i = 0; subcmds[i]; i++)
462 if (!strcmp(subcmds[i], argv[2]))
465 return -E_COMMAND_SYNTAX;
468 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
470 return -E_SENDER_CMD;
473 switch (scd->cmd_num) {
477 return -E_COMMAND_SYNTAX;
481 if (argc != 4 && argc != 5)
482 return -E_COMMAND_SYNTAX;
483 if (!inet_aton(argv[3], &scd->addr))
484 return -E_COMMAND_SYNTAX;
487 scd->netmask = atoi(argv[4]);
488 if (scd->netmask < 0 || scd->netmask > 32)
489 return -E_COMMAND_SYNTAX;
494 if (argc != 4 && argc != 5)
495 return -E_COMMAND_SYNTAX;
496 if (!inet_aton(argv[3], &scd->addr))
497 return -E_COMMAND_SYNTAX;
500 scd->port = atoi(argv[4]);
501 if (scd->port < 0 || scd->port > 65535)
502 return -E_COMMAND_SYNTAX;
506 return -E_COMMAND_SYNTAX;
511 static int com_sender(int fd, int argc, char **argv)
514 struct sender_command_data scd;
518 for (i = 0; senders[i].name; i++) {
519 char *tmp = make_message("%s%s\n",
520 msg? msg : "", senders[i].name);
524 ret = send_buffer(fd, msg);
528 ret = check_sender_args(argc, argv, &scd);
531 if (scd.sender_num < 0)
533 msg = senders[scd.sender_num].help();
534 send_buffer(fd, msg);
538 for (i = 0; i < 10; i++) {
540 if (mmd->sender_cmd_data.cmd_num >= 0) {
545 mmd->sender_cmd_data = scd;
549 return (i < 10)? 1 : -E_LOCK;
553 static int com_si(int fd, int argc, __a_unused char **argv)
557 char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
560 return -E_COMMAND_SYNTAX;
562 for (i = 0; selectors[i].name; i++) {
563 selector_string = para_strcat(selector_string, selectors[i].name);
564 selector_string = para_strcat(selector_string, " ");
566 for (i = 0; senders[i].name; i++) {
567 char *info = senders[i].info();
568 sender_info = para_strcat(sender_info, info);
570 sender_list = para_strcat(sender_list, senders[i].name);
571 sender_list = para_strcat(sender_list, " ");
574 ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
576 "connections (active/accepted/total): %u/%u/%u\n"
577 "current loglevel: %i\n"
578 "supported audio file selectors: %s\n"
579 "supported audio formats: %s\n"
580 "supported senders: %s\n"
584 mmd->active_connections,
589 supported_audio_formats(),
595 free(selector_string);
602 static int com_version(int socket_fd, int argc, __a_unused char **argv)
605 return -E_COMMAND_SYNTAX;
606 return send_buffer(socket_fd, "para_server-" PACKAGE_VERSION ", \""
609 "built: " BUILD_DATE "\n"
610 SYSTEM ", " CC_VERSION "\n"
615 static int com_sc(int socket_fd, int argc, char **argv)
618 int ret, old = 0, count = -1; /* print af change forever */
621 count = atoi(argv[1]);
624 if (old != mmd->num_played) {
625 old = mmd->num_played;
626 name = para_strdup(mmd->filename);
630 ret = send_va_buffer(socket_fd, "%s\n", name);
635 if (argc > 1 && !--count)
643 static int com_sb(int socket_fd, int argc, char **argv)
646 int ret, nr = -1; /* status bar will be printed that many
647 * times. Negative value means: print
654 sb = get_sb_string(mmd);
656 ret = send_va_buffer(socket_fd, "%s\n", sb);
670 static int com_stat(int socket_fd, int argc, char **argv)
672 int ret, num = 0;/* status will be printed that many
673 * times. num <= 0 means: print forever
675 struct misc_meta_data tmp, *nmmd = &tmp;
678 signal(SIGUSR1, dummy);
685 s = get_status(nmmd);
686 ret = send_buffer(socket_fd, s);
695 return -E_SERVER_CRASH;
701 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
705 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
706 char *perms = cmd_perms_itohuman(cmd->perms);
707 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
718 /* always returns string that must be freed by the caller in handler */
719 static struct server_command *get_cmd_ptr(char *name, char **handler)
721 struct server_command *cmd = cmd_struct;
723 for (cmd = cmd_struct; cmd->name; cmd++)
724 if (!strcmp(cmd->name, name)) {
726 *handler = para_strdup("para_server"); /* server commands */
729 /* not found, look for commands supported by the current selector */
732 *handler = make_message("the %s selector",
733 selectors[mmd->selector_num].name);
734 cmd = selectors[mmd->selector_num].cmd_list;
736 for (; cmd->name; cmd++)
737 if (!strcmp(cmd->name, name))
743 static int com_help(int fd, int argc, char **argv)
745 struct server_command *cmd;
746 char *perms, *handler;
750 /* no argument given, print list of commands */
751 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
754 handler = para_strdup(selectors[mmd->selector_num].name);
755 cmd = selectors[mmd->selector_num].cmd_list;
757 ret = send_description(fd, cmd, handler, 0);
761 /* argument given for help */
762 cmd = get_cmd_ptr(argv[1], &handler);
767 perms = cmd_perms_itohuman(cmd->perms);
768 ret = send_va_buffer(fd,
770 "SYNOPSIS\n\t para_client %s\n"
773 "This command is handled by %s.\n\n"
775 "Needed privileges for %s: %s\n",
790 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
793 return -E_COMMAND_SYNTAX;
794 kill(getppid(), SIGHUP);
799 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
802 return -E_COMMAND_SYNTAX;
803 kill(getppid(), SIGTERM);
807 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
810 return -E_COMMAND_SYNTAX;
812 mmd->new_afs_status_flags |= AFS_PLAYING;
813 mmd->new_afs_status_flags &= ~AFS_NOMORE;
820 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
823 return -E_COMMAND_SYNTAX;
825 mmd->new_afs_status_flags &= ~AFS_PLAYING;
826 mmd->new_afs_status_flags &= ~AFS_REPOS;
827 mmd->new_afs_status_flags |= AFS_NEXT;
833 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
836 return -E_COMMAND_SYNTAX;
840 mmd->new_afs_status_flags &= ~AFS_PLAYING;
841 mmd->new_afs_status_flags &= ~AFS_NEXT;
846 static int com_chs(int fd, int argc, char **argv)
853 selector = para_strdup(selectors[mmd->selector_num].name);
855 ret = send_va_buffer(fd, "%s\n", selector);
859 for (i = 0; selectors[i].name; i++) {
860 if (strcmp(selectors[i].name, argv[1]))
863 mmd->selector_change = i;
868 return -E_BAD_SELECTOR;
872 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
875 return -E_COMMAND_SYNTAX;
878 mmd->new_afs_status_flags |= AFS_NEXT;
884 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
887 return -E_COMMAND_SYNTAX;
889 if (afs_playing() || afs_paused())
890 mmd->new_afs_status_flags |= AFS_NOMORE;
896 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
899 int ret, backwards = 0;
904 return -E_COMMAND_SYNTAX;
905 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
906 return -E_COMMAND_SYNTAX;
907 if (ret > 1 && c == '-')
908 backwards = 1; /* jmp backwards */
910 ret = -E_NO_AUDIO_FILE;
911 if (!mmd->chunks_total || !mmd->seconds_total)
913 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
915 promille -= 1000 * i / mmd->seconds_total;
917 promille += 1000 * i / mmd->seconds_total;
920 if (promille > 1000) {
921 mmd->new_afs_status_flags |= AFS_NEXT;
924 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
925 mmd->new_afs_status_flags |= AFS_REPOS;
926 mmd->new_afs_status_flags &= ~AFS_NEXT;
935 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
941 return -E_COMMAND_SYNTAX;
942 if (sscanf(argv[1], "%lu", &i) <= 0)
943 return -E_COMMAND_SYNTAX;
945 ret = -E_NO_AUDIO_FILE;
946 if (!mmd->chunks_total)
950 PARA_INFO_LOG("jumping to %lu%%\n", i);
951 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
952 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
953 mmd->chunks_sent, mmd->offset);
954 mmd->new_afs_status_flags |= AFS_REPOS;
955 mmd->new_afs_status_flags &= ~AFS_NEXT;
964 * check if perms are sufficient to exec a command having perms cmd_perms.
965 * Returns 0 if perms are sufficient, -E_PERM otherwise.
967 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
969 PARA_DEBUG_LOG("%s", "checking permissions\n");
970 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
974 * Parse first string from *cmd and lookup in table of valid commands.
975 * On error, NULL is returned.
977 static struct server_command *parse_cmd(const char *cmdstr)
982 sscanf(cmdstr, "%200s%n", buf, &n);
986 return get_cmd_ptr(buf, NULL);
989 long int para_rand(long unsigned max)
991 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
994 /* Open user_list file, returns pointer to opened file on success,
997 static FILE *open_user_list(char *file)
999 PARA_DEBUG_LOG("opening user list %s\n", file);
1000 return fopen(file, "r");
1004 * lookup user in user_list file. Fills in a user struct containing
1005 * filename of the user's public key as well as the permissions of that user.
1006 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1008 static int get_user(struct user *user) {
1012 /* keyword, user, key, perms */
1013 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1016 file_ptr = open_user_list(user_list);
1019 while (fgets(line, MAXLINE, file_ptr)) {
1020 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1021 // "from config file\n", __func__, strlen(line));
1022 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1024 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1025 PARA_DEBUG_LOG("found entry for %s\n", n);
1026 strcpy(user->name, n);
1027 strcpy(user->pubkey_file, k);
1030 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1031 tmp[0], tmp[1], tmp[2], tmp[3]);
1032 PARA_DEBUG_LOG("found %i perm entries\n",
1037 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1039 if (!strcmp(tmp[num], "AFS_READ"))
1041 user->perms | AFS_READ;
1042 else if (!strcmp(tmp[num], "AFS_WRITE"))
1044 user->perms | AFS_WRITE;
1045 else if (!strcmp(tmp[num], "DB_READ"))
1046 user->perms = user->perms | DB_READ;
1047 else if (!strcmp(tmp[num], "DB_WRITE"))
1048 user->perms = user->perms | DB_WRITE;
1049 else /* unknown permission */
1050 PARA_WARNING_LOG("unknown permission:"
1061 static void init_rc4_keys(void)
1065 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1066 rc4_buf[i] = para_rand(256);
1067 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1068 (unsigned char) rc4_buf[0],
1069 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1070 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1071 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1074 static void rc4_recv(unsigned long len, const unsigned char *indata,
1075 unsigned char *outdata, __a_unused void *private_data)
1077 RC4(&rc4_recv_key, len, indata, outdata);
1080 static void rc4_send(unsigned long len, const unsigned char *indata,
1081 unsigned char *outdata, __a_unused void *private_data)
1083 RC4(&rc4_send_key, len, indata, outdata);
1086 int handle_connect(int fd, struct sockaddr_in *addr)
1088 int numbytes, ret, argc, use_rc4 = 0;
1089 char buf[STRINGSIZE];
1090 unsigned char crypt_buf[MAXLINE];
1092 struct server_command *cmd = NULL;
1093 long unsigned challenge_nr, chall_response;
1095 char *p, *command = NULL;
1097 signal(SIGCHLD, SIG_IGN);
1098 signal(SIGINT, SIG_DFL);
1099 signal(SIGTERM, SIG_DFL);
1100 signal(SIGHUP, SIG_DFL);
1101 signal(SIGUSR1, SIG_IGN);
1104 challenge_nr = random();
1105 /* send Welcome message */
1106 ret = send_va_buffer(fd, "This is para_server, version "
1107 PACKAGE_VERSION ".\n" );
1110 /* recv auth request line */
1111 ret = recv_buffer(fd, buf, sizeof(buf));
1120 if (strncmp(buf, "auth ", 5))
1123 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1124 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1126 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1129 // strcpy(u.name, buf + 5); /* ok, but ugly */
1130 PARA_DEBUG_LOG("received %s request for user %s\n",
1131 use_rc4? "rc4" : "auth", u.name);
1132 /* lookup user in list file */
1133 if ((ret = get_user(&u)) < 0)
1135 if (!ret) { /* user not found */
1136 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1140 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1144 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1145 /* We can't use send_buffer here since buf may contain null bytes */
1146 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1149 /* recv decrypted number */
1150 numbytes = recv_buffer(fd, buf, sizeof(buf));
1157 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1158 || chall_response != challenge_nr)
1160 /* auth successful. Send 'Proceed' message */
1161 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1162 sprintf(buf, "%s", PROCEED_MSG);
1165 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1166 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1169 numbytes = ret + strlen(PROCEED_MSG) + 1;
1171 numbytes = strlen(buf);
1172 ret = send_bin_buffer(fd, buf, numbytes);
1176 enable_crypt(fd, rc4_recv, rc4_send, NULL);
1178 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1179 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1180 ret = -E_COMMAND_SYNTAX;
1181 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1183 command = para_strcat(command, buf);
1184 if ((p = strstr(command, EOC_MSG))) {
1194 if (!(cmd = parse_cmd(command)))
1196 /* valid command, check permissions */
1197 ret = check_perms(u.perms, cmd);
1200 /* valid command and sufficient perms */
1202 argc = split_args(command, &argv, "\n");
1204 mmd->num_commands++;
1206 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1207 inet_ntoa(addr->sin_addr));
1208 ret = cmd->handler(fd, argc, argv);
1214 if (ret != -E_SEND && ret != -E_RECV) {
1215 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1216 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1223 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1225 mmd->active_connections--;