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 | }