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