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