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