Reverse the order of const and type specifier e.g. const char * becomes char const *
[freeradius.git] / src / modules / rlm_perl / rlm_perl.c
1 /*
2  *   This program is is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License, version 2 if the
4  *   License as published by the Free Software Foundation.
5  *
6  *   This program is distributed in the hope that it will be useful,
7  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *   GNU General Public License for more details.
10  *
11  *   You should have received a copy of the GNU General Public License
12  *   along with this program; if not, write to the Free Software
13  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15
16 /**
17  * $Id$
18  * @file rlm_perl.c
19  * @brief Translates requests between the server an a perl interpreter.
20  *
21  * @copyright 2002,2006  The FreeRADIUS server project
22  * @copyright 2002  Boian Jordanov <bjordanov@orbitel.bg>
23  */
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
29
30 #ifdef INADDR_ANY
31 #undef INADDR_ANY
32 #endif
33 #include <EXTERN.h>
34 #include <perl.h>
35 #include <XSUB.h>
36 #include <dlfcn.h>
37 #include <semaphore.h>
38
39 #ifdef __APPLE__
40 extern char **environ;
41 #endif
42
43 /*
44  *      Define a structure for our module configuration.
45  *
46  *      These variables do not need to be in a structure, but it's
47  *      a lot cleaner to do so, and a pointer to the structure can
48  *      be used as the instance handle.
49  */
50 typedef struct rlm_perl_t {
51         /* Name of the perl module */
52         char    *module;
53
54         /* Name of the functions for each module method */
55         char    *func_authorize;
56         char    *func_authenticate;
57         char    *func_accounting;
58         char    *func_start_accounting;
59         char    *func_stop_accounting;
60         char    *func_preacct;
61         char    *func_checksimul;
62         char    *func_detach;
63         char    *func_xlat;
64 #ifdef WITH_PROXY
65         char    *func_pre_proxy;
66         char    *func_post_proxy;
67 #endif
68         char    *func_post_auth;
69 #ifdef WITH_COA
70         char    *func_recv_coa;
71         char    *func_send_coa;
72 #endif
73         char    *xlat_name;
74         char    *perl_flags;
75         PerlInterpreter *perl;
76         pthread_key_t   *thread_key;
77
78         pthread_mutex_t clone_mutex;
79 } rlm_perl_t;
80 /*
81  *      A mapping of configuration file names to internal variables.
82  */
83 #define RLM_PERL_CONF(_x) { "func_" Stringify(_x), PW_TYPE_STRING_PTR, \
84                         offsetof(rlm_perl_t,func_##_x), NULL, Stringify(_x)}
85
86 static const CONF_PARSER module_config[] = {
87         { "module",  PW_TYPE_FILENAME,
88           offsetof(rlm_perl_t,module), NULL,  "module"},
89
90         RLM_PERL_CONF(authorize),
91         RLM_PERL_CONF(authenticate),
92         RLM_PERL_CONF(post_auth),
93         RLM_PERL_CONF(accounting),
94         RLM_PERL_CONF(preacct),
95         RLM_PERL_CONF(checksimul),
96         RLM_PERL_CONF(detach),
97         RLM_PERL_CONF(xlat),
98
99 #ifdef WITH_PROXY
100         RLM_PERL_CONF(pre_proxy),
101         RLM_PERL_CONF(post_proxy),
102 #endif
103 #ifdef WITH_COA
104         RLM_PERL_CONF(recv_coa),
105         RLM_PERL_CONF(send_coa),
106 #endif
107         { "perl_flags", PW_TYPE_STRING_PTR,
108           offsetof(rlm_perl_t,perl_flags), NULL, NULL},
109
110         { "func_start_accounting", PW_TYPE_STRING_PTR,
111           offsetof(rlm_perl_t,func_start_accounting), NULL, NULL},
112
113         { "func_stop_accounting", PW_TYPE_STRING_PTR,
114           offsetof(rlm_perl_t,func_stop_accounting), NULL, NULL},
115
116         { NULL, -1, 0, NULL, NULL }             /* end the list */
117 };
118
119 /*
120  * man perlembed
121  */
122 EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
123
124 #ifdef USE_ITHREADS
125 #define dl_librefs "DynaLoader::dl_librefs"
126 #define dl_modules "DynaLoader::dl_modules"
127 static void rlm_perl_clear_handles(pTHX)
128 {
129         AV *librefs = get_av(dl_librefs, FALSE);
130         if (librefs) {
131                 av_clear(librefs);
132         }
133 }
134
135 static void **rlm_perl_get_handles(pTHX)
136 {
137         I32 i;
138         AV *librefs = get_av(dl_librefs, FALSE);
139         AV *modules = get_av(dl_modules, FALSE);
140         void **handles;
141
142         if (!librefs) return NULL;
143
144         if (!(AvFILL(librefs) >= 0)) {
145                 return NULL;
146         }
147
148         handles = (void **)rad_malloc(sizeof(void *) * (AvFILL(librefs)+2));
149
150         for (i=0; i<=AvFILL(librefs); i++) {
151                 void *handle;
152                 SV *handle_sv = *av_fetch(librefs, i, FALSE);
153
154                 if(!handle_sv) {
155                         ERROR("Could not fetch $%s[%d]!\n",
156                                dl_librefs, (int)i);
157                         continue;
158                 }
159                 handle = (void *)SvIV(handle_sv);
160
161                 if (handle) {
162                         handles[i] = handle;
163                 }
164         }
165
166         av_clear(modules);
167         av_clear(librefs);
168
169         handles[i] = (void *)0;
170
171         return handles;
172 }
173
174 static void rlm_perl_close_handles(void **handles)
175 {
176         int i;
177
178         if (!handles) {
179                 return;
180         }
181
182         for (i=0; handles[i]; i++) {
183                 DEBUG("close %p\n", handles[i]);
184                 dlclose(handles[i]);
185         }
186
187         free(handles);
188 }
189
190 static void rlm_perl_destruct(PerlInterpreter *perl)
191 {
192         dTHXa(perl);
193
194         PERL_SET_CONTEXT(perl);
195
196         PL_perl_destruct_level = 2;
197
198         PL_origenviron = environ;
199
200 DIAG_OFF(shadow)
201         {
202                 dTHXa(perl);
203         }
204 DIAG_ON(shadow)
205         /*
206          * FIXME: This shouldn't happen
207          *
208          */
209         while (PL_scopestack_ix > 1 ){
210                 LEAVE;
211         }
212
213         perl_destruct(perl);
214         perl_free(perl);
215 }
216
217 static void rlm_destroy_perl(PerlInterpreter *perl)
218 {
219         void    **handles;
220
221         dTHXa(perl);
222         PERL_SET_CONTEXT(perl);
223
224         handles = rlm_perl_get_handles(aTHX);
225         if (handles) rlm_perl_close_handles(handles);
226         rlm_perl_destruct(perl);
227 }
228
229 /* Create Key */
230 static void rlm_perl_make_key(pthread_key_t *key)
231 {
232         pthread_key_create(key, (void*)rlm_destroy_perl);
233 }
234
235 static PerlInterpreter *rlm_perl_clone(PerlInterpreter *perl, pthread_key_t *key)
236 {
237         int ret;
238         
239         PerlInterpreter *interp;
240         UV clone_flags = 0;
241
242         PERL_SET_CONTEXT(perl);
243
244         interp = pthread_getspecific(*key);
245         if (interp) return interp;
246
247         interp = perl_clone(perl, clone_flags);
248         {
249                 dTHXa(interp);
250         }
251 #if PERL_REVISION >= 5 && PERL_VERSION <8
252         call_pv("CLONE",0);
253 #endif
254         ptr_table_free(PL_ptr_table);
255         PL_ptr_table = NULL;
256
257         PERL_SET_CONTEXT(aTHX);
258         rlm_perl_clear_handles(aTHX);
259
260         ret = pthread_setspecific(*key, interp);
261         if (ret != 0) {
262                 DEBUG("rlm_perl: Failed associating interpretor with thread %s", strerror(ret));
263                 
264                 rlm_perl_destruct(interp);
265                 return NULL;
266         }
267
268         return interp;
269 }
270 #endif
271
272 static void xs_init(pTHX)
273 {
274         char const *file = __FILE__;
275
276         /* DynaLoader is a special case */
277         newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
278
279 }
280 /*
281  *
282  * This is wrapper for radlog
283  * Now users can call radiusd::radlog(level,msg) wich is the same
284  * calling radlog from C code.
285  * Boyan
286  */
287 static XS(XS_radiusd_radlog)
288 {
289         dXSARGS;
290         if (items !=2)
291                 croak("Usage: radiusd::radlog(level, message)");
292         {
293                 int     level;
294                 char    *msg;
295
296                 level = (int) SvIV(ST(0));
297                 msg   = (char *) SvPV(ST(1), PL_na);
298
299                 /*
300                  *      Because 'msg' is a 'char *', we don't want '%s', etc.
301                  *      in it to give us printf-style vulnerabilities.
302                  */
303                 radlog(level, "rlm_perl: %s", msg);
304         }
305         XSRETURN_NO;
306 }
307
308 /*
309  * The xlat function
310  */
311 static size_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
312 {
313
314         rlm_perl_t      *inst= (rlm_perl_t *) instance;
315         PerlInterpreter *perl;
316         char            *tmp;
317         char const      *p, *q;
318         int             count;
319         size_t          ret = 0;
320         STRLEN          n_a;
321
322 #ifndef WITH_ITHREADS
323         perl = inst->perl;
324 #else
325         perl = rlm_perl_clone(inst->perl,inst->thread_key);
326         {
327                 dTHXa(perl);
328         }
329 #endif
330         PERL_SET_CONTEXT(perl);
331         {
332                 dSP;
333                 ENTER;SAVETMPS;
334
335                 PUSHMARK(SP);
336                 
337                 p = fmt;
338                 while ((q = strchr(p, ' '))) {
339                         XPUSHs(sv_2mortal(newSVpv(p, p - q)));
340                         
341                         p = q + 1;
342                 }
343                 
344                 PUTBACK;
345
346                 count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);
347
348                 SPAGAIN;
349                 if (SvTRUE(ERRSV)) {
350                         RDEBUGE("Exit %s", SvPV(ERRSV,n_a));
351                         (void)POPs;
352                 } else if (count > 0) {
353                         tmp = POPp;
354                         strlcpy(out, tmp, freespace);
355                         ret = strlen(out);
356
357                         RDEBUG("Len is %zu , out is %s freespace is %zu", ret, out, freespace);
358                 }
359
360                 PUTBACK ;
361                 FREETMPS ;
362                 LEAVE ;
363
364         }
365         
366         return ret;
367 }
368 /*
369  *      Do any per-module initialization that is separate to each
370  *      configured instance of the module.  e.g. set up connections
371  *      to external databases, read configuration files, set up
372  *      dictionary entries, etc.
373  *
374  *      If configuration information is given in the config section
375  *      that must be referenced in later calls, store a handle to it
376  *      in *instance otherwise put a null pointer there.
377  *
378  *      Boyan:
379  *      Setup a hashes wich we will use later
380  *      parse a module and give him a chance to live
381  *
382  */
383 static int mod_instantiate(CONF_SECTION *conf, void *instance)
384 {
385         rlm_perl_t       *inst = instance;
386         AV              *end_AV;
387
388         char **embed;
389         char **envp = NULL;
390         char const *xlat_name;
391         int exitstatus = 0, argc=0;
392
393         MEM(embed = talloc_zero_array(inst, char *, 4));
394
395         /*
396          *      Create pthread key. This key will be stored in instance
397          */
398
399 #ifdef USE_ITHREADS
400         pthread_mutex_init(&inst->clone_mutex, NULL);
401
402         inst->thread_key = rad_malloc(sizeof(*inst->thread_key));
403         memset(inst->thread_key,0,sizeof(*inst->thread_key));
404         
405         rlm_perl_make_key(inst->thread_key);
406 #endif
407
408         char arg[] = "0";
409         
410         embed[0] = NULL;
411         if (inst->perl_flags) {
412                 embed[1] = inst->perl_flags;
413                 embed[2] = inst->module;
414                 embed[3] = arg;
415                 argc = 4;
416         } else {
417                 embed[1] = inst->module;
418                 embed[2] = arg;
419                 argc = 3;
420         }
421
422         PERL_SYS_INIT3(&argc, &embed, &envp);
423
424         if ((inst->perl = perl_alloc()) == NULL) {
425                 ERROR("rlm_perl: No memory for allocating new perl !");
426                 return (-1);
427         }
428
429         perl_construct(inst->perl);
430
431 #ifdef USE_ITHREADS
432         PL_perl_destruct_level = 2;
433
434         {
435                 dTHXa(inst->perl);
436         }
437         PERL_SET_CONTEXT(inst->perl);
438 #endif
439
440 #if PERL_REVISION >= 5 && PERL_VERSION >=8
441         PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
442 #endif
443
444         exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL);
445
446         end_AV = PL_endav;
447         PL_endav = Nullav;
448
449         newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl");
450
451         if(!exitstatus) {
452                 exitstatus = perl_run(inst->perl);
453         } else {
454                 ERROR("rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);
455                 return (-1);
456         }
457
458         PL_endav = end_AV;
459
460         xlat_name = cf_section_name2(conf);
461         if (!xlat_name)
462                 xlat_name = cf_section_name1(conf);
463         if (xlat_name) {
464                 xlat_register(xlat_name, perl_xlat, NULL, inst);
465         }
466
467         return 0;
468 }
469
470 /*
471  *      get the vps and put them in perl hash
472  *      If one VP have multiple values it is added as array_ref
473  *      Example for this is Cisco-AVPair that holds multiple values.
474  *      Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
475  */
476 static void perl_store_vps(TALLOC_CTX *ctx, VALUE_PAIR *vps, HV *rad_hv)
477 {
478         VALUE_PAIR *head, *sublist;
479         AV *av;
480         char const *name;
481         char namebuf[256];
482         char buffer[1024];
483         int len;
484
485         hv_undef(rad_hv);
486         
487         /*
488          *      Copy the valuepair list so we can remove attributes
489          *      we've already processed.  This is a horrible hack to
490          *      get around various other stupidity.
491          */
492         head = paircopy(ctx, vps);
493
494         while (head) {
495                 /*
496                  *      Tagged attributes are added to the hash with name
497                  *      <attribute>:<tag>, others just use the normal attribute
498                  *      name as the key.
499                  */
500                 if (head->da->flags.has_tag && (head->tag != 0)) {
501                         snprintf(namebuf, sizeof(namebuf), "%s:%d",
502                                  head->da->name, head->tag);
503                         name = namebuf;
504                 } else {
505                         name = head->da->name;
506                 }
507
508                 /*
509                  *      Create a new list with all the attributes like this one
510                  *      which are in the same tag group.
511                  */
512                 sublist = NULL;
513                 pairfilter(ctx, &sublist, &head, head->da->attr, head->da->vendor, head->tag);
514
515                 /*
516                  *      Attribute has multiple values
517                  */
518                 if (sublist->next) {
519                         VALUE_PAIR *vp;
520
521                         av = newAV();
522                         for (vp = sublist; vp; vp = vp->next) {
523                                 len = vp_prints_value(buffer, sizeof(buffer), vp, FALSE);
524                                 av_push(av, newSVpv(buffer, len));
525                         }
526                         (void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
527                 
528                         /*
529                          *      Attribute has a single value, so its value just gets
530                          *      added to the hash.
531                          */
532                 } else {
533                         len = vp_prints_value(buffer, sizeof(buffer), sublist, FALSE);
534                         (void)hv_store(rad_hv, name, strlen(name), newSVpv(buffer, len), 0);
535                 }
536
537                 pairfree(&sublist);
538         }
539
540         rad_assert(!head);
541 }
542
543 /*
544  *
545  *     Verify that a Perl SV is a string and save it in FreeRadius
546  *     Value Pair Format
547  *
548  */
549 static int pairadd_sv(TALLOC_CTX *ctx, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op)
550 {
551         char        *val;
552         VALUE_PAIR      *vp;
553
554         if (SvOK(sv)) {
555                 val = SvPV_nolen(sv);
556                 vp = pairmake(ctx, vps, key, val, op);
557                 if (vp != NULL) {
558                         DEBUG("rlm_perl: Added pair %s = %s", key, val);
559                         return 1;
560                 } else {
561                         DEBUG("rlm_perl: ERROR: Failed to create pair %s = %s", key, val);
562                 }
563         }
564         return 0;
565 }
566
567 /*
568  *     Boyan :
569  *     Gets the content from hashes
570  */
571 static int get_hv_content(TALLOC_CTX *ctx, HV *my_hv, VALUE_PAIR **vps)
572 {
573         SV              *res_sv, **av_sv;
574         AV              *av;
575         char            *key;
576         I32             key_len, len, i, j;
577         int             ret=0;
578
579         *vps = NULL;
580         for (i = hv_iterinit(my_hv); i > 0; i--) {
581                 res_sv = hv_iternextsv(my_hv,&key,&key_len);
582                 if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
583                         av = (AV*)SvRV(res_sv);
584                         len = av_len(av);
585                         for (j = 0; j <= len; j++) {
586                                 av_sv = av_fetch(av, j, 0);
587                                 ret = pairadd_sv(ctx, vps, key, *av_sv, T_OP_ADD) + ret;
588                         }
589                 } else ret = pairadd_sv(ctx, vps, key, res_sv, T_OP_EQ) + ret;
590         }
591
592         return ret;
593 }
594
595 /*
596  *      Call the function_name inside the module
597  *      Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
598  *
599  */
600 static int do_perl(void *instance, REQUEST *request, char *function_name)
601 {
602
603         rlm_perl_t      *inst = instance;
604         VALUE_PAIR      *vp;
605         int             exitstatus=0, count;
606         STRLEN          n_a;
607
608         HV              *rad_reply_hv;
609         HV              *rad_check_hv;
610         HV              *rad_config_hv;
611         HV              *rad_request_hv;
612 #ifdef WITH_PROXY
613         HV              *rad_request_proxy_hv;
614         HV              *rad_request_proxy_reply_hv;
615 #endif
616         
617         /*
618          *      Radius has told us to call this function, but none
619          *      is defined.
620          */
621         if (!function_name) return RLM_MODULE_FAIL;
622
623 #ifdef USE_ITHREADS
624         pthread_mutex_lock(&inst->clone_mutex);
625
626         PerlInterpreter *interp;
627
628         interp = rlm_perl_clone(inst->perl,inst->thread_key);
629         {
630                 dTHXa(interp);
631                 PERL_SET_CONTEXT(interp);
632         }
633         
634         pthread_mutex_unlock(&inst->clone_mutex);
635 #else
636         PERL_SET_CONTEXT(inst->perl);
637 #endif
638
639         {
640                 dSP;
641
642                 ENTER;
643                 SAVETMPS;
644
645                 rad_reply_hv = get_hv("RAD_REPLY",1);
646                 rad_check_hv = get_hv("RAD_CHECK",1);
647                 rad_config_hv = get_hv("RAD_CONFIG",1);
648                 rad_request_hv = get_hv("RAD_REQUEST",1);
649
650                 perl_store_vps(request->reply, request->reply->vps, rad_reply_hv);
651                 perl_store_vps(request, request->config_items, rad_check_hv);
652                 perl_store_vps(request->packet, request->packet->vps, rad_request_hv);
653                 perl_store_vps(request, request->config_items, rad_config_hv);
654
655 #ifdef WITH_PROXY
656                 rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
657                 rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
658
659                 if (request->proxy != NULL) {
660                         perl_store_vps(request->proxy, request->proxy->vps, rad_request_proxy_hv);
661                 } else {
662                         hv_undef(rad_request_proxy_hv);
663                 }
664
665                 if (request->proxy_reply !=NULL) {
666                         perl_store_vps(request->proxy_reply, request->proxy_reply->vps, rad_request_proxy_reply_hv);
667                 } else {
668                         hv_undef(rad_request_proxy_reply_hv);
669                 }
670 #endif
671
672                 PUSHMARK(SP);
673                 /*
674                  * This way %RAD_xx can be pushed onto stack as sub parameters.
675                  * XPUSHs( newRV_noinc((SV *)rad_request_hv) );
676                  * XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
677                  * XPUSHs( newRV_noinc((SV *)rad_check_hv) );
678                  * PUTBACK;
679                  */
680
681                 count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);
682
683                 SPAGAIN;
684
685                 if (SvTRUE(ERRSV)) {
686                         ERROR("rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n",
687                                inst->module,
688                                function_name, SvPV(ERRSV,n_a));
689                         (void)POPs;
690                 }
691
692                 if (count == 1) {
693                         exitstatus = POPi;
694                         if (exitstatus >= 100 || exitstatus < 0) {
695                                 exitstatus = RLM_MODULE_FAIL;
696                         }
697                 }
698
699
700                 PUTBACK;
701                 FREETMPS;
702                 LEAVE;
703
704                 vp = NULL;
705                 if ((get_hv_content(request->packet, rad_request_hv, &vp)) > 0 ) {
706                         pairfree(&request->packet->vps);
707                         request->packet->vps = vp;
708                         vp = NULL;
709
710                         /*
711                          *      Update cached copies
712                          */
713                         request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
714                         request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
715                         if (!request->password)
716                                 request->password = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
717                 }
718
719                 if ((get_hv_content(request->reply, rad_reply_hv, &vp)) > 0 ) {
720                         pairfree(&request->reply->vps);
721                         request->reply->vps = vp;
722                         vp = NULL;
723                 }
724
725                 if ((get_hv_content(request, rad_check_hv, &vp)) > 0 ) {
726                         pairfree(&request->config_items);
727                         request->config_items = vp;
728                         vp = NULL;
729                 }
730
731 #ifdef WITH_PROXY
732                 if (request->proxy &&
733                     (get_hv_content(request->proxy, rad_request_proxy_hv, &vp) > 0)) {
734                         pairfree(&request->proxy->vps);
735                         request->proxy->vps = vp;
736                         vp = NULL;
737                 }
738
739                 if (request->proxy_reply &&
740                     (get_hv_content(request->proxy_reply, rad_request_proxy_reply_hv, &vp) > 0)) {
741                         pairfree(&request->proxy_reply->vps);
742                         request->proxy_reply->vps = vp;
743                         vp = NULL;
744                 }
745 #endif
746
747         }
748         return exitstatus;
749 }
750
751 #define RLM_PERL_FUNC(_x) static rlm_rcode_t mod_##_x(void *instance, REQUEST *request) \
752         {                                                               \
753                 return do_perl(instance, request,                       \
754                                ((rlm_perl_t *)instance)->func_##_x); \
755         }
756
757 RLM_PERL_FUNC(authorize)
758 RLM_PERL_FUNC(authenticate)
759 RLM_PERL_FUNC(post_auth)
760
761 RLM_PERL_FUNC(checksimul)
762
763 #ifdef WITH_PROXY
764 RLM_PERL_FUNC(pre_proxy)
765 RLM_PERL_FUNC(post_proxy)
766 #endif
767
768 #ifdef WITH_COA
769 RLM_PERL_FUNC(recv_coa)
770 RLM_PERL_FUNC(send_coa)
771 #endif
772
773 RLM_PERL_FUNC(preacct)
774
775 /*
776  *      Write accounting information to this modules database.
777  */
778 static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
779 {
780         VALUE_PAIR      *pair;
781         int             acctstatustype=0;
782
783         if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL) {
784                 acctstatustype = pair->vp_integer;
785         } else {
786                 ERROR("Invalid Accounting Packet");
787                 return RLM_MODULE_INVALID;
788         }
789
790         switch (acctstatustype) {
791
792         case PW_STATUS_START:
793
794                 if (((rlm_perl_t *)instance)->func_start_accounting) {
795                         return do_perl(instance, request,
796                                        ((rlm_perl_t *)instance)->func_start_accounting);
797                 } else {
798                         return do_perl(instance, request,
799                                        ((rlm_perl_t *)instance)->func_accounting);
800                 }
801                 break;
802
803         case PW_STATUS_STOP:
804
805                 if (((rlm_perl_t *)instance)->func_stop_accounting) {
806                         return do_perl(instance, request,
807                                        ((rlm_perl_t *)instance)->func_stop_accounting);
808                 } else {
809                         return do_perl(instance, request,
810                                        ((rlm_perl_t *)instance)->func_accounting);
811                 }
812                 break;
813         default:
814                 return do_perl(instance, request,
815                                ((rlm_perl_t *)instance)->func_accounting);
816
817         }
818 }
819
820
821 /*
822  * Detach a instance give a chance to a module to make some internal setup ...
823  */
824 static int mod_detach(void *instance)
825 {
826         rlm_perl_t      *inst = (rlm_perl_t *) instance;
827         int             exitstatus = 0, count = 0;
828
829 #if 0
830         /*
831          *      FIXME: Call this in the destruct function?
832          */
833         {
834                 dTHXa(handle->clone);
835                 PERL_SET_CONTEXT(handle->clone);
836                 {
837                         dSP; ENTER; SAVETMPS; PUSHMARK(SP);
838                         count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
839                         SPAGAIN;
840
841                         if (count == 1) {
842                                 exitstatus = POPi;
843                                 /*
844                                  * FIXME: bug in perl
845                                  *
846                                  */
847                                 if (exitstatus >= 100 || exitstatus < 0) {
848                                         exitstatus = RLM_MODULE_FAIL;
849                                 }
850                         }
851                         PUTBACK;
852                         FREETMPS;
853                         LEAVE;
854                 }
855         }
856 #endif
857
858         if (inst->func_detach) {
859                 dTHXa(inst->perl);
860                 PERL_SET_CONTEXT(inst->perl);
861                 {
862                         dSP; ENTER; SAVETMPS;
863                         PUSHMARK(SP);
864
865                         count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
866                         SPAGAIN;
867
868                         if (count == 1) {
869                                 exitstatus = POPi;
870                                 if (exitstatus >= 100 || exitstatus < 0) {
871                                         exitstatus = RLM_MODULE_FAIL;
872                                 }
873                         }
874                         PUTBACK;
875                         FREETMPS;
876                         LEAVE;
877                 }
878         }
879
880 #ifdef USE_ITHREADS
881         rlm_perl_destruct(inst->perl);
882         pthread_mutex_destroy(&inst->clone_mutex);
883 #else
884         perl_destruct(inst->perl);
885         perl_free(inst->perl);
886 #endif
887
888         PERL_SYS_TERM();
889         return exitstatus;
890 }
891
892
893 /*
894  *      The module name should be the only globally exported symbol.
895  *      That is, everything else should be 'static'.
896  *
897  *      If the module needs to temporarily modify it's instantiation
898  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
899  *      The server will then take care of ensuring that the module
900  *      is single-threaded.
901  */
902 module_t rlm_perl = {
903         RLM_MODULE_INIT,
904         "perl",                         /* Name */
905 #ifdef USE_ITHREADS
906         RLM_TYPE_THREAD_SAFE,           /* type */
907 #else
908         RLM_TYPE_THREAD_UNSAFE,
909 #endif
910         sizeof(rlm_perl_t),
911         module_config,
912         mod_instantiate,                /* instantiation */
913         mod_detach,                     /* detach */
914         {
915                 mod_authenticate,       /* authenticate */
916                 mod_authorize,          /* authorize */
917                 mod_preacct,            /* preacct */
918                 mod_accounting, /* accounting */
919                 mod_checksimul,         /* check simul */
920 #ifdef WITH_PROXY
921                 mod_pre_proxy,          /* pre-proxy */
922                 mod_post_proxy, /* post-proxy */
923 #else
924                 NULL, NULL,
925 #endif
926                 mod_post_auth           /* post-auth */
927 #ifdef WITH_COA
928                 , mod_recv_coa,
929                 mod_send_coa
930 #endif
931         },
932 };