1    | /***************************************
2    |   $Revision: 1.5 $
3    | 
4    |   Error reporting (er) er_macro.c - simple macro processor
5    | 
6    |   Status: NOT REVUED, PARTLY TESTED
7    | 
8    |   Design and implementation by: Marek Bukowy
9    | 
10   |   ******************/ /******************
11   |   Copyright (c) 1999,2000                             RIPE NCC
12   |  
13   |   All Rights Reserved
14   |   
15   |   Permission to use, copy, modify, and distribute this software and its
16   |   documentation for any purpose and without fee is hereby granted,
17   |   provided that the above copyright notice appear in all copies and that
18   |   both that copyright notice and this permission notice appear in
19   |   supporting documentation, and that the name of the author not be
20   |   used in advertising or publicity pertaining to distribution of the
21   |   software without specific, written prior permission.
22   |   
23   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29   |   ***************************************/
30   | 
31   | #include <string.h>
32   | #include <glib.h>
33   | #include "stubs.h"
34   | #include "sk.h"
35   | #include "er_macro.h"
36   | #include "er_paths.h"
37   | #include "er_yacc_helper.h" 
38   | #include "memwrap.h"
39   | 
40   | #include "ca_configFns.h"
41   | #include "ca_dictSyms.h"
42   | #include "ca_macros.h"
43   | 
44   | GHashTable *er_macro_hash = NULL;
45   | 
46   | /* process a macro call, i.e. execute one of the predefined macros 
47   |    selected by the 0th argument, using other arguments.
48   |    
49   |    Uses the er_macro_array[] to find the macro definition.
50   |    
51   |    Allocates the result string and stores the pointer to it in **output.
52   | 
53   |    returns 0 on success, non-0 on failure.
54   | */
55   | 
56   | int
57   | ER_process_split(int argc, char **argv, char **output)
58   | {
59   |   char *pattern, *ch;
60   |   GString *result = g_string_new("");
61   | 
62   |   dieif( argc == 0 ); /* may not be called without the macro name */
63   | 
64   |   /* find macro, error if not found */
65   |   if( (pattern = g_hash_table_lookup(er_macro_hash, argv[0])) == NULL ) {
66   |     return -1;
67   |   }
68   | 
69   |   /* copy the macro definition by portions, substituting the $([0-9]) 
70   |      entries with arguments. Error if not enough arguments.
71   |   */
72   |   do {
73   | 
74   |     if( (ch = strstr( pattern, "$(" )) == NULL ) {
75   |       /* no more entries. copy the rest */
76   |       g_string_append ( result, pattern );
77   |       break;
78   |     }
79   |     else {
80   |       /* pass the string between here and ch */
81   |       while( pattern != ch ) {
82   | 	g_string_append_c ( result, *pattern );
83   | 	pattern++;
84   |       }
85   |       /* check the next 3 characters exist, break the look if not */
86   |       if( *(ch+2) == '\0' ||  *(ch+3) == '\0') {
87   | 	break;
88   |       }
89   | 
90   |       /* look for the digit and ")", pass the $( through if not present */
91   |       if( ! isdigit(*(ch+2)) || *(ch+3) != ')' ) {
92   | 	/* not need to do anything to make it pass through */
93   | 	;
94   |       }
95   |       else {
96   | 	/* substitute the $(?) with the appropriate argument.
97   | 	   error if not enough arguments or $(0) is used.*/
98   | 	int a = *(ch+2) - '0';
99   | 	
100  | 	if( argc < a || a==0) {
101  | 	  return -1;
102  | 	}
103  | 	g_string_append( result, argv[a]);
104  | 	/* advance the pattern pointer */
105  | 	pattern += strlen("$(1)");
106  |       }
107  |     }
108  |   } while(1);
109  | 
110  |   /* copy the pointer, free the orig structure, keep the text */
111  | 
112  |   *output = (result->str); 
113  |   
114  |   g_string_free( result, FALSE );
115  | 
116  |   return 0;
117  | }
118  | 
119  | 
120  | /* wrapper around the above that splits the string into argv 
121  |    and calls the ER_parse. 
122  | 
123  |    sets the errbuf to the ER_parse_spec result
124  | 
125  |    returns 0 on success, non-0 on failure.
126  | */
127  | int
128  | ER_macro_spec(char *input, char **errbuf)
129  | {
130  |   char **argv = g_strsplit(input, " ", 0);
131  |   int argc = 0, ret;
132  |   char *fullspec;
133  | 
134  |   while( argv[argc] != NULL ) {
135  |     argc++;
136  |   }
137  |   
138  | 
139  |   if( ER_process_split(argc, argv, &fullspec) != 0 ) {
140  |     /* macro unknown. That's OK, just parse that text now */
141  | 
142  |     fullspec = strdup(input);
143  |   }
144  | 
145  |   ret = ER_parse_spec(fullspec, errbuf);
146  | 
147  |   free(fullspec);
148  |   g_strfreev(argv);
149  |   return ret;
150  |   
151  | }
152  | 
153  | 
154  | void
155  | ER_make_macro(char *name, char *def)
156  | {
157  |   char *cp_name = wr_string(name);
158  |   char *cp_def  = wr_string(def);
159  | 
160  |   void *oldkey, *oldval;
161  |   
162  |   /* cleanup on redefinition */
163  |   if( g_hash_table_lookup_extended(er_macro_hash, name, 
164  | 				   &oldkey, &oldval) == TRUE ) {
165  |     g_hash_table_remove(er_macro_hash, name);
166  |     wr_free(oldkey);
167  |     wr_free(oldval);
168  |   }
169  |   
170  |   g_hash_table_insert(er_macro_hash, cp_name, cp_def);
171  | }
172  | 
173  | 
174  | /* predefine some macros */
175  | void
176  | ER_macro_predef(void)
177  | {
178  |   /* create the hash with hashing and equality testing functions
179  |      specific for strings 
180  |   */
181  |   er_macro_hash = g_hash_table_new(g_str_hash, g_str_equal);
182  |   
183  | #define DBUPDLOG_FORMAT "  FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|MNEMONIC  "
184  | #define RIPLOG_FORMAT   "  FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|THR_ID|MNEMONIC  "
185  | 
186  |   /* catch-all for dbupdate */
187  |   ER_make_macro("DBUPERR", "CREATE dbuperr {"
188  | 		DBUPDLOG_FORMAT "NAME $(1) DATE}"
189  | 		" ( FAC MM|UP SEV W- )");
190  | 
191  |   /* catch-all for rip */
192  |   ER_make_macro("ALLRIPERR", "CREATE allriperr { " 
193  | 		RIPLOG_FORMAT "NAME $(1) DATE}" 
194  | 		" (FAC ALL SEV W- )");
195  | 
196  |   /* selected: errors in ripupdate */
197  |   ER_make_macro("RIPUPERR", "CREATE ripuperr {" 
198  | 		RIPLOG_FORMAT "NAME $(1) DATE}" 
199  | 		" (FAC UD SEV W- )");
200  | 
201  |   /* querylog: logs all rip queries */
202  |   ER_make_macro("QRYLOG", "CREATE qrylog {" 
203  | 		RIPLOG_FORMAT "NAME $(1) DATE}" 
204  | 		" (FAC PW ASP PW_I_QRYLOG SEV I )");
205  | 
206  |   /* audit: any security related messages from RIP */
207  |   ER_make_macro("RIPAUDIT", "CREATE ripaudit {"
208  | 		RIPLOG_FORMAT "NAME $(1) DATE}"
209  | 		"( FAC PW ASP PW_I_PASSUN SEV i )" 
210  | 		" (  FAC AC ASP AC_I_PERMBAN SEV I )");
211  | 
212  |   /* ripupdlog: logs all update transactions */
213  |   ER_make_macro("RIPUPDLOG", "CREATE ripupdlog_$(2) {" 
214  | 		RIPLOG_FORMAT "NAME $(1)_$(2) DATE}" 
215  | 		" ( FAC UD ASP 0xffffffff SEV I THR self)");
216  | 
217  |   /* ripmirlog */
218  |   ER_make_macro("RIPMIRLOG", "CREATE ripmirlog {"  
219  | 		RIPLOG_FORMAT "NAME $(1) DATE }"
220  | 		"( FAC PM ASP 0xffffffff SEV I )");
221  | 
222  |   /* server log: all administration by SV (startup, shutdown, etc) and errors */
223  |   ER_make_macro("RIPSVRLOG", "CREATE ripsvrlog {" 
224  | 		RIPLOG_FORMAT "NAME $(1) DATE}" 
225  | 		" ( FAC SV ASP 0xffffffff SEV I-F )");											      
226  |   /* dbase log: all errors of SQ */
227  |   ER_make_macro("SQLOG", " CREATE sqlog {" 
228  | 		RIPLOG_FORMAT "NAME $(1) DATE}" 
229  | 		" ( FAC SQ SEV W- )");
230  |   
231  | }
232  | 
233  | static
234  | void er_macro_list_hook (void* key, void * value, void *condat)
235  | {
236  |   SK_cd_printf(condat, "%s: %s\n", (char *) key, (char *) value);
237  | }
238  |      
239  | void 
240  | ER_macro_list(sk_conn_st *condat)
241  | {
242  |   g_hash_table_foreach(er_macro_hash, er_macro_list_hook, condat );
243  | }
244  | 
245  | /* override macros with the definitions from the config file */
246  | void 
247  | ER_proc_ca_macro(void)
248  | {
249  |   char *alldef = ca_get_er_macro ;
250  |   char *this_line = alldef;
251  |   char *defname, *defbody, *end_line;
252  |   
253  |   /* alldef is a copy of the configured value. so we can modify it
254  |      if it helps us to do it line by line */
255  |   
256  |   /* ER_MACRO may not be present in the configuration, in which case 
257  |      ca_get_er_macro returns NULL */
258  |   
259  |   if( alldef != NULL ) {
260  |     
261  |     while( *this_line != '\0' ) {
262  |       /* separate the line */
263  |       end_line = strchr(this_line, '\n');
264  |       *end_line = '\0';
265  |       
266  |       /* advance to non-whitespace */
267  |       while( isspace(*this_line) ) {
268  | 	this_line++;
269  |       }
270  |       
271  |       /* find the name and body of the definition */
272  |       defname = strsep(&this_line, " \t");
273  |       defbody = this_line;
274  |       
275  |       /* fire */
276  |       dieif( defname == NULL || defbody == NULL );
277  |       ER_make_macro( defname, defbody );
278  |       
279  |       this_line = end_line + 1;
280  |     }
281  |     
282  |     free(alldef);
283  |   }
284  | }
285  | 
286  | 
287  | /* process the error definitions from the config file */
288  | void 
289  | ER_proc_ca_err(void)
290  | {
291  |   char *alldef = ca_get_er_def ;
292  |   char *this_line = alldef;
293  |   char *defname, *defbody, *end_line;
294  |   char *erret = NULL;
295  |   int res;
296  |  
297  |     /* alldef is a copy of the configured value. so we can modify it
298  |        if it helps us to do it line by line */
299  | 
300  |   /* ER_DEF may not be present in the configuration, in which case 
301  |      ca_get_er_def returns NULL */
302  |   if( alldef != NULL ) {
303  |     
304  |     while( *this_line != '\0' ) {
305  |       /* separate the line */
306  |       end_line = strchr(this_line, '\n');
307  |       *end_line = '\0';
308  |       
309  |       /* fire */      
310  |       if( (res = ER_macro_spec(this_line, &erret)) != 0 ) {
311  | 	fputs(erret, stderr);
312  | 	die;
313  |       }
314  |       
315  |       free(erret); 
316  |       
317  |       this_line = end_line + 1;
318  |     }
319  |     
320  |     free(alldef);
321  |   }
322  | }