Always set the logging function
[freeradius.git] / src / main / util.c
1 /*
2  * util.c       Various utility functions.
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 2000,2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/rad_assert.h>
27
28 #include <ctype.h>
29 #include <signal.h>
30
31 #include <sys/stat.h>
32 #include <fcntl.h>
33
34 /*
35  *      The signal() function in Solaris 2.5.1 sets SA_NODEFER in
36  *      sa_flags, which causes grief if signal() is called in the
37  *      handler before the cause of the signal has been cleared.
38  *      (Infinite recursion).
39  *
40  *      The same problem appears on HPUX, so we avoid it, if we can.
41  *
42  *      Using sigaction() to reset the signal handler fixes the problem,
43  *      so where available, we prefer that solution.
44  */
45
46 void (*reset_signal(int signo, void (*func)(int)))(int)
47 {
48 #ifdef HAVE_SIGACTION
49         struct sigaction act, oact;
50
51         memset(&act, 0, sizeof(act));
52         act.sa_handler = func;
53         sigemptyset(&act.sa_mask);
54         act.sa_flags = 0;
55 #ifdef  SA_INTERRUPT            /* SunOS */
56         act.sa_flags |= SA_INTERRUPT;
57 #endif
58         if (sigaction(signo, &act, &oact) < 0)
59                 return SIG_ERR;
60         return oact.sa_handler;
61 #else
62
63         /*
64          *      re-set by calling the 'signal' function, which
65          *      may cause infinite recursion and core dumps due to
66          *      stack growth.
67          *
68          *      However, the system is too dumb to implement sigaction(),
69          *      so we don't have a choice.
70          */
71         signal(signo, func);
72
73         return NULL;
74 #endif
75 }
76
77 /*
78  *      Per-request data, added by modules...
79  */
80 struct request_data_t {
81         request_data_t  *next;
82
83         void            *unique_ptr;
84         int             unique_int;
85         void            *opaque;
86         void            (*free_opaque)(void *);
87 };
88
89 /*
90  *      Add opaque data (with a "free" function) to a REQUEST.
91  *
92  *      The unique ptr is meant to be a module configuration,
93  *      and the unique integer allows the caller to have multiple
94  *      opaque data associated with a REQUEST.
95  */
96 int request_data_add(REQUEST *request,
97                      void *unique_ptr, int unique_int,
98                      void *opaque, void (*free_opaque)(void *))
99 {
100         request_data_t *this, **last, *next;
101
102         /*
103          *      Some simple sanity checks.
104          */
105         if (!request || !opaque) return -1;
106
107         this = next = NULL;
108         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
109                 if (((*last)->unique_ptr == unique_ptr) &&
110                     ((*last)->unique_int == unique_int)) {
111                         this = *last;
112
113                         next = this->next;
114
115                         if (this->opaque && /* free it, if necessary */
116                             this->free_opaque)
117                                 this->free_opaque(this->opaque);
118                         break;  /* replace the existing entry */
119                 }
120         }
121
122         if (!this) this = rad_malloc(sizeof(*this));
123         memset(this, 0, sizeof(*this));
124
125         this->next = next;
126         this->unique_ptr = unique_ptr;
127         this->unique_int = unique_int;
128         this->opaque = opaque;
129         this->free_opaque = free_opaque;
130
131         *last = this;
132
133         return 0;
134 }
135
136
137 /*
138  *      Get opaque data from a request.
139  */
140 void *request_data_get(REQUEST *request,
141                        void *unique_ptr, int unique_int)
142 {
143         request_data_t **last;
144
145         if (!request) return NULL;
146
147         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
148                 if (((*last)->unique_ptr == unique_ptr) &&
149                     ((*last)->unique_int == unique_int)) {
150                         request_data_t *this = *last;
151                         void *ptr = this->opaque;
152
153                         /*
154                          *      Remove the entry from the list, and free it.
155                          */
156                         *last = this->next;
157                         free(this);
158                         return ptr; /* don't free it, the caller does that */
159                 }
160         }
161
162         return NULL;            /* wasn't found, too bad... */
163 }
164
165
166 /*
167  *      Get opaque data from a request without removing it.
168  */
169 void *request_data_reference(REQUEST *request,
170                        void *unique_ptr, int unique_int)
171 {
172         request_data_t **last;
173
174         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
175                 if (((*last)->unique_ptr == unique_ptr) &&
176                     ((*last)->unique_int == unique_int)) {
177                         request_data_t *this = *last;
178                         void *ptr = this->opaque;
179
180                         return ptr;
181                 }
182         }
183
184         return NULL;            /* wasn't found, too bad... */
185 }
186
187
188 /*
189  *      Free a REQUEST struct.
190  */
191 void request_free(REQUEST **request_ptr)
192 {
193         REQUEST *request;
194
195         if (!request_ptr || !*request_ptr) {
196                 return;
197         }
198
199         request = *request_ptr;
200
201         rad_assert(!request->in_request_hash);
202 #ifdef WITH_PROXY
203         rad_assert(!request->in_proxy_hash);
204 #endif
205         rad_assert(!request->ev);
206
207         if (request->packet)
208                 rad_free(&request->packet);
209
210 #ifdef WITH_PROXY
211         if (request->proxy)
212                 rad_free(&request->proxy);
213 #endif
214
215         if (request->reply)
216                 rad_free(&request->reply);
217
218 #ifdef WITH_PROXY
219         if (request->proxy_reply)
220                 rad_free(&request->proxy_reply);
221 #endif
222
223         if (request->config_items)
224                 pairfree(&request->config_items);
225
226         request->username = NULL;
227         request->password = NULL;
228
229         if (request->data) {
230                 request_data_t *this, *next;
231
232                 for (this = request->data; this != NULL; this = next) {
233                         next = this->next;
234                         if (this->opaque && /* free it, if necessary */
235                             this->free_opaque)
236                                 this->free_opaque(this->opaque);
237                         free(this);
238                 }
239                 request->data = NULL;
240         }
241
242         if (request->root &&
243             (request->root->refcount > 0)) {
244                 request->root->refcount--;
245                 request->root = NULL;
246         }
247
248 #ifdef WITH_COA
249         if (request->coa) {
250                 request->coa->parent = NULL;
251                 rad_assert(request->coa->ev == NULL);
252                 request_free(&request->coa);
253         }
254
255         if (request->parent && (request->parent->coa == request)) {
256                 request->parent->coa = NULL;
257         }
258 #endif
259
260 #ifndef NDEBUG
261         request->magic = 0x01020304;    /* set the request to be nonsense */
262 #endif
263         request->client = NULL;
264 #ifdef WITH_PROXY
265         request->home_server = NULL;
266 #endif
267         talloc_free(request);
268         *request_ptr = NULL;
269 }
270
271 /*
272  *      Check a filename for sanity.
273  *
274  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
275  */
276 int rad_checkfilename(char const *filename)
277 {
278         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
279                 return 0;
280         }
281
282         return -1;
283 }
284
285 /** Check if file exists
286  *
287  * @param filename to check.
288  * @return 0 if the file does not exist, 1 if the file exists, -1 if the file
289  *      exists but there was an error opening it. errno value should be usable
290  *      for error messages.
291  */
292 int rad_file_exists(char const *filename)
293 {
294         int des;
295         int ret = 1;
296         
297         if ((des = open(filename, O_RDONLY)) == -1) {
298                 if (errno == ENOENT) {
299                         ret = 0;
300                 } else {
301                         ret = -1;
302                 }
303         } else {
304                 close(des);
305         }
306         
307         return ret;
308 }
309
310 /*
311  *      Create possibly many directories.
312  *
313  *      Note that the input directory name is NOT a constant!
314  *      This is so that IF an error is returned, the 'directory' ptr
315  *      points to the name of the file which caused the error.
316  */
317 int rad_mkdir(char *directory, mode_t mode)
318 {
319         int rcode;
320         char *p;
321         struct stat st;
322
323         /*
324          *      If the directory exists, don't do anything.
325          */
326         if (stat(directory, &st) == 0) {
327                 return 0;
328         }
329
330         /*
331          *      Look for the LAST directory name.  Try to create that,
332          *      failing on any error.
333          */
334         p = strrchr(directory, FR_DIR_SEP);
335         if (p != NULL) {
336                 *p = '\0';
337                 rcode = rad_mkdir(directory, mode);
338
339                 /*
340                  *      On error, we leave the directory name as the
341                  *      one which caused the error.
342                  */
343                 if (rcode < 0) {
344                         if (errno == EEXIST) return 0;
345                         return rcode;
346                 }
347
348                 /*
349                  *      Reset the directory delimiter, and go ask
350                  *      the system to make the directory.
351                  */
352                 *p = FR_DIR_SEP;
353         } else {
354                 return 0;
355         }
356
357         /*
358          *      Having done everything successfully, we do the
359          *      system call to actually go create the directory.
360          */
361         rcode = mkdir(directory, mode & 0777);
362         if (rcode < 0) {
363                 return rcode;
364         }
365         
366         /*
367          *      Set things like sticky bits that aren't supported by
368          *      mkdir.
369          */
370         if (mode & ~0777) {
371                 rcode = chmod(directory, mode);
372         }
373         
374         return rcode;
375 }
376
377
378 /*
379  *      Allocate memory, or exit.
380  *
381  *      This call ALWAYS succeeds!
382  */
383 void *rad_malloc(size_t size)
384 {
385         void *ptr = malloc(size);
386
387         if (ptr == NULL) {
388                 ERROR("no memory");
389                 exit(1);
390         }
391
392         return ptr;
393 }
394
395
396 void *rad_calloc(size_t size)
397 {
398         void *ptr = rad_malloc(size);
399         memset(ptr, 0, size);
400         return ptr;
401 }
402
403 void rad_const_free(void const *ptr)
404 {
405         void *tmp;
406         if (!ptr) return;
407
408         memcpy(&tmp, &ptr, sizeof(tmp));
409         talloc_free(tmp);
410 }
411
412
413 /*
414  *      Signature for free is dumb, and raises errors when we try
415  *      to free const ptrs.
416  */
417 void rad_cfree(void const *ptr)
418 {
419         void *tmp;
420         if (!ptr) return;
421
422         memcpy(&tmp, &ptr, sizeof(tmp));
423         free(tmp);
424 }
425
426 /*
427  *      Logs an error message and aborts the program
428  *
429  */
430
431 void NEVER_RETURNS rad_assert_fail (char const *file, unsigned int line,
432                                     char const *expr)
433 {
434         ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
435         abort();
436 }
437
438
439 /*
440  *      Create a new REQUEST data structure.
441  */
442 REQUEST *request_alloc(void)
443 {
444         REQUEST *request;
445
446         request = talloc_zero(NULL, REQUEST);
447 #ifndef NDEBUG
448         request->magic = REQUEST_MAGIC;
449 #endif
450 #ifdef WITH_PROXY
451         request->proxy = NULL;
452 #endif
453         request->reply = NULL;
454 #ifdef WITH_PROXY
455         request->proxy_reply = NULL;
456 #endif
457         request->config_items = NULL;
458         request->username = NULL;
459         request->password = NULL;
460         request->timestamp = time(NULL);
461         request->options = debug_flag; /* Default to global debug level */
462
463         request->module = "";
464         request->component = "<core>";
465         request->radlog = radlog_request;
466
467         return request;
468 }
469
470
471 /*
472  *      Create a new REQUEST, based on an old one.
473  *
474  *      This function allows modules to inject fake requests
475  *      into the server, for tunneled protocols like TTLS & PEAP.
476  */
477 REQUEST *request_alloc_fake(REQUEST *request)
478 {
479   REQUEST *fake;
480
481   fake = request_alloc();
482
483   fake->number = request->number;
484 #ifdef HAVE_PTHREAD_H
485   fake->child_pid = request->child_pid;
486 #endif
487   fake->parent = request;
488   fake->root = request->root;
489   fake->client = request->client;
490
491   /*
492    *    For new server support.
493    *
494    *    FIXME: Key instead off of a "virtual server" data structure.
495    *
496    *    FIXME: Permit different servers for inner && outer sessions?
497    */
498   fake->server = request->server;
499
500   fake->packet = rad_alloc(request, 1);
501   if (!fake->packet) {
502           request_free(&fake);
503           return NULL;
504   }
505
506   fake->reply = rad_alloc(request, 0);
507   if (!fake->reply) {
508           request_free(&fake);
509           return NULL;
510   }
511
512   fake->master_state = REQUEST_ACTIVE;
513   fake->child_state = REQUEST_RUNNING;
514
515   /*
516    *    Fill in the fake request.
517    */
518   fake->packet->sockfd = -1;
519   fake->packet->src_ipaddr = request->packet->src_ipaddr;
520   fake->packet->src_port = request->packet->src_port;
521   fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
522   fake->packet->dst_port = 0;
523
524   /*
525    *    This isn't STRICTLY required, as the fake request MUST NEVER
526    *    be put into the request list.  However, it's still reasonable
527    *    practice.
528    */
529   fake->packet->id = fake->number & 0xff;
530   fake->packet->code = request->packet->code;
531   fake->timestamp = request->timestamp;
532
533   /*
534    *    Required for new identity support
535    */
536   fake->listener = request->listener;
537
538   /*
539    *    Fill in the fake reply, based on the fake request.
540    */
541   fake->reply->sockfd = fake->packet->sockfd;
542   fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
543   fake->reply->src_port = fake->packet->dst_port;
544   fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
545   fake->reply->dst_port = fake->packet->src_port;
546   fake->reply->id = fake->packet->id;
547   fake->reply->code = 0; /* UNKNOWN code */
548
549   /*
550    *    Copy debug information.
551    */
552   fake->options = request->options;
553   fake->radlog = request->radlog;
554
555   return fake;
556 }
557
558 #ifdef WITH_COA
559 REQUEST *request_alloc_coa(REQUEST *request)
560 {
561         if (!request || request->coa) return NULL;
562
563         /*
564          *      Originate CoA requests only when necessary.
565          */
566         if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
567             (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
568
569         request->coa = request_alloc_fake(request);
570         if (!request->coa) return NULL;
571
572         request->coa->packet->code = 0; /* unknown, as of yet */
573         request->coa->child_state = REQUEST_RUNNING;
574         request->coa->proxy = rad_alloc(request->coa, 0);
575         if (!request->coa->proxy) {
576                 request_free(&request->coa);
577                 return NULL;
578         }
579
580         return request->coa;
581 }
582 #endif
583
584 /*
585  *      Copy a quoted string.
586  */
587 int rad_copy_string(char *to, char const *from)
588 {
589         int length = 0;
590         char quote = *from;
591
592         do {
593                 if (*from == '\\') {
594                         *(to++) = *(from++);
595                         length++;
596                 }
597                 *(to++) = *(from++);
598                 length++;
599         } while (*from && (*from != quote));
600
601         if (*from != quote) return -1; /* not properly quoted */
602
603         *(to++) = quote;
604         length++;
605         *to = '\0';
606
607         return length;
608 }
609
610 /*
611  *      Copy a quoted string but without the quotes. The length
612  *      returned is the number of chars written; the number of
613  *      characters consumed is 2 more than this.
614  */
615 int rad_copy_string_bare(char *to, char const *from)
616 {
617         int length = 0;
618         char quote = *from;
619
620         from++;
621         while (*from && (*from != quote)) {
622                 if (*from == '\\') {
623                         *(to++) = *(from++);
624                         length++;
625                 }
626                 *(to++) = *(from++);
627                 length++;
628         }
629
630         if (*from != quote) return -1; /* not properly quoted */
631
632         *to = '\0';
633
634         return length;
635 }
636
637
638 /*
639  *      Copy a %{} string.
640  */
641 int rad_copy_variable(char *to, char const *from)
642 {
643         int length = 0;
644         int sublen;
645
646         *(to++) = *(from++);
647         length++;
648
649         while (*from) {
650                 switch (*from) {
651                 case '"':
652                 case '\'':
653                         sublen = rad_copy_string(to, from);
654                         if (sublen < 0) return sublen;
655                         from += sublen;
656                         to += sublen;
657                         length += sublen;
658                         break;
659
660                 case '}':       /* end of variable expansion */
661                         *(to++) = *(from++);
662                         *to = '\0';
663                         length++;
664                         return length; /* proper end of variable */
665
666                 case '\\':
667                         *(to++) = *(from++);
668                         *(to++) = *(from++);
669                         length += 2;
670                         break;
671
672                 case '%':       /* start of variable expansion */
673                         if (from[1] == '{') {
674                                 *(to++) = *(from++);
675                                 length++;
676
677                                 sublen = rad_copy_variable(to, from);
678                                 if (sublen < 0) return sublen;
679                                 from += sublen;
680                                 to += sublen;
681                                 length += sublen;
682                                 break;
683                         } /* else FIXME: catch %%{ ?*/
684
685                         /* FALL-THROUGH */
686                 default:
687                         *(to++) = *(from++);
688                         length++;
689                         break;
690                 }
691         } /* loop over the input string */
692
693         /*
694          *      We ended the string before a trailing '}'
695          */
696
697         return -1;
698 }
699
700 #ifndef USEC
701 #define USEC 1000000
702 #endif
703
704 int rad_pps(int *past, int *present, time_t *then, struct timeval *now)
705 {
706         int pps;
707
708         if (*then != now->tv_sec) {
709                 *then = now->tv_sec;
710                 *past = *present;
711                 *present = 0;
712         }
713
714         /*
715          *      Bootstrap PPS by looking at a percentage of
716          *      the previous PPS.  This lets us take a moving
717          *      count, without doing a moving average.  If
718          *      we're a fraction "f" (0..1) into the current
719          *      second, we can get a good guess for PPS by
720          *      doing:
721          *
722          *      PPS = pps_now + pps_old * (1 - f)
723          *
724          *      It's an instantaneous measurement, rather than
725          *      a moving average.  This will hopefully let it
726          *      respond better to sudden spikes.
727          *
728          *      Doing the calculations by thousands allows us
729          *      to not overflow 2^32, AND to not underflow
730          *      when we divide by USEC.
731          */
732         pps = USEC - now->tv_usec; /* useconds left in previous second */
733         pps /= 1000;               /* scale to milliseconds */
734         pps *= *past;              /* multiply by past count to get fraction */
735         pps /= 1000;               /* scale to usec again */
736         pps += *present;           /* add in current count */
737
738         return pps;
739 }
740
741 /** Split string into words and expand each one
742  *
743  * @param request Current request.
744  * @param cmd string to split.
745  * @param max_argc the maximum number of arguments to split into.
746  * @param argv Where to write the pointers into argv_buf.
747  * @param can_fail If false, stop processing if any of the xlat expansions fail.
748  * @param argv_buflen size of argv_buf.
749  * @param argv_buf temporary buffer we used to mangle/expand cmd.
750  *      Pointers to offsets of this buffer will be written to argv.
751  * @return argc or -1 on failure.
752  */
753
754 int rad_expand_xlat(REQUEST *request, char const *cmd,
755                     int max_argc, char *argv[], bool can_fail,
756                     size_t argv_buflen, char *argv_buf)
757 {
758         char const *from;
759         char *to;
760         int argc = -1;
761         int i;
762         int left;
763
764         if (strlen(cmd) > (argv_buflen - 1)) {
765                 ERROR("rad_expand_xlat: Command line is too long");
766                 return -1;
767         }
768
769         /*
770          *      Check for bad escapes.
771          */
772         if (cmd[strlen(cmd) - 1] == '\\') {
773                 ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
774                 return -1;
775         }
776
777         strlcpy(argv_buf, cmd, argv_buflen);
778
779         /*
780          *      Split the string into argv's BEFORE doing radius_xlat...
781          */
782         from = cmd;
783         to = argv_buf;
784         argc = 0;
785         while (*from) {
786                 int length;
787
788                 /*
789                  *      Skip spaces.
790                  */
791                 if ((*from == ' ') || (*from == '\t')) {
792                         from++;
793                         continue;
794                 }
795
796                 argv[argc] = to;
797                 argc++;
798
799                 if (argc >= (max_argc - 1)) break;
800
801                 /*
802                  *      Copy the argv over to our buffer.
803                  */
804                 while (*from && (*from != ' ') && (*from != '\t')) {
805                         if (to >= argv_buf + argv_buflen - 1) {
806                                 ERROR("rad_expand_xlat: Ran out of space in command line");
807                                 return -1;
808                         }
809
810                         switch (*from) {
811                         case '"':
812                         case '\'':
813                                 length = rad_copy_string_bare(to, from);
814                                 if (length < 0) {
815                                         ERROR("rad_expand_xlat: Invalid string passed as argument");
816                                         return -1;
817                                 }
818                                 from += length+2;
819                                 to += length;
820                                 break;
821
822                         case '%':
823                                 if (from[1] == '{') {
824                                         *(to++) = *(from++);
825
826                                         length = rad_copy_variable(to, from);
827                                         if (length < 0) {
828                                                 ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
829                                                 return -1;
830                                         }
831                                         from += length;
832                                         to += length;
833                                 } else { /* FIXME: catch %%{ ? */
834                                         *(to++) = *(from++);
835                                 }
836                                 break;
837
838                         case '\\':
839                                 if (from[1] == ' ') from++;
840                                 /* FALL-THROUGH */
841
842                         default:
843                                 *(to++) = *(from++);
844                         }
845                 } /* end of string, or found a space */
846
847                 *(to++) = '\0'; /* terminate the string */
848         }
849
850         /*
851          *      We have to have SOMETHING, at least.
852          */
853         if (argc <= 0) {
854                 ERROR("rad_expand_xlat: Empty command line.");
855                 return -1;
856         }
857
858         /*
859          *      Expand each string, as appropriate.
860          */
861         left = argv_buf + argv_buflen - to;
862         for (i = 0; i < argc; i++) {
863                 int sublen;
864
865                 /*
866                  *      Don't touch argv's which won't be translated.
867                  */
868                 if (strchr(argv[i], '%') == NULL) continue;
869
870                 if (!request) continue;
871
872                 sublen = radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
873                 if (sublen <= 0) {
874                         if (can_fail) {
875                                 /*
876                                  *      Fail to be backwards compatible.
877                                  *
878                                  *      It's yucky, but it won't break anything,
879                                  *      and it won't cause security problems.
880                                  */
881                                 sublen = 0;
882                         } else {
883                                 ERROR("rad_expand_xlat: xlat failed");
884                                 return -1;
885                         }
886                 }
887
888                 argv[i] = to;
889                 to += sublen;
890                 *(to++) = '\0';
891                 left -= sublen;
892                 left--;
893
894                 if (left <= 0) {
895                         ERROR("rad_expand_xlat: Ran out of space while expanding arguments.");
896                         return -1;
897                 }
898         }
899         argv[argc] = NULL;
900
901         return argc;
902 }
903
904 const FR_NAME_NUMBER pair_lists[] = {
905         { "request",            PAIR_LIST_REQUEST },
906         { "reply",              PAIR_LIST_REPLY },
907         { "config",             PAIR_LIST_CONTROL },
908         { "control",            PAIR_LIST_CONTROL },
909 #ifdef WITH_PROXY
910         { "proxy-request",      PAIR_LIST_PROXY_REQUEST },
911         { "proxy-reply",        PAIR_LIST_PROXY_REPLY },
912 #endif
913 #ifdef WITH_COA
914         { "coa",                PAIR_LIST_COA },
915         { "coa-reply",          PAIR_LIST_COA_REPLY },
916         { "disconnect",         PAIR_LIST_DM },
917         { "disconnect-reply",   PAIR_LIST_DM_REPLY },
918 #endif
919         {  NULL , -1 }
920 };
921
922 const FR_NAME_NUMBER request_refs[] = {
923         { "outer",              REQUEST_OUTER },
924         { "current",            REQUEST_CURRENT },
925         { "parent",             REQUEST_PARENT },
926         {  NULL , -1 }
927 };
928
929
930 /** Resolve attribute name to a list.
931  *
932  * Check the name string for qualifiers that specify a list and return
933  * an pair_lists_t value for that list. This value may be passed to
934  * radius_list, along with the current request, to get a pointer to the
935  * actual list in the request.
936  *
937  * If qualifiers were consumed, write a new pointer into name to the
938  * char after the last qualifier to be consumed.
939  *
940  * radius_list_name should be called before passing a name string that
941  * may contain qualifiers to dict_attrbyname.
942  *
943  * @see dict_attrbyname
944  *
945  * @param[in,out] name of attribute.
946  * @param[in] unknown the list to return if no qualifiers were found.
947  * @return PAIR_LIST_UNKOWN if qualifiers couldn't be resolved to a list.
948  */
949 pair_lists_t radius_list_name(char const **name, pair_lists_t unknown)
950 {
951         char const *p = *name;
952         char const *q;
953         pair_lists_t output;
954         
955         /* This should never be a NULL pointer or zero length string */
956         rad_assert(name && *name);
957
958         /*
959          *      We couldn't determine the list if:
960          *      
961          *      A colon delimiter was found, but the next char was a
962          *      number, indicating a tag, not a list qualifier.
963          *
964          *      No colon was found and the first char was upper case
965          *      indicating an attribute.
966          *
967          */
968         q = strchr(p, ':');
969         if (((q && (q[1] >= '0') && (q[1] <= '9'))) ||
970             (!q && isupper((int) *p))) {
971                 return unknown;
972         }
973         
974         if (q) {
975                 *name = (q + 1);        /* Consume the list and delimiter */
976                 return fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
977         }
978
979         q = (p + strlen(p));    /* Consume the entire string */
980         output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
981         if (output != PAIR_LIST_UNKNOWN) {
982                 *name = q;
983                 return output;
984         }
985
986         return unknown;
987 }
988
989
990 /** Resolve attribute name to a request.
991  *
992  * Check the name string for qualifiers that reference a parent request and
993  * write the pointer to this request to 'request'.
994  *
995  * If qualifiers were consumed, write a new pointer into name to the
996  * char after the last qualifier to be consumed.
997  *
998  * radius_ref_request should be called before radius_list_name.
999  *
1000  * @see radius_list_name
1001  * @param[in,out] name of attribute.
1002  * @param[in] def default request ref to return if no request qualifier is present.
1003  * @return one of the REQUEST_* definitions or REQUEST_UNKOWN
1004  */
1005 request_refs_t radius_request_name(char const **name, request_refs_t def)
1006 {
1007         char *p;
1008         int request;
1009
1010         p = strchr(*name, '.');
1011         if (!p) {
1012                 return REQUEST_CURRENT;
1013         }
1014         
1015         /*
1016          *      We may get passed "127.0.0.1".
1017          */
1018         request = fr_substr2int(request_refs, *name, REQUEST_UNKNOWN,
1019                                 p - *name);
1020
1021         /*
1022          *      If we get a VALID LIST, skip it.
1023          */
1024         if (request != REQUEST_UNKNOWN) {
1025                 *name = p + 1;
1026                 return request;
1027         }
1028
1029         /*
1030          *      Otherwise leave it alone, and return the caller's
1031          *      default.
1032          */
1033         return def;
1034 }
1035
1036 /** Resolve request to a request.
1037  *
1038  * Resolve name to a current request.
1039  *
1040  * @see radius_list
1041  * @param[in,out] context Base context to use, and to write the result back to.
1042  * @param[in] name (request) to resolve to.
1043  * @return 0 if request is valid in this context, else -1.
1044  */
1045 int radius_request(REQUEST **context, request_refs_t name)
1046 {
1047         REQUEST *request = *context;
1048         
1049         switch (name) {
1050                 case REQUEST_CURRENT:
1051                         return 0;
1052                 
1053                 case REQUEST_PARENT:    /* for future use in request chaining */
1054                 case REQUEST_OUTER:
1055                         if (!request->parent) {
1056                                 RWDEBUG("Specified request \"%s\" is not available in this context",
1057                                        fr_int2str(request_refs, name, "¿unknown?"));
1058                                 return -1;
1059                         }
1060                         
1061                         *context = request->parent;
1062                         
1063                         break;
1064         
1065                 case REQUEST_UNKNOWN:
1066                 default:
1067                         rad_assert(0);
1068                         return -1;
1069         }
1070         
1071         return 0;
1072 }
1073