Debug packets only if NOT in debugging mode.
[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_flag && mainconfig.radlog_dest == RADLOG_STDOUT) {
598                 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
599                 return -1;
600         }
601
602         if (debug_log_file) {
603                 free(debug_log_file);
604                 debug_log_file = NULL;
605         }
606         debug_log_file = strdup(argv[0]);
607
608         return 0;
609 }
610
611 extern char *debug_condition;
612 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
613 {
614         /*
615          *      Delete old condition.
616          *
617          *      This is thread-safe because the condition is evaluated
618          *      in the main server thread, as is this code.
619          */
620         free(debug_condition);
621         debug_condition = NULL;
622
623         /*
624          *      Disable it.
625          */
626         if (argc == 0) {
627                 return 0;
628         }
629
630         debug_condition = strdup(argv[0]);
631
632         return 0;
633 }
634
635 static int command_show_debug_condition(rad_listen_t *listener,
636                                         UNUSED int argc, UNUSED char *argv[])
637 {
638         if (!debug_condition) return 0;
639
640         cprintf(listener, "%s\n", debug_condition);
641         return 0;
642 }
643
644
645 static int command_show_debug_file(rad_listen_t *listener,
646                                         UNUSED int argc, UNUSED char *argv[])
647 {
648         if (!debug_log_file) return 0;
649
650         cprintf(listener, "%s\n", debug_log_file);
651         return 0;
652 }
653
654
655 static int command_show_debug_level(rad_listen_t *listener,
656                                         UNUSED int argc, UNUSED char *argv[])
657 {
658         cprintf(listener, "%d\n", debug_flag);
659         return 0;
660 }
661
662
663 static fr_command_table_t command_table_debug[] = {
664         { "condition",
665           "debug condition <condition> - Enable debugging for requests matching <condition>",
666           command_debug_condition, NULL },
667
668         { "level",
669           "debug level <number> - Set debug level to <number>.  Higher is more debugging.",
670           command_debug_level, NULL },
671
672         { "file",
673           "debug file <filename> - Send all debuggin output to <filename>",
674           command_debug_file, NULL },
675
676         { NULL, NULL, NULL, NULL }
677 };
678
679 static fr_command_table_t command_table_show_debug[] = {
680         { "condition",
681           "show debug condition - Shows current debugging condition.",
682           command_show_debug_condition, NULL },
683
684         { "level",
685           "show debug level - Shows current debugging level.",
686           command_show_debug_level, NULL },
687
688         { "file",
689           "show debug file - Shows current debugging file.",
690           command_show_debug_file, NULL },
691
692
693         { NULL, NULL, NULL, NULL }
694 };
695
696 static fr_command_table_t command_table_show_module[] = {
697         { "config",
698           "show module config <module> - show configuration for <module>",
699           command_show_module_config, NULL },
700         { "flags",
701           "show module flags <module> - show other module properties",
702           command_show_module_flags, NULL },
703         { "list",
704           "shows list of loaded modules",
705           command_show_modules, NULL },
706         { "methods",
707           "show module methods <module> - show sections where <module> may be used",
708           command_show_module_methods, NULL },
709
710         { NULL, NULL, NULL, NULL }
711 };
712
713
714 static fr_command_table_t command_table_show[] = {
715         { "config",
716           "show config <module> - show configuration for module",
717           command_show_module_config, NULL },
718         { "debug",
719           "show debug <command> - show debug properties",
720           NULL, command_table_show_debug },
721         { "module",
722           "show module <command> - do sub-command of module",
723           NULL, command_table_show_module },
724         { "modules",
725           "show modules - shows list of loaded modules",
726           command_show_modules, NULL },
727         { "uptime",
728           "show uptime - shows time at which server started",
729           command_uptime, NULL },
730         { "xml",
731           "show xml <reference> - Prints out configuration as XML",
732           command_show_xml, NULL },
733         { NULL, NULL, NULL, NULL }
734 };
735
736
737 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
738 {
739         int i, rcode;
740         CONF_PAIR *cp;
741         CONF_SECTION *cs;
742         module_instance_t *mi;
743         const CONF_PARSER *variables;
744         void *data;
745
746         if (argc < 3) {
747                 cprintf(listener, "ERROR: No module name or variable was given\n");
748                 return 0;
749         }
750
751         cs = cf_section_find("modules");
752         if (!cs) return 0;
753
754         mi = find_module_instance(cs, argv[0], 0);
755         if (!mi) {
756                 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
757                 return 0;
758         }
759
760         if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
761                 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
762                 return 0;
763         }
764
765         variables = cf_section_parse_table(mi->cs);
766         if (!variables) {
767                 cprintf(listener, "ERROR: Cannot find configuration for module\n");
768                 return 0;
769         }
770
771         rcode = -1;
772         for (i = 0; variables[i].name != NULL; i++) {
773                 /*
774                  *      FIXME: Recurse into sub-types somehow...
775                  */
776                 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
777
778                 if (strcmp(variables[i].name, argv[1]) == 0) {
779                         rcode = i;
780                         break;
781                 }
782         }
783
784         if (rcode < 0) {
785                 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
786                 return 0;
787         }
788
789         i = rcode;              /* just to be safe */
790
791         /*
792          *      It's not part of the dynamic configuration.  The module
793          *      needs to re-parse && validate things.
794          */
795         if (variables[i].data) {
796                 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
797                 return 0;
798         }
799
800         data = ((char *) mi->insthandle) + variables[i].offset;
801
802         cp = cf_pair_find(mi->cs, argv[1]);
803         if (!cp) return 0;
804
805         /*
806          *      Replace the OLD value in the configuration file with
807          *      the NEW value.
808          *
809          *      FIXME: Parse argv[2] depending on it's data type!
810          *      If it's a string, look for leading single/double quotes,
811          *      end then call tokenize functions???
812          */
813         cf_pair_replace(mi->cs, cp, argv[2]);
814
815         rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
816                               data, argv[2]);
817         if (rcode < 0) {
818                 cprintf(listener, "ERROR: Failed to parse value\n");
819                 return 0;
820         }
821
822         return 1;               /* success */
823 }
824
825
826 static fr_command_table_t command_table_set_module[] = {
827         { "config",
828           "set module config <module> variable value - set configuration for <module>",
829           command_set_module_config, NULL },
830
831         { NULL, NULL, NULL, NULL }
832 };
833
834
835 static fr_command_table_t command_table_set[] = {
836         { "module", NULL, NULL, command_table_set_module },
837
838         { NULL, NULL, NULL, NULL }
839 };
840
841
842 static fr_command_table_t command_table[] = {
843         { "debug",
844           "debug <command> - debugging commands",
845           NULL, command_table_debug },
846         { "hup",
847           "hup [module] - sends a HUP signal to the server, or optionally to one module",
848           command_hup, NULL },
849         { "terminate",
850           "terminate - terminates the server, and causes it to exit",
851           command_terminate, NULL },
852         { "show", NULL, NULL, command_table_show },
853         { "set", NULL, NULL, command_table_set },
854
855         { NULL, NULL, NULL, NULL }
856 };
857
858
859 /*
860  *      FIXME: Unix domain sockets!
861  */
862 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
863 {
864         fr_command_socket_t *sock;
865
866         sock = this->data;
867
868         if (cf_section_parse(cs, sock, command_config) < 0) {
869                 return -1;
870         }
871
872 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
873         if (sock->uid_name) {
874                 struct passwd *pw;
875                 
876                 pw = getpwnam(sock->uid_name);
877                 if (!pw) {
878                         radlog(L_ERR, "Failed getting uid for %s: %s",
879                                sock->uid_name, strerror(errno));
880                         return -1;
881                 }
882
883                 sock->uid = pw->pw_uid;
884         }
885
886         if (sock->gid_name) {
887                 struct group *gr;
888
889                 gr = getgrnam(sock->gid_name);
890                 if (!gr) {
891                         radlog(L_ERR, "Failed getting gid for %s: %s",
892                                sock->gid_name, strerror(errno));
893                         return -1;
894                 }
895                 sock->gid = gr->gr_gid; 
896         }
897
898 #else  /* can't get uid or gid of connecting user */
899
900         if (sock->uid_name || sock->gid_name) {
901                 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
902                 return -1;
903         }
904
905 #endif
906
907         /*
908          *      FIXME: check for absolute pathnames?
909          *      check for uid/gid on the other end...    
910          */
911
912         this->fd = fr_server_domain_socket(sock->path);
913         if (this->fd < 0) {
914                 return -1;
915         }
916
917         return 0;
918 }
919
920 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
921 {
922         fr_command_socket_t *sock = this->data;
923
924         snprintf(buffer, bufsize, "command file %s", sock->path);
925         return 1;
926 }
927
928
929 /*
930  *      String split routine.  Splits an input string IN PLACE
931  *      into pieces, based on spaces.
932  */
933 static int str2argv(char *str, char **argv, int max_argc)
934 {
935         int argc = 0;
936         size_t len;
937         char buffer[1024];
938
939         while (*str) {
940                 if (argc >= max_argc) return argc;
941
942                 /*
943                  *      Chop out comments early.
944                  */
945                 if (*str == '#') {
946                         *str = '\0';
947                         break;
948                 }
949
950                 while ((*str == ' ') ||
951                        (*str == '\t') ||
952                        (*str == '\r') ||
953                        (*str == '\n')) *(str++) = '\0';
954
955                 if (!*str) return argc;
956
957                 if ((*str == '\'') || (*str == '"')) {
958                         char *p = str;
959                         FR_TOKEN token;
960
961                         token = gettoken((const char **) &p, buffer,
962                                          sizeof(buffer));
963                         if ((token != T_SINGLE_QUOTED_STRING) &&
964                             (token != T_DOUBLE_QUOTED_STRING)) {
965                                 return -1;
966                         }
967
968                         len = strlen(buffer);
969                         if (len >= (size_t) (p - str)) {
970                                 return -1;
971                         }
972
973                         memcpy(str, buffer, len + 1);
974                         argv[argc] = str;
975                         str = p;
976
977                 } else {
978                         argv[argc] = str;
979                 }
980                 argc++;
981
982                 while (*str &&
983                        (*str != ' ') &&
984                        (*str != '\t') &&
985                        (*str != '\r') &&
986                        (*str != '\n')) str++;
987         }
988
989         return argc;
990 }
991
992 #define MAX_ARGV (16)
993
994 /*
995  *      Check if an incoming request is "ok"
996  *
997  *      It takes packets, not requests.  It sees if the packet looks
998  *      OK.  If so, it does a number of sanity checks on it.
999  */
1000 static int command_domain_recv(rad_listen_t *listener,
1001                                UNUSED RAD_REQUEST_FUNP *pfun,
1002                                UNUSED REQUEST **prequest)
1003 {
1004         int i, rcode;
1005         ssize_t len;
1006         int argc;
1007         char *my_argv[MAX_ARGV], **argv;
1008         fr_command_table_t *table;
1009         fr_command_socket_t *co = listener->data;
1010
1011         *pfun = NULL;
1012         *prequest = NULL;
1013
1014         do {
1015                 ssize_t c;
1016                 char *p;
1017
1018                 len = recv(listener->fd, co->buffer + co->offset,
1019                            sizeof(co->buffer) - co->offset - 1, 0);
1020                 if (len == 0) goto close_socket; /* clean close */
1021
1022                 if (len < 0) {
1023                         if ((errno == EAGAIN) || (errno == EINTR)) {
1024                                 return 0;
1025                         }
1026                         goto close_socket;
1027                 }
1028
1029                 /*
1030                  *      CTRL-D
1031                  */
1032                 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1033                 close_socket:
1034                         listener->status = RAD_LISTEN_STATUS_CLOSED;
1035                         event_new_fd(listener);
1036                         return 0;
1037                 }
1038
1039                 /*
1040                  *      See if there are multiple lines in the buffer.
1041                  */
1042                 p = co->buffer + co->offset;
1043                 rcode = 0;
1044                 p[len] = '\0';
1045                 for (c = 0; c < len; c++) {
1046                         if ((*p == '\r') || (*p == '\n')) {
1047                                 rcode = 1;
1048                                 *p = '\0';
1049
1050                                 /*
1051                                  *      FIXME: do real buffering...
1052                                  *      handling of CTRL-C, etc.
1053                                  */
1054
1055                         } else if (rcode) {
1056                                 /*
1057                                  *      \r \n followed by ASCII...
1058                                  */
1059                                 break;
1060                         }
1061
1062                         p++;
1063                 }
1064
1065                 co->offset += len;
1066
1067                 /*
1068                  *      Saw CR/LF.  Set next element, and exit.
1069                  */
1070                 if (rcode) {
1071                         co->next = p - co->buffer;
1072                         break;
1073                 }
1074
1075                 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1076                         radlog(L_ERR, "Line too long!");
1077                         goto close_socket;
1078                 }
1079
1080                 co->offset++;
1081         } while (1);
1082
1083         argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1084         if (argc == 0) goto do_next; /* empty strings are OK */
1085
1086         if (argc < 0) {
1087                 cprintf(listener, "ERROR: Failed parsing command.\n");
1088                 goto do_next;
1089         }
1090
1091         argv = my_argv;
1092
1093         for (len = 0; len <= co->offset; len++) {
1094                 if (co->buffer[len] < 0x20) {
1095                         co->buffer[len] = '\0';
1096                         break;
1097                 }
1098         }
1099
1100         /*
1101          *      Hard-code exit && quit.
1102          */
1103         if ((strcmp(argv[0], "exit") == 0) ||
1104             (strcmp(argv[0], "quit") == 0)) goto close_socket;
1105
1106 #if 0
1107         if (!co->user[0]) {
1108                 if (strcmp(argv[0], "login") != 0) {
1109                         cprintf(listener, "ERROR: Login required\n");
1110                         goto do_next;
1111                 }
1112
1113                 if (argc < 3) {
1114                         cprintf(listener, "ERROR: login <user> <password>\n");
1115                         goto do_next;
1116                 }
1117
1118                 /*
1119                  *      FIXME: Generate && process fake RADIUS request.
1120                  */
1121                 if ((strcmp(argv[1], "root") == 0) &&
1122                     (strcmp(argv[2], "password") == 0)) {
1123                         strlcpy(co->user, argv[1], sizeof(co->user));
1124                         goto do_next;
1125                 }
1126
1127                 cprintf(listener, "ERROR: Login incorrect\n");
1128                 goto do_next;
1129         }
1130 #endif
1131
1132         table = command_table;
1133  retry:
1134         len = 0;
1135         for (i = 0; table[i].command != NULL; i++) {
1136                 if (strcmp(table[i].command, argv[0]) == 0) {
1137                         if (table[i].table) {
1138                                 /*
1139                                  *      This is the last argument, but
1140                                  *      there's a sub-table.  Print help.
1141                                  *      
1142                                  */
1143                                 if (argc == 1) {
1144                                         table = table[i].table;
1145                                         goto do_help;
1146                                 }
1147
1148                                 argc--;
1149                                 argv++;
1150                                 table = table[i].table;
1151                                 goto retry;
1152                         }
1153
1154                         len = 1;
1155                         rcode = table[i].func(listener,
1156                                               argc - 1, argv + 1);
1157                         break;
1158                 }
1159         }
1160
1161         /*
1162          *      No such command
1163          */
1164         if (!len) {
1165                 if ((strcmp(argv[0], "help") == 0) ||
1166                     (strcmp(argv[0], "?") == 0)) {
1167                 do_help:
1168                         for (i = 0; table[i].command != NULL; i++) {
1169                                 if (table[i].help) {
1170                                         cprintf(listener, "%s\n",
1171                                                 table[i].help);
1172                                 } else {
1173                                         cprintf(listener, "%s <command> - do sub-command of %s\n",
1174                                                 table[i].command, table[i].command);
1175                                 }
1176                         }
1177                         goto do_next;
1178                 }
1179
1180                 cprintf(listener, "ERROR: Unknown command \"%s\"\r\n",
1181                         argv[0]);
1182         }
1183
1184  do_next:
1185         cprintf(listener, "radmin> ");
1186
1187         if (co->next <= co->offset) {
1188                 co->offset = 0;
1189         } else {
1190                 memmove(co->buffer, co->buffer + co->next,
1191                         co->offset - co->next);
1192                 co->offset -= co->next;
1193         }
1194
1195         return 0;
1196 }
1197
1198
1199 static int command_domain_accept(rad_listen_t *listener,
1200                                  UNUSED RAD_REQUEST_FUNP *pfun,
1201                                  UNUSED REQUEST **prequest)
1202 {
1203         int newfd;
1204         uint32_t magic;
1205         rad_listen_t *this;
1206         socklen_t salen;
1207         struct sockaddr_storage src;
1208         fr_command_socket_t *sock = listener->data;
1209         
1210         salen = sizeof(src);
1211
1212         DEBUG2(" ... new connection request on command socket.");
1213         
1214         newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
1215         if (newfd < 0) {
1216                 /*
1217                  *      Non-blocking sockets must handle this.
1218                  */
1219                 if (errno == EWOULDBLOCK) {
1220                         return 0;
1221                 }
1222
1223                 DEBUG2(" ... failed to accept connection.");
1224                 return -1;
1225         }
1226
1227         /*
1228          *      Perform user authentication.
1229          */
1230         if (sock->uid_name || sock->gid_name) {
1231                 uid_t uid;
1232                 gid_t gid;
1233
1234                 if (getpeereid(listener->fd, &uid, &gid) < 0) {
1235                         radlog(L_ERR, "Failed getting peer credentials for %s: %s",
1236                                sock->path, strerror(errno));
1237                         close(newfd);
1238                         return -1;
1239                 }
1240
1241                 if (sock->uid_name && (sock->uid != uid)) {
1242                         radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
1243                                sock->path, (long int) uid);
1244                         close(newfd);
1245                         return -1;
1246                 }
1247
1248                 if (sock->gid_name && (sock->gid != gid)) {
1249                         radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
1250                                sock->path, (long int) gid);
1251                         close(newfd);
1252                         return -1;
1253                 }
1254         }
1255
1256         /*
1257          *      Write 32-bit magic number && version information.
1258          */
1259         magic = htonl(0xf7eead15);
1260         if (write(newfd, &magic, 4) < 0) {
1261                 radlog(L_ERR, "Failed writing initial data to socket: %s",
1262                        strerror(errno));
1263                 close(newfd);
1264                 return -1;
1265         }
1266         magic = htonl(1);       /* protocol version */
1267         if (write(newfd, &magic, 4) < 0) {
1268                 radlog(L_ERR, "Failed writing initial data to socket: %s",
1269                        strerror(errno));
1270                 close(newfd);
1271                 return -1;
1272         }
1273
1274
1275         /*
1276          *      Add the new listener.
1277          */
1278         this = listen_alloc(listener->type);
1279         if (!this) return -1;
1280
1281         /*
1282          *      Copy everything, including the pointer to the socket
1283          *      information.
1284          */
1285         sock = this->data;
1286         memcpy(this, listener, sizeof(*this));
1287         this->status = RAD_LISTEN_STATUS_INIT;
1288         this->next = NULL;
1289         this->data = sock;      /* fix it back */
1290
1291         sock->offset = 0;
1292         sock->user[0] = '\0';
1293         sock->path = ((fr_command_socket_t *) listener->data)->path;
1294
1295         this->fd = newfd;
1296         this->recv = command_domain_recv;
1297
1298         /*
1299          *      Tell the event loop that we have a new FD
1300          */
1301         event_new_fd(this);
1302
1303         return 0;
1304 }
1305
1306
1307 /*
1308  *      Send an authentication response packet
1309  */
1310 static int command_domain_send(UNUSED rad_listen_t *listener,
1311                                UNUSED REQUEST *request)
1312 {
1313         return 0;
1314 }
1315
1316
1317 static int command_socket_encode(UNUSED rad_listen_t *listener,
1318                                  UNUSED REQUEST *request)
1319 {
1320         return 0;
1321 }
1322
1323
1324 static int command_socket_decode(UNUSED rad_listen_t *listener,
1325                                  UNUSED REQUEST *request)
1326 {
1327         return 0;
1328 }
1329
1330 #endif /* WITH_COMMAND_SOCKET */