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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2002 The FreeRADIUS server project
21 * Copyright 2002 Boian Jordanov <bjordanov@orbitel.bg>
25 #include "libradius.h"
47 static const char rcsid[] = "$Id$";
50 * Define a structure for our module configuration.
52 * These variables do not need to be in a structure, but it's
53 * a lot cleaner to do so, and a pointer to the structure can
54 * be used as the instance handle.
56 typedef struct perl_inst {
61 PerlInterpreter *perl;
67 * A mapping of configuration file names to internal variables.
69 * Note that the string is dynamically allocated, so it MUST
70 * be freed. When the configuration file parse re-reads the string,
71 * it free's the old one, and strdup's the new one, placing the pointer
72 * to the strdup'd string into 'config.string'. This gets around
75 static CONF_PARSER module_config[] = {
76 { "cmd", PW_TYPE_STRING_PTR, offsetof(PERL_INST,cmd), NULL, NULL},
77 { "persistent", PW_TYPE_STRING_PTR, offsetof(PERL_INST,persistent), NULL, NULL},
78 { NULL, -1, 0, NULL, NULL } /* end the list */
84 EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
87 * Do any per-module initialization. e.g. set up connections
88 * to external databases, read configuration files, set up
89 * dictionary entries, etc.
91 * Try to avoid putting too much stuff in here - it's better to
92 * do it in instantiate() where it is not global.
94 static int perl_init(void)
97 * Everything's OK, return without an error.
106 static void xs_init(pTHX)
108 const char *file = __FILE__;
111 /* DynaLoader is a special case */
112 DEBUG("rlm_perl:: xs_init enter \n");
113 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
114 DEBUG("rlm_perl:: xs_init leave \n");
119 * Perl xlat we use already running perl just recompile and store in memory
120 * REMEMBER: each file will only be compiled once. Note that the process
121 * will continue to grow for each file that it uses and is not compiled.
124 * %{perl:/usr/bin/test.pl %{User-Name}} will run /usr/bin/test.pl,
125 * give @ARGV with User-Name in $ARGV[0]
126 * To return something just assign it to $main::ret_val
133 * print "ARGV[1]=$ARGV[1] ARGV[2]=$ARGV[2]\n";
134 * $main::ret_val = "B";
138 static int perl_xlat(void *instance, REQUEST *request, char *fmt, char *out, int freespace,
139 RADIUS_ESCAPE_STRING func)
141 PERL_INST *inst=instance;
144 char *args[] = {"", DO_CLEAN, NULL};
145 char params[1024], *tmp_ptr, *ptr;
146 int exitstatus=0,len;
151 * Do an xlat on the provided string (nice recursive operation).
154 if (!radius_xlat(params, sizeof(params), fmt, request, func))
156 radlog(L_ERR, "rlm_perl: xlat failed.");
160 PERL_SET_CONTEXT(inst->perl);
161 ptr = strtok(params, " ");
164 array_av = get_av("ARGV",0);
166 ret_val = get_sv("main::ret_val",1);
169 while ((tmp_ptr=strtok(NULL, " ")) != NULL) {
170 av_store(array_av,key++,newSVpv(tmp_ptr,0));
173 PERL_SET_CONTEXT(inst->perl);
174 call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
177 exitstatus = SvIV(perl_get_sv("!",FALSE));
178 radlog(L_INFO, "perl_embed::perl_xlat exit status=%d, %s\n", exitstatus, SvPV(ERRSV,n_a));
182 * Now get the variable we need
183 * His name is $ret_val
188 if (SvTRUE(ret_val)) {
190 out = SvPV(ret_val,n_a);
193 radlog(L_INFO,"Len is %d , out is %s", len, out);
195 if (len <= freespace)
204 * Do any per-module initialization that is separate to each
205 * configured instance of the module. e.g. set up connections
206 * to external databases, read configuration files, set up
207 * dictionary entries, etc.
209 * If configuration information is given in the config section
210 * that must be referenced in later calls, store a handle to it
211 * in *instance otherwise put a null pointer there.
213 static int perl_instantiate(CONF_SECTION *conf, void **instance)
216 char *embed[2], *xlat_name;
220 * Set up a storage area for instance data
223 inst = rad_malloc(sizeof(PERL_INST));
224 memset(inst, 0, sizeof(PERL_INST));
227 * If the configuration parameters can't be parsed, then
230 if (cf_section_parse(conf, inst, module_config) < 0) {
238 * Prepare perl instance
241 if((inst->perl = perl_alloc()) == NULL) {
242 radlog(L_INFO, "no memory!");
246 PERL_SET_CONTEXT(inst->perl);
247 perl_construct(inst->perl);
249 PERL_SET_CONTEXT(inst->perl);
252 embed[1] = inst->persistent;
254 exitstatus = perl_parse(inst->perl, xs_init, 2, embed, NULL);
256 PERL_SET_CONTEXT(inst->perl);
258 exitstatus = perl_run(inst->perl);
260 radlog(L_INFO,"perl_parse failed: %s not found or has syntax errors. \n", inst->persistent);
264 inst->env_hv = perl_get_hv("ENV",0);
265 inst->result_hv = perl_get_hv("main::result",1);
267 xlat_name = cf_section_name2(conf);
268 if (xlat_name == NULL)
269 xlat_name = cf_section_name1(conf);
271 inst->xlat_name = strdup(xlat_name);
272 xlat_register(xlat_name, perl_xlat, inst);
280 * Boyan get the request and put them in perl hash
281 * which will be given to perl cmd
283 static void perl_env(VALUE_PAIR *vp, PERL_INST *inst)
287 hv_clear(inst->env_hv);
288 hv_clear(inst->result_hv);
290 for ( ; vp != NULL; vp = vp->next) {
293 len = vp_prints_value(buffer, sizeof(buffer), vp, FALSE);
295 hv_store(inst->env_hv, vp->name, strlen(vp->name),
296 newSVpv(buffer, len),0);
301 * return structs and status 0 OK 1 Not
304 static int rlmperl_call(void *instance, REQUEST *request)
307 PERL_INST *inst = (PERL_INST *) instance;
310 char *key, *val, *ptr, *p;
311 char *args[] = {NULL, DO_CLEAN, NULL};
315 int exitstatus = 0, comma = 0;
320 perl_env(request->packet->vps, inst);
322 for (i = hv_iterinit(inst->env_hv); i > 0; i--) {
323 res_sv = hv_iternextsv(inst->env_hv, &key, &key_len);
324 val = SvPV(res_sv,val_len);
325 radlog(L_DBG, "ENV %s= %s", key, val);
328 PERL_SET_CONTEXT(inst->perl);
329 call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
334 exitstatus = SvIV(perl_get_sv("!",FALSE));;
335 radlog(L_INFO, "exit status=%d, %s\n", exitstatus,
340 PERL_SET_CONTEXT(inst->perl);
342 for (i = hv_iterinit(inst->result_hv); i > 0; i--) {
343 res_sv = hv_iternextsv(inst->result_hv,&key,&key_len);
344 val = SvPV(res_sv,val_len);
345 sprintf(ptr, "%s=\"%s\"\n", key, val); /* FIXME: snprintf */
346 ptr += key_len + val_len + 4;
348 /* perl_free(inst->perl); */
353 for (p = answer; *p; p++) {
355 *p = comma ? ' ' : ',';
358 if (*p == ',') comma++;
362 * Replace any trailing comma by a NUL.
364 if (answer[strlen(answer) - 1] == ',') {
365 answer[strlen(answer) - 1] = '\0';
367 radlog(L_INFO,"perl_embed :: value-pairs: %s", answer);
369 if (userparse(answer, &vp) < 0) {
370 radlog(L_ERR, "perl_embed :: %s: unparsable reply", args[0]);
372 pairmove(&request->reply->vps, &vp);
380 * Find the named user in this modules database. Create the set
381 * of attribute-value pairs to check and reply with for this user
382 * from the database. The authentication code only needs to check
383 * the password, the rest is done here.
385 static int perl_authorize(void *instance, REQUEST *request)
389 radlog(L_INFO,"perl_embed :: Enter Authorize");
391 if ((status = rlmperl_call(instance, request)) == 0) {
392 return RLM_MODULE_OK;
395 return RLM_MODULE_FAIL;
399 * Authenticate the user with the given password.
401 static int perl_authenticate(void *instance, REQUEST *request)
405 radlog(L_INFO,"perl_embed :: Enter Auth");
407 if ((status = rlmperl_call(instance, request)) == 0) {
408 return RLM_MODULE_OK;
411 return RLM_MODULE_FAIL;
416 * Massage the request before recording it or proxying it
418 static int perl_preacct(void *instance, REQUEST *request)
422 radlog(L_INFO,"mod_perl :: Enter PreAccounting");
424 if ((status = rlmperl_call(instance, request)) == 0) {
425 return RLM_MODULE_OK;
428 return RLM_MODULE_FAIL;
432 * Write accounting information to this modules database.
435 static int perl_accounting(void *instance, REQUEST *request)
439 radlog(L_INFO,"mod_perl :: Enter Accounting");
441 if ((status = (rlmperl_call(instance, request))) == 0) {
442 return RLM_MODULE_OK;
445 return RLM_MODULE_FAIL;
449 * Detach a instance free all ..
451 static int perl_detach(void *instance)
453 PERL_INST *inst=instance;
455 PERL_SET_CONTEXT(inst->perl);
456 perl_destruct(inst->perl);
457 PERL_SET_CONTEXT(inst->perl);
458 perl_free(inst->perl);
460 hv_clear(inst->env_hv);
461 hv_clear(inst->result_hv);
463 xlat_unregister(inst->xlat_name, perl_xlat);
464 free(inst->xlat_name);
467 free(inst->persistent);
474 * The module name should be the only globally exported symbol.
475 * That is, everything else should be 'static'.
477 * If the module needs to temporarily modify it's instantiation
478 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
479 * The server will then take care of ensuring that the module
480 * is single-threaded.
482 module_t rlm_perl = {
484 RLM_TYPE_THREAD_UNSAFE, /* type */
485 perl_init, /* initialization */
486 perl_instantiate, /* instantiation */
493 perl_detach, /* detach */