1 | /*************************************** 2 | $Revision: 1.5 $ 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 | #include "sk.h" 35 | #include "er_macro.h" 36 | #include "er_paths.h" 37 | #include "er_yacc_helper.h" 38 | #include "memwrap.h" 39 | 40 | #include "ca_configFns.h" 41 | #include "ca_dictSyms.h" 42 | #include "ca_macros.h" 43 | 44 | GHashTable *er_macro_hash = NULL; 45 | 46 | /* process a macro call, i.e. execute one of the predefined macros 47 | selected by the 0th argument, using other arguments. 48 | 49 | Uses the er_macro_array[] to find the macro definition. 50 | 51 | Allocates the result string and stores the pointer to it in **output. 52 | 53 | returns 0 on success, non-0 on failure. 54 | */ 55 | 56 | int 57 | ER_process_split(int argc, char **argv, char **output) 58 | { 59 | char *pattern, *ch; 60 | GString *result = g_string_new(""); 61 | 62 | dieif( argc == 0 ); /* may not be called without the macro name */ 63 | 64 | /* find macro, error if not found */ 65 | if( (pattern = g_hash_table_lookup(er_macro_hash, argv[0])) == NULL ) { 66 | return -1; 67 | } 68 | 69 | /* copy the macro definition by portions, substituting the $([0-9]) 70 | entries with arguments. Error if not enough arguments. 71 | */ 72 | do { 73 | 74 | if( (ch = strstr( pattern, "$(" )) == NULL ) { 75 | /* no more entries. copy the rest */ 76 | g_string_append ( result, pattern ); 77 | break; 78 | } 79 | else { 80 | /* pass the string between here and ch */ 81 | while( pattern != ch ) { 82 | g_string_append_c ( result, *pattern ); 83 | pattern++; 84 | } 85 | /* check the next 3 characters exist, break the look if not */ 86 | if( *(ch+2) == '\0' || *(ch+3) == '\0') { 87 | break; 88 | } 89 | 90 | /* look for the digit and ")", pass the $( through if not present */ 91 | if( ! isdigit(*(ch+2)) || *(ch+3) != ')' ) { 92 | /* not need to do anything to make it pass through */ 93 | ; 94 | } 95 | else { 96 | /* substitute the $(?) with the appropriate argument. 97 | error if not enough arguments or $(0) is used.*/ 98 | int a = *(ch+2) - '0'; 99 | 100 | if( argc < a || a==0) { 101 | return -1; 102 | } 103 | g_string_append( result, argv[a]); 104 | /* advance the pattern pointer */ 105 | pattern += strlen("$(1)"); 106 | } 107 | } 108 | } while(1); 109 | 110 | /* copy the pointer, free the orig structure, keep the text */ 111 | 112 | *output = (result->str); 113 | 114 | g_string_free( result, FALSE ); 115 | 116 | return 0; 117 | } 118 | 119 | 120 | /* wrapper around the above that splits the string into argv 121 | and calls the ER_parse. 122 | 123 | sets the errbuf to the ER_parse_spec result 124 | 125 | returns 0 on success, non-0 on failure. 126 | */ 127 | int 128 | ER_macro_spec(char *input, char **errbuf) 129 | { 130 | char **argv = g_strsplit(input, " ", 0); 131 | int argc = 0, ret; 132 | char *fullspec; 133 | 134 | while( argv[argc] != NULL ) { 135 | argc++; 136 | } 137 | 138 | 139 | if( ER_process_split(argc, argv, &fullspec) != 0 ) { 140 | /* macro unknown. That's OK, just parse that text now */ 141 | 142 | fullspec = strdup(input); 143 | } 144 | 145 | ret = ER_parse_spec(fullspec, errbuf); 146 | 147 | free(fullspec); 148 | g_strfreev(argv); 149 | return ret; 150 | 151 | } 152 | 153 | 154 | void 155 | ER_make_macro(char *name, char *def) 156 | { 157 | char *cp_name = wr_string(name); 158 | char *cp_def = wr_string(def); 159 | 160 | void *oldkey, *oldval; 161 | 162 | /* cleanup on redefinition */ 163 | if( g_hash_table_lookup_extended(er_macro_hash, name, 164 | &oldkey, &oldval) == TRUE ) { 165 | g_hash_table_remove(er_macro_hash, name); 166 | wr_free(oldkey); 167 | wr_free(oldval); 168 | } 169 | 170 | g_hash_table_insert(er_macro_hash, cp_name, cp_def); 171 | } 172 | 173 | 174 | /* predefine some macros */ 175 | void 176 | ER_macro_predef(void) 177 | { 178 | /* create the hash with hashing and equality testing functions 179 | specific for strings 180 | */ 181 | er_macro_hash = g_hash_table_new(g_str_hash, g_str_equal); 182 | 183 | #define DBUPDLOG_FORMAT " FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|MNEMONIC " 184 | #define RIPLOG_FORMAT " FORMAT SEVCHAR|FACSYMB|TEXTLONG|DATETIME|PIDFULL|PROGNAME|THR_ID|MNEMONIC " 185 | 186 | /* catch-all for dbupdate */ 187 | ER_make_macro("DBUPERR", "CREATE dbuperr {" 188 | DBUPDLOG_FORMAT "NAME $(1) DATE}" 189 | " ( FAC MM|UP SEV W- )"); 190 | 191 | /* catch-all for rip */ 192 | ER_make_macro("ALLRIPERR", "CREATE allriperr { " 193 | RIPLOG_FORMAT "NAME $(1) DATE}" 194 | " (FAC ALL SEV W- )"); 195 | 196 | /* selected: errors in ripupdate */ 197 | ER_make_macro("RIPUPERR", "CREATE ripuperr {" 198 | RIPLOG_FORMAT "NAME $(1) DATE}" 199 | " (FAC UD SEV W- )"); 200 | 201 | /* querylog: logs all rip queries */ 202 | ER_make_macro("QRYLOG", "CREATE qrylog {" 203 | RIPLOG_FORMAT "NAME $(1) DATE}" 204 | " (FAC PW ASP PW_I_QRYLOG SEV I )"); 205 | 206 | /* audit: any security related messages from RIP */ 207 | ER_make_macro("RIPAUDIT", "CREATE ripaudit {" 208 | RIPLOG_FORMAT "NAME $(1) DATE}" 209 | "( FAC PW ASP PW_I_PASSUN SEV i )" 210 | " ( FAC AC ASP AC_I_PERMBAN SEV I )"); 211 | 212 | /* ripupdlog: logs all update transactions */ 213 | ER_make_macro("RIPUPDLOG", "CREATE ripupdlog_$(2) {" 214 | RIPLOG_FORMAT "NAME $(1)_$(2) DATE}" 215 | " ( FAC UD ASP 0xffffffff SEV I THR self)"); 216 | 217 | /* ripmirlog */ 218 | ER_make_macro("RIPMIRLOG", "CREATE ripmirlog {" 219 | RIPLOG_FORMAT "NAME $(1) DATE }" 220 | "( FAC PM ASP 0xffffffff SEV I )"); 221 | 222 | /* server log: all administration by SV (startup, shutdown, etc) and errors */ 223 | ER_make_macro("RIPSVRLOG", "CREATE ripsvrlog {" 224 | RIPLOG_FORMAT "NAME $(1) DATE}" 225 | " ( FAC SV ASP 0xffffffff SEV I-F )"); 226 | /* dbase log: all errors of SQ */ 227 | ER_make_macro("SQLOG", " CREATE sqlog {" 228 | RIPLOG_FORMAT "NAME $(1) DATE}" 229 | " ( FAC SQ SEV W- )"); 230 | 231 | } 232 | 233 | static 234 | void er_macro_list_hook (void* key, void * value, void *condat) 235 | { 236 | SK_cd_printf(condat, "%s: %s\n", (char *) key, (char *) value); 237 | } 238 | 239 | void 240 | ER_macro_list(sk_conn_st *condat) 241 | { 242 | g_hash_table_foreach(er_macro_hash, er_macro_list_hook, condat ); 243 | } 244 | 245 | /* override macros with the definitions from the config file */ 246 | void 247 | ER_proc_ca_macro(void) 248 | { 249 | char *alldef = ca_get_er_macro ; 250 | char *this_line = alldef; 251 | char *defname, *defbody, *end_line; 252 | 253 | /* alldef is a copy of the configured value. so we can modify it 254 | if it helps us to do it line by line */ 255 | 256 | /* ER_MACRO may not be present in the configuration, in which case 257 | ca_get_er_macro returns NULL */ 258 | 259 | if( alldef != NULL ) { 260 | 261 | while( *this_line != '\0' ) { 262 | /* separate the line */ 263 | end_line = strchr(this_line, '\n'); 264 | *end_line = '\0'; 265 | 266 | /* advance to non-whitespace */ 267 | while( isspace(*this_line) ) { 268 | this_line++; 269 | } 270 | 271 | /* find the name and body of the definition */ 272 | defname = strsep(&this_line, " \t"); 273 | defbody = this_line; 274 | 275 | /* fire */ 276 | dieif( defname == NULL || defbody == NULL ); 277 | ER_make_macro( defname, defbody ); 278 | 279 | this_line = end_line + 1; 280 | } 281 | 282 | free(alldef); 283 | } 284 | } 285 | 286 | 287 | /* process the error definitions from the config file */ 288 | void 289 | ER_proc_ca_err(void) 290 | { 291 | char *alldef = ca_get_er_def ; 292 | char *this_line = alldef; 293 | char *defname, *defbody, *end_line; 294 | char *erret = NULL; 295 | int res; 296 | 297 | /* alldef is a copy of the configured value. so we can modify it 298 | if it helps us to do it line by line */ 299 | 300 | /* ER_DEF may not be present in the configuration, in which case 301 | ca_get_er_def returns NULL */ 302 | if( alldef != NULL ) { 303 | 304 | while( *this_line != '\0' ) { 305 | /* separate the line */ 306 | end_line = strchr(this_line, '\n'); 307 | *end_line = '\0'; 308 | 309 | /* fire */ 310 | if( (res = ER_macro_spec(this_line, &erret)) != 0 ) { 311 | fputs(erret, stderr); 312 | die; 313 | } 314 | 315 | free(erret); 316 | 317 | this_line = end_line + 1; 318 | } 319 | 320 | free(alldef); 321 | } 322 | }