7df01083b717bf5276d8223af1c57ab4d11d976f
[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 < 2)
457                 return -E_COMMAND_SYNTAX;
458         for (i = 0; senders[i].name; i++)
459                 if (!strcmp(senders[i].name, argv[1]))
460                         break;
461         PARA_DEBUG_LOG("%d:%s\n", argc, argv[1]);
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[2]))
467                         break;
468         if (!subcmds[i])
469                 return -E_COMMAND_SYNTAX;
470         scd->cmd_num = i;
471         mmd_lock();
472         if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
473                 mmd_unlock();
474                 return -E_SENDER_CMD;
475         }
476         mmd_unlock();
477         switch (scd->cmd_num) {
478         case SENDER_ON:
479         case SENDER_OFF:
480                 if (argc != 3)
481                         return -E_COMMAND_SYNTAX;
482                 break;
483         case SENDER_DENY:
484         case SENDER_ALLOW:
485                 if (argc != 4 && argc != 5)
486                         return -E_COMMAND_SYNTAX;
487                 if (!inet_aton(argv[3], &scd->addr))
488                         return -E_COMMAND_SYNTAX;
489                 scd->netmask = 32;
490                 if (argc == 5) {
491                         scd->netmask = atoi(argv[4]);
492                         if (scd->netmask < 0 || scd->netmask > 32)
493                                 return -E_COMMAND_SYNTAX;
494                 }
495                 break;
496         case SENDER_ADD:
497         case SENDER_DELETE:
498                 if (argc != 4 && argc != 5)
499                         return -E_COMMAND_SYNTAX;
500                 if (!inet_aton(argv[3], &scd->addr))
501                         return -E_COMMAND_SYNTAX;
502                 scd->port = -1;
503                 if (argc == 5) {
504                         scd->port = atoi(argv[4]);
505                         if (scd->port < 0 || scd->port > 65535)
506                                 return -E_COMMAND_SYNTAX;
507                 }
508                 break;
509         default:
510                 return -E_COMMAND_SYNTAX;
511         }
512         return 1;
513 }
514
515 static int com_sender(int fd, int argc, char **argv)
516 {
517         int i, ret;
518         struct sender_command_data scd;
519
520         if (argc < 2) {
521                 char *msg = NULL;
522                 for (i = 0; senders[i].name; i++) {
523                         char *tmp = make_message("%s%s\n",
524                                 msg? msg : "", senders[i].name);
525                         free(msg);
526                         msg = tmp;
527                 }
528                 ret = send_buffer(fd, msg);
529                 free(msg);
530                 return ret;
531         }
532         ret = check_sender_args(argc, argv, &scd);
533         if (ret < 0) {
534                 char *msg;
535                 if (scd.sender_num < 0)
536                         return ret;
537                 msg = senders[scd.sender_num].help();
538                 send_buffer(fd, msg);
539                 free(msg);
540                 return 1;
541         }
542         for (i = 0; i < 10; i++) {
543                 mmd_lock();
544                 if (mmd->sender_cmd_data.cmd_num >= 0) {
545                         mmd_unlock();
546                         usleep(100 * 1000);
547                         continue;
548                 }
549                 mmd->sender_cmd_data = scd;
550                 mmd_unlock();
551                 break;
552         }
553         return (i < 10)? 1 : -E_LOCK;
554 }
555
556 /* server info */
557 static int com_si(int fd, int argc, __unused char **argv)
558 {
559         int i, ret;
560         char *ut;
561         char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
562         struct mallinfo mi = mallinfo();
563
564         if (argc != 1)
565                 return -E_COMMAND_SYNTAX;
566         mmd_lock();
567         for (i = 0; selectors[i].name; i++) {
568                 selector_string = para_strcat(selector_string, selectors[i].name);
569                 selector_string = para_strcat(selector_string, " ");
570         }
571         for (i = 0; senders[i].name; i++) {
572                 char *info = senders[i].info();
573                 sender_info = para_strcat(sender_info, info);
574                 free(info);
575                 sender_list = para_strcat(sender_list, senders[i].name);
576                 sender_list = para_strcat(sender_list, " ");
577         }
578         ut = uptime_str();
579         ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
580                 "pid: %d\n"
581                 "mallinfo: %d\n"
582                 "connections (active/accepted/total): %u/%u/%u\n"
583                 "current loglevel: %i\n"
584                 "supported audio file selectors: %s\n"
585                 "supported audio formats: %s\n"
586                 "supported senders: %s\n"
587                 "%s",
588                 ut, mmd->num_played,
589                 getppid(),
590                 mi.arena / 1024,
591                 mmd->active_connections,
592                 mmd->num_commands,
593                 mmd->num_connects,
594                 conf.loglevel_arg,
595                 selector_string,
596                 SUPPORTED_AUDIO_FORMATS,
597                 sender_list,
598                 sender_info
599         );
600         mmd_unlock();
601         free(ut);
602         free(selector_string);
603         free(sender_list);
604         free(sender_info);
605         return ret;
606 }
607
608 /* version */
609 static int com_version(int socket_fd, int argc, __unused char **argv)
610 {
611         if (argc != 1)
612                 return -E_COMMAND_SYNTAX;
613         return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
614                         COPYRIGHT "\n"
615                         "built: " BUILD_DATE "\n"
616                         SYSTEM ", " CC_VERSION "\n"
617                 );
618 }
619
620 /* sc */
621 static int com_sc(int socket_fd, int argc, char **argv)
622 {
623         char *name = NULL;
624         int ret, old = 0, count = -1; /* print af change forever */
625
626         if (argc > 1)
627                 count = atoi(argv[1]);
628 repeat:
629         mmd_lock();
630         if (old != mmd->num_played) {
631                 old = mmd->num_played;
632                 name = para_strdup(mmd->filename);
633         }
634         mmd_unlock();
635         if (name) {
636                 ret = send_va_buffer(socket_fd, "%s\n", name);
637                 free(name);
638                 name = NULL;
639                 if (ret < 0)
640                         return ret;
641                 if (argc > 1 && !--count)
642                         return 1;
643         }
644         usleep(500000);
645         goto repeat;
646 }
647
648 /* sb */
649 static int com_sb(int socket_fd, int argc, char **argv)
650 {
651         char *sb;
652         int ret, nr = -1;       /* status bar will be printed that many
653                                  * times. Negative value means: print
654                                  * forever
655                                  */
656         if (argc > 1)
657                 nr = atoi(argv[1]);
658         while (nr) {
659                 mmd_lock();
660                 sb = get_sb_string(mmd);
661                 mmd_unlock();
662                 ret = send_va_buffer(socket_fd, "%s\n", sb);
663                 free(sb);
664                 if (ret < 0)
665                         return ret;
666                 if (nr == 1)
667                         return 1;
668                 usleep(500000);
669                 if (nr > 0)
670                         nr--;
671         }
672         return 1;
673 }
674
675 /* stat */
676 static int com_stat(int socket_fd, int argc, char **argv)
677 {
678         int ret, num = 0;/* status will be printed that many
679                           * times. num <= 0 means: print forever
680                           */
681         struct misc_meta_data tmp, *nmmd = &tmp;
682         char *s;
683
684         signal(SIGUSR1, dummy);
685
686         if (argc > 1)
687                 num = atoi(argv[1]);
688         for (;;) {
689
690                 mmd_dup(nmmd);
691                 s = get_status(nmmd);
692                 ret = send_buffer(socket_fd, s);
693                 free(s);
694                 if (ret < 0)
695                         goto out;
696                 ret = 1;
697                 if (num == 1)
698                         goto out;
699                 usleep(500000 * 100);
700         }
701 out:
702         return ret;
703 }
704
705 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
706 {
707         int ret, i;
708
709         for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
710                 char *perms = cmd_perms_itohuman(cmd->perms);
711                 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
712                         handler,
713                         perms,
714                         cmd->description);
715                 free(perms);
716                 if (ret < 0)
717                         return ret;
718         }
719         return 1;
720 }
721
722 /* always returns string that must be freed by the caller in handler */
723 static struct server_command *get_cmd_ptr(char *name, char **handler)
724 {
725         struct server_command *cmd = cmd_struct;
726
727         for (cmd = cmd_struct; cmd->name; cmd++)
728                 if (!strcmp(cmd->name, name)) {
729                         if (handler)
730                                 *handler = para_strdup("para_server"); /* server commands */
731                         return cmd;
732                 }
733         /* not found, look for commands supported by the current selector */
734         mmd_lock();
735         if (handler)
736                 *handler = make_message("the %s selector",
737                         selectors[mmd->selector_num].name);
738         cmd = selectors[mmd->selector_num].cmd_list;
739         mmd_unlock();
740         for (; cmd->name; cmd++)
741                 if (!strcmp(cmd->name, name))
742                         return cmd;
743         return NULL;
744 }
745
746 /* help */
747 static int com_help(int fd, int argc, char **argv)
748 {
749         struct server_command *cmd;
750         char *perms, *handler;
751         int ret;
752
753         if (argc < 2) {
754                 /* no argument given, print list of commands */
755                 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
756                         return ret;
757                 mmd_lock();
758                 handler = para_strdup(selectors[mmd->selector_num].name);
759                 cmd = selectors[mmd->selector_num].cmd_list;
760                 mmd_unlock();
761                 ret = send_description(fd, cmd, handler, 0);
762                 free(handler);
763                 return ret;
764         }
765         /* argument given for help */
766         cmd = get_cmd_ptr(argv[1], &handler);
767         if (!cmd) {
768                 free(handler);
769                 return -E_BAD_CMD;
770         }
771         perms = cmd_perms_itohuman(cmd->perms);
772         ret = send_va_buffer(fd,
773                 "NAME\n\t%s - %s\n"
774                 "SYNOPSIS\n\t para_client %s\n"
775                 "DESCRIPTION\n%s\n"
776                 "HANDLER\n"
777                 "This command is handled by %s.\n\n"
778                 "PERMISSIONS\n"
779                 "Needed privileges for %s: %s\n",
780                 argv[1],
781                 cmd->description,
782                 cmd->synopsis,
783                 cmd->help,
784                 handler,
785                 argv[1],
786                 perms
787         );
788         free(perms);
789         free(handler);
790         return ret;
791 }
792
793 /* hup */
794 static int com_hup(__unused int socket_fd, int argc, __unused char **argv)
795 {
796         if (argc != 1)
797                 return -E_COMMAND_SYNTAX;
798         kill(getppid(), SIGHUP);
799         return 1;
800 }
801
802 /* term */
803 static int com_term(__unused int socket_fd, int argc, __unused char **argv)
804 {
805         if (argc != 1)
806                 return -E_COMMAND_SYNTAX;
807         kill(getppid(), SIGTERM);
808         return 1;
809 }
810
811 static int com_play(__unused int socket_fd, int argc, __unused char **argv)
812 {
813         if (argc != 1)
814                 return -E_COMMAND_SYNTAX;
815         mmd_lock();
816         mmd->new_afs_status_flags |= AFS_PLAYING;
817         mmd->new_afs_status_flags &= ~AFS_NOMORE;
818         mmd_unlock();
819         return 1;
820
821 }
822
823 /* stop */
824 static int com_stop(__unused int socket_fd, int argc, __unused char **argv)
825 {
826         if (argc != 1)
827                 return -E_COMMAND_SYNTAX;
828         mmd_lock();
829         mmd->new_afs_status_flags &= ~AFS_PLAYING;
830         mmd->new_afs_status_flags &= ~AFS_REPOS;
831         mmd->new_afs_status_flags |= AFS_NEXT;
832         mmd_unlock();
833         return 1;
834 }
835
836 /* pause */
837 static int com_pause(__unused int socket_fd, int argc, __unused char **argv)
838 {
839         if (argc != 1)
840                 return -E_COMMAND_SYNTAX;
841         mmd_lock();
842         if (!afs_paused())
843                 mmd->events++;
844         mmd->new_afs_status_flags &= ~AFS_PLAYING;
845         mmd->new_afs_status_flags &= ~AFS_NEXT;
846         mmd_unlock();
847         return 1;
848 }
849
850 static int com_chs(int fd, int argc, char **argv)
851 {
852         int i, ret;
853
854         if (argc == 1) {
855                 char *selector;
856                 mmd_lock();
857                 selector = para_strdup(selectors[mmd->selector_num].name);
858                 mmd_unlock();
859                 ret = send_va_buffer(fd, "%s\n", selector);
860                 free(selector);
861                 return ret;
862         }
863         for (i = 0; selectors[i].name; i++) {
864                 if (strcmp(selectors[i].name, argv[1]))
865                         continue;
866                 mmd_lock();
867                 mmd->selector_change = i;
868                 mmd->events++;
869                 mmd_unlock();
870                 return 1;
871         }
872         return -E_BAD_SELECTOR;
873 }
874
875 /* next */
876 static int com_next(__unused int socket_fd, int argc, __unused char **argv)
877 {
878         if (argc != 1)
879                 return -E_COMMAND_SYNTAX;
880         mmd_lock();
881         mmd->events++;
882         mmd->new_afs_status_flags |= AFS_NEXT;
883         mmd_unlock();
884         return 1;
885 }
886
887 /* nomore */
888 static int com_nomore(__unused int socket_fd, int argc, __unused char **argv)
889 {
890         if (argc != 1)
891                 return -E_COMMAND_SYNTAX;
892         mmd_lock();
893         if (afs_playing() || afs_paused())
894                 mmd->new_afs_status_flags |= AFS_NOMORE;
895         mmd_unlock();
896         return 1;
897 }
898
899 /* ff */
900 static int com_ff(__unused int socket_fd, int argc, char **argv)
901 {
902         long promille;
903         int ret, backwards = 0;
904         unsigned i;
905         char c;
906
907         if (argc != 2)
908                 return -E_COMMAND_SYNTAX;
909         if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
910                 return -E_COMMAND_SYNTAX;
911         if (ret > 1 && c == '-')
912                 backwards = 1; /* jmp backwards */
913         mmd_lock();
914         ret = -E_NO_AUDIO_FILE;
915         if (!mmd->chunks_total || !mmd->seconds_total)
916                 goto out;
917         promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
918         if (backwards)
919                 promille -= 1000 * i / mmd->seconds_total;
920         else
921                 promille += 1000 * i / mmd->seconds_total;
922         if (promille < 0)
923                 promille = 0;
924         if (promille >  1000) {
925                 mmd->new_afs_status_flags |= AFS_NEXT;
926                 goto out;
927         }
928         mmd->repos_request = (mmd->chunks_total * promille) / 1000;
929         mmd->new_afs_status_flags |= AFS_REPOS;
930         mmd->new_afs_status_flags &= ~AFS_NEXT;
931         mmd->events++;
932         ret = 1;
933 out:
934         mmd_unlock();
935         return ret;
936 }
937
938 /* jmp */
939 static int com_jmp(__unused int socket_fd, int argc, char **argv)
940 {
941         long unsigned int i;
942         int ret;
943
944         if (argc != 2)
945                 return -E_COMMAND_SYNTAX;
946         if (sscanf(argv[1], "%lu", &i) <= 0)
947                 return -E_COMMAND_SYNTAX;
948         mmd_lock();
949         ret = -E_NO_AUDIO_FILE;
950         if (!mmd->chunks_total)
951                 goto out;
952         if (i > 100)
953                 i = 100;
954         PARA_INFO_LOG("jumping to %lu%%\n", i);
955         mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
956         PARA_INFO_LOG("sent: %lu,  offset before jmp: %lu\n",
957                 mmd->chunks_sent, mmd->offset);
958         mmd->new_afs_status_flags |= AFS_REPOS;
959         mmd->new_afs_status_flags &= ~AFS_NEXT;
960         ret = 1;
961         mmd->events++;
962 out:
963         mmd_unlock();
964         return ret;
965 }
966
967 /*
968  * check if perms are sufficient to exec a command having perms cmd_perms.
969  * Returns 0 if perms are sufficient, -E_PERM otherwise.
970  */
971 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
972 {
973         PARA_DEBUG_LOG("%s", "checking permissions\n");
974         return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
975 }
976
977 /*
978  * Parse first string from *cmd and lookup in table of valid commands.
979  * On error, NULL is returned.
980  */
981 static struct server_command *parse_cmd(const char *cmdstr)
982 {
983         char buf[255];
984         int n = 0;
985
986         sscanf(cmdstr, "%200s%n", buf, &n);
987         if (!n)
988                 return NULL;
989         buf[n] = '\0';
990         return get_cmd_ptr(buf, NULL);
991 }
992
993 long int para_rand(long unsigned max)
994 {
995         return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
996 }
997
998 /* Open user_list file, returns pointer to opened file on success,
999  * NULL on errors
1000  */
1001 static FILE *open_user_list(char *file)
1002 {
1003         PARA_DEBUG_LOG("opening user list %s\n", file);
1004         return fopen(file, "r");
1005 }
1006
1007 /*
1008  * lookup user in user_list file. Fills in a user struct containing
1009  * filename of the user's public key as well as the permissions of that user.
1010  * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1011  */
1012 static int get_user(struct user *user) {
1013         FILE *file_ptr;
1014         char *char_ptr;
1015         char line[MAXLINE];
1016         /* keyword, user, key, perms */
1017         char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1018         int num;
1019
1020         file_ptr = open_user_list(user_list);
1021         if (!file_ptr)
1022                 return -E_USERLIST;
1023         while (fgets(line, MAXLINE, file_ptr)) {
1024 //              PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1025 //                      "from config file\n", __func__, strlen(line));
1026                 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1027                         continue;
1028                 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1029                         PARA_DEBUG_LOG("found entry for %s\n", n);
1030                         strcpy(user->name, n);
1031                         strcpy(user->pubkey_file, k);
1032                         user->perms = 0;
1033                         char_ptr = p;
1034                         num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1035                                 tmp[0], tmp[1], tmp[2], tmp[3]);
1036                         PARA_DEBUG_LOG("found %i perm entries\n",
1037                                 num);
1038                         user->perms = 0;
1039                         while (num > 0) {
1040                                 num--;
1041                                 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1042                                 //      num, tmp[num]);
1043                                 if (!strcmp(tmp[num], "AFS_READ"))
1044                                         user->perms =
1045                                                 user->perms | AFS_READ;
1046                                 else if (!strcmp(tmp[num], "AFS_WRITE"))
1047                                         user->perms =
1048                                                 user->perms | AFS_WRITE;
1049                                 else if (!strcmp(tmp[num], "DB_READ"))
1050                                         user->perms = user->perms | DB_READ;
1051                                 else if (!strcmp(tmp[num], "DB_WRITE"))
1052                                         user->perms = user->perms | DB_WRITE;
1053                                 else /* unknown permission */
1054                                         PARA_WARNING_LOG("unknown permission:"
1055                                                 "%s\n", tmp[num]);
1056                         }
1057                         fclose(file_ptr);
1058                         return 1;
1059                 }
1060         }
1061         fclose(file_ptr);
1062         return 0;
1063 }
1064
1065 static void init_rc4_keys(void)
1066 {
1067         int i;
1068
1069         for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1070                 rc4_buf[i] = para_rand(256);
1071         PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1072                 (unsigned char) rc4_buf[0],
1073                 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1074         RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1075         RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1076 }
1077
1078 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1079 {
1080         RC4(&rc4_recv_key, len, indata, outdata);
1081 }
1082
1083 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1084 {
1085         RC4(&rc4_send_key, len, indata, outdata);
1086 }
1087
1088 int handle_connect(int fd, struct sockaddr_in *addr)
1089 {
1090         int numbytes, ret, argc, use_rc4 = 0;
1091         char buf[STRINGSIZE];
1092         unsigned char crypt_buf[MAXLINE];
1093         struct user u;
1094         struct server_command *cmd = NULL;
1095         long unsigned challenge_nr, chall_response;
1096         char **argv = NULL;
1097         char *p, *command = NULL;
1098
1099         signal(SIGCHLD, SIG_IGN);
1100         signal(SIGINT, SIG_DFL);
1101         signal(SIGTERM, SIG_DFL);
1102         signal(SIGHUP, SIG_DFL);
1103         signal(SIGUSR1, SIG_IGN);
1104
1105         in_addr = addr;
1106         challenge_nr = random();
1107         /* send Welcome message */
1108         ret = send_va_buffer(fd, "This is para_server, version " VERSION  ".\n" );
1109         if (ret < 0)
1110                 goto err_out;
1111         /* recv auth request line */
1112         ret = recv_buffer(fd, buf, sizeof(buf));
1113         if (ret < 0)
1114                 goto err_out;
1115         if (ret <= 6) {
1116                 ret = -E_AUTH;
1117                 goto err_out;
1118         }
1119         numbytes = ret;
1120         ret = -E_AUTH;
1121         if (strncmp(buf, "auth ", 5))
1122                 goto err_out;
1123
1124         if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1125                 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1126         else {
1127                 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1128                 use_rc4 = 1;
1129         }
1130 //      strcpy(u.name, buf + 5); /* ok, but ugly */
1131         PARA_DEBUG_LOG("received %s request for user %s\n",
1132                 use_rc4? "rc4" : "auth", u.name);
1133         /* lookup user in list file */
1134         if ((ret = get_user(&u)) < 0)
1135                 goto err_out;
1136         if (!ret) { /* user not found */
1137                 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1138                 ret = -E_BAD_USER;
1139                 goto err_out;
1140         }
1141         ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1142         if (ret <= 0)
1143                 goto err_out;
1144         numbytes = ret;
1145         PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1146         /* We can't use send_buffer here since buf may contain null bytes */
1147         ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1148         if (ret < 0)
1149                 goto err_out;
1150         /* recv decrypted number */
1151         numbytes = recv_buffer(fd, buf, sizeof(buf));
1152         ret = numbytes;
1153         if (ret < 0)
1154                 goto err_out;
1155         ret = -E_AUTH;
1156         if (!numbytes)
1157                 goto err_out;
1158         if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1159                         || chall_response != challenge_nr)
1160                 goto err_out;
1161         /* auth successful. Send 'Proceed' message */
1162         PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1163         sprintf(buf, "%s", PROCEED_MSG);
1164         if (use_rc4) {
1165                 init_rc4_keys();
1166                 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1167                         (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1168                 if (ret <= 0)
1169                         goto err_out;
1170                 numbytes = ret + strlen(PROCEED_MSG) + 1;
1171         } else
1172                 numbytes = strlen(buf);
1173         ret = send_bin_buffer(fd, buf, numbytes);
1174         if (ret < 0)
1175                 goto err_out;
1176         if (use_rc4) {
1177                 crypt_function_recv = rc4_recv;
1178                 crypt_function_send = rc4_send;
1179                 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1180         }
1181         /* read command */
1182         while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1183 //              PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1184                 ret = -E_COMMAND_SYNTAX;
1185                 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1186                         goto err_out;
1187                 command = para_strcat(command, buf);
1188                 if ((p = strstr(command, EOC_MSG))) {
1189                         *p = '\0';
1190                         break;
1191                 }
1192         }
1193         ret = numbytes;
1194         if (ret < 0)
1195                 goto err_out;
1196         ret = -E_BAD_CMD;
1197         /* parse command */
1198         if (!(cmd = parse_cmd(command)))
1199                 goto err_out;
1200         /* valid command, check permissions */
1201         ret = check_perms(u.perms, cmd);
1202         if (ret < 0)
1203                 goto err_out;
1204         /* valid command and sufficient perms */
1205         alarm(0);
1206         argc = split_args(command, &argv, "\n");
1207         mmd_lock();
1208         mmd->num_commands++;
1209         mmd_unlock();
1210         PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1211                 inet_ntoa(addr->sin_addr));
1212         ret = cmd->handler(fd, argc, argv);
1213         if (ret >= 0) {
1214                 ret = EXIT_SUCCESS;
1215                 goto out;
1216         }
1217 err_out:
1218         if (ret != -E_SEND && ret != -E_RECV) {
1219                 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1220                 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1221         }
1222         ret = EXIT_FAILURE;
1223 out:
1224         free(command);
1225         free(argv);
1226         mmd_lock();
1227         if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1228                 mmd->events++;
1229         mmd->active_connections--;
1230         mmd_unlock();
1231         return ret;
1232 }