3b92be657bd28b49ca690923583d2b42cb5dd770
[paraslash.git] / command.c
1 /*
2  * Copyright (C) 1997-2006 Andre Noll <maan@systemlinux.org>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 /** \file command.c does client authentication and executes server commands */
20
21 #include <malloc.h> /* mallinfo */
22 #include <sys/time.h> /* gettimeofday */
23 #include "crypt.h"
24 #include "server.cmdline.h"
25 #include "db.h"
26 #include "server.h"
27 #include "afs.h"
28 #include "send.h"
29 #include "rc4.h"
30 #include <openssl/rc4.h>
31 #include "error.h"
32 #include "net.h"
33 #include "daemon.h"
34 #include "string.h"
35
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];
43
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 selectors[];
48 extern struct audio_format afl[];
49 extern struct sender senders[];
50 extern char *user_list;
51 struct sockaddr_in *in_addr;
52
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 **);
70
71
72 /* commands that are handled by the server itself */
73 static struct server_command cmd_struct[] = {
74 {
75 .name = "chs",
76 .handler = com_chs,
77 .perms = DB_READ | DB_WRITE,
78 .description = "change the current audio file selector",
79 .synopsis = "chs [new_selector]",
80 .help =
81 "Shutdown the current selector and activate new_selector. If no\n"
82 "argument was given, print the name of the current selector.\n"
83 },
84
85 {
86 .name = "ff",
87 .handler = com_ff,
88 .perms = AFS_READ | AFS_WRITE,
89 .description = "jmp amount of time forwards or backwards "
90         "in current audio file",
91 .synopsis = "ff n[-]",
92 .help =
93
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"
97 "\n"
98 "EXAMPLE\n"
99 "\n"
100 "\t\tff 30-\n"
101 "\n"
102 "\tjumps 30 seconds backwards.\n"
103
104 },
105
106 {
107 .name = "help",
108 .handler = com_help,
109 .perms = 0,
110 .description = "print help text",
111 .synopsis = "help [command]",
112 .help =
113
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"
117
118 },
119
120 {
121 .name = "hup",
122 .handler = com_hup,
123 .perms = AFS_WRITE,
124 .description = "force reload of config file and log file",
125 .synopsis = "hup",
126 .help =
127
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"
130
131 },
132
133 {
134 .name = "jmp",
135 .handler = com_jmp,
136 .perms = AFS_READ | AFS_WRITE,
137 .description = "jmp to given position in current audio file",
138 .synopsis = "jmp [n]",
139 .help =
140
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"
144
145 },
146
147 {
148 .name = "next",
149 .handler = com_next,
150 .perms = AFS_READ | AFS_WRITE,
151 .description = "skip rest of current audio file",
152 .synopsis = "next",
153 .help =
154
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"
158
159
160 },
161
162 {
163 .name = "nomore",
164 .handler = com_nomore,
165 .perms = AFS_READ | AFS_WRITE,
166 .description = "stop playing after current audio file",
167 .synopsis = "nomore",
168 .help =
169
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"
173 "\n"
174 "Use this command instead of stop if you don't like\n"
175 "sudden endings.\n"
176
177 },
178
179 {
180 .name ="pause",
181 .handler = com_pause,
182 .perms = AFS_READ | AFS_WRITE,
183 .description = "pause current audio file",
184 .synopsis = "pause",
185 .help =
186
187 "\tClear the 'P' (playing) bit of the afs status flags.\n"
188
189 },
190
191 {
192 .name = "play",
193 .handler = com_play,
194 .perms = AFS_READ | AFS_WRITE,
195 .description = "start playing or resume playing when paused",
196 .synopsis = "play",
197 .help =
198
199 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
200 "\tresults in starting/continuing to stream.\n"
201
202 },
203
204 {
205 .name = "sb",
206 .handler = com_sb,
207 .perms = AFS_READ,
208 .description = "print status bar for current audio file",
209 .synopsis = "sb [n]",
210 .help =
211
212 "Without any arguments, sb continuously prints a status bar of the form\n"
213 "\n"
214 "       12:34 [56:12] (56%) filename\n"
215 "\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"
219
220 },
221 {
222 .name = "sc",
223 .handler = com_sc,
224 .perms = AFS_READ,
225 .description = "print name of audio file whenever it changes",
226 .synopsis = "sc [n]",
227 .help =
228
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"
232
233 },
234 {
235 .name = "sender",
236 .handler = com_sender,
237 .perms = AFS_READ | AFS_WRITE,
238 .description = "control paraslash internal senders",
239 .synopsis = "sender [s cmd [arguments]]",
240 .help =
241
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"
247
248 },
249 {
250 .name = "si",
251 .handler = com_si,
252 .perms = 0,
253 .description = "print server info",
254 .synopsis = "si",
255 .help =
256 "Print server uptime and other information.\n"
257 },
258
259 {
260 .name = "stat",
261 .handler = com_stat,
262 .perms = AFS_READ,
263 .description = "print status info for current audio file",
264 .synopsis = "stat [n]",
265 .help =
266
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"
270
271 },
272
273 {
274 .name = "stop",
275 .handler = com_stop,
276 .perms = AFS_READ | AFS_WRITE,
277 .description = "stop playing",
278 .synopsis = "stop",
279 .help =
280
281 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
282 "\tflags.\n"
283
284 },
285 {
286 .name = "term",
287 .handler = com_term,
288 .perms = AFS_READ | AFS_WRITE,
289 .description = "terminate para_server",
290 .synopsis = "term",
291 .help =
292
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"
295
296 },
297 {
298 .name = "version",
299 .handler = com_version,
300 .perms = 0,
301 .description = "print server's version",
302 .synopsis = "version",
303 .help =
304 "Show version and other info\n"
305 },
306 /* this indicates the end of the list. Do not touch. */
307 {
308 .name = NULL,
309 }
310 };
311
312 static void dummy(__unused int s)
313 {}
314
315 static void mmd_dup(struct misc_meta_data *new_mmd)
316 {
317         mmd_lock();
318         *new_mmd = *mmd;
319         mmd_unlock();
320 }
321
322 /*
323  * compute human readable string containing
324  * afs_status for given integer value
325  */
326 static char *afs_status_tohuman(unsigned int flags)
327 {
328         if (flags & AFS_PLAYING)
329                 return para_strdup("playing");
330         else if (flags & AFS_NEXT)
331                 return para_strdup("stopped");
332         else
333                 return para_strdup("paused");
334 }
335
336 /*
337  * return human readable permission string. Never returns NULL.
338  */
339 char *cmd_perms_itohuman(unsigned int perms)
340 {
341         char *msg = para_malloc(7 * sizeof(char));
342
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' : '-';
347         msg[4] = '\0';
348         return msg;
349 }
350
351 /*
352  * Never returns NULL.
353  */
354 static char *afs_get_status_flags(unsigned int flags)
355 {
356         char *msg = para_malloc(5 * sizeof(char));
357
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' : '_';
362         msg[4] = '\0';
363         return msg;
364 }
365
366 /*
367  * compute status bar string. Never returns NULL
368  */
369 char *get_sb_string(struct misc_meta_data *nmmd)
370 {
371         char *base, *ret;
372         long long unsigned secs = 0, rsecs = 0, percent = 0;
373
374         base = para_basename(nmmd->filename);
375         if (!base)
376                 return para_strdup("");
377         if (!base[0])
378                 return base;
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);
387         }
388         ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
389                 secs / 60, secs % 60,
390                 rsecs / 60, rsecs % 60,
391                 percent,
392                 base
393         );
394         free(base);
395         return ret;
396 }
397
398 static char *get_status(struct misc_meta_data *nmmd)
399 {
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;
404         struct timeval now;
405         struct tm mtime_tm;
406
407         if (nmmd->audio_format >= 0) {
408                 localtime_r(&nmmd->mtime, &mtime_tm);
409                 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
410         }
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);
416         ret = make_message(
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,
425
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], selectors[nmmd->selector_num].name,
430
431                 status_item_list[SI_OFFSET], offset,
432                 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
433                 nmmd->selector_info,
434                 nmmd->audio_file_info,
435
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
440
441         );
442         free(bar);
443         free(flags);
444         free(status);
445         free(ut);
446         return ret;
447 }
448
449 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
450 {
451         int i;
452         /* this has to match sender.h */
453         const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
454
455         scd->sender_num = -1;
456         if (argc < 0)
457                 return -E_COMMAND_SYNTAX;
458         for (i = 0; senders[i].name; i++)
459                 if (!strcmp(senders[i].name, argv[0]))
460                         break;
461 //      PARA_DEBUG_LOG("%d:%s\n", argc, argv[0]);
462         if (!senders[i].name)
463                 return -E_COMMAND_SYNTAX;
464         scd->sender_num = i;
465         for (i = 0; subcmds[i]; i++)
466                 if (!strcmp(subcmds[i], argv[1]))
467                         break;
468         if (!subcmds[i])
469                 return -E_COMMAND_SYNTAX;
470         scd->cmd_num = i;
471 //      scd->self = *in_addr;
472         mmd_lock();
473         if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
474                 mmd_unlock();
475                 return -E_SENDER_CMD;
476         }
477         mmd_unlock();
478         switch (scd->cmd_num) {
479         case SENDER_ON:
480         case SENDER_OFF:
481                 if (argc != 1)
482                         return -E_COMMAND_SYNTAX;
483                 break;
484         case SENDER_DENY:
485         case SENDER_ALLOW:
486                 if (argc != 2 && argc != 3)
487                         return -E_COMMAND_SYNTAX;
488                 if (!inet_aton(argv[2], &scd->addr))
489                         return -E_COMMAND_SYNTAX;
490                 scd->netmask = 32;
491                 if (argc == 3) {
492                         scd->netmask = atoi(argv[3]);
493                         if (scd->netmask < 0 || scd->netmask > 32)
494                                 return -E_COMMAND_SYNTAX;
495                 }
496                 break;
497         case SENDER_ADD:
498         case SENDER_DELETE:
499                 if (argc != 2 && argc != 3)
500                         return -E_COMMAND_SYNTAX;
501                 if (!inet_aton(argv[2], &scd->addr))
502                         return -E_COMMAND_SYNTAX;
503                 scd->port = -1;
504                 if (argc == 3) {
505                         scd->port = atoi(argv[3]);
506                         if (scd->port < 0 || scd->port > 65535)
507                                 return -E_COMMAND_SYNTAX;
508                 }
509                 break;
510         default:
511                 return -E_COMMAND_SYNTAX;
512         }
513         return 1;
514 }
515
516 static int com_sender(int fd, int argc, char **argv)
517 {
518         int i, ret;
519         struct sender_command_data scd;
520
521         if (!argc) {
522                 char *msg = NULL;
523                 for (i = 0; senders[i].name; i++) {
524                         char *tmp = make_message("%s%s\n",
525                                 msg? msg : "", senders[i].name);
526                         free(msg);
527                         msg = tmp;
528                 }
529                 ret = send_buffer(fd, msg);
530                 free(msg);
531                 return ret;
532         }
533         ret = check_sender_args(argc - 1, argv + 1, &scd);
534         if (ret < 0) {
535                 char *msg;
536                 if (scd.sender_num < 0)
537                         return ret;
538                 msg = senders[scd.sender_num].help();
539                 send_buffer(fd, msg);
540                 free(msg);
541                 return 1;
542         }
543         for (i = 0; i < 10; i++) {
544                 mmd_lock();
545                 if (mmd->sender_cmd_data.cmd_num >= 0) {
546                         mmd_unlock();
547                         usleep(100 * 1000);
548                         continue;
549                 }
550                 mmd->sender_cmd_data = scd;
551                 mmd_unlock();
552                 break;
553         }
554         return (i < 10)? 1 : -E_LOCK;
555 }
556
557 /* server info */
558 static int com_si(int fd, int argc, __unused char **argv)
559 {
560         int i, ret;
561         char *ut;
562         char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
563         struct mallinfo mi = mallinfo();
564
565         if (argc)
566                 return -E_COMMAND_SYNTAX;
567         mmd_lock();
568         for (i = 0; selectors[i].name; i++) {
569                 selector_string = para_strcat(selector_string, selectors[i].name);
570                 selector_string = para_strcat(selector_string, " ");
571         }
572         for (i = 0; senders[i].name; i++) {
573                 char *info = senders[i].info();
574                 sender_info = para_strcat(sender_info, info);
575                 free(info);
576                 sender_list = para_strcat(sender_list, senders[i].name);
577                 sender_list = para_strcat(sender_list, " ");
578         }
579         ut = uptime_str();
580         ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
581                 "pid: %d\n"
582                 "mallinfo: %d\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"
588                 "%s",
589                 ut, mmd->num_played,
590                 getppid(),
591                 mi.arena / 1024,
592                 mmd->active_connections,
593                 mmd->num_commands,
594                 mmd->num_connects,
595                 conf.loglevel_arg,
596                 selector_string,
597                 SUPPORTED_AUDIO_FORMATS,
598                 sender_list,
599                 sender_info
600         );
601         mmd_unlock();
602         free(ut);
603         free(selector_string);
604         free(sender_list);
605         free(sender_info);
606         return ret;
607 }
608
609 /* version */
610 static int com_version(int socket_fd, int argc, __unused char **argv)
611 {
612         if (argc)
613                 return -E_COMMAND_SYNTAX;
614         return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
615                         COPYRIGHT "\n"
616                         "built: " BUILD_DATE "\n"
617                         SYSTEM ", " CC_VERSION "\n"
618                 );
619 }
620
621 /* sc */
622 static int com_sc(int socket_fd, int argc, char **argv)
623 {
624         char *name = NULL;
625         int ret, old = 0, count = -1; /* print af change forever */
626
627         if (argc)
628                 count = atoi(argv[1]);
629 repeat:
630         mmd_lock();
631         if (old != mmd->num_played) {
632                 old = mmd->num_played;
633                 name = para_strdup(mmd->filename);
634         }
635         mmd_unlock();
636         if (name) {
637                 ret = send_va_buffer(socket_fd, "%s\n", name);
638                 free(name);
639                 name = NULL;
640                 if (ret < 0)
641                         return ret;
642                 if (argc && !--count)
643                         return 1;
644         }
645         usleep(500000);
646         goto repeat;
647 }
648
649 /* sb */
650 static int com_sb(int socket_fd, int argc, char **argv)
651 {
652         char *sb;
653         int ret, nr = -1;       /* status bar will be printed that many
654                                  * times. Negative value means: print
655                                  * forever
656                                  */
657         if (argc)
658                 nr = atoi(argv[1]);
659         while (nr) {
660                 mmd_lock();
661                 sb = get_sb_string(mmd);
662                 mmd_unlock();
663                 ret = send_va_buffer(socket_fd, "%s\n", sb);
664                 free(sb);
665                 if (ret < 0)
666                         return ret;
667                 if (nr == 1)
668                         return 1;
669                 usleep(500000);
670                 if (nr > 0)
671                         nr--;
672         }
673         return 1;
674 }
675
676 /* stat */
677 static int com_stat(int socket_fd, int argc, char **argv)
678 {
679         int ret, num = 0;/* status will be printed that many
680                           * times. num <= 0 means: print forever
681                           */
682         struct misc_meta_data tmp, *nmmd = &tmp;
683         char *s;
684
685         signal(SIGUSR1, dummy);
686
687         if (argc)
688                 num = atoi(argv[1]);
689         for (;;) {
690
691                 mmd_dup(nmmd);
692                 s = get_status(nmmd);
693                 ret = send_buffer(socket_fd, s);
694                 free(s);
695                 if (ret < 0)
696                         goto out;
697                 ret = 1;
698                 if (num == 1)
699                         goto out;
700                 usleep(500000 * 100);
701         }
702 out:
703         return ret;
704 }
705
706 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
707 {
708         int ret, i;
709
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,
713                         handler,
714                         perms,
715                         cmd->description);
716                 free(perms);
717                 if (ret < 0)
718                         return ret;
719         }
720         return 1;
721 }
722
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)
725 {
726         struct server_command *cmd = cmd_struct;
727
728         for (cmd = cmd_struct; cmd->name; cmd++)
729                 if (!strcmp(cmd->name, name)) {
730                         if (handler)
731                                 *handler = para_strdup("para_server"); /* server commands */
732                         return cmd;
733                 }
734         /* not found, look for commands supported by the current selector */
735         mmd_lock();
736         if (handler)
737                 *handler = make_message("the %s selector",
738                         selectors[mmd->selector_num].name);
739         cmd = selectors[mmd->selector_num].cmd_list;
740         mmd_unlock();
741         for (; cmd->name; cmd++)
742                 if (!strcmp(cmd->name, name))
743                         return cmd;
744         return NULL;
745 }
746
747 /* help */
748 static int com_help(int fd, int argc, char **argv)
749 {
750         struct server_command *cmd;
751         char *perms, *handler;
752         int ret;
753
754         if (!argc) {
755                 /* no argument given, print list of commands */
756                 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
757                         return ret;
758                 mmd_lock();
759                 handler = para_strdup(selectors[mmd->selector_num].name);
760                 cmd = selectors[mmd->selector_num].cmd_list;
761                 mmd_unlock();
762                 ret = send_description(fd, cmd, handler, 0);
763                 free(handler);
764                 return ret;
765         }
766         /* argument given for help */
767         cmd = get_cmd_ptr(argv[1], &handler);
768         if (!cmd) {
769                 free(handler);
770                 return -E_BAD_CMD;
771         }
772         perms = cmd_perms_itohuman(cmd->perms);
773         ret = send_va_buffer(fd,
774                 "NAME\n\t%s - %s\n"
775                 "SYNOPSIS\n\t para_client %s\n"
776                 "DESCRIPTION\n%s\n"
777                 "HANDLER\n"
778                 "This command is handled by %s.\n\n"
779                 "PERMISSIONS\n"
780                 "Needed privileges for %s: %s\n",
781                 argv[1],
782                 cmd->description,
783                 cmd->synopsis,
784                 cmd->help,
785                 handler,
786                 argv[1],
787                 perms
788         );
789         free(perms);
790         free(handler);
791         return ret;
792 }
793
794 /* hup */
795 static int com_hup(__unused int socket_fd, int argc, __unused char **argv)
796 {
797         if (argc)
798                 return -E_COMMAND_SYNTAX;
799         kill(getppid(), SIGHUP);
800         return 1;
801 }
802
803 /* term */
804 static int com_term(__unused int socket_fd, int argc, __unused char **argv)
805 {
806         if (argc)
807                 return -E_COMMAND_SYNTAX;
808         kill(getppid(), SIGTERM);
809         return 1;
810 }
811
812 static int com_play(__unused int socket_fd, int argc, __unused char **argv)
813 {
814         if (argc)
815                 return -E_COMMAND_SYNTAX;
816         mmd_lock();
817         mmd->new_afs_status_flags |= AFS_PLAYING;
818         mmd->new_afs_status_flags &= ~AFS_NOMORE;
819         mmd_unlock();
820         return 1;
821
822 }
823
824 /* stop */
825 static int com_stop(__unused int socket_fd, int argc, __unused char **argv)
826 {
827         if (argc)
828                 return -E_COMMAND_SYNTAX;
829         mmd_lock();
830         mmd->new_afs_status_flags &= ~AFS_PLAYING;
831         mmd->new_afs_status_flags &= ~AFS_REPOS;
832         mmd->new_afs_status_flags |= AFS_NEXT;
833         mmd_unlock();
834         return 1;
835 }
836
837 /* pause */
838 static int com_pause(__unused int socket_fd, int argc, __unused char **argv)
839 {
840         if (argc)
841                 return -E_COMMAND_SYNTAX;
842         mmd_lock();
843         if (!afs_paused())
844                 mmd->events++;
845         mmd->new_afs_status_flags &= ~AFS_PLAYING;
846         mmd->new_afs_status_flags &= ~AFS_NEXT;
847         mmd_unlock();
848         return 1;
849 }
850
851 static int com_chs(int fd, int argc, char **argv)
852 {
853         int i, ret;
854
855         if (!argc) {
856                 char *selector;
857                 mmd_lock();
858                 selector = para_strdup(selectors[mmd->selector_num].name);
859                 mmd_unlock();
860                 ret = send_va_buffer(fd, "%s\n", selector);
861                 free(selector);
862                 return ret;
863         }
864         for (i = 0; selectors[i].name; i++) {
865                 if (strcmp(selectors[i].name, argv[1]))
866                         continue;
867                 mmd_lock();
868                 mmd->selector_change = i;
869                 mmd->events++;
870                 mmd_unlock();
871                 return 1;
872         }
873         return -E_BAD_SELECTOR;
874 }
875
876 /* next */
877 static int com_next(__unused int socket_fd, int argc, __unused char **argv)
878 {
879         if (argc)
880                 return -E_COMMAND_SYNTAX;
881         mmd_lock();
882         mmd->events++;
883         mmd->new_afs_status_flags |= AFS_NEXT;
884         mmd_unlock();
885         return 1;
886 }
887
888 /* nomore */
889 static int com_nomore(__unused int socket_fd, int argc, __unused char **argv)
890 {
891         if (argc)
892                 return -E_COMMAND_SYNTAX;
893         mmd_lock();
894         if (afs_playing() || afs_paused())
895                 mmd->new_afs_status_flags |= AFS_NOMORE;
896         mmd_unlock();
897         return 1;
898 }
899
900 /* ff */
901 static int com_ff(__unused int socket_fd, int argc, char **argv)
902 {
903         long promille;
904         int ret, backwards = 0;
905         unsigned i;
906         char c;
907
908         if (!argc)
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 */
914         mmd_lock();
915         ret = -E_NO_AUDIO_FILE;
916         if (!mmd->chunks_total || !mmd->seconds_total)
917                 goto out;
918         promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
919         if (backwards)
920                 promille -= 1000 * i / mmd->seconds_total;
921         else
922                 promille += 1000 * i / mmd->seconds_total;
923         if (promille < 0)
924                 promille = 0;
925         if (promille >  1000) {
926                 mmd->new_afs_status_flags |= AFS_NEXT;
927                 goto out;
928         }
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;
932         mmd->events++;
933         ret = 1;
934 out:
935         mmd_unlock();
936         return ret;
937 }
938
939 /* jmp */
940 static int com_jmp(__unused int socket_fd, int argc, char **argv)
941 {
942         long unsigned int i;
943         int ret;
944
945         if (!argc)
946                 return -E_COMMAND_SYNTAX;
947         if (sscanf(argv[1], "%lu", &i) <= 0)
948                 return -E_COMMAND_SYNTAX;
949         mmd_lock();
950         ret = -E_NO_AUDIO_FILE;
951         if (!mmd->chunks_total)
952                 goto out;
953         if (i > 100)
954                 i = 100;
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;
961         ret = 1;
962         mmd->events++;
963 out:
964         mmd_unlock();
965         return ret;
966 }
967
968 /*
969  * check if perms are sufficient to exec a command having perms cmd_perms.
970  * Returns 0 if perms are sufficient, -E_PERM otherwise.
971  */
972 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
973 {
974         PARA_DEBUG_LOG("%s", "checking permissions\n");
975         return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
976 }
977
978 /*
979  * Parse first string from *cmd and lookup in table of valid commands.
980  * On error, NULL is returned.
981  */
982 static struct server_command *parse_cmd(const char *cmdstr)
983 {
984         char buf[255];
985         int n = 0;
986
987         sscanf(cmdstr, "%200s%n", buf, &n);
988         if (!n)
989                 return NULL;
990         buf[n] = '\0';
991         return get_cmd_ptr(buf, NULL);
992 }
993
994 long int para_rand(long unsigned max)
995 {
996         return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
997 }
998
999 /* Open user_list file, returns pointer to opened file on success,
1000  * NULL on errors
1001  */
1002 static FILE *open_user_list(char *file)
1003 {
1004         PARA_DEBUG_LOG("opening user list %s\n", file);
1005         return fopen(file, "r");
1006 }
1007
1008 /*
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.
1012  */
1013 static int get_user(struct user *user) {
1014         FILE *file_ptr;
1015         char *char_ptr;
1016         char line[MAXLINE];
1017         /* keyword, user, key, perms */
1018         char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1019         int num;
1020
1021         file_ptr = open_user_list(user_list);
1022         if (!file_ptr)
1023                 return -E_USERLIST;
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)
1028                         continue;
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);
1033                         user->perms = 0;
1034                         char_ptr = p;
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",
1038                                 num);
1039                         user->perms = 0;
1040                         while (num > 0) {
1041                                 num--;
1042                                 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1043                                 //      num, tmp[num]);
1044                                 if (!strcmp(tmp[num], "AFS_READ"))
1045                                         user->perms =
1046                                                 user->perms | AFS_READ;
1047                                 else if (!strcmp(tmp[num], "AFS_WRITE"))
1048                                         user->perms =
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:"
1056                                                 "%s\n", tmp[num]);
1057                         }
1058                         fclose(file_ptr);
1059                         return 1;
1060                 }
1061         }
1062         fclose(file_ptr);
1063         return 0;
1064 }
1065
1066 static void init_rc4_keys(void)
1067 {
1068         int i;
1069
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);
1077 }
1078
1079 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1080 {
1081         RC4(&rc4_recv_key, len, indata, outdata);
1082 }
1083
1084 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1085 {
1086         RC4(&rc4_send_key, len, indata, outdata);
1087 }
1088
1089 int handle_connect(int fd, struct sockaddr_in *addr)
1090 {
1091         int numbytes, ret, argc, use_rc4 = 0;
1092         char buf[STRINGSIZE];
1093         unsigned char crypt_buf[MAXLINE];
1094         struct user u;
1095         struct server_command *cmd = NULL;
1096         long unsigned challenge_nr, chall_response;
1097         char **argv = NULL;
1098         char *p, *command = NULL;
1099
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);
1105
1106         in_addr = addr;
1107         challenge_nr = random();
1108         /* send Welcome message */
1109         ret = send_va_buffer(fd, "This is para_server, version " VERSION  ".\n" );
1110         if (ret < 0)
1111                 goto err_out;
1112         /* recv auth request line */
1113         ret = recv_buffer(fd, buf, sizeof(buf));
1114         if (ret < 0)
1115                 goto err_out;
1116         if (ret <= 6) {
1117                 ret = -E_AUTH;
1118                 goto err_out;
1119         }
1120         numbytes = ret;
1121         ret = -E_AUTH;
1122         if (strncmp(buf, "auth ", 5))
1123                 goto err_out;
1124
1125         if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1126                 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1127         else {
1128                 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1129                 use_rc4 = 1;
1130         }
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)
1136                 goto err_out;
1137         if (!ret) { /* user not found */
1138                 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1139                 ret = -E_BAD_USER;
1140                 goto err_out;
1141         }
1142         ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1143         if (ret <= 0)
1144                 goto err_out;
1145         numbytes = ret;
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);
1149         if (ret < 0)
1150                 goto err_out;
1151         /* recv decrypted number */
1152         numbytes = recv_buffer(fd, buf, sizeof(buf));
1153         ret = numbytes;
1154         if (ret < 0)
1155                 goto err_out;
1156         ret = -E_AUTH;
1157         if (!numbytes)
1158                 goto err_out;
1159         if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1160                         || chall_response != challenge_nr)
1161                 goto err_out;
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);
1165         if (use_rc4) {
1166                 init_rc4_keys();
1167                 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1168                         (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1169                 if (ret <= 0)
1170                         goto err_out;
1171                 numbytes = ret + strlen(PROCEED_MSG) + 1;
1172         } else
1173                 numbytes = strlen(buf);
1174         ret = send_bin_buffer(fd, buf, numbytes);
1175         if (ret < 0)
1176                 goto err_out;
1177         if (use_rc4) {
1178                 crypt_function_recv = rc4_recv;
1179                 crypt_function_send = rc4_send;
1180                 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1181         }
1182         /* read command */
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 */
1187                         goto err_out;
1188                 command = para_strcat(command, buf);
1189                 if ((p = strstr(command, EOC_MSG))) {
1190                         *p = '\0';
1191                         break;
1192                 }
1193         }
1194         ret = numbytes;
1195         if (ret < 0)
1196                 goto err_out;
1197         ret = -E_BAD_CMD;
1198         /* parse command */
1199         if (!(cmd = parse_cmd(command)))
1200                 goto err_out;
1201         /* valid command, check permissions */
1202         ret = check_perms(u.perms, cmd);
1203         if (ret < 0)
1204                 goto err_out;
1205         /* valid command and sufficient perms */
1206         alarm(0);
1207         argc = split_args(command, &argv, '\n');
1208         mmd_lock();
1209         mmd->num_commands++;
1210         mmd_unlock();
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);
1214         if (ret >= 0) {
1215                 ret = EXIT_SUCCESS;
1216                 goto out;
1217         }
1218 err_out:
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));
1222         }
1223         ret = EXIT_FAILURE;
1224 out:
1225         free(command);
1226         free(argv);
1227         mmd_lock();
1228         if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1229                 mmd->events++;
1230         mmd->active_connections--;
1231         mmd_unlock();
1232         return ret;
1233 }