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