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