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