2 * rlm_dbm_parser.c : Create dbm file from plain text
6 * This program is is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2 if the
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * Copyright 2001 Koulik Andrei, Sandy Service
20 "$Id$ sandy module project\n Copyright 2001 Sandy Service\nCopyright 2001 Koulik Andrei";
31 #ifdef HAVE_GDBM_NDBM_H
32 #include <gdbm/ndbm.h>
35 #ifdef HAVE_GDBMNDBM_H
36 #include <gdbm-ndbm.h>
49 #define MAX_BUFF_SIZE 1024
51 #define DOUT1 if( librad_debug > 0 ) printf
52 #define DOUT2 if( librad_debug > 5 ) printf
54 typedef enum sm_parse_state_t {
65 const char * progname;
67 unsigned long st_errors = 0,
77 int dumplist(VALUE_PAIR *vp) {
81 printf("VP: name: %s\nattribute: %d\ntype: %d\nlvalue: %lu"
82 "\noperator %d\naddport: %d\nValue: %s\n",
83 vp -> name, vp -> attribute, vp -> type, vp -> lvalue,
84 vp -> operator, vp -> addport, (char*)vp -> strvalue);
93 char const *sm_tokens[]={
94 "INVALID","EOL","{","}","(",")",",",";","+=",
95 "-=",":=","=","!=",">=",">","<=","<","=~","!~","==","#"
100 static int sm_prints(char *out, int outlen, VALUE_PAIR *vp) {
107 if (strlen(vp->name) + 4 > (size_t)outlen) {
111 snprintf(out, outlen, "%s %s ",
113 sm_tokens[vp->operator] );
116 vp_prints_value(out + len, outlen - len, vp, 1);
126 int oflags = O_RDWR | O_CREAT;
130 static int open_storage(const char * fname) {
132 if ( (pdb = dbm_open(fname, oflags, 0600 )) == NULL ) {
133 perror("Couldn't open database");
139 static void close_storage(void){
143 static int addlinetocontent(VALUE_PAIR *vp) {
145 int outlen = sizeof(content) - concntr - 1;
148 if ( outlen < 4 ) return -1;
149 if ( vp == NULL ) { /* add empty line */
150 content[concntr++] = '\n';
151 content[concntr] = '\0';
153 while ( vp != NULL ){
154 lendiv = sm_prints(&content[concntr],outlen,vp);
159 strcat(content,", ");
160 concntr += lendiv + 2;
170 if ( concntr > 2 ) { /* remove trailing ',' */
171 content[--concntr] = '\0';
172 content[concntr - 1] = '\n';
179 static int storecontent (const char * username) {
184 if ( pdb == NULL || concntr < 3 ) return 1;
186 DOUT2("store:\n%s\ncontent:\n%s",username,content);
189 d.dsize = concntr + 1;
192 k.dsize = strlen(username) + 1;
194 res = dbm_store(pdb, k, d, DBM_INSERT);
195 if ( res == 1 ) dbm_store(pdb, k, d, DBM_REPLACE);
197 perror("Couldn't insert record");
207 static int getuname(char **p,char *u,int n) {
210 for(i=0 ; ( i < n-1 ) && ( **p ) && (! isspace(**p) ) ; (*p)++ )
213 return ( i == 0) ? 1:0;
216 static int sm_parse_file(FILE*fp,const char* fname) {
218 VALUE_PAIR *vp = NULL;
219 sm_parse_state_t parse_state = SMP_USER;
220 unsigned long lino = 0;
222 char buff[MAX_BUFF_SIZE];
226 while( parse_state != SMP_INVALID && fgets(buff, sizeof(buff), fp) != NULL ) {
230 if ( strchr(buff, '\n') == NULL) {
231 fprintf(stderr,"%s: %s[%lu]:Warning: line too long or not closed by \\n character. Skiped\n",progname,fname,lino);
233 st_skiped++; /* _LINE_ skiped */
237 DOUT2("Parseline: %s",buff);
238 for ( p = buff; isspace(*p); p++);
240 if ( *p == '#' || *p == 0 ) continue;
243 if ( *p == ';' ) *p = '\n';
246 /* try to decide is this line new user or new pattern */
247 if ( parse_state == SMP_PATTERN_OR_USER ) {
248 if ( isspace(buff[0]) ) parse_state = SMP_PATTERN;
250 parse_state = SMP_USER;
251 storecontent(username);
256 if ( parse_state == SMP_USER ) {
257 tok = getuname(&p,username,sizeof(username));
259 /* check: is it include. not implemented */
262 fprintf(stderr ,"%s: %s[%lu]: error while expecting user name\n",progname,fname,lino);
263 parse_state = SMP_INVALID;
266 parse_state = SMP_PATTERN;
267 DOUT1("Found user: %s\n",username);
271 if ( parse_state == SMP_PATTERN || parse_state == SMP_ACTION ) {
273 /* check for empty line */
274 while( *p && isspace(*p) ) p++;
276 if ( *p && ( *p != ';' ) ) tok = userparse(p,&vp);
277 else tok = T_EOL; /* ';' - signs empty line */
280 case T_EOL: /* add to content */
281 addlinetocontent(vp);
283 if ( parse_state == SMP_PATTERN )
284 parse_state = SMP_ACTION;
285 else parse_state = SMP_PATTERN_OR_USER;
287 case T_COMMA: break; /* parse next line */
288 default: /* error: we do not expect anything else */
289 fprintf(stderr ,"%s: %s[%lu]: sintax error\n",progname,fname,lino);
290 librad_perror("Error");
291 parse_state = SMP_INVALID;
296 if ( feof(fp) ) switch (parse_state ) {
297 case SMP_USER: /* file is empty, last line is comment */
299 case SMP_PATTERN: /* only username ?*/
300 fprintf(stderr ,"%s: %s[%lu]: EOF while pattern line are expecting\n",progname,fname,lino);
302 parse_state = SMP_INVALID;
304 case SMP_ACTION: /* looking for reply line */
305 fprintf(stderr ,"%s: %s[%lu]: EOF while reply line are expecting\n",progname,fname,lino);
307 parse_state = SMP_INVALID;
309 case SMP_PATTERN_OR_USER:
310 storecontent(username);
314 } else if ( parse_state != SMP_INVALID ) { /* file read error */
315 fprintf(stderr ,"%s: error file reading from file\n",progname);
319 return (parse_state == SMP_INVALID)?-1:0;
323 static void sm_usage(void) {
324 fprintf(stderr, "Usage: %s [-c] [-d raddb] [-f imputfile] [-o outputfile] [-x] [-v] [-q] [username1 [username2] ...]\n\n",progname);
326 fprintf(stderr, "-c create new database.\n");
327 fprintf(stderr, "-x debug mode.\n");
328 fprintf(stderr, "-q do not print statistic\n");
329 fprintf(stderr, "-v print version\n");
330 fprintf(stderr, "-r remove user(s) from database\n");
334 int main(int n,char **argv) {
336 const char *fname = NULL;
337 const char *ofile = NULL;
341 const char *sm_radius_dir = NULL;
347 while ((ch = getopt(n, argv, "d:i:xo:qvc")) != -1)
350 sm_radius_dir = optarg;
364 printf("%s: $Id$ \n",progname);
367 oflags = O_CREAT | O_TRUNC | O_RDWR;
369 default: sm_usage();exit(1);
375 if ( sm_radius_dir == NULL ) sm_radius_dir = RADDBDIR;
377 DOUT1("Use dictionary in: %s\n",sm_radius_dir);
378 if (dict_init(sm_radius_dir, RADIUS_DICTIONARY) < 0 ) {
379 librad_perror("parser: init dictionary:");
383 if ( fname == NULL || fname[0] == '-') {
386 } else if ( ( fp = fopen(fname, "r") ) == NULL ) {
387 fprintf( stderr,"%s: Couldn't open source file\n", progname);
391 if ( ofile == NULL ) ofile = "sandy_db" ;
392 if ( open_storage(ofile) ) {
396 sm_parse_file(fp,fname);
401 fprintf(stderr,"\nRecord loaded: %lu\nLines parsed: %lu\nRecord skiped: %lu\nWarnings: %lu\nErrors: %lu\n"
402 ,st_loaded,st_lines,st_skiped,st_warns,st_errors);