1    | /***************************************
2    |   $Revision: 1.10 $
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   | 
35   | #include "erroutines.h"
36   | #include "er_yacc_helper.h" 
37   | 
38   | #include "memwrap.h"
39   | #include "sk.h"
40   | 
41   | #include "ca_configFns.h"
42   | #include "ca_dictionary.h"
43   | #include "ca_macros.h"
44   | 
45   | #include "thread.h" /*rwlock*/
46   | 
47   | #include "er_macro.h"
48   | 
49   | #include "ut_string.h"
50   | 
51   | 
52   | /*++++++++++++++++++++++++++++++++++++++
53   |   
54   |   processes a macro call, i.e. executes one of the predefined macros
55   |   selected by the 0th word of the array, using other words as
56   |   arguments to that macro. Uses the er_macro_array[] to find the
57   |   macro definition.  Allocates the result string and stores the
58   |   pointer to it in **output.
59   |   
60   |   int ER_process_split    returns 0 on success, non-0 on failure.
61   | 
62   |   int argc                number of words in the word array
63   |   
64   |   char **argv             word array (pointers to strings)
65   |   
66   |   char **output           storage for the result pointer (to allocated text)
67   |   ++++++++++++++++++++++++++++++++++++++*/
68   | int
69   | ER_process_split(int argc, char **argv, char **output)
70   | {
71   |   unsigned char *ch;
72   |   char *pattern;
73   |   GString *result = g_string_new("");
74   |   int retval = 0;
75   | 
76   |   TH_acquire_write_lock( &er_paths_lock );
77   | 
78   |   if( /* if called without the macro name */
79   |      argc == 0  
80   |      /* or macro can not be found */
81   |      || (pattern = g_hash_table_lookup(er_macro_hash, argv[0])) == NULL ) {
82   | 
83   |     retval = -1;
84   |   }
85   |   else {
86   |     /* copy the macro definition by portions, substituting the $([0-9]) 
87   |        entries with arguments. Error if not enough arguments.
88   |     */
89   |     do {
90   |       
91   |       if( (ch = (unsigned char *) strstr( pattern, "$(" )) == NULL ) {
92   | 	/* no more entries. copy the rest */
93   | 	g_string_append ( result, pattern );
94   | 	break;
95   |       }
96   |       else {
97   | 	/* pass the string between here and ch */
98   | 	while( pattern != (char *)ch ) {
99   | 	  g_string_append_c ( result, *pattern );
100  | 	  pattern++;
101  | 	}
102  | 	/* check the next 3 characters exist, break the look if not */
103  | 	if( *(ch+2) == '\0' ||  *(ch+3) == '\0') {
104  | 	  break;
105  | 	}
106  | 
107  | 	/* look for the digit and ")", pass the $( through if not present */
108  | 	if( ! isdigit(*(ch+2)) || *(ch+3) != ')' ) {
109  | 	  /* not need to do anything to make it pass through */
110  | 	  ;
111  | 	}
112  | 	else {
113  | 	  /* substitute the $(?) with the appropriate argument.
114  | 	     error if not enough arguments or $(0) is used.*/
115  | 	  int a = *(ch+2) - '0';
116  | 	
117  | 	  if( argc < a || a==0) {
118  | 	    retval = -1;
119  | 	    break;
120  | 	  }
121  | 	  g_string_append( result, argv[a]);
122  | 	  /* advance the pattern pointer */
123  | 	  pattern += strlen("$(1)");
124  | 	}
125  |       }
126  |     } while(1);
127  |   }
128  | 
129  |   /* copy the pointer, free the orig structure, keep the text */
130  |     
131  |   *output = (result->str); 
132  |   
133  |   g_string_free( result, FALSE );
134  | 
135  |   TH_release_write_lock( &er_paths_lock );
136  | 
137  |   return retval;
138  | }
139  | 
140  | 
141  | /*++++++++++++++++++++++++++++++++++++++
142  |   
143  |   Take a text line and parse it as an error specification
144  |   line. Optionally, if the first word is a macro, run the macro using
145  |   other words as its arguments.  This is basically a wrapper around
146  |   ER_process_split() that splits the string into argv and calls the
147  |   ER_parse.
148  | 
149  |   sets the errbuf to the result of ER_parse_spec.
150  | 
151  |   int ER_macro_spec      returns 0 on success, non-0 on failure.  
152  | 
153  |   char *input            input line
154  | 
155  |   char **errbuf          storage for the result pointer (to allocated text)
156  |   ++++++++++++++++++++++++++++++++++++++*/
157  | int
158  | ER_macro_spec(char *input, char **errbuf)
159  | {
160  |   char *copy = ut_string_compress(input);
161  |   char **argv = g_strsplit(copy, " ", 0);
162  |   int argc = 0, ret;
163  |   char *fullspec;
164  | 
165  |   while( argv[argc] != NULL ) {
166  |     argc++;
167  |   }
168  |   
169  | 
170  |   if( ER_process_split(argc, argv, &fullspec) != 0 ) {
171  |     /* macro unknown. That's OK, just parse that text now */
172  | 
173  |     fullspec = strdup(input);
174  |   }
175  | 
176  |   ret = ER_parse_spec(fullspec, errbuf);
177  | 
178  |   free(fullspec);
179  |   free(copy);
180  |   g_strfreev(argv);
181  | 
182  |   return ret;
183  |   
184  | }
185  | 
186  | 
187  | /*++++++++++++++++++++++++++++++++++++++
188  |   (Re)Define a macro.
189  |   
190  |   char *name     macro name
191  |   
192  |   char *def      macro contents
193  |   ++++++++++++++++++++++++++++++++++++++*/
194  | void
195  | ER_make_macro(char *name, char *def)
196  | {
197  |   char *cp_name = wr_string(name);
198  |   char *cp_def  = wr_string(def);
199  | 
200  |   void *oldkey, *oldval;
201  | 
202  |   TH_acquire_write_lock( &er_paths_lock );
203  | 
204  |   /* cleanup on redefinition */
205  |   if( g_hash_table_lookup_extended(er_macro_hash, name, 
206  | 				   &oldkey, &oldval) == TRUE ) {
207  |     g_hash_table_remove(er_macro_hash, name);
208  |     wr_free(oldkey);
209  |     wr_free(oldval);
210  |   }
211  |   
212  |   g_hash_table_insert(er_macro_hash, cp_name, cp_def);
213  | 
214  |   TH_release_write_lock( &er_paths_lock );
215  | }
216  | 
217  | 
218  | /*++++++++++++++++++++++++++++++++++++++
219  |   
220  |   predefine some macros useful for the whois_rip server.
221  |   XXX - this should not be here, it should be done via the CA module!
222  | 
223  |   ++++++++++++++++++++++++++++++++++++++*/
224  | void
225  | ER_macro_predef(void)
226  | {
227  | 
228  | #define DBUPDLOG_FORMAT "  FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|MNEMONIC  "
229  | #define RIPLOG_FORMAT   "  FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|THR_ID|MNEMONIC  "
230  | 
231  |   /* catch-all for dbupdate */
232  |   ER_make_macro("DBUPERR", "CREATE dbuperr {"
233  | 		DBUPDLOG_FORMAT "NAME '$(1)' DATE}"
234  | 		" ( FAC MM|UP SEV W- )");
235  | 
236  |   /* catch-all for rip */
237  |   ER_make_macro("ALLRIPERR", "CREATE allriperr { " 
238  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}" 
239  | 		" (FAC ALL SEV W- )");
240  | 
241  |   /* selected: errors in ripupdate */
242  |   ER_make_macro("RIPUPERR", "CREATE ripuperr {" 
243  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}" 
244  | 		" (FAC UD SEV W- )");
245  | 
246  |   /* querylog: logs all rip queries */
247  |   ER_make_macro("QRYLOG", "CREATE qrylog {" 
248  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}" 
249  | 		" (FAC PW ASP PW_I_QRYLOG SEV I )");
250  | 
251  |   /* audit: any security related messages from RIP */
252  |   ER_make_macro("RIPAUDIT", "CREATE ripaudit {"
253  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}"
254  | 		"( FAC PW ASP PW_I_PASSUN SEV i )" 
255  | 		" (  FAC AC ASP AC_I_PERMBAN SEV I )");
256  | 
257  |   /* ripupdlog: logs all update transactions */
258  |   ER_make_macro("RIPUPDLOG", "CREATE 'ripupdlog_$(2)' {" 
259  | 		RIPLOG_FORMAT "NAME '$(1)_$(2)' DATE}" 
260  | 		" ( FAC UD ASP 0xffffffff SEV I THR self)");
261  | 
262  |   /* ripmirlog */
263  |   ER_make_macro("RIPMIRLOG", "CREATE ripmirlog {"  
264  | 		RIPLOG_FORMAT "NAME '$(1)' DATE }"
265  | 		"( FAC PM ASP 0xffffffff SEV I )");
266  | 
267  |   /* server log: all administration by SV (startup, shutdown, etc) and errors */
268  |   ER_make_macro("RIPSVRLOG", "CREATE ripsvrlog {" 
269  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}" 
270  | 		" ( FAC SV ASP 0xffffffff SEV I-F )");											      
271  |   /* dbase log: all errors of SQ */
272  |   ER_make_macro("SQLOG", " CREATE sqlog {" 
273  | 		RIPLOG_FORMAT "NAME '$(1)' DATE}" 
274  | 		" ( FAC SQ SEV W- )");
275  |   
276  | }
277  | 
278  | 
279  | /*++++++++++++++++++++++++++++++++++++++
280  |   
281  |   Prints the arguments (key and value of a hash) to the given
282  |   connection (used for listing the defined macros)
283  | 
284  |   void * key       hash key
285  | 
286  |   void * value     hash value
287  | 
288  |   void *condat     connection data structure
289  |   ++++++++++++++++++++++++++++++++++++++*/
290  | static
291  | void er_macro_list_hook (void* key, void * value, void *condat)
292  | {
293  |   SK_cd_printf(condat, "%s: %s\n", (char *) key, (char *) value);
294  | }
295  |      
296  | 
297  | 
298  | /*++++++++++++++++++++++++++++++++++++++
299  |   
300  |   Lists all currently defined macros to the given connection.
301  | 
302  |   sk_conn_st *condat  connection data structure
303  |   ++++++++++++++++++++++++++++++++++++++*/
304  | void 
305  | ER_macro_list(sk_conn_st *condat)
306  | {
307  |   TH_acquire_read_lock( &er_paths_lock );
308  |   g_hash_table_foreach(er_macro_hash, er_macro_list_hook, condat );
309  |   TH_release_read_lock( &er_paths_lock );
310  | }
311  | 
312  | 
313  | 
314  | /*++++++++++++++++++++++++++++++++++++++
315  | 
316  |  Defines the macros with the definitions from the config file,
317  |  overriding any currently defined ones if the same name is used.
318  |  
319  |  ++++++++++++++++++++++++++++++++++++++*/
320  | void 
321  | ER_proc_ca_macro(void)
322  | {
323  |   char *alldef = ca_get_er_macro ;
324  |   char *this_line = alldef;
325  |   char *defname, *defbody, *end_line;
326  |   
327  |   /* alldef is a copy of the configured value. so we can modify it
328  |      if it helps us to do it line by line */
329  |   
330  |   /* ER_MACRO may not be present in the configuration, in which case 
331  |      ca_get_er_macro returns NULL */
332  | 
333  |   if( alldef != NULL ) {
334  |     
335  |     while( *this_line != '\0' ) {
336  |       /* separate the line */
337  |       end_line = strchr(this_line, '\n');
338  |       *end_line = '\0';
339  |       
340  |       /* advance to non-whitespace */
341  |       while( isspace(* (unsigned char*) this_line) ) {
342  | 	this_line++;
343  |       }
344  |       
345  |       /* find the name and body of the definition */
346  |       defname = strsep(&this_line, " \t");
347  |       defbody = this_line;
348  |       
349  |       /* fire */
350  |       dieif( defname == NULL || defbody == NULL );
351  |       ER_make_macro( defname, defbody );
352  |       
353  |       this_line = end_line + 1;
354  |     }
355  |     
356  |     free(alldef);
357  |   } 
358  |   
359  | }
360  | 
361  | 
362  | /*++++++++++++++++++++++++++++++++++++++
363  |   
364  |   Processes the error definitions from the config file. The
365  |   definitions can be specified with the use of a macro or without.
366  |   
367  |   ++++++++++++++++++++++++++++++++++++++*/
368  | void 
369  | ER_proc_ca_err(void)
370  | {
371  |   char *alldef = ca_get_er_def ;
372  |   char *this_line = alldef;
373  |   char *end_line;
374  |   char *erret = NULL;
375  |   int res;
376  |  
377  |     /* alldef is a copy of the configured value. so we can modify it
378  |        if it helps us to do it line by line */
379  | 
380  |   /* ER_DEF may not be present in the configuration, in which case 
381  |      ca_get_er_def returns NULL */
382  |   if( alldef != NULL ) {
383  |     
384  |     while( *this_line != '\0' ) {
385  |       /* separate the line */
386  |       end_line = strchr(this_line, '\n');
387  |       *end_line = '\0';
388  |       
389  |       /* fire */      
390  |       if( (res = ER_macro_spec(this_line, &erret)) != 0 ) {
391  | 	fputs(erret, stderr);
392  | 	die;
393  |       }
394  |       
395  |       free(erret); 
396  |       
397  |       this_line = end_line + 1;
398  |     }
399  |     
400  |     free(alldef);
401  |   }
402  | }