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