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