Source File modules/er/er_macro.c

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