get rid of init_shed()
[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 static RC4_KEY rc4_recv_key;
36 static RC4_KEY rc4_send_key;
37 static unsigned char rc4_buf[2 * RC4_KEY_LEN];
38
39 extern const char *status_item_list[NUM_STAT_ITEMS];
40 extern struct misc_meta_data *mmd;
41 extern struct gengetopt_args_info conf;
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-" VERSION ", \"" CODENAME "\"\n"
608                         COPYRIGHT "\n"
609                         "built: " BUILD_DATE "\n"
610                         SYSTEM ", " CC_VERSION "\n"
611                 );
612 }
613
614 /* sc */
615 static int com_sc(int socket_fd, int argc, char **argv)
616 {
617         char *name = NULL;
618         int ret, old = 0, count = -1; /* print af change forever */
619
620         if (argc > 1)
621                 count = atoi(argv[1]);
622 repeat:
623         mmd_lock();
624         if (old != mmd->num_played) {
625                 old = mmd->num_played;
626                 name = para_strdup(mmd->filename);
627         }
628         mmd_unlock();
629         if (name) {
630                 ret = send_va_buffer(socket_fd, "%s\n", name);
631                 free(name);
632                 name = NULL;
633                 if (ret < 0)
634                         return ret;
635                 if (argc > 1 && !--count)
636                         return 1;
637         }
638         usleep(500000);
639         goto repeat;
640 }
641
642 /* sb */
643 static int com_sb(int socket_fd, int argc, char **argv)
644 {
645         char *sb;
646         int ret, nr = -1;       /* status bar will be printed that many
647                                  * times. Negative value means: print
648                                  * forever
649                                  */
650         if (argc > 1)
651                 nr = atoi(argv[1]);
652         while (nr) {
653                 mmd_lock();
654                 sb = get_sb_string(mmd);
655                 mmd_unlock();
656                 ret = send_va_buffer(socket_fd, "%s\n", sb);
657                 free(sb);
658                 if (ret < 0)
659                         return ret;
660                 if (nr == 1)
661                         return 1;
662                 usleep(500000);
663                 if (nr > 0)
664                         nr--;
665         }
666         return 1;
667 }
668
669 /* stat */
670 static int com_stat(int socket_fd, int argc, char **argv)
671 {
672         int ret, num = 0;/* status will be printed that many
673                           * times. num <= 0 means: print forever
674                           */
675         struct misc_meta_data tmp, *nmmd = &tmp;
676         char *s;
677
678         signal(SIGUSR1, dummy);
679
680         if (argc > 1)
681                 num = atoi(argv[1]);
682         for (;;) {
683
684                 mmd_dup(nmmd);
685                 s = get_status(nmmd);
686                 ret = send_buffer(socket_fd, s);
687                 free(s);
688                 if (ret < 0)
689                         goto out;
690                 ret = 1;
691                 if (num == 1)
692                         goto out;
693                 usleep(500000 * 100);
694         }
695 out:
696         return ret;
697 }
698
699 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
700 {
701         int ret, i;
702
703         for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
704                 char *perms = cmd_perms_itohuman(cmd->perms);
705                 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
706                         handler,
707                         perms,
708                         cmd->description);
709                 free(perms);
710                 if (ret < 0)
711                         return ret;
712         }
713         return 1;
714 }
715
716 /* always returns string that must be freed by the caller in handler */
717 static struct server_command *get_cmd_ptr(char *name, char **handler)
718 {
719         struct server_command *cmd = cmd_struct;
720
721         for (cmd = cmd_struct; cmd->name; cmd++)
722                 if (!strcmp(cmd->name, name)) {
723                         if (handler)
724                                 *handler = para_strdup("para_server"); /* server commands */
725                         return cmd;
726                 }
727         /* not found, look for commands supported by the current selector */
728         mmd_lock();
729         if (handler)
730                 *handler = make_message("the %s selector",
731                         selectors[mmd->selector_num].name);
732         cmd = selectors[mmd->selector_num].cmd_list;
733         mmd_unlock();
734         for (; cmd->name; cmd++)
735                 if (!strcmp(cmd->name, name))
736                         return cmd;
737         return NULL;
738 }
739
740 /* help */
741 static int com_help(int fd, int argc, char **argv)
742 {
743         struct server_command *cmd;
744         char *perms, *handler;
745         int ret;
746
747         if (argc < 2) {
748                 /* no argument given, print list of commands */
749                 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
750                         return ret;
751                 mmd_lock();
752                 handler = para_strdup(selectors[mmd->selector_num].name);
753                 cmd = selectors[mmd->selector_num].cmd_list;
754                 mmd_unlock();
755                 ret = send_description(fd, cmd, handler, 0);
756                 free(handler);
757                 return ret;
758         }
759         /* argument given for help */
760         cmd = get_cmd_ptr(argv[1], &handler);
761         if (!cmd) {
762                 free(handler);
763                 return -E_BAD_CMD;
764         }
765         perms = cmd_perms_itohuman(cmd->perms);
766         ret = send_va_buffer(fd,
767                 "NAME\n\t%s - %s\n"
768                 "SYNOPSIS\n\t para_client %s\n"
769                 "DESCRIPTION\n%s\n"
770                 "HANDLER\n"
771                 "This command is handled by %s.\n\n"
772                 "PERMISSIONS\n"
773                 "Needed privileges for %s: %s\n",
774                 argv[1],
775                 cmd->description,
776                 cmd->synopsis,
777                 cmd->help,
778                 handler,
779                 argv[1],
780                 perms
781         );
782         free(perms);
783         free(handler);
784         return ret;
785 }
786
787 /* hup */
788 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
789 {
790         if (argc != 1)
791                 return -E_COMMAND_SYNTAX;
792         kill(getppid(), SIGHUP);
793         return 1;
794 }
795
796 /* term */
797 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
798 {
799         if (argc != 1)
800                 return -E_COMMAND_SYNTAX;
801         kill(getppid(), SIGTERM);
802         return 1;
803 }
804
805 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
806 {
807         if (argc != 1)
808                 return -E_COMMAND_SYNTAX;
809         mmd_lock();
810         mmd->new_afs_status_flags |= AFS_PLAYING;
811         mmd->new_afs_status_flags &= ~AFS_NOMORE;
812         mmd_unlock();
813         return 1;
814
815 }
816
817 /* stop */
818 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
819 {
820         if (argc != 1)
821                 return -E_COMMAND_SYNTAX;
822         mmd_lock();
823         mmd->new_afs_status_flags &= ~AFS_PLAYING;
824         mmd->new_afs_status_flags &= ~AFS_REPOS;
825         mmd->new_afs_status_flags |= AFS_NEXT;
826         mmd_unlock();
827         return 1;
828 }
829
830 /* pause */
831 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
832 {
833         if (argc != 1)
834                 return -E_COMMAND_SYNTAX;
835         mmd_lock();
836         if (!afs_paused())
837                 mmd->events++;
838         mmd->new_afs_status_flags &= ~AFS_PLAYING;
839         mmd->new_afs_status_flags &= ~AFS_NEXT;
840         mmd_unlock();
841         return 1;
842 }
843
844 static int com_chs(int fd, int argc, char **argv)
845 {
846         int i, ret;
847
848         if (argc == 1) {
849                 char *selector;
850                 mmd_lock();
851                 selector = para_strdup(selectors[mmd->selector_num].name);
852                 mmd_unlock();
853                 ret = send_va_buffer(fd, "%s\n", selector);
854                 free(selector);
855                 return ret;
856         }
857         for (i = 0; selectors[i].name; i++) {
858                 if (strcmp(selectors[i].name, argv[1]))
859                         continue;
860                 mmd_lock();
861                 mmd->selector_change = i;
862                 mmd->events++;
863                 mmd_unlock();
864                 return 1;
865         }
866         return -E_BAD_SELECTOR;
867 }
868
869 /* next */
870 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
871 {
872         if (argc != 1)
873                 return -E_COMMAND_SYNTAX;
874         mmd_lock();
875         mmd->events++;
876         mmd->new_afs_status_flags |= AFS_NEXT;
877         mmd_unlock();
878         return 1;
879 }
880
881 /* nomore */
882 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
883 {
884         if (argc != 1)
885                 return -E_COMMAND_SYNTAX;
886         mmd_lock();
887         if (afs_playing() || afs_paused())
888                 mmd->new_afs_status_flags |= AFS_NOMORE;
889         mmd_unlock();
890         return 1;
891 }
892
893 /* ff */
894 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
895 {
896         long promille;
897         int ret, backwards = 0;
898         unsigned i;
899         char c;
900
901         if (argc != 2)
902                 return -E_COMMAND_SYNTAX;
903         if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
904                 return -E_COMMAND_SYNTAX;
905         if (ret > 1 && c == '-')
906                 backwards = 1; /* jmp backwards */
907         mmd_lock();
908         ret = -E_NO_AUDIO_FILE;
909         if (!mmd->chunks_total || !mmd->seconds_total)
910                 goto out;
911         promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
912         if (backwards)
913                 promille -= 1000 * i / mmd->seconds_total;
914         else
915                 promille += 1000 * i / mmd->seconds_total;
916         if (promille < 0)
917                 promille = 0;
918         if (promille >  1000) {
919                 mmd->new_afs_status_flags |= AFS_NEXT;
920                 goto out;
921         }
922         mmd->repos_request = (mmd->chunks_total * promille) / 1000;
923         mmd->new_afs_status_flags |= AFS_REPOS;
924         mmd->new_afs_status_flags &= ~AFS_NEXT;
925         mmd->events++;
926         ret = 1;
927 out:
928         mmd_unlock();
929         return ret;
930 }
931
932 /* jmp */
933 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
934 {
935         long unsigned int i;
936         int ret;
937
938         if (argc != 2)
939                 return -E_COMMAND_SYNTAX;
940         if (sscanf(argv[1], "%lu", &i) <= 0)
941                 return -E_COMMAND_SYNTAX;
942         mmd_lock();
943         ret = -E_NO_AUDIO_FILE;
944         if (!mmd->chunks_total)
945                 goto out;
946         if (i > 100)
947                 i = 100;
948         PARA_INFO_LOG("jumping to %lu%%\n", i);
949         mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
950         PARA_INFO_LOG("sent: %lu,  offset before jmp: %lu\n",
951                 mmd->chunks_sent, mmd->offset);
952         mmd->new_afs_status_flags |= AFS_REPOS;
953         mmd->new_afs_status_flags &= ~AFS_NEXT;
954         ret = 1;
955         mmd->events++;
956 out:
957         mmd_unlock();
958         return ret;
959 }
960
961 /*
962  * check if perms are sufficient to exec a command having perms cmd_perms.
963  * Returns 0 if perms are sufficient, -E_PERM otherwise.
964  */
965 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
966 {
967         PARA_DEBUG_LOG("%s", "checking permissions\n");
968         return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
969 }
970
971 /*
972  * Parse first string from *cmd and lookup in table of valid commands.
973  * On error, NULL is returned.
974  */
975 static struct server_command *parse_cmd(const char *cmdstr)
976 {
977         char buf[255];
978         int n = 0;
979
980         sscanf(cmdstr, "%200s%n", buf, &n);
981         if (!n)
982                 return NULL;
983         buf[n] = '\0';
984         return get_cmd_ptr(buf, NULL);
985 }
986
987 long int para_rand(long unsigned max)
988 {
989         return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
990 }
991
992 /* Open user_list file, returns pointer to opened file on success,
993  * NULL on errors
994  */
995 static FILE *open_user_list(char *file)
996 {
997         PARA_DEBUG_LOG("opening user list %s\n", file);
998         return fopen(file, "r");
999 }
1000
1001 /*
1002  * lookup user in user_list file. Fills in a user struct containing
1003  * filename of the user's public key as well as the permissions of that user.
1004  * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1005  */
1006 static int get_user(struct user *user) {
1007         FILE *file_ptr;
1008         char *char_ptr;
1009         char line[MAXLINE];
1010         /* keyword, user, key, perms */
1011         char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1012         int num;
1013
1014         file_ptr = open_user_list(user_list);
1015         if (!file_ptr)
1016                 return -E_USERLIST;
1017         while (fgets(line, MAXLINE, file_ptr)) {
1018 //              PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1019 //                      "from config file\n", __func__, strlen(line));
1020                 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1021                         continue;
1022                 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1023                         PARA_DEBUG_LOG("found entry for %s\n", n);
1024                         strcpy(user->name, n);
1025                         strcpy(user->pubkey_file, k);
1026                         user->perms = 0;
1027                         char_ptr = p;
1028                         num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1029                                 tmp[0], tmp[1], tmp[2], tmp[3]);
1030                         PARA_DEBUG_LOG("found %i perm entries\n",
1031                                 num);
1032                         user->perms = 0;
1033                         while (num > 0) {
1034                                 num--;
1035                                 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1036                                 //      num, tmp[num]);
1037                                 if (!strcmp(tmp[num], "AFS_READ"))
1038                                         user->perms =
1039                                                 user->perms | AFS_READ;
1040                                 else if (!strcmp(tmp[num], "AFS_WRITE"))
1041                                         user->perms =
1042                                                 user->perms | AFS_WRITE;
1043                                 else if (!strcmp(tmp[num], "DB_READ"))
1044                                         user->perms = user->perms | DB_READ;
1045                                 else if (!strcmp(tmp[num], "DB_WRITE"))
1046                                         user->perms = user->perms | DB_WRITE;
1047                                 else /* unknown permission */
1048                                         PARA_WARNING_LOG("unknown permission:"
1049                                                 "%s\n", tmp[num]);
1050                         }
1051                         fclose(file_ptr);
1052                         return 1;
1053                 }
1054         }
1055         fclose(file_ptr);
1056         return 0;
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, unsigned char *outdata)
1073 {
1074         RC4(&rc4_recv_key, len, indata, outdata);
1075 }
1076
1077 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1078 {
1079         RC4(&rc4_send_key, len, indata, outdata);
1080 }
1081
1082 int handle_connect(int fd, struct sockaddr_in *addr)
1083 {
1084         int numbytes, ret, argc, use_rc4 = 0;
1085         char buf[STRINGSIZE];
1086         unsigned char crypt_buf[MAXLINE];
1087         struct user u;
1088         struct server_command *cmd = NULL;
1089         long unsigned challenge_nr, chall_response;
1090         char **argv = NULL;
1091         char *p, *command = NULL;
1092
1093         signal(SIGCHLD, SIG_IGN);
1094         signal(SIGINT, SIG_DFL);
1095         signal(SIGTERM, SIG_DFL);
1096         signal(SIGHUP, SIG_DFL);
1097         signal(SIGUSR1, SIG_IGN);
1098
1099         in_addr = addr;
1100         challenge_nr = random();
1101         /* send Welcome message */
1102         ret = send_va_buffer(fd, "This is para_server, version " VERSION  ".\n" );
1103         if (ret < 0)
1104                 goto err_out;
1105         /* recv auth request line */
1106         ret = recv_buffer(fd, buf, sizeof(buf));
1107         if (ret < 0)
1108                 goto err_out;
1109         if (ret <= 6) {
1110                 ret = -E_AUTH;
1111                 goto err_out;
1112         }
1113         numbytes = ret;
1114         ret = -E_AUTH;
1115         if (strncmp(buf, "auth ", 5))
1116                 goto err_out;
1117
1118         if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1119                 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1120         else {
1121                 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1122                 use_rc4 = 1;
1123         }
1124 //      strcpy(u.name, buf + 5); /* ok, but ugly */
1125         PARA_DEBUG_LOG("received %s request for user %s\n",
1126                 use_rc4? "rc4" : "auth", u.name);
1127         /* lookup user in list file */
1128         if ((ret = get_user(&u)) < 0)
1129                 goto err_out;
1130         if (!ret) { /* user not found */
1131                 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1132                 ret = -E_BAD_USER;
1133                 goto err_out;
1134         }
1135         ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1136         if (ret <= 0)
1137                 goto err_out;
1138         numbytes = ret;
1139         PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1140         /* We can't use send_buffer here since buf may contain null bytes */
1141         ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1142         if (ret < 0)
1143                 goto err_out;
1144         /* recv decrypted number */
1145         numbytes = recv_buffer(fd, buf, sizeof(buf));
1146         ret = numbytes;
1147         if (ret < 0)
1148                 goto err_out;
1149         ret = -E_AUTH;
1150         if (!numbytes)
1151                 goto err_out;
1152         if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1153                         || chall_response != challenge_nr)
1154                 goto err_out;
1155         /* auth successful. Send 'Proceed' message */
1156         PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1157         sprintf(buf, "%s", PROCEED_MSG);
1158         if (use_rc4) {
1159                 init_rc4_keys();
1160                 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1161                         (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1162                 if (ret <= 0)
1163                         goto err_out;
1164                 numbytes = ret + strlen(PROCEED_MSG) + 1;
1165         } else
1166                 numbytes = strlen(buf);
1167         ret = send_bin_buffer(fd, buf, numbytes);
1168         if (ret < 0)
1169                 goto err_out;
1170         if (use_rc4)
1171                 enable_crypt(fd, rc4_recv, rc4_send);
1172         /* read command */
1173         while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1174 //              PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1175                 ret = -E_COMMAND_SYNTAX;
1176                 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1177                         goto err_out;
1178                 command = para_strcat(command, buf);
1179                 if ((p = strstr(command, EOC_MSG))) {
1180                         *p = '\0';
1181                         break;
1182                 }
1183         }
1184         ret = numbytes;
1185         if (ret < 0)
1186                 goto err_out;
1187         ret = -E_BAD_CMD;
1188         /* parse command */
1189         if (!(cmd = parse_cmd(command)))
1190                 goto err_out;
1191         /* valid command, check permissions */
1192         ret = check_perms(u.perms, cmd);
1193         if (ret < 0)
1194                 goto err_out;
1195         /* valid command and sufficient perms */
1196         alarm(0);
1197         argc = split_args(command, &argv, "\n");
1198         mmd_lock();
1199         mmd->num_commands++;
1200         mmd_unlock();
1201         PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1202                 inet_ntoa(addr->sin_addr));
1203         ret = cmd->handler(fd, argc, argv);
1204         if (ret >= 0) {
1205                 ret = EXIT_SUCCESS;
1206                 goto out;
1207         }
1208 err_out:
1209         if (ret != -E_SEND && ret != -E_RECV) {
1210                 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1211                 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1212         }
1213         ret = EXIT_FAILURE;
1214 out:
1215         free(command);
1216         free(argv);
1217         mmd_lock();
1218         if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1219                 mmd->events++;
1220         mmd->active_connections--;
1221         mmd_unlock();
1222         return ret;
1223 }