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