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>
36 static RC4_KEY rc4_recv_key;
37 static RC4_KEY rc4_send_key;
38 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
40 extern const char *status_item_list[NUM_STAT_ITEMS];
41 extern struct misc_meta_data *mmd;
42 extern struct audio_file_selector selectors[];
43 extern struct sender senders[];
44 extern char *user_list;
45 struct sockaddr_in *in_addr;
47 static int com_si(int, int, char **);
48 static int com_version(int, int, char **);
49 static int com_sb(int, int, char **);
50 static int com_sc(int, int, char **);
51 static int com_stat(int, int, char **);
52 static int com_help(int, int, char **);
53 static int com_hup(int, int, char **);
54 static int com_term(int, int, char **);
55 static int com_play(int, int, char **);
56 static int com_stop(int, int, char **);
57 static int com_pause(int, int, char **);
58 static int com_next(int, int, char **);
59 static int com_nomore(int, int, char **);
60 static int com_chs(int, int, char **);
61 static int com_ff(int, int, char **);
62 static int com_jmp(int, int, char **);
63 static int com_sender(int, int, char **);
66 /* commands that are handled by the server itself */
67 static struct server_command cmd_struct[] = {
71 .perms = DB_READ | DB_WRITE,
72 .description = "change the current audio file selector",
73 .synopsis = "chs [new_selector]",
75 "Shutdown the current selector and activate new_selector. If no\n"
76 "argument was given, print the name of the current selector.\n"
82 .perms = AFS_READ | AFS_WRITE,
83 .description = "jmp amount of time forwards or backwards "
84 "in current audio file",
85 .synopsis = "ff n[-]",
88 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
89 "\tand enqueue a request to jump n seconds forwards or backwards\n"
90 "\tin the current audio file.\n"
96 "\tjumps 30 seconds backwards.\n"
104 .description = "print help text",
105 .synopsis = "help [command]",
108 "Without any arguments, help prints a list of availible commands. When\n"
109 "issued with a command name as first argument, print out a description\n"
110 "for that command.\n"
118 .description = "force reload of config file and log file",
122 "After rereading the config file, a signal is sent to all children\n"
123 "which forces them to close/reopen the log file.\n"
130 .perms = AFS_READ | AFS_WRITE,
131 .description = "jmp to given position in current audio file",
132 .synopsis = "jmp [n]",
135 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
136 "\tand enqueue a request to jump to n% of the current audio file,\n"
137 "\twhere 0 <= n <= 100.\n"
144 .perms = AFS_READ | AFS_WRITE,
145 .description = "skip rest of current audio file",
149 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
150 "\tplaying, change audio file immediately. Equivalent to stop\n"
151 "\tif paused, NOP if stopped.\n"
158 .handler = com_nomore,
159 .perms = AFS_READ | AFS_WRITE,
160 .description = "stop playing after current audio file",
161 .synopsis = "nomore",
164 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
165 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
166 "the 'N' (next audio file) bit being set.\n"
168 "Use this command instead of stop if you don't like\n"
175 .handler = com_pause,
176 .perms = AFS_READ | AFS_WRITE,
177 .description = "pause current audio file",
181 "\tClear the 'P' (playing) bit of the afs status flags.\n"
188 .perms = AFS_READ | AFS_WRITE,
189 .description = "start playing or resume playing when paused",
193 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
194 "\tresults in starting/continuing to stream.\n"
202 .description = "print status bar for current audio file",
203 .synopsis = "sb [n]",
206 "Without any arguments, sb continuously prints a status bar of the form\n"
208 " 12:34 [56:12] (56%) filename\n"
210 "indicating playing time, remaining time, percentage and the name of\n"
211 "the file beeing streamed. Use the optional number n to let stat exit\n"
212 "after having displayed the status bar n times.\n"
219 .description = "print name of audio file whenever it changes",
220 .synopsis = "sc [n]",
223 "\tsc prints exactly one line (the filename of the audio file\n"
224 "\tbeing played) whenever the audio file changes. Stops after\n"
225 "\tn iterations, or never if n is not specified.\n"
230 .handler = com_sender,
231 .perms = AFS_READ | AFS_WRITE,
232 .description = "control paraslash internal senders",
233 .synopsis = "sender [s cmd [arguments]]",
236 "send command cmd to sender s. cmd may be one of the following:\n"
237 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
238 "support each command. Try e.g. 'para_client sender http help' for\n"
239 "more information about the http sender. If no argument is given,\n"
240 "print out a list of all senders that are compiled in.\n"
247 .description = "print server info",
250 "Print server uptime and other information.\n"
257 .description = "print status info for current audio file",
258 .synopsis = "stat [n]",
261 "\tWithout any arguments, stat continuously prints status messages\n"
262 "\tof the audio file being streamed. Use the optional number n\n"
263 "\tto let stat exit after having displayed status n times.\n"
270 .perms = AFS_READ | AFS_WRITE,
271 .description = "stop playing",
275 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
282 .perms = AFS_READ | AFS_WRITE,
283 .description = "terminate para_server",
287 "Shuts down the server. Instead of this command, you can also send\n"
288 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
293 .handler = com_version,
295 .description = "print server's version",
296 .synopsis = "version",
298 "Show version and other info\n"
300 /* this indicates the end of the list. Do not touch. */
306 static void dummy(__a_unused int s)
309 static void mmd_dup(struct misc_meta_data *new_mmd)
317 * compute human readable string containing
318 * afs_status for given integer value
320 static char *afs_status_tohuman(unsigned int flags)
322 if (flags & AFS_PLAYING)
323 return para_strdup("playing");
324 else if (flags & AFS_NEXT)
325 return para_strdup("stopped");
327 return para_strdup("paused");
331 * return human readable permission string. Never returns NULL.
333 char *cmd_perms_itohuman(unsigned int perms)
335 char *msg = para_malloc(7 * sizeof(char));
337 msg[0] = perms & DB_READ? 'd' : '-';
338 msg[1] = perms & DB_WRITE? 'D' : '-';
339 msg[2] = perms & AFS_READ? 'a' : '-';
340 msg[3] = perms & AFS_WRITE? 'A' : '-';
346 * Never returns NULL.
348 static char *afs_get_status_flags(unsigned int flags)
350 char *msg = para_malloc(5 * sizeof(char));
352 msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
353 msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
354 msg[2] = (flags & AFS_NEXT)? 'N' : '_';
355 msg[3] = (flags & AFS_REPOS)? 'R' : '_';
361 * compute status bar string. Never returns NULL
363 char *get_sb_string(struct misc_meta_data *nmmd)
366 long long unsigned secs = 0, rsecs = 0, percent = 0;
368 base = para_basename(nmmd->filename);
370 return para_strdup("");
373 if (nmmd->chunks_total) {
374 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
375 / nmmd->chunks_total;
376 rsecs = (long long) nmmd->seconds_total *
377 (nmmd->chunks_total - nmmd->chunks_sent)
378 / nmmd->chunks_total;
379 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
380 / ((nmmd->chunks_total + 5) / 10);
382 ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
383 secs / 60, secs % 60,
384 rsecs / 60, rsecs % 60,
392 static char *get_status(struct misc_meta_data *nmmd)
394 char *bar, *ret, mtime[30] = "";
395 char *status, *flags; /* afs status info */
396 char *ut = uptime_str();
397 long offset = (nmmd->offset + 500) / 1000;
401 if (nmmd->audio_format >= 0) {
402 localtime_r(&nmmd->mtime, &mtime_tm);
403 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
405 /* report real status */
406 status = afs_status_tohuman(nmmd->afs_status_flags);
407 flags = afs_get_status_flags(nmmd->afs_status_flags);
408 bar = para_basename(nmmd->filename);
409 gettimeofday(&now, NULL);
411 "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n"
412 "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n"
413 "%s:%li\n" "%s:%s\n" "%s" "%s"
414 "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n",
415 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
416 status_item_list[SI_MTIME], mtime,
417 status_item_list[SI_LENGTH], nmmd->seconds_total,
418 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
420 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
421 status_item_list[SI_STATUS], status,
422 status_item_list[SI_STATUS_FLAGS], flags,
423 status_item_list[SI_SELECTOR], selectors[nmmd->selector_num].name,
425 status_item_list[SI_OFFSET], offset,
426 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
428 nmmd->audio_file_info,
430 status_item_list[SI_UPTIME], ut,
431 status_item_list[SI_STREAM_START],
432 (long unsigned)nmmd->stream_start.tv_sec,
433 (long unsigned)nmmd->stream_start.tv_usec,
434 status_item_list[SI_CURRENT_TIME],
435 (long unsigned)now.tv_sec,
436 (long unsigned)now.tv_usec
446 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
449 /* this has to match sender.h */
450 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
452 scd->sender_num = -1;
454 return -E_COMMAND_SYNTAX;
455 for (i = 0; senders[i].name; i++)
456 if (!strcmp(senders[i].name, argv[1]))
458 PARA_DEBUG_LOG("%d:%s\n", argc, argv[1]);
459 if (!senders[i].name)
460 return -E_COMMAND_SYNTAX;
462 for (i = 0; subcmds[i]; i++)
463 if (!strcmp(subcmds[i], argv[2]))
466 return -E_COMMAND_SYNTAX;
469 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
471 return -E_SENDER_CMD;
474 switch (scd->cmd_num) {
478 return -E_COMMAND_SYNTAX;
482 if (argc != 4 && argc != 5)
483 return -E_COMMAND_SYNTAX;
484 if (!inet_aton(argv[3], &scd->addr))
485 return -E_COMMAND_SYNTAX;
488 scd->netmask = atoi(argv[4]);
489 if (scd->netmask < 0 || scd->netmask > 32)
490 return -E_COMMAND_SYNTAX;
495 if (argc != 4 && argc != 5)
496 return -E_COMMAND_SYNTAX;
497 if (!inet_aton(argv[3], &scd->addr))
498 return -E_COMMAND_SYNTAX;
501 scd->port = atoi(argv[4]);
502 if (scd->port < 0 || scd->port > 65535)
503 return -E_COMMAND_SYNTAX;
507 return -E_COMMAND_SYNTAX;
512 static int com_sender(int fd, int argc, char **argv)
515 struct sender_command_data scd;
519 for (i = 0; senders[i].name; i++) {
520 char *tmp = make_message("%s%s\n",
521 msg? msg : "", senders[i].name);
525 ret = send_buffer(fd, msg);
529 ret = check_sender_args(argc, argv, &scd);
532 if (scd.sender_num < 0)
534 msg = senders[scd.sender_num].help();
535 send_buffer(fd, msg);
539 for (i = 0; i < 10; i++) {
541 if (mmd->sender_cmd_data.cmd_num >= 0) {
546 mmd->sender_cmd_data = scd;
550 return (i < 10)? 1 : -E_LOCK;
554 static int com_si(int fd, int argc, __a_unused char **argv)
558 char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
561 return -E_COMMAND_SYNTAX;
563 for (i = 0; selectors[i].name; i++) {
564 selector_string = para_strcat(selector_string, selectors[i].name);
565 selector_string = para_strcat(selector_string, " ");
567 for (i = 0; senders[i].name; i++) {
568 char *info = senders[i].info();
569 sender_info = para_strcat(sender_info, info);
571 sender_list = para_strcat(sender_list, senders[i].name);
572 sender_list = para_strcat(sender_list, " ");
575 ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
577 "connections (active/accepted/total): %u/%u/%u\n"
578 "current loglevel: %i\n"
579 "supported audio file selectors: %s\n"
580 "supported audio formats: %s\n"
581 "supported senders: %s\n"
585 mmd->active_connections,
590 supported_audio_formats(),
596 free(selector_string);
603 static int com_version(int socket_fd, int argc, __a_unused char **argv)
606 return -E_COMMAND_SYNTAX;
607 return send_buffer(socket_fd, "para_server-" PACKAGE_VERSION ", \""
610 "built: " BUILD_DATE "\n"
611 SYSTEM ", " CC_VERSION "\n"
616 static int com_sc(int socket_fd, int argc, char **argv)
619 int ret, old = 0, count = -1; /* print af change forever */
622 count = atoi(argv[1]);
625 if (old != mmd->num_played) {
626 old = mmd->num_played;
627 name = para_strdup(mmd->filename);
631 ret = send_va_buffer(socket_fd, "%s\n", name);
636 if (argc > 1 && !--count)
644 static int com_sb(int socket_fd, int argc, char **argv)
647 int ret, nr = -1; /* status bar will be printed that many
648 * times. Negative value means: print
655 sb = get_sb_string(mmd);
657 ret = send_va_buffer(socket_fd, "%s\n", sb);
671 static int com_stat(int socket_fd, int argc, char **argv)
673 int ret, num = 0;/* status will be printed that many
674 * times. num <= 0 means: print forever
676 struct misc_meta_data tmp, *nmmd = &tmp;
679 signal(SIGUSR1, dummy);
686 s = get_status(nmmd);
687 ret = send_buffer(socket_fd, s);
696 return -E_SERVER_CRASH;
702 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
706 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
707 char *perms = cmd_perms_itohuman(cmd->perms);
708 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
719 /* always returns string that must be freed by the caller in handler */
720 static struct server_command *get_cmd_ptr(char *name, char **handler)
722 struct server_command *cmd = cmd_struct;
724 for (cmd = cmd_struct; cmd->name; cmd++)
725 if (!strcmp(cmd->name, name)) {
727 *handler = para_strdup("para_server"); /* server commands */
730 /* not found, look for commands supported by the current selector */
733 *handler = make_message("the %s selector",
734 selectors[mmd->selector_num].name);
735 cmd = selectors[mmd->selector_num].cmd_list;
737 for (; cmd->name; cmd++)
738 if (!strcmp(cmd->name, name))
744 static int com_help(int fd, int argc, char **argv)
746 struct server_command *cmd;
747 char *perms, *handler;
751 /* no argument given, print list of commands */
752 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
755 handler = para_strdup(selectors[mmd->selector_num].name);
756 cmd = selectors[mmd->selector_num].cmd_list;
758 ret = send_description(fd, cmd, handler, 0);
762 /* argument given for help */
763 cmd = get_cmd_ptr(argv[1], &handler);
768 perms = cmd_perms_itohuman(cmd->perms);
769 ret = send_va_buffer(fd,
771 "SYNOPSIS\n\t para_client %s\n"
774 "This command is handled by %s.\n\n"
776 "Needed privileges for %s: %s\n",
791 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
794 return -E_COMMAND_SYNTAX;
795 kill(getppid(), SIGHUP);
800 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
803 return -E_COMMAND_SYNTAX;
804 kill(getppid(), SIGTERM);
808 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
811 return -E_COMMAND_SYNTAX;
813 mmd->new_afs_status_flags |= AFS_PLAYING;
814 mmd->new_afs_status_flags &= ~AFS_NOMORE;
821 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
824 return -E_COMMAND_SYNTAX;
826 mmd->new_afs_status_flags &= ~AFS_PLAYING;
827 mmd->new_afs_status_flags &= ~AFS_REPOS;
828 mmd->new_afs_status_flags |= AFS_NEXT;
834 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
837 return -E_COMMAND_SYNTAX;
841 mmd->new_afs_status_flags &= ~AFS_PLAYING;
842 mmd->new_afs_status_flags &= ~AFS_NEXT;
847 static int com_chs(int fd, int argc, char **argv)
854 selector = para_strdup(selectors[mmd->selector_num].name);
856 ret = send_va_buffer(fd, "%s\n", selector);
860 for (i = 0; selectors[i].name; i++) {
861 if (strcmp(selectors[i].name, argv[1]))
864 mmd->selector_change = i;
869 return -E_BAD_SELECTOR;
873 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
876 return -E_COMMAND_SYNTAX;
879 mmd->new_afs_status_flags |= AFS_NEXT;
885 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
888 return -E_COMMAND_SYNTAX;
890 if (afs_playing() || afs_paused())
891 mmd->new_afs_status_flags |= AFS_NOMORE;
897 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
900 int ret, backwards = 0;
905 return -E_COMMAND_SYNTAX;
906 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
907 return -E_COMMAND_SYNTAX;
908 if (ret > 1 && c == '-')
909 backwards = 1; /* jmp backwards */
911 ret = -E_NO_AUDIO_FILE;
912 if (!mmd->chunks_total || !mmd->seconds_total)
914 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
916 promille -= 1000 * i / mmd->seconds_total;
918 promille += 1000 * i / mmd->seconds_total;
921 if (promille > 1000) {
922 mmd->new_afs_status_flags |= AFS_NEXT;
925 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
926 mmd->new_afs_status_flags |= AFS_REPOS;
927 mmd->new_afs_status_flags &= ~AFS_NEXT;
936 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
942 return -E_COMMAND_SYNTAX;
943 if (sscanf(argv[1], "%lu", &i) <= 0)
944 return -E_COMMAND_SYNTAX;
946 ret = -E_NO_AUDIO_FILE;
947 if (!mmd->chunks_total)
951 PARA_INFO_LOG("jumping to %lu%%\n", i);
952 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
953 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
954 mmd->chunks_sent, mmd->offset);
955 mmd->new_afs_status_flags |= AFS_REPOS;
956 mmd->new_afs_status_flags &= ~AFS_NEXT;
965 * check if perms are sufficient to exec a command having perms cmd_perms.
966 * Returns 0 if perms are sufficient, -E_PERM otherwise.
968 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
970 PARA_DEBUG_LOG("%s", "checking permissions\n");
971 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
975 * Parse first string from *cmd and lookup in table of valid commands.
976 * On error, NULL is returned.
978 static struct server_command *parse_cmd(const char *cmdstr)
983 sscanf(cmdstr, "%200s%n", buf, &n);
987 return get_cmd_ptr(buf, NULL);
990 long int para_rand(long unsigned max)
992 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
995 /* Open user_list file, returns pointer to opened file on success,
998 static FILE *open_user_list(char *file)
1000 PARA_DEBUG_LOG("opening user list %s\n", file);
1001 return fopen(file, "r");
1005 * lookup user in user_list file. Fills in a user struct containing
1006 * filename of the user's public key as well as the permissions of that user.
1007 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1009 static int get_user(struct user *user) {
1013 /* keyword, user, key, perms */
1014 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1017 file_ptr = open_user_list(user_list);
1021 ret = para_fgets(line, MAXLINE, file_ptr);
1023 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
1026 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1028 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", num);
1041 if (!strcmp(tmp[num], "AFS_READ"))
1042 user->perms = user->perms | AFS_READ;
1043 else if (!strcmp(tmp[num], "AFS_WRITE"))
1044 user->perms = 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: %s\n",
1059 static void init_rc4_keys(void)
1063 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1064 rc4_buf[i] = para_rand(256);
1065 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1066 (unsigned char) rc4_buf[0],
1067 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1068 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1069 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1072 static void rc4_recv(unsigned long len, const unsigned char *indata,
1073 unsigned char *outdata, __a_unused void *private_data)
1075 RC4(&rc4_recv_key, len, indata, outdata);
1078 static void rc4_send(unsigned long len, const unsigned char *indata,
1079 unsigned char *outdata, __a_unused void *private_data)
1081 RC4(&rc4_send_key, len, indata, outdata);
1084 int handle_connect(int fd, struct sockaddr_in *addr)
1086 int numbytes, ret, argc, use_rc4 = 0;
1087 char buf[STRINGSIZE];
1088 unsigned char crypt_buf[MAXLINE];
1090 struct server_command *cmd = NULL;
1091 long unsigned challenge_nr, chall_response;
1093 char *p, *command = NULL;
1095 signal(SIGCHLD, SIG_IGN);
1096 signal(SIGINT, SIG_DFL);
1097 signal(SIGTERM, SIG_DFL);
1098 signal(SIGHUP, SIG_DFL);
1099 signal(SIGUSR1, SIG_IGN);
1102 challenge_nr = random();
1103 /* send Welcome message */
1104 ret = send_va_buffer(fd, "This is para_server, version "
1105 PACKAGE_VERSION ".\n" );
1108 /* recv auth request line */
1109 ret = recv_buffer(fd, buf, sizeof(buf));
1118 if (strncmp(buf, "auth ", 5))
1121 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1122 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1124 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1127 // strcpy(u.name, buf + 5); /* ok, but ugly */
1128 PARA_DEBUG_LOG("received %s request for user %s\n",
1129 use_rc4? "rc4" : "auth", u.name);
1130 /* lookup user in list file */
1131 if ((ret = get_user(&u)) < 0)
1133 if (!ret) { /* user not found */
1134 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1138 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1142 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1143 /* We can't use send_buffer here since buf may contain null bytes */
1144 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1147 /* recv decrypted number */
1148 numbytes = recv_buffer(fd, buf, sizeof(buf));
1155 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1156 || chall_response != challenge_nr)
1158 /* auth successful. Send 'Proceed' message */
1159 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1160 sprintf(buf, "%s", PROCEED_MSG);
1163 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1164 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1167 numbytes = ret + strlen(PROCEED_MSG) + 1;
1169 numbytes = strlen(buf);
1170 ret = send_bin_buffer(fd, buf, numbytes);
1174 enable_crypt(fd, rc4_recv, rc4_send, NULL);
1176 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1177 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1178 ret = -E_COMMAND_SYNTAX;
1179 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1181 command = para_strcat(command, buf);
1182 if ((p = strstr(command, EOC_MSG))) {
1192 if (!(cmd = parse_cmd(command)))
1194 /* valid command, check permissions */
1195 ret = check_perms(u.perms, cmd);
1198 /* valid command and sufficient perms */
1200 argc = split_args(command, &argv, "\n");
1202 mmd->num_commands++;
1204 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1205 inet_ntoa(addr->sin_addr));
1206 ret = cmd->handler(fd, argc, argv);
1212 if (ret != -E_SEND && ret != -E_RECV) {
1213 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1214 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1221 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1223 mmd->active_connections--;