Handle tagged attributes with multiple values in rlm_perl.
[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)
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, NULL, NULL)) {
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 len;
557
558         hv_undef(rad_hv);
559         nvp = paircopy(vp);
560
561         while (nvp != NULL) {
562                 if (nvp->flags.has_tag && (nvp->flags.tag != 0)) {
563                         snprintf(namebuf, sizeof(namebuf), "%s:%d",
564                                  nvp->name, nvp->flags.tag);
565                         name = namebuf;
566                 } else {
567                         name = nvp->name;
568                 }
569
570                 vpa = paircopy2(nvp, nvp->attribute, nvp->vendor, nvp->flags.tag);
571
572                 if (vpa->next) {
573                         av = newAV();
574                         for (vpn = vpa; vpn; vpn = vpn->next) {
575                                 len = vp_prints_value(buffer, sizeof(buffer), vpn, FALSE);
576                                 av_push(av, newSVpv(buffer, len));
577                         }
578                         hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
579                 } else {
580                         len = vp_prints_value(buffer, sizeof(buffer), vpa, FALSE);
581                         hv_store(rad_hv, name, strlen(name), newSVpv(buffer, len), 0);
582                 }
583
584                 pairfree(&vpa);
585                 pairdelete(&nvp, nvp->attribute, nvp->vendor, nvp->flags.tag);
586         }
587 }
588
589 /*
590  *
591  *     Verify that a Perl SV is a string and save it in FreeRadius
592  *     Value Pair Format
593  *
594  */
595 static int pairadd_sv(VALUE_PAIR **vp, char *key, SV *sv, int operator) {
596        char            *val;
597        VALUE_PAIR      *vpp;
598
599        if (SvOK(sv)) {
600                val = SvPV_nolen(sv);
601                vpp = pairmake(key, val, operator);
602                if (vpp != NULL) {
603                        pairadd(vp, vpp);
604                        radlog(L_DBG,
605                          "rlm_perl: Added pair %s = %s", key, val);
606                        return 1;
607                } else {
608                        radlog(L_DBG,
609                          "rlm_perl: ERROR: Failed to create pair %s = %s",
610                          key, val);
611                }
612         }
613        return 0;
614 }
615
616 /*
617   *     Boyan :
618   *     Gets the content from hashes
619   */
620 static int get_hv_content(HV *my_hv, VALUE_PAIR **vp)
621 {
622        SV               *res_sv, **av_sv;
623        AV               *av;
624        char             *key;
625        I32              key_len, len, i, j;
626        int              ret=0;
627
628        *vp = NULL;
629        for (i = hv_iterinit(my_hv); i > 0; i--) {
630                res_sv = hv_iternextsv(my_hv,&key,&key_len);
631                if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
632                        av = (AV*)SvRV(res_sv);
633                        len = av_len(av);
634                        for (j = 0; j <= len; j++) {
635                                av_sv = av_fetch(av, j, 0);
636                                ret = pairadd_sv(vp, key, *av_sv, T_OP_ADD) + ret;
637                        }
638                } else ret = pairadd_sv(vp, key, res_sv, T_OP_EQ) + ret;
639         }
640
641         return ret;
642 }
643
644 /*
645  *      Call the function_name inside the module
646  *      Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
647  *
648  */
649 static int rlmperl_call(void *instance, REQUEST *request, char *function_name)
650 {
651
652         PERL_INST       *inst = instance;
653         VALUE_PAIR      *vp;
654         int             exitstatus=0, count;
655         STRLEN          n_a;
656
657         HV              *rad_reply_hv;
658         HV              *rad_check_hv;
659         HV              *rad_config_hv;
660         HV              *rad_request_hv;
661 #ifdef WITH_PROXY
662         HV              *rad_request_proxy_hv;
663         HV              *rad_request_proxy_reply_hv;
664 #endif
665         
666 #ifdef USE_ITHREADS
667         pthread_mutex_lock(&inst->clone_mutex);
668
669         PerlInterpreter *interp;
670
671         interp = rlm_perl_clone(inst->perl,inst->thread_key);
672         {
673           dTHXa(interp);
674           PERL_SET_CONTEXT(interp);
675         }
676         
677         pthread_mutex_unlock(&inst->clone_mutex);
678 #else
679         PERL_SET_CONTEXT(inst->perl);
680 #endif
681
682         {
683         dSP;
684
685         ENTER;
686         SAVETMPS;
687
688
689         /*
690          *      Radius has told us to call this function, but none
691          *      is defined.
692          */
693         if (!function_name) {
694                 return RLM_MODULE_FAIL;
695         }
696
697         rad_reply_hv = get_hv("RAD_REPLY",1);
698         rad_check_hv = get_hv("RAD_CHECK",1);
699         rad_config_hv = get_hv("RAD_CONFIG",1);
700         rad_request_hv = get_hv("RAD_REQUEST",1);
701 #ifdef WITH_PROXY
702         rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
703         rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
704 #endif
705
706         perl_store_vps(request->reply->vps, rad_reply_hv);
707         perl_store_vps(request->config_items, rad_check_hv);
708         perl_store_vps(request->packet->vps, rad_request_hv);
709         perl_store_vps(request->config_items, rad_config_hv);
710
711 #ifdef WITH_PROXY
712         if (request->proxy != NULL) {
713                 perl_store_vps(request->proxy->vps, rad_request_proxy_hv);
714         } else {
715                 hv_undef(rad_request_proxy_hv);
716         }
717
718         if (request->proxy_reply !=NULL) {
719                 perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv);
720         } else {
721                 hv_undef(rad_request_proxy_reply_hv);
722         }
723 #endif
724
725         PUSHMARK(SP);
726         /*
727         * This way %RAD_xx can be pushed onto stack as sub parameters.
728         * XPUSHs( newRV_noinc((SV *)rad_request_hv) );
729         * XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
730         * XPUSHs( newRV_noinc((SV *)rad_check_hv) );
731         * PUTBACK;
732         */
733
734         count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);
735
736         SPAGAIN;
737
738         if (SvTRUE(ERRSV)) {
739                 radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n",
740                        inst->module,
741                        function_name, SvPV(ERRSV,n_a));
742                 POPs;
743         }
744
745         if (count == 1) {
746                 exitstatus = POPi;
747                 if (exitstatus >= 100 || exitstatus < 0) {
748                         exitstatus = RLM_MODULE_FAIL;
749                 }
750         }
751
752
753         PUTBACK;
754         FREETMPS;
755         LEAVE;
756
757         vp = NULL;
758         if ((get_hv_content(rad_request_hv, &vp)) > 0 ) {
759                 pairfree(&request->packet->vps);
760                 request->packet->vps = vp;
761                 vp = NULL;
762
763                 /*
764                  *      Update cached copies
765                  */
766                 request->username = pairfind(request->packet->vps,
767                                              PW_USER_NAME, 0);
768                 request->password = pairfind(request->packet->vps,
769                                              PW_USER_PASSWORD, 0);
770                 if (!request->password)
771                         request->password = pairfind(request->packet->vps,
772                                                      PW_CHAP_PASSWORD, 0);
773         }
774
775         if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) {
776                 pairfree(&request->reply->vps);
777                 request->reply->vps = vp;
778                 vp = NULL;
779         }
780
781         if ((get_hv_content(rad_check_hv, &vp)) > 0 ) {
782                 pairfree(&request->config_items);
783                 request->config_items = vp;
784                 vp = NULL;
785         }
786
787 #ifdef WITH_PROXY
788         if (request->proxy &&
789             (get_hv_content(rad_request_proxy_hv, &vp) > 0)) {
790                 pairfree(&request->proxy->vps);
791                 request->proxy->vps = vp;
792                 vp = NULL;
793         }
794
795         if (request->proxy_reply &&
796             (get_hv_content(rad_request_proxy_reply_hv, &vp) > 0)) {
797                 pairfree(&request->proxy_reply->vps);
798                 request->proxy_reply->vps = vp;
799                 vp = NULL;
800         }
801 #endif
802
803         }
804         return exitstatus;
805 }
806
807 /*
808  *      Find the named user in this modules database.  Create the set
809  *      of attribute-value pairs to check and reply with for this user
810  *      from the database. The authentication code only needs to check
811  *      the password, the rest is done here.
812  */
813 static int perl_authorize(void *instance, REQUEST *request)
814 {
815         return rlmperl_call(instance, request,
816                             ((PERL_INST *)instance)->func_authorize);
817 }
818
819 /*
820  *      Authenticate the user with the given password.
821  */
822 static int perl_authenticate(void *instance, REQUEST *request)
823 {
824         return rlmperl_call(instance, request,
825                             ((PERL_INST *)instance)->func_authenticate);
826 }
827 /*
828  *      Massage the request before recording it or proxying it
829  */
830 static int perl_preacct(void *instance, REQUEST *request)
831 {
832         return rlmperl_call(instance, request,
833                             ((PERL_INST *)instance)->func_preacct);
834 }
835 /*
836  *      Write accounting information to this modules database.
837  */
838 static int perl_accounting(void *instance, REQUEST *request)
839 {
840         VALUE_PAIR      *pair;
841         int             acctstatustype=0;
842
843         if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0)) != NULL) {
844                 acctstatustype = pair->vp_integer;
845         } else {
846                 radlog(L_ERR, "Invalid Accounting Packet");
847                 return RLM_MODULE_INVALID;
848         }
849
850         switch (acctstatustype) {
851
852                 case PW_STATUS_START:
853
854                         if (((PERL_INST *)instance)->func_start_accounting) {
855                                 return rlmperl_call(instance, request,
856                                             ((PERL_INST *)instance)->func_start_accounting);
857                         } else {
858                                 return rlmperl_call(instance, request,
859                                             ((PERL_INST *)instance)->func_accounting);
860                         }
861                         break;
862
863                 case PW_STATUS_STOP:
864
865                         if (((PERL_INST *)instance)->func_stop_accounting) {
866                                 return rlmperl_call(instance, request,
867                                             ((PERL_INST *)instance)->func_stop_accounting);
868                         } else {
869                                 return rlmperl_call(instance, request,
870                                             ((PERL_INST *)instance)->func_accounting);
871                         }
872                         break;
873                 default:
874                         return rlmperl_call(instance, request,
875                                             ((PERL_INST *)instance)->func_accounting);
876
877         }
878 }
879 /*
880  *      Check for simultaneouse-use
881  */
882 static int perl_checksimul(void *instance, REQUEST *request)
883 {
884         return rlmperl_call(instance, request,
885                         ((PERL_INST *)instance)->func_checksimul);
886 }
887
888 #ifdef WITH_PROXY
889 /*
890  *      Pre-Proxy request
891  */
892 static int perl_pre_proxy(void *instance, REQUEST *request)
893 {
894         return rlmperl_call(instance, request,
895                         ((PERL_INST *)instance)->func_pre_proxy);
896 }
897 /*
898  *      Post-Proxy request
899  */
900 static int perl_post_proxy(void *instance, REQUEST *request)
901 {
902         return rlmperl_call(instance, request,
903                         ((PERL_INST *)instance)->func_post_proxy);
904 }
905 #endif
906
907 /*
908  *      Pre-Auth request
909  */
910 static int perl_post_auth(void *instance, REQUEST *request)
911 {
912         return rlmperl_call(instance, request,
913                         ((PERL_INST *)instance)->func_post_auth);
914 }
915 #ifdef WITH_COA
916 /*
917  *      Recv CoA request
918  */
919 static int perl_recv_coa(void *instance, REQUEST *request)
920 {
921         return rlmperl_call(instance, request,
922                         ((PERL_INST *)instance)->func_recv_coa);
923 }
924 /*
925  *      Send CoA request
926  */
927 static int perl_send_coa(void *instance, REQUEST *request)
928 {
929         return rlmperl_call(instance, request,
930                         ((PERL_INST *)instance)->func_send_coa);
931 }
932 #endif
933 /*
934  * Detach a instance give a chance to a module to make some internal setup ...
935  */
936 static int perl_detach(void *instance)
937 {
938         PERL_INST       *inst = (PERL_INST *) instance;
939         int             exitstatus = 0, count = 0;
940
941 #if 0
942         /*
943          *      FIXME: Call this in the destruct function?
944          */
945                 {
946                 dTHXa(handle->clone);
947                 PERL_SET_CONTEXT(handle->clone);
948                 {
949                 dSP; ENTER; SAVETMPS; PUSHMARK(SP);
950                 count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
951                 SPAGAIN;
952
953                 if (count == 1) {
954                         exitstatus = POPi;
955                         /*
956                          * FIXME: bug in perl
957                          *
958                          */
959                         if (exitstatus >= 100 || exitstatus < 0) {
960                                 exitstatus = RLM_MODULE_FAIL;
961                         }
962                 }
963                 PUTBACK;
964                 FREETMPS;
965                 LEAVE;
966                 }
967                 }
968 #endif
969
970                 if (inst->func_detach) {
971         dTHXa(inst->perl);
972         PERL_SET_CONTEXT(inst->perl);
973         {
974         dSP; ENTER; SAVETMPS;
975         PUSHMARK(SP);
976
977         count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
978         SPAGAIN;
979
980         if (count == 1) {
981                 exitstatus = POPi;
982                 if (exitstatus >= 100 || exitstatus < 0) {
983                         exitstatus = RLM_MODULE_FAIL;
984                 }
985         }
986         PUTBACK;
987         FREETMPS;
988         LEAVE;
989         }
990         }
991
992         xlat_unregister(inst->xlat_name, perl_xlat, instance);
993         free(inst->xlat_name);
994
995 #ifdef USE_ITHREADS
996         rlm_perl_destruct(inst->perl);
997         pthread_mutex_destroy(&inst->clone_mutex);
998 #else
999         perl_destruct(inst->perl);
1000         perl_free(inst->perl);
1001 #endif
1002
1003         PERL_SYS_TERM();
1004         free(inst);
1005         return exitstatus;
1006 }
1007
1008
1009 /*
1010  *      The module name should be the only globally exported symbol.
1011  *      That is, everything else should be 'static'.
1012  *
1013  *      If the module needs to temporarily modify it's instantiation
1014  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
1015  *      The server will then take care of ensuring that the module
1016  *      is single-threaded.
1017  */
1018 module_t rlm_perl = {
1019         RLM_MODULE_INIT,
1020         "perl",                         /* Name */
1021 #ifdef USE_ITHREADS
1022         RLM_TYPE_THREAD_SAFE,           /* type */
1023 #else
1024         RLM_TYPE_THREAD_UNSAFE,
1025 #endif
1026         perl_instantiate,               /* instantiation */
1027         perl_detach,                    /* detach */
1028         {
1029                 perl_authenticate,      /* authenticate */
1030                 perl_authorize,         /* authorize */
1031                 perl_preacct,           /* preacct */
1032                 perl_accounting,        /* accounting */
1033                 perl_checksimul,        /* check simul */
1034 #ifdef WITH_PROXY
1035                 perl_pre_proxy,         /* pre-proxy */
1036                 perl_post_proxy,        /* post-proxy */
1037 #else
1038                 NULL, NULL,
1039 #endif
1040                 perl_post_auth          /* post-auth */
1041 #ifdef WITH_COA
1042                 , perl_recv_coa,
1043                 perl_send_coa
1044 #endif
1045         },
1046 };