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 2000 The FreeRADIUS server project
21 * Copyright 2000 Boian Jordanov <bjordanov@orbitel.bg>
25 #include "libradius.h"
45 static const char rcsid[] = "$Id$";
48 * Define a structure for our module configuration.
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.
54 typedef struct perl_config {
59 * Some other things will be added in future
61 typedef struct perl_inst {
62 PerlInterpreter *perl;
69 * A mapping of configuration file names to internal variables.
71 * Note that the string is dynamically allocated, so it MUST
72 * be freed. When the configuration file parse re-reads the string,
73 * it free's the old one, and strdup's the new one, placing the pointer
74 * to the strdup'd string into 'config.string'. This gets around
77 static CONF_PARSER module_config[] = {
78 { "cmd", PW_TYPE_STRING_PTR, offsetof(PERL_CONFIG,cmd), NULL, NULL},
79 { NULL, -1, 0, NULL, NULL } /* end the list */
85 EXTERN_C void xs_init _((void));
88 * Do any per-module initialization. e.g. set up connections
89 * to external databases, read configuration files, set up
90 * dictionary entries, etc.
92 * Try to avoid putting too much stuff in here - it's better to
93 * do it in instantiate() where it is not global.
95 static int perl_init(void)
98 * Everything's OK, return without an error.
104 * Do any per-module initialization that is separate to each
105 * configured instance of the module. e.g. set up connections
106 * to external databases, read configuration files, set up
107 * dictionary entries, etc.
109 * If configuration information is given in the config section
110 * that must be referenced in later calls, store a handle to it
111 * in *instance otherwise put a null pointer there.
113 static int perl_instantiate(CONF_SECTION *conf, void **instance)
119 * Set up a storage area for instance data
122 inst = rad_malloc(sizeof(PERL_INST));
123 memset(inst, 0, sizeof(PERL_INST));
125 inst->config = rad_malloc(sizeof(PERL_CONFIG));
126 memset(inst->config, 0, sizeof(PERL_CONFIG));
128 * If the configuration parameters can't be parsed, then
131 if (cf_section_parse(conf, inst->config, module_config) < 0) {
139 * Prepare perl instance
142 if((inst->perl = perl_alloc()) == NULL) {
143 radlog(L_INFO, "no memory!");
147 PERL_SET_CONTEXT(inst->perl);
148 perl_construct(inst->perl);
150 PERL_SET_CONTEXT(inst->perl);
153 * FIXME: This should be:
155 * ... perl_parse(inst->perl, xs_init, my_argc, my_argv, NULL);
157 * but we have no idea where to get my_argc and my_argv from.
159 exitstatus = perl_parse(inst->perl, xs_init, 0, NULL, NULL);
161 PERL_SET_CONTEXT(inst->perl);
163 exitstatus = perl_run(inst->perl);
165 radlog(L_INFO,"perl_parse failed: persistent.pl not found or has syntax errors. \n");
168 inst->env_hv=perl_get_hv("ENV",0);
169 inst->result_hv=perl_get_hv("main::result",1);
177 * Boyan get the request and put them in perl hash
178 * which will be given to perl cmd
181 static void perl_env(VALUE_PAIR *vp, PERL_INST *inst)
185 hv_clear(inst->env_hv);
186 hv_clear(inst->result_hv);
188 for ( ; vp != NULL; vp = vp->next) {
191 len = vp_prints_value(buffer, sizeof(buffer), vp, FALSE);
193 hv_store(inst->env_hv, vp->name, strlen(vp->name),
194 newSVpv(buffer, len),0);
199 * return structs and status 0 OK 1 Not
202 static int rlmperl_call(void *instance, REQUEST *request)
205 PERL_INST *inst=instance;
208 char *key,*val,*ptr,*p;
209 char *args[] = {"", DO_CLEAN, NULL};
213 int exitstatus = 0,comma=0;
216 args[0] = inst->config->cmd;
218 perl_env(request->packet->vps, inst);
220 for (i = hv_iterinit(inst->env_hv); i > 0; i--) {
221 res_sv = hv_iternextsv(inst->env_hv, &key, &key_len);
222 val = SvPV(res_sv,val_len);
223 radlog(L_INFO, "ENV %s= %s",key,val);
227 PERL_SET_CONTEXT(inst->perl);
228 call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
233 exitstatus = SvIV(perl_get_sv("!",FALSE));;
234 radlog(L_INFO, "exit status=%d, %s\n", exitstatus,
239 PERL_SET_CONTEXT(inst->perl);
241 for (i = hv_iterinit(inst->result_hv); i > 0; i--) {
242 res_sv = hv_iternextsv(inst->result_hv,&key,&key_len);
243 val = SvPV(res_sv,val_len);
244 sprintf(ptr, "%s=\"%s\"\n", key, val); /* FIXME: snprintf */
245 ptr += key_len + val_len + 4;
247 /* perl_free(inst->perl); */
252 for (p = answer; *p; p++) {
254 *p = comma ? ' ' : ',';
257 if (*p == ',') comma++;
261 * Replace any trailing comma by a NUL.
263 if (answer[strlen(answer) - 1] == ',') {
264 answer[strlen(answer) - 1] = '\0';
266 radlog(L_INFO,"perl_embed :: value-pairs: %s", answer);
268 if (userparse(answer, &vp) < 0) {
269 radlog(L_ERR, "perl_embed :: %s: unparsable reply", args[0]);
271 pairmove(&request->reply->vps, &vp);
279 * Find the named user in this modules database. Create the set
280 * of attribute-value pairs to check and reply with for this user
281 * from the database. The authentication code only needs to check
282 * the password, the rest is done here.
284 static int perl_authorize(void *instance, REQUEST *request)
288 radlog(L_INFO,"perl_embed :: Enter Authorize");
290 if ((status = rlmperl_call(instance, request)) == 0) {
291 return RLM_MODULE_OK;
294 return RLM_MODULE_FAIL;
298 * Authenticate the user with the given password.
300 static int perl_authenticate(void *instance, REQUEST *request)
304 radlog(L_INFO,"perl_embed :: Enter Auth");
306 if ((status = rlmperl_call(instance, request)) == 0) {
307 return RLM_MODULE_OK;
310 return RLM_MODULE_FAIL;
315 * Massage the request before recording it or proxying it
317 static int perl_preacct(void *instance, REQUEST *request)
321 radlog(L_INFO,"mod_perl :: Enter PreAccounting");
323 if ((status = rlmperl_call(instance, request)) == 0) {
324 return RLM_MODULE_OK;
327 return RLM_MODULE_FAIL;
331 * Write accounting information to this modules database.
334 static int perl_accounting(void *instance, REQUEST *request)
338 radlog(L_INFO,"mod_perl :: Enter Accounting");
340 if ((status = (rlmperl_call(instance, request))) == 0) {
341 return RLM_MODULE_OK;
344 return RLM_MODULE_FAIL;
348 * Detach a instance free all ..
350 static int perl_detach(void *instance)
352 PERL_INST *inst=instance;
353 PERL_SET_CONTEXT(inst->perl);
354 perl_destruct(inst->perl);
355 PERL_SET_CONTEXT(inst->perl);
356 perl_free(inst->perl);
359 hv_clear(inst->env_hv);
360 hv_clear(inst->result_hv);
367 * The module name should be the only globally exported symbol.
368 * That is, everything else should be 'static'.
370 * If the module needs to temporarily modify it's instantiation
371 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
372 * The server will then take care of ensuring that the module
373 * is single-threaded.
375 module_t rlm_perl = {
377 RLM_TYPE_THREAD_UNSAFE, /* type */
378 perl_init, /* initialization */
379 perl_instantiate, /* instantiation */
386 perl_detach, /* detach */