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 <malloc.h> /* mallinfo */
22 #include <sys/time.h> /* gettimeofday */
24 #include "server.cmdline.h"
30 #include <openssl/rc4.h>
36 void (*crypt_function_recv)(unsigned long len, const unsigned char *indata,
37 unsigned char *outdata) = NULL;
38 void (*crypt_function_send)(unsigned long len, const unsigned char *indata,
39 unsigned char *outdata) = NULL;
40 static RC4_KEY rc4_recv_key;
41 static RC4_KEY rc4_send_key;
42 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
44 extern const char *status_item_list[NUM_STAT_ITEMS];
45 extern struct misc_meta_data *mmd;
46 extern struct gengetopt_args_info conf;
47 extern struct audio_file_selector dblist[];
48 extern struct audio_format afl[];
49 extern struct sender senders[];
50 extern char *user_list;
51 struct sockaddr_in *in_addr;
53 static int com_si(int, int, char **);
54 static int com_version(int, int, char **);
55 static int com_sb(int, int, char **);
56 static int com_sc(int, int, char **);
57 static int com_stat(int, int, char **);
58 static int com_help(int, int, char **);
59 static int com_hup(int, int, char **);
60 static int com_term(int, int, char **);
61 static int com_play(int, int, char **);
62 static int com_stop(int, int, char **);
63 static int com_pause(int, int, char **);
64 static int com_next(int, int, char **);
65 static int com_nomore(int, int, char **);
66 static int com_chs(int, int, char **);
67 static int com_ff(int, int, char **);
68 static int com_jmp(int, int, char **);
69 static int com_sender(int, int, char **);
72 /* commands that are handled by the server itself */
73 static struct server_command cmd_struct[] = {
77 .perms = DB_READ | DB_WRITE,
78 .description = "change the current audio file selector",
79 .synopsis = "chs [new_selector]",
81 "Shutdown the current selector and activate new_selector. If no\n"
82 "argument was given, print the name of the current selector.\n"
88 .perms = AFS_READ | AFS_WRITE,
89 .description = "jmp amount of time forwards or backwards "
90 "in current audio file",
91 .synopsis = "ff n[-]",
94 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
95 "\tand enqueue a request to jump n seconds forwards or backwards\n"
96 "\tin the current audio file.\n"
102 "\tjumps 30 seconds backwards.\n"
110 .description = "print help text",
111 .synopsis = "help [command]",
114 "Without any arguments, help prints a list of availible commands. When\n"
115 "issued with a command name as first argument, print out a description\n"
116 "for that command.\n"
124 .description = "force reload of config file and log file",
128 "After rereading the config file, a signal is sent to all children\n"
129 "which forces them to close/reopen the log file.\n"
136 .perms = AFS_READ | AFS_WRITE,
137 .description = "jmp to given position in current audio file",
138 .synopsis = "jmp [n]",
141 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
142 "\tand enqueue a request to jump to n% of the current audio file,\n"
143 "\twhere 0 <= n <= 100.\n"
150 .perms = AFS_READ | AFS_WRITE,
151 .description = "skip rest of current audio file",
155 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
156 "\tplaying, change audio file immediately. Equivalent to stop\n"
157 "\tif paused, NOP if stopped.\n"
164 .handler = com_nomore,
165 .perms = AFS_READ | AFS_WRITE,
166 .description = "stop playing after current audio file",
167 .synopsis = "nomore",
170 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
171 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
172 "the 'N' (next audio file) bit being set.\n"
174 "Use this command instead of stop if you don't like\n"
181 .handler = com_pause,
182 .perms = AFS_READ | AFS_WRITE,
183 .description = "pause current audio file",
187 "\tClear the 'P' (playing) bit of the afs status flags.\n"
194 .perms = AFS_READ | AFS_WRITE,
195 .description = "start playing or resume playing when paused",
199 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
200 "\tresults in starting/continuing to stream.\n"
208 .description = "print status bar for current audio file",
209 .synopsis = "sb [n]",
212 "Without any arguments, sb continuously prints a status bar of the form\n"
214 " 12:34 [56:12] (56%) filename\n"
216 "indicating playing time, remaining time, percentage and the name of\n"
217 "the file beeing streamed. Use the optional number n to let stat exit\n"
218 "after having displayed the status bar n times.\n"
225 .description = "print name of audio file whenever it changes",
226 .synopsis = "sc [n]",
229 "\tsc prints exactly one line (the filename of the audio file\n"
230 "\tbeing played) whenever the audio file changes. Stops after\n"
231 "\tn iterations, or never if n is not specified.\n"
236 .handler = com_sender,
237 .perms = AFS_READ | AFS_WRITE,
238 .description = "control paraslash internal senders",
239 .synopsis = "sender [s cmd [arguments]]",
242 "send command cmd to sender s. cmd may be one of the following:\n"
243 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
244 "support each command. Try e.g. 'para_client sender http help' for\n"
245 "more information about the http sender. If no argument is given,\n"
246 "print out a list of all senders that are compiled in.\n"
253 .description = "print server info",
256 "Print server uptime and other information.\n"
263 .description = "print status info for current audio file",
264 .synopsis = "stat [n]",
267 "\tWithout any arguments, stat continuously prints status messages\n"
268 "\tof the audio file being streamed. Use the optional number n\n"
269 "\tto let stat exit after having displayed status n times.\n"
276 .perms = AFS_READ | AFS_WRITE,
277 .description = "stop playing",
281 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
288 .perms = AFS_READ | AFS_WRITE,
289 .description = "terminate para_server",
293 "Shuts down the server. Instead of this command, you can also send\n"
294 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
299 .handler = com_version,
301 .description = "print server's version",
302 .synopsis = "version",
304 "Show version and other info\n"
306 /* this indicates the end of the list. Do not touch. */
312 static void dummy(__unused int s)
315 static void mmd_dup(struct misc_meta_data *new_mmd)
323 * compute human readable string containing
324 * afs_status for given integer value
326 static char *afs_status_tohuman(unsigned int flags)
328 if (flags & AFS_PLAYING)
329 return para_strdup("playing");
330 else if (flags & AFS_NEXT)
331 return para_strdup("stopped");
333 return para_strdup("paused");
337 * return human readable permission string. Never returns NULL.
339 char *cmd_perms_itohuman(unsigned int perms)
341 char *msg = para_malloc(7 * sizeof(char));
343 msg[0] = perms & DB_READ? 'd' : '-';
344 msg[1] = perms & DB_WRITE? 'D' : '-';
345 msg[2] = perms & AFS_READ? 'a' : '-';
346 msg[3] = perms & AFS_WRITE? 'A' : '-';
352 * Never returns NULL.
354 static char *afs_get_status_flags(unsigned int flags)
356 char *msg = para_malloc(5 * sizeof(char));
358 msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
359 msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
360 msg[2] = (flags & AFS_NEXT)? 'N' : '_';
361 msg[3] = (flags & AFS_REPOS)? 'R' : '_';
367 * compute status bar string. Never returns NULL
369 char *get_sb_string(struct misc_meta_data *nmmd)
372 long long unsigned secs = 0, rsecs = 0, percent = 0;
374 base = para_basename(nmmd->filename);
376 return para_strdup("");
379 if (nmmd->chunks_total) {
380 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
381 / nmmd->chunks_total;
382 rsecs = (long long) nmmd->seconds_total *
383 (nmmd->chunks_total - nmmd->chunks_sent)
384 / nmmd->chunks_total;
385 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
386 / ((nmmd->chunks_total + 5) / 10);
388 ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
389 secs / 60, secs % 60,
390 rsecs / 60, rsecs % 60,
398 static char *get_status(struct misc_meta_data *nmmd)
400 char *bar, *ret, mtime[30] = "";
401 char *status, *flags; /* afs status info */
402 char *ut = uptime_str();
403 long offset = (nmmd->offset + 500) / 1000;
407 if (nmmd->audio_format >= 0) {
408 localtime_r(&nmmd->mtime, &mtime_tm);
409 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
411 /* report real status */
412 status = afs_status_tohuman(nmmd->afs_status_flags);
413 flags = afs_get_status_flags(nmmd->afs_status_flags);
414 bar = para_basename(nmmd->filename);
415 gettimeofday(&now, NULL);
417 "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n"
418 "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n"
419 "%s:%li\n" "%s:%s\n" "%s" "%s"
420 "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n",
421 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
422 status_item_list[SI_MTIME], mtime,
423 status_item_list[SI_LENGTH], nmmd->seconds_total,
424 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
426 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
427 status_item_list[SI_STATUS], status,
428 status_item_list[SI_STATUS_FLAGS], flags,
429 status_item_list[SI_SELECTOR], dblist[nmmd->selector_num].name,
431 status_item_list[SI_OFFSET], offset,
432 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
434 nmmd->audio_file_info,
436 status_item_list[SI_UPTIME], ut,
437 status_item_list[SI_STREAM_START], nmmd->stream_start.tv_sec,
438 nmmd->stream_start.tv_usec,
439 status_item_list[SI_CURRENT_TIME], now.tv_sec, now.tv_usec
449 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
452 /* this has to match sender.h */
453 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
455 scd->sender_num = -1;
457 return -E_COMMAND_SYNTAX;
458 for (i = 0; senders[i].name; i++)
459 if (!strcmp(senders[i].name, argv[0]))
461 // PARA_DEBUG_LOG("%d:%s\n", argc, argv[0]);
462 if (!senders[i].name)
463 return -E_COMMAND_SYNTAX;
465 for (i = 0; subcmds[i]; i++)
466 if (!strcmp(subcmds[i], argv[1]))
469 return -E_COMMAND_SYNTAX;
471 // scd->self = *in_addr;
473 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
475 return -E_SENDER_CMD;
478 switch (scd->cmd_num) {
482 return -E_COMMAND_SYNTAX;
486 if (argc != 2 && argc != 3)
487 return -E_COMMAND_SYNTAX;
488 if (!inet_aton(argv[2], &scd->addr))
489 return -E_COMMAND_SYNTAX;
492 scd->netmask = atoi(argv[3]);
493 if (scd->netmask < 0 || scd->netmask > 32)
494 return -E_COMMAND_SYNTAX;
499 if (argc != 2 && argc != 3)
500 return -E_COMMAND_SYNTAX;
501 if (!inet_aton(argv[2], &scd->addr))
502 return -E_COMMAND_SYNTAX;
505 scd->port = atoi(argv[3]);
506 if (scd->port < 0 || scd->port > 65535)
507 return -E_COMMAND_SYNTAX;
511 return -E_COMMAND_SYNTAX;
516 static int com_sender(int fd, int argc, char **argv)
519 struct sender_command_data scd;
523 for (i = 0; senders[i].name; i++) {
524 char *tmp = make_message("%s%s\n",
525 msg? msg : "", senders[i].name);
529 ret = send_buffer(fd, msg);
533 ret = check_sender_args(argc - 1, argv + 1, &scd);
536 if (scd.sender_num < 0)
538 msg = senders[scd.sender_num].help();
539 send_buffer(fd, msg);
543 for (i = 0; i < 10; i++) {
545 if (mmd->sender_cmd_data.cmd_num >= 0) {
550 mmd->sender_cmd_data = scd;
554 return (i < 10)? 1 : -E_LOCK;
558 static int com_si(int fd, int argc, __unused char **argv)
562 char *selectors = NULL, *sender_info = NULL, *sender_list = NULL;
563 struct mallinfo mi = mallinfo();
566 return -E_COMMAND_SYNTAX;
568 for (i = 0; dblist[i].name; i++) {
569 selectors = para_strcat(selectors, dblist[i].name);
570 selectors = para_strcat(selectors, " ");
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"
583 "connections (active/accepted/total): %u/%u/%u\n"
584 "current loglevel: %i\n"
585 "supported audio file selectors: %s\n"
586 "supported audio formats: %s\n"
587 "supported senders: %s\n"
592 mmd->active_connections,
597 SUPPORTED_AUDIO_FORMATS,
610 static int com_version(int socket_fd, int argc, __unused char **argv)
613 return -E_COMMAND_SYNTAX;
614 return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
616 "built: " BUILD_DATE "\n"
617 SYSTEM ", " CC_VERSION "\n"
622 static int com_sc(int socket_fd, int argc, char **argv)
625 int ret, old = 0, count = -1; /* print af change forever */
628 count = atoi(argv[1]);
631 if (old != mmd->num_played) {
632 old = mmd->num_played;
633 name = para_strdup(mmd->filename);
637 ret = send_va_buffer(socket_fd, "%s\n", name);
642 if (argc && !--count)
650 static int com_sb(int socket_fd, int argc, char **argv)
653 int ret, nr = -1; /* status bar will be printed that many
654 * times. Negative value means: print
661 sb = get_sb_string(mmd);
663 ret = send_va_buffer(socket_fd, "%s\n", sb);
677 static int com_stat(int socket_fd, int argc, char **argv)
679 int ret, num = 0;/* status will be printed that many
680 * times. num <= 0 means: print forever
682 struct misc_meta_data tmp, *nmmd = &tmp;
685 signal(SIGUSR1, dummy);
692 s = get_status(nmmd);
693 ret = send_buffer(socket_fd, s);
700 usleep(500000 * 100);
706 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
710 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
711 char *perms = cmd_perms_itohuman(cmd->perms);
712 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
723 /* always returns string that must be freed by the caller in handeler */
724 static struct server_command *get_cmd_ptr(char *name, char **handler)
726 struct server_command *cmd = cmd_struct;
728 for (cmd = cmd_struct; cmd->name; cmd++)
729 if (!strcmp(cmd->name, name)) {
731 *handler = para_strdup("para_server"); /* server commands */
734 /* not found, look for commands supported by the current selector */
737 *handler = make_message("the %s selector",
738 dblist[mmd->selector_num].name);
739 cmd = dblist[mmd->selector_num].cmd_list;
741 for (; cmd->name; cmd++)
742 if (!strcmp(cmd->name, name))
748 static int com_help(int fd, int argc, char **argv)
750 struct server_command *cmd;
751 char *perms, *handler;
755 /* no argument given, print list of commands */
756 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
759 handler = para_strdup(dblist[mmd->selector_num].name);
760 cmd = dblist[mmd->selector_num].cmd_list;
762 ret = send_description(fd, cmd, handler, 0);
766 /* argument given for help */
767 cmd = get_cmd_ptr(argv[1], &handler);
772 perms = cmd_perms_itohuman(cmd->perms);
773 ret = send_va_buffer(fd,
775 "SYNOPSIS\n\t para_client %s\n"
778 "This command is handled by %s.\n\n"
780 "Needed privileges for %s: %s\n",
795 static int com_hup(__unused int socket_fd, int argc, __unused char **argv)
798 return -E_COMMAND_SYNTAX;
799 kill(getppid(), SIGHUP);
804 static int com_term(__unused int socket_fd, int argc, __unused char **argv)
807 return -E_COMMAND_SYNTAX;
808 kill(getppid(), SIGTERM);
812 static int com_play(__unused int socket_fd, int argc, __unused char **argv)
815 return -E_COMMAND_SYNTAX;
817 mmd->new_afs_status_flags |= AFS_PLAYING;
818 mmd->new_afs_status_flags &= ~AFS_NOMORE;
825 static int com_stop(__unused int socket_fd, int argc, __unused char **argv)
828 return -E_COMMAND_SYNTAX;
830 mmd->new_afs_status_flags &= ~AFS_PLAYING;
831 mmd->new_afs_status_flags &= ~AFS_REPOS;
832 mmd->new_afs_status_flags |= AFS_NEXT;
838 static int com_pause(__unused int socket_fd, int argc, __unused char **argv)
841 return -E_COMMAND_SYNTAX;
845 mmd->new_afs_status_flags &= ~AFS_PLAYING;
846 mmd->new_afs_status_flags &= ~AFS_NEXT;
851 static int com_chs(int fd, int argc, char **argv)
858 selector = para_strdup(dblist[mmd->selector_num].name);
860 ret = send_va_buffer(fd, "%s\n", selector);
864 for (i = 0; dblist[i].name; i++) {
865 if (strcmp(dblist[i].name, argv[1]))
868 mmd->selector_change = i;
873 return -E_BAD_SELECTOR;
877 static int com_next(__unused int socket_fd, int argc, __unused char **argv)
880 return -E_COMMAND_SYNTAX;
883 mmd->new_afs_status_flags |= AFS_NEXT;
889 static int com_nomore(__unused int socket_fd, int argc, __unused char **argv)
892 return -E_COMMAND_SYNTAX;
894 if (afs_playing() || afs_paused())
895 mmd->new_afs_status_flags |= AFS_NOMORE;
901 static int com_ff(__unused int socket_fd, int argc, char **argv)
904 int ret, backwards = 0;
909 return -E_COMMAND_SYNTAX;
910 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
911 return -E_COMMAND_SYNTAX;
912 if (ret > 1 && c == '-')
913 backwards = 1; /* jmp backwards */
915 ret = -E_NO_AUDIO_FILE;
916 if (!mmd->chunks_total || !mmd->seconds_total)
918 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
920 promille -= 1000 * i / mmd->seconds_total;
922 promille += 1000 * i / mmd->seconds_total;
925 if (promille > 1000) {
926 mmd->new_afs_status_flags |= AFS_NEXT;
929 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
930 mmd->new_afs_status_flags |= AFS_REPOS;
931 mmd->new_afs_status_flags &= ~AFS_NEXT;
940 static int com_jmp(__unused int socket_fd, int argc, char **argv)
946 return -E_COMMAND_SYNTAX;
947 if (sscanf(argv[1], "%lu", &i) <= 0)
948 return -E_COMMAND_SYNTAX;
950 ret = -E_NO_AUDIO_FILE;
951 if (!mmd->chunks_total)
955 PARA_INFO_LOG("jumping to %lu%%\n", i);
956 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
957 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
958 mmd->chunks_sent, mmd->offset);
959 mmd->new_afs_status_flags |= AFS_REPOS;
960 mmd->new_afs_status_flags &= ~AFS_NEXT;
969 * check if perms are sufficient to exec a command having perms cmd_perms.
970 * Returns 0 if perms are sufficient, -E_PERM otherwise.
972 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
974 PARA_DEBUG_LOG("%s", "checking permissions\n");
975 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
979 * Parse first string from *cmd and lookup in table of valid commands.
980 * On error, NULL is returned.
982 static struct server_command *parse_cmd(const char *cmdstr)
987 sscanf(cmdstr, "%200s%n", buf, &n);
991 return get_cmd_ptr(buf, NULL);
994 long int para_rand(long unsigned max)
996 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
999 /* Open user_list file, returns pointer to opened file on success,
1002 static FILE *open_user_list(char *file)
1004 PARA_DEBUG_LOG("opening user list %s\n", file);
1005 return fopen(file, "r");
1009 * lookup user in user_list file. Fills in a user struct containing
1010 * filename of the user's public key as well as the permissions of that user.
1011 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1013 static int get_user(struct user *user) {
1017 /* keyword, user, key, perms */
1018 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1021 file_ptr = open_user_list(user_list);
1024 while (fgets(line, MAXLINE, file_ptr)) {
1025 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1026 // "from config file\n", __func__, strlen(line));
1027 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1029 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1030 PARA_DEBUG_LOG("found entry for %s\n", n);
1031 strcpy(user->name, n);
1032 strcpy(user->pubkey_file, k);
1035 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1036 tmp[0], tmp[1], tmp[2], tmp[3]);
1037 PARA_DEBUG_LOG("found %i perm entries\n",
1042 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1044 if (!strcmp(tmp[num], "AFS_READ"))
1046 user->perms | AFS_READ;
1047 else if (!strcmp(tmp[num], "AFS_WRITE"))
1049 user->perms | AFS_WRITE;
1050 else if (!strcmp(tmp[num], "DB_READ"))
1051 user->perms = user->perms | DB_READ;
1052 else if (!strcmp(tmp[num], "DB_WRITE"))
1053 user->perms = user->perms | DB_WRITE;
1054 else /* unknown permission */
1055 PARA_WARNING_LOG("unknown permission:"
1066 static void init_rc4_keys(void)
1070 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1071 rc4_buf[i] = para_rand(256);
1072 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1073 (unsigned char) rc4_buf[0],
1074 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1075 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1076 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1079 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1081 RC4(&rc4_recv_key, len, indata, outdata);
1084 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1086 RC4(&rc4_send_key, len, indata, outdata);
1089 int handle_connect(int fd, struct sockaddr_in *addr)
1091 int numbytes, ret, argc, use_rc4 = 0;
1092 char buf[STRINGSIZE];
1093 unsigned char crypt_buf[MAXLINE];
1095 struct server_command *cmd = NULL;
1096 long unsigned challenge_nr, chall_response;
1098 char *p, *command = NULL;
1100 signal(SIGCHLD, SIG_IGN);
1101 signal(SIGINT, SIG_DFL);
1102 signal(SIGTERM, SIG_DFL);
1103 signal(SIGHUP, SIG_DFL);
1104 signal(SIGUSR1, SIG_IGN);
1107 challenge_nr = random();
1108 /* send Welcome message */
1109 ret = send_va_buffer(fd, "This is para_server, version " VERSION ".\n" );
1112 /* recv auth request line */
1113 ret = recv_buffer(fd, buf, sizeof(buf));
1122 if (strncmp(buf, "auth ", 5))
1125 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1126 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1128 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1131 // strcpy(u.name, buf + 5); /* ok, but ugly */
1132 PARA_DEBUG_LOG("received %s request for user %s\n",
1133 use_rc4? "rc4" : "auth", u.name);
1134 /* lookup user in list file */
1135 if ((ret = get_user(&u)) < 0)
1137 if (!ret) { /* user not found */
1138 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1142 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1146 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1147 /* We can't use send_buffer here since buf may contain null bytes */
1148 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1151 /* recv decrypted number */
1152 numbytes = recv_buffer(fd, buf, sizeof(buf));
1159 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1160 || chall_response != challenge_nr)
1162 /* auth successful. Send 'Proceed' message */
1163 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1164 sprintf(buf, "%s", PROCEED_MSG);
1167 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1168 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1171 numbytes = ret + strlen(PROCEED_MSG) + 1;
1173 numbytes = strlen(buf);
1174 ret = send_bin_buffer(fd, buf, numbytes);
1178 crypt_function_recv = rc4_recv;
1179 crypt_function_send = rc4_send;
1180 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1183 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1184 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1185 ret = -E_COMMAND_SYNTAX;
1186 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1188 command = para_strcat(command, buf);
1189 if ((p = strstr(command, EOC_MSG))) {
1199 if (!(cmd = parse_cmd(command)))
1201 /* valid command, check permissions */
1202 ret = check_perms(u.perms, cmd);
1205 /* valid command and sufficient perms */
1207 argc = split_args(command, &argv, '\n');
1209 mmd->num_commands++;
1211 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1212 inet_ntoa(addr->sin_addr));
1213 ret = cmd->handler(fd, argc, argv);
1219 if (ret != -E_SEND && ret != -E_RECV) {
1220 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1221 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1228 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1230 mmd->active_connections--;