para_play: introduce struct private_alsa_data
[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], now.tv_sec, now.tv_usec
440
441 );
442 free(bar);
443 free(flags);
444 free(status);
445 free(ut);
446 return ret;
447 }
448
449 static int check_sender_args(int argc, char **argv, struct sender_command_data *scd)
450 {
451 int i;
452 /* this has to match sender.h */
453 const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
454
455 scd->sender_num = -1;
456 if (argc < 2)
457 return -E_COMMAND_SYNTAX;
458 for (i = 0; senders[i].name; i++)
459 if (!strcmp(senders[i].name, argv[1]))
460 break;
461 PARA_DEBUG_LOG("%d:%s\n", argc, argv[1]);
462 if (!senders[i].name)
463 return -E_COMMAND_SYNTAX;
464 scd->sender_num = i;
465 for (i = 0; subcmds[i]; i++)
466 if (!strcmp(subcmds[i], argv[2]))
467 break;
468 if (!subcmds[i])
469 return -E_COMMAND_SYNTAX;
470 scd->cmd_num = i;
471 mmd_lock();
472 if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) {
473 mmd_unlock();
474 return -E_SENDER_CMD;
475 }
476 mmd_unlock();
477 switch (scd->cmd_num) {
478 case SENDER_ON:
479 case SENDER_OFF:
480 if (argc != 3)
481 return -E_COMMAND_SYNTAX;
482 break;
483 case SENDER_DENY:
484 case SENDER_ALLOW:
485 if (argc != 4 && argc != 5)
486 return -E_COMMAND_SYNTAX;
487 if (!inet_aton(argv[3], &scd->addr))
488 return -E_COMMAND_SYNTAX;
489 scd->netmask = 32;
490 if (argc == 5) {
491 scd->netmask = atoi(argv[4]);
492 if (scd->netmask < 0 || scd->netmask > 32)
493 return -E_COMMAND_SYNTAX;
494 }
495 break;
496 case SENDER_ADD:
497 case SENDER_DELETE:
498 if (argc != 4 && argc != 5)
499 return -E_COMMAND_SYNTAX;
500 if (!inet_aton(argv[3], &scd->addr))
501 return -E_COMMAND_SYNTAX;
502 scd->port = -1;
503 if (argc == 5) {
504 scd->port = atoi(argv[4]);
505 if (scd->port < 0 || scd->port > 65535)
506 return -E_COMMAND_SYNTAX;
507 }
508 break;
509 default:
510 return -E_COMMAND_SYNTAX;
511 }
512 return 1;
513 }
514
515 static int com_sender(int fd, int argc, char **argv)
516 {
517 int i, ret;
518 struct sender_command_data scd;
519
520 if (argc < 2) {
521 char *msg = NULL;
522 for (i = 0; senders[i].name; i++) {
523 char *tmp = make_message("%s%s\n",
524 msg? msg : "", senders[i].name);
525 free(msg);
526 msg = tmp;
527 }
528 ret = send_buffer(fd, msg);
529 free(msg);
530 return ret;
531 }
532 ret = check_sender_args(argc, argv, &scd);
533 if (ret < 0) {
534 char *msg;
535 if (scd.sender_num < 0)
536 return ret;
537 msg = senders[scd.sender_num].help();
538 send_buffer(fd, msg);
539 free(msg);
540 return 1;
541 }
542 for (i = 0; i < 10; i++) {
543 mmd_lock();
544 if (mmd->sender_cmd_data.cmd_num >= 0) {
545 mmd_unlock();
546 usleep(100 * 1000);
547 continue;
548 }
549 mmd->sender_cmd_data = scd;
550 mmd_unlock();
551 break;
552 }
553 return (i < 10)? 1 : -E_LOCK;
554 }
555
556 /* server info */
557 static int com_si(int fd, int argc, __a_unused char **argv)
558 {
559 int i, ret;
560 char *ut;
561 char *selector_string = NULL, *sender_info = NULL, *sender_list = NULL;
562
563 if (argc != 1)
564 return -E_COMMAND_SYNTAX;
565 mmd_lock();
566 for (i = 0; selectors[i].name; i++) {
567 selector_string = para_strcat(selector_string, selectors[i].name);
568 selector_string = para_strcat(selector_string, " ");
569 }
570 for (i = 0; senders[i].name; i++) {
571 char *info = senders[i].info();
572 sender_info = para_strcat(sender_info, info);
573 free(info);
574 sender_list = para_strcat(sender_list, senders[i].name);
575 sender_list = para_strcat(sender_list, " ");
576 }
577 ut = uptime_str();
578 ret = send_va_buffer(fd, "up: %s\nplayed: %u\n"
579 "pid: %d\n"
580 "connections (active/accepted/total): %u/%u/%u\n"
581 "current loglevel: %i\n"
582 "supported audio file selectors: %s\n"
583 "supported audio formats: %s\n"
584 "supported senders: %s\n"
585 "%s",
586 ut, mmd->num_played,
587 getppid(),
588 mmd->active_connections,
589 mmd->num_commands,
590 mmd->num_connects,
591 conf.loglevel_arg,
592 selector_string,
593 SUPPORTED_AUDIO_FORMATS,
594 sender_list,
595 sender_info
596 );
597 mmd_unlock();
598 free(ut);
599 free(selector_string);
600 free(sender_list);
601 free(sender_info);
602 return ret;
603 }
604
605 /* version */
606 static int com_version(int socket_fd, int argc, __a_unused char **argv)
607 {
608 if (argc != 1)
609 return -E_COMMAND_SYNTAX;
610 return send_buffer(socket_fd, "para_server-" VERSION ", \"" CODENAME "\"\n"
611 COPYRIGHT "\n"
612 "built: " BUILD_DATE "\n"
613 SYSTEM ", " CC_VERSION "\n"
614 );
615 }
616
617 /* sc */
618 static int com_sc(int socket_fd, int argc, char **argv)
619 {
620 char *name = NULL;
621 int ret, old = 0, count = -1; /* print af change forever */
622
623 if (argc > 1)
624 count = atoi(argv[1]);
625 repeat:
626 mmd_lock();
627 if (old != mmd->num_played) {
628 old = mmd->num_played;
629 name = para_strdup(mmd->filename);
630 }
631 mmd_unlock();
632 if (name) {
633 ret = send_va_buffer(socket_fd, "%s\n", name);
634 free(name);
635 name = NULL;
636 if (ret < 0)
637 return ret;
638 if (argc > 1 && !--count)
639 return 1;
640 }
641 usleep(500000);
642 goto repeat;
643 }
644
645 /* sb */
646 static int com_sb(int socket_fd, int argc, char **argv)
647 {
648 char *sb;
649 int ret, nr = -1; /* status bar will be printed that many
650 * times. Negative value means: print
651 * forever
652 */
653 if (argc > 1)
654 nr = atoi(argv[1]);
655 while (nr) {
656 mmd_lock();
657 sb = get_sb_string(mmd);
658 mmd_unlock();
659 ret = send_va_buffer(socket_fd, "%s\n", sb);
660 free(sb);
661 if (ret < 0)
662 return ret;
663 if (nr == 1)
664 return 1;
665 usleep(500000);
666 if (nr > 0)
667 nr--;
668 }
669 return 1;
670 }
671
672 /* stat */
673 static int com_stat(int socket_fd, int argc, char **argv)
674 {
675 int ret, num = 0;/* status will be printed that many
676 * times. num <= 0 means: print forever
677 */
678 struct misc_meta_data tmp, *nmmd = &tmp;
679 char *s;
680
681 signal(SIGUSR1, dummy);
682
683 if (argc > 1)
684 num = atoi(argv[1]);
685 for (;;) {
686
687 mmd_dup(nmmd);
688 s = get_status(nmmd);
689 ret = send_buffer(socket_fd, s);
690 free(s);
691 if (ret < 0)
692 goto out;
693 ret = 1;
694 if (num == 1)
695 goto out;
696 usleep(500000 * 100);
697 }
698 out:
699 return ret;
700 }
701
702 static int send_description(int fd, struct server_command *cmd, const char *handler, int num)
703 {
704 int ret, i;
705
706 for (i = 1; cmd->name && (!num || i <= num); cmd++, i++) {
707 char *perms = cmd_perms_itohuman(cmd->perms);
708 ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name,
709 handler,
710 perms,
711 cmd->description);
712 free(perms);
713 if (ret < 0)
714 return ret;
715 }
716 return 1;
717 }
718
719 /* always returns string that must be freed by the caller in handler */
720 static struct server_command *get_cmd_ptr(char *name, char **handler)
721 {
722 struct server_command *cmd = cmd_struct;
723
724 for (cmd = cmd_struct; cmd->name; cmd++)
725 if (!strcmp(cmd->name, name)) {
726 if (handler)
727 *handler = para_strdup("para_server"); /* server commands */
728 return cmd;
729 }
730 /* not found, look for commands supported by the current selector */
731 mmd_lock();
732 if (handler)
733 *handler = make_message("the %s selector",
734 selectors[mmd->selector_num].name);
735 cmd = selectors[mmd->selector_num].cmd_list;
736 mmd_unlock();
737 for (; cmd->name; cmd++)
738 if (!strcmp(cmd->name, name))
739 return cmd;
740 return NULL;
741 }
742
743 /* help */
744 static int com_help(int fd, int argc, char **argv)
745 {
746 struct server_command *cmd;
747 char *perms, *handler;
748 int ret;
749
750 if (argc < 2) {
751 /* no argument given, print list of commands */
752 if ((ret = send_description(fd, cmd_struct, "server", 0)) < 0)
753 return ret;
754 mmd_lock();
755 handler = para_strdup(selectors[mmd->selector_num].name);
756 cmd = selectors[mmd->selector_num].cmd_list;
757 mmd_unlock();
758 ret = send_description(fd, cmd, handler, 0);
759 free(handler);
760 return ret;
761 }
762 /* argument given for help */
763 cmd = get_cmd_ptr(argv[1], &handler);
764 if (!cmd) {
765 free(handler);
766 return -E_BAD_CMD;
767 }
768 perms = cmd_perms_itohuman(cmd->perms);
769 ret = send_va_buffer(fd,
770 "NAME\n\t%s - %s\n"
771 "SYNOPSIS\n\t para_client %s\n"
772 "DESCRIPTION\n%s\n"
773 "HANDLER\n"
774 "This command is handled by %s.\n\n"
775 "PERMISSIONS\n"
776 "Needed privileges for %s: %s\n",
777 argv[1],
778 cmd->description,
779 cmd->synopsis,
780 cmd->help,
781 handler,
782 argv[1],
783 perms
784 );
785 free(perms);
786 free(handler);
787 return ret;
788 }
789
790 /* hup */
791 static int com_hup(__a_unused int socket_fd, int argc, __a_unused char **argv)
792 {
793 if (argc != 1)
794 return -E_COMMAND_SYNTAX;
795 kill(getppid(), SIGHUP);
796 return 1;
797 }
798
799 /* term */
800 static int com_term(__a_unused int socket_fd, int argc, __a_unused char **argv)
801 {
802 if (argc != 1)
803 return -E_COMMAND_SYNTAX;
804 kill(getppid(), SIGTERM);
805 return 1;
806 }
807
808 static int com_play(__a_unused int socket_fd, int argc, __a_unused char **argv)
809 {
810 if (argc != 1)
811 return -E_COMMAND_SYNTAX;
812 mmd_lock();
813 mmd->new_afs_status_flags |= AFS_PLAYING;
814 mmd->new_afs_status_flags &= ~AFS_NOMORE;
815 mmd_unlock();
816 return 1;
817
818 }
819
820 /* stop */
821 static int com_stop(__a_unused int socket_fd, int argc, __a_unused char **argv)
822 {
823 if (argc != 1)
824 return -E_COMMAND_SYNTAX;
825 mmd_lock();
826 mmd->new_afs_status_flags &= ~AFS_PLAYING;
827 mmd->new_afs_status_flags &= ~AFS_REPOS;
828 mmd->new_afs_status_flags |= AFS_NEXT;
829 mmd_unlock();
830 return 1;
831 }
832
833 /* pause */
834 static int com_pause(__a_unused int socket_fd, int argc, __a_unused char **argv)
835 {
836 if (argc != 1)
837 return -E_COMMAND_SYNTAX;
838 mmd_lock();
839 if (!afs_paused())
840 mmd->events++;
841 mmd->new_afs_status_flags &= ~AFS_PLAYING;
842 mmd->new_afs_status_flags &= ~AFS_NEXT;
843 mmd_unlock();
844 return 1;
845 }
846
847 static int com_chs(int fd, int argc, char **argv)
848 {
849 int i, ret;
850
851 if (argc == 1) {
852 char *selector;
853 mmd_lock();
854 selector = para_strdup(selectors[mmd->selector_num].name);
855 mmd_unlock();
856 ret = send_va_buffer(fd, "%s\n", selector);
857 free(selector);
858 return ret;
859 }
860 for (i = 0; selectors[i].name; i++) {
861 if (strcmp(selectors[i].name, argv[1]))
862 continue;
863 mmd_lock();
864 mmd->selector_change = i;
865 mmd->events++;
866 mmd_unlock();
867 return 1;
868 }
869 return -E_BAD_SELECTOR;
870 }
871
872 /* next */
873 static int com_next(__a_unused int socket_fd, int argc, __a_unused char **argv)
874 {
875 if (argc != 1)
876 return -E_COMMAND_SYNTAX;
877 mmd_lock();
878 mmd->events++;
879 mmd->new_afs_status_flags |= AFS_NEXT;
880 mmd_unlock();
881 return 1;
882 }
883
884 /* nomore */
885 static int com_nomore(__a_unused int socket_fd, int argc, __a_unused char **argv)
886 {
887 if (argc != 1)
888 return -E_COMMAND_SYNTAX;
889 mmd_lock();
890 if (afs_playing() || afs_paused())
891 mmd->new_afs_status_flags |= AFS_NOMORE;
892 mmd_unlock();
893 return 1;
894 }
895
896 /* ff */
897 static int com_ff(__a_unused int socket_fd, int argc, char **argv)
898 {
899 long promille;
900 int ret, backwards = 0;
901 unsigned i;
902 char c;
903
904 if (argc != 2)
905 return -E_COMMAND_SYNTAX;
906 if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
907 return -E_COMMAND_SYNTAX;
908 if (ret > 1 && c == '-')
909 backwards = 1; /* jmp backwards */
910 mmd_lock();
911 ret = -E_NO_AUDIO_FILE;
912 if (!mmd->chunks_total || !mmd->seconds_total)
913 goto out;
914 promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
915 if (backwards)
916 promille -= 1000 * i / mmd->seconds_total;
917 else
918 promille += 1000 * i / mmd->seconds_total;
919 if (promille < 0)
920 promille = 0;
921 if (promille > 1000) {
922 mmd->new_afs_status_flags |= AFS_NEXT;
923 goto out;
924 }
925 mmd->repos_request = (mmd->chunks_total * promille) / 1000;
926 mmd->new_afs_status_flags |= AFS_REPOS;
927 mmd->new_afs_status_flags &= ~AFS_NEXT;
928 mmd->events++;
929 ret = 1;
930 out:
931 mmd_unlock();
932 return ret;
933 }
934
935 /* jmp */
936 static int com_jmp(__a_unused int socket_fd, int argc, char **argv)
937 {
938 long unsigned int i;
939 int ret;
940
941 if (argc != 2)
942 return -E_COMMAND_SYNTAX;
943 if (sscanf(argv[1], "%lu", &i) <= 0)
944 return -E_COMMAND_SYNTAX;
945 mmd_lock();
946 ret = -E_NO_AUDIO_FILE;
947 if (!mmd->chunks_total)
948 goto out;
949 if (i > 100)
950 i = 100;
951 PARA_INFO_LOG("jumping to %lu%%\n", i);
952 mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
953 PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
954 mmd->chunks_sent, mmd->offset);
955 mmd->new_afs_status_flags |= AFS_REPOS;
956 mmd->new_afs_status_flags &= ~AFS_NEXT;
957 ret = 1;
958 mmd->events++;
959 out:
960 mmd_unlock();
961 return ret;
962 }
963
964 /*
965 * check if perms are sufficient to exec a command having perms cmd_perms.
966 * Returns 0 if perms are sufficient, -E_PERM otherwise.
967 */
968 static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
969 {
970 PARA_DEBUG_LOG("%s", "checking permissions\n");
971 return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
972 }
973
974 /*
975 * Parse first string from *cmd and lookup in table of valid commands.
976 * On error, NULL is returned.
977 */
978 static struct server_command *parse_cmd(const char *cmdstr)
979 {
980 char buf[255];
981 int n = 0;
982
983 sscanf(cmdstr, "%200s%n", buf, &n);
984 if (!n)
985 return NULL;
986 buf[n] = '\0';
987 return get_cmd_ptr(buf, NULL);
988 }
989
990 long int para_rand(long unsigned max)
991 {
992 return (long int) ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
993 }
994
995 /* Open user_list file, returns pointer to opened file on success,
996 * NULL on errors
997 */
998 static FILE *open_user_list(char *file)
999 {
1000 PARA_DEBUG_LOG("opening user list %s\n", file);
1001 return fopen(file, "r");
1002 }
1003
1004 /*
1005 * lookup user in user_list file. Fills in a user struct containing
1006 * filename of the user's public key as well as the permissions of that user.
1007 * Returns 1 on success, 0 if user does not exist and < 0 on errors.
1008 */
1009 static int get_user(struct user *user) {
1010 FILE *file_ptr;
1011 char *char_ptr;
1012 char line[MAXLINE];
1013 /* keyword, user, key, perms */
1014 char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
1015 int num;
1016
1017 file_ptr = open_user_list(user_list);
1018 if (!file_ptr)
1019 return -E_USERLIST;
1020 while (fgets(line, MAXLINE, file_ptr)) {
1021 // PARA_DEBUG_LOG("%s: Read line (%i bytes) "
1022 // "from config file\n", __func__, strlen(line));
1023 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
1024 continue;
1025 if (!strcmp(w, "user") && !strcmp(user->name, n)) {
1026 PARA_DEBUG_LOG("found entry for %s\n", n);
1027 strcpy(user->name, n);
1028 strcpy(user->pubkey_file, k);
1029 user->perms = 0;
1030 char_ptr = p;
1031 num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
1032 tmp[0], tmp[1], tmp[2], tmp[3]);
1033 PARA_DEBUG_LOG("found %i perm entries\n",
1034 num);
1035 user->perms = 0;
1036 while (num > 0) {
1037 num--;
1038 //PARA_DEBUG_LOG("%s: tmp[%i]=%s\n", __func__,
1039 // num, tmp[num]);
1040 if (!strcmp(tmp[num], "AFS_READ"))
1041 user->perms =
1042 user->perms | AFS_READ;
1043 else if (!strcmp(tmp[num], "AFS_WRITE"))
1044 user->perms =
1045 user->perms | AFS_WRITE;
1046 else if (!strcmp(tmp[num], "DB_READ"))
1047 user->perms = user->perms | DB_READ;
1048 else if (!strcmp(tmp[num], "DB_WRITE"))
1049 user->perms = user->perms | DB_WRITE;
1050 else /* unknown permission */
1051 PARA_WARNING_LOG("unknown permission:"
1052 "%s\n", tmp[num]);
1053 }
1054 fclose(file_ptr);
1055 return 1;
1056 }
1057 }
1058 fclose(file_ptr);
1059 return 0;
1060 }
1061
1062 static void init_rc4_keys(void)
1063 {
1064 int i;
1065
1066 for (i = 0; i < 2 * RC4_KEY_LEN; i++)
1067 rc4_buf[i] = para_rand(256);
1068 PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
1069 (unsigned char) rc4_buf[0],
1070 (unsigned char) rc4_buf[RC4_KEY_LEN]);
1071 RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf);
1072 RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
1073 }
1074
1075 static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1076 {
1077 RC4(&rc4_recv_key, len, indata, outdata);
1078 }
1079
1080 static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
1081 {
1082 RC4(&rc4_send_key, len, indata, outdata);
1083 }
1084
1085 int handle_connect(int fd, struct sockaddr_in *addr)
1086 {
1087 int numbytes, ret, argc, use_rc4 = 0;
1088 char buf[STRINGSIZE];
1089 unsigned char crypt_buf[MAXLINE];
1090 struct user u;
1091 struct server_command *cmd = NULL;
1092 long unsigned challenge_nr, chall_response;
1093 char **argv = NULL;
1094 char *p, *command = NULL;
1095
1096 signal(SIGCHLD, SIG_IGN);
1097 signal(SIGINT, SIG_DFL);
1098 signal(SIGTERM, SIG_DFL);
1099 signal(SIGHUP, SIG_DFL);
1100 signal(SIGUSR1, SIG_IGN);
1101
1102 in_addr = addr;
1103 challenge_nr = random();
1104 /* send Welcome message */
1105 ret = send_va_buffer(fd, "This is para_server, version " VERSION ".\n" );
1106 if (ret < 0)
1107 goto err_out;
1108 /* recv auth request line */
1109 ret = recv_buffer(fd, buf, sizeof(buf));
1110 if (ret < 0)
1111 goto err_out;
1112 if (ret <= 6) {
1113 ret = -E_AUTH;
1114 goto err_out;
1115 }
1116 numbytes = ret;
1117 ret = -E_AUTH;
1118 if (strncmp(buf, "auth ", 5))
1119 goto err_out;
1120
1121 if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9))
1122 strcpy(u.name, buf + 5); /* client version < 0.2.6 */
1123 else {
1124 strcpy(u.name, buf + 9); /* client version >= 0.2.6 */
1125 use_rc4 = 1;
1126 }
1127 // strcpy(u.name, buf + 5); /* ok, but ugly */
1128 PARA_DEBUG_LOG("received %s request for user %s\n",
1129 use_rc4? "rc4" : "auth", u.name);
1130 /* lookup user in list file */
1131 if ((ret = get_user(&u)) < 0)
1132 goto err_out;
1133 if (!ret) { /* user not found */
1134 PARA_WARNING_LOG("auth request for unknown user %s\n", u.name);
1135 ret = -E_BAD_USER;
1136 goto err_out;
1137 }
1138 ret = para_encrypt_challenge(u.pubkey_file, challenge_nr, crypt_buf);
1139 if (ret <= 0)
1140 goto err_out;
1141 numbytes = ret;
1142 PARA_DEBUG_LOG("sending %d byte challenge\n", numbytes);
1143 /* We can't use send_buffer here since buf may contain null bytes */
1144 ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes);
1145 if (ret < 0)
1146 goto err_out;
1147 /* recv decrypted number */
1148 numbytes = recv_buffer(fd, buf, sizeof(buf));
1149 ret = numbytes;
1150 if (ret < 0)
1151 goto err_out;
1152 ret = -E_AUTH;
1153 if (!numbytes)
1154 goto err_out;
1155 if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1
1156 || chall_response != challenge_nr)
1157 goto err_out;
1158 /* auth successful. Send 'Proceed' message */
1159 PARA_INFO_LOG("good auth for %s (%lu)\n", u.name, challenge_nr);
1160 sprintf(buf, "%s", PROCEED_MSG);
1161 if (use_rc4) {
1162 init_rc4_keys();
1163 ret = para_encrypt_buffer(u.pubkey_file, rc4_buf, 2 * RC4_KEY_LEN,
1164 (unsigned char *)buf + PROCEED_MSG_LEN + 1);
1165 if (ret <= 0)
1166 goto err_out;
1167 numbytes = ret + strlen(PROCEED_MSG) + 1;
1168 } else
1169 numbytes = strlen(buf);
1170 ret = send_bin_buffer(fd, buf, numbytes);
1171 if (ret < 0)
1172 goto err_out;
1173 if (use_rc4) {
1174 crypt_function_recv = rc4_recv;
1175 crypt_function_send = rc4_send;
1176 PARA_INFO_LOG("%s", "rc4 encrytion activated\n");
1177 }
1178 /* read command */
1179 while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
1180 // PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
1181 ret = -E_COMMAND_SYNTAX;
1182 if (command && numbytes + strlen(command) > STRINGSIZE) /* DOS */
1183 goto err_out;
1184 command = para_strcat(command, buf);
1185 if ((p = strstr(command, EOC_MSG))) {
1186 *p = '\0';
1187 break;
1188 }
1189 }
1190 ret = numbytes;
1191 if (ret < 0)
1192 goto err_out;
1193 ret = -E_BAD_CMD;
1194 /* parse command */
1195 if (!(cmd = parse_cmd(command)))
1196 goto err_out;
1197 /* valid command, check permissions */
1198 ret = check_perms(u.perms, cmd);
1199 if (ret < 0)
1200 goto err_out;
1201 /* valid command and sufficient perms */
1202 alarm(0);
1203 argc = split_args(command, &argv, "\n");
1204 mmd_lock();
1205 mmd->num_commands++;
1206 mmd_unlock();
1207 PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u.name,
1208 inet_ntoa(addr->sin_addr));
1209 ret = cmd->handler(fd, argc, argv);
1210 if (ret >= 0) {
1211 ret = EXIT_SUCCESS;
1212 goto out;
1213 }
1214 err_out:
1215 if (ret != -E_SEND && ret != -E_RECV) {
1216 PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-ret));
1217 send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
1218 }
1219 ret = EXIT_FAILURE;
1220 out:
1221 free(command);
1222 free(argv);
1223 mmd_lock();
1224 if (cmd && (cmd->perms & DB_WRITE) && ret >= 0)
1225 mmd->events++;
1226 mmd->active_connections--;
1227 mmd_unlock();
1228 return ret;
1229 }