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