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