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