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