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 void (*crypt_function_recv)(unsigned long len, const unsigned char *indata,
36 unsigned char *outdata) = NULL;
37 void (*crypt_function_send)(unsigned long len, const unsigned char *indata,
38 unsigned char *outdata) = NULL;
39 static RC4_KEY rc4_recv_key;
40 static RC4_KEY rc4_send_key;
41 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
43 extern const char *status_item_list[NUM_STAT_ITEMS];
44 extern struct misc_meta_data *mmd;
45 extern struct gengetopt_args_info conf;
46 extern struct audio_file_selector selectors[];
47 extern struct audio_format afl[];
48 extern struct sender senders[];
49 extern char *user_list;
50 struct sockaddr_in *in_addr;
52 static int com_si(int, int, char **);
53 static int com_version(int, int, char **);
54 static int com_sb(int, int, char **);
55 static int com_sc(int, int, char **);
56 static int com_stat(int, int, char **);
57 static int com_help(int, int, char **);
58 static int com_hup(int, int, char **);
59 static int com_term(int, int, char **);
60 static int com_play(int, int, char **);
61 static int com_stop(int, int, char **);
62 static int com_pause(int, int, char **);
63 static int com_next(int, int, char **);
64 static int com_nomore(int, int, char **);
65 static int com_chs(int, int, char **);
66 static int com_ff(int, int, char **);
67 static int com_jmp(int, int, char **);
68 static int com_sender(int, int, char **);
71 /* commands that are handled by the server itself */
72 static struct server_command cmd_struct[] = {
76 .perms = DB_READ | DB_WRITE,
77 .description = "change the current audio file selector",
78 .synopsis = "chs [new_selector]",
80 "Shutdown the current selector and activate new_selector. If no\n"
81 "argument was given, print the name of the current selector.\n"
87 .perms = AFS_READ | AFS_WRITE,
88 .description = "jmp amount of time forwards or backwards "
89 "in current audio file",
90 .synopsis = "ff n[-]",
93 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
94 "\tand enqueue a request to jump n seconds forwards or backwards\n"
95 "\tin the current audio file.\n"
101 "\tjumps 30 seconds backwards.\n"
109 .description = "print help text",
110 .synopsis = "help [command]",
113 "Without any arguments, help prints a list of availible commands. When\n"
114 "issued with a command name as first argument, print out a description\n"
115 "for that command.\n"
123 .description = "force reload of config file and log file",
127 "After rereading the config file, a signal is sent to all children\n"
128 "which forces them to close/reopen the log file.\n"
135 .perms = AFS_READ | AFS_WRITE,
136 .description = "jmp to given position in current audio file",
137 .synopsis = "jmp [n]",
140 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
141 "\tand enqueue a request to jump to n% of the current audio file,\n"
142 "\twhere 0 <= n <= 100.\n"
149 .perms = AFS_READ | AFS_WRITE,
150 .description = "skip rest of current audio file",
154 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
155 "\tplaying, change audio file immediately. Equivalent to stop\n"
156 "\tif paused, NOP if stopped.\n"
163 .handler = com_nomore,
164 .perms = AFS_READ | AFS_WRITE,
165 .description = "stop playing after current audio file",
166 .synopsis = "nomore",
169 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
170 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
171 "the 'N' (next audio file) bit being set.\n"
173 "Use this command instead of stop if you don't like\n"
180 .handler = com_pause,
181 .perms = AFS_READ | AFS_WRITE,
182 .description = "pause current audio file",
186 "\tClear the 'P' (playing) bit of the afs status flags.\n"
193 .perms = AFS_READ | AFS_WRITE,
194 .description = "start playing or resume playing when paused",
198 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
199 "\tresults in starting/continuing to stream.\n"
207 .description = "print status bar for current audio file",
208 .synopsis = "sb [n]",
211 "Without any arguments, sb continuously prints a status bar of the form\n"
213 " 12:34 [56:12] (56%) filename\n"
215 "indicating playing time, remaining time, percentage and the name of\n"
216 "the file beeing streamed. Use the optional number n to let stat exit\n"
217 "after having displayed the status bar n times.\n"
224 .description = "print name of audio file whenever it changes",
225 .synopsis = "sc [n]",
228 "\tsc prints exactly one line (the filename of the audio file\n"
229 "\tbeing played) whenever the audio file changes. Stops after\n"
230 "\tn iterations, or never if n is not specified.\n"
235 .handler = com_sender,
236 .perms = AFS_READ | AFS_WRITE,
237 .description = "control paraslash internal senders",
238 .synopsis = "sender [s cmd [arguments]]",
241 "send command cmd to sender s. cmd may be one of the following:\n"
242 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
243 "support each command. Try e.g. 'para_client sender http help' for\n"
244 "more information about the http sender. If no argument is given,\n"
245 "print out a list of all senders that are compiled in.\n"
252 .description = "print server info",
255 "Print server uptime and other information.\n"
262 .description = "print status info for current audio file",
263 .synopsis = "stat [n]",
266 "\tWithout any arguments, stat continuously prints status messages\n"
267 "\tof the audio file being streamed. Use the optional number n\n"
268 "\tto let stat exit after having displayed status n times.\n"
275 .perms = AFS_READ | AFS_WRITE,
276 .description = "stop playing",
280 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
287 .perms = AFS_READ | AFS_WRITE,
288 .description = "terminate para_server",
292 "Shuts down the server. Instead of this command, you can also send\n"
293 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
298 .handler = com_version,
300 .description = "print server's version",
301 .synopsis = "version",
303 "Show version and other info\n"
305 /* this indicates the end of the list. Do not touch. */
311 static void dummy(__a_unused int s)
314 static void mmd_dup(struct misc_meta_data *new_mmd)
322 * compute human readable string containing
323 * afs_status for given integer value
325 static char *afs_status_tohuman(unsigned int flags)
327 if (flags & AFS_PLAYING)
328 return para_strdup("playing");
329 else if (flags & AFS_NEXT)
330 return para_strdup("stopped");
332 return para_strdup("paused");
336 * return human readable permission string. Never returns NULL.
338 char *cmd_perms_itohuman(unsigned int perms)
340 char *msg = para_malloc(7 * sizeof(char));
342 msg[0] = perms & DB_READ? 'd' : '-';
343 msg[1] = perms & DB_WRITE? 'D' : '-';
344 msg[2] = perms & AFS_READ? 'a' : '-';
345 msg[3] = perms & AFS_WRITE? 'A' : '-';
351 * Never returns NULL.
353 static char *afs_get_status_flags(unsigned int flags)
355 char *msg = para_malloc(5 * sizeof(char));
357 msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
358 msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
359 msg[2] = (flags & AFS_NEXT)? 'N' : '_';
360 msg[3] = (flags & AFS_REPOS)? 'R' : '_';
366 * compute status bar string. Never returns NULL
368 char *get_sb_string(struct misc_meta_data *nmmd)
371 long long unsigned secs = 0, rsecs = 0, percent = 0;
373 base = para_basename(nmmd->filename);
375 return para_strdup("");
378 if (nmmd->chunks_total) {
379 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
380 / nmmd->chunks_total;
381 rsecs = (long long) nmmd->seconds_total *
382 (nmmd->chunks_total - nmmd->chunks_sent)
383 / nmmd->chunks_total;
384 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
385 / ((nmmd->chunks_total + 5) / 10);
387 ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
388 secs / 60, secs % 60,
389 rsecs / 60, rsecs % 60,
397 static char *get_status(struct misc_meta_data *nmmd)
399 char *bar, *ret, mtime[30] = "";
400 char *status, *flags; /* afs status info */
401 char *ut = uptime_str();
402 long offset = (nmmd->offset + 500) / 1000;
406 if (nmmd->audio_format >= 0) {
407 localtime_r(&nmmd->mtime, &mtime_tm);
408 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
410 /* report real status */
411 status = afs_status_tohuman(nmmd->afs_status_flags);
412 flags = afs_get_status_flags(nmmd->afs_status_flags);
413 bar = para_basename(nmmd->filename);
414 gettimeofday(&now, NULL);
416 "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n"
417 "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n"
418 "%s:%li\n" "%s:%s\n" "%s" "%s"
419 "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n",
420 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
421 status_item_list[SI_MTIME], mtime,
422 status_item_list[SI_LENGTH], nmmd->seconds_total,
423 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
425 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
426 status_item_list[SI_STATUS], status,
427 status_item_list[SI_STATUS_FLAGS], flags,
428 status_item_list[SI_SELECTOR], selectors[nmmd->selector_num].name,
430 status_item_list[SI_OFFSET], offset,
431 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
433 nmmd->audio_file_info,
435 status_item_list[SI_UPTIME], ut,
436 status_item_list[SI_STREAM_START],
437 (long unsigned)nmmd->stream_start.tv_sec,
438 (long unsigned)nmmd->stream_start.tv_usec,
439 status_item_list[SI_CURRENT_TIME],
440 (long unsigned)now.tv_sec,
441 (long unsigned)now.tv_usec
451 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
454 /* this has to match sender.h */
455 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
457 scd->sender_num = -1;
459 return -E_COMMAND_SYNTAX;
460 for (i = 0; senders[i].name; i++)
461 if (!strcmp(senders[i].name, argv[1]))
463 PARA_DEBUG_LOG("%d:%s\n", argc, argv[1]);
464 if (!senders[i].name)
465 return -E_COMMAND_SYNTAX;
467 for (i = 0; subcmds[i]; i++)
468 if (!strcmp(subcmds[i], argv[2]))
471 return -E_COMMAND_SYNTAX;
474 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
476 return -E_SENDER_CMD;
479 switch (scd->cmd_num) {
483 return -E_COMMAND_SYNTAX;
487 if (argc != 4 && argc != 5)
488 return -E_COMMAND_SYNTAX;
489 if (!inet_aton(argv[3], &scd->addr))
490 return -E_COMMAND_SYNTAX;
493 scd->netmask = atoi(argv[4]);
494 if (scd->netmask < 0 || scd->netmask > 32)
495 return -E_COMMAND_SYNTAX;
500 if (argc != 4 && argc != 5)
501 return -E_COMMAND_SYNTAX;
502 if (!inet_aton(argv[3], &scd->addr))
503 return -E_COMMAND_SYNTAX;
506 scd->port = atoi(argv[4]);
507 if (scd->port < 0 || scd->port > 65535)
508 return -E_COMMAND_SYNTAX;
512 return -E_COMMAND_SYNTAX;
517 static int com_sender(int fd, int argc, char **argv)
520 struct sender_command_data scd;
524 for (i = 0; senders[i].name; i++) {
525 char *tmp = make_message("%s%s\n",
526 msg? msg : "", senders[i].name);
530 ret = send_buffer(fd, msg);
534 ret = check_sender_args(argc, argv, &scd);
537 if (scd.sender_num < 0)
539 msg = senders[scd.sender_num].help();
540 send_buffer(fd, msg);
544 for (i = 0; i < 10; i++) {
546 if (mmd->sender_cmd_data.cmd_num >= 0) {
551 mmd->sender_cmd_data = scd;
555 return (i < 10)? 1 : -E_LOCK;
559 static int com_si(int fd, int argc, __a_unused char **argv)
563 char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
566 return -E_COMMAND_SYNTAX;
568 for (i = 0; selectors[i].name; i++) {
569 selector_string = para_strcat(selector_string, selectors[i].name);
570 selector_string = para_strcat(selector_string, " ");
572 for (i = 0; senders[i].name; i++) {
573 char *info = senders[i].info();
574 sender_info = para_strcat(sender_info, info);
576 sender_list = para_strcat(sender_list, senders[i].name);
577 sender_list = para_strcat(sender_list, " ");
580 ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
582 "connections (active/accepted/total): %u/%u/%u\n"
583 "current loglevel: %i\n"
584 "supported audio file selectors: %s\n"
585 "supported audio formats: %s\n"
586 "supported senders: %s\n"
590 mmd->active_connections,
595 SUPPORTED_AUDIO_FORMATS,
601 free(selector_string);
608 static int com_version(int socket_fd, int argc, __a_unused char **argv)
611 return -E_COMMAND_SYNTAX;
612 return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
614 "built: " BUILD_DATE "\n"
615 SYSTEM ", " CC_VERSION "\n"
620 static int com_sc(int socket_fd, int argc, char **argv)
623 int ret, old = 0, count = -1; /* print af change forever */
626 count = atoi(argv[1]);
629 if (old != mmd->num_played) {
630 old = mmd->num_played;
631 name = para_strdup(mmd->filename);
635 ret = send_va_buffer(socket_fd, "%s\n", name);
640 if (argc > 1 && !--count)
648 static int com_sb(int socket_fd, int argc, char **argv)
651 int ret, nr = -1; /* status bar will be printed that many
652 * times. Negative value means: print
659 sb = get_sb_string(mmd);
661 ret = send_va_buffer(socket_fd, "%s\n", sb);
675 static int com_stat(int socket_fd, int argc, char **argv)
677 int ret, num = 0;/* status will be printed that many
678 * times. num <= 0 means: print forever
680 struct misc_meta_data tmp, *nmmd = &tmp;
683 signal(SIGUSR1, dummy);
690 s = get_status(nmmd);
691 ret = send_buffer(socket_fd, s);
698 usleep(500000 * 100);
704 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
708 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
709 char *perms = cmd_perms_itohuman(cmd->perms);
710 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
721 /* always returns string that must be freed by the caller in handler */
722 static struct server_command *get_cmd_ptr(char *name, char **handler)
724 struct server_command *cmd = cmd_struct;
726 for (cmd = cmd_struct; cmd->name; cmd++)
727 if (!strcmp(cmd->name, name)) {
729 *handler = para_strdup("para_server"); /* server commands */
732 /* not found, look for commands supported by the current selector */
735 *handler = make_message("the %s selector",
736 selectors[mmd->selector_num].name);
737 cmd = selectors[mmd->selector_num].cmd_list;
739 for (; cmd->name; cmd++)
740 if (!strcmp(cmd->name, name))
746 static int com_help(int fd, int argc, char **argv)
748 struct server_command *cmd;
749 char *perms, *handler;
753 /* no argument given, print list of commands */
754 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
757 handler = para_strdup(selectors[mmd->selector_num].name);
758 cmd = selectors[mmd->selector_num].cmd_list;
760 ret = send_description(fd, cmd, handler, 0);
764 /* argument given for help */
765 cmd = get_cmd_ptr(argv[1], &handler);
770 perms = cmd_perms_itohuman(cmd->perms);
771 ret = send_va_buffer(fd,
773 "SYNOPSIS\n\t para_client %s\n"
776 "This command is handled by %s.\n\n"
778 "Needed privileges for %s: %s\n",
793 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
796 return -E_COMMAND_SYNTAX;
797 kill(getppid(), SIGHUP);
802 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
805 return -E_COMMAND_SYNTAX;
806 kill(getppid(), SIGTERM);
810 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
813 return -E_COMMAND_SYNTAX;
815 mmd->new_afs_status_flags |= AFS_PLAYING;
816 mmd->new_afs_status_flags &= ~AFS_NOMORE;
823 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
826 return -E_COMMAND_SYNTAX;
828 mmd->new_afs_status_flags &= ~AFS_PLAYING;
829 mmd->new_afs_status_flags &= ~AFS_REPOS;
830 mmd->new_afs_status_flags |= AFS_NEXT;
836 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
839 return -E_COMMAND_SYNTAX;
843 mmd->new_afs_status_flags &= ~AFS_PLAYING;
844 mmd->new_afs_status_flags &= ~AFS_NEXT;
849 static int com_chs(int fd, int argc, char **argv)
856 selector = para_strdup(selectors[mmd->selector_num].name);
858 ret = send_va_buffer(fd, "%s\n", selector);
862 for (i = 0; selectors[i].name; i++) {
863 if (strcmp(selectors[i].name, argv[1]))
866 mmd->selector_change = i;
871 return -E_BAD_SELECTOR;
875 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
878 return -E_COMMAND_SYNTAX;
881 mmd->new_afs_status_flags |= AFS_NEXT;
887 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
890 return -E_COMMAND_SYNTAX;
892 if (afs_playing() || afs_paused())
893 mmd->new_afs_status_flags |= AFS_NOMORE;
899 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
902 int ret, backwards = 0;
907 return -E_COMMAND_SYNTAX;
908 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
909 return -E_COMMAND_SYNTAX;
910 if (ret > 1 && c == '-')
911 backwards = 1; /* jmp backwards */
913 ret = -E_NO_AUDIO_FILE;
914 if (!mmd->chunks_total || !mmd->seconds_total)
916 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
918 promille -= 1000 * i / mmd->seconds_total;
920 promille += 1000 * i / mmd->seconds_total;
923 if (promille > 1000) {
924 mmd->new_afs_status_flags |= AFS_NEXT;
927 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
928 mmd->new_afs_status_flags |= AFS_REPOS;
929 mmd->new_afs_status_flags &= ~AFS_NEXT;
938 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
944 return -E_COMMAND_SYNTAX;
945 if (sscanf(argv[1], "%lu", &i) <= 0)
946 return -E_COMMAND_SYNTAX;
948 ret = -E_NO_AUDIO_FILE;
949 if (!mmd->chunks_total)
953 PARA_INFO_LOG("jumping to %lu%%\n", i);
954 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
955 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
956 mmd->chunks_sent, mmd->offset);
957 mmd->new_afs_status_flags |= AFS_REPOS;
958 mmd->new_afs_status_flags &= ~AFS_NEXT;
967 * check if perms are sufficient to exec a command having perms cmd_perms.
968 * Returns 0 if perms are sufficient, -E_PERM otherwise.
970 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
972 PARA_DEBUG_LOG("%s", "checking permissions\n");
973 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
977 * Parse first string from *cmd and lookup in table of valid commands.
978 * On error, NULL is returned.
980 static struct server_command *parse_cmd(const char *cmdstr)
985 sscanf(cmdstr, "%200s%n", buf, &n);
989 return get_cmd_ptr(buf, NULL);
992 long int para_rand(long unsigned max)
994 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
997 /* Open user_list file, returns pointer to opened file on success,
1000 static FILE *open_user_list(char *file)
1002 PARA_DEBUG_LOG("opening user list %s\n", file);
1003 return fopen(file, "r");
1007 * lookup user in user_list file. Fills in a user struct containing
1008 * filename of the user's public key as well as the permissions of that user.
1009 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1011 static int get_user(struct user *user) {
1015 /* keyword, user, key, perms */
1016 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1019 file_ptr = open_user_list(user_list);
1022 while (fgets(line, MAXLINE, file_ptr)) {
1023 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1024 // "from config file\n", __func__, strlen(line));
1025 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1027 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1028 PARA_DEBUG_LOG("found entry for %s\n", n);
1029 strcpy(user->name, n);
1030 strcpy(user->pubkey_file, k);
1033 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1034 tmp[0], tmp[1], tmp[2], tmp[3]);
1035 PARA_DEBUG_LOG("found %i perm entries\n",
1040 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1042 if (!strcmp(tmp[num], "AFS_READ"))
1044 user->perms | AFS_READ;
1045 else if (!strcmp(tmp[num], "AFS_WRITE"))
1047 user->perms | AFS_WRITE;
1048 else if (!strcmp(tmp[num], "DB_READ"))
1049 user->perms = user->perms | DB_READ;
1050 else if (!strcmp(tmp[num], "DB_WRITE"))
1051 user->perms = user->perms | DB_WRITE;
1052 else /* unknown permission */
1053 PARA_WARNING_LOG("unknown permission:"
1064 static void init_rc4_keys(void)
1068 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1069 rc4_buf[i] = para_rand(256);
1070 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1071 (unsigned char) rc4_buf[0],
1072 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1073 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1074 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1077 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1079 RC4(&rc4_recv_key, len, indata, outdata);
1082 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1084 RC4(&rc4_send_key, len, indata, outdata);
1087 int handle_connect(int fd, struct sockaddr_in *addr)
1089 int numbytes, ret, argc, use_rc4 = 0;
1090 char buf[STRINGSIZE];
1091 unsigned char crypt_buf[MAXLINE];
1093 struct server_command *cmd = NULL;
1094 long unsigned challenge_nr, chall_response;
1096 char *p, *command = NULL;
1098 signal(SIGCHLD, SIG_IGN);
1099 signal(SIGINT, SIG_DFL);
1100 signal(SIGTERM, SIG_DFL);
1101 signal(SIGHUP, SIG_DFL);
1102 signal(SIGUSR1, SIG_IGN);
1105 challenge_nr = random();
1106 /* send Welcome message */
1107 ret = send_va_buffer(fd, "This is para_server, version " 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 crypt_function_recv = rc4_recv;
1177 crypt_function_send = rc4_send;
1178 PARA_INFO_LOG("%s", "rc4 encryption activated\n");
1181 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1182 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1183 ret = -E_COMMAND_SYNTAX;
1184 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1186 command = para_strcat(command, buf);
1187 if ((p = strstr(command, EOC_MSG))) {
1197 if (!(cmd = parse_cmd(command)))
1199 /* valid command, check permissions */
1200 ret = check_perms(u.perms, cmd);
1203 /* valid command and sufficient perms */
1205 argc = split_args(command, &argv, "\n");
1207 mmd->num_commands++;
1209 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1210 inet_ntoa(addr->sin_addr));
1211 ret = cmd->handler(fd, argc, argv);
1217 if (ret != -E_SEND && ret != -E_RECV) {
1218 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1219 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1226 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1228 mmd->active_connections--;