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