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 */
22 #include <malloc.h> /* mallinfo */
23 #include <sys/time.h> /* gettimeofday */
25 #include "server.cmdline.h"
31 #include <openssl/rc4.h>
32 #include "gcc-compat.h"
38 void (*crypt_function_recv)(unsigned long len, const unsigned char *indata,
39 unsigned char *outdata) = NULL;
40 void (*crypt_function_send)(unsigned long len, const unsigned char *indata,
41 unsigned char *outdata) = NULL;
42 static RC4_KEY rc4_recv_key;
43 static RC4_KEY rc4_send_key;
44 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
46 extern const char *status_item_list[NUM_STAT_ITEMS];
47 extern struct misc_meta_data *mmd;
48 extern struct gengetopt_args_info conf;
49 extern struct dbtool dblist[];
50 extern struct audio_format afl[];
51 extern struct sender senders[];
52 extern char *user_list;
53 struct sockaddr_in *in_addr;
55 static int com_si(int, int, char **);
56 static int com_version(int, int, char **);
57 static int com_sb(int, int, char **);
58 static int com_sc(int, int, char **);
59 static int com_stat(int, int, char **);
60 static int com_help(int, int, char **);
61 static int com_hup(int, int, char **);
62 static int com_term(int, int, char **);
63 static int com_play(int, int, char **);
64 static int com_stop(int, int, char **);
65 static int com_pause(int, int, char **);
66 static int com_next(int, int, char **);
67 static int com_nomore(int, int, char **);
68 static int com_cdt(int, int, char **);
69 static int com_ff(int, int, char **);
70 static int com_jmp(int, int, char **);
71 static int com_sender(int, int, char **);
74 /* commands that are handled by the server itself */
75 static struct server_command cmd_struct[] = {
79 .perms = DB_READ | DB_WRITE,
80 .description = "change database tool",
81 .synopsis = "cdt [name_of_new_dbtool]",
83 "Deactivate current dbtool and activate name_of_new_dbtool. If no\n"
84 "argument was given, print the current database tool.\n"
90 .perms = AFS_READ | AFS_WRITE,
91 .description = "jmp amount of time forwards or backwards "
92 "in current audio file",
93 .synopsis = "ff n[-]",
96 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
97 "\tand enqueue a request to jump n seconds forwards or backwards\n"
98 "\tin the current audio file.\n"
104 "\tjumps 30 seconds backwards.\n"
112 .description = "print help text",
113 .synopsis = "help [command]",
116 "Without any arguments, help prints a list of availible commands. When\n"
117 "issued with a command name as first argument, print out a description\n"
118 "for that command.\n"
126 .description = "force reload of config file and log file",
130 "After rereading the config file, a signal is sent to all children\n"
131 "which forces them to close/reopen the log file.\n"
138 .perms = AFS_READ | AFS_WRITE,
139 .description = "jmp to given position in current audio file",
140 .synopsis = "jmp [n]",
143 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
144 "\tand enqueue a request to jump to n% of the current audio file,\n"
145 "\twhere 0 <= n <= 100.\n"
152 .perms = AFS_READ | AFS_WRITE,
153 .description = "skip rest of current audio file",
157 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
158 "\tplaying, change audio file immediately. Equivalent to stop\n"
159 "\tif paused, NOP if stopped.\n"
166 .handler = com_nomore,
167 .perms = AFS_READ | AFS_WRITE,
168 .description = "stop playing after current audio file",
169 .synopsis = "nomore",
172 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
173 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
174 "the 'N' (next audio file) bit being set.\n"
176 "Use this command instead of stop if you don't like\n"
183 .handler = com_pause,
184 .perms = AFS_READ | AFS_WRITE,
185 .description = "pause current audio file",
189 "\tClear the 'P' (playing) bit of the afs status flags.\n"
196 .perms = AFS_READ | AFS_WRITE,
197 .description = "start playing or resume playing when paused",
201 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
202 "\tresults in starting/continuing to stream.\n"
210 .description = "print status bar for current audio file",
211 .synopsis = "sb [n]",
214 "Without any arguments, sb continuously prints a status bar of the form\n"
216 " 12:34 [56:12] (56%) filename\n"
218 "indicating playing time, remaining time, percentage and the name of\n"
219 "the file beeing streamed. Use the optional number n to let stat exit\n"
220 "after having displayed the status bar n times.\n"
227 .description = "print name of audio file whenever it changes",
228 .synopsis = "sc [n]",
231 "\tsc prints exactly one line (the filename of the audio file\n"
232 "\tbeing played) whenever the audio file changes. Stops after\n"
233 "\tn iterations, or never if n is not specified.\n"
238 .handler = com_sender,
239 .perms = AFS_READ | AFS_WRITE,
240 .description = "control paraslash internal senders",
241 .synopsis = "sender [s cmd [arguments]]",
244 "send command cmd to sender s. cmd may be one of the following:\n"
245 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
246 "support each command. Try e.g. 'para_client sender http help' for\n"
247 "more information about the http sender. If no argument is given,\n"
248 "print out a list of all senders that are compiled in.\n"
255 .description = "print server info",
258 "Print server uptime and other information.\n"
265 .description = "print status info for current audio file",
266 .synopsis = "stat [n]",
269 "\tWithout any arguments, stat continuously prints status messages\n"
270 "\tof the audio file being streamed. Use the optional number n\n"
271 "\tto let stat exit after having displayed status n times.\n"
278 .perms = AFS_READ | AFS_WRITE,
279 .description = "stop playing",
283 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
290 .perms = AFS_READ | AFS_WRITE,
291 .description = "terminate para_server",
295 "Shuts down the server. Instead of this command, you can also send\n"
296 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
301 .handler = com_version,
303 .description = "print server's version",
304 .synopsis = "version",
306 "Show version and other info\n"
308 /* this indicates the end of the list. Do not touch. */
314 static void dummy(__unused int s)
317 static void mmd_dup(struct misc_meta_data *new_mmd)
325 * compute human readable string containing
326 * afs_status for given integer value
328 static char *afs_status_tohuman(unsigned int flags)
330 if (flags & AFS_PLAYING)
331 return para_strdup("playing");
332 else if (flags & AFS_NEXT)
333 return para_strdup("stopped");
335 return para_strdup("paused");
340 * return human readable permission string. Never returns NULL.
342 char *cmd_perms_itohuman(unsigned int perms)
344 char *msg = para_malloc(7 * sizeof(char));
346 msg[0] = perms & DB_READ? 'd' : '-';
347 msg[1] = perms & DB_WRITE? 'D' : '-';
348 msg[2] = perms & AFS_READ? 'a' : '-';
349 msg[3] = perms & AFS_WRITE? 'A' : '-';
355 * Never returns NULL.
357 static char *afs_get_status_flags(unsigned int flags)
359 char *msg = para_malloc(5 * sizeof(char));
361 msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
362 msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
363 msg[2] = (flags & AFS_NEXT)? 'N' : '_';
364 msg[3] = (flags & AFS_REPOS)? 'R' : '_';
370 * compute status bar string. Never returns NULL
372 char *get_sb_string(struct misc_meta_data *nmmd)
375 long long unsigned secs = 0, rsecs = 0, percent = 0;
377 base = para_basename(nmmd->filename);
379 return para_strdup("");
382 if (nmmd->chunks_total) {
383 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
384 / nmmd->chunks_total;
385 rsecs = (long long) nmmd->seconds_total *
386 (nmmd->chunks_total - nmmd->chunks_sent)
387 / nmmd->chunks_total;
388 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
389 / ((nmmd->chunks_total + 5) / 10);
391 ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
392 secs / 60, secs % 60,
393 rsecs / 60, rsecs % 60,
401 static char *get_status(struct misc_meta_data *nmmd)
403 char *bar, *ret, mtime[30] = "";
404 char *status, *flags; /* afs status info */
405 char *ut = uptime_str();
406 long offset = (nmmd->offset + 500) / 1000;
410 if (nmmd->audio_format >= 0) {
411 localtime_r(&nmmd->mtime, &mtime_tm);
412 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
414 /* report real status */
415 status = afs_status_tohuman(nmmd->afs_status_flags);
416 flags = afs_get_status_flags(nmmd->afs_status_flags);
417 bar = para_basename(nmmd->filename);
418 gettimeofday(&now, NULL);
420 "%s:%lu\n" "%s:%s\n" "%s:%i\n" "%s:%u\n"
421 "%s:%s\n" "%s:%s\n" "%s:%s\n" "%s:%s\n"
422 "%s:%li\n" "%s:%s\n" "%s" "%s"
423 "%s:%s\n" "%s:%lu.%lu\n" "%s:%lu.%lu\n",
424 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
425 status_item_list[SI_MTIME], mtime,
426 status_item_list[SI_LENGTH], nmmd->seconds_total,
427 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
429 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
430 status_item_list[SI_STATUS], status,
431 status_item_list[SI_STATUS_FLAGS], flags,
432 status_item_list[SI_DBTOOL], dblist[nmmd->dbt_num].name,
434 status_item_list[SI_OFFSET], offset,
435 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
437 nmmd->audio_file_info,
439 status_item_list[SI_UPTIME], ut,
440 status_item_list[SI_STREAM_START], nmmd->stream_start.tv_sec,
441 nmmd->stream_start.tv_usec,
442 status_item_list[SI_CURRENT_TIME], now.tv_sec, now.tv_usec
452 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
455 /* this has to match sender.h */
456 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
458 scd->sender_num = -1;
460 return -E_COMMAND_SYNTAX;
461 for (i = 0; senders[i].name; i++)
462 if (!strcmp(senders[i].name, argv[0]))
464 // PARA_DEBUG_LOG("%d:%s\n", argc, argv[0]);
465 if (!senders[i].name)
466 return -E_COMMAND_SYNTAX;
468 for (i = 0; subcmds[i]; i++)
469 if (!strcmp(subcmds[i], argv[1]))
472 return -E_COMMAND_SYNTAX;
474 // scd->self = *in_addr;
476 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
478 return -E_SENDER_CMD;
481 switch (scd->cmd_num) {
485 return -E_COMMAND_SYNTAX;
489 if (argc != 2 && argc != 3)
490 return -E_COMMAND_SYNTAX;
491 if (!inet_aton(argv[2], &scd->addr))
492 return -E_COMMAND_SYNTAX;
495 scd->netmask = atoi(argv[3]);
496 if (scd->netmask < 0 || scd->netmask > 32)
497 return -E_COMMAND_SYNTAX;
502 if (argc != 2 && argc != 3)
503 return -E_COMMAND_SYNTAX;
504 if (!inet_aton(argv[2], &scd->addr))
505 return -E_COMMAND_SYNTAX;
508 scd->port = atoi(argv[3]);
509 if (scd->port < 0 || scd->port > 65535)
510 return -E_COMMAND_SYNTAX;
514 return -E_COMMAND_SYNTAX;
519 static int com_sender(int fd, int argc, char **argv)
522 struct sender_command_data scd;
526 for (i = 0; senders[i].name; i++) {
527 char *tmp = make_message("%s%s\n",
528 msg? msg : "", senders[i].name);
532 ret = send_buffer(fd, msg);
536 ret = check_sender_args(argc - 1, argv + 1, &scd);
539 if (scd.sender_num < 0)
541 msg = senders[scd.sender_num].help();
542 send_buffer(fd, msg);
546 for (i = 0; i < 10; i++) {
548 if (mmd->sender_cmd_data.cmd_num >= 0) {
553 mmd->sender_cmd_data = scd;
557 return (i < 10)? 1 : -E_LOCK;
561 static int com_si(int fd, int argc, __unused char **argv)
565 char *dbtools = NULL, *sender_info = NULL, *sender_list = NULL;
566 struct mallinfo mi = mallinfo();
569 return -E_COMMAND_SYNTAX;
571 for (i = 0; dblist[i].name; i++) {
572 dbtools = para_strcat(dbtools, dblist[i].name);
573 dbtools = para_strcat(dbtools, " ");
575 for (i = 0; senders[i].name; i++) {
576 char *info = senders[i].info();
577 sender_info = para_strcat(sender_info, info);
579 sender_list = para_strcat(sender_list, senders[i].name);
580 sender_list = para_strcat(sender_list, " ");
583 ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
586 "connections (active/accepted/total): %u/%u/%u\n"
587 "current loglevel: %i\n"
588 "supported database tools: %s\n"
589 "supported audio formats: %s\n"
590 "supported senders: %s\n"
595 mmd->active_connections,
600 SUPPORTED_AUDIO_FORMATS,
613 static int com_version(int socket_fd, int argc, __unused char **argv)
616 return -E_COMMAND_SYNTAX;
617 return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
619 "built: " BUILD_DATE "\n"
620 SYSTEM ", " CC_VERSION "\n"
625 static int com_sc(int socket_fd, int argc, char **argv)
628 int ret, old = 0, count = -1; /* print af change forever */
631 count = atoi(argv[1]);
634 if (old != mmd->num_played) {
635 old = mmd->num_played;
636 name = para_strdup(mmd->filename);
640 ret = send_va_buffer(socket_fd, "%s\n", name);
645 if (argc && !--count)
653 static int com_sb(int socket_fd, int argc, char **argv)
656 int ret, nr = -1; /* status bar will be printed that many
657 * times. Negative value means: print
664 sb = get_sb_string(mmd);
666 ret = send_va_buffer(socket_fd, "%s\n", sb);
680 static int com_stat(int socket_fd, int argc, char **argv)
682 // char *old_stat = NULL, *old_dbinfo = NULL;
683 int ret, num = 0;/* status will be printed that many
684 * times. num <= 0 means: print forever
686 struct misc_meta_data tmp, *nmmd = &tmp;
689 signal(SIGUSR1, dummy);
696 s = get_status(nmmd);
697 ret = send_buffer(socket_fd, s);
704 usleep(500000 * 100);
710 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
714 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
715 char *perms = cmd_perms_itohuman(cmd->perms);
716 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
727 /* always returns string that must be freed by the caller in handeler */
728 static struct server_command *get_cmd_ptr(char *name, char **handler)
730 struct server_command *cmd = cmd_struct;
732 for (cmd = cmd_struct; cmd->name; cmd++)
733 if (!strcmp(cmd->name, name)) {
735 *handler = para_strdup("para_server"); /* server commands */
738 /* not found, look for dbtool commands */
741 *handler = make_message("the %s database tool", dblist[mmd->dbt_num].name);
742 cmd = dblist[mmd->dbt_num].cmd_list;
744 for (; cmd->name; cmd++)
745 if (!strcmp(cmd->name, name))
751 static int com_help(int fd, int argc, char **argv)
753 struct server_command *cmd;
754 char *perms, *handler;
758 /* no argument given, print list of commands */
759 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
762 handler = para_strdup(dblist[mmd->dbt_num].name);
763 cmd = dblist[mmd->dbt_num].cmd_list;
765 ret = send_description(fd, cmd, handler, 0);
769 /* argument given for help */
770 cmd = get_cmd_ptr(argv[1], &handler);
775 perms = cmd_perms_itohuman(cmd->perms);
776 ret = send_va_buffer(fd,
778 "SYNOPSIS\n\t para_client %s\n"
781 "This command is handled by %s.\n\n"
783 "Needed privileges for %s: %s\n",
798 static int com_hup(__unused int socket_fd, int argc, __unused char **argv)
801 return -E_COMMAND_SYNTAX;
802 kill(getppid(), SIGHUP);
807 static int com_term(__unused int socket_fd, int argc, __unused char **argv)
810 return -E_COMMAND_SYNTAX;
811 kill(getppid(), SIGTERM);
815 static int com_play(__unused int socket_fd, int argc, __unused char **argv)
818 return -E_COMMAND_SYNTAX;
820 mmd->new_afs_status_flags |= AFS_PLAYING;
821 mmd->new_afs_status_flags &= ~AFS_NOMORE;
828 static int com_stop(__unused int socket_fd, int argc, __unused char **argv)
831 return -E_COMMAND_SYNTAX;
833 mmd->new_afs_status_flags &= ~AFS_PLAYING;
834 mmd->new_afs_status_flags &= ~AFS_REPOS;
835 mmd->new_afs_status_flags |= AFS_NEXT;
841 static int com_pause(__unused int socket_fd, int argc, __unused char **argv)
844 return -E_COMMAND_SYNTAX;
848 mmd->new_afs_status_flags &= ~AFS_PLAYING;
849 mmd->new_afs_status_flags &= ~AFS_NEXT;
854 static int com_cdt(int fd, int argc, char **argv)
861 dbtool = para_strdup(dblist[mmd->dbt_num].name);
863 ret = send_va_buffer(fd, "%s\n", dbtool);
867 for (i = 0; dblist[i].name; i++) {
868 if (strcmp(dblist[i].name, argv[1]))
876 return -E_BAD_DBTOOL;
880 static int com_next(__unused int socket_fd, int argc, __unused char **argv)
883 return -E_COMMAND_SYNTAX;
885 mmd->new_afs_status_flags |= AFS_NEXT;
891 static int com_nomore(__unused int socket_fd, int argc, __unused char **argv)
894 return -E_COMMAND_SYNTAX;
896 if (afs_playing() || afs_paused())
897 mmd->new_afs_status_flags |= AFS_NOMORE;
903 static int com_ff(__unused int socket_fd, int argc, char **argv)
906 int ret, backwards = 0;
911 return -E_COMMAND_SYNTAX;
912 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
913 return -E_COMMAND_SYNTAX;
914 if (ret > 1 && c == '-')
915 backwards = 1; /* jmp backwards */
917 ret = -E_NO_AUDIO_FILE;
918 if (!mmd->chunks_total || !mmd->seconds_total)
920 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
922 promille -= 1000 * i / mmd->seconds_total;
924 promille += 1000 * i / mmd->seconds_total;
927 if (promille > 1000) {
928 mmd->new_afs_status_flags |= AFS_NEXT;
931 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
932 mmd->new_afs_status_flags |= AFS_REPOS;
933 mmd->new_afs_status_flags &= ~AFS_NEXT;
942 static int com_jmp(__unused int socket_fd, int argc, char **argv)
948 return -E_COMMAND_SYNTAX;
949 if (sscanf(argv[1], "%lu", &i) <= 0)
950 return -E_COMMAND_SYNTAX;
952 ret = -E_NO_AUDIO_FILE;
953 if (!mmd->chunks_total)
957 PARA_INFO_LOG("jumping to %lu%%\n", i);
958 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
959 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
960 mmd->chunks_sent, mmd->offset);
961 mmd->new_afs_status_flags |= AFS_REPOS;
962 mmd->new_afs_status_flags &= ~AFS_NEXT;
971 * check if perms are sufficient to exec a command having perms cmd_perms.
972 * Returns 0 if perms are sufficient, -E_PERM otherwise.
974 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
976 PARA_DEBUG_LOG("%s", "checking permissions\n");
977 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
981 * Parse first string from *cmd and lookup in table of valid commands.
982 * On error, NULL is returned.
984 static struct server_command *parse_cmd(const char *cmdstr)
989 sscanf(cmdstr, "%200s%n", buf, &n);
993 return get_cmd_ptr(buf, NULL);
996 long int para_rand(long unsigned max)
998 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
1002 /* Open user_list file, returns pointer to opened file on success,
1005 static FILE *open_user_list(char *file)
1007 PARA_DEBUG_LOG("opening user list %s\n", file);
1008 return fopen(file, "r");
1012 * lookup user in user_list file. Fills in a user struct containing
1013 * filename of the user's public key as well as the permissions of that user.
1014 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1016 static int get_user(struct user *user) {
1020 /* keyword, user, key, perms */
1021 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1024 file_ptr = open_user_list(user_list);
1027 while (fgets(line, MAXLINE, file_ptr)) {
1028 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1029 // "from config file\n", __func__, strlen(line));
1030 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1032 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1033 PARA_DEBUG_LOG("found entry for %s\n", n);
1034 strcpy(user->name, n);
1035 strcpy(user->pubkey_file, k);
1038 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1039 tmp[0], tmp[1], tmp[2], tmp[3]);
1040 PARA_DEBUG_LOG("found %i perm entries\n",
1045 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1047 if (!strcmp(tmp[num], "AFS_READ"))
1049 user->perms | AFS_READ;
1050 else if (!strcmp(tmp[num], "AFS_WRITE"))
1052 user->perms | AFS_WRITE;
1053 else if (!strcmp(tmp[num], "DB_READ"))
1054 user->perms = user->perms | DB_READ;
1055 else if (!strcmp(tmp[num], "DB_WRITE"))
1056 user->perms = user->perms | DB_WRITE;
1057 else /* unknown permission */
1058 PARA_WARNING_LOG("unknown permission:"
1069 static void init_rc4_keys(void)
1073 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1074 rc4_buf[i] = para_rand(256);
1075 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1076 (unsigned char) rc4_buf[0],
1077 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1078 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1079 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1082 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1084 RC4(&rc4_recv_key, len, indata, outdata);
1086 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1088 RC4(&rc4_send_key, len, indata, outdata);
1094 int handle_connect(int fd, struct sockaddr_in *addr)
1096 int numbytes, ret, argc, use_rc4 = 0;
1097 char buf[STRINGSIZE];
1098 unsigned char crypt_buf[MAXLINE];
1100 struct server_command *cmd = NULL;
1101 long unsigned challenge_nr, chall_response;
1103 char *p, *command = NULL;
1105 signal(SIGCHLD, SIG_IGN);
1106 signal(SIGINT, SIG_DFL);
1107 signal(SIGTERM, SIG_DFL);
1108 signal(SIGHUP, SIG_DFL);
1109 signal(SIGUSR1, SIG_IGN);
1112 challenge_nr = random();
1113 /* send Welcome message */
1114 ret = send_va_buffer(fd, "This is para_server, version " VERSION ".\n" );
1117 /* recv auth request line */
1118 ret = recv_buffer(fd, buf, sizeof(buf));
1127 if (strncmp(buf, "auth ", 5))
1130 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1131 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1133 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1136 // strcpy(u.name, buf + 5); /* ok, but ugly */
1137 PARA_DEBUG_LOG("received %s request for user %s\n",
1138 use_rc4? "rc4" : "auth", u.name);
1139 /* lookup user in list file */
1140 if ((ret = get_user(&u)) < 0)
1142 if (!ret) { /* user not found */
1143 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1147 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1151 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1152 /* We can't use send_buffer here since buf may contain null bytes */
1153 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1156 /* recv decrypted number */
1157 numbytes = recv_buffer(fd, buf, sizeof(buf));
1164 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1165 || chall_response != challenge_nr)
1167 /* auth successful. Send 'Proceed' message */
1168 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1169 sprintf(buf, "%s", PROCEED_MSG);
1172 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1173 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1176 numbytes = ret + strlen(PROCEED_MSG) + 1;
1178 numbytes = strlen(buf);
1179 ret = send_bin_buffer(fd, buf, numbytes);
1183 crypt_function_recv = rc4_recv;
1184 crypt_function_send = rc4_send;
1185 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1188 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1189 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1190 ret = -E_COMMAND_SYNTAX;
1191 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1193 command = para_strcat(command, buf);
1194 if ((p = strstr(command, EOC_MSG))) {
1204 if (!(cmd = parse_cmd(command)))
1206 /* valid command, check permissions */
1207 ret = check_perms(u.perms, cmd);
1210 /* valid command and sufficient perms */
1212 argc = split_args(command, &argv, '\n');
1213 argv[0] = cmd->name;
1215 mmd->num_commands++;
1217 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1218 inet_ntoa(addr->sin_addr));
1219 ret = cmd->handler(fd, argc, argv);
1225 if (ret != -E_SEND && ret != -E_RECV) {
1226 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1227 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1234 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1236 mmd->active_connections--;