document rlm_otp fd leak fix
[freeradius.git] / src / modules / rlm_dbm / rlm_dbm_parser.c
1 /*
2  * rlm_dbm_parser.c :    Create dbm file from plain text
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 2001 Koulik Andrei, Sandy Service
21  */
22
23
24 char sccsid[] =
25 "$Id$ sandy module project\n Copyright 2001 Sandy Service\nCopyright 2001 Koulik Andrei";
26
27 #include <freeradius-devel/autoconf.h>
28 #include <fcntl.h>
29
30 #include <stdlib.h>
31
32 #ifdef HAVE_NDBM_H
33 #include <ndbm.h>
34 #endif
35
36 #ifdef HAVE_GDBM_NDBM_H
37 #include <gdbm/ndbm.h>
38 #endif
39
40 #ifdef HAVE_GDBMNDBM_H
41 #include <gdbm-ndbm.h>
42 #endif
43
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <string.h>
47
48 #include <freeradius-devel/radiusd.h>
49
50 #include <freeradius-devel/conf.h>
51 #include <freeradius-devel/radpaths.h>
52 #include <freeradius-devel/missing.h>
53
54 #define MAX_BUFF_SIZE   1024
55
56 #define DOUT1   if( librad_debug > 0 ) printf
57 #define DOUT2   if( librad_debug > 5 ) printf
58
59 typedef enum sm_parse_state_t {
60         SMP_INVALID = 0,
61         SMP_USER,
62         SMP_PATTERN,
63         SMP_ACTION,
64         SMP_PATTERN_OR_USER
65 } sm_parse_state_t;
66
67
68
69
70 const char * progname;
71
72 unsigned long   st_errors = 0,
73                 st_warns  = 0,
74                 st_lines  = 0,
75                 st_users  = 0,
76                 st_skiped = 0,
77                 st_loaded = 0;
78
79
80 /*  test
81
82 int dumplist(VALUE_PAIR *vp) {
83
84         while (vp != NULL) {
85
86                 printf("VP: name: %s\nattribute: %d\ntype: %d\nlvalue: %lu"
87                         "\noperator %d\naddport: %d\nValue: %s\n",
88                         vp -> name, vp -> attribute, vp -> type, vp -> lvalue,
89                         vp -> operator, vp -> addport, (char*)vp -> strvalue);
90                 vp = vp -> next;
91         }
92         return 0;
93 }
94
95 */
96
97
98 char content[4096];
99 int  concntr = 0;
100 int  oflags = O_RDWR | O_CREAT;
101 DBM * pdb = NULL;
102
103
104 static int open_storage(const char * fname) {
105
106   if ( (pdb = dbm_open(fname, oflags, 0600 )) == NULL ) {
107         perror("Couldn't open database");
108         return 1;
109   }
110   return 0;
111 }
112
113 static void  close_storage(void){
114   dbm_close(pdb);
115 }
116
117 static int  addlinetocontent(VALUE_PAIR *vp) {
118
119         int outlen = sizeof(content) - concntr - 1;
120         int lendiv;
121
122         if ( outlen < 4 ) return -1;
123         if ( vp == NULL ) { /* add empty line */
124                 content[concntr++] = '\n';
125                 content[concntr] = '\0';
126         } else {
127                 while ( vp != NULL ){
128                         lendiv = vp_prints(&content[concntr],outlen,vp);
129                         if ( lendiv > 0 ) {
130                                 outlen -= lendiv;
131
132                                 if (outlen > 3)  {
133                                         strcat(content,", ");
134                                         concntr += lendiv + 2;
135                                         outlen -= 2;
136                                 } else {
137                                         concntr = 0;
138                                         return -1;
139                                 }
140                         }
141                         vp = vp -> next;
142                 }
143
144                 if ( concntr > 2 ) {  /* remove trailing ',' */
145                         content[--concntr] = '\0';
146                         content[concntr - 1] = '\n';
147                 }
148         }
149
150         return 0;
151 }
152
153 static int storecontent (const char * username) {
154
155          datum d,k;
156          int res;
157
158         if ( pdb == NULL || concntr < 2 ) return 1;
159
160         DOUT2("store:\n%s\ncontent:\n%s",username,content);
161
162         d.dptr = content;
163         d.dsize = concntr + 1;
164
165         k.dptr = username;
166         k.dsize = strlen(username) + 1;
167
168         res = dbm_store(pdb, k, d, DBM_INSERT);
169         if ( res == 1 ) dbm_store(pdb, k, d, DBM_REPLACE);
170         if ( res < 0 ) {
171           perror("Couldn't insert record");
172           st_errors++;
173           st_skiped++;
174         }  else st_loaded++;
175
176         concntr = 0;
177         *content = '\0';
178         return 0;
179 }
180
181 static int getuname(char **p,char *u,int n) {
182         int     i;
183
184         for(i=0 ; ( i < n-1 ) && ( **p ) && (! isspace((int) **p) ) ; (*p)++ )
185             u[i++] = **p;
186         u[i] = '\0';
187         return ( i == 0) ? 1:0;
188 }
189
190 static int sm_parse_file(FILE*fp,const char* fname) {
191         LRAD_TOKEN tok;
192         VALUE_PAIR *vp = NULL;
193         sm_parse_state_t  parse_state = SMP_USER;
194         unsigned long lino  = 0;
195         char *p;
196         char buff[MAX_BUFF_SIZE];
197         char username[256];
198
199
200         while( parse_state != SMP_INVALID && fgets(buff, sizeof(buff), fp) != NULL ) {
201
202                 lino ++;
203                 st_lines++;
204                 if ( strchr(buff, '\n') == NULL) {
205                         fprintf(stderr,"%s: %s[%lu]:Warning: line too long or not closed by \\n character. Skiped\n",progname,fname,lino);
206                         st_warns++;
207                         st_skiped++; /* _LINE_ skiped */
208                         continue;
209                 }
210
211                 DOUT2("Parseline: %s",buff);
212                 for ( p = buff; isspace((int) *p); p++);
213
214                 if ( *p == '#' || *p == 0 ) continue;
215
216                 /* userparse hack */
217                 if (  *p == ';' ) *p = '\n';
218                 p = buff;
219
220                 /* try to decide is this line new user or new pattern */
221                 if ( parse_state == SMP_PATTERN_OR_USER ) {
222                      if ( isspace((int) buff[0]) ) parse_state = SMP_PATTERN;
223                         else {
224                                 parse_state = SMP_USER;
225                                 storecontent(username);
226                                 st_users++;
227                         }
228                  }
229
230                 if ( parse_state == SMP_USER ) {
231                     tok = getuname(&p,username,sizeof(username));
232
233                     /* check: is it include. not implemented */
234
235                     if ( tok ) {
236                         fprintf(stderr ,"%s: %s[%lu]: error while expecting user name\n",progname,fname,lino);
237                         parse_state = SMP_INVALID;
238                         st_errors++;
239                     } else {
240                         parse_state = SMP_PATTERN;
241                         DOUT1("Found user: %s\n",username);
242
243                     }
244                 }
245                 if ( parse_state == SMP_PATTERN || parse_state == SMP_ACTION ) {
246
247                     /* check for empty line */
248                     while( *p && isspace((int) *p) ) p++;
249
250                     if ( *p && ( *p != ';' ) ) tok = userparse(p,&vp);
251                     else tok = T_EOL;  /* ';' - signs empty line */
252
253                     switch(tok) {
254                         case T_EOL: /* add to content */
255                                         addlinetocontent(vp);
256                                         pairfree(&vp);
257                                         if ( parse_state == SMP_PATTERN )
258                                                 parse_state = SMP_ACTION;
259                                         else parse_state = SMP_PATTERN_OR_USER;
260
261                         case T_COMMA: break;  /* parse next line */
262                         default: /* error: we do  not expect anything else */
263                                         fprintf(stderr ,"%s: %s[%lu]: sintax error\n",progname,fname,lino);
264                                         librad_perror("Error");
265                                         parse_state = SMP_INVALID;
266                                         st_errors++;
267                     }
268                 }
269         }
270         if ( feof(fp) ) switch (parse_state ) {
271                 case  SMP_USER: /* file is empty, last line is comment  */
272                                                 break;
273                 case  SMP_PATTERN: /* only username ?*/
274                                 fprintf(stderr ,"%s: %s[%lu]: EOF while pattern line are expecting\n",progname,fname,lino);
275                                 st_errors++;
276                                 parse_state = SMP_INVALID;
277                                 break;
278                 case  SMP_ACTION: /* looking for reply line */
279                                 fprintf(stderr ,"%s: %s[%lu]: EOF while reply line are expecting\n",progname,fname,lino);
280                                 st_errors++;
281                                 parse_state = SMP_INVALID;
282                                 break;
283                 case  SMP_PATTERN_OR_USER:
284                                 storecontent(username);
285                                 st_users++;
286                                 break;
287                 default:break;
288         } else if ( parse_state != SMP_INVALID ) {  /* file read error */
289                 fprintf(stderr ,"%s: error file reading from file\n",progname);
290         }
291         pairfree(&vp);
292
293         return (parse_state == SMP_INVALID)?-1:0;
294 }
295
296
297 static void sm_usage(void) {
298         fprintf(stderr, "Usage: %s [-c] [-d raddb] [-i inputfile] [-o outputfile] [-x] [-v] [-q] [username1 [username2] ...]\n\n",progname);
299
300         fprintf(stderr, "-c     create new database.\n");
301         fprintf(stderr, "-x     debug mode.\n");
302         fprintf(stderr, "-q     do not print statistic\n");
303         fprintf(stderr, "-v     print version\n");
304         fprintf(stderr, "-r     remove user(s) from database\n");
305
306 }
307
308 int main(int n,char **argv) {
309
310         const char *fname = NULL;
311         const char *ofile = NULL;
312         FILE    *fp;
313         int     print_stat = 1;
314         int     ch;
315         const char  *sm_radius_dir = NULL;
316
317         progname = argv[0];
318
319         librad_debug = 0;
320
321         while ((ch = getopt(n, argv, "d:i:xo:qvc")) != -1)
322                 switch (ch) {
323                         case 'd':
324                                 sm_radius_dir = optarg;
325                                 break;
326                         case 'i':
327                                 fname = optarg;
328                                 break;
329                         case 'x':
330                                 librad_debug++;
331                         case 'o':
332                                 ofile = optarg;
333                                 break;
334                         case 'q':
335                                 print_stat = 0;
336                                 break;
337                         case 'v':
338                                 printf("%s: $Id$ \n",progname);
339                                 exit(0);
340                         case 'c':
341                                 oflags = O_CREAT | O_TRUNC | O_RDWR;
342                                 break;
343                         default: sm_usage();exit(1);
344                 }
345
346
347
348
349         if ( sm_radius_dir == NULL ) sm_radius_dir = RADDBDIR;
350
351         DOUT1("Use dictionary in: %s\n",sm_radius_dir);
352         if (dict_init(sm_radius_dir, RADIUS_DICTIONARY) < 0 ) {
353                 librad_perror("parser: init dictionary:");
354                 exit(1);
355         }
356
357         if ( fname == NULL || fname[0] == '-') {
358                 fp = stdin;
359                 fname = "STDIN";
360         } else if ( ( fp = fopen(fname, "r") ) == NULL ) {
361                 fprintf( stderr,"%s: Couldn't open source file\n", progname);
362                 exit(1);
363         }
364
365         if ( ofile == NULL ) ofile = "sandy_db" ;
366         if ( open_storage(ofile) ) {
367                 exit (1);
368         }
369
370         sm_parse_file(fp,fname);
371
372         close_storage();
373
374         if ( print_stat )
375           fprintf(stderr,"\nRecord loaded: %lu\nLines parsed: %lu\nRecord skiped: %lu\nWarnings: %lu\nErrors: %lu\n"
376                 ,st_loaded,st_lines,st_skiped,st_warns,st_errors);
377
378         return 0;
379 }