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