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