Makefile.in: kill sample_conf variable
[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 <sys/time.h> /* gettimeofday */
22 #include "crypt.h"
23 #include "server.cmdline.h"
24 #include "db.h"
25 #include "server.h"
26 #include "afs.h"
27 #include "send.h"
28 #include "rc4.h"
29 #include <openssl/rc4.h>
30 #include "error.h"
31 #include "net.h"
32 #include "daemon.h"
33 #include "string.h"
34
35 void (*crypt_function_recv)(unsigned long len, const unsigned char *indata,
36         unsigned char *outdata) = NULL;
37 void (*crypt_function_send)(unsigned long len, const unsigned char *indata,
38         unsigned char *outdata) = NULL;
39 static RC4_KEY rc4_recv_key;
40 static RC4_KEY rc4_send_key;
41 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
42
43 extern const char *status_item_list[NUM_STAT_ITEMS];
44 extern struct misc_meta_data *mmd;
45 extern struct gengetopt_args_info conf;
46 extern struct audio_file_selector selectors[];
47 extern struct audio_format afl[];
48 extern struct sender senders[];
49 extern char *user_list;
50 struct sockaddr_in *in_addr;
51
52 static int com_si(int, int, char **);
53 static int com_version(int, int, char **);
54 static int com_sb(int, int, char **);
55 static int com_sc(int, int, char **);
56 static int com_stat(int, int, char **);
57 static int com_help(int, int, char **);
58 static int com_hup(int, int, char **);
59 static int com_term(int, int, char **);
60 static int com_play(int, int, char **);
61 static int com_stop(int, int, char **);
62 static int com_pause(int, int, char **);
63 static int com_next(int, int, char **);
64 static int com_nomore(int, int, char **);
65 static int com_chs(int, int, char **);
66 static int com_ff(int, int, char **);
67 static int com_jmp(int, int, char **);
68 static int com_sender(int, int, char **);
69
70
71 /* commands that are handled by the server itself */
72 static struct server_command cmd_struct[] = {
73 {
74 .name = "chs",
75 .handler = com_chs,
76 .perms = DB_READ | DB_WRITE,
77 .description = "change the current audio file selector",
78 .synopsis = "chs [new_selector]",
79 .help =
80 "Shutdown the current selector and activate new_selector. If no\n"
81 "argument was given, print the name of the current selector.\n"
82 },
83
84 {
85 .name = "ff",
86 .handler = com_ff,
87 .perms = AFS_READ | AFS_WRITE,
88 .description = "jmp amount of time forwards or backwards "
89         "in current audio file",
90 .synopsis = "ff n[-]",
91 .help =
92
93 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
94 "\tand enqueue a request to jump n seconds forwards or backwards\n"
95 "\tin the current audio file.\n"
96 "\n"
97 "EXAMPLE\n"
98 "\n"
99 "\t\tff 30-\n"
100 "\n"
101 "\tjumps 30 seconds backwards.\n"
102
103 },
104
105 {
106 .name = "help",
107 .handler = com_help,
108 .perms = 0,
109 .description = "print help text",
110 .synopsis = "help [command]",
111 .help =
112
113 "Without any arguments, help prints a list of availible commands. When\n"
114 "issued with a command name as first argument, print out a description\n"
115 "for that command.\n"
116
117 },
118
119 {
120 .name = "hup",
121 .handler = com_hup,
122 .perms = AFS_WRITE,
123 .description = "force reload of config file and log file",
124 .synopsis = "hup",
125 .help =
126
127 "After rereading the config file, a signal is sent to all children\n"
128 "which forces them to close/reopen the log file.\n"
129
130 },
131
132 {
133 .name = "jmp",
134 .handler = com_jmp,
135 .perms = AFS_READ | AFS_WRITE,
136 .description = "jmp to given position in current audio file",
137 .synopsis = "jmp [n]",
138 .help =
139
140 "\tSet the 'R' (reposition request) bit of the afs status flags\n"
141 "\tand enqueue a request to jump to n% of the current audio file,\n"
142 "\twhere 0 <= n <= 100.\n"
143
144 },
145
146 {
147 .name = "next",
148 .handler = com_next,
149 .perms = AFS_READ | AFS_WRITE,
150 .description = "skip rest of current audio file",
151 .synopsis = "next",
152 .help =
153
154 "\tSet the 'N' (next audio file) bit of the afs status flags. When\n"
155 "\tplaying, change audio file immediately. Equivalent to stop\n"
156 "\tif paused, NOP if stopped.\n"
157
158
159 },
160
161 {
162 .name = "nomore",
163 .handler = com_nomore,
164 .perms = AFS_READ | AFS_WRITE,
165 .description = "stop playing after current audio file",
166 .synopsis = "nomore",
167 .help =
168
169 "Set the 'O' (no more) bit of the afs status flags. This instructs\n"
170 "para_server to clear the 'P' (playing) bit as soon as it encounters\n"
171 "the 'N' (next audio file) bit being set.\n"
172 "\n"
173 "Use this command instead of stop if you don't like\n"
174 "sudden endings.\n"
175
176 },
177
178 {
179 .name ="pause",
180 .handler = com_pause,
181 .perms = AFS_READ | AFS_WRITE,
182 .description = "pause current audio file",
183 .synopsis = "pause",
184 .help =
185
186 "\tClear the 'P' (playing) bit of the afs status flags.\n"
187
188 },
189
190 {
191 .name = "play",
192 .handler = com_play,
193 .perms = AFS_READ | AFS_WRITE,
194 .description = "start playing or resume playing when paused",
195 .synopsis = "play",
196 .help =
197
198 "\tSet the 'P' (playing) bit of the afs status flags. This\n"
199 "\tresults in starting/continuing to stream.\n"
200
201 },
202
203 {
204 .name = "sb",
205 .handler = com_sb,
206 .perms = AFS_READ,
207 .description = "print status bar for current audio file",
208 .synopsis = "sb [n]",
209 .help =
210
211 "Without any arguments, sb continuously prints a status bar of the form\n"
212 "\n"
213 "       12:34 [56:12] (56%) filename\n"
214 "\n"
215 "indicating playing time, remaining time, percentage and the name of\n"
216 "the file beeing streamed. Use the optional number n to let stat exit\n"
217 "after having displayed the status bar n times.\n"
218
219 },
220 {
221 .name = "sc",
222 .handler = com_sc,
223 .perms = AFS_READ,
224 .description = "print name of audio file whenever it changes",
225 .synopsis = "sc [n]",
226 .help =
227
228 "\tsc prints exactly one line (the filename of the audio file\n"
229 "\tbeing played) whenever the audio file changes. Stops after\n"
230 "\tn iterations, or never if n is not specified.\n"
231
232 },
233 {
234 .name = "sender",
235 .handler = com_sender,
236 .perms = AFS_READ | AFS_WRITE,
237 .description = "control paraslash internal senders",
238 .synopsis = "sender [s cmd [arguments]]",
239 .help =
240
241 "send command cmd to sender s. cmd may be one of the following:\n"
242 "help, on, off, add, delete, allow, or deny. Note that not all senders\n"
243 "support each command. Try e.g. 'para_client sender http help' for\n"
244 "more information about the http sender. If no argument is given,\n"
245 "print out a list of all senders that are compiled in.\n"
246
247 },
248 {
249 .name = "si",
250 .handler = com_si,
251 .perms = 0,
252 .description = "print server info",
253 .synopsis = "si",
254 .help =
255 "Print server uptime and other information.\n"
256 },
257
258 {
259 .name = "stat",
260 .handler = com_stat,
261 .perms = AFS_READ,
262 .description = "print status info for current audio file",
263 .synopsis = "stat [n]",
264 .help =
265
266 "\tWithout any arguments, stat continuously prints status messages\n"
267 "\tof the audio file being streamed. Use the optional number n\n"
268 "\tto let stat exit after having displayed status n times.\n"
269
270 },
271
272 {
273 .name = "stop",
274 .handler = com_stop,
275 .perms = AFS_READ | AFS_WRITE,
276 .description = "stop playing",
277 .synopsis = "stop",
278 .help =
279
280 "\tClear the 'P' (play) bit and set the 'N' bit of the afs status\n"
281 "\tflags.\n"
282
283 },
284 {
285 .name = "term",
286 .handler = com_term,
287 .perms = AFS_READ | AFS_WRITE,
288 .description = "terminate para_server",
289 .synopsis = "term",
290 .help =
291
292 "Shuts down the server. Instead of this command, you can also send\n"
293 "SIGINT or SIGTERM. It should never be necessary to send SIGKILL.\n"
294
295 },
296 {
297 .name = "version",
298 .handler = com_version,
299 .perms = 0,
300 .description = "print server's version",
301 .synopsis = "version",
302 .help =
303 "Show version and other info\n"
304 },
305 /* this indicates the end of the list. Do not touch. */
306 {
307 .name = NULL,
308 }
309 };
310
311 static void dummy(__a_unused int s)
312 {}
313
314 static void mmd_dup(struct misc_meta_data *new_mmd)
315 {
316         mmd_lock();
317         *new_mmd = *mmd;
318         mmd_unlock();
319 }
320
321 /*
322  * compute human readable string containing
323  * afs_status for given integer value
324  */
325 static char *afs_status_tohuman(unsigned int flags)
326 {
327         if (flags & AFS_PLAYING)
328                 return para_strdup("playing");
329         else if (flags & AFS_NEXT)
330                 return para_strdup("stopped");
331         else
332                 return para_strdup("paused");
333 }
334
335 /*
336  * return human readable permission string. Never returns NULL.
337  */
338 char *cmd_perms_itohuman(unsigned int perms)
339 {
340         char *msg = para_malloc(7 * sizeof(char));
341
342         msg[0] = perms & DB_READ? 'd' : '-';
343         msg[1] = perms & DB_WRITE? 'D' : '-';
344         msg[2] = perms & AFS_READ? 'a' : '-';
345         msg[3] = perms & AFS_WRITE? 'A' : '-';
346         msg[4] = '\0';
347         return msg;
348 }
349
350 /*
351  * Never returns NULL.
352  */
353 static char *afs_get_status_flags(unsigned int flags)
354 {
355         char *msg = para_malloc(5 * sizeof(char));
356
357         msg[0] = (flags & AFS_PLAYING)? 'P' : '_';
358         msg[1] = (flags & AFS_NOMORE)? 'O' : '_';
359         msg[2] = (flags & AFS_NEXT)? 'N' : '_';
360         msg[3] = (flags & AFS_REPOS)? 'R' : '_';
361         msg[4] = '\0';
362         return msg;
363 }
364
365 /*
366  * compute status bar string. Never returns NULL
367  */
368 char *get_sb_string(struct misc_meta_data *nmmd)
369 {
370         char *base, *ret;
371         long long unsigned secs = 0, rsecs = 0, percent = 0;
372
373         base = para_basename(nmmd->filename);
374         if (!base)
375                 return para_strdup("");
376         if (!base[0])
377                 return base;
378         if (nmmd->chunks_total) {
379                 secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
380                         / nmmd->chunks_total;
381                 rsecs = (long long) nmmd->seconds_total *
382                         (nmmd->chunks_total - nmmd->chunks_sent)
383                         / nmmd->chunks_total;
384                 percent = 100 * ((nmmd->chunks_sent + 5) / 10)
385                         / ((nmmd->chunks_total + 5) / 10);
386         }
387         ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
388                 secs / 60, secs % 60,
389                 rsecs / 60, rsecs % 60,
390                 percent,
391                 base
392         );
393         free(base);
394         return ret;
395 }
396
397 static char *get_status(struct misc_meta_data *nmmd)
398 {
399         char *bar, *ret, mtime[30] = "";
400         char *status, *flags; /* afs status info */
401         char *ut = uptime_str();
402         long offset = (nmmd->offset + 500) / 1000;
403         struct timeval now;
404         struct tm mtime_tm;
405
406         if (nmmd->audio_format >= 0) {
407                 localtime_r(&nmmd->mtime, &mtime_tm);
408                 strftime(mtime, 29, "%a %b %d %Y", &mtime_tm);
409         }
410         /* report real status */
411         status = afs_status_tohuman(nmmd->afs_status_flags);
412         flags = afs_get_status_flags(nmmd->afs_status_flags);
413         bar = para_basename(nmmd->filename);
414         gettimeofday(&now, NULL);
415         ret = make_message(
416                 "%s:%lu\n"      "%s:%s\n"               "%s:%i\n"       "%s:%u\n"
417                 "%s:%s\n"       "%s:%s\n"       "%s:%s\n"       "%s:%s\n"
418                 "%s:%li\n"      "%s:%s\n"       "%s"            "%s"
419                 "%s:%s\n"       "%s:%lu.%lu\n"  "%s:%lu.%lu\n",
420                 status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
421                 status_item_list[SI_MTIME], mtime,
422                 status_item_list[SI_LENGTH], nmmd->seconds_total,
423                 status_item_list[SI_NUM_PLAYED], nmmd->num_played,
424
425                 status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
426                 status_item_list[SI_STATUS], status,
427                 status_item_list[SI_STATUS_FLAGS], flags,
428                 status_item_list[SI_SELECTOR], selectors[nmmd->selector_num].name,
429
430                 status_item_list[SI_OFFSET], offset,
431                 status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
432                 nmmd->selector_info,
433                 nmmd->audio_file_info,
434
435                 status_item_list[SI_UPTIME], ut,
436                 status_item_list[SI_STREAM_START],
437                         (long unsigned)nmmd->stream_start.tv_sec,
438                         (long unsigned)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, __a_unused char **argv)
558 {
559         int i, ret;
560         char *ut;
561         char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
562
563         if (argc != 1)
564                 return -E_COMMAND_SYNTAX;
565         mmd_lock();
566         for (i = 0; selectors[i].name; i++) {
567                 selector_string = para_strcat(selector_string, selectors[i].name);
568                 selector_string = para_strcat(selector_string, " ");
569         }
570         for (i = 0; senders[i].name; i++) {
571                 char *info = senders[i].info();
572                 sender_info = para_strcat(sender_info, info);
573                 free(info);
574                 sender_list = para_strcat(sender_list, senders[i].name);
575                 sender_list = para_strcat(sender_list, " ");
576         }
577         ut = uptime_str();
578         ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
579                 "pid: %d\n"
580                 "connections (active/accepted/total): %u/%u/%u\n"
581                 "current loglevel: %i\n"
582                 "supported audio file selectors: %s\n"
583                 "supported audio formats: %s\n"
584                 "supported senders: %s\n"
585                 "%s",
586                 ut, mmd->num_played,
587                 getppid(),
588                 mmd->active_connections,
589                 mmd->num_commands,
590                 mmd->num_connects,
591                 conf.loglevel_arg,
592                 selector_string,
593                 SUPPORTED_AUDIO_FORMATS,
594                 sender_list,
595                 sender_info
596         );
597         mmd_unlock();
598         free(ut);
599         free(selector_string);
600         free(sender_list);
601         free(sender_info);
602         return ret;
603 }
604
605 /* version */
606 static int com_version(int socket_fd, int argc, __a_unused char **argv)
607 {
608         if (argc != 1)
609                 return -E_COMMAND_SYNTAX;
610         return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
611                         COPYRIGHT "\n"
612                         "built: " BUILD_DATE "\n"
613                         SYSTEM ", " CC_VERSION "\n"
614                 );
615 }
616
617 /* sc */
618 static int com_sc(int socket_fd, int argc, char **argv)
619 {
620         char *name = NULL;
621         int ret, old = 0, count = -1; /* print af change forever */
622
623         if (argc > 1)
624                 count = atoi(argv[1]);
625 repeat:
626         mmd_lock();
627         if (old != mmd->num_played) {
628                 old = mmd->num_played;
629                 name = para_strdup(mmd->filename);
630         }
631         mmd_unlock();
632         if (name) {
633                 ret = send_va_buffer(socket_fd, "%s\n", name);
634                 free(name);
635                 name = NULL;
636                 if (ret < 0)
637                         return ret;
638                 if (argc > 1 && !--count)
639                         return 1;
640         }
641         usleep(500000);
642         goto repeat;
643 }
644
645 /* sb */
646 static int com_sb(int socket_fd, int argc, char **argv)
647 {
648         char *sb;
649         int ret, nr = -1;       /* status bar will be printed that many
650                                  * times. Negative value means: print
651                                  * forever
652                                  */
653         if (argc > 1)
654                 nr = atoi(argv[1]);
655         while (nr) {
656                 mmd_lock();
657                 sb = get_sb_string(mmd);
658                 mmd_unlock();
659                 ret = send_va_buffer(socket_fd, "%s\n", sb);
660                 free(sb);
661                 if (ret < 0)
662                         return ret;
663                 if (nr == 1)
664                         return 1;
665                 usleep(500000);
666                 if (nr > 0)
667                         nr--;
668         }
669         return 1;
670 }
671
672 /* stat */
673 static int com_stat(int socket_fd, int argc, char **argv)
674 {
675         int ret, num = 0;/* status will be printed that many
676                           * times. num <= 0 means: print forever
677                           */
678         struct misc_meta_data tmp, *nmmd = &tmp;
679         char *s;
680
681         signal(SIGUSR1, dummy);
682
683         if (argc > 1)
684                 num = atoi(argv[1]);
685         for (;;) {
686
687                 mmd_dup(nmmd);
688                 s = get_status(nmmd);
689                 ret = send_buffer(socket_fd, s);
690                 free(s);
691                 if (ret < 0)
692                         goto out;
693                 ret = 1;
694                 if (num == 1)
695                         goto out;
696                 usleep(500000 * 100);
697         }
698 out:
699         return ret;
700 }
701
702 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
703 {
704         int ret, i;
705
706         for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
707                 char *perms = cmd_perms_itohuman(cmd->perms);
708                 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
709                         handler,
710                         perms,
711                         cmd->description);
712                 free(perms);
713                 if (ret < 0)
714                         return ret;
715         }
716         return 1;
717 }
718
719 /* always returns string that must be freed by the caller in handler */
720 static struct server_command *get_cmd_ptr(char *name, char **handler)
721 {
722         struct server_command *cmd = cmd_struct;
723
724         for (cmd = cmd_struct; cmd->name; cmd++)
725                 if (!strcmp(cmd->name, name)) {
726                         if (handler)
727                                 *handler = para_strdup("para_server"); /* server commands */
728                         return cmd;
729                 }
730         /* not found, look for commands supported by the current selector */
731         mmd_lock();
732         if (handler)
733                 *handler = make_message("the %s selector",
734                         selectors[mmd->selector_num].name);
735         cmd = selectors[mmd->selector_num].cmd_list;
736         mmd_unlock();
737         for (; cmd->name; cmd++)
738                 if (!strcmp(cmd->name, name))
739                         return cmd;
740         return NULL;
741 }
742
743 /* help */
744 static int com_help(int fd, int argc, char **argv)
745 {
746         struct server_command *cmd;
747         char *perms, *handler;
748         int ret;
749
750         if (argc < 2) {
751                 /* no argument given, print list of commands */
752                 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
753                         return ret;
754                 mmd_lock();
755                 handler = para_strdup(selectors[mmd->selector_num].name);
756                 cmd = selectors[mmd->selector_num].cmd_list;
757                 mmd_unlock();
758                 ret = send_description(fd, cmd, handler, 0);
759                 free(handler);
760                 return ret;
761         }
762         /* argument given for help */
763         cmd = get_cmd_ptr(argv[1], &handler);
764         if (!cmd) {
765                 free(handler);
766                 return -E_BAD_CMD;
767         }
768         perms = cmd_perms_itohuman(cmd->perms);
769         ret = send_va_buffer(fd,
770                 "NAME\n\t%s - %s\n"
771                 "SYNOPSIS\n\t para_client %s\n"
772                 "DESCRIPTION\n%s\n"
773                 "HANDLER\n"
774                 "This command is handled by %s.\n\n"
775                 "PERMISSIONS\n"
776                 "Needed privileges for %s: %s\n",
777                 argv[1],
778                 cmd->description,
779                 cmd->synopsis,
780                 cmd->help,
781                 handler,
782                 argv[1],
783                 perms
784         );
785         free(perms);
786         free(handler);
787         return ret;
788 }
789
790 /* hup */
791 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
792 {
793         if (argc != 1)
794                 return -E_COMMAND_SYNTAX;
795         kill(getppid(), SIGHUP);
796         return 1;
797 }
798
799 /* term */
800 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
801 {
802         if (argc != 1)
803                 return -E_COMMAND_SYNTAX;
804         kill(getppid(), SIGTERM);
805         return 1;
806 }
807
808 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
809 {
810         if (argc != 1)
811                 return -E_COMMAND_SYNTAX;
812         mmd_lock();
813         mmd->new_afs_status_flags |= AFS_PLAYING;
814         mmd->new_afs_status_flags &= ~AFS_NOMORE;
815         mmd_unlock();
816         return 1;
817
818 }
819
820 /* stop */
821 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
822 {
823         if (argc != 1)
824                 return -E_COMMAND_SYNTAX;
825         mmd_lock();
826         mmd->new_afs_status_flags &= ~AFS_PLAYING;
827         mmd->new_afs_status_flags &= ~AFS_REPOS;
828         mmd->new_afs_status_flags |= AFS_NEXT;
829         mmd_unlock();
830         return 1;
831 }
832
833 /* pause */
834 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
835 {
836         if (argc != 1)
837                 return -E_COMMAND_SYNTAX;
838         mmd_lock();
839         if (!afs_paused())
840                 mmd->events++;
841         mmd->new_afs_status_flags &= ~AFS_PLAYING;
842         mmd->new_afs_status_flags &= ~AFS_NEXT;
843         mmd_unlock();
844         return 1;
845 }
846
847 static int com_chs(int fd, int argc, char **argv)
848 {
849         int i, ret;
850
851         if (argc == 1) {
852                 char *selector;
853                 mmd_lock();
854                 selector = para_strdup(selectors[mmd->selector_num].name);
855                 mmd_unlock();
856                 ret = send_va_buffer(fd, "%s\n", selector);
857                 free(selector);
858                 return ret;
859         }
860         for (i = 0; selectors[i].name; i++) {
861                 if (strcmp(selectors[i].name, argv[1]))
862                         continue;
863                 mmd_lock();
864                 mmd->selector_change = i;
865                 mmd->events++;
866                 mmd_unlock();
867                 return 1;
868         }
869         return -E_BAD_SELECTOR;
870 }
871
872 /* next */
873 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
874 {
875         if (argc != 1)
876                 return -E_COMMAND_SYNTAX;
877         mmd_lock();
878         mmd->events++;
879         mmd->new_afs_status_flags |= AFS_NEXT;
880         mmd_unlock();
881         return 1;
882 }
883
884 /* nomore */
885 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
886 {
887         if (argc != 1)
888                 return -E_COMMAND_SYNTAX;
889         mmd_lock();
890         if (afs_playing() || afs_paused())
891                 mmd->new_afs_status_flags |= AFS_NOMORE;
892         mmd_unlock();
893         return 1;
894 }
895
896 /* ff */
897 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
898 {
899         long promille;
900         int ret, backwards = 0;
901         unsigned i;
902         char c;
903
904         if (argc != 2)
905                 return -E_COMMAND_SYNTAX;
906         if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
907                 return -E_COMMAND_SYNTAX;
908         if (ret > 1 && c == '-')
909                 backwards = 1; /* jmp backwards */
910         mmd_lock();
911         ret = -E_NO_AUDIO_FILE;
912         if (!mmd->chunks_total || !mmd->seconds_total)
913                 goto out;
914         promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
915         if (backwards)
916                 promille -= 1000 * i / mmd->seconds_total;
917         else
918                 promille += 1000 * i / mmd->seconds_total;
919         if (promille < 0)
920                 promille = 0;
921         if (promille >  1000) {
922                 mmd->new_afs_status_flags |= AFS_NEXT;
923                 goto out;
924         }
925         mmd->repos_request = (mmd->chunks_total * promille) / 1000;
926         mmd->new_afs_status_flags |= AFS_REPOS;
927         mmd->new_afs_status_flags &= ~AFS_NEXT;
928         mmd->events++;
929         ret = 1;
930 out:
931         mmd_unlock();
932         return ret;
933 }
934
935 /* jmp */
936 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
937 {
938         long unsigned int i;
939         int ret;
940
941         if (argc != 2)
942                 return -E_COMMAND_SYNTAX;
943         if (sscanf(argv[1], "%lu", &i) <= 0)
944                 return -E_COMMAND_SYNTAX;
945         mmd_lock();
946         ret = -E_NO_AUDIO_FILE;
947         if (!mmd->chunks_total)
948                 goto out;
949         if (i > 100)
950                 i = 100;
951         PARA_INFO_LOG("jumping to %lu%%\n", i);
952         mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
953         PARA_INFO_LOG("sent: %lu,  offset before jmp: %lu\n",
954                 mmd->chunks_sent, mmd->offset);
955         mmd->new_afs_status_flags |= AFS_REPOS;
956         mmd->new_afs_status_flags &= ~AFS_NEXT;
957         ret = 1;
958         mmd->events++;
959 out:
960         mmd_unlock();
961         return ret;
962 }
963
964 /*
965  * check if perms are sufficient to exec a command having perms cmd_perms.
966  * Returns 0 if perms are sufficient, -E_PERM otherwise.
967  */
968 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
969 {
970         PARA_DEBUG_LOG("%s", "checking permissions\n");
971         return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
972 }
973
974 /*
975  * Parse first string from *cmd and lookup in table of valid commands.
976  * On error, NULL is returned.
977  */
978 static struct server_command *parse_cmd(const char *cmdstr)
979 {
980         char buf[255];
981         int n = 0;
982
983         sscanf(cmdstr, "%200s%n", buf, &n);
984         if (!n)
985                 return NULL;
986         buf[n] = '\0';
987         return get_cmd_ptr(buf, NULL);
988 }
989
990 long int para_rand(long unsigned max)
991 {
992         return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
993 }
994
995 /* Open user_list file, returns pointer to opened file on success,
996  * NULL on errors
997  */
998 static FILE *open_user_list(char *file)
999 {
1000         PARA_DEBUG_LOG("opening user list %s\n", file);
1001         return fopen(file, "r");
1002 }
1003
1004 /*
1005  * lookup user in user_list file. Fills in a user struct containing
1006  * filename of the user's public key as well as the permissions of that user.
1007  * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1008  */
1009 static int get_user(struct user *user) {
1010         FILE *file_ptr;
1011         char *char_ptr;
1012         char line[MAXLINE];
1013         /* keyword, user, key, perms */
1014         char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1015         int num;
1016
1017         file_ptr = open_user_list(user_list);
1018         if (!file_ptr)
1019                 return -E_USERLIST;
1020         while (fgets(line, MAXLINE, file_ptr)) {
1021 //              PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1022 //                      "from config file\n", __func__, strlen(line));
1023                 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1024                         continue;
1025                 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1026                         PARA_DEBUG_LOG("found entry for %s\n", n);
1027                         strcpy(user->name, n);
1028                         strcpy(user->pubkey_file, k);
1029                         user->perms = 0;
1030                         char_ptr = p;
1031                         num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1032                                 tmp[0], tmp[1], tmp[2], tmp[3]);
1033                         PARA_DEBUG_LOG("found %i perm entries\n",
1034                                 num);
1035                         user->perms = 0;
1036                         while (num > 0) {
1037                                 num--;
1038                                 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1039                                 //      num, tmp[num]);
1040                                 if (!strcmp(tmp[num], "AFS_READ"))
1041                                         user->perms =
1042                                                 user->perms | AFS_READ;
1043                                 else if (!strcmp(tmp[num], "AFS_WRITE"))
1044                                         user->perms =
1045                                                 user->perms | AFS_WRITE;
1046                                 else if (!strcmp(tmp[num], "DB_READ"))
1047                                         user->perms = user->perms | DB_READ;
1048                                 else if (!strcmp(tmp[num], "DB_WRITE"))
1049                                         user->perms = user->perms | DB_WRITE;
1050                                 else /* unknown permission */
1051                                         PARA_WARNING_LOG("unknown permission:"
1052                                                 "%s\n", tmp[num]);
1053                         }
1054                         fclose(file_ptr);
1055                         return 1;
1056                 }
1057         }
1058         fclose(file_ptr);
1059         return 0;
1060 }
1061
1062 static void init_rc4_keys(void)
1063 {
1064         int i;
1065
1066         for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1067                 rc4_buf[i] = para_rand(256);
1068         PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1069                 (unsigned char) rc4_buf[0],
1070                 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1071         RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1072         RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1073 }
1074
1075 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1076 {
1077         RC4(&rc4_recv_key, len, indata, outdata);
1078 }
1079
1080 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1081 {
1082         RC4(&rc4_send_key, len, indata, outdata);
1083 }
1084
1085 int handle_connect(int fd, struct sockaddr_in *addr)
1086 {
1087         int numbytes, ret, argc, use_rc4 = 0;
1088         char buf[STRINGSIZE];
1089         unsigned char crypt_buf[MAXLINE];
1090         struct user u;
1091         struct server_command *cmd = NULL;
1092         long unsigned challenge_nr, chall_response;
1093         char **argv = NULL;
1094         char *p, *command = NULL;
1095
1096         signal(SIGCHLD, SIG_IGN);
1097         signal(SIGINT, SIG_DFL);
1098         signal(SIGTERM, SIG_DFL);
1099         signal(SIGHUP, SIG_DFL);
1100         signal(SIGUSR1, SIG_IGN);
1101
1102         in_addr = addr;
1103         challenge_nr = random();
1104         /* send Welcome message */
1105         ret = send_va_buffer(fd, "This is para_server, version " VERSION  ".\n" );
1106         if (ret < 0)
1107                 goto err_out;
1108         /* recv auth request line */
1109         ret = recv_buffer(fd, buf, sizeof(buf));
1110         if (ret < 0)
1111                 goto err_out;
1112         if (ret <= 6) {
1113                 ret = -E_AUTH;
1114                 goto err_out;
1115         }
1116         numbytes = ret;
1117         ret = -E_AUTH;
1118         if (strncmp(buf, "auth ", 5))
1119                 goto err_out;
1120
1121         if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1122                 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1123         else {
1124                 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1125                 use_rc4 = 1;
1126         }
1127 //      strcpy(u.name, buf + 5); /* ok, but ugly */
1128         PARA_DEBUG_LOG("received %s request for user %s\n",
1129                 use_rc4? "rc4" : "auth", u.name);
1130         /* lookup user in list file */
1131         if ((ret = get_user(&u)) < 0)
1132                 goto err_out;
1133         if (!ret) { /* user not found */
1134                 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1135                 ret = -E_BAD_USER;
1136                 goto err_out;
1137         }
1138         ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1139         if (ret <= 0)
1140                 goto err_out;
1141         numbytes = ret;
1142         PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1143         /* We can't use send_buffer here since buf may contain null bytes */
1144         ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1145         if (ret < 0)
1146                 goto err_out;
1147         /* recv decrypted number */
1148         numbytes = recv_buffer(fd, buf, sizeof(buf));
1149         ret = numbytes;
1150         if (ret < 0)
1151                 goto err_out;
1152         ret = -E_AUTH;
1153         if (!numbytes)
1154                 goto err_out;
1155         if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1156                         || chall_response != challenge_nr)
1157                 goto err_out;
1158         /* auth successful. Send 'Proceed' message */
1159         PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1160         sprintf(buf, "%s", PROCEED_MSG);
1161         if (use_rc4) {
1162                 init_rc4_keys();
1163                 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1164                         (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1165                 if (ret <= 0)
1166                         goto err_out;
1167                 numbytes = ret + strlen(PROCEED_MSG) + 1;
1168         } else
1169                 numbytes = strlen(buf);
1170         ret = send_bin_buffer(fd, buf, numbytes);
1171         if (ret < 0)
1172                 goto err_out;
1173         if (use_rc4) {
1174                 crypt_function_recv = rc4_recv;
1175                 crypt_function_send = rc4_send;
1176                 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1177         }
1178         /* read command */
1179         while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1180 //              PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1181                 ret = -E_COMMAND_SYNTAX;
1182                 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1183                         goto err_out;
1184                 command = para_strcat(command, buf);
1185                 if ((p = strstr(command, EOC_MSG))) {
1186                         *p = '\0';
1187                         break;
1188                 }
1189         }
1190         ret = numbytes;
1191         if (ret < 0)
1192                 goto err_out;
1193         ret = -E_BAD_CMD;
1194         /* parse command */
1195         if (!(cmd = parse_cmd(command)))
1196                 goto err_out;
1197         /* valid command, check permissions */
1198         ret = check_perms(u.perms, cmd);
1199         if (ret < 0)
1200                 goto err_out;
1201         /* valid command and sufficient perms */
1202         alarm(0);
1203         argc = split_args(command, &argv, "\n");
1204         mmd_lock();
1205         mmd->num_commands++;
1206         mmd_unlock();
1207         PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1208                 inet_ntoa(addr->sin_addr));
1209         ret = cmd->handler(fd, argc, argv);
1210         if (ret >= 0) {
1211                 ret = EXIT_SUCCESS;
1212                 goto out;
1213         }
1214 err_out:
1215         if (ret != -E_SEND && ret != -E_RECV) {
1216                 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1217                 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1218         }
1219         ret = EXIT_FAILURE;
1220 out:
1221         free(command);
1222         free(argv);
1223         mmd_lock();
1224         if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1225                 mmd->events++;
1226         mmd->active_connections--;
1227         mmd_unlock();
1228         return ret;
1229 }