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