2 * rlm_dbm.c authorize: authorize using ndbm database
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 2001 Koulik Andrei, Sandy Service
23 #include <freeradius-devel/autoconf.h>
32 #ifdef HAVE_GDBM_NDBM_H
33 #include <gdbm/ndbm.h>
36 #ifdef HAVE_GDBMNDBM_H
37 #include <gdbm-ndbm.h>
42 #include <freeradius-devel/radiusd.h>
43 #include <freeradius-devel/modules.h>
46 # include "sandymod.h"
49 static const char rcsid[] = "$Id$";
52 #define get_user_content dbm_fetch
54 #define SM_JOIN_ATTR 1029
57 # define SM_POOL_ATTR 510
60 typedef struct rlm_dbm_t {
70 typedef struct user_entry {
72 struct user_entry * next;
76 static const CONF_PARSER module_config[] = {
77 { "usersfile", PW_TYPE_STRING_PTR,offsetof(struct rlm_dbm_t,userfile),
79 { NULL, -1, 0, NULL, NULL }
82 static void sm_user_list_wipe (SM_USER_ENTRY **ue) {
84 SM_USER_ENTRY * pue, *nue;
89 while ( pue != NULL ) {
91 DEBUG2("Remove %s from user list", pue -> username);
92 free(pue -> username);
100 * add username un to user list ue;
101 * return 0 if user succefuly added
102 * 1 - if username already exists
103 * -1 - error: no memmory
106 static int sm_user_list_add(SM_USER_ENTRY **ue, const char *un) {
109 if ( strcmp( (*ue) -> username, un) == 0 ) return 1;
110 ue = & ((*ue) -> next);
112 *ue = malloc(sizeof(SM_USER_ENTRY));
113 if ( !*ue ) return -1;
114 (*ue) -> username = strdup(un);
115 DEBUG2("Add %s to user list", (*ue) -> username);
116 (*ue) -> next = NULL ;
117 if ( ! (*ue) -> username ) {
134 static int isfallthrough(VALUE_PAIR *vp) {
137 tmp = pairfind(vp, PW_FALL_THROUGH);
138 return tmp ? tmp -> lvalue : 1; /* if no FALL_THROUGH - keep looking */
142 * find user, parse and return result
145 * username - user name from request
146 * request - pair originated from the nas
147 * mode - search mode SM_SM_ACCUM - accumulative search mode
150 * parsed_users - list of parsed user names for loop removal
153 static int sm_parse_user(DBM *pdb, const char * username, VALUE_PAIR const* request, VALUE_PAIR **config,
154 VALUE_PAIR **reply, SM_USER_ENTRY **ulist)
157 int retcod, found = RLM_MODULE_NOTFOUND, res ;
158 VALUE_PAIR *vp = NULL,* tmp_config = NULL, *tmp_reply = NULL, *nu_reply = NULL;
159 VALUE_PAIR *join_attr;
162 int parse_state = SMP_PATTERN;
163 int continue_search = 1;
167 DEBUG2("sm_parse_user.c: check for loops");
169 if ( (retcod = sm_user_list_add(ulist,username) ) ) {
170 if ( retcod < 0 ) radlog(L_ERR,"rlm_dbm: Couldn't allocate memory");
171 else radlog(L_ERR,"rlm_dbm: Invalid configuration: loop detected");
172 return RLM_MODULE_FAIL;
175 /* retrieve user content */
178 k.dsize = strlen(username) + 1 ; /* username stored with '\0' */
180 d = dbm_fetch(pdb, k);
181 if ( d.dptr == NULL ) {
182 DEBUG2("rlm_dbm: User <%s> not foud in database\n",username);
183 return RLM_MODULE_NOTFOUND;
187 ch [ d.dsize - 1 ] = '\0'; /* should be closed by 0 */
189 DEBUG2("sm_parse_user: start parsing: user: %s", username);
191 /* start parse content */
192 while ( parse_state != SMP_ERROR && *ch && continue_search ) {
196 while( *ch && *ch != '\n') ch++ ;
198 if ( *ch == '\n' ) { *ch = 0; ch++; }
200 DEBUG2("parse buffer: <<%s>>\n",beg);
202 retcod = userparse(beg,&vp);
203 if ( retcod == T_OP_INVALID ) librad_perror("parse error ");
206 case T_COMMA: break; /* continue parse the current list */
207 case T_EOL: DEBUG2("rlm_dbm: recod parsed\n"); /* vp contains full pair list */
208 if ( parse_state == SMP_PATTERN ) { /* pattern line found */
209 DEBUG2("process pattern");
210 /* check pattern against request */
211 if ( paircompare(NULL, request, vp, reply ) == 0 ) {
212 DEBUG2("rlm_dbm: Pattern matched, look for request");
213 pairmove(&tmp_config, &vp);
215 parse_state = SMP_REPLY; /* look for reply */
218 DEBUG2("rlm_dbm: patern not matched, reply skiped");
220 while ( *ch && *ch !='\n' ) ch++;
221 if ( *ch == '\n' ) ch++;
223 } else { /* reply line found */
224 /* look for join-attribute */
225 DEBUG2("rlm_dbm: Reply found");
227 while( (join_attr = pairfind(join_attr,SM_JOIN_ATTR) ) != NULL ) {
228 DEBUG2("rlm_dbm: Proccess nested record: username %s",
229 (char *)join_attr->vp_strvalue);
230 /* res = RLM_MODULE_NOTFOUND; */
231 res = sm_parse_user(pdb, (char *)join_attr->vp_strvalue, request, &tmp_config,
233 DEBUG("rlm_dbm: recived: %d\n",res);
235 case RLM_MODULE_NOTFOUND:
238 default: /* seems error code */
239 parse_state = SMP_ERROR;
240 DEBUG2("rlm_dbm: Nested record error\n");
243 join_attr = join_attr -> next;
245 pairdelete(&vp,SM_JOIN_ATTR);
246 if ( parse_state != SMP_ERROR ) {
247 if ( ! isfallthrough(vp) ) {
249 DEBUG2("rlm_dbm: Break search due Fall-Through = no");
251 pairmove(&vp,&nu_reply);
253 pairmove(&tmp_reply,&vp);
255 parse_state = SMP_PATTERN;
256 found = RLM_MODULE_OK;
259 pairfree(&nu_reply); }
261 default: /* we do not wait that !!!! */
262 parse_state = SMP_ERROR;
263 DEBUG2("rlm_dbm: Unknown token: %d\n",retcod);
268 if ( parse_state == SMP_PATTERN ) {
269 pairmove(config,&tmp_config);
270 pairfree(&tmp_config);
271 pairmove(reply,&tmp_reply);
272 pairfree(&tmp_reply);
274 pairfree(&tmp_config);
275 pairfree(&tmp_reply);
277 DEBUG2("rlm_dbm: Bad final parse state: %d\n",parse_state);
278 found = RLM_MODULE_FAIL ;
284 static int sm_postprocessor(VALUE_PAIR **reply UNUSED) {
288 static int rlm_dbm_instantiate(CONF_SECTION *conf, void **instance) {
289 struct rlm_dbm_t *inst;
291 inst = rad_malloc(sizeof(rlm_dbm_t));
295 memset(inst, 0, sizeof(*inst));
297 if (cf_section_parse(conf, inst, module_config) < 0) {
304 static int rlm_dbm_authorize(void *instance, REQUEST *request)
306 VALUE_PAIR *namepair;
307 VALUE_PAIR *request_pairs;
308 VALUE_PAIR *check_tmp = NULL;
309 VALUE_PAIR *reply_tmp = NULL;
313 SM_USER_ENTRY *ulist = NULL;
316 struct rlm_dbm_t *inst = instance;
318 VALUE_PAIR **check_pairs, **reply_pairs;
320 request_pairs = request->packet->vps;
321 check_pairs = &request->config_items;
322 reply_pairs = &request->reply->vps;
325 * Grab the canonical user name.
327 namepair = request->username;
328 name = namepair ? (char *) namepair->vp_strvalue : "NONE";
330 DEBUG2("rlm_dbm: try open database file: %s\n",inst -> userfile);
333 if ( ( pdb = dbm_open(inst->userfile, O_RDONLY, 0600) ) != NULL ) {
334 DEBUG("rlm_dbm: Call parse_user:\n");
335 found = sm_parse_user(pdb, name, request_pairs, &check_tmp, &reply_tmp, &ulist);
336 if ( found == RLM_MODULE_NOTFOUND ) {
337 sm_user_list_wipe(&ulist);
338 found = sm_parse_user(pdb, "DEFAULT", request_pairs, &check_tmp, &reply_tmp, &ulist);
342 found = RLM_MODULE_FAIL;
343 DEBUG2("rlm_dbm: Cannot open database file: %s\n",
347 if ( found == RLM_MODULE_OK ) {
348 /* do preprocessor for final reply-pair tranformation */
349 if ( !sm_postprocessor(&reply_tmp) ) {
350 pairmove(reply_pairs, &reply_tmp);
351 pairmove(check_pairs, &check_tmp);
352 } else found = RLM_MODULE_FAIL;
354 sm_user_list_wipe(&ulist);
355 pairfree(&reply_tmp);
356 pairfree(&check_tmp);
361 static int rlm_dbm_detach(void *instance)
363 struct rlm_dbm_t *inst = instance;
364 free(inst -> userfile);
370 /* globally exported name */
374 0, /* type: reserved */
375 rlm_dbm_instantiate, /* instantiation */
376 rlm_dbm_detach, /* detach */
378 NULL, /* authentication */
379 rlm_dbm_authorize, /* authorization */
380 NULL, /* preaccounting */
381 NULL, /* accounting */
382 NULL, /* checksimul */
383 NULL, /* pre-proxy */
384 NULL, /* post-proxy */