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