newvector should be a bool
[freeradius.git] / src / main / command.c
1 /*
2  * command.c    Command socket processing.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008 Alan DeKok <aland@deployingradius.com>
22  */
23
24 #ifdef WITH_COMMAND_SOCKET
25
26 #include <freeradius-devel/parser.h>
27 #include <freeradius-devel/md5.h>
28
29 #ifdef HAVE_INTTYPES_H
30 #include <inttypes.h>
31 #endif
32
33 #ifdef HAVE_SYS_UN_H
34 #include <sys/un.h>
35 #ifndef SUN_LEN
36 #define SUN_LEN(su)  (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
37 #endif
38 #endif
39
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h>
42 #endif
43
44 #ifdef HAVE_PWD_H
45 #include <pwd.h>
46 #endif
47
48 #ifdef HAVE_GRP_H
49 #include <grp.h>
50 #endif
51
52 typedef struct fr_command_table_t fr_command_table_t;
53
54 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
55
56 #define FR_READ  (1)
57 #define FR_WRITE (2)
58
59 struct fr_command_table_t {
60         char const *command;
61         int mode;               /* read/write */
62         char const *help;
63         fr_command_func_t func;
64         fr_command_table_t *table;
65 };
66
67 #define COMMAND_BUFFER_SIZE (1024)
68
69 typedef struct fr_cs_buffer_t {
70         int             auth;
71         int             mode;
72         ssize_t         offset;
73         ssize_t         next;
74         char            buffer[COMMAND_BUFFER_SIZE];
75 } fr_cs_buffer_t;
76
77 #define COMMAND_SOCKET_MAGIC (0xffdeadee)
78 typedef struct fr_command_socket_t {
79         uint32_t        magic;
80         char const      *path;
81         char            *copy;          /* <sigh> */
82         uid_t           uid;
83         gid_t           gid;
84         char const      *uid_name;
85         char const      *gid_name;
86         char const      *mode_name;
87         char user[256];
88
89         /*
90          *      The next few entries handle fake packets injected by
91          *      the control socket.
92          */
93         fr_ipaddr_t     src_ipaddr; /* src_port is always 0 */
94         fr_ipaddr_t     dst_ipaddr;
95         uint16_t        dst_port;
96         rad_listen_t    *inject_listener;
97         RADCLIENT       *inject_client;
98
99         fr_cs_buffer_t  co;
100 } fr_command_socket_t;
101
102 static const CONF_PARSER command_config[] = {
103         { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, path), "${run_dir}/radiusd.sock" },
104         { "uid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, uid_name), NULL },
105         { "gid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, gid_name), NULL },
106         { "mode", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, mode_name), NULL },
107
108         { NULL, -1, 0, NULL, NULL }             /* end the list */
109 };
110
111 static FR_NAME_NUMBER mode_names[] = {
112         { "ro", FR_READ },
113         { "read-only", FR_READ },
114         { "read-write", FR_READ | FR_WRITE },
115         { "rw", FR_READ | FR_WRITE },
116         { NULL, 0 }
117 };
118
119 extern const FR_NAME_NUMBER mod_rcode_table[];
120
121 #ifndef HAVE_GETPEEREID
122 static int getpeereid(int s, uid_t *euid, gid_t *egid)
123 {
124 #ifndef SO_PEERCRED
125         return -1;
126 #else
127         struct ucred cr;
128         socklen_t cl = sizeof(cr);
129
130         if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
131                 return -1;
132         }
133
134         *euid = cr.uid;
135         *egid = cr.gid;
136         return 0;
137 #endif /* SO_PEERCRED */
138 }
139 #endif /* HAVE_GETPEEREID */
140
141
142 static int fr_server_domain_socket(char const *path)
143 {
144         int sockfd;
145         size_t len;
146         socklen_t socklen;
147         struct sockaddr_un salocal;
148         struct stat buf;
149
150         if (!path) {
151                 ERROR("No path provided, was NULL");
152                 return -1;
153         }
154
155         len = strlen(path);
156         if (len >= sizeof(salocal.sun_path)) {
157                 ERROR("Path too long in socket filename");
158                 return -1;
159         }
160
161         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
162                 ERROR("Failed creating socket: %s",
163                         fr_syserror(errno));
164                 return -1;
165         }
166
167         memset(&salocal, 0, sizeof(salocal));
168         salocal.sun_family = AF_UNIX;
169         memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
170
171         socklen = SUN_LEN(&salocal);
172
173         /*
174          *      Check the path.
175          */
176         if (stat(path, &buf) < 0) {
177                 if (errno != ENOENT) {
178                         ERROR("Failed to stat %s: %s",
179                                path, fr_syserror(errno));
180                         close(sockfd);
181                         return -1;
182                 }
183
184                 /*
185                  *      FIXME: Check the enclosing directory?
186                  */
187         } else {                /* it exists */
188                 if (!S_ISREG(buf.st_mode)
189 #ifdef S_ISSOCK
190                     && !S_ISSOCK(buf.st_mode)
191 #endif
192                         ) {
193                         ERROR("Cannot turn %s into socket", path);
194                         close(sockfd);
195                         return -1;
196                 }
197
198                 /*
199                  *      Refuse to open sockets not owned by us.
200                  */
201                 if (buf.st_uid != geteuid()) {
202                         ERROR("We do not own %s", path);
203                         close(sockfd);
204                         return -1;
205                 }
206
207                 if (unlink(path) < 0) {
208                        ERROR("Failed to delete %s: %s",
209                              path, fr_syserror(errno));
210                        close(sockfd);
211                        return -1;
212                 }
213         }
214
215         if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
216                 ERROR("Failed binding to %s: %s",
217                         path, fr_syserror(errno));
218                 close(sockfd);
219                 return -1;
220         }
221
222         /*
223          *      FIXME: There's a race condition here.  But Linux
224          *      doesn't seem to permit fchmod on domain sockets.
225          */
226         if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
227                 ERROR("Failed setting permissions on %s: %s",
228                        path, fr_syserror(errno));
229                 close(sockfd);
230                 return -1;
231         }
232
233         if (listen(sockfd, 8) < 0) {
234                 ERROR("Failed listening to %s: %s",
235                         path, fr_syserror(errno));
236                 close(sockfd);
237                 return -1;
238         }
239
240 #ifdef O_NONBLOCK
241         {
242                 int flags;
243
244                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
245                         ERROR("Failure getting socket flags: %s",
246                                 fr_syserror(errno));
247                         close(sockfd);
248                         return -1;
249                 }
250
251                 flags |= O_NONBLOCK;
252                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
253                         ERROR("Failure setting socket flags: %s",
254                                 fr_syserror(errno));
255                         close(sockfd);
256                         return -1;
257                 }
258         }
259 #endif
260
261         return sockfd;
262 }
263
264
265 static void command_close_socket(rad_listen_t *this)
266 {
267         this->status = RAD_LISTEN_STATUS_EOL;
268
269         /*
270          *      This removes the socket from the event fd, so no one
271          *      will be calling us any more.
272          */
273         radius_update_listener(this);
274 }
275
276 static ssize_t CC_HINT(format (printf, 2, 3)) cprintf(rad_listen_t *listener, char const *fmt, ...)
277 {
278         ssize_t len;
279         va_list ap;
280         char buffer[256];
281
282         va_start(ap, fmt);
283         len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
284         va_end(ap);
285
286         if (listener->status == RAD_LISTEN_STATUS_EOL) return 0;
287
288         len = write(listener->fd, buffer, len);
289         if (len <= 0) command_close_socket(listener);
290
291         /*
292          *      FIXME: Keep writing until done?
293          */
294         return len;
295 }
296
297 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
298 {
299         CONF_SECTION *cs;
300         module_instance_t *mi;
301         char buffer[256];
302
303         if (argc == 0) {
304                 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
305                 return 1;
306         }
307
308         /*
309          *      Hack a "main" HUP thingy
310          */
311         if (strcmp(argv[0], "main.log") == 0) {
312                 hup_logfile();
313                 return 1;
314         }
315
316         cs = cf_section_find("modules");
317         if (!cs) return 0;
318
319         mi = find_module_instance(cs, argv[0], 0);
320         if (!mi) {
321                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
322                 return 0;
323         }
324
325         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
326                 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
327                         argv[0]);
328                 return 0;
329         }
330
331         if (!module_hup_module(mi->cs, mi, time(NULL))) {
332                 cprintf(listener, "ERROR: Failed to reload module\n");
333                 return 0;
334         }
335
336         snprintf(buffer, sizeof(buffer), "modules.%s.hup",
337                  cf_section_name1(mi->cs));
338         exec_trigger(NULL, mi->cs, buffer, true);
339
340         return 1;               /* success */
341 }
342
343 static int command_terminate(UNUSED rad_listen_t *listener,
344                              UNUSED int argc, UNUSED char *argv[])
345 {
346         radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
347
348         return 1;               /* success */
349 }
350
351 extern time_t fr_start_time;
352
353 static int command_uptime(rad_listen_t *listener,
354                           UNUSED int argc, UNUSED char *argv[])
355 {
356         char buffer[128];
357
358         CTIME_R(&fr_start_time, buffer, sizeof(buffer));
359         cprintf(listener, "Up since %s", buffer); /* no \r\n */
360
361         return 1;               /* success */
362 }
363
364 static int command_show_config(rad_listen_t *listener, int argc, char *argv[])
365 {
366         CONF_ITEM *ci;
367         CONF_PAIR *cp;
368         char const *value;
369
370         if (argc != 1) {
371                 cprintf(listener, "ERROR: No path was given\n");
372                 return 0;
373         }
374
375         ci = cf_reference_item(main_config.config, main_config.config, argv[0]);
376         if (!ci) return 0;
377
378         if (!cf_item_is_pair(ci)) return 0;
379
380         cp = cf_itemtopair(ci);
381         value = cf_pair_value(cp);
382         if (!value) return 0;
383
384         cprintf(listener, "%s\n", value);
385
386         return 1;               /* success */
387 }
388
389 static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
390
391 /*
392  *      FIXME: Recurse && indent?
393  */
394 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
395                                void const *base)
396
397 {
398         int i;
399         char const *name1 = cf_section_name1(cs);
400         char const *name2 = cf_section_name2(cs);
401         CONF_PARSER const *variables = cf_section_parse_table(cs);
402
403         if (name2) {
404                 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
405         } else {
406                 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
407         }
408
409         indent++;
410
411         /*
412          *      Print
413          */
414         if (variables) for (i = 0; variables[i].name != NULL; i++) {
415                 void const *data;
416                 char buffer[256];
417
418                 /*
419                  *      No base struct offset, data must be the pointer.
420                  *      If data doesn't exist, ignore the entry, there
421                  *      must be something wrong.
422                  */
423                 if (!base) {
424                         if (!variables[i].data) {
425                                 continue;
426                         }
427
428                         data = variables[i].data;;
429
430                 } else if (variables[i].data) {
431                         data = variables[i].data;;
432
433                 } else {
434                         data = (((char const *)base) + variables[i].offset);
435                 }
436
437                 switch (variables[i].type) {
438                 default:
439                         cprintf(listener, "%.*s%s = ?\n", indent, tabs,
440                                 variables[i].name);
441                         break;
442
443                 case PW_TYPE_INTEGER:
444                         cprintf(listener, "%.*s%s = %u\n", indent, tabs,
445                                 variables[i].name, *(int const *) data);
446                         break;
447
448                 case PW_TYPE_IPV4_ADDR:
449                         inet_ntop(AF_INET, data, buffer, sizeof(buffer));
450                         break;
451
452                 case PW_TYPE_IPV6_ADDR:
453                         inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
454                         break;
455
456                 case PW_TYPE_BOOLEAN:
457                         cprintf(listener, "%.*s%s = %s\n", indent, tabs,
458                                 variables[i].name,
459                                 ((*(bool const *) data) == false) ? "no" : "yes");
460                         break;
461
462                 case PW_TYPE_STRING:
463                 case PW_TYPE_FILE_INPUT:
464                 case PW_TYPE_FILE_OUTPUT:
465                         /*
466                          *      FIXME: Escape things in the string!
467                          */
468                         if (*(char const * const *) data) {
469                                 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
470                                         variables[i].name, *(char const * const *) data);
471                         } else {
472                                 cprintf(listener, "%.*s%s = \n", indent, tabs,
473                                         variables[i].name);
474                         }
475
476                         break;
477                 }
478         }
479
480         indent--;
481
482         cprintf(listener, "%.*s}\n", indent, tabs);
483 }
484
485 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
486 {
487         CONF_SECTION *cs;
488         module_instance_t *mi;
489
490         if (argc != 1) {
491                 cprintf(listener, "ERROR: No module name was given\n");
492                 return 0;
493         }
494
495         cs = cf_section_find("modules");
496         if (!cs) return 0;
497
498         mi = find_module_instance(cs, argv[0], 0);
499         if (!mi) {
500                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
501                 return 0;
502         }
503
504         cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
505
506         return 1;               /* success */
507 }
508
509 static char const *method_names[RLM_COMPONENT_COUNT] = {
510         "authenticate",
511         "authorize",
512         "preacct",
513         "accounting",
514         "session",
515         "pre-proxy",
516         "post-proxy",
517         "post-auth"
518 };
519
520
521 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
522 {
523         int i;
524         CONF_SECTION *cs;
525         module_instance_t const *mi;
526         module_t const *mod;
527
528         if (argc != 1) {
529                 cprintf(listener, "ERROR: No module name was given\n");
530                 return 0;
531         }
532
533         cs = cf_section_find("modules");
534         if (!cs) return 0;
535
536         mi = find_module_instance(cs, argv[0], 0);
537         if (!mi) {
538                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
539                 return 0;
540         }
541
542         mod = mi->entry->module;
543
544         for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
545                 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
546         }
547
548         return 1;               /* success */
549 }
550
551
552 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
553 {
554         CONF_SECTION *cs;
555         module_instance_t const *mi;
556         module_t const *mod;
557
558         if (argc != 1) {
559                 cprintf(listener, "ERROR: No module name was given\n");
560                 return 0;
561         }
562
563         cs = cf_section_find("modules");
564         if (!cs) return 0;
565
566         mi = find_module_instance(cs, argv[0], 0);
567         if (!mi) {
568                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
569                 return 0;
570         }
571
572         mod = mi->entry->module;
573
574         if ((mod->type & RLM_TYPE_THREAD_UNSAFE) != 0)
575                 cprintf(listener, "\tthread-unsafe\n");
576
577
578         if ((mod->type & RLM_TYPE_CHECK_CONFIG_UNSAFE) != 0)
579                 cprintf(listener, "\tno-check-config\n");
580
581
582         if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
583                 cprintf(listener, "\treload-on-hup\n");
584
585         return 1;               /* success */
586 }
587
588 static int command_show_module_status(rad_listen_t *listener, int argc, char *argv[])
589 {
590         CONF_SECTION *cs;
591         const module_instance_t *mi;
592
593         if (argc != 1) {
594                 cprintf(listener, "ERROR: No module name was given\n");
595                 return 0;
596         }
597
598         cs = cf_section_find("modules");
599         if (!cs) return 0;
600
601         mi = find_module_instance(cs, argv[0], 0);
602         if (!mi) {
603                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
604                 return 0;
605         }
606
607         if (!mi->force) {
608                 cprintf(listener, "alive\n");
609         } else {
610                 cprintf(listener, "%s\n", fr_int2str(mod_rcode_table, mi->code, "<invalid>"));
611         }
612
613
614         return 1;               /* success */
615 }
616
617
618 /*
619  *      Show all loaded modules
620  */
621 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
622 {
623         CONF_SECTION *cs, *subcs;
624
625         cs = cf_section_find("modules");
626         if (!cs) return 0;
627
628         subcs = NULL;
629         while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
630                 char const *name1 = cf_section_name1(subcs);
631                 char const *name2 = cf_section_name2(subcs);
632
633                 module_instance_t *mi;
634
635                 if (name2) {
636                         mi = find_module_instance(cs, name2, 0);
637                         if (!mi) continue;
638
639                         cprintf(listener, "\t%s (%s)\n", name2, name1);
640                 } else {
641                         mi = find_module_instance(cs, name1, 0);
642                         if (!mi) continue;
643
644                         cprintf(listener, "\t%s\n", name1);
645                 }
646         }
647
648         return 1;               /* success */
649 }
650
651 #ifdef WITH_PROXY
652 static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
653 {
654         int i;
655         home_server_t *home;
656         char const *type, *state, *proto;
657
658         char buffer[256];
659
660         for (i = 0; i < 256; i++) {
661                 home = home_server_bynumber(i);
662                 if (!home) break;
663
664                 /*
665                  *      Internal "virtual" home server.
666                  */
667                 if (home->ipaddr.af == AF_UNSPEC) continue;
668
669                 if (home->type == HOME_TYPE_AUTH) {
670                         type = "auth";
671
672                 } else if (home->type == HOME_TYPE_ACCT) {
673                         type = "acct";
674
675 #ifdef WITH_COA
676                 } else if (home->type == HOME_TYPE_COA) {
677                         type = "coa";
678 #endif
679
680                 } else continue;
681
682                 if (home->proto == IPPROTO_UDP) {
683                         proto = "udp";
684                 }
685 #ifdef WITH_TCP
686                 else if (home->proto == IPPROTO_TCP) {
687                         proto = "tcp";
688                 }
689 #endif
690                 else proto = "??";
691
692                 if (home->state == HOME_STATE_ALIVE) {
693                         state = "alive";
694
695                 } else if (home->state == HOME_STATE_ZOMBIE) {
696                         state = "zombie";
697
698                 } else if (home->state == HOME_STATE_IS_DEAD) {
699                         state = "dead";
700
701                 } else if (home->state == HOME_STATE_UNKNOWN) {
702                         time_t now = time(NULL);
703
704                         /*
705                          *      We've recently received a packet, so
706                          *      the home server seems to be alive.
707                          *
708                          *      The *reported* state changes because
709                          *      the internal state machine NEEDS THE
710                          *      RIGHT STATE.  However, reporting that
711                          *      to the admin will confuse them.
712                          *      So... we lie.  No, that dress doesn't
713                          *      make you look fat...
714                          */
715                         if ((home->last_packet_recv + (int)home->ping_interval) >= now) {
716                                 state = "alive";
717                         } else {
718                                 state = "unknown";
719                         }
720
721                 } else continue;
722
723                 cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\n",
724                         ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
725                         home->port, proto, type, state,
726                         home->currently_outstanding);
727         }
728
729         return 0;
730 }
731 #endif
732
733 static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
734 {
735         int i;
736         RADCLIENT *client;
737         char buffer[256];
738
739         for (i = 0; i < 256; i++) {
740                 client = client_findbynumber(NULL, i);
741                 if (!client) break;
742
743                 ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
744
745                 if (((client->ipaddr.af == AF_INET) &&
746                      (client->ipaddr.prefix != 32)) ||
747                     ((client->ipaddr.af == AF_INET6) &&
748                      (client->ipaddr.prefix != 128))) {
749                         cprintf(listener, "\t%s/%d\n", buffer, client->ipaddr.prefix);
750                 } else {
751                         cprintf(listener, "\t%s\n", buffer);
752                 }
753         }
754
755         return 0;
756 }
757
758
759 static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
760 {
761         cprintf(listener, "%s\n", radiusd_version);
762         return 1;
763 }
764
765 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
766 {
767         int number;
768
769         if (argc == 0) {
770                 cprintf(listener, "ERROR: Must specify <number>\n");
771                 return -1;
772         }
773
774         number = atoi(argv[0]);
775         if ((number < 0) || (number > 4)) {
776                 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
777                 return -1;
778         }
779
780         fr_debug_flag = debug_flag = number;
781
782         return 0;
783 }
784
785 static char debug_log_file_buffer[1024];
786
787 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
788 {
789         if (debug_flag && default_log.dst == L_DST_STDOUT) {
790                 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
791                 return -1;
792         }
793
794         if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) != NULL)) {
795                 cprintf(listener, "ERROR: Cannot direct debug logs to absolute path.\n");
796         }
797
798         default_log.debug_file = NULL;
799
800         if (argc == 0) return 0;
801
802         /*
803          *      This looks weird, but it's here to avoid locking
804          *      a mutex for every log message.
805          */
806         memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer));
807
808         /*
809          *      Debug files always go to the logging directory.
810          */
811         snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer),
812                  "%s/%s", radlog_dir, argv[0]);
813
814         default_log.debug_file = &debug_log_file_buffer[0];
815
816         return 0;
817 }
818
819 extern fr_cond_t *debug_condition;
820 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
821 {
822         int i;
823         char const *error;
824         fr_cond_t *new_condition = NULL;
825         char *p, buffer[1024];
826
827         /*
828          *      Disable it.
829          */
830         if (argc == 0) {
831                 talloc_free(debug_condition);
832                 debug_condition = NULL;
833                 return 0;
834         }
835
836         if (!((argc == 1) &&
837               ((argv[0][0] == '"') || (argv[0][0] == '\'')))) {
838                 p = buffer;
839                 *p = '\0';
840                 for (i = 0; i < argc; i++) {
841                         size_t len;
842
843                         len = strlcpy(p, argv[i], buffer + sizeof(buffer) - p);
844                         p += len;
845                         *(p++) = ' ';
846                         *p = '\0';
847                 }
848
849         } else {
850                 /*
851                  *      Backwards compatibility.  De-escape the string.
852                  */
853                 char quote;
854                 char *q;
855
856                 p = argv[0];
857                 q = buffer;
858
859                 quote = *(p++);
860
861                 while (true) {
862                         if (!*p) {
863                                 ERROR("Failed parsing condition '%s': Unexpected end of string", argv[0]);
864                                 return 0;
865                         }
866
867                         if (*p == quote) {
868                                 if (p[1]) {
869                                         ERROR("Failed parsing condition '%s': Unexpected text after end of string", argv[0]);
870                                         return 0;
871                                 }
872                                 *q = '\0';
873                                 break;
874                         }
875
876                         if (*p == '\\') {
877                                 *(q++) = p[1];
878                                 p += 2;
879                                 continue;
880                         }
881
882                         *(q++) = *(p++);
883                 }
884         }
885
886         if (fr_condition_tokenize(NULL, NULL, buffer, &new_condition, &error, FR_COND_ONE_PASS) < 0) {
887                 ERROR("Failed parsing condition '%s': %s", buffer, error);
888                 return 0;
889         }
890
891         /*
892          *      Delete old condition.
893          *
894          *      This is thread-safe because the condition is evaluated
895          *      in the main server thread, along with this code.
896          */
897         talloc_free(debug_condition);
898         debug_condition = new_condition;
899
900         return 0;
901 }
902
903 static int command_show_debug_condition(rad_listen_t *listener,
904                                         UNUSED int argc, UNUSED char *argv[])
905 {
906         char buffer[1024];
907
908         if (!debug_condition) return 0;
909
910         fr_cond_sprint(buffer, sizeof(buffer), debug_condition);
911
912         cprintf(listener, "%s\n", buffer);
913         return 0;
914 }
915
916
917 static int command_show_debug_file(rad_listen_t *listener,
918                                         UNUSED int argc, UNUSED char *argv[])
919 {
920         if (!default_log.debug_file) return 0;
921
922         cprintf(listener, "%s\n", default_log.debug_file);
923         return 0;
924 }
925
926
927 static int command_show_debug_level(rad_listen_t *listener,
928                                         UNUSED int argc, UNUSED char *argv[])
929 {
930         cprintf(listener, "%d\n", debug_flag);
931         return 0;
932 }
933
934
935 static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[])
936 {
937         RADCLIENT *client;
938         fr_ipaddr_t ipaddr;
939         int proto = IPPROTO_UDP;
940
941         if (argc < 1) {
942                 cprintf(listener, "ERROR: Must specify <ipaddr>\n");
943                 return NULL;
944         }
945
946         if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
947                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
948                         fr_strerror());
949                 return NULL;
950         }
951
952 #ifdef WITH_TCP
953         if (argc >= 2) {
954                 if (strcmp(argv[1], "tcp") == 0) {
955                         proto = IPPROTO_TCP;
956
957                 } else if (strcmp(argv[1], "udp") == 0) {
958                         proto = IPPROTO_UDP;
959
960                 } else {
961                         cprintf(listener, "ERROR: Unknown protocol %s.  Please use \"udp\" or \"tcp\"\n",
962                                 argv[1]);
963                         return NULL;
964                 }
965         }
966 #endif
967
968         client = client_find(NULL, &ipaddr, proto);
969         if (!client) {
970                 cprintf(listener, "ERROR: No such client\n");
971                 return NULL;
972         }
973
974         return client;
975 }
976
977 #ifdef WITH_PROXY
978 static home_server_t *get_home_server(rad_listen_t *listener, int argc,
979                                     char *argv[], int *last)
980 {
981         home_server_t *home;
982         uint16_t port;
983         int proto = IPPROTO_UDP;
984         fr_ipaddr_t ipaddr;
985
986         if (argc < 2) {
987                 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto]\n");
988                 return NULL;
989         }
990
991         if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
992                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
993                         fr_strerror());
994                 return NULL;
995         }
996
997         port = atoi(argv[1]);
998
999         if (last) *last = 2;
1000         if (argc > 2) {
1001                 if (strcmp(argv[2], "udp") == 0) {
1002                         proto = IPPROTO_UDP;
1003                         if (last) *last = 3;
1004                 }
1005 #ifdef WITH_TCP
1006                 if (strcmp(argv[2], "tcp") == 0) {
1007                         proto = IPPROTO_TCP;
1008                         if (last) *last = 3;
1009                 }
1010 #endif
1011         }
1012
1013         home = home_server_find(&ipaddr, port, proto);
1014         if (!home) {
1015                 cprintf(listener, "ERROR: No such home server\n");
1016                 return NULL;
1017         }
1018
1019         return home;
1020 }
1021
1022 static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
1023 {
1024         int last;
1025         home_server_t *home;
1026
1027         if (argc < 3) {
1028                 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto] <state>\n");
1029                 return 0;
1030         }
1031
1032         home = get_home_server(listener, argc, argv, &last);
1033         if (!home) {
1034                 return 0;
1035         }
1036
1037         if (strcmp(argv[last], "alive") == 0) {
1038                 revive_home_server(home);
1039
1040         } else if (strcmp(argv[last], "dead") == 0) {
1041                 struct timeval now;
1042
1043                 gettimeofday(&now, NULL); /* we do this WAY too ofetn */
1044                 mark_home_server_dead(home, &now);
1045
1046         } else {
1047                 cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[last]);
1048                 return 0;
1049         }
1050
1051         return 1;
1052 }
1053
1054 static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
1055 {
1056         home_server_t *home;
1057
1058         home = get_home_server(listener, argc, argv, NULL);
1059         if (!home) {
1060                 return 0;
1061         }
1062
1063         switch (home->state) {
1064         case HOME_STATE_ALIVE:
1065                 cprintf(listener, "alive\n");
1066                 break;
1067
1068         case HOME_STATE_IS_DEAD:
1069                 cprintf(listener, "dead\n");
1070                 break;
1071
1072         case HOME_STATE_ZOMBIE:
1073                 cprintf(listener, "zombie\n");
1074                 break;
1075
1076         case HOME_STATE_UNKNOWN:
1077                 cprintf(listener, "unknown\n");
1078                 break;
1079
1080         default:
1081                 cprintf(listener, "invalid\n");
1082                 break;
1083         }
1084
1085         return 1;
1086 }
1087 #endif
1088
1089 /*
1090  *      For encode/decode stuff
1091  */
1092 static int null_socket_dencode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
1093 {
1094         return 0;
1095 }
1096
1097 static int null_socket_send(UNUSED rad_listen_t *listener, REQUEST *request)
1098 {
1099         vp_cursor_t cursor;
1100         char *output_file;
1101         FILE *fp;
1102
1103         output_file = request_data_reference(request, null_socket_send, 0);
1104         if (!output_file) {
1105                 ERROR("No output file for injected packet %d", request->number);
1106                 return 0;
1107         }
1108
1109         fp = fopen(output_file, "w");
1110         if (!fp) {
1111                 ERROR("Failed to send injected file to %s: %s",
1112                        output_file, fr_syserror(errno));
1113                 return 0;
1114         }
1115
1116         if (request->reply->code != 0) {
1117                 char const *what = "reply";
1118                 VALUE_PAIR *vp;
1119                 char buffer[1024];
1120
1121                 if (request->reply->code < FR_MAX_PACKET_CODE) {
1122                         what = fr_packet_codes[request->reply->code];
1123                 }
1124
1125                 fprintf(fp, "%s\n", what);
1126
1127                 if (debug_flag) {
1128                         RDEBUG("Injected %s packet to host %s port 0 code=%d, id=%d", what,
1129                                inet_ntop(request->reply->src_ipaddr.af,
1130                                          &request->reply->src_ipaddr.ipaddr,
1131                                          buffer, sizeof(buffer)),
1132                                          request->reply->code, request->reply->id);
1133                 }
1134
1135                 for (vp = fr_cursor_init(&cursor, &request->reply->vps);
1136                      vp;
1137                      vp = fr_cursor_next(&cursor)) {
1138                         vp_prints(buffer, sizeof(buffer), vp);
1139                         fprintf(fp, "%s\n", buffer);
1140                         if (debug_flag) {
1141                                 RDEBUG("\t%s", buffer);
1142                         }
1143                 }
1144         }
1145         fclose(fp);
1146
1147         return 0;
1148 }
1149
1150 static rad_listen_t *get_socket(rad_listen_t *listener, int argc,
1151                                char *argv[], int *last)
1152 {
1153         rad_listen_t *sock;
1154         uint16_t port;
1155         int proto = IPPROTO_UDP;
1156         fr_ipaddr_t ipaddr;
1157
1158         if (argc < 2) {
1159                 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto]\n");
1160                 return NULL;
1161         }
1162
1163         if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
1164                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1165                         fr_strerror());
1166                 return NULL;
1167         }
1168
1169         port = atoi(argv[1]);
1170
1171         if (last) *last = 2;
1172         if (argc > 2) {
1173                 if (strcmp(argv[2], "udp") == 0) {
1174                         proto = IPPROTO_UDP;
1175                         if (last) *last = 3;
1176                 }
1177 #ifdef WITH_TCP
1178                 if (strcmp(argv[2], "tcp") == 0) {
1179                         proto = IPPROTO_TCP;
1180                         if (last) *last = 3;
1181                 }
1182 #endif
1183         }
1184
1185         sock = listener_find_byipaddr(&ipaddr, port, proto);
1186         if (!sock) {
1187                 cprintf(listener, "ERROR: No such listen section\n");
1188                 return NULL;
1189         }
1190
1191         return sock;
1192 }
1193
1194
1195 static int command_inject_to(rad_listen_t *listener, int argc, char *argv[])
1196 {
1197         fr_command_socket_t *sock = listener->data;
1198         listen_socket_t *data;
1199         rad_listen_t *found;
1200
1201         found = get_socket(listener, argc, argv, NULL);
1202         if (!found) {
1203                 return 0;
1204         }
1205
1206         data = found->data;
1207         sock->inject_listener = found;
1208         sock->dst_ipaddr = data->my_ipaddr;
1209         sock->dst_port = data->my_port;
1210
1211         return 1;
1212 }
1213
1214 static int command_inject_from(rad_listen_t *listener, int argc, char *argv[])
1215 {
1216         RADCLIENT *client;
1217         fr_command_socket_t *sock = listener->data;
1218
1219         if (argc < 1) {
1220                 cprintf(listener, "ERROR: No <ipaddr> was given\n");
1221                 return 0;
1222         }
1223
1224         if (!sock->inject_listener) {
1225                 cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject from\"\n");
1226                 return 0;
1227         }
1228
1229         sock->src_ipaddr.af = AF_UNSPEC;
1230         if (ip_hton(&sock->src_ipaddr, AF_UNSPEC, argv[0], false) < 0) {
1231                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1232                         fr_strerror());
1233                 return 0;
1234         }
1235
1236         client = client_listener_find(sock->inject_listener, &sock->src_ipaddr,
1237                                       0);
1238         if (!client) {
1239                 cprintf(listener, "ERROR: No such client %s\n", argv[0]);
1240                 return 0;
1241         }
1242         sock->inject_client = client;
1243
1244         return 1;
1245 }
1246
1247 static int command_inject_file(rad_listen_t *listener, int argc, char *argv[])
1248 {
1249         static int inject_id = 0;
1250         int ret;
1251         bool filedone;
1252         fr_command_socket_t *sock = listener->data;
1253         rad_listen_t *fake;
1254         RADIUS_PACKET *packet;
1255         vp_cursor_t cursor;
1256         VALUE_PAIR *vp;
1257         FILE *fp;
1258         RAD_REQUEST_FUNP fun = NULL;
1259         char buffer[2048];
1260
1261         if (argc < 2) {
1262                 cprintf(listener, "ERROR: You must specify <input-file> <output-file>\n");
1263                 return 0;
1264         }
1265
1266         if (!sock->inject_listener) {
1267                 cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject file\"\n");
1268                 return 0;
1269         }
1270
1271         if (!sock->inject_client) {
1272                 cprintf(listener, "ERROR: You must specify \"inject from\" before using \"inject file\"\n");
1273                 return 0;
1274         }
1275
1276         /*
1277          *      Output files always go to the logging directory.
1278          */
1279         snprintf(buffer, sizeof(buffer), "%s/%s", radlog_dir, argv[1]);
1280
1281         fp = fopen(argv[0], "r");
1282         if (!fp ) {
1283                 cprintf(listener, "ERROR: Failed opening %s: %s\n",
1284                         argv[0], fr_syserror(errno));
1285                 return 0;
1286         }
1287
1288         ret = readvp2(&vp, NULL, fp, &filedone);
1289         fclose(fp);
1290         if (ret < 0) {
1291                 cprintf(listener, "ERROR: Failed reading attributes from %s: %s\n",
1292                         argv[0], fr_strerror());
1293                 return 0;
1294         }
1295
1296         fake = talloc(NULL, rad_listen_t);
1297         memcpy(fake, sock->inject_listener, sizeof(*fake));
1298
1299         /*
1300          *      Re-write the IO for the listener.
1301          */
1302         fake->encode = null_socket_dencode;
1303         fake->decode = null_socket_dencode;
1304         fake->send = null_socket_send;
1305
1306         packet = rad_alloc(NULL, false);
1307         packet->src_ipaddr = sock->src_ipaddr;
1308         packet->src_port = 0;
1309
1310         packet->dst_ipaddr = sock->dst_ipaddr;
1311         packet->dst_port = sock->dst_port;
1312         packet->vps = vp;
1313         packet->id = inject_id++;
1314
1315         if (fake->type == RAD_LISTEN_AUTH) {
1316                 packet->code = PW_CODE_ACCESS_REQUEST;
1317                 fun = rad_authenticate;
1318
1319         } else {
1320 #ifdef WITH_ACCOUNTING
1321                 packet->code = PW_CODE_ACCOUNTING_REQUEST;
1322                 fun = rad_accounting;
1323 #else
1324                 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1325                 rad_free(&packet);
1326                 free(fake);
1327                 return 0;
1328 #endif
1329         }
1330
1331         if (debug_flag) {
1332                 DEBUG("Injecting %s packet from host %s port 0 code=%d, id=%d",
1333                                 fr_packet_codes[packet->code],
1334                                 inet_ntop(packet->src_ipaddr.af,
1335                                           &packet->src_ipaddr.ipaddr,
1336                                           buffer, sizeof(buffer)),
1337                                 packet->code, packet->id);
1338
1339                 for (vp = fr_cursor_init(&cursor, &packet->vps);
1340                      vp;
1341                      vp = fr_cursor_next(&cursor)) {
1342                         vp_prints(buffer, sizeof(buffer), vp);
1343                         DEBUG("\t%s", buffer);
1344                 }
1345
1346                 WARN("INJECTION IS LEAKING MEMORY!");
1347         }
1348
1349         if (!request_receive(fake, packet, sock->inject_client, fun)) {
1350                 cprintf(listener, "ERROR: Failed to inject request.  See log file for details\n");
1351                 rad_free(&packet);
1352                 free(fake);
1353                 return 0;
1354         }
1355
1356 #if 0
1357         /*
1358          *      Remember what the output file is, and remember to
1359          *      delete the fake listener when done.
1360          */
1361         request_data_add(request, null_socket_send, 0, talloc_typed_strdup(NULL, buffer), true);
1362         request_data_add(request, null_socket_send, 1, fake, true);
1363
1364 #endif
1365
1366         return 1;
1367 }
1368
1369
1370 static fr_command_table_t command_table_inject[] = {
1371         { "to", FR_WRITE,
1372           "inject to <ipaddr> <port> - Inject packets to the destination IP and port.",
1373           command_inject_to, NULL },
1374
1375         { "from", FR_WRITE,
1376           "inject from <ipaddr> - Inject packets as if they came from <ipaddr>",
1377           command_inject_from, NULL },
1378
1379         { "file", FR_WRITE,
1380           "inject file <input-file> <output-file> - Inject packet from input-file>, with results sent to <output-file>",
1381           command_inject_file, NULL },
1382
1383         { NULL, 0, NULL, NULL, NULL }
1384 };
1385
1386 static fr_command_table_t command_table_debug[] = {
1387         { "condition", FR_WRITE,
1388           "debug condition [condition] - Enable debugging for requests matching [condition]",
1389           command_debug_condition, NULL },
1390
1391         { "level", FR_WRITE,
1392           "debug level <number> - Set debug level to <number>.  Higher is more debugging.",
1393           command_debug_level, NULL },
1394
1395         { "file", FR_WRITE,
1396           "debug file [filename] - Send all debugging output to [filename]",
1397           command_debug_file, NULL },
1398
1399         { NULL, 0, NULL, NULL, NULL }
1400 };
1401
1402 static fr_command_table_t command_table_show_debug[] = {
1403         { "condition", FR_READ,
1404           "show debug condition - Shows current debugging condition.",
1405           command_show_debug_condition, NULL },
1406
1407         { "level", FR_READ,
1408           "show debug level - Shows current debugging level.",
1409           command_show_debug_level, NULL },
1410
1411         { "file", FR_READ,
1412           "show debug file - Shows current debugging file.",
1413           command_show_debug_file, NULL },
1414
1415         { NULL, 0, NULL, NULL, NULL }
1416 };
1417
1418 static fr_command_table_t command_table_show_module[] = {
1419         { "config", FR_READ,
1420           "show module config <module> - show configuration for given module",
1421           command_show_module_config, NULL },
1422         { "flags", FR_READ,
1423           "show module flags <module> - show other module properties",
1424           command_show_module_flags, NULL },
1425         { "list", FR_READ,
1426           "show module list - shows list of loaded modules",
1427           command_show_modules, NULL },
1428         { "methods", FR_READ,
1429           "show module methods <module> - show sections where <module> may be used",
1430           command_show_module_methods, NULL },
1431         { "status", FR_READ,
1432           "show module status <module> - show the module status",
1433           command_show_module_status, NULL },
1434
1435         { NULL, 0, NULL, NULL, NULL }
1436 };
1437
1438 static fr_command_table_t command_table_show_client[] = {
1439         { "list", FR_READ,
1440           "show client list - shows list of global clients",
1441           command_show_clients, NULL },
1442
1443         { NULL, 0, NULL, NULL, NULL }
1444 };
1445
1446 #ifdef WITH_PROXY
1447 static fr_command_table_t command_table_show_home[] = {
1448         { "list", FR_READ,
1449           "show home_server list - shows list of home servers",
1450           command_show_home_servers, NULL },
1451         { "state", FR_READ,
1452           "show home_server state <ipaddr> <port> [proto] - shows state of given home server",
1453           command_show_home_server_state, NULL },
1454
1455         { NULL, 0, NULL, NULL, NULL }
1456 };
1457 #endif
1458
1459
1460 static fr_command_table_t command_table_show[] = {
1461         { "client", FR_READ,
1462           "show client <command> - do sub-command of client",
1463           NULL, command_table_show_client },
1464         { "config", FR_READ,
1465           "show config <path> - shows the value of configuration option <path>",
1466           command_show_config, NULL },
1467         { "debug", FR_READ,
1468           "show debug <command> - show debug properties",
1469           NULL, command_table_show_debug },
1470 #ifdef WITH_PROXY
1471         { "home_server", FR_READ,
1472           "show home_server <command> - do sub-command of home_server",
1473           NULL, command_table_show_home },
1474 #endif
1475         { "module", FR_READ,
1476           "show module <command> - do sub-command of module",
1477           NULL, command_table_show_module },
1478         { "uptime", FR_READ,
1479           "show uptime - shows time at which server started",
1480           command_uptime, NULL },
1481         { "version", FR_READ,
1482           "show version - Prints version of the running server",
1483           command_show_version, NULL },
1484         { NULL, 0, NULL, NULL, NULL }
1485 };
1486
1487
1488 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
1489 {
1490         int i, rcode;
1491         CONF_PAIR *cp;
1492         CONF_SECTION *cs;
1493         module_instance_t *mi;
1494         CONF_PARSER const *variables;
1495         void *data;
1496
1497         if (argc < 3) {
1498                 cprintf(listener, "ERROR: No module name or variable was given\n");
1499                 return 0;
1500         }
1501
1502         cs = cf_section_find("modules");
1503         if (!cs) return 0;
1504
1505         mi = find_module_instance(cs, argv[0], 0);
1506         if (!mi) {
1507                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1508                 return 0;
1509         }
1510
1511         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
1512                 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
1513                 return 0;
1514         }
1515
1516         variables = cf_section_parse_table(mi->cs);
1517         if (!variables) {
1518                 cprintf(listener, "ERROR: Cannot find configuration for module\n");
1519                 return 0;
1520         }
1521
1522         rcode = -1;
1523         for (i = 0; variables[i].name != NULL; i++) {
1524                 /*
1525                  *      FIXME: Recurse into sub-types somehow...
1526                  */
1527                 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
1528
1529                 if (strcmp(variables[i].name, argv[1]) == 0) {
1530                         rcode = i;
1531                         break;
1532                 }
1533         }
1534
1535         if (rcode < 0) {
1536                 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
1537                 return 0;
1538         }
1539
1540         i = rcode;              /* just to be safe */
1541
1542         /*
1543          *      It's not part of the dynamic configuration.  The module
1544          *      needs to re-parse && validate things.
1545          */
1546         if (variables[i].data) {
1547                 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
1548                 return 0;
1549         }
1550
1551         data = ((char *) mi->insthandle) + variables[i].offset;
1552
1553         cp = cf_pair_find(mi->cs, argv[1]);
1554         if (!cp) return 0;
1555
1556         /*
1557          *      Replace the OLD value in the configuration file with
1558          *      the NEW value.
1559          *
1560          *      FIXME: Parse argv[2] depending on it's data type!
1561          *      If it's a string, look for leading single/double quotes,
1562          *      end then call tokenize functions???
1563          */
1564         cf_pair_replace(mi->cs, cp, argv[2]);
1565
1566         rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, data, argv[2]);
1567         if (rcode < 0) {
1568                 cprintf(listener, "ERROR: Failed to parse value\n");
1569                 return 0;
1570         }
1571
1572         return 1;               /* success */
1573 }
1574
1575 static int command_set_module_status(rad_listen_t *listener, int argc, char *argv[])
1576 {
1577         CONF_SECTION *cs;
1578         module_instance_t *mi;
1579
1580         if (argc < 2) {
1581                 cprintf(listener, "ERROR: No module name or status was given\n");
1582                 return 0;
1583         }
1584
1585         cs = cf_section_find("modules");
1586         if (!cs) return 0;
1587
1588         mi = find_module_instance(cs, argv[0], 0);
1589         if (!mi) {
1590                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1591                 return 0;
1592         }
1593
1594
1595         if (strcmp(argv[1], "alive") == 0) {
1596                 mi->force = false;
1597
1598         } else if (strcmp(argv[1], "dead") == 0) {
1599                 mi->code = RLM_MODULE_FAIL;
1600                 mi->force = true;
1601
1602         } else {
1603                 int rcode;
1604
1605                 rcode = fr_str2int(mod_rcode_table, argv[1], -1);
1606                 if (rcode < 0) {
1607                         cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[1]);
1608                         return 0;
1609                 }
1610
1611                 mi->code = rcode;
1612                 mi->force = true;
1613         }
1614
1615         return 1;               /* success */
1616 }
1617
1618 #ifdef WITH_STATS
1619 static char const *elapsed_names[8] = {
1620         "1us", "10us", "100us", "1ms", "10ms", "100ms", "1s", "10s"
1621 };
1622
1623 #undef PU
1624 #ifdef WITH_STATS_64BIT
1625 #ifdef PRIu64
1626 #define PU "%" PRIu64
1627 #else
1628 #define PU "%lu"
1629 #endif
1630 #else
1631 #ifdef PRIu32
1632 #define PU "%" PRIu32
1633 #else
1634 #define PU "%u"
1635 #endif
1636 #endif
1637
1638 static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
1639                                int auth, int server)
1640 {
1641         int i;
1642
1643         cprintf(listener, "\trequests\t" PU "\n", stats->total_requests);
1644         cprintf(listener, "\tresponses\t" PU "\n", stats->total_responses);
1645
1646         if (auth) {
1647                 cprintf(listener, "\taccepts\t\t" PU "\n",
1648                         stats->total_access_accepts);
1649                 cprintf(listener, "\trejects\t\t" PU "\n",
1650                         stats->total_access_rejects);
1651                 cprintf(listener, "\tchallenges\t" PU "\n",
1652                         stats->total_access_challenges);
1653         }
1654
1655         cprintf(listener, "\tdup\t\t" PU "\n", stats->total_dup_requests);
1656         cprintf(listener, "\tinvalid\t\t" PU "\n", stats->total_invalid_requests);
1657         cprintf(listener, "\tmalformed\t" PU "\n", stats->total_malformed_requests);
1658         cprintf(listener, "\tbad_authenticator\t" PU "\n", stats->total_bad_authenticators);
1659         cprintf(listener, "\tdropped\t\t" PU "\n", stats->total_packets_dropped);
1660         cprintf(listener, "\tunknown_types\t" PU "\n", stats->total_unknown_types);
1661
1662         if (server) {
1663                 cprintf(listener, "\ttimeouts\t" PU "\n", stats->total_timeouts);
1664         }
1665
1666         cprintf(listener, "\tlast_packet\t%" PRId64 "\n", (int64_t) stats->last_packet);
1667         for (i = 0; i < 8; i++) {
1668                 cprintf(listener, "\telapsed.%s\t%u\n",
1669                         elapsed_names[i], stats->elapsed[i]);
1670         }
1671
1672         return 1;
1673 }
1674
1675 #ifdef WITH_DETAIL
1676 static FR_NAME_NUMBER state_names[] = {
1677         { "unopened", STATE_UNOPENED },
1678         { "unlocked", STATE_UNLOCKED },
1679         { "header", STATE_HEADER },
1680         { "reading", STATE_READING },
1681         { "queued", STATE_QUEUED },
1682         { "running", STATE_RUNNING },
1683         { "no-reply", STATE_NO_REPLY },
1684         { "replied", STATE_REPLIED },
1685
1686         { NULL, 0 }
1687 };
1688
1689 static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
1690 {
1691         rad_listen_t *this;
1692         listen_detail_t *data;
1693         struct stat buf;
1694
1695         if (argc == 0) {
1696                 cprintf(listener, "ERROR: Must specify <filename>\n");
1697                 return 0;
1698         }
1699
1700         data = NULL;
1701         for (this = main_config.listen; this != NULL; this = this->next) {
1702                 if (this->type != RAD_LISTEN_DETAIL) continue;
1703
1704                 data = this->data;
1705                 if (strcmp(argv[1], data->filename) != 0) continue;
1706
1707                 break;
1708         }
1709
1710         if (!data) {
1711                 cprintf(listener, "ERROR: No detail file listener\n");
1712                 return 0;
1713         }
1714
1715         cprintf(listener, "\tstate\t%s\n",
1716                 fr_int2str(state_names, data->state, "?"));
1717
1718         if ((data->state == STATE_UNOPENED) ||
1719             (data->state == STATE_UNLOCKED)) {
1720                 return 1;
1721         }
1722
1723         /*
1724          *      Race conditions: file might not exist.
1725          */
1726         if (stat(data->filename_work, &buf) < 0) {
1727                 cprintf(listener, "packets\t0\n");
1728                 cprintf(listener, "tries\t0\n");
1729                 cprintf(listener, "offset\t0\n");
1730                 cprintf(listener, "size\t0\n");
1731                 return 1;
1732         }
1733
1734         cprintf(listener, "packets\t%d\n", data->packets);
1735         cprintf(listener, "tries\t%d\n", data->tries);
1736         cprintf(listener, "offset\t%u\n", (unsigned int) data->offset);
1737         cprintf(listener, "size\t%u\n", (unsigned int) buf.st_size);
1738
1739         return 1;
1740 }
1741 #endif
1742
1743 #ifdef WITH_PROXY
1744 static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
1745 {
1746         home_server_t *home;
1747
1748         if (argc == 0) {
1749                 cprintf(listener, "ERROR: Must specify [auth/acct] OR <ipaddr> <port>\n");
1750                 return 0;
1751         }
1752
1753         if (argc == 1) {
1754 #ifdef WITH_ACCOUNTING
1755                 if (strcmp(argv[0], "acct") == 0) {
1756                         return command_print_stats(listener,
1757                                                    &proxy_acct_stats, 0, 1);
1758                 }
1759 #endif
1760                 if (strcmp(argv[0], "auth") == 0) {
1761                         return command_print_stats(listener,
1762                                                    &proxy_auth_stats, 1, 1);
1763                 }
1764
1765                 cprintf(listener, "ERROR: Should specify [auth/acct]\n");
1766                 return 0;
1767         }
1768
1769         home = get_home_server(listener, argc, argv, NULL);
1770         if (!home) {
1771                 return 0;
1772         }
1773
1774         command_print_stats(listener, &home->stats,
1775                             (home->type == HOME_TYPE_AUTH), 1);
1776         cprintf(listener, "\toutstanding\t%d\n", home->currently_outstanding);
1777         return 1;
1778 }
1779 #endif
1780
1781 static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
1782 {
1783         bool auth = true;
1784         fr_stats_t *stats;
1785         RADCLIENT *client, fake;
1786
1787         if (argc < 1) {
1788                 cprintf(listener, "ERROR: Must specify [auth/acct]\n");
1789                 return 0;
1790         }
1791
1792         if (argc == 1) {
1793                 /*
1794                  *      Global statistics.
1795                  */
1796                 fake.auth = radius_auth_stats;
1797 #ifdef WITH_ACCOUNTING
1798                 fake.auth = radius_acct_stats;
1799 #endif
1800 #ifdef WITH_COA
1801                 fake.coa = radius_coa_stats;
1802                 fake.dsc = radius_dsc_stats;
1803 #endif
1804                 client = &fake;
1805
1806         } else {
1807                 /*
1808                  *      Per-client statistics.
1809                  */
1810                 client = get_client(listener, argc - 1, argv + 1);
1811                 if (!client) {
1812                         return 0;
1813                 }
1814         }
1815
1816         if (strcmp(argv[0], "auth") == 0) {
1817                 auth = true;
1818                 stats = &client->auth;
1819
1820         } else if (strcmp(argv[0], "acct") == 0) {
1821 #ifdef WITH_ACCOUNTING
1822                 auth = false;
1823                 stats = &client->acct;
1824 #else
1825                 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1826                 return 0;
1827 #endif
1828
1829         } else if (strcmp(argv[0], "coa") == 0) {
1830 #ifdef WITH_COA
1831                 auth = false;
1832                 stats = &client->coa;
1833 #else
1834                 cprintf(listener, "ERROR: This server was built without CoA support.\n");
1835                 return 0;
1836 #endif
1837
1838         } else if (strcmp(argv[0], "disconnect") == 0) {
1839 #ifdef WITH_COA
1840                 auth = false;
1841                 stats = &client->dsc;
1842 #else
1843                 cprintf(listener, "ERROR: This server was built without CoA support.\n");
1844                 return 0;
1845 #endif
1846
1847         } else {
1848                 cprintf(listener, "ERROR: Unknown statistics type\n");
1849                 return 0;
1850         }
1851
1852         /*
1853          *      Global results for all client.
1854          */
1855         if (argc == 1) {
1856 #ifdef WITH_ACCOUNTING
1857                 if (!auth) {
1858                         return command_print_stats(listener,
1859                                                    &radius_acct_stats, auth, 0);
1860                 }
1861 #endif
1862                 return command_print_stats(listener, &radius_auth_stats, auth, 0);
1863         }
1864
1865         return command_print_stats(listener, stats, auth, 0);
1866 }
1867
1868
1869 static int command_stats_socket(rad_listen_t *listener, int argc, char *argv[])
1870 {
1871         bool auth = true;
1872         rad_listen_t *sock;
1873
1874         sock = get_socket(listener, argc, argv, NULL);
1875         if (!sock) {
1876                 return 0;
1877         }
1878
1879         if (sock->type != RAD_LISTEN_AUTH) auth = false;
1880
1881         return command_print_stats(listener, &sock->stats, auth, 0);
1882 }
1883 #endif  /* WITH_STATS */
1884
1885
1886 #ifdef WITH_DYNAMIC_CLIENTS
1887 static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
1888 {
1889         RADCLIENT *c;
1890
1891         if (argc < 1) {
1892                 cprintf(listener, "ERROR: <file> is required\n");
1893                 return 0;
1894         }
1895
1896         /*
1897          *      Read the file and generate the client.
1898          */
1899         c = client_read(argv[0], false, false);
1900         if (!c) {
1901                 cprintf(listener, "ERROR: Unknown error reading client file.\n");
1902                 return 0;
1903         }
1904
1905         if (!client_add(NULL, c)) {
1906                 cprintf(listener, "ERROR: Unknown error inserting new client.\n");
1907                 client_free(c);
1908                 return 0;
1909         }
1910
1911         return 1;
1912 }
1913
1914
1915 static int command_del_client(rad_listen_t *listener, int argc, char *argv[])
1916 {
1917         RADCLIENT *client;
1918
1919         client = get_client(listener, argc, argv);
1920         if (!client) return 0;
1921
1922         if (!client->dynamic) {
1923                 cprintf(listener, "ERROR: Client %s was not dynamically defined.\n", argv[0]);
1924                 return 0;
1925         }
1926
1927         /*
1928          *      DON'T delete it.  Instead, mark it as "dead now".  The
1929          *      next time we receive a packet for the client, it will
1930          *      be deleted.
1931          *
1932          *      If we don't receive a packet from it, the client
1933          *      structure will stick around for a while.  Oh well...
1934          */
1935         client->lifetime = 1;
1936
1937         return 1;
1938 }
1939
1940
1941 static fr_command_table_t command_table_del_client[] = {
1942         { "ipaddr", FR_WRITE,
1943           "del client ipaddr <ipaddr> - Delete a dynamically created client",
1944           command_del_client, NULL },
1945
1946         { NULL, 0, NULL, NULL, NULL }
1947 };
1948
1949
1950 static fr_command_table_t command_table_del[] = {
1951         { "client", FR_WRITE,
1952           "del client <command> - Delete client configuration commands",
1953           NULL, command_table_del_client },
1954
1955         { NULL, 0, NULL, NULL, NULL }
1956 };
1957
1958
1959 static fr_command_table_t command_table_add_client[] = {
1960         { "file", FR_WRITE,
1961           "add client file <filename> - Add new client definition from <filename>",
1962           command_add_client_file, NULL },
1963
1964         { NULL, 0, NULL, NULL, NULL }
1965 };
1966
1967
1968 static fr_command_table_t command_table_add[] = {
1969         { "client", FR_WRITE,
1970           "add client <command> - Add client configuration commands",
1971           NULL, command_table_add_client },
1972
1973         { NULL, 0, NULL, NULL, NULL }
1974 };
1975 #endif
1976
1977 #ifdef WITH_PROXY
1978 static fr_command_table_t command_table_set_home[] = {
1979         { "state", FR_WRITE,
1980           "set home_server state <ipaddr> <port> [proto] [alive|dead] - set state for given home server",
1981           command_set_home_server_state, NULL },
1982
1983         { NULL, 0, NULL, NULL, NULL }
1984 };
1985 #endif
1986
1987 static fr_command_table_t command_table_set_module[] = {
1988         { "config", FR_WRITE,
1989           "set module config <module> variable value - set configuration for <module>",
1990           command_set_module_config, NULL },
1991
1992         { "status", FR_WRITE,
1993           "set module status <module> [alive|...] - set the module status to be alive (operating normally), or force a particular code (ok,fail, etc.)",
1994           command_set_module_status, NULL },
1995
1996         { NULL, 0, NULL, NULL, NULL }
1997 };
1998
1999
2000 static fr_command_table_t command_table_set[] = {
2001         { "module", FR_WRITE,
2002           "set module <command> - set module commands",
2003           NULL, command_table_set_module },
2004 #ifdef WITH_PROXY
2005         { "home_server", FR_WRITE,
2006           "set home_server <command> - set home server commands",
2007           NULL, command_table_set_home },
2008 #endif
2009
2010         { NULL, 0, NULL, NULL, NULL }
2011 };
2012
2013
2014 #ifdef WITH_STATS
2015 static fr_command_table_t command_table_stats[] = {
2016         { "client", FR_READ,
2017           "stats client [auth/acct] <ipaddr> "
2018 #ifdef WITH_TCP
2019           "[proto] "
2020 #endif
2021           "- show statistics for given client, or for all clients (auth or acct)",
2022           command_stats_client, NULL },
2023
2024 #ifdef WITH_DETAIL
2025         { "detail", FR_READ,
2026           "stats detail <filename> - show statistics for the given detail file",
2027           command_stats_detail, NULL },
2028 #endif
2029
2030 #ifdef WITH_PROXY
2031         { "home_server", FR_READ,
2032           "stats home_server [<ipaddr>/auth/acct] <port> - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
2033           command_stats_home_server, NULL },
2034 #endif
2035
2036         { "socket", FR_READ,
2037           "stats socket <ipaddr> <port> "
2038 #ifdef WITH_TCP
2039           "[proto] "
2040 #endif
2041           "- show statistics for given socket",
2042           command_stats_socket, NULL },
2043
2044         { NULL, 0, NULL, NULL, NULL }
2045 };
2046 #endif
2047
2048 static fr_command_table_t command_table[] = {
2049 #ifdef WITH_DYNAMIC_CLIENTS
2050         { "add", FR_WRITE, NULL, NULL, command_table_add },
2051 #endif
2052         { "debug", FR_WRITE,
2053           "debug <command> - debugging commands",
2054           NULL, command_table_debug },
2055 #ifdef WITH_DYNAMIC_CLIENTS
2056         { "del", FR_WRITE, NULL, NULL, command_table_del },
2057 #endif
2058         { "hup", FR_WRITE,
2059           "hup [module] - sends a HUP signal to the server, or optionally to one module",
2060           command_hup, NULL },
2061         { "inject", FR_WRITE,
2062           "inject <command> - commands to inject packets into a running server",
2063           NULL, command_table_inject },
2064         { "reconnect", FR_READ,
2065           "reconnect - reconnect to a running server",
2066           NULL, NULL },         /* just here for "help" */
2067         { "terminate", FR_WRITE,
2068           "terminate - terminates the server, and cause it to exit",
2069           command_terminate, NULL },
2070         { "set", FR_WRITE, NULL, NULL, command_table_set },
2071         { "show",  FR_READ, NULL, NULL, command_table_show },
2072 #ifdef WITH_STATS
2073         { "stats",  FR_READ, NULL, NULL, command_table_stats },
2074 #endif
2075
2076         { NULL, 0, NULL, NULL, NULL }
2077 };
2078
2079
2080 static void command_socket_free(rad_listen_t *this)
2081 {
2082         fr_command_socket_t *cmd = this->data;
2083
2084         /*
2085          *      If it's a TCP socket, don't do anything.
2086          */
2087         if (cmd->magic != COMMAND_SOCKET_MAGIC) {
2088                 return;
2089         }
2090
2091         if (!cmd->copy) return;
2092         unlink(cmd->copy);
2093 }
2094
2095
2096 /*
2097  *      Parse the unix domain sockets.
2098  *
2099  *      FIXME: TCP + SSL, after RadSec is in.
2100  */
2101 static int command_socket_parse_unix(CONF_SECTION *cs, rad_listen_t *this)
2102 {
2103         fr_command_socket_t *sock;
2104
2105         if (check_config) return 0;
2106
2107         sock = this->data;
2108
2109         if (cf_section_parse(cs, sock, command_config) < 0) {
2110                 return -1;
2111         }
2112
2113         sock->magic = COMMAND_SOCKET_MAGIC;
2114         sock->copy = NULL;
2115         if (sock->path) sock->copy = talloc_typed_strdup(sock, sock->path);
2116
2117 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2118         if (sock->uid_name) {
2119                 struct passwd *pw;
2120
2121                 pw = getpwnam(sock->uid_name);
2122                 if (!pw) {
2123                         ERROR("Failed getting uid for %s: %s",
2124                                sock->uid_name, fr_syserror(errno));
2125                         return -1;
2126                 }
2127
2128                 sock->uid = pw->pw_uid;
2129         } else {
2130                 sock->uid = -1;
2131         }
2132
2133         if (sock->gid_name) {
2134                 struct group *gr;
2135
2136                 gr = getgrnam(sock->gid_name);
2137                 if (!gr) {
2138                         ERROR("Failed getting gid for %s: %s",
2139                                sock->gid_name, fr_syserror(errno));
2140                         return -1;
2141                 }
2142                 sock->gid = gr->gr_gid;
2143         } else {
2144                 sock->gid = -1;
2145         }
2146
2147 #else  /* can't get uid or gid of connecting user */
2148
2149         if (sock->uid_name || sock->gid_name) {
2150                 ERROR("System does not support uid or gid authentication for sockets");
2151                 return -1;
2152         }
2153
2154 #endif
2155
2156         if (!sock->mode_name) {
2157                 sock->co.mode = FR_READ;
2158         } else {
2159                 sock->co.mode = fr_str2int(mode_names, sock->mode_name, 0);
2160                 if (!sock->co.mode) {
2161                         ERROR("Invalid mode name \"%s\"",
2162                                sock->mode_name);
2163                         return -1;
2164                 }
2165         }
2166
2167         /*
2168          *      FIXME: check for absolute pathnames?
2169          *      check for uid/gid on the other end...
2170          */
2171
2172         this->fd = fr_server_domain_socket(sock->path);
2173         if (this->fd < 0) {
2174                 return -1;
2175         }
2176
2177 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2178         /*
2179          *      Don't chown it from (possibly) non-root to root.
2180          *      Do chown it from (possibly) root to non-root.
2181          */
2182         if ((sock->uid != (uid_t) -1) || (sock->gid != (gid_t) -1)) {
2183                 fr_suid_up();
2184                 if (fchown(this->fd, sock->uid, sock->gid) < 0) {
2185                         ERROR("Failed setting ownership of %s: %s",
2186                                sock->path, fr_syserror(errno));
2187                         fr_suid_down();
2188                         return -1;
2189                 }
2190                 fr_suid_down();
2191         }
2192 #endif
2193
2194         return 0;
2195 }
2196
2197 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
2198 {
2199         int rcode;
2200         CONF_PAIR const *cp;
2201         listen_socket_t *sock;
2202
2203         cp = cf_pair_find(cs, "socket");
2204         if (cp) return command_socket_parse_unix(cs, this);
2205
2206         rcode = common_socket_parse(cs, this);
2207         if (rcode < 0) return -1;
2208
2209 #ifdef WITH_TLS
2210         if (this->tls) {
2211                 cf_log_err_cs(cs,
2212                            "TLS is not supported for control sockets");
2213                 return -1;
2214         }
2215 #endif
2216
2217         sock = this->data;
2218         if (sock->proto != IPPROTO_TCP) {
2219                 cf_log_err_cs(cs,
2220                            "UDP is not supported for control sockets");
2221                 return -1;
2222         }
2223
2224         return 0;
2225 }
2226
2227 static int command_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
2228 {
2229         fr_command_socket_t *sock = this->data;
2230
2231         if (sock->magic != COMMAND_SOCKET_MAGIC) {
2232                 return common_socket_print(this, buffer, bufsize);
2233         }
2234
2235         snprintf(buffer, bufsize, "command file %s", sock->path);
2236         return 1;
2237 }
2238
2239
2240 /*
2241  *      String split routine.  Splits an input string IN PLACE
2242  *      into pieces, based on spaces.
2243  */
2244 static int str2argvX(char *str, char **argv, int max_argc)
2245 {
2246         int argc = 0;
2247
2248         while (*str) {
2249                 if (argc >= max_argc) return argc;
2250
2251                 /*
2252                  *      Chop out comments early.
2253                  */
2254                 if (*str == '#') {
2255                         *str = '\0';
2256                         break;
2257                 }
2258
2259                 while ((*str == ' ') ||
2260                        (*str == '\t') ||
2261                        (*str == '\r') ||
2262                        (*str == '\n')) *(str++) = '\0';
2263
2264                 if (!*str) return argc;
2265
2266                 argv[argc++] = str;
2267
2268                 if ((*str == '\'') || (*str == '"')) {
2269                         char quote = *str;
2270                         char *p = str + 1;
2271
2272                         while (true) {
2273                                 if (!*p) return -1;
2274
2275                                 if (*p == quote) {
2276                                         str = p + 1;
2277                                         break;
2278                                 }
2279
2280                                 /*
2281                                  *      Handle \" and nothing else.
2282                                  */
2283                                 if (*p == '\\') {
2284                                         p += 2;
2285                                         continue;
2286                                 }
2287
2288                                 p++;
2289                         }
2290                 }
2291
2292                 while (*str &&
2293                        (*str != ' ') &&
2294                        (*str != '\t') &&
2295                        (*str != '\r') &&
2296                        (*str != '\n')) str++;
2297         }
2298
2299         return argc;
2300 }
2301
2302 static void print_help(rad_listen_t *listener,
2303                        fr_command_table_t *table, int recursive)
2304 {
2305         int i;
2306
2307         for (i = 0; table[i].command != NULL; i++) {
2308                 if (table[i].help) {
2309                         cprintf(listener, "%s\n",
2310                                 table[i].help);
2311                 } else {
2312                         cprintf(listener, "%s <command> - do sub-command of %s\n",
2313                                 table[i].command, table[i].command);
2314                 }
2315
2316                 if (recursive && table[i].table) {
2317                         print_help(listener, table[i].table, recursive);
2318                 }
2319         }
2320 }
2321
2322 #define MAX_ARGV (16)
2323
2324 /*
2325  *      Check if an incoming request is "ok"
2326  *
2327  *      It takes packets, not requests.  It sees if the packet looks
2328  *      OK.  If so, it does a number of sanity checks on it.
2329  */
2330 static int command_domain_recv_co(rad_listen_t *listener, fr_cs_buffer_t *co)
2331 {
2332         int i, rcode;
2333         ssize_t len;
2334         int argc;
2335         char *my_argv[MAX_ARGV], **argv;
2336         fr_command_table_t *table;
2337
2338         do {
2339                 ssize_t c;
2340                 char *p;
2341
2342                 len = recv(listener->fd, co->buffer + co->offset,
2343                            sizeof(co->buffer) - co->offset - 1, 0);
2344                 if (len == 0) goto close_socket; /* clean close */
2345
2346                 if (len < 0) {
2347                         if ((errno == EAGAIN) || (errno == EINTR)) {
2348                                 return 0;
2349                         }
2350                         goto close_socket;
2351                 }
2352
2353                 /*
2354                  *      CTRL-D
2355                  */
2356                 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
2357                 close_socket:
2358                         command_close_socket(listener);
2359                         return 0;
2360                 }
2361
2362                 /*
2363                  *      See if there are multiple lines in the buffer.
2364                  */
2365                 p = co->buffer + co->offset;
2366                 rcode = 0;
2367                 p[len] = '\0';
2368                 for (c = 0; c < len; c++) {
2369                         if ((*p == '\r') || (*p == '\n')) {
2370                                 rcode = 1;
2371                                 *p = '\0';
2372
2373                                 /*
2374                                  *      FIXME: do real buffering...
2375                                  *      handling of CTRL-C, etc.
2376                                  */
2377
2378                         } else if (rcode) {
2379                                 /*
2380                                  *      \r \n followed by ASCII...
2381                                  */
2382                                 break;
2383                         }
2384
2385                         p++;
2386                 }
2387
2388                 co->offset += len;
2389
2390                 /*
2391                  *      Saw CR/LF.  Set next element, and exit.
2392                  */
2393                 if (rcode) {
2394                         co->next = p - co->buffer;
2395                         break;
2396                 }
2397
2398                 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
2399                         ERROR("Line too long!");
2400                         goto close_socket;
2401                 }
2402
2403                 co->offset++;
2404         } while (1);
2405
2406         DEBUG("radmin> %s", co->buffer);
2407
2408         argc = str2argvX(co->buffer, my_argv, MAX_ARGV);
2409         if (argc == 0) goto do_next; /* empty strings are OK */
2410
2411         if (argc < 0) {
2412                 cprintf(listener, "ERROR: Failed parsing command.\n");
2413                 goto do_next;
2414         }
2415
2416         argv = my_argv;
2417
2418         for (len = 0; len <= co->offset; len++) {
2419                 if (co->buffer[len] < 0x20) {
2420                         co->buffer[len] = '\0';
2421                         break;
2422                 }
2423         }
2424
2425         /*
2426          *      Hard-code exit && quit.
2427          */
2428         if ((strcmp(argv[0], "exit") == 0) ||
2429             (strcmp(argv[0], "quit") == 0)) goto close_socket;
2430
2431         table = command_table;
2432  retry:
2433         len = 0;
2434         for (i = 0; table[i].command != NULL; i++) {
2435                 if (strcmp(table[i].command, argv[0]) == 0) {
2436                         /*
2437                          *      Check permissions.
2438                          */
2439                         if (((co->mode & FR_WRITE) == 0) &&
2440                             ((table[i].mode & FR_WRITE) != 0)) {
2441                                 cprintf(listener, "ERROR: You do not have write permission.  See \"mode = rw\" in the \"listen\" section for this socket.\n");
2442                                 goto do_next;
2443                         }
2444
2445                         if (table[i].table) {
2446                                 /*
2447                                  *      This is the last argument, but
2448                                  *      there's a sub-table.  Print help.
2449                                  *
2450                                  */
2451                                 if (argc == 1) {
2452                                         table = table[i].table;
2453                                         goto do_help;
2454                                 }
2455
2456                                 argc--;
2457                                 argv++;
2458                                 table = table[i].table;
2459                                 goto retry;
2460                         }
2461
2462                         if ((argc == 2) && (strcmp(argv[1], "?") == 0)) goto do_help;
2463
2464                         if (!table[i].func) {
2465                                 cprintf(listener, "ERROR: Invalid command\n");
2466                                 goto do_next;
2467                         }
2468
2469                         len = 1;
2470                         table[i].func(listener, argc - 1, argv + 1);
2471                         break;
2472                 }
2473         }
2474
2475         /*
2476          *      No such command
2477          */
2478         if (!len) {
2479                 if ((strcmp(argv[0], "help") == 0) ||
2480                     (strcmp(argv[0], "?") == 0)) {
2481                         int recursive;
2482
2483                 do_help:
2484                         if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
2485                                 recursive = true;
2486                         } else {
2487                                 recursive = false;
2488                         }
2489
2490                         print_help(listener, table, recursive);
2491                         goto do_next;
2492                 }
2493
2494                 cprintf(listener, "ERROR: Unknown command \"%s\"\n",
2495                         argv[0]);
2496         }
2497
2498  do_next:
2499         cprintf(listener, "radmin> ");
2500
2501         if (co->next <= co->offset) {
2502                 co->offset = 0;
2503         } else {
2504                 memmove(co->buffer, co->buffer + co->next,
2505                         co->offset - co->next);
2506                 co->offset -= co->next;
2507         }
2508
2509         return 0;
2510 }
2511
2512
2513 /*
2514  *      Write 32-bit magic number && version information.
2515  */
2516 static int command_write_magic(int newfd, listen_socket_t *sock)
2517 {
2518         uint32_t magic;
2519
2520         magic = htonl(0xf7eead15);
2521         if (write(newfd, &magic, 4) < 0) {
2522                 ERROR("Failed writing initial data to socket: %s",
2523                        fr_syserror(errno));
2524                 return -1;
2525         }
2526
2527         if (sock) {
2528                 magic = htonl(2);       /* protocol version */
2529         } else {
2530                 magic = htonl(1);
2531         }
2532         if (write(newfd, &magic, 4) < 0) {
2533                 ERROR("Failed writing initial data to socket: %s", fr_syserror(errno));
2534                 return -1;
2535         }
2536
2537         /*
2538          *      Write an initial challenge
2539          */
2540         if (sock) {
2541                 int i;
2542                 fr_cs_buffer_t *co;
2543
2544                 co = talloc_zero(sock, fr_cs_buffer_t);
2545                 sock->packet = (void *) co;
2546
2547                 for (i = 0; i < 16; i++) {
2548                         co->buffer[i] = fr_rand();
2549                 }
2550
2551                 /*
2552                  *      FIXME: EINTR, etc.
2553                  */
2554                 if (write(newfd, co->buffer, 16) < 0) {
2555                         ERROR("Failed writing version data to socket: %s", fr_syserror(errno));
2556                         return -1;
2557                 }
2558         }
2559
2560         return 0;
2561 }
2562
2563
2564 static int command_tcp_recv(rad_listen_t *this)
2565 {
2566         listen_socket_t *sock = this->data;
2567         fr_cs_buffer_t *co = (void *) sock->packet;
2568
2569         rad_assert(co != NULL);
2570
2571         if (!co->auth) {
2572                 uint8_t expected[16];
2573
2574                 /*
2575                  *      No response yet: keep reading it.
2576                  */
2577                 if (co->offset < 16) {
2578                         ssize_t r;
2579
2580                         r = read(this->fd,
2581                                  co->buffer + 16 + co->offset, 16 - co->offset);
2582                         if (r == 0) {
2583                         close_socket:
2584                                 command_close_socket(this);
2585                                 return 0;
2586                         }
2587
2588                         if (r < 0) {
2589 #ifdef ECONNRESET
2590                                 if (errno == ECONNRESET) goto close_socket;
2591 #endif
2592                                 if (errno == EINTR) return 0;
2593
2594                                 ERROR("Failed reading from control socket; %s",
2595                                        fr_syserror(errno));
2596                                 goto close_socket;
2597                         }
2598
2599                         co->offset += r;
2600
2601                         if (co->offset < 16) return 0;
2602                 }
2603
2604                 fr_hmac_md5(expected, (void const *) sock->client->secret,
2605                             strlen(sock->client->secret),
2606                             (uint8_t *) co->buffer, 16);
2607
2608                 if (rad_digest_cmp(expected,
2609                                    (uint8_t *) co->buffer + 16, 16 != 0)) {
2610                         ERROR("radmin failed challenge: Closing socket");
2611                         goto close_socket;
2612                 }
2613
2614                 co->auth = true;
2615                 co->offset = 0;
2616         }
2617
2618         return command_domain_recv_co(this, co);
2619 }
2620
2621 /*
2622  *      Should never be called.  The functions should just call write().
2623  */
2624 static int command_tcp_send(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
2625 {
2626         return 0;
2627 }
2628
2629 static int command_domain_recv(rad_listen_t *listener)
2630 {
2631         fr_command_socket_t *sock = listener->data;
2632
2633         return command_domain_recv_co(listener, &sock->co);
2634 }
2635
2636 static int command_domain_accept(rad_listen_t *listener)
2637 {
2638         int newfd;
2639         rad_listen_t *this;
2640         socklen_t salen;
2641         struct sockaddr_storage src;
2642         fr_command_socket_t *sock = listener->data;
2643
2644         salen = sizeof(src);
2645
2646         DEBUG2(" ... new connection request on command socket");
2647
2648         newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
2649         if (newfd < 0) {
2650                 /*
2651                  *      Non-blocking sockets must handle this.
2652                  */
2653                 if (errno == EWOULDBLOCK) {
2654                         return 0;
2655                 }
2656
2657                 DEBUG2(" ... failed to accept connection");
2658                 return 0;
2659         }
2660
2661 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2662         /*
2663          *      Perform user authentication.
2664          */
2665         if (sock->uid_name || sock->gid_name) {
2666                 uid_t uid;
2667                 gid_t gid;
2668
2669                 if (getpeereid(newfd, &uid, &gid) < 0) {
2670                         ERROR("Failed getting peer credentials for %s: %s",
2671                                sock->path, fr_syserror(errno));
2672                         close(newfd);
2673                         return 0;
2674                 }
2675
2676                 /*
2677                  *      Only do UID checking if the caller is
2678                  *      non-root.  The superuser can do anything, so
2679                  *      we might as well let them.
2680                  */
2681                 if (uid != 0) do {
2682                         /*
2683                          *      Allow entry if UID or GID matches.
2684                          */
2685                         if (sock->uid_name && (sock->uid == uid)) break;
2686                         if (sock->gid_name && (sock->gid == gid)) break;
2687
2688                         if (sock->uid_name && (sock->uid != uid)) {
2689                                 ERROR("Unauthorized connection to %s from uid %ld",
2690
2691                                        sock->path, (long int) uid);
2692                                 close(newfd);
2693                                 return 0;
2694                         }
2695
2696                         if (sock->gid_name && (sock->gid != gid)) {
2697                                 ERROR("Unauthorized connection to %s from gid %ld",
2698                                        sock->path, (long int) gid);
2699                                 close(newfd);
2700                                 return 0;
2701                         }
2702                 } while (0);
2703         }
2704 #endif
2705
2706         if (command_write_magic(newfd, NULL) < 0) {
2707                 close(newfd);
2708                 return 0;
2709         }
2710
2711         /*
2712          *      Add the new listener.
2713          */
2714         this = listen_alloc(listener, listener->type);
2715         if (!this) return 0;
2716
2717         /*
2718          *      Copy everything, including the pointer to the socket
2719          *      information.
2720          */
2721         sock = this->data;
2722         memcpy(this, listener, sizeof(*this));
2723         this->status = RAD_LISTEN_STATUS_INIT;
2724         this->next = NULL;
2725         this->data = sock;      /* fix it back */
2726
2727         sock->user[0] = '\0';
2728         sock->path = ((fr_command_socket_t *) listener->data)->path;
2729         sock->co.offset = 0;
2730         sock->co.mode = ((fr_command_socket_t *) listener->data)->co.mode;
2731
2732         this->fd = newfd;
2733         this->recv = command_domain_recv;
2734
2735         /*
2736          *      Tell the event loop that we have a new FD
2737          */
2738         radius_update_listener(this);
2739
2740         return 0;
2741 }
2742
2743
2744 /*
2745  *      Send an authentication response packet
2746  */
2747 static int command_domain_send(UNUSED rad_listen_t *listener,
2748                                UNUSED REQUEST *request)
2749 {
2750         return 0;
2751 }
2752
2753
2754 static int command_socket_encode(UNUSED rad_listen_t *listener,
2755                                  UNUSED REQUEST *request)
2756 {
2757         return 0;
2758 }
2759
2760
2761 static int command_socket_decode(UNUSED rad_listen_t *listener,
2762                                  UNUSED REQUEST *request)
2763 {
2764         return 0;
2765 }
2766
2767 #endif /* WITH_COMMAND_SOCKET */