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