Include proto in API, no matter what build options
[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/modpriv.h>
27 #include <freeradius-devel/conffile.h>
28 #include <freeradius-devel/stats.h>
29 #include <freeradius-devel/realms.h>
30
31 #ifdef HAVE_SYS_UN_H
32 #include <sys/un.h>
33 #ifndef SUN_LEN
34 #define SUN_LEN(su)  (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
35 #endif
36 #endif
37
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41
42 #ifdef HAVE_PWD_H
43 #include <pwd.h>
44 #endif
45
46 #ifdef HAVE_GRP_H
47 #include <grp.h>
48 #endif
49
50 typedef struct fr_command_table_t fr_command_table_t;
51
52 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
53
54 #define FR_READ  (1)
55 #define FR_WRITE (2)
56
57 struct fr_command_table_t {
58         const char *command;
59         int mode;               /* read/write */
60         const char *help;
61         fr_command_func_t func;
62         fr_command_table_t *table;
63 };
64
65 #define COMMAND_BUFFER_SIZE (1024)
66
67 typedef struct fr_command_socket_t {
68         char    *path;
69         uid_t   uid;
70         gid_t   gid;
71         int     mode;
72         char    *uid_name;
73         char    *gid_name;
74         char    *mode_name;
75         char user[256];
76
77         /*
78          *      The next few entries handle fake packets injected by
79          *      the control socket.
80          */
81         fr_ipaddr_t     src_ipaddr; /* src_port is always 0 */
82         fr_ipaddr_t     dst_ipaddr;
83         int             dst_port;
84         rad_listen_t    *inject_listener;
85         RADCLIENT       *inject_client;
86
87         /*
88          *      The next few entries do buffer management.
89          */
90         ssize_t offset;
91         ssize_t next;
92         char buffer[COMMAND_BUFFER_SIZE];
93 } fr_command_socket_t;
94
95 static const CONF_PARSER command_config[] = {
96   { "socket",  PW_TYPE_STRING_PTR,
97     offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
98   { "uid",  PW_TYPE_STRING_PTR,
99     offsetof(fr_command_socket_t, uid_name), NULL, NULL},
100   { "gid",  PW_TYPE_STRING_PTR,
101     offsetof(fr_command_socket_t, gid_name), NULL, NULL},
102   { "mode",  PW_TYPE_STRING_PTR,
103     offsetof(fr_command_socket_t, mode_name), NULL, NULL},
104
105   { NULL, -1, 0, NULL, NULL }           /* end the list */
106 };
107
108 static FR_NAME_NUMBER mode_names[] = {
109         { "ro", FR_READ },
110         { "read-only", FR_READ },
111         { "read-write", FR_READ | FR_WRITE },
112         { "rw", FR_READ | FR_WRITE },
113         { NULL, 0 }
114 };
115
116
117 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
118 #ifdef __GNUC__
119                 __attribute__ ((format (printf, 2, 3)))
120 #endif
121 ;
122
123 #ifndef HAVE_GETPEEREID
124 static int getpeereid(int s, uid_t *euid, gid_t *egid)
125 {
126 #ifndef SO_PEERCRED
127         return -1;
128 #else
129         struct ucred cr;
130         socklen_t cl = sizeof(cr);
131         
132         if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
133                 return -1;
134         }
135
136         *euid = cr.uid;
137         *egid = cr.gid;
138         return 0;
139 #endif /* SO_PEERCRED */
140 }
141 #endif /* HAVE_GETPEEREID */
142
143
144 static int fr_server_domain_socket(const char *path)
145 {
146         int sockfd;
147         size_t len;
148         socklen_t socklen;
149         struct sockaddr_un salocal;
150         struct stat buf;
151
152         len = strlen(path);
153         if (len >= sizeof(salocal.sun_path)) {
154                 radlog(L_ERR, "Path too long in socket filename.");
155                 return -1;
156         }
157
158         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
159                 radlog(L_ERR, "Failed creating socket: %s",
160                         strerror(errno));
161                 return -1;
162         }
163
164         memset(&salocal, 0, sizeof(salocal));
165         salocal.sun_family = AF_UNIX;
166         memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
167         
168         socklen = SUN_LEN(&salocal);
169
170         /*
171          *      Check the path.
172          */
173         if (stat(path, &buf) < 0) {
174                 if (errno != ENOENT) {
175                         radlog(L_ERR, "Failed to stat %s: %s",
176                                path, strerror(errno));
177                         return -1;
178                 }
179
180                 /*
181                  *      FIXME: Check the enclosing directory?
182                  */
183         } else {                /* it exists */
184                 if (!S_ISREG(buf.st_mode)
185 #ifdef S_ISSOCK
186                     && !S_ISSOCK(buf.st_mode)
187 #endif
188                         ) {
189                         radlog(L_ERR, "Cannot turn %s into socket", path);
190                         return -1;                     
191                 }
192
193                 /*
194                  *      Refuse to open sockets not owned by us.
195                  */
196                 if (buf.st_uid != geteuid()) {
197                         radlog(L_ERR, "We do not own %s", path);
198                         return -1;
199                 }
200
201                 if (unlink(path) < 0) {
202                         radlog(L_ERR, "Failed to delete %s: %s",
203                                path, strerror(errno));
204                         return -1;
205                 }
206         }
207
208         if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
209                 radlog(L_ERR, "Failed binding to %s: %s",
210                         path, strerror(errno));
211                 close(sockfd);
212                 return -1;
213         }
214
215         /*
216          *      FIXME: There's a race condition here.  But Linux
217          *      doesn't seem to permit fchmod on domain sockets.
218          */
219         if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
220                 radlog(L_ERR, "Failed setting permissions on %s: %s",
221                        path, strerror(errno));
222                 close(sockfd);
223                 return -1;
224         }
225
226         if (listen(sockfd, 8) < 0) {
227                 radlog(L_ERR, "Failed listening to %s: %s",
228                         path, strerror(errno));
229                 close(sockfd);
230                 return -1;
231         }
232
233 #ifdef O_NONBLOCK
234         {
235                 int flags;
236                 
237                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
238                         radlog(L_ERR, "Failure getting socket flags: %s",
239                                 strerror(errno));
240                         close(sockfd);
241                         return -1;
242                 }
243                 
244                 flags |= O_NONBLOCK;
245                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
246                         radlog(L_ERR, "Failure setting socket flags: %s",
247                                 strerror(errno));
248                         close(sockfd);
249                         return -1;
250                 }
251         }
252 #endif
253
254         return sockfd;
255 }
256
257 static void command_close_socket(rad_listen_t *this)
258 {
259         this->status = RAD_LISTEN_STATUS_CLOSED;
260
261         /*
262          *      This removes the socket from the event fd, so no one
263          *      will be calling us any more.
264          */
265         event_new_fd(this);
266
267         listen_free(&this);
268 }
269
270
271 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
272 {
273         ssize_t len;
274         va_list ap;
275         char buffer[256];
276
277         va_start(ap, fmt);
278         len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
279         va_end(ap);
280
281         if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0;
282
283         len = write(listener->fd, buffer, len);
284         if (len <= 0) command_close_socket(listener);
285
286         /*
287          *      FIXME: Keep writing until done?
288          */
289         return len;
290 }
291
292 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
293 {
294         CONF_SECTION *cs;
295         module_instance_t *mi;
296
297         if (argc == 0) {
298                 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
299                 return 1;
300         }
301
302         cs = cf_section_find("modules");
303         if (!cs) return 0;
304
305         mi = find_module_instance(cs, argv[0], 0);
306         if (!mi) {
307                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
308                 return 0;
309         }
310
311         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
312                 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
313                         argv[0]);
314                 return 0;
315         }
316
317         if (!module_hup_module(mi->cs, mi, time(NULL))) {
318                 cprintf(listener, "ERROR: Failed to reload module\n");
319                 return 0;
320         }
321
322         return 1;               /* success */
323 }
324
325 static int command_terminate(UNUSED rad_listen_t *listener,
326                              UNUSED int argc, UNUSED char *argv[])
327 {
328         radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
329
330         return 1;               /* success */
331 }
332
333 extern time_t fr_start_time;
334
335 static int command_uptime(rad_listen_t *listener,
336                           UNUSED int argc, UNUSED char *argv[])
337 {
338         char buffer[128];
339
340         CTIME_R(&fr_start_time, buffer, sizeof(buffer));
341         cprintf(listener, "Up since %s", buffer); /* no \r\n */
342
343         return 1;               /* success */
344 }
345
346 static const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
347
348 /*
349  *      FIXME: Recurse && indent?
350  */
351 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
352                                const void *base)
353                                
354 {
355         int i;
356         const void *data;
357         const char *name1 = cf_section_name1(cs);
358         const char *name2 = cf_section_name2(cs);
359         const CONF_PARSER *variables = cf_section_parse_table(cs);
360         char buffer[256];
361
362         if (name2) {
363                 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
364         } else {
365                 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
366         }
367
368         indent++;
369         
370         /*
371          *      Print
372          */
373         if (variables) for (i = 0; variables[i].name != NULL; i++) {
374                 /*
375                  *      No base struct offset, data must be the pointer.
376                  *      If data doesn't exist, ignore the entry, there
377                  *      must be something wrong.
378                  */
379                 if (!base) {
380                         if (!variables[i].data) {
381                                 continue;
382                         }
383                         
384                         data = variables[i].data;;
385                         
386                 } else if (variables[i].data) {
387                         data = variables[i].data;;
388                         
389                 } else {
390                         data = (((char *)base) + variables[i].offset);
391                 }
392
393                 switch (variables[i].type) {
394                 default:
395                         cprintf(listener, "%.*s%s = ?\n", indent, tabs,
396                                 variables[i].name);
397                         break;
398                         
399                 case PW_TYPE_INTEGER:
400                         cprintf(listener, "%.*s%s = %u\n", indent, tabs,
401                                 variables[i].name, *(int *) data);
402                         break;
403                         
404                 case PW_TYPE_IPADDR:
405                         inet_ntop(AF_INET, data, buffer, sizeof(buffer));
406                         break;
407
408                 case PW_TYPE_IPV6ADDR:
409                         inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
410                         break;
411
412                 case PW_TYPE_BOOLEAN:
413                         cprintf(listener, "%.*s%s = %s\n", indent, tabs,
414                                 variables[i].name, 
415                                 ((*(int *) data) == 0) ? "no" : "yes");
416                         break;
417                         
418                 case PW_TYPE_STRING_PTR:
419                 case PW_TYPE_FILENAME:
420                         /*
421                          *      FIXME: Escape things in the string!
422                          */
423                         if (*(char **) data) {
424                                 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
425                                         variables[i].name, *(char **) data);
426                         } else {
427                                 cprintf(listener, "%.*s%s = \n", indent, tabs,
428                                         variables[i].name);
429                         }
430                                 
431                         break;
432                 }
433         }
434
435         indent--;
436
437         cprintf(listener, "%.*s}\n", indent, tabs);
438 }
439
440 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
441 {
442         CONF_SECTION *cs;
443         module_instance_t *mi;
444
445         if (argc != 1) {
446                 cprintf(listener, "ERROR: No module name was given\n");
447                 return 0;
448         }
449
450         cs = cf_section_find("modules");
451         if (!cs) return 0;
452
453         mi = find_module_instance(cs, argv[0], 0);
454         if (!mi) {
455                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
456                 return 0;
457         }
458
459         cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
460
461         return 1;               /* success */
462 }
463
464 static const char *method_names[RLM_COMPONENT_COUNT] = {
465         "authenticate",
466         "authorize",
467         "preacct",
468         "accounting",
469         "session",
470         "pre-proxy",
471         "post-proxy",
472         "post-auth"
473 };
474
475
476 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
477 {
478         int i;
479         CONF_SECTION *cs;
480         const module_instance_t *mi;
481         const module_t *mod;
482
483         if (argc != 1) {
484                 cprintf(listener, "ERROR: No module name was given\n");
485                 return 0;
486         }
487
488         cs = cf_section_find("modules");
489         if (!cs) return 0;
490
491         mi = find_module_instance(cs, argv[0], 0);
492         if (!mi) {
493                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
494                 return 0;
495         }
496
497         mod = mi->entry->module;
498
499         for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
500                 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
501         }
502
503         return 1;               /* success */
504 }
505
506
507 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
508 {
509         CONF_SECTION *cs;
510         const module_instance_t *mi;
511         const module_t *mod;
512
513         if (argc != 1) {
514                 cprintf(listener, "ERROR: No module name was given\n");
515                 return 0;
516         }
517
518         cs = cf_section_find("modules");
519         if (!cs) return 0;
520
521         mi = find_module_instance(cs, argv[0], 0);
522         if (!mi) {
523                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
524                 return 0;
525         }
526
527         mod = mi->entry->module;
528
529         if ((mod->type & RLM_TYPE_THREAD_SAFE) != 0)
530                 cprintf(listener, "\tthread-safe\n");
531
532
533         if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
534                 cprintf(listener, "\twill-check-config\n");
535
536
537         if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
538                 cprintf(listener, "\treload-on-hup\n");
539
540         return 1;               /* success */
541 }
542
543
544 /*
545  *      Show all loaded modules
546  */
547 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
548 {
549         CONF_SECTION *cs, *subcs;
550
551         cs = cf_section_find("modules");
552         if (!cs) return 0;
553
554         subcs = NULL;
555         while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
556                 const char *name1 = cf_section_name1(subcs);
557                 const char *name2 = cf_section_name2(subcs);
558
559                 module_instance_t *mi;
560
561                 if (name2) {
562                         mi = find_module_instance(cs, name2, 0);
563                         if (!mi) continue;
564
565                         cprintf(listener, "\t%s (%s)\n", name2, name1);
566                 } else {
567                         mi = find_module_instance(cs, name1, 0);
568                         if (!mi) continue;
569
570                         cprintf(listener, "\t%s\n", name1);
571                 }
572         }
573
574         return 1;               /* success */
575 }
576
577 #ifdef WITH_PROXY
578 static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
579 {
580         int i;
581         home_server *home;
582         const char *type, *state;
583
584         char buffer[256];
585
586         for (i = 0; i < 256; i++) {
587                 home = home_server_bynumber(i);
588                 if (!home) break;
589
590                 /*
591                  *      Internal "virtual" home server.
592                  */
593                 if (home->ipaddr.af == AF_UNSPEC) continue;
594
595                 if (home->type == HOME_TYPE_AUTH) {
596                         type = "auth";
597
598                 } else if (home->type == HOME_TYPE_ACCT) {
599                         type = "acct";
600
601                 } else continue;
602
603                 if (home->state == HOME_STATE_ALIVE) {
604                         state = "alive";
605
606                 } else if (home->state == HOME_STATE_ZOMBIE) {
607                         state = "zombie";
608
609                 } else if (home->state == HOME_STATE_IS_DEAD) {
610                         state = "dead";
611
612                 } else continue;
613
614                 cprintf(listener, "%s\t%d\t%s\t%s\t%d\n",
615                         ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
616                         home->port, type, state,
617                         home->currently_outstanding);
618         }
619
620         return 0;
621 }
622 #endif
623
624 static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
625 {
626         int i;
627         RADCLIENT *client;
628         char buffer[256];
629
630         for (i = 0; i < 256; i++) {
631                 client = client_findbynumber(NULL, i);
632                 if (!client) break;
633
634                 ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
635
636                 if (((client->ipaddr.af == AF_INET) &&
637                      (client->prefix != 32)) ||
638                     ((client->ipaddr.af == AF_INET6) &&
639                      (client->prefix != 128))) {
640                         cprintf(listener, "\t%s/%d\n", buffer, client->prefix);
641                 } else {
642                         cprintf(listener, "\t%s\n", buffer);
643                 }
644         }
645
646         return 0;
647 }
648
649
650 static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
651 {
652         CONF_ITEM *ci;
653         FILE *fp = fdopen(dup(listener->fd), "a");
654
655         if (!fp) {
656                 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
657                 return 0;
658         }
659
660         if (argc == 0) {
661                 cprintf(listener, "ERROR: <reference> is required\n");
662                 return 0;
663         }
664         
665         ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
666         if (!ci) {
667                 cprintf(listener, "ERROR: No such item <reference>\n");
668                 return 0;
669         }
670
671         if (cf_item_is_section(ci)) {
672                 cf_section2xml(fp, cf_itemtosection(ci));
673
674         } else if (cf_item_is_pair(ci)) {
675                 cf_pair2xml(fp, cf_itemtopair(ci));
676
677         } else {
678                 cprintf(listener, "ERROR: No such item <reference>\n");
679                 fclose(fp);
680                 return 0;
681         }
682
683         fclose(fp);
684
685         return 1;               /* success */
686 }
687
688 static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
689 {
690         cprintf(listener, "%s\n", radiusd_version);
691         return 1;
692 }
693
694 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
695 {
696         int number;
697
698         if (argc == 0) {
699                 cprintf(listener, "ERROR: Must specify <number>\n");
700                 return -1;
701         }
702
703         number = atoi(argv[0]);
704         if ((number < 0) || (number > 4)) {
705                 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
706                 return -1;
707         }
708
709         fr_debug_flag = debug_flag = number;
710
711         return 0;
712 }
713
714 char *debug_log_file = NULL;
715 static char debug_log_file_buffer[1024];
716
717 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
718 {
719         if (debug_flag && mainconfig.radlog_dest == RADLOG_STDOUT) {
720                 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
721                 return -1;
722         }
723
724         if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) != NULL)) {
725                 cprintf(listener, "ERROR: Cannot direct debug logs to absolute path.\n");
726         }
727
728         debug_log_file = NULL;
729
730         if (argc == 0) return 0;
731
732         /*
733          *      This looks weird, but it's here to avoid locking
734          *      a mutex for every log message.
735          */
736         memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer));
737
738         /*
739          *      Debug files always go to the logging directory.
740          */
741         snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer),
742                  "%s/%s", radlog_dir, argv[0]);
743
744         debug_log_file = &debug_log_file_buffer[0];
745
746         return 0;
747 }
748
749 extern char *debug_condition;
750 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
751 {
752         /*
753          *      Delete old condition.
754          *
755          *      This is thread-safe because the condition is evaluated
756          *      in the main server thread, as is this code.
757          */
758         free(debug_condition);
759         debug_condition = NULL;
760
761         /*
762          *      Disable it.
763          */
764         if (argc == 0) {
765                 return 0;
766         }
767
768         debug_condition = strdup(argv[0]);
769
770         return 0;
771 }
772
773 static int command_show_debug_condition(rad_listen_t *listener,
774                                         UNUSED int argc, UNUSED char *argv[])
775 {
776         if (!debug_condition) return 0;
777
778         cprintf(listener, "%s\n", debug_condition);
779         return 0;
780 }
781
782
783 static int command_show_debug_file(rad_listen_t *listener,
784                                         UNUSED int argc, UNUSED char *argv[])
785 {
786         if (!debug_log_file) return 0;
787
788         cprintf(listener, "%s\n", debug_log_file);
789         return 0;
790 }
791
792
793 static int command_show_debug_level(rad_listen_t *listener,
794                                         UNUSED int argc, UNUSED char *argv[])
795 {
796         cprintf(listener, "%d\n", debug_flag);
797         return 0;
798 }
799
800
801 static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[])
802 {
803         RADCLIENT *client;
804         fr_ipaddr_t ipaddr;
805         int proto = IPPROTO_UDP;
806
807         if (argc < 1) {
808                 cprintf(listener, "ERROR: Must specify <ipaddr>\n");
809                 return NULL;
810         }
811
812         if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
813                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
814                         fr_strerror());
815                 return NULL;
816         }
817
818 #ifdef WITH_TCP
819         if (argc >= 2) {
820                 if (strcmp(argv[1], "tcp") == 0) {
821                         proto = IPPROTO_TCP;
822
823                 } else if (strcmp(argv[1], "udp") == 0) {
824                         proto = IPPROTO_UDP;
825
826                 } else {
827                         cprintf(listener, "ERROR: Unknown protocol %s.  Please use \"udp\" or \"tcp\"\n",
828                                 argv[1]);
829                         return NULL;
830                 }
831         }
832 #endif
833
834         client = client_find(NULL, &ipaddr, proto);
835         if (!client) {
836                 cprintf(listener, "ERROR: No such client\n");
837                 return NULL;
838         }
839
840         return client;
841 }
842
843
844 static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[])
845 {
846         RADCLIENT *client;
847         FILE *fp;
848
849         client = get_client(listener, argc, argv);
850         if (!client) {
851                 return 0;
852         }
853
854         if (!client->cs) return 1;
855
856         fp = fdopen(dup(listener->fd), "a");
857         if (!fp) {
858                 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
859                 return 0;
860         }
861
862         cf_section2file(fp, client->cs);
863         fclose(fp);
864
865         return 1;
866 }
867
868 #ifdef WITH_PROXY
869 static home_server *get_home_server(rad_listen_t *listener, int argc, char *argv[])
870 {
871         home_server *home;
872         int port;
873         fr_ipaddr_t ipaddr;
874
875         if (argc < 2) {
876                 cprintf(listener, "ERROR: Must specify <ipaddr> <port>\n");
877                 return NULL;
878         }
879
880         if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
881                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
882                         fr_strerror());
883                 return NULL;
884         }
885
886         port = atoi(argv[1]);
887
888         home = home_server_find(&ipaddr, port);
889         if (!home) {
890                 cprintf(listener, "ERROR: No such home server\n");
891                 return NULL;
892         }
893
894         return home;
895 }
896
897 static int command_show_home_server_config(rad_listen_t *listener, int argc, char *argv[])
898 {
899         home_server *home;
900         FILE *fp;
901
902         home = get_home_server(listener, argc, argv);
903         if (!home) {
904                 return 0;
905         }
906
907         if (!home->cs) return 1;
908
909         fp = fdopen(dup(listener->fd), "a");
910         if (!fp) {
911                 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
912                 return 0;
913         }
914
915         cf_section2file(fp, home->cs);
916         fclose(fp);
917
918         return 1;
919 }
920
921 extern void revive_home_server(void *ctx);
922 extern void mark_home_server_dead(home_server *home, struct timeval *when);
923
924 static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
925 {
926         home_server *home;
927
928         if (argc < 3) {
929                 cprintf(listener, "ERROR: Must specify <ipaddr> <port> <state>\n");
930                 return 0;
931         }
932
933         home = get_home_server(listener, argc, argv);
934         if (!home) {
935                 return 0;
936         }
937
938         if (strcmp(argv[2], "alive") == 0) {
939                 revive_home_server(home);
940
941         } else if (strcmp(argv[2], "dead") == 0) {
942                 struct timeval now;
943
944                 gettimeofday(&now, NULL); /* we do this WAY too ofetn */
945                 mark_home_server_dead(home, &now);
946
947         } else {
948                 cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[2]);
949                 return 0;
950         }
951
952         return 1;
953 }
954
955 static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
956 {
957         home_server *home;
958
959         home = get_home_server(listener, argc, argv);
960         if (!home) {
961                 return 0;
962         }
963
964         switch (home->state) {
965         case HOME_STATE_ALIVE:
966                 cprintf(listener, "alive\n");
967                 break;
968
969         case HOME_STATE_IS_DEAD:
970                 cprintf(listener, "dead\n");
971                 break;
972
973         case HOME_STATE_ZOMBIE:
974                 cprintf(listener, "zombie\n");
975                 break;
976
977         default:
978                 cprintf(listener, "unknown\n");
979                 break;
980         }
981         
982         return 1;
983 }
984 #endif
985
986 /*
987  *      For encode/decode stuff
988  */
989 static int null_socket_dencode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
990 {
991         return 0;
992 }
993
994 static int null_socket_send(UNUSED rad_listen_t *listener, REQUEST *request)
995 {
996         char *output_file;
997         FILE *fp;
998         VALUE_PAIR *vp;
999
1000         output_file = request_data_reference(request, null_socket_send, 0);
1001         if (!output_file) {
1002                 radlog(L_ERR, "WARNING: No output file for injected packet %d",
1003                        request->number);
1004                 return 0;
1005         }
1006
1007         fp = fopen(output_file, "w");
1008         if (!fp) {
1009                 radlog(L_ERR, "Failed to send injected file to %s: %s",
1010                        output_file, strerror(errno));
1011                 return 0;
1012         }
1013
1014         if (request->reply->code != 0) {
1015                 const char *what = "reply";
1016                 char buffer[1024];
1017
1018                 if (request->reply->code < FR_MAX_PACKET_CODE) {
1019                         what = fr_packet_codes[request->reply->code];
1020                 }
1021
1022                 fprintf(fp, "%s\n", what);
1023
1024                 if (debug_flag) {
1025                         request->radlog(L_DBG, 0, request,
1026                                         "Injected %s packet to host %s port 0 code=%d, id=%d",
1027                                         what,
1028                                         inet_ntop(request->reply->src_ipaddr.af,
1029                                                   &request->reply->src_ipaddr.ipaddr,
1030                                                   buffer, sizeof(buffer)),
1031                                         request->reply->code, request->reply->id);
1032                 }
1033
1034                 for (vp = request->reply->vps; vp != NULL; vp = vp->next) {
1035                         vp_prints(buffer, sizeof(buffer), vp);
1036                         fprintf(fp, "%s\n", buffer);
1037                         if (debug_flag) {
1038                                 request->radlog(L_DBG, 0, request, "\t%s",
1039                                                 buffer);
1040                         }
1041                 }
1042         }
1043         fclose(fp);
1044
1045         return 0;
1046 }
1047
1048 static int command_inject_to(rad_listen_t *listener, int argc, char *argv[])
1049 {
1050         int port;
1051         RAD_LISTEN_TYPE type;
1052         fr_command_socket_t *sock = listener->data;
1053         fr_ipaddr_t ipaddr;
1054         rad_listen_t *found = NULL;
1055
1056         if (argc < 1) {
1057                 cprintf(listener, "ERROR: Must specify [auth/acct]\n");
1058                 return 0;
1059         }
1060
1061         if (strcmp(argv[0], "auth") == 0) {
1062                 type = RAD_LISTEN_AUTH;
1063
1064         } else if (strcmp(argv[0], "acct") == 0) {
1065 #ifdef WITH_ACCOUNTING
1066                 type = RAD_LISTEN_ACCT;
1067 #else
1068                 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1069                 return 0;
1070 #endif
1071
1072         } else {
1073                 cprintf(listener, "ERROR: Unknown socket type\n");
1074                 return 0;
1075         }
1076
1077         if (argc < 3) {
1078                 cprintf(listener, "ERROR: No <ipaddr> <port> was given\n");
1079                 return 0;
1080         }
1081
1082         /*
1083          *      FIXME:  Look for optional arg 4, and bind interface.
1084          */
1085
1086         if (ip_hton(argv[1], AF_UNSPEC, &ipaddr) < 0) {
1087                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1088                         fr_strerror());
1089                 return 0;
1090         }
1091         port = atoi(argv[2]);
1092
1093         found = listener_find_byipaddr(&ipaddr, port);
1094         if (!found) {
1095                 cprintf(listener, "ERROR: Could not find matching listener\n");
1096                 return 0;
1097         }
1098
1099         sock->inject_listener = found;
1100         sock->dst_ipaddr = ipaddr;
1101         sock->dst_port = port;
1102
1103         return 1;
1104 }
1105
1106 static int command_inject_from(rad_listen_t *listener, int argc, char *argv[])
1107 {
1108         RADCLIENT *client;
1109         fr_command_socket_t *sock = listener->data;
1110
1111         if (argc < 1) {
1112                 cprintf(listener, "ERROR: No <ipaddr> was given\n");
1113                 return 0;
1114         }
1115
1116         if (!sock->inject_listener) {
1117                 cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject from\"\n");
1118                 return 0;
1119         }
1120
1121         sock->src_ipaddr.af = AF_UNSPEC;
1122         if (ip_hton(argv[0], AF_UNSPEC, &sock->src_ipaddr) < 0) {
1123                 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1124                         fr_strerror());
1125                 return 0;
1126         }
1127
1128         client = client_listener_find(sock->inject_listener, &sock->src_ipaddr,
1129                                       0);
1130         if (!client) {
1131                 cprintf(listener, "ERROR: No such client %s\n", argv[0]);
1132                 return 0;
1133         }
1134         sock->inject_client = client;
1135
1136         return 1;
1137 }
1138
1139 static int command_inject_file(rad_listen_t *listener, int argc, char *argv[])
1140 {
1141         static int inject_id = 0;
1142         int filedone;
1143         fr_command_socket_t *sock = listener->data;
1144         rad_listen_t *fake;
1145         REQUEST *request = NULL;
1146         RADIUS_PACKET *packet;
1147         VALUE_PAIR *vp;
1148         FILE *fp;
1149         RAD_REQUEST_FUNP fun = NULL;
1150         char buffer[2048];
1151
1152         if (argc < 2) {
1153                 cprintf(listener, "ERROR: You must specify <input-file> <output-file>\n");
1154                 return 0;
1155         }
1156
1157         /*
1158          *      Output files always go to the logging directory.
1159          */
1160         snprintf(buffer, sizeof(buffer), "%s/%s", radlog_dir, argv[1]);
1161
1162         fp = fopen(argv[0], "r");
1163         if (!fp ) {
1164                 cprintf(listener, "ERROR: Failed opening %s: %s\n",
1165                         argv[0], strerror(errno));
1166                 return 0;
1167         }
1168
1169         vp = readvp2(fp, &filedone, "");
1170         fclose(fp);
1171         if (!vp) {
1172                 cprintf(listener, "ERROR: Failed reading attributes from %s: %s\n",
1173                         argv[0], fr_strerror());
1174                 return 0;
1175         }
1176
1177         fake = rad_malloc(sizeof(*fake));
1178         memcpy(fake, sock->inject_listener, sizeof(*fake));
1179
1180         /*
1181          *      Re-write the IO for the listener.
1182          */
1183         fake->encode = null_socket_dencode;
1184         fake->decode = null_socket_dencode;
1185         fake->send = null_socket_send;
1186
1187         packet = rad_alloc(0);
1188         packet->src_ipaddr = sock->src_ipaddr;
1189         packet->src_port = 0;
1190
1191         packet->dst_ipaddr = sock->dst_ipaddr;
1192         packet->dst_port = sock->dst_port;
1193         packet->vps = vp;
1194         packet->id = inject_id++;
1195
1196         if (fake->type == RAD_LISTEN_AUTH) {
1197                 packet->code = PW_AUTHENTICATION_REQUEST;
1198                 fun = rad_authenticate;
1199
1200         } else {
1201 #ifdef WITH_ACCOUNTING
1202                 packet->code = PW_ACCOUNTING_REQUEST;
1203                 fun = rad_accounting;
1204 #else
1205                 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1206                 rad_free(&packet);
1207                 free(fake);
1208                 return 0;
1209 #endif
1210         }
1211
1212         if (!received_request(fake, packet, &request, sock->inject_client)) {
1213                 cprintf(listener, "ERROR: Failed to inject request.  See log file for details\n");
1214                 rad_free(&packet);
1215                 free(fake);
1216                 return 0;
1217         }
1218
1219         /*
1220          *      Remember what the output file is, and remember to
1221          *      delete the fake listener when done.
1222          */
1223         request_data_add(request, null_socket_send, 0, strdup(buffer), free);
1224         request_data_add(request, null_socket_send, 1, fake, free);
1225
1226         if (debug_flag) {
1227                 request->radlog(L_DBG, 0, request,
1228                                 "Injected %s packet from host %s port 0 code=%d, id=%d",
1229                                 fr_packet_codes[packet->code],
1230                                 inet_ntop(packet->src_ipaddr.af,
1231                                           &packet->src_ipaddr.ipaddr,
1232                                           buffer, sizeof(buffer)),
1233                                 packet->code, packet->id);
1234                 
1235                 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1236                         vp_prints(buffer, sizeof(buffer), vp);
1237                         request->radlog(L_DBG, 0, request, "\t%s", buffer);
1238                 }
1239         }
1240
1241         /*
1242          *      And go process it.
1243          */
1244         thread_pool_addrequest(request, fun);
1245
1246         return 1;
1247 }
1248
1249
1250 static fr_command_table_t command_table_inject[] = {
1251         { "to", FR_WRITE,
1252           "inject to <ipaddr> <port> - Inject packets to the destination IP and port.",
1253           command_inject_to, NULL },
1254
1255         { "from", FR_WRITE,
1256           "inject from <ipaddr> - Inject packets as if they came from <ipaddr>",
1257           command_inject_from, NULL },
1258
1259         { "file", FR_WRITE,
1260           "inject file <input-file> <output-file> - Inject packet from input-file>, with results sent to <output-file>",
1261           command_inject_file, NULL },
1262
1263         { NULL, 0, NULL, NULL, NULL }
1264 };
1265
1266 static fr_command_table_t command_table_debug[] = {
1267         { "condition", FR_WRITE,
1268           "debug condition [condition] - Enable debugging for requests matching [condition]",
1269           command_debug_condition, NULL },
1270
1271         { "level", FR_WRITE,
1272           "debug level <number> - Set debug level to <number>.  Higher is more debugging.",
1273           command_debug_level, NULL },
1274
1275         { "file", FR_WRITE,
1276           "debug file [filename] - Send all debugging output to [filename]",
1277           command_debug_file, NULL },
1278
1279         { NULL, 0, NULL, NULL, NULL }
1280 };
1281
1282 static fr_command_table_t command_table_show_debug[] = {
1283         { "condition", FR_READ,
1284           "show debug condition - Shows current debugging condition.",
1285           command_show_debug_condition, NULL },
1286
1287         { "level", FR_READ,
1288           "show debug level - Shows current debugging level.",
1289           command_show_debug_level, NULL },
1290
1291         { "file", FR_READ,
1292           "show debug file - Shows current debugging file.",
1293           command_show_debug_file, NULL },
1294
1295         { NULL, 0, NULL, NULL, NULL }
1296 };
1297
1298 static fr_command_table_t command_table_show_module[] = {
1299         { "config", FR_READ,
1300           "show module config <module> - show configuration for given module",
1301           command_show_module_config, NULL },
1302         { "flags", FR_READ,
1303           "show module flags <module> - show other module properties",
1304           command_show_module_flags, NULL },
1305         { "list", FR_READ,
1306           "show module list - shows list of loaded modules",
1307           command_show_modules, NULL },
1308         { "methods", FR_READ,
1309           "show module methods <module> - show sections where <module> may be used",
1310           command_show_module_methods, NULL },
1311
1312         { NULL, 0, NULL, NULL, NULL }
1313 };
1314
1315 static fr_command_table_t command_table_show_client[] = {
1316         { "config", FR_READ,
1317           "show client config <ipaddr> "
1318 #ifdef WITH_TCP
1319           "[proto] "
1320 #endif
1321           "- show configuration for given client",
1322           command_show_client_config, NULL },
1323         { "list", FR_READ,
1324           "show client list - shows list of global clients",
1325           command_show_clients, NULL },
1326
1327         { NULL, 0, NULL, NULL, NULL }
1328 };
1329
1330 #ifdef WITH_PROXY
1331 static fr_command_table_t command_table_show_home[] = {
1332         { "config", FR_READ,
1333           "show home_server config <ipaddr> <port> - show configuration for given home server",
1334           command_show_home_server_config, NULL },
1335         { "list", FR_READ,
1336           "show home_server list - shows list of home servers",
1337           command_show_home_servers, NULL },
1338         { "state", FR_READ,
1339           "show home_server state <ipaddr> <port> - shows state of given home server",
1340           command_show_home_server_state, NULL },
1341
1342         { NULL, 0, NULL, NULL, NULL }
1343 };
1344 #endif
1345
1346
1347 static fr_command_table_t command_table_show[] = {
1348         { "client", FR_READ,
1349           "show client <command> - do sub-command of client",
1350           NULL, command_table_show_client },
1351         { "debug", FR_READ,
1352           "show debug <command> - show debug properties",
1353           NULL, command_table_show_debug },
1354 #ifdef WITH_PROXY
1355         { "home_server", FR_READ,
1356           "show home_server <command> - do sub-command of home_server",
1357           NULL, command_table_show_home },
1358 #endif
1359         { "module", FR_READ,
1360           "show module <command> - do sub-command of module",
1361           NULL, command_table_show_module },
1362         { "uptime", FR_READ,
1363           "show uptime - shows time at which server started",
1364           command_uptime, NULL },
1365         { "version", FR_READ,
1366           "show version - Prints version of the running server",
1367           command_show_version, NULL },
1368         { "xml", FR_READ,
1369           "show xml <reference> - Prints out configuration as XML",
1370           command_show_xml, NULL },
1371         { NULL, 0, NULL, NULL, NULL }
1372 };
1373
1374
1375 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
1376 {
1377         int i, rcode;
1378         CONF_PAIR *cp;
1379         CONF_SECTION *cs;
1380         module_instance_t *mi;
1381         const CONF_PARSER *variables;
1382         void *data;
1383
1384         if (argc < 3) {
1385                 cprintf(listener, "ERROR: No module name or variable was given\n");
1386                 return 0;
1387         }
1388
1389         cs = cf_section_find("modules");
1390         if (!cs) return 0;
1391
1392         mi = find_module_instance(cs, argv[0], 0);
1393         if (!mi) {
1394                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1395                 return 0;
1396         }
1397
1398         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
1399                 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
1400                 return 0;
1401         }
1402
1403         variables = cf_section_parse_table(mi->cs);
1404         if (!variables) {
1405                 cprintf(listener, "ERROR: Cannot find configuration for module\n");
1406                 return 0;
1407         }
1408
1409         rcode = -1;
1410         for (i = 0; variables[i].name != NULL; i++) {
1411                 /*
1412                  *      FIXME: Recurse into sub-types somehow...
1413                  */
1414                 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
1415
1416                 if (strcmp(variables[i].name, argv[1]) == 0) {
1417                         rcode = i;
1418                         break;
1419                 }
1420         }
1421
1422         if (rcode < 0) {
1423                 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
1424                 return 0;
1425         }
1426
1427         i = rcode;              /* just to be safe */
1428
1429         /*
1430          *      It's not part of the dynamic configuration.  The module
1431          *      needs to re-parse && validate things.
1432          */
1433         if (variables[i].data) {
1434                 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
1435                 return 0;
1436         }
1437
1438         data = ((char *) mi->insthandle) + variables[i].offset;
1439
1440         cp = cf_pair_find(mi->cs, argv[1]);
1441         if (!cp) return 0;
1442
1443         /*
1444          *      Replace the OLD value in the configuration file with
1445          *      the NEW value.
1446          *
1447          *      FIXME: Parse argv[2] depending on it's data type!
1448          *      If it's a string, look for leading single/double quotes,
1449          *      end then call tokenize functions???
1450          */
1451         cf_pair_replace(mi->cs, cp, argv[2]);
1452
1453         rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
1454                               data, argv[2]);
1455         if (rcode < 0) {
1456                 cprintf(listener, "ERROR: Failed to parse value\n");
1457                 return 0;
1458         }
1459
1460         return 1;               /* success */
1461 }
1462
1463 static int command_set_module_status(rad_listen_t *listener, int argc, char *argv[])
1464 {
1465         CONF_SECTION *cs;
1466         module_instance_t *mi;
1467
1468         if (argc < 2) {
1469                 cprintf(listener, "ERROR: No module name or status was given\n");
1470                 return 0;
1471         }
1472
1473         cs = cf_section_find("modules");
1474         if (!cs) return 0;
1475
1476         mi = find_module_instance(cs, argv[0], 0);
1477         if (!mi) {
1478                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1479                 return 0;
1480         }
1481
1482
1483         if (strcmp(argv[1], "alive") == 0) {
1484                 mi->dead = FALSE;
1485
1486         } else if (strcmp(argv[1], "dead") == 0) {
1487                 mi->dead = TRUE;
1488
1489         } else {
1490                 cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[2]);
1491                 return 0;
1492         }
1493
1494         return 1;               /* success */
1495 }
1496
1497 static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
1498                                int auth)
1499 {
1500         cprintf(listener, "\trequests\t%d\n", stats->total_requests);
1501         cprintf(listener, "\tresponses\t%d\n", stats->total_responses);
1502         
1503         if (auth) {
1504                 cprintf(listener, "\taccepts\t\t%d\n",
1505                         stats->total_access_accepts);
1506                 cprintf(listener, "\trejects\t\t%d\n",
1507                         stats->total_access_rejects);
1508                 cprintf(listener, "\tchallenges\t%d\n",
1509                         stats->total_access_challenges);
1510         }
1511
1512         cprintf(listener, "\tdup\t\t%d\n", stats->total_dup_requests);
1513         cprintf(listener, "\tinvalid\t\t%d\n", stats->total_invalid_requests);
1514         cprintf(listener, "\tmalformed\t%d\n", stats->total_malformed_requests);
1515         cprintf(listener, "\tbad_signature\t%d\n", stats->total_bad_authenticators);
1516         cprintf(listener, "\tdropped\t\t%d\n", stats->total_packets_dropped);
1517         cprintf(listener, "\tunknown_types\t%d\n", stats->total_unknown_types);
1518         
1519         return 1;
1520 }
1521
1522
1523 #ifdef WITH_PROXY
1524 static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
1525 {
1526         home_server *home;
1527
1528         if (argc == 0) {
1529                 cprintf(listener, "ERROR: Must specify [auth/acct] OR <ipaddr> <port>\n");
1530                 return 0;
1531         }
1532
1533         if (argc == 1) {
1534 #ifdef WITH_ACCOUNTING
1535                 if (strcmp(argv[0], "acct") == 0) {
1536                         return command_print_stats(listener,
1537                                                    &proxy_acct_stats, 0);
1538                 }
1539 #endif
1540                 if (strcmp(argv[0], "auth") == 0) {
1541                         return command_print_stats(listener,
1542                                                    &proxy_auth_stats, 1);
1543                 }
1544
1545                 cprintf(listener, "ERROR: Should specify [auth/acct]\n");
1546                 return 0;
1547         }
1548
1549         home = get_home_server(listener, argc, argv);
1550         if (!home) {
1551                 return 0;
1552         }
1553
1554         command_print_stats(listener, &home->stats,
1555                             (home->type == HOME_TYPE_AUTH));
1556         cprintf(listener, "\toutstanding\t%d\n", home->currently_outstanding);
1557         return 1;
1558 }
1559 #endif
1560
1561 static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
1562 {
1563         int auth = TRUE;
1564         RADCLIENT *client;
1565
1566         if (argc < 1) {
1567                 cprintf(listener, "ERROR: Must specify [auth/acct]\n");
1568                 return 0;
1569         }
1570
1571         if (strcmp(argv[0], "auth") == 0) {
1572                 auth = TRUE;
1573
1574         } else if (strcmp(argv[0], "acct") == 0) {
1575 #ifdef WITH_ACCOUNTING
1576                 auth = FALSE;
1577 #else
1578                 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1579                 return 0;
1580 #endif
1581
1582         } else {
1583                 cprintf(listener, "ERROR: Unknown statistics type\n");
1584                 return 0;
1585         }
1586
1587         /*
1588          *      Global results for all client.
1589          */
1590         if (argc == 1) {
1591 #ifdef WITH_ACCOUNTING
1592                 if (!auth) {
1593                         return command_print_stats(listener,
1594                                                    &radius_acct_stats, auth);
1595                 }
1596 #endif
1597                 return command_print_stats(listener, &radius_auth_stats, auth);
1598         }
1599
1600         client = get_client(listener, argc - 1, argv + 1);
1601         if (!client) {
1602                 return 0;
1603         }
1604
1605 #ifdef WITH_ACCOUNTING
1606         if (!auth) {
1607                 return command_print_stats(listener, client->acct, auth);
1608         }
1609 #endif
1610
1611         return command_print_stats(listener, client->auth, auth);
1612 }
1613
1614
1615 static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
1616 {
1617         RADCLIENT *c;
1618
1619         if (argc < 1) {
1620                 cprintf(listener, "ERROR: <file> is required\n");
1621                 return 0;
1622         }
1623
1624         /*
1625          *      Read the file and generate the client.
1626          */
1627         c = client_read(argv[0], FALSE, FALSE);
1628         if (!c) {
1629                 cprintf(listener, "ERROR: Unknown error reading client file.\n");
1630                 return 0;
1631         }
1632
1633         if (!client_add(NULL, c)) {
1634                 cprintf(listener, "ERROR: Unknown error inserting new client.\n");
1635                 client_free(c);
1636                 return 0;
1637         }
1638
1639         return 1;
1640 }
1641
1642
1643 static fr_command_table_t command_table_add_client[] = {
1644         { "file", FR_WRITE,
1645           "add client file <filename> - Add new client definition from <filename>",
1646           command_add_client_file, NULL },
1647
1648         { NULL, 0, NULL, NULL, NULL }
1649 };
1650
1651
1652 static fr_command_table_t command_table_add[] = {
1653         { "client", FR_WRITE,
1654           "add client <command> - Add client configuration commands",
1655           NULL, command_table_add_client },
1656
1657         { NULL, 0, NULL, NULL, NULL }
1658 };
1659
1660
1661 #ifdef WITH_PROXY
1662 static fr_command_table_t command_table_set_home[] = {
1663         { "state", FR_WRITE,
1664           "set home_server state <ipaddr> <port> [alive|dead] - set state for given home server",
1665           command_set_home_server_state, NULL },
1666
1667         { NULL, 0, NULL, NULL, NULL }
1668 };
1669 #endif
1670
1671 static fr_command_table_t command_table_set_module[] = {
1672         { "config", FR_WRITE,
1673           "set module config <module> variable value - set configuration for <module>",
1674           command_set_module_config, NULL },
1675
1676         { "status", FR_WRITE,
1677           "set module status [alive|dead] - set the module to be alive or dead (always return \"fail\")",
1678           command_set_module_status, NULL },
1679
1680         { NULL, 0, NULL, NULL, NULL }
1681 };
1682
1683
1684 static fr_command_table_t command_table_set[] = {
1685         { "module", FR_WRITE,
1686           "set module <command> - set module commands",
1687           NULL, command_table_set_module },
1688 #ifdef WITH_PROXY
1689         { "home_server", FR_WRITE, 
1690           "set home_server <command> - set home server commands",
1691           NULL, command_table_set_home },
1692 #endif
1693
1694         { NULL, 0, NULL, NULL, NULL }
1695 };
1696
1697
1698 static fr_command_table_t command_table_stats[] = {
1699         { "client", FR_READ,
1700           "stats client [auth/acct] <ipaddr> "
1701 #ifdef WITH_TCP
1702           "[proto] "
1703 #endif
1704           "- show statistics for given client, or for all clients (auth or acct)",
1705           command_stats_client, NULL },
1706 #ifdef WITH_PROXY
1707         { "home_server", FR_READ,
1708           "stats home_server [<ipaddr>/auth/acct] <port> - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
1709           command_stats_home_server, NULL },
1710 #endif
1711
1712         { NULL, 0, NULL, NULL, NULL }
1713 };
1714
1715 static fr_command_table_t command_table[] = {
1716         { "add", FR_WRITE, NULL, NULL, command_table_add },
1717         { "debug", FR_WRITE,
1718           "debug <command> - debugging commands",
1719           NULL, command_table_debug },
1720         { "hup", FR_WRITE,
1721           "hup [module] - sends a HUP signal to the server, or optionally to one module",
1722           command_hup, NULL },
1723         { "inject", FR_WRITE,
1724           "inject <command> - commands to inject packets into a running server",
1725           NULL, command_table_inject },
1726         { "reconnect", FR_READ,
1727           "reconnect - reconnect to a running server",
1728           NULL, NULL },         /* just here for "help" */
1729         { "terminate", FR_WRITE,
1730           "terminate - terminates the server, and cause it to exit",
1731           command_terminate, NULL },
1732         { "set", FR_WRITE, NULL, NULL, command_table_set },
1733         { "show",  FR_READ, NULL, NULL, command_table_show },
1734         { "stats",  FR_READ, NULL, NULL, command_table_stats },
1735
1736         { NULL, 0, NULL, NULL, NULL }
1737 };
1738
1739
1740 /*
1741  *      Parse the unix domain sockets.
1742  *
1743  *      FIXME: TCP + SSL, after RadSec is in.
1744  */
1745 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
1746 {
1747         fr_command_socket_t *sock;
1748
1749         sock = this->data;
1750
1751         if (cf_section_parse(cs, sock, command_config) < 0) {
1752                 return -1;
1753         }
1754
1755 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
1756         if (sock->uid_name) {
1757                 struct passwd *pw;
1758                 
1759                 pw = getpwnam(sock->uid_name);
1760                 if (!pw) {
1761                         radlog(L_ERR, "Failed getting uid for %s: %s",
1762                                sock->uid_name, strerror(errno));
1763                         return -1;
1764                 }
1765
1766                 sock->uid = pw->pw_uid;
1767         }
1768
1769         if (sock->gid_name) {
1770                 struct group *gr;
1771
1772                 gr = getgrnam(sock->gid_name);
1773                 if (!gr) {
1774                         radlog(L_ERR, "Failed getting gid for %s: %s",
1775                                sock->gid_name, strerror(errno));
1776                         return -1;
1777                 }
1778                 sock->gid = gr->gr_gid; 
1779         }
1780
1781 #else  /* can't get uid or gid of connecting user */
1782
1783         if (sock->uid_name || sock->gid_name) {
1784                 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
1785                 return -1;
1786         }
1787
1788 #endif
1789
1790         if (!sock->mode_name) {
1791                 sock->mode = FR_READ;
1792         } else {
1793                 sock->mode = fr_str2int(mode_names, sock->mode_name, 0);
1794                 if (!sock->mode) {
1795                         radlog(L_ERR, "Invalid mode name \"%s\"",
1796                                sock->mode_name);
1797                         return -1;
1798                 }
1799         }
1800
1801         /*
1802          *      FIXME: check for absolute pathnames?
1803          *      check for uid/gid on the other end...    
1804          */
1805
1806         this->fd = fr_server_domain_socket(sock->path);
1807         if (this->fd < 0) {
1808                 return -1;
1809         }
1810
1811         return 0;
1812 }
1813
1814 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
1815 {
1816         fr_command_socket_t *sock = this->data;
1817
1818         snprintf(buffer, bufsize, "command file %s", sock->path);
1819         return 1;
1820 }
1821
1822
1823 /*
1824  *      String split routine.  Splits an input string IN PLACE
1825  *      into pieces, based on spaces.
1826  */
1827 static int str2argv(char *str, char **argv, int max_argc)
1828 {
1829         int argc = 0;
1830         size_t len;
1831         char buffer[1024];
1832
1833         while (*str) {
1834                 if (argc >= max_argc) return argc;
1835
1836                 /*
1837                  *      Chop out comments early.
1838                  */
1839                 if (*str == '#') {
1840                         *str = '\0';
1841                         break;
1842                 }
1843
1844                 while ((*str == ' ') ||
1845                        (*str == '\t') ||
1846                        (*str == '\r') ||
1847                        (*str == '\n')) *(str++) = '\0';
1848
1849                 if (!*str) return argc;
1850
1851                 if ((*str == '\'') || (*str == '"')) {
1852                         char *p = str;
1853                         FR_TOKEN token;
1854
1855                         token = gettoken((const char **) &p, buffer,
1856                                          sizeof(buffer));
1857                         if ((token != T_SINGLE_QUOTED_STRING) &&
1858                             (token != T_DOUBLE_QUOTED_STRING)) {
1859                                 return -1;
1860                         }
1861
1862                         len = strlen(buffer);
1863                         if (len >= (size_t) (p - str)) {
1864                                 return -1;
1865                         }
1866
1867                         memcpy(str, buffer, len + 1);
1868                         argv[argc] = str;
1869                         str = p;
1870
1871                 } else {
1872                         argv[argc] = str;
1873                 }
1874                 argc++;
1875
1876                 while (*str &&
1877                        (*str != ' ') &&
1878                        (*str != '\t') &&
1879                        (*str != '\r') &&
1880                        (*str != '\n')) str++;
1881         }
1882
1883         return argc;
1884 }
1885
1886 static void print_help(rad_listen_t *listener,
1887                        fr_command_table_t *table, int recursive)
1888 {
1889         int i;
1890         
1891         for (i = 0; table[i].command != NULL; i++) {
1892                 if (table[i].help) {
1893                         cprintf(listener, "%s\n",
1894                                 table[i].help);
1895                 } else {
1896                         cprintf(listener, "%s <command> - do sub-command of %s\n",
1897                                 table[i].command, table[i].command);
1898                 }
1899
1900                 if (recursive && table[i].table) {
1901                         print_help(listener, table[i].table, recursive);
1902                 }
1903         }
1904 }
1905
1906 #define MAX_ARGV (16)
1907
1908 /*
1909  *      Check if an incoming request is "ok"
1910  *
1911  *      It takes packets, not requests.  It sees if the packet looks
1912  *      OK.  If so, it does a number of sanity checks on it.
1913  */
1914 static int command_domain_recv(rad_listen_t *listener,
1915                                UNUSED RAD_REQUEST_FUNP *pfun,
1916                                UNUSED REQUEST **prequest)
1917 {
1918         int i, rcode;
1919         ssize_t len;
1920         int argc;
1921         char *my_argv[MAX_ARGV], **argv;
1922         fr_command_table_t *table;
1923         fr_command_socket_t *co = listener->data;
1924
1925         *pfun = NULL;
1926         *prequest = NULL;
1927
1928         do {
1929                 ssize_t c;
1930                 char *p;
1931
1932                 len = recv(listener->fd, co->buffer + co->offset,
1933                            sizeof(co->buffer) - co->offset - 1, 0);
1934                 if (len == 0) goto close_socket; /* clean close */
1935
1936                 if (len < 0) {
1937                         if ((errno == EAGAIN) || (errno == EINTR)) {
1938                                 return 0;
1939                         }
1940                         goto close_socket;
1941                 }
1942
1943                 /*
1944                  *      CTRL-D
1945                  */
1946                 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1947                 close_socket:
1948                         command_close_socket(listener);
1949                         return 0;
1950                 }
1951
1952                 /*
1953                  *      See if there are multiple lines in the buffer.
1954                  */
1955                 p = co->buffer + co->offset;
1956                 rcode = 0;
1957                 p[len] = '\0';
1958                 for (c = 0; c < len; c++) {
1959                         if ((*p == '\r') || (*p == '\n')) {
1960                                 rcode = 1;
1961                                 *p = '\0';
1962
1963                                 /*
1964                                  *      FIXME: do real buffering...
1965                                  *      handling of CTRL-C, etc.
1966                                  */
1967
1968                         } else if (rcode) {
1969                                 /*
1970                                  *      \r \n followed by ASCII...
1971                                  */
1972                                 break;
1973                         }
1974
1975                         p++;
1976                 }
1977
1978                 co->offset += len;
1979
1980                 /*
1981                  *      Saw CR/LF.  Set next element, and exit.
1982                  */
1983                 if (rcode) {
1984                         co->next = p - co->buffer;
1985                         break;
1986                 }
1987
1988                 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1989                         radlog(L_ERR, "Line too long!");
1990                         goto close_socket;
1991                 }
1992
1993                 co->offset++;
1994         } while (1);
1995
1996         argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1997         if (argc == 0) goto do_next; /* empty strings are OK */
1998
1999         if (argc < 0) {
2000                 cprintf(listener, "ERROR: Failed parsing command.\n");
2001                 goto do_next;
2002         }
2003
2004         argv = my_argv;
2005
2006         for (len = 0; len <= co->offset; len++) {
2007                 if (co->buffer[len] < 0x20) {
2008                         co->buffer[len] = '\0';
2009                         break;
2010                 }
2011         }
2012
2013         /*
2014          *      Hard-code exit && quit.
2015          */
2016         if ((strcmp(argv[0], "exit") == 0) ||
2017             (strcmp(argv[0], "quit") == 0)) goto close_socket;
2018
2019 #if 0
2020         if (!co->user[0]) {
2021                 if (strcmp(argv[0], "login") != 0) {
2022                         cprintf(listener, "ERROR: Login required\n");
2023                         goto do_next;
2024                 }
2025
2026                 if (argc < 3) {
2027                         cprintf(listener, "ERROR: login <user> <password>\n");
2028                         goto do_next;
2029                 }
2030
2031                 /*
2032                  *      FIXME: Generate && process fake RADIUS request.
2033                  */
2034                 if ((strcmp(argv[1], "root") == 0) &&
2035                     (strcmp(argv[2], "password") == 0)) {
2036                         strlcpy(co->user, argv[1], sizeof(co->user));
2037                         goto do_next;
2038                 }
2039
2040                 cprintf(listener, "ERROR: Login incorrect\n");
2041                 goto do_next;
2042         }
2043 #endif
2044
2045         table = command_table;
2046  retry:
2047         len = 0;
2048         for (i = 0; table[i].command != NULL; i++) {
2049                 if (strcmp(table[i].command, argv[0]) == 0) {
2050                         /*
2051                          *      Check permissions.
2052                          */
2053                         if (((co->mode & FR_WRITE) == 0) &&
2054                             ((table[i].mode & FR_WRITE) != 0)) {
2055                                 cprintf(listener, "ERROR: You do not have write permission.  See \"mode = rw\" in %s\n", co->path);
2056                                 goto do_next;
2057                         }
2058
2059                         if (table[i].table) {
2060                                 /*
2061                                  *      This is the last argument, but
2062                                  *      there's a sub-table.  Print help.
2063                                  *      
2064                                  */
2065                                 if (argc == 1) {
2066                                         table = table[i].table;
2067                                         goto do_help;
2068                                 }
2069
2070                                 argc--;
2071                                 argv++;
2072                                 table = table[i].table;
2073                                 goto retry;
2074                         }
2075
2076                         if ((argc == 2) && (strcmp(argv[1], "?") == 0)) goto do_help;
2077
2078                         if (!table[i].func) {
2079                                 cprintf(listener, "ERROR: Invalid command\n");
2080                                 goto do_next;
2081                         }
2082
2083                         len = 1;
2084                         rcode = table[i].func(listener,
2085                                               argc - 1, argv + 1);
2086                         break;
2087                 }
2088         }
2089
2090         /*
2091          *      No such command
2092          */
2093         if (!len) {
2094                 if ((strcmp(argv[0], "help") == 0) ||
2095                     (strcmp(argv[0], "?") == 0)) {
2096                         int recursive;
2097
2098                 do_help:
2099                         if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
2100                                 recursive = TRUE;
2101                         } else {
2102                                 recursive = FALSE;
2103                         }
2104
2105                         print_help(listener, table, recursive);
2106                         goto do_next;
2107                 }
2108
2109                 cprintf(listener, "ERROR: Unknown command \"%s\"\n",
2110                         argv[0]);
2111         }
2112
2113  do_next:
2114         cprintf(listener, "radmin> ");
2115
2116         if (co->next <= co->offset) {
2117                 co->offset = 0;
2118         } else {
2119                 memmove(co->buffer, co->buffer + co->next,
2120                         co->offset - co->next);
2121                 co->offset -= co->next;
2122         }
2123
2124         return 0;
2125 }
2126
2127
2128 static int command_domain_accept(rad_listen_t *listener,
2129                                  UNUSED RAD_REQUEST_FUNP *pfun,
2130                                  UNUSED REQUEST **prequest)
2131 {
2132         int newfd;
2133         uint32_t magic;
2134         rad_listen_t *this;
2135         socklen_t salen;
2136         struct sockaddr_storage src;
2137         fr_command_socket_t *sock = listener->data;
2138         
2139         salen = sizeof(src);
2140
2141         DEBUG2(" ... new connection request on command socket.");
2142
2143         *pfun = NULL;
2144         *prequest = NULL;
2145         
2146         newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
2147         if (newfd < 0) {
2148                 /*
2149                  *      Non-blocking sockets must handle this.
2150                  */
2151                 if (errno == EWOULDBLOCK) {
2152                         return 0;
2153                 }
2154
2155                 DEBUG2(" ... failed to accept connection.");
2156                 return 0;
2157         }
2158
2159         /*
2160          *      Perform user authentication.
2161          */
2162         if (sock->uid_name || sock->gid_name) {
2163                 uid_t uid;
2164                 gid_t gid;
2165
2166                 if (getpeereid(listener->fd, &uid, &gid) < 0) {
2167                         radlog(L_ERR, "Failed getting peer credentials for %s: %s",
2168                                sock->path, strerror(errno));
2169                         close(newfd);
2170                         return 0;
2171                 }
2172
2173                 if (sock->uid_name && (sock->uid != uid)) {
2174                         radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
2175                                sock->path, (long int) uid);
2176                         close(newfd);
2177                         return 0;
2178                 }
2179
2180                 if (sock->gid_name && (sock->gid != gid)) {
2181                         radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
2182                                sock->path, (long int) gid);
2183                         close(newfd);
2184                         return 0;
2185                 }
2186         }
2187
2188         /*
2189          *      Write 32-bit magic number && version information.
2190          */
2191         magic = htonl(0xf7eead15);
2192         if (write(newfd, &magic, 4) < 0) {
2193                 radlog(L_ERR, "Failed writing initial data to socket: %s",
2194                        strerror(errno));
2195                 close(newfd);
2196                 return 0;
2197         }
2198         magic = htonl(1);       /* protocol version */
2199         if (write(newfd, &magic, 4) < 0) {
2200                 radlog(L_ERR, "Failed writing initial data to socket: %s",
2201                        strerror(errno));
2202                 close(newfd);
2203                 return 0;
2204         }
2205
2206
2207         /*
2208          *      Add the new listener.
2209          */
2210         this = listen_alloc(listener->type);
2211         if (!this) return 0;
2212
2213         /*
2214          *      Copy everything, including the pointer to the socket
2215          *      information.
2216          */
2217         sock = this->data;
2218         memcpy(this, listener, sizeof(*this));
2219         this->status = RAD_LISTEN_STATUS_INIT;
2220         this->next = NULL;
2221         this->data = sock;      /* fix it back */
2222
2223         sock->offset = 0;
2224         sock->user[0] = '\0';
2225         sock->path = ((fr_command_socket_t *) listener->data)->path;
2226         sock->mode = ((fr_command_socket_t *) listener->data)->mode;
2227
2228         this->fd = newfd;
2229         this->recv = command_domain_recv;
2230
2231         /*
2232          *      Tell the event loop that we have a new FD
2233          */
2234         event_new_fd(this);
2235
2236         return 0;
2237 }
2238
2239
2240 /*
2241  *      Send an authentication response packet
2242  */
2243 static int command_domain_send(UNUSED rad_listen_t *listener,
2244                                UNUSED REQUEST *request)
2245 {
2246         return 0;
2247 }
2248
2249
2250 static int command_socket_encode(UNUSED rad_listen_t *listener,
2251                                  UNUSED REQUEST *request)
2252 {
2253         return 0;
2254 }
2255
2256
2257 static int command_socket_decode(UNUSED rad_listen_t *listener,
2258                                  UNUSED REQUEST *request)
2259 {
2260         return 0;
2261 }
2262
2263 #endif /* WITH_COMMAND_SOCKET */