420bc4d365d6767e49287d9979e6d27f14988157
[freeradius.git] / src / main / modules.c
1 /*
2  * modules.c    Radius module support.
3  *
4  * Author:      Alan DeKok <aland@ox.org>
5  *
6  * Version:     $Id$
7  *
8  */
9
10 static const char rcsid[] = "$Id$";
11
12 #include        "autoconf.h"
13
14 #include        <stdio.h>
15 #include        <stdlib.h>
16 #include        <string.h>
17 #include        <assert.h>
18
19 #include        "radiusd.h"
20 #include        "modules.h"
21 #include        "conffile.h"
22 #include        "ltdl.h"
23
24 #define RLM_AUTHORIZE           1
25 #define RLM_AUTHENTICATE        2
26 #define RLM_ACCOUNTING          4
27
28 /*
29  *      Keep track of which modules we've loaded.
30  */
31 typedef struct module_list_t {
32         char                    filename[MAX_STRING_LEN];
33         int                     default_auth_type;
34         module_t                *module;
35         lt_dlhandle             handle;
36         struct module_list_t    *next;
37 } module_list_t;
38
39 static module_list_t *module_list = NULL;
40
41 typedef struct module_instance_t {
42         module_list_t           *entry;
43         char                    name[MAX_STRING_LEN];
44         void                    *insthandle;
45         struct module_instance_t *next;
46 } module_instance_t;
47
48 static module_instance_t *module_instance_list = NULL;
49
50 typedef struct config_module_t {
51         module_instance_t       *instance;
52         struct config_module_t  *next;
53 } config_module_t;
54
55 typedef struct indexed_config_module_t {
56         int idx;
57         config_module_t *modulelist;
58         struct indexed_config_module_t *next;
59 } indexed_config_module_t;
60
61 static config_module_t *authorize = NULL;
62 static indexed_config_module_t *authenticate = NULL;
63 static config_module_t *preacct = NULL;
64 static config_module_t *accounting = NULL;
65
66 static void config_list_free(config_module_t **cf)
67 {
68         config_module_t *c, *next;
69
70         c = *cf;
71         while (c) {
72                 next = c->next;
73                 free(c);
74                 c = next;
75         }
76         *cf = NULL;
77 }
78
79 static void indexed_config_list_free(indexed_config_module_t **cf)
80 {
81         indexed_config_module_t *c, *next;
82
83         c = *cf;
84         while (c) {
85                 next = c->next;
86                 config_list_free(&c->modulelist);
87                 free(c);
88                 c = next;
89         }
90         *cf = NULL;
91 }
92
93 static void instance_list_free(module_instance_t **i)
94 {
95         module_instance_t       *c, *next;
96
97         c = *i;
98         while (c) {
99                 next = c->next;
100                 if(c->entry->module->detach)
101                         (c->entry->module->detach)(c->insthandle);
102                 free(c);
103                 c = next;
104         }
105         *i = NULL;
106 }
107
108 static void module_list_free(void)
109 {
110         module_list_t *ml, *next;
111
112         indexed_config_list_free(&authenticate);
113         config_list_free(&authorize);
114         config_list_free(&preacct);
115         config_list_free(&accounting);
116
117         instance_list_free(&module_instance_list);
118
119         ml = module_list;
120         while (ml) {
121                 next = ml->next;
122                 if (ml->module->destroy)
123                         (ml->module->destroy)();
124                 lt_dlclose(ml->handle); /* ignore any errors */
125                 free(ml);
126                 ml = next;
127         }
128
129         module_list = NULL;
130 }
131
132 /*
133  *  New Auth-Type's start at a large number, and go up from there.
134  *
135  *  We could do something more intelligent, but this should work almost
136  *  all of the time.
137  *
138  * FIXME: move this to dict.c as dict_valadd() and dict_valdel()
139  *        also clear value in module_list free (necessary?)
140  */
141 static int new_authtype_value(const char *name)
142 {
143   static int max_value = 32767;
144   DICT_VALUE *old_value, *new_value;
145
146   /*
147    *  Check to see if it's already defined.
148    *  If so, return the old value.
149    */
150   old_value = dict_valbyname(name);
151   if (old_value) return old_value->value;
152
153   /* Look for the predefined Auth-Type value */
154   old_value = dict_valbyattr(PW_AUTHTYPE, 0);
155   if (!old_value) return 0;     /* something WIERD is happening */
156
157   /* allocate a new value */
158   new_value = (DICT_VALUE *) malloc(sizeof(DICT_VALUE));
159   if (!new_value) {
160     fprintf(stderr, "Out of memory\n");
161     exit(1);
162   }
163
164   /* copy the old to the new */
165   memcpy(new_value, old_value, sizeof(DICT_VALUE));
166   old_value->next = new_value;
167
168   /* set it up */
169   strNcpy(new_value->name, name, sizeof(new_value->name));
170   new_value->value = max_value++;
171
172   return new_value->value;
173 }
174
175 static module_list_t *find_module(module_list_t *head, const char *filename,
176                                   const char *module_name,
177                                   const char *cffilename, int cflineno)
178 {
179         module_list_t   **last, *node;
180         module_list_t   *new;
181         void            *handle;
182         const char      *error;
183
184         while (head) {
185                 if (strcmp(head->filename, filename) == 0)
186                         return head;
187                 head = head->next;
188         }
189
190         last = &module_list;
191         node = module_list;
192         while (node) {
193                 last = &node->next;
194                 node = node->next;
195         }
196
197         /*
198          * Keep the handle around so we can dlclose() it.
199          * Also ensure that any further dependencies are exported,
200          * so that PAM can work.
201          *
202          * i.e. rlm_pam.so links to libpam.so, which in turn dlopen()'s
203          * pam_foo.so.  Without RTLD_GLOBAL, the functions in libpam.so
204          * won't get exported to pam_foo.so.
205          */
206         handle = lt_dlopenext(filename);
207         if (handle == NULL) {
208                 fprintf(stderr, "%s[%d] Failed to link to module '%s':"
209                         " %s\n", cffilename, cflineno, filename, lt_dlerror());
210                 return NULL;
211         }
212
213         /* make room for the module type */
214         new = (module_list_t *) malloc(sizeof(module_list_t));
215         if (new == NULL) {
216                 fprintf(stderr, "%s[%d] Failed to allocate memory.\n",
217                         cffilename, cflineno);
218                 lt_dlclose(handle);     /* ignore any errors */
219                 return NULL;
220         }
221
222         /* fill in the module structure */
223         new->next = NULL;
224         new->handle = handle;
225         strNcpy(new->filename, filename, sizeof(new->filename));
226
227         new->module = (module_t *) lt_dlsym(new->handle, module_name);
228         error = lt_dlerror();
229         if (!new->module) {
230                 fprintf(stderr, "%s[%d] Failed linking to "
231                                 "%s structure in %s: %s\n",
232                                 cffilename, cflineno,
233                                 module_name, cffilename, error);
234                 lt_dlclose(new->handle);        /* ignore any errors */
235                 free(new);
236                 return NULL;
237         }
238
239         /* If there's an authentication method, add a new Auth-Type */
240         if (new->module->authenticate)
241                 new->default_auth_type =
242                         new_authtype_value(new->module->name);
243
244         /* call the modules initialization */
245         if (new->module->init &&
246             (new->module->init)() < 0) {
247                 fprintf(stderr,
248                    "%s[%d] Module initialization failed.\n",
249                         cffilename, cflineno);
250                 lt_dlclose(new->handle);        /* ignore any errors */
251                 free(new);
252                 return NULL;
253         }
254
255         DEBUG("Module: Loaded %s ", new->module->name);
256
257         *last = new;
258
259         return new;
260 }
261
262 static module_instance_t *find_module_instance(module_instance_t *head,
263                                                const char *instname)
264 {
265         CONF_SECTION *cs, *inst_cs;
266         const char *name1, *name2;
267         module_instance_t *new;
268         char library[256];
269         char module_name[256];
270
271         while (head) {
272                 if (strcmp(head->name, instname) == 0)
273                         return head;
274                 head = head->next;
275         }
276
277         /* Instance doesn't exist yet. Try to find the corresponding config
278          * section and create it. */
279
280         new = malloc(sizeof *new);
281         if (!new) {
282                 fprintf(stderr, "Out of memory\n");
283                 exit(1);
284         }
285
286         cs = cf_section_find("modules");
287         if (!cs) {
288                 return NULL;
289         }
290
291         /* Module instances are declared in the modules{} block and referenced
292          * later by their name, which is the name2 from the config section,
293          * or name1 if there was no name2. */
294
295         for(inst_cs=cf_subsection_find_next(cs, NULL, NULL)
296             ; inst_cs ;
297             inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) {
298                 name1 = cf_section_name1(inst_cs);
299                 name2 = cf_section_name2(inst_cs);
300                 if ( (name2 && !strcmp(name2, instname)) ||
301                      (!name2 && !strcmp(name1, instname)) )
302                         break;
303         }
304         if (!inst_cs)
305                 return NULL;
306
307         snprintf(library, sizeof library, "rlm_%s.so", name1);
308         snprintf(module_name, sizeof module_name, "rlm_%s", name1);
309         new->entry = find_module(module_list, library, module_name,
310                                  "radiusd.conf", cf_section_lineno(inst_cs));
311         if(!new->entry) {
312                 free(new);
313                 return NULL;
314         }
315
316         if(!new->entry->module->instantiate) {
317                 new->insthandle = 0;
318         } else if((new->entry->module->instantiate)(inst_cs,
319                                                     &new->insthandle) < 0) {
320                 fprintf(stderr,
321                         "radiusd.conf[%d]: %s: Module instantiation failed.\n",
322                         cf_section_lineno(inst_cs), instname);
323                 free(new);
324                 return NULL;
325         }
326
327         strNcpy(new->name, instname, sizeof(new->name));
328         new->next = module_instance_list;
329         module_instance_list = new;
330
331         DEBUG("Module: Instantiated %s (%s) ", name1, new->name);
332
333         return new;
334 }
335
336 /*
337  *      Add one entry at the end of the config_module_t list.
338  */
339 static void add_to_list(config_module_t **head, module_instance_t *instance)
340 {
341         config_module_t *node = *head;
342         config_module_t **last = head;
343
344         while (node) {
345                 last = &node->next;
346                 node = node->next;
347         }
348
349         node = (config_module_t *) malloc(sizeof(config_module_t));
350         if (!node) {
351                 fprintf(stderr, "Out of memory\n");
352                 exit(1);
353         }
354
355         node->next = NULL;
356         node->instance = instance;
357         *last = node;
358 }
359
360 static indexed_config_module_t *new_sublist(indexed_config_module_t **head,
361                                             int idx)
362 {
363         indexed_config_module_t *node = *head;
364         indexed_config_module_t **last = head;
365
366         while (node) {
367                 if (node->idx == idx) {
368                         /* It is an error to try to create a sublist that
369                          * already exists. */
370                         return NULL;
371                 }
372                 last = &node->next;
373                 node = node->next;
374         }
375
376         node = malloc(sizeof *node);
377         if (!node) {
378                 fprintf(stderr, "Out of memory\n");
379                 exit(1);
380         }
381
382         node->next = NULL;
383         node->modulelist = NULL;
384         node->idx = idx;
385         *last = node;
386         return node;
387 }
388
389 static config_module_t *lookup_indexed_config(indexed_config_module_t *head,
390                                               int idx)
391 {
392         indexed_config_module_t *p;
393         for (p=head; p; p=p->next) {
394                 if(p->idx==idx)
395                         return p->modulelist;
396         }
397         return NULL;
398 }
399
400 /* Why is this both here and in radiusd.c:server_config? --Pac. */
401 static CONF_PARSER module_config[] = {
402   { "libdir",            PW_TYPE_STRING_PTR, &radlib_dir,        LIBDIR },
403
404   { NULL, -1, NULL, NULL }
405 };
406
407 static void load_authtype_subsection(CONF_SECTION *cs, const char *filename)
408 {
409         module_instance_t *this;
410         CONF_ITEM *modref;
411         int modreflineno;
412         const char *modrefname;
413         int auth_type;
414         indexed_config_module_t *auth_type_config;
415
416         auth_type = new_authtype_value(cf_section_name2(cs));
417         auth_type_config = new_sublist(&authenticate, auth_type);
418         if (!auth_type_config) {
419                 radlog(L_ERR|L_CONS,
420                        "%s[%d] authtype %s already configured - skipping",
421                        filename, cf_section_lineno(cs), cf_section_name2(cs));
422                 return;
423         }
424
425         for(modref=cf_item_find_next(cs, NULL)
426             ; modref ;
427             modref=cf_item_find_next(cs, modref)) {
428
429                 if(cf_item_is_section(modref)) {
430                         CONF_SECTION *scs;
431                         scs = cf_itemtosection(modref);
432                         modreflineno = cf_section_lineno(scs);
433                         modrefname = cf_section_name1(scs);
434                 } else {
435                         CONF_PAIR *cp;
436                         cp = cf_itemtopair(modref);
437                         modreflineno = cf_pair_lineno(cp);
438                         modrefname = cf_pair_attr(cp);
439                 }
440
441                 this = find_module_instance(module_instance_list, modrefname);
442                 if (this == NULL) {
443                         exit(1); /* FIXME */
444                 }
445
446                 if (!this->entry->module->authenticate) {
447                         radlog(L_ERR|L_CONS,
448                                 "%s[%d] Module %s does not contain "
449                                 "an 'authenticate' entry\n",
450                                 filename, modreflineno,
451                                 this->entry->module->name);
452                         exit(1);
453                 }
454                 add_to_list(&auth_type_config->modulelist, this);
455
456         }
457 }
458
459 static void load_indexed_module_section(CONF_SECTION *cs, int comp, const char *filename)
460 {
461         module_instance_t *this;
462         CONF_ITEM       *modref;
463         int             modreflineno;
464         const char      *modrefname;
465         indexed_config_module_t *auth_type_config;
466
467         /* This function does not yet need or want to handle anything but
468          * authtypes. */
469         assert(comp==RLM_COMPONENT_AUTH);
470
471         for(modref=cf_item_find_next(cs, NULL)
472             ; modref ;
473             modref=cf_item_find_next(cs, modref)) {
474
475                 if(cf_item_is_section(modref)) {
476                         CONF_SECTION *scs;
477                         scs = cf_itemtosection(modref);
478                         if (!strcmp(cf_section_name1(scs), "authtype")) {
479                                 load_authtype_subsection(scs, filename);
480                                 continue;
481                         }
482                         modreflineno = cf_section_lineno(scs);
483                         modrefname = cf_section_name1(scs);
484                 } else {
485                         CONF_PAIR *cp;
486                         cp = cf_itemtopair(modref);
487                         modreflineno = cf_pair_lineno(cp);
488                         modrefname = cf_pair_attr(cp);
489                 }
490
491                 this = find_module_instance(module_instance_list, modrefname);
492                 if (this == NULL) {
493                         exit(1); /* FIXME */
494                 }
495
496                 if (!this->entry->module->authenticate) {
497                         radlog(L_ERR|L_CONS,
498                                 "%s[%d] Module %s does not contain "
499                                 "an 'authenticate' entry\n",
500                                 filename, modreflineno,
501                                 this->entry->module->name);
502                         exit(1);
503                 }
504                 auth_type_config = new_sublist(&authenticate,
505                                                this->entry->default_auth_type);
506                 if (!auth_type_config) {
507                         radlog(L_ERR|L_CONS,
508                             "%s[%d] authtype %s already configured - skipping",
509                             filename, modreflineno, this->entry->module->name);
510                         continue;
511                 }
512                 add_to_list(&auth_type_config->modulelist, this);
513
514         }
515 }
516
517 static void load_module_section(CONF_SECTION *cs, int comp, const char *filename)
518 {
519         module_instance_t *this;
520         CONF_ITEM       *modref;
521         int             modreflineno;
522         const char      *modrefname;
523
524         /* Authentication is special - it is not an ordered list but an
525          * associative array keyed on auth-type */
526         if (comp==RLM_COMPONENT_AUTH) {
527                 load_indexed_module_section(cs, comp, filename);
528                 return;
529         }
530
531         for(modref=cf_item_find_next(cs, NULL)
532             ; modref ;
533             modref=cf_item_find_next(cs, modref)) {
534
535                 if(cf_item_is_section(modref)) {
536                         CONF_SECTION *scs;
537                         scs = cf_itemtosection(modref);
538                         modreflineno = cf_section_lineno(scs);
539                         modrefname = cf_section_name1(scs);
540                 } else {
541                         CONF_PAIR *cp;
542                         cp = cf_itemtopair(modref);
543                         modreflineno = cf_pair_lineno(cp);
544                         modrefname = cf_pair_attr(cp);
545                 }
546
547                 this = find_module_instance(module_instance_list, modrefname);
548                 if (this == NULL) {
549                         exit(1); /* FIXME */
550                 }
551
552                 switch (comp) {
553                 case RLM_COMPONENT_AUTZ:
554                         if (!this->entry->module->authorize) {
555                                 radlog(L_ERR|L_CONS,
556                                         "%s[%d] Module %s does not contain "
557                                         "an 'authorize' entry\n",
558                                         filename, modreflineno,
559                                         this->entry->module->name);
560                                 exit(1);
561                         }
562                         add_to_list(&authorize, this);
563                         break;
564                 case RLM_COMPONENT_PREACCT:
565                         if (!this->entry->module->preaccounting) {
566                                 radlog(L_ERR|L_CONS,
567                                         "%s[%d] Module %s does not contain "
568                                         "a 'preacct' entry\n",
569                                         filename, modreflineno,
570                                         this->entry->module->name);
571                                 exit(1);
572                         }
573                         add_to_list(&preacct, this);
574                         break;
575                 case RLM_COMPONENT_ACCT:
576                         if (!this->entry->module->accounting) {
577                                 radlog(L_ERR|L_CONS,
578                                         "%s[%d] Module %s does not contain "
579                                         "an 'accounting' entry\n",
580                                         filename, modreflineno,
581                                         this->entry->module->name);
582                                 exit(1);
583                         }
584                         add_to_list(&accounting, this);
585                         break;
586                 default:
587                         radlog(L_ERR|L_CONS, "%s[%d] Unknown component %d.\n",
588                                 filename, modreflineno, comp);
589                         exit(1);
590                 }
591         }
592 }
593
594 /*
595  *      Parse the module config sections, and load
596  *      and call each module's init() function.
597  *
598  *      Libtool makes your life a LOT easier, especially with libltdl.
599  *      see: http://www.gnu.org/software/libtool/
600  */
601 int setup_modules(void)
602 {
603         const char      *control;
604         int             comp;
605         CONF_SECTION    *cs;
606         const char *filename="radiusd.conf";
607
608         /*
609          *      And parse the modules configuration values.
610          */
611         cs = cf_section_find(NULL);
612         if (cs) {
613                 cf_section_parse(cs, module_config);
614         }
615
616         /*
617          *      No current list of modules: Go initialize libltdl.
618          */
619         if (!module_list) {
620                 if (lt_dlinit() != 0) {
621                         fprintf(stderr, "Failed to initialize libraries: %s\n",
622                                 lt_dlerror());
623                         exit(1); /* FIXME */
624                         
625                 }
626                 /*
627                  *      Set the default list of preloaded symbols.
628                  *      This is used to initialize libltdl's list of
629                  *      preloaded modules. 
630                  *
631                  *      i.e. Static modules.
632                  */
633                 LTDL_SET_PRELOADED_SYMBOLS();
634
635                 /*
636                  *      Set the search path to ONLY our library directory.
637                  *      This prevents the modules from being found from
638                  *      any location on the disk.
639                  */
640                 lt_dlsetsearchpath(radlib_dir);
641                 
642                 DEBUG2("modules: Library search path is %s",
643                        lt_dlgetsearchpath());
644
645         } else {
646                 module_list_free();
647         }
648
649         for (comp=0; comp<RLM_COMPONENT_COUNT; ++comp) {
650                 switch(comp) {
651                 case RLM_COMPONENT_AUTH: control="authenticate"; break;
652                 case RLM_COMPONENT_AUTZ: control="authorize"; break;
653                 case RLM_COMPONENT_PREACCT: control="preacct"; break;
654                 case RLM_COMPONENT_ACCT: control="accounting"; break;
655                 default: control="unknown";
656                 }
657                 
658                 cs = cf_section_find(control);
659                 if (!cs)
660                         continue;
661                 
662                 load_module_section(cs, comp, filename);
663         }
664
665         return 0;
666 }
667
668
669 /*
670  *      Update the Stripped-User-Name attribute.
671  */
672 static void update_username(REQUEST *request, char *newname)
673 {
674         VALUE_PAIR *vp;
675
676         /*
677          *      If there isn't a Stripped-User-Name attribute,
678          *      go add one, and make it the definitive user name.
679          */
680         if (request->username->attribute != PW_STRIPPED_USER_NAME) {
681                 vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
682                 if (!vp) {
683                         radlog(L_ERR|L_CONS, "no memory");
684                         exit(1);
685                 }
686                 DEBUG2("  authorize: Creating Stripped-User-Name of %s", newname);
687                 strcpy((char *)vp->strvalue, newname);
688                 vp->length = strlen((char *)vp->strvalue);
689                 pairadd(&request->packet->vps, vp);
690                 request->username = vp;
691                 return;
692         }
693
694         /*
695          *      There is one, update it in place.
696          */
697         vp = request->username;
698         DEBUG2("  authorize: Updating Stripped-User-Name from %s to %s",
699                vp->strvalue, newname);
700         strcpy((char *)vp->strvalue, newname);
701         vp->length = strlen((char *)vp->strvalue);
702 }
703
704 /*
705  *      Call all authorization modules until one returns
706  *      somethings else than RLM_MODULE_OK
707  */
708 int module_authorize(REQUEST *request)
709 {
710         config_module_t *this;
711         int             rcode = RLM_MODULE_OK;
712
713         this = authorize;
714         rcode = RLM_MODULE_OK;
715
716         while (this && rcode == RLM_MODULE_OK) {
717                 DEBUG2("  authorize: %s", this->instance->entry->module->name);
718                 rcode = (this->instance->entry->module->authorize)(
719                          this->instance->insthandle, request);
720                 this = this->next;
721         }
722
723         /*
724          *      Before authenticating the user, update the
725          *      Stripped-User-Name attribute with any additions.
726          *
727          *      No name: nothing to add.
728          */
729         if (request->username != NULL) {
730                 char newname[256];
731                 VALUE_PAIR *vp;
732
733                 /*
734                  *      Try to add a prefix
735                  */
736                 for (vp = request->config_items; vp != NULL; vp = vp->next) {
737                         switch (vp->attribute) {
738                         default:
739                                 break;
740                                 
741                         case PW_ADD_PREFIX:
742                                 if ((size_t)(vp->length + request->username->length) > sizeof(vp->strvalue)) {
743                                         DEBUG2("\"%s\"+\"%s\" too long",
744                                                vp->strvalue,
745                                                request->username->strvalue);
746                                         continue;
747                                 }
748                                 strcpy(newname, (char *)vp->strvalue);
749                                 strcat(newname, (char *)request->username->strvalue);
750                                 update_username(request, newname);
751                                 break;
752                                 
753                         case PW_ADD_SUFFIX:
754                                 if ((size_t)(vp->length + request->username->length) > sizeof(vp->strvalue)) {
755                                         DEBUG2("\"%s\"+\"%s\" too long",
756                                                request->username->strvalue,
757                                                vp->strvalue);
758                                         continue;
759                                 }
760                                 strcpy(newname,
761                                         (char *)request->username->strvalue);
762                                 strcat(newname, (char *)vp->strvalue);
763                                 update_username(request, newname);
764                                 break;
765                         }
766                 } /* over all configuration items */
767
768                 pairdelete(&request->config_items, PW_ADD_PREFIX);
769                 pairdelete(&request->config_items, PW_ADD_SUFFIX);
770         }
771
772         return rcode;
773 }
774
775 /*
776  *      Authenticate a user/password with various methods.
777  */
778 int module_authenticate(int auth_type, REQUEST *request)
779 {
780         config_module_t *this;
781         int             rcode = RLM_MODULE_FAIL;
782
783         /*
784          *  We MUST have a password, of SOME type!
785          */
786         if (request->password == NULL) {
787                 return RLM_MODULE_FAIL;
788         }
789
790         this = lookup_indexed_config(authenticate, auth_type);
791
792         while (this && rcode == RLM_MODULE_FAIL) {
793                 DEBUG2("  authenticate: %s",
794                         this->instance->entry->module->name);
795                 rcode = (this->instance->entry->module->authenticate)(
796                         this->instance->insthandle, request);
797                 this = this->next;
798         }
799         return rcode;
800 }
801
802
803 /*
804  *      Do pre-accounting for ALL configured sessions
805  */
806 int module_preacct(REQUEST *request)
807 {
808         config_module_t *this;
809         int             rcode;
810
811         this = preacct;
812         rcode = RLM_MODULE_OK;
813
814         while (this && (rcode == RLM_MODULE_OK)) {
815                 DEBUG2("  preacct: %s", this->instance->entry->module->name);
816                 rcode = (this->instance->entry->module->preaccounting)
817                                 (this->instance->insthandle, request);
818                 this = this->next;
819         }
820
821         return rcode;
822 }
823
824 /*
825  *      Do accounting for ALL configured sessions
826  */
827 int module_accounting(REQUEST *request)
828 {
829         config_module_t *this;
830         int             rcode;
831
832         this = accounting;
833         rcode = RLM_MODULE_OK;
834
835         while (this && (rcode == RLM_MODULE_OK)) {
836                 DEBUG2("  accounting: %s", this->instance->entry->module->name);
837                 rcode = (this->instance->entry->module->accounting)
838                                 (this->instance->insthandle, request);
839                 this = this->next;
840         }
841
842         return rcode;
843 }
844
845 /*
846  *      Module malloc() call, which does stuff if the malloc fails.
847  *
848  *      This call ALWAYS succeeds!
849  */
850 void *rlm_malloc(size_t size)
851 {
852         void *ptr = malloc(size);
853         
854         if (ptr == NULL) {
855                 radlog(L_ERR|L_CONS, "no memory");
856                 exit(1);
857         }
858
859         return ptr;
860 }