Show debug settings
[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 #
29 #ifdef HAVE_SYS_UN_H
30 #include <sys/un.h>
31 #endif
32
33 #ifdef HAVE_SYS_STAT_H
34 #include <sys/stat.h>
35 #endif
36
37 #ifdef HAVE_PWD_H
38 #include <pwd.h>
39 #endif
40
41 #ifdef HAVE_GRP_H
42 #include <grp.h>
43 #endif
44
45 typedef struct fr_command_table_t fr_command_table_t;
46
47 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
48
49 struct fr_command_table_t {
50         const char *command;
51         const char *help;
52         fr_command_func_t func;
53         fr_command_table_t *table;
54 };
55
56 #define COMMAND_BUFFER_SIZE (1024)
57
58 typedef struct fr_command_socket_t {
59         char    *path;
60         uid_t   uid;
61         gid_t   gid;
62         char    *uid_name;
63         char    *gid_name;
64         char user[256];
65         ssize_t offset;
66         ssize_t next;
67         char buffer[COMMAND_BUFFER_SIZE];
68 } fr_command_socket_t;
69
70 static const CONF_PARSER command_config[] = {
71   { "socket",  PW_TYPE_STRING_PTR,
72     offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
73   { "uid",  PW_TYPE_STRING_PTR,
74     offsetof(fr_command_socket_t, uid_name), NULL, NULL},
75   { "gid",  PW_TYPE_STRING_PTR,
76     offsetof(fr_command_socket_t, gid_name), NULL, NULL},
77
78   { NULL, -1, 0, NULL, NULL }           /* end the list */
79 };
80
81 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
82 #ifdef __GNUC__
83                 __attribute__ ((format (printf, 2, 3)))
84 #endif
85 ;
86
87 #ifndef HAVE_GETPEEREID
88 static int getpeereid(int s, uid_t *euid, gid_t *egid)
89 {
90 #ifndef SO_PEERCRED
91         return -1;
92 #else
93         struct ucred cr;
94         socklen_t cl = sizeof(cr);
95         
96         if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
97                 return -1;
98         }
99
100         *euid = cr.uid;
101         *egid = cr.gid;
102         return 0;
103 #endif /* SO_PEERCRED */
104 }
105 #endif /* HAVE_GETPEEREID */
106
107
108 static int fr_server_domain_socket(const char *path)
109 {
110         int sockfd;
111         size_t len;
112         socklen_t socklen;
113         struct sockaddr_un salocal;
114         struct stat buf;
115
116         len = strlen(path);
117         if (len >= sizeof(salocal.sun_path)) {
118                 radlog(L_ERR, "Path too long in socket filename.");
119                 return -1;
120         }
121
122         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
123                 radlog(L_ERR, "Failed creating socket: %s",
124                         strerror(errno));
125                 return -1;
126         }
127
128         memset(&salocal, 0, sizeof(salocal));
129         salocal.sun_family = AF_UNIX;
130         memcpy(salocal.sun_path, path, len); /* not zero terminated */
131         
132         socklen = sizeof(salocal.sun_family) + len;
133
134         /*
135          *      Check the path.
136          */
137         if (stat(path, &buf) < 0) {
138                 if (errno != ENOENT) {
139                         radlog(L_ERR, "Failed to stat %s: %s",
140                                path, strerror(errno));
141                         return -1;
142                 }
143
144                 /*
145                  *      FIXME: Check the enclosing directory?
146                  */
147         } else {                /* it exists */
148                 if (!S_ISREG(buf.st_mode)
149 #ifdef S_ISSOCK
150                     && !S_ISSOCK(buf.st_mode)
151 #endif
152                         ) {
153                         radlog(L_ERR, "Cannot turn %s into socket", path);
154                         return -1;                     
155                 }
156
157                 /*
158                  *      Refuse to open sockets not owned by us.
159                  */
160                 if (buf.st_uid != geteuid()) {
161                         radlog(L_ERR, "We do not own %s", path);
162                         return -1;
163                 }
164
165                 if (unlink(path) < 0) {
166                         radlog(L_ERR, "Failed to delete %s: %s",
167                                path, strerror(errno));
168                         return -1;
169                 }
170         }
171
172         if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
173                 radlog(L_ERR, "Failed binding to %s: %s",
174                         path, strerror(errno));
175                 close(sockfd);
176                 return -1;
177         }
178
179         /*
180          *      FIXME: There's a race condition here.  But Linux
181          *      doesn't seem to permit fchmod on domain sockets.
182          */
183         if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
184                 radlog(L_ERR, "Failed setting permissions on %s: %s",
185                        path, strerror(errno));
186                 close(sockfd);
187                 return -1;
188         }
189
190         if (listen(sockfd, 8) < 0) {
191                 radlog(L_ERR, "Failed listening to %s: %s",
192                         path, strerror(errno));
193                 close(sockfd);
194                 return -1;
195         }
196
197 #ifdef O_NONBLOCK
198         {
199                 int flags;
200                 
201                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
202                         radlog(L_ERR, "Failure getting socket flags: %s",
203                                 strerror(errno));
204                         close(sockfd);
205                         return -1;
206                 }
207                 
208                 flags |= O_NONBLOCK;
209                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
210                         radlog(L_ERR, "Failure setting socket flags: %s",
211                                 strerror(errno));
212                         close(sockfd);
213                         return -1;
214                 }
215         }
216 #endif
217
218         return sockfd;
219 }
220
221
222 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
223 {
224         ssize_t len;
225         va_list ap;
226         char buffer[256];
227
228         va_start(ap, fmt);
229         len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
230         va_end(ap);
231
232         if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0;
233
234         len = write(listener->fd, buffer, len);
235         if (len < 0) {
236                 listener->status = RAD_LISTEN_STATUS_CLOSED;
237                 event_new_fd(listener);
238         }
239
240         /*
241          *      FIXME: Keep writing until done?
242          */
243         return len;
244 }
245
246 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
247 {
248         CONF_SECTION *cs;
249         module_instance_t *mi;
250
251         if (argc == 0) {
252                 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
253                 return 1;
254         }
255
256         cs = cf_section_find("modules");
257         if (!cs) return 0;
258
259         mi = find_module_instance(cs, argv[0], 0);
260         if (!mi) {
261                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
262                 return 0;
263         }
264
265         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
266                 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
267                         argv[0]);
268                 return 0;
269         }
270
271         if (!module_hup_module(mi->cs, mi, time(NULL))) {
272                 cprintf(listener, "ERROR: Failed to reload module\n");
273                 return 0;
274         }
275
276         return 1;               /* success */
277 }
278
279 static int command_terminate(UNUSED rad_listen_t *listener,
280                              UNUSED int argc, UNUSED char *argv[])
281 {
282         radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
283
284         return 1;               /* success */
285 }
286
287 extern time_t fr_start_time;
288
289 static int command_uptime(rad_listen_t *listener,
290                           UNUSED int argc, UNUSED char *argv[])
291 {
292         char buffer[128];
293
294         CTIME_R(&fr_start_time, buffer, sizeof(buffer));
295         cprintf(listener, "Up since %s", buffer); /* no \r\n */
296
297         return 1;               /* success */
298 }
299
300 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";
301
302 /*
303  *      FIXME: Recurse && indent?
304  */
305 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
306                                const void *base)
307                                
308 {
309         int i;
310         const void *data;
311         const char *name1 = cf_section_name1(cs);
312         const char *name2 = cf_section_name2(cs);
313         const CONF_PARSER *variables = cf_section_parse_table(cs);
314         char buffer[256];
315
316         if (name2) {
317                 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
318         } else {
319                 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
320         }
321
322         indent++;
323         
324         /*
325          *      Print
326          */
327         if (variables) for (i = 0; variables[i].name != NULL; i++) {
328                 /*
329                  *      No base struct offset, data must be the pointer.
330                  *      If data doesn't exist, ignore the entry, there
331                  *      must be something wrong.
332                  */
333                 if (!base) {
334                         if (!variables[i].data) {
335                                 continue;
336                         }
337                         
338                         data = variables[i].data;;
339                         
340                 } else if (variables[i].data) {
341                         data = variables[i].data;;
342                         
343                 } else {
344                         data = (((char *)base) + variables[i].offset);
345                 }
346
347                 switch (variables[i].type) {
348                 default:
349                         cprintf(listener, "%.*s%s = ?\n", indent, tabs,
350                                 variables[i].name);
351                         break;
352                         
353                 case PW_TYPE_INTEGER:
354                         cprintf(listener, "%.*s%s = %u\n", indent, tabs,
355                                 variables[i].name, *(int *) data);
356                         break;
357                         
358                 case PW_TYPE_IPADDR:
359                         inet_ntop(AF_INET, data, buffer, sizeof(buffer));
360                         break;
361
362                 case PW_TYPE_IPV6ADDR:
363                         inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
364                         break;
365
366                 case PW_TYPE_BOOLEAN:
367                         cprintf(listener, "%.*s%s = %s\n", indent, tabs,
368                                 variables[i].name, 
369                                 ((*(int *) data) == 0) ? "no" : "yes");
370                         break;
371                         
372                 case PW_TYPE_STRING_PTR:
373                 case PW_TYPE_FILENAME:
374                         /*
375                          *      FIXME: Escape things in the string!
376                          */
377                         if (*(char **) data) {
378                                 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
379                                         variables[i].name, *(char **) data);
380                         } else {
381                                 cprintf(listener, "%.*s%s = \n", indent, tabs,
382                                         variables[i].name);
383                         }
384                                 
385                         break;
386                 }
387         }
388
389         indent--;
390
391         cprintf(listener, "%.*s}\n", indent, tabs);
392 }
393
394 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
395 {
396         CONF_SECTION *cs;
397         module_instance_t *mi;
398
399         if (argc != 1) {
400                 cprintf(listener, "ERROR: No module name was given\n");
401                 return 0;
402         }
403
404         cs = cf_section_find("modules");
405         if (!cs) return 0;
406
407         mi = find_module_instance(cs, argv[0], 0);
408         if (!mi) {
409                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
410                 return 0;
411         }
412
413         cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
414
415         return 1;               /* success */
416 }
417
418 static const char *method_names[RLM_COMPONENT_COUNT] = {
419         "authenticate",
420         "authorize",
421         "preacct",
422         "accounting",
423         "session",
424         "pre-proxy",
425         "post-proxy",
426         "post-auth"
427 };
428
429
430 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
431 {
432         int i;
433         CONF_SECTION *cs;
434         const module_instance_t *mi;
435         const module_t *mod;
436
437         if (argc != 1) {
438                 cprintf(listener, "ERROR: No module name was given\n");
439                 return 0;
440         }
441
442         cs = cf_section_find("modules");
443         if (!cs) return 0;
444
445         mi = find_module_instance(cs, argv[0], 0);
446         if (!mi) {
447                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
448                 return 0;
449         }
450
451         mod = mi->entry->module;
452
453         for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
454                 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
455         }
456
457         return 1;               /* success */
458 }
459
460
461 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
462 {
463         CONF_SECTION *cs;
464         const module_instance_t *mi;
465         const module_t *mod;
466
467         if (argc != 1) {
468                 cprintf(listener, "ERROR: No module name was given\n");
469                 return 0;
470         }
471
472         cs = cf_section_find("modules");
473         if (!cs) return 0;
474
475         mi = find_module_instance(cs, argv[0], 0);
476         if (!mi) {
477                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
478                 return 0;
479         }
480
481         mod = mi->entry->module;
482
483         if ((mod->type & RLM_TYPE_THREAD_SAFE) != 0)
484                 cprintf(listener, "\tthread-safe\n");
485
486
487         if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
488                 cprintf(listener, "\twill-check-config\n");
489
490
491         if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
492                 cprintf(listener, "\treload-on-hup\n");
493
494         return 1;               /* success */
495 }
496
497
498 /*
499  *      Show all loaded modules
500  */
501 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
502 {
503         CONF_SECTION *cs, *subcs;
504
505         cs = cf_section_find("modules");
506         if (!cs) return 0;
507
508         subcs = NULL;
509         while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
510                 const char *name1 = cf_section_name1(subcs);
511                 const char *name2 = cf_section_name2(subcs);
512
513                 module_instance_t *mi;
514
515                 if (name2) {
516                         mi = find_module_instance(cs, name2, 0);
517                         if (!mi) continue;
518
519                         cprintf(listener, "\t%s (%s)\n", name2, name1);
520                 } else {
521                         mi = find_module_instance(cs, name1, 0);
522                         if (!mi) continue;
523
524                         cprintf(listener, "\t%s\n", name1);
525                 }
526         }
527
528         return 1;               /* success */
529 }
530
531 static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
532 {
533         CONF_ITEM *ci;
534         FILE *fp = fdopen(dup(listener->fd), "a");
535
536         if (!fp) {
537                 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
538                 return 0;
539         }
540
541         if (argc == 0) {
542                 cprintf(listener, "ERROR: <reference> is required\n");
543                 return 0;
544         }
545         
546         ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
547         if (!ci) {
548                 cprintf(listener, "ERROR: No such item <reference>\n");
549                 return 0;
550         }
551
552         if (cf_item_is_section(ci)) {
553                 cf_section2xml(fp, cf_itemtosection(ci));
554
555         } else if (cf_item_is_pair(ci)) {
556                 cf_pair2xml(fp, cf_itemtopair(ci));
557
558         } else {
559                 cprintf(listener, "ERROR: No such item <reference>\n");
560                 fclose(fp);
561                 return 0;
562         }
563
564         fclose(fp);
565
566         return 1;               /* success */
567 }
568
569 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
570 {
571         int number;
572
573         if (argc == 0) {
574                 cprintf(listener, "ERROR: Must specify <number>\n");
575                 return -1;
576         }
577
578         number = atoi(argv[0]);
579         if ((number < 0) || (number > 4)) {
580                 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
581                 return -1;
582         }
583
584         fr_debug_flag = debug_flag = number;
585
586         return 0;
587 }
588
589 extern char *debug_log_file;
590 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
591 {
592         if (argc == 0) {
593                 cprintf(listener, "ERROR: Must specify <filename>\n");
594                 return -1;
595         }
596
597         if (debug_log_file) {
598                 free(debug_log_file);
599                 debug_log_file = NULL;
600         }
601         debug_log_file = strdup(argv[0]);
602
603         return 0;
604 }
605
606 extern char *debug_condition;
607 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
608 {
609         /*
610          *      Delete old condition.
611          *
612          *      This is thread-safe because the condition is evaluated
613          *      in the main server thread, as is this code.
614          */
615         free(debug_condition);
616         debug_condition = NULL;
617
618         /*
619          *      Disable it.
620          */
621         if (argc == 0) {
622                 return 0;
623         }
624
625         debug_condition = strdup(argv[0]);
626
627         return 0;
628 }
629
630 static int command_show_debug_condition(rad_listen_t *listener,
631                                         UNUSED int argc, UNUSED char *argv[])
632 {
633         if (!debug_condition) return 0;
634
635         cprintf(listener, "%s\n", debug_condition);
636         return 0;
637 }
638
639
640 static int command_show_debug_file(rad_listen_t *listener,
641                                         UNUSED int argc, UNUSED char *argv[])
642 {
643         if (!debug_log_file) return 0;
644
645         cprintf(listener, "%s\n", debug_log_file);
646         return 0;
647 }
648
649
650 static int command_show_debug_level(rad_listen_t *listener,
651                                         UNUSED int argc, UNUSED char *argv[])
652 {
653         cprintf(listener, "%d\n", debug_flag);
654         return 0;
655 }
656
657
658 static fr_command_table_t command_table_debug[] = {
659         { "condition",
660           "debug condition <condition> - Enable debugging for requests matching <condition>",
661           command_debug_condition, NULL },
662
663         { "level",
664           "debug level <number> - Set debug level to <number>.  Higher is more debugging.",
665           command_debug_level, NULL },
666
667         { "file",
668           "debug file <filename> - Send all debuggin output to <filename>",
669           command_debug_file, NULL },
670
671         { NULL, NULL, NULL, NULL }
672 };
673
674 static fr_command_table_t command_table_show_debug[] = {
675         { "condition",
676           "show debug condition - Shows current debugging condition.",
677           command_show_debug_condition, NULL },
678
679         { "level",
680           "show debug level - Shows current debugging level.",
681           command_show_debug_level, NULL },
682
683         { "file",
684           "show debug file - Shows current debugging file.",
685           command_show_debug_file, NULL },
686
687
688         { NULL, NULL, NULL, NULL }
689 };
690
691 static fr_command_table_t command_table_show_module[] = {
692         { "config",
693           "show module config <module> - show configuration for <module>",
694           command_show_module_config, NULL },
695         { "flags",
696           "show module flags <module> - show other module properties",
697           command_show_module_flags, NULL },
698         { "list",
699           "shows list of loaded modules",
700           command_show_modules, NULL },
701         { "methods",
702           "show module methods <module> - show sections where <module> may be used",
703           command_show_module_methods, NULL },
704
705         { NULL, NULL, NULL, NULL }
706 };
707
708
709 static fr_command_table_t command_table_show[] = {
710         { "config",
711           "show config <module> - show configuration for module",
712           command_show_module_config, NULL },
713         { "debug",
714           "show debug <command> - show debug properties",
715           NULL, command_table_show_debug },
716         { "module",
717           "show module <command> - do sub-command of module",
718           NULL, command_table_show_module },
719         { "modules",
720           "show modules - shows list of loaded modules",
721           command_show_modules, NULL },
722         { "uptime",
723           "show uptime - shows time at which server started",
724           command_uptime, NULL },
725         { "xml",
726           "show xml <reference> - Prints out configuration as XML",
727           command_show_xml, NULL },
728         { NULL, NULL, NULL, NULL }
729 };
730
731
732 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
733 {
734         int i, rcode;
735         CONF_PAIR *cp;
736         CONF_SECTION *cs;
737         module_instance_t *mi;
738         const CONF_PARSER *variables;
739         void *data;
740
741         if (argc < 3) {
742                 cprintf(listener, "ERROR: No module name or variable was given\n");
743                 return 0;
744         }
745
746         cs = cf_section_find("modules");
747         if (!cs) return 0;
748
749         mi = find_module_instance(cs, argv[0], 0);
750         if (!mi) {
751                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
752                 return 0;
753         }
754
755         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
756                 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
757                 return 0;
758         }
759
760         variables = cf_section_parse_table(mi->cs);
761         if (!variables) {
762                 cprintf(listener, "ERROR: Cannot find configuration for module\n");
763                 return 0;
764         }
765
766         rcode = -1;
767         for (i = 0; variables[i].name != NULL; i++) {
768                 /*
769                  *      FIXME: Recurse into sub-types somehow...
770                  */
771                 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
772
773                 if (strcmp(variables[i].name, argv[1]) == 0) {
774                         rcode = i;
775                         break;
776                 }
777         }
778
779         if (rcode < 0) {
780                 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
781                 return 0;
782         }
783
784         i = rcode;              /* just to be safe */
785
786         /*
787          *      It's not part of the dynamic configuration.  The module
788          *      needs to re-parse && validate things.
789          */
790         if (variables[i].data) {
791                 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
792                 return 0;
793         }
794
795         data = ((char *) mi->insthandle) + variables[i].offset;
796
797         cp = cf_pair_find(mi->cs, argv[1]);
798         if (!cp) return 0;
799
800         /*
801          *      Replace the OLD value in the configuration file with
802          *      the NEW value.
803          *
804          *      FIXME: Parse argv[2] depending on it's data type!
805          *      If it's a string, look for leading single/double quotes,
806          *      end then call tokenize functions???
807          */
808         cf_pair_replace(mi->cs, cp, argv[2]);
809
810         rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
811                               data, argv[2]);
812         if (rcode < 0) {
813                 cprintf(listener, "ERROR: Failed to parse value\n");
814                 return 0;
815         }
816
817         return 1;               /* success */
818 }
819
820
821 static fr_command_table_t command_table_set_module[] = {
822         { "config",
823           "set module config <module> variable value - set configuration for <module>",
824           command_set_module_config, NULL },
825
826         { NULL, NULL, NULL, NULL }
827 };
828
829
830 static fr_command_table_t command_table_set[] = {
831         { "module", NULL, NULL, command_table_set_module },
832
833         { NULL, NULL, NULL, NULL }
834 };
835
836
837 static fr_command_table_t command_table[] = {
838         { "debug",
839           "debug <command> - debugging commands",
840           NULL, command_table_debug },
841         { "hup",
842           "hup [module] - sends a HUP signal to the server, or optionally to one module",
843           command_hup, NULL },
844         { "terminate",
845           "terminate - terminates the server, and causes it to exit",
846           command_terminate, NULL },
847         { "show", NULL, NULL, command_table_show },
848         { "set", NULL, NULL, command_table_set },
849
850         { NULL, NULL, NULL, NULL }
851 };
852
853
854 /*
855  *      FIXME: Unix domain sockets!
856  */
857 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
858 {
859         fr_command_socket_t *sock;
860
861         sock = this->data;
862
863         if (cf_section_parse(cs, sock, command_config) < 0) {
864                 return -1;
865         }
866
867 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
868         if (sock->uid_name) {
869                 struct passwd *pw;
870                 
871                 pw = getpwnam(sock->uid_name);
872                 if (!pw) {
873                         radlog(L_ERR, "Failed getting uid for %s: %s",
874                                sock->uid_name, strerror(errno));
875                         return -1;
876                 }
877
878                 sock->uid = pw->pw_uid;
879         }
880
881         if (sock->gid_name) {
882                 struct group *gr;
883
884                 gr = getgrnam(sock->gid_name);
885                 if (!gr) {
886                         radlog(L_ERR, "Failed getting gid for %s: %s",
887                                sock->gid_name, strerror(errno));
888                         return -1;
889                 }
890                 sock->gid = gr->gr_gid; 
891         }
892
893 #else  /* can't get uid or gid of connecting user */
894
895         if (sock->uid_name || sock->gid_name) {
896                 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
897                 return -1;
898         }
899
900 #endif
901
902         /*
903          *      FIXME: check for absolute pathnames?
904          *      check for uid/gid on the other end...    
905          */
906
907         this->fd = fr_server_domain_socket(sock->path);
908         if (this->fd < 0) {
909                 return -1;
910         }
911
912         return 0;
913 }
914
915 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
916 {
917         fr_command_socket_t *sock = this->data;
918
919         snprintf(buffer, bufsize, "command file %s", sock->path);
920         return 1;
921 }
922
923
924 /*
925  *      String split routine.  Splits an input string IN PLACE
926  *      into pieces, based on spaces.
927  */
928 static int str2argv(char *str, char **argv, int max_argc)
929 {
930         int argc = 0;
931         size_t len;
932         char buffer[1024];
933
934         while (*str) {
935                 if (argc >= max_argc) return argc;
936
937                 /*
938                  *      Chop out comments early.
939                  */
940                 if (*str == '#') {
941                         *str = '\0';
942                         break;
943                 }
944
945                 while ((*str == ' ') ||
946                        (*str == '\t') ||
947                        (*str == '\r') ||
948                        (*str == '\n')) *(str++) = '\0';
949
950                 if (!*str) return argc;
951
952                 if ((*str == '\'') || (*str == '"')) {
953                         char *p = str;
954                         FR_TOKEN token;
955
956                         token = gettoken((const char **) &p, buffer,
957                                          sizeof(buffer));
958                         if ((token != T_SINGLE_QUOTED_STRING) &&
959                             (token != T_DOUBLE_QUOTED_STRING)) {
960                                 return -1;
961                         }
962
963                         len = strlen(buffer);
964                         if (len >= (size_t) (p - str)) {
965                                 return -1;
966                         }
967
968                         memcpy(str, buffer, len + 1);
969                         argv[argc] = str;
970                         str = p;
971
972                 } else {
973                         argv[argc] = str;
974                 }
975                 argc++;
976
977                 while (*str &&
978                        (*str != ' ') &&
979                        (*str != '\t') &&
980                        (*str != '\r') &&
981                        (*str != '\n')) str++;
982         }
983
984         return argc;
985 }
986
987 #define MAX_ARGV (16)
988
989 /*
990  *      Check if an incoming request is "ok"
991  *
992  *      It takes packets, not requests.  It sees if the packet looks
993  *      OK.  If so, it does a number of sanity checks on it.
994  */
995 static int command_domain_recv(rad_listen_t *listener,
996                                UNUSED RAD_REQUEST_FUNP *pfun,
997                                UNUSED REQUEST **prequest)
998 {
999         int i, rcode;
1000         ssize_t len;
1001         int argc;
1002         char *my_argv[MAX_ARGV], **argv;
1003         fr_command_table_t *table;
1004         fr_command_socket_t *co = listener->data;
1005
1006         *pfun = NULL;
1007         *prequest = NULL;
1008
1009         do {
1010                 ssize_t c;
1011                 char *p;
1012
1013                 len = recv(listener->fd, co->buffer + co->offset,
1014                            sizeof(co->buffer) - co->offset - 1, 0);
1015                 if (len == 0) goto close_socket; /* clean close */
1016
1017                 if (len < 0) {
1018                         if ((errno == EAGAIN) || (errno == EINTR)) {
1019                                 return 0;
1020                         }
1021                         goto close_socket;
1022                 }
1023
1024                 /*
1025                  *      CTRL-D
1026                  */
1027                 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1028                 close_socket:
1029                         listener->status = RAD_LISTEN_STATUS_CLOSED;
1030                         event_new_fd(listener);
1031                         return 0;
1032                 }
1033
1034                 /*
1035                  *      See if there are multiple lines in the buffer.
1036                  */
1037                 p = co->buffer + co->offset;
1038                 rcode = 0;
1039                 p[len] = '\0';
1040                 for (c = 0; c < len; c++) {
1041                         if ((*p == '\r') || (*p == '\n')) {
1042                                 rcode = 1;
1043                                 *p = '\0';
1044
1045                                 /*
1046                                  *      FIXME: do real buffering...
1047                                  *      handling of CTRL-C, etc.
1048                                  */
1049
1050                         } else if (rcode) {
1051                                 /*
1052                                  *      \r \n followed by ASCII...
1053                                  */
1054                                 break;
1055                         }
1056
1057                         p++;
1058                 }
1059
1060                 co->offset += len;
1061
1062                 /*
1063                  *      Saw CR/LF.  Set next element, and exit.
1064                  */
1065                 if (rcode) {
1066                         co->next = p - co->buffer;
1067                         break;
1068                 }
1069
1070                 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1071                         radlog(L_ERR, "Line too long!");
1072                         goto close_socket;
1073                 }
1074
1075                 co->offset++;
1076         } while (1);
1077
1078         argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1079         if (argc == 0) goto do_next; /* empty strings are OK */
1080
1081         if (argc < 0) {
1082                 cprintf(listener, "ERROR: Failed parsing command.\n");
1083                 goto do_next;
1084         }
1085
1086         argv = my_argv;
1087
1088         for (len = 0; len <= co->offset; len++) {
1089                 if (co->buffer[len] < 0x20) {
1090                         co->buffer[len] = '\0';
1091                         break;
1092                 }
1093         }
1094
1095         /*
1096          *      Hard-code exit && quit.
1097          */
1098         if ((strcmp(argv[0], "exit") == 0) ||
1099             (strcmp(argv[0], "quit") == 0)) goto close_socket;
1100
1101 #if 0
1102         if (!co->user[0]) {
1103                 if (strcmp(argv[0], "login") != 0) {
1104                         cprintf(listener, "ERROR: Login required\n");
1105                         goto do_next;
1106                 }
1107
1108                 if (argc < 3) {
1109                         cprintf(listener, "ERROR: login <user> <password>\n");
1110                         goto do_next;
1111                 }
1112
1113                 /*
1114                  *      FIXME: Generate && process fake RADIUS request.
1115                  */
1116                 if ((strcmp(argv[1], "root") == 0) &&
1117                     (strcmp(argv[2], "password") == 0)) {
1118                         strlcpy(co->user, argv[1], sizeof(co->user));
1119                         goto do_next;
1120                 }
1121
1122                 cprintf(listener, "ERROR: Login incorrect\n");
1123                 goto do_next;
1124         }
1125 #endif
1126
1127         table = command_table;
1128  retry:
1129         len = 0;
1130         for (i = 0; table[i].command != NULL; i++) {
1131                 if (strcmp(table[i].command, argv[0]) == 0) {
1132                         if (table[i].table) {
1133                                 /*
1134                                  *      This is the last argument, but
1135                                  *      there's a sub-table.  Print help.
1136                                  *      
1137                                  */
1138                                 if (argc == 1) {
1139                                         table = table[i].table;
1140                                         goto do_help;
1141                                 }
1142
1143                                 argc--;
1144                                 argv++;
1145                                 table = table[i].table;
1146                                 goto retry;
1147                         }
1148
1149                         len = 1;
1150                         rcode = table[i].func(listener,
1151                                               argc - 1, argv + 1);
1152                         break;
1153                 }
1154         }
1155
1156         /*
1157          *      No such command
1158          */
1159         if (!len) {
1160                 if ((strcmp(argv[0], "help") == 0) ||
1161                     (strcmp(argv[0], "?") == 0)) {
1162                 do_help:
1163                         for (i = 0; table[i].command != NULL; i++) {
1164                                 if (table[i].help) {
1165                                         cprintf(listener, "%s\n",
1166                                                 table[i].help);
1167                                 } else {
1168                                         cprintf(listener, "%s <command> - do sub-command of %s\n",
1169                                                 table[i].command, table[i].command);
1170                                 }
1171                         }
1172                         goto do_next;
1173                 }
1174
1175                 cprintf(listener, "ERROR: Unknown command \"%s\"\r\n",
1176                         argv[0]);
1177         }
1178
1179  do_next:
1180         cprintf(listener, "radmin> ");
1181
1182         if (co->next <= co->offset) {
1183                 co->offset = 0;
1184         } else {
1185                 memmove(co->buffer, co->buffer + co->next,
1186                         co->offset - co->next);
1187                 co->offset -= co->next;
1188         }
1189
1190         return 0;
1191 }
1192
1193
1194 static int command_domain_accept(rad_listen_t *listener,
1195                                  UNUSED RAD_REQUEST_FUNP *pfun,
1196                                  UNUSED REQUEST **prequest)
1197 {
1198         int newfd;
1199         uint32_t magic;
1200         rad_listen_t *this;
1201         socklen_t salen;
1202         struct sockaddr_storage src;
1203         fr_command_socket_t *sock = listener->data;
1204         
1205         salen = sizeof(src);
1206
1207         DEBUG2(" ... new connection request on command socket.");
1208         
1209         newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
1210         if (newfd < 0) {
1211                 /*
1212                  *      Non-blocking sockets must handle this.
1213                  */
1214                 if (errno == EWOULDBLOCK) {
1215                         return 0;
1216                 }
1217
1218                 DEBUG2(" ... failed to accept connection.");
1219                 return -1;
1220         }
1221
1222         /*
1223          *      Perform user authentication.
1224          */
1225         if (sock->uid_name || sock->gid_name) {
1226                 uid_t uid;
1227                 gid_t gid;
1228
1229                 if (getpeereid(listener->fd, &uid, &gid) < 0) {
1230                         radlog(L_ERR, "Failed getting peer credentials for %s: %s",
1231                                sock->path, strerror(errno));
1232                         close(newfd);
1233                         return -1;
1234                 }
1235
1236                 if (sock->uid_name && (sock->uid != uid)) {
1237                         radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
1238                                sock->path, (long int) uid);
1239                         close(newfd);
1240                         return -1;
1241                 }
1242
1243                 if (sock->gid_name && (sock->gid != gid)) {
1244                         radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
1245                                sock->path, (long int) gid);
1246                         close(newfd);
1247                         return -1;
1248                 }
1249         }
1250
1251         /*
1252          *      Write 32-bit magic number && version information.
1253          */
1254         magic = htonl(0xf7eead15);
1255         if (write(newfd, &magic, 4) < 0) {
1256                 radlog(L_ERR, "Failed writing initial data to socket: %s",
1257                        strerror(errno));
1258                 close(newfd);
1259                 return -1;
1260         }
1261         magic = htonl(1);       /* protocol version */
1262         if (write(newfd, &magic, 4) < 0) {
1263                 radlog(L_ERR, "Failed writing initial data to socket: %s",
1264                        strerror(errno));
1265                 close(newfd);
1266                 return -1;
1267         }
1268
1269
1270         /*
1271          *      Add the new listener.
1272          */
1273         this = listen_alloc(listener->type);
1274         if (!this) return -1;
1275
1276         /*
1277          *      Copy everything, including the pointer to the socket
1278          *      information.
1279          */
1280         sock = this->data;
1281         memcpy(this, listener, sizeof(*this));
1282         this->status = RAD_LISTEN_STATUS_INIT;
1283         this->next = NULL;
1284         this->data = sock;      /* fix it back */
1285
1286         sock->offset = 0;
1287         sock->user[0] = '\0';
1288         sock->path = ((fr_command_socket_t *) listener->data)->path;
1289
1290         this->fd = newfd;
1291         this->recv = command_domain_recv;
1292
1293         /*
1294          *      Tell the event loop that we have a new FD
1295          */
1296         event_new_fd(this);
1297
1298         return 0;
1299 }
1300
1301
1302 /*
1303  *      Send an authentication response packet
1304  */
1305 static int command_domain_send(UNUSED rad_listen_t *listener,
1306                                UNUSED REQUEST *request)
1307 {
1308         return 0;
1309 }
1310
1311
1312 static int command_socket_encode(UNUSED rad_listen_t *listener,
1313                                  UNUSED REQUEST *request)
1314 {
1315         return 0;
1316 }
1317
1318
1319 static int command_socket_decode(UNUSED rad_listen_t *listener,
1320                                  UNUSED REQUEST *request)
1321 {
1322         return 0;
1323 }
1324
1325 #endif /* WITH_COMMAND_SOCKET */