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