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-" VERSION ", \"" CODENAME "\"\n"
608 "built: " BUILD_DATE "\n"
609 SYSTEM ", " CC_VERSION "\n"
614 static int com_sc(int socket_fd, int argc, char **argv)
617 int ret, old = 0, count = -1; /* print af change forever */
620 count = atoi(argv[1]);
623 if (old != mmd->num_played) {
624 old = mmd->num_played;
625 name = para_strdup(mmd->filename);
629 ret = send_va_buffer(socket_fd, "%s\n", name);
634 if (argc > 1 && !--count)
642 static int com_sb(int socket_fd, int argc, char **argv)
645 int ret, nr = -1; /* status bar will be printed that many
646 * times. Negative value means: print
653 sb = get_sb_string(mmd);
655 ret = send_va_buffer(socket_fd, "%s\n", sb);
669 static int com_stat(int socket_fd, int argc, char **argv)
671 int ret, num = 0;/* status will be printed that many
672 * times. num <= 0 means: print forever
674 struct misc_meta_data tmp, *nmmd = &tmp;
677 signal(SIGUSR1, dummy);
684 s = get_status(nmmd);
685 ret = send_buffer(socket_fd, s);
692 usleep(500000 * 100);
698 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
702 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
703 char *perms = cmd_perms_itohuman(cmd->perms);
704 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
715 /* always returns string that must be freed by the caller in handler */
716 static struct server_command *get_cmd_ptr(char *name, char **handler)
718 struct server_command *cmd = cmd_struct;
720 for (cmd = cmd_struct; cmd->name; cmd++)
721 if (!strcmp(cmd->name, name)) {
723 *handler = para_strdup("para_server"); /* server commands */
726 /* not found, look for commands supported by the current selector */
729 *handler = make_message("the %s selector",
730 selectors[mmd->selector_num].name);
731 cmd = selectors[mmd->selector_num].cmd_list;
733 for (; cmd->name; cmd++)
734 if (!strcmp(cmd->name, name))
740 static int com_help(int fd, int argc, char **argv)
742 struct server_command *cmd;
743 char *perms, *handler;
747 /* no argument given, print list of commands */
748 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
751 handler = para_strdup(selectors[mmd->selector_num].name);
752 cmd = selectors[mmd->selector_num].cmd_list;
754 ret = send_description(fd, cmd, handler, 0);
758 /* argument given for help */
759 cmd = get_cmd_ptr(argv[1], &handler);
764 perms = cmd_perms_itohuman(cmd->perms);
765 ret = send_va_buffer(fd,
767 "SYNOPSIS\n\t para_client %s\n"
770 "This command is handled by %s.\n\n"
772 "Needed privileges for %s: %s\n",
787 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
790 return -E_COMMAND_SYNTAX;
791 kill(getppid(), SIGHUP);
796 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
799 return -E_COMMAND_SYNTAX;
800 kill(getppid(), SIGTERM);
804 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
807 return -E_COMMAND_SYNTAX;
809 mmd->new_afs_status_flags |= AFS_PLAYING;
810 mmd->new_afs_status_flags &= ~AFS_NOMORE;
817 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
820 return -E_COMMAND_SYNTAX;
822 mmd->new_afs_status_flags &= ~AFS_PLAYING;
823 mmd->new_afs_status_flags &= ~AFS_REPOS;
824 mmd->new_afs_status_flags |= AFS_NEXT;
830 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
833 return -E_COMMAND_SYNTAX;
837 mmd->new_afs_status_flags &= ~AFS_PLAYING;
838 mmd->new_afs_status_flags &= ~AFS_NEXT;
843 static int com_chs(int fd, int argc, char **argv)
850 selector = para_strdup(selectors[mmd->selector_num].name);
852 ret = send_va_buffer(fd, "%s\n", selector);
856 for (i = 0; selectors[i].name; i++) {
857 if (strcmp(selectors[i].name, argv[1]))
860 mmd->selector_change = i;
865 return -E_BAD_SELECTOR;
869 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
872 return -E_COMMAND_SYNTAX;
875 mmd->new_afs_status_flags |= AFS_NEXT;
881 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
884 return -E_COMMAND_SYNTAX;
886 if (afs_playing() || afs_paused())
887 mmd->new_afs_status_flags |= AFS_NOMORE;
893 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
896 int ret, backwards = 0;
901 return -E_COMMAND_SYNTAX;
902 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
903 return -E_COMMAND_SYNTAX;
904 if (ret > 1 && c == '-')
905 backwards = 1; /* jmp backwards */
907 ret = -E_NO_AUDIO_FILE;
908 if (!mmd->chunks_total || !mmd->seconds_total)
910 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
912 promille -= 1000 * i / mmd->seconds_total;
914 promille += 1000 * i / mmd->seconds_total;
917 if (promille > 1000) {
918 mmd->new_afs_status_flags |= AFS_NEXT;
921 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
922 mmd->new_afs_status_flags |= AFS_REPOS;
923 mmd->new_afs_status_flags &= ~AFS_NEXT;
932 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
938 return -E_COMMAND_SYNTAX;
939 if (sscanf(argv[1], "%lu", &i) <= 0)
940 return -E_COMMAND_SYNTAX;
942 ret = -E_NO_AUDIO_FILE;
943 if (!mmd->chunks_total)
947 PARA_INFO_LOG("jumping to %lu%%\n", i);
948 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
949 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
950 mmd->chunks_sent, mmd->offset);
951 mmd->new_afs_status_flags |= AFS_REPOS;
952 mmd->new_afs_status_flags &= ~AFS_NEXT;
961 * check if perms are sufficient to exec a command having perms cmd_perms.
962 * Returns 0 if perms are sufficient, -E_PERM otherwise.
964 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
966 PARA_DEBUG_LOG("%s", "checking permissions\n");
967 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
971 * Parse first string from *cmd and lookup in table of valid commands.
972 * On error, NULL is returned.
974 static struct server_command *parse_cmd(const char *cmdstr)
979 sscanf(cmdstr, "%200s%n", buf, &n);
983 return get_cmd_ptr(buf, NULL);
986 long int para_rand(long unsigned max)
988 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
991 /* Open user_list file, returns pointer to opened file on success,
994 static FILE *open_user_list(char *file)
996 PARA_DEBUG_LOG("opening user list %s\n", file);
997 return fopen(file, "r");
1001 * lookup user in user_list file. Fills in a user struct containing
1002 * filename of the user's public key as well as the permissions of that user.
1003 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1005 static int get_user(struct user *user) {
1009 /* keyword, user, key, perms */
1010 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1013 file_ptr = open_user_list(user_list);
1016 while (fgets(line, MAXLINE, file_ptr)) {
1017 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1018 // "from config file\n", __func__, strlen(line));
1019 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1021 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1022 PARA_DEBUG_LOG("found entry for %s\n", n);
1023 strcpy(user->name, n);
1024 strcpy(user->pubkey_file, k);
1027 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1028 tmp[0], tmp[1], tmp[2], tmp[3]);
1029 PARA_DEBUG_LOG("found %i perm entries\n",
1034 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1036 if (!strcmp(tmp[num], "AFS_READ"))
1038 user->perms | AFS_READ;
1039 else if (!strcmp(tmp[num], "AFS_WRITE"))
1041 user->perms | AFS_WRITE;
1042 else if (!strcmp(tmp[num], "DB_READ"))
1043 user->perms = user->perms | DB_READ;
1044 else if (!strcmp(tmp[num], "DB_WRITE"))
1045 user->perms = user->perms | DB_WRITE;
1046 else /* unknown permission */
1047 PARA_WARNING_LOG("unknown permission:"
1058 static void init_rc4_keys(void)
1062 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1063 rc4_buf[i] = para_rand(256);
1064 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1065 (unsigned char) rc4_buf[0],
1066 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1067 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1068 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1071 static void rc4_recv(unsigned long len, const unsigned char *indata,
1072 unsigned char *outdata, __a_unused void *private_data)
1074 RC4(&rc4_recv_key, len, indata, outdata);
1077 static void rc4_send(unsigned long len, const unsigned char *indata,
1078 unsigned char *outdata, __a_unused void *private_data)
1080 RC4(&rc4_send_key, len, indata, outdata);
1083 int handle_connect(int fd, struct sockaddr_in *addr)
1085 int numbytes, ret, argc, use_rc4 = 0;
1086 char buf[STRINGSIZE];
1087 unsigned char crypt_buf[MAXLINE];
1089 struct server_command *cmd = NULL;
1090 long unsigned challenge_nr, chall_response;
1092 char *p, *command = NULL;
1094 signal(SIGCHLD, SIG_IGN);
1095 signal(SIGINT, SIG_DFL);
1096 signal(SIGTERM, SIG_DFL);
1097 signal(SIGHUP, SIG_DFL);
1098 signal(SIGUSR1, SIG_IGN);
1101 challenge_nr = random();
1102 /* send Welcome message */
1103 ret = send_va_buffer(fd, "This is para_server, version " VERSION ".\n" );
1106 /* recv auth request line */
1107 ret = recv_buffer(fd, buf, sizeof(buf));
1116 if (strncmp(buf, "auth ", 5))
1119 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1120 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1122 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1125 // strcpy(u.name, buf + 5); /* ok, but ugly */
1126 PARA_DEBUG_LOG("received %s request for user %s\n",
1127 use_rc4? "rc4" : "auth", u.name);
1128 /* lookup user in list file */
1129 if ((ret = get_user(&u)) < 0)
1131 if (!ret) { /* user not found */
1132 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1136 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1140 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1141 /* We can't use send_buffer here since buf may contain null bytes */
1142 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1145 /* recv decrypted number */
1146 numbytes = recv_buffer(fd, buf, sizeof(buf));
1153 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1154 || chall_response != challenge_nr)
1156 /* auth successful. Send 'Proceed' message */
1157 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1158 sprintf(buf, "%s", PROCEED_MSG);
1161 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1162 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1165 numbytes = ret + strlen(PROCEED_MSG) + 1;
1167 numbytes = strlen(buf);
1168 ret = send_bin_buffer(fd, buf, numbytes);
1172 enable_crypt(fd, rc4_recv, rc4_send, NULL);
1174 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1175 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1176 ret = -E_COMMAND_SYNTAX;
1177 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1179 command = para_strcat(command, buf);
1180 if ((p = strstr(command, EOC_MSG))) {
1190 if (!(cmd = parse_cmd(command)))
1192 /* valid command, check permissions */
1193 ret = check_perms(u.perms, cmd);
1196 /* valid command and sufficient perms */
1198 argc = split_args(command, &argv, "\n");
1200 mmd->num_commands++;
1202 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1203 inet_ntoa(addr->sin_addr));
1204 ret = cmd->handler(fd, argc, argv);
1210 if (ret != -E_SEND && ret != -E_RECV) {
1211 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1212 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1219 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1221 mmd->active_connections--;