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