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