1 | /***************************************
2 | $Revision: 1.9 $
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 | }