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