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