Source File ud/ud_core.c

    1    | /***************************************
    2    |
    3    |   $Revision: 1.52 $
    4    |
    5    |   Core functions for update lower layer
    6    |
    7    |   Status: NOT REVUED, NOT TESTED
    8    |
    9    |  Author(s):       Chris Ottrey, Andrei Robachevsky
    10   |
    11   |   ******************/ /******************
    12   |   Modification History:
    13   |         andrei (17/01/2000) Created.
    14   |   ******************/ /******************
    15   |   Copyright (c) 2000,2001,2002                    RIPE NCC
    16   |
    17   |   All Rights Reserved
    18   |
    19   |   Permission to use, copy, modify, and distribute this software and its
    20   |   documentation for any purpose and without fee is hereby granted,
    21   |   provided that the above copyright notice appear in all copies and that
    22   |   both that copyright notice and this permission notice appear in
    23   |   supporting documentation, and that the name of the author not be
    24   |   used in advertising or publicity pertaining to distribution of the
    25   |   software without specific, written prior permission.
    26   |
    27   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    28   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    29   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    30   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    31   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    32   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    33   |  ***************************************/
    34   |
    35   | #include "rip.h"
    36   |
    37   | #include <sys/types.h>
    38   | #include <signal.h>
    39   | #include <time.h>
    40   |
    41   |
    42   | /* return codes from create_attr() function */
    43   | #define ATTR_CREATE_OK       0
    44   | #define ATTR_CREATE_DONE     1
    45   | #define ATTR_CREATE_ERR      2
    46   | #define ATTR_CREATE_NO       3
    47   |
    48   | static int perform_update(Transaction_t *tr);
    49   |
    50   | static int perform_create(Transaction_t *tr);
    51   |
    52   | static void each_attribute_process(void *element_data, void *tr_ptr);
    53   |
    54   | static void update_attr(const rpsl_attr_t *attr, Transaction_t *tr);
    55   |
    56   | static int create_dummy(const rpsl_attr_t *attr, Transaction_t *tr);
    57   |
    58   | static int auth_member_of(const rpsl_attr_t *attr, Transaction_t *tr);
    59   |
    60   | /**********************************************************
    61   | * Attribute expansion/conversion functions                *
    62   | ***********************************************************/
    63   | /* Convert ifaddr attribute into a number */
    64   | er_ret_t convert_if(const char *avalue, unsigned int *pif_address)
    65   | {
    66   | char *delim;
    67   | char *ifaddr;
    68   | ip_addr_t ip_addr;
    69   | er_ret_t ret;
    70   |
    71   |  ifaddr= g_strdup(avalue);
    72   |  delim = ifaddr;
    73   |
    74   |   while((*delim) && (!isspace((int)*delim))) {
    75   |       delim++;
    76   |   }
    77   |   *delim='\0';
    78   |
    79   |   ret=IP_addr_a2v4(ifaddr, &ip_addr,  pif_address );
    80   |
    81   |   UT_free(ifaddr);
    82   |   return(ret);
    83   | }
    84   |
    85   |
    86   | /* Convert refer attribute. Free host after use ! */
    87   | char *convert_rf(const char *avalue, int *type, int *port)
    88   | {
    89   | char *delim, *token;
    90   | char *refer;
    91   | char *host;
    92   |
    93   |   host=NULL;
    94   |   refer = g_strdup(avalue);
    95   |   g_strchug(refer);
    96   |   delim=refer;
    97   |   while((*delim) && (!isspace((int)*delim))) {
    98   |       delim++;
    99   |   }
    100  |   if (*delim)*delim='\0'; else return(NULL);
    101  |   delim++;
    102  |
    103  | /* convert the type      */
    104  |   if(g_strcasecmp(refer, S_RIPE)==0)*type=RF_RIPE;
    105  |    else if(g_strcasecmp(refer, S_INTERNIC)==0)*type=RF_INTERNIC;
    106  |     else if(g_strcasecmp(refer, S_SIMPLE)==0)*type=RF_SIMPLE;
    107  |      else if(g_strcasecmp(refer, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS;
    108  |
    109  |   token=delim;
    110  |   g_strchug(token);
    111  |   delim=token;
    112  |   while((*delim) && (!isspace((int)*delim))) {
    113  |       delim++;
    114  |   }
    115  |
    116  |   if(*delim){
    117  |    *delim='\0';
    118  |    delim++;
    119  |   }
    120  | /* convert the hostname      */
    121  |   host = g_strdup(token);
    122  |
    123  | /* convert port number      */
    124  |   if(*delim){
    125  |     token=delim;
    126  |     *port = atoi(token);
    127  |     if (*port==0) *port=RF_DEF_PORT; /* default port number*/
    128  |   } else *port=RF_DEF_PORT;
    129  |
    130  |   UT_free(refer);
    131  |   return(host);
    132  | }
    133  |
    134  |
    135  | /* Convert AS# into integer */
    136  | static int convert_as(const char *as)
    137  | {
    138  | char *ptr;
    139  |
    140  |  ptr=(char *)as;
    141  |  while((*ptr) && (!isdigit((int)*ptr))) ptr++;
    142  |  return(atoi(ptr));
    143  | }
    144  |
    145  | /* Convert AS range (AS4321 - AS5672) into numbers */
    146  | int convert_as_range(const char *as_range, int *begin, int *end)
    147  | {
    148  | char *range;
    149  | char *token;
    150  |
    151  |   range=g_strdup(as_range);
    152  |   token=range;
    153  |   *begin=convert_as(strsep(&token, "-"));
    154  |   *end=convert_as(token);
    155  |   UT_free(range);
    156  |   return(0);
    157  | }
    158  |
    159  | /* Convert time in ASCII format (19991224) into time_t unix time */
    160  | time_t convert_time(const char *asc_time)
    161  | {
    162  | struct tm tm;
    163  | char buf[5];
    164  | char *ptr;
    165  |
    166  |
    167  |   bzero(&tm, sizeof(tm));
    168  |
    169  |   strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
    170  |   tm.tm_year = atoi(buf) - 1900;
    171  |
    172  |   strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
    173  |   tm.tm_mon = atoi(buf) - 1;
    174  |
    175  |   strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
    176  |   tm.tm_mday = atoi(buf);
    177  |
    178  |   return(mktime(&tm));
    179  |
    180  | }
    181  |
    182  |
    183  | /************************************************************
    184  | *  char *get_set_name()                                     *
    185  | *                                                           *
    186  | * Returns set name for the specified object class           *
    187  | *                                                           *
    188  | * **********************************************************/
    189  | static char *get_set_name(C_Type_t class_type)
    190  | {
    191  |  switch(class_type){
    192  |   case C_RT:   return("route_set");
    193  |   case C_AN:   return("as_set");
    194  |   case C_IR:   return("rtr_set");
    195  |   default:     return(NULL);
    196  |  }
    197  | }
    198  |
    199  |
    200  | /************************************************************
    201  | * long get_object_id()                                      *
    202  | * Queries the database for an object.                       *
    203  | * For constructing a query uses each_primary_key_select()   *
    204  | *                                                           *
    205  | * Returns:                                                  *
    206  | * >0 - object exists, returns object_id                     *
    207  | * 0  - object does not exist                                *
    208  | * -1 - error (f.e. more than one object with the same PK)   *
    209  | * -2 - synatx error in the primary key                      *
    210  | * Error code is stored in tr->error                         *
    211  | *                                                           *
    212  | * **********************************************************/
    213  | long get_object_id(Transaction_t *tr)
    214  | {
    215  | rpsl_object_t *object;
    216  | SQ_result_set_t *sql_result;
    217  | SQ_row_t *sql_row;
    218  | char *sql_str;
    219  | long object_id=0;
    220  | int sql_err;
    221  | GList *attr_list;
    222  |
    223  |
    224  |  object=tr->object;
    225  |
    226  | /* compose query */
    227  |  g_string_sprintf(tr->query, "SELECT object_id FROM %s WHERE",
    228  |                              DF_get_class_sql_table(rpsl_get_class_id(rpsl_object_get_class(object))));
    229  |  /* add all primary keys */
    230  |  attr_list = rpsl_object_get_all_attr(object);
    231  |  g_list_foreach(attr_list,  ud_each_primary_key_select, tr);
    232  |
    233  |
    234  |
    235  |  /* check if error has been detected */
    236  |  /* the caller should check tr->succeeded */
    237  |  if(tr->succeeded == 0) return(-2);
    238  |
    239  |  /* truncate the last ' AND '*/
    240  |  g_string_truncate(tr->query, (tr->query->len) - 4);
    241  |
    242  | /* execute query */
    243  |  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    244  |  sql_err=SQ_execute_query(tr->sql_connection, tr->query->str, &sql_result);
    245  |
    246  | /* in case of an error copy error code and return */
    247  |  if(sql_err) {
    248  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    249  |    tr->succeeded=0;
    250  | /*XXX need to return (-2) in case wrong PK was specified */
    251  |    tr->error |= ERROR_U_DBS;
    252  |    die;
    253  |  }
    254  |
    255  | /* Fetch the row */
    256  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
    257  | /* Object exists */
    258  | #define OBJECT_ID 0
    259  |    sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
    260  |    if (sql_str != NULL) {
    261  |      object_id = atol(sql_str);
    262  |      UT_free(sql_str);
    263  |    }
    264  |
    265  | /* We must process all the rows of the result */
    266  | /* otherwise we'll have them as part of the next qry */
    267  |    while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
    268  |  } else
    269  |       object_id=0;  /* object does not exist*/
    270  |
    271  |  SQ_free_result(sql_result);
    272  |  return(object_id);
    273  | }
    274  |
    275  | /************************************************************
    276  | * get_qresult_str()                                         *
    277  | *                                                           *
    278  | * Returns string containing query result                    *
    279  | *                                                           *
    280  | *                                                           *
    281  | * Returns:                                                  *
    282  | *  String containing the result.Needs to be freed after use *
    283  | *  NULL in case of an error                                 *
    284  | *  - SQL error                                              *
    285  | *  - if query returns more than one string (row)            *
    286  | *                                                           *
    287  | *************************************************************/
    288  | char *get_qresult_str(SQ_connection_t *sql_connection, char *query)
    289  | {
    290  | SQ_result_set_t *sql_result;
    291  | SQ_row_t *sql_row;
    292  | char *sql_str;
    293  | int sql_err;
    294  |
    295  |
    296  |  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    297  |  sql_err=SQ_execute_query(sql_connection, query, &sql_result);
    298  |
    299  |  if(sql_err) {
    300  |     ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query);
    301  |     die;
    302  |  }
    303  |
    304  |
    305  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
    306  | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
    307  |
    308  |      /* We must process all the rows of the result,*/
    309  |      /* otherwise we'll have them as part of the next qry */
    310  | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
    311  | 	  ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query);
    312  | 	  if(sql_str) UT_free(sql_str); sql_str=NULL;
    313  | 	}
    314  |  }
    315  |  else sql_str=NULL;
    316  |
    317  |  SQ_free_result(sql_result);
    318  |  return(sql_str);
    319  | }
    320  |
    321  |
    322  |
    323  | /************************************************************
    324  | * get_field_str()                                           *
    325  | *                                                           *
    326  | * Returns string containing the field.                      *
    327  | *  field - field name to be retrieved                       *
    328  | *  ref_tbl_name - name of the table containing the field    *
    329  | *  ref_name - reference name                                *
    330  | *  attr_value - reference value                             *
    331  | *  condition - additional condition ( f.e. 'AND dummy=0'    *
    332  | *                                                           *
    333  | * Returns:                                                  *
    334  | *  String containing the field. Needs to be freed after use *
    335  | *  NULL in case of an error                                 *
    336  | *                                                           *
    337  | *************************************************************/
    338  | char *get_field_str(SQ_connection_t *sql_connection, const char *field,
    339  | 			   const char *ref_tbl_name, const char *ref_name,
    340  | 			   const char * attr_value,  const char *condition)
    341  | {
    342  | GString *query;
    343  | char *result;
    344  |
    345  |  query = g_string_sized_new(STR_L);
    346  |
    347  |  g_string_sprintf(query, "SELECT %s FROM %s "
    348  |                          "WHERE %s='%s' ",
    349  | 		         field, ref_tbl_name, ref_name, attr_value);
    350  |  if (condition)g_string_append(query, condition);
    351  |
    352  |  result = get_qresult_str(sql_connection, query->str);
    353  |  g_string_free(query, TRUE);
    354  |  return( result );
    355  |
    356  | }
    357  |
    358  | /************************************************************
    359  | * long get_sequence_id(Transaction_t *tr)
    360  | * >0 - success
    361  | * -1 - sql error
    362  | *
    363  | * **********************************************************/
    364  |
    365  | long get_sequence_id(Transaction_t *tr)
    366  | {
    367  | char *sql_str;
    368  | char str_id[STR_M];
    369  | long sequence_id=-1;
    370  |
    371  |
    372  |   sprintf(str_id, "%ld", tr->object_id);
    373  |   sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL);
    374  |   if(sql_str) {
    375  |        	  sequence_id = atol(sql_str);
    376  |        	  UT_free(sql_str);
    377  |   }
    378  |
    379  |   return(sequence_id);
    380  |
    381  | }
    382  |
    383  |
    384  | /************************************************************
    385  | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
    386  | * >0 - success
    387  | * -1 - sql error
    388  | *
    389  | * **********************************************************/
    390  |
    391  | static long get_ref_id(Transaction_t *tr, const char *ref_tbl_name, const char *ref_name, const char * attr_value, const char *condition)
    392  | {
    393  | char *sql_str;
    394  | long ref_id=-1;
    395  |
    396  | 	sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition);
    397  | 	if(sql_str) {
    398  | 		 ref_id = atol(sql_str);
    399  | 		 UT_free(sql_str);
    400  | 	}
    401  | 	return(ref_id);
    402  | }
    403  |
    404  |
    405  | /************************************************************
    406  | * int isdummy()
    407  | *
    408  | * Returns 1 if the object in question is a dummy,
    409  | * otherwise returns 0.
    410  | *
    411  | * In case of error:
    412  | * -1 - sql error or object does not exist
    413  | *
    414  | ***********************************************************/
    415  |
    416  | int isdummy(Transaction_t *tr)
    417  | {
    418  | char *sql_str;
    419  | char str_id[STR_M];
    420  | int object_type=-1;
    421  |
    422  |   sprintf(str_id, "%ld", tr->object_id);
    423  |   sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL);
    424  |   if(sql_str) {
    425  |        	  object_type = atoi(sql_str);
    426  |        	  UT_free(sql_str);
    427  |   }
    428  |
    429  |   if (object_type==-1) {
    430  |    ER_perror(FAC_UD, UD_SQL, "cannot get object type\n");
    431  |    die;
    432  |   }
    433  |   if (object_type==DUMMY_TYPE) return(1);
    434  |   else return(0);
    435  |
    436  | }
    437  |
    438  | /************************************************************
    439  | * process_reverse_domain()                                  *
    440  | *                                                           *
    441  | * Tries to insert additional data for reverse domains       *
    442  | * This data includes prefix and perfix length for reverse   *
    443  | * delegation block. It is stored in inaddr_arpa table for   *
    444  | * IPv4 and ip6int table for IPv6 address spaces             *
    445  | *                                                           *
    446  | * Returns:                                                  *
    447  | * 0  success                                                *
    448  | * -1 sql error                                              *
    449  | *                                                           *
    450  | *************************************************************/
    451  |
    452  | static int process_reverse_domain(Transaction_t *tr,
    453  | 				  ip_prefix_t *prefptr,
    454  | 				  int op)
    455  | {
    456  |   unsigned prefix, prefix_length; /* ipv4 */
    457  |   ip_v6word_t msb, lsb;          /* ipv6 */
    458  |   char query[512];
    459  |   int num;
    460  |   int sql_err;
    461  |
    462  |
    463  |   if( IP_pref_b2_space(prefptr) == IP_V4 ) {  /* ipv4 */
    464  |     if(op==0) { /* insert record */
    465  |       IP_revd_b2v4(prefptr, &prefix, &prefix_length);
    466  |       sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ",
    467  | 	      tr->thread_ins, tr->object_id, prefix, prefix_length);
    468  |     }
    469  |     else {
    470  |       /* update record */
    471  |       sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ",
    472  | 	      tr->thread_upd, tr->object_id);
    473  |     }
    474  |   }
    475  |   else { /* ipv6 */
    476  |     if(op==0) { /* insert record */
    477  |       IP_revd_b2v6(prefptr, &msb, &lsb, &prefix_length);
    478  |       sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, msb='%llu', lsb='%llu', prefix_length=%d ",
    479  | 	      tr->thread_ins, tr->object_id, msb, lsb, prefix_length);
    480  |     }
    481  |     else {
    482  |       /* update record */
    483  |       sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ",
    484  | 	      tr->thread_upd, tr->object_id);
    485  |     }
    486  |   }
    487  |
    488  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    489  |   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    490  |   num = SQ_get_affected_rows(tr->sql_connection);
    491  |
    492  |   /* Check for errors */
    493  |   if (sql_err) {
    494  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
    495  |    die;
    496  |   }
    497  |   /* If nothing was affected then WHERE clause returned nothing - DB error */
    498  |   if(num == 0) {
    499  |    ER_perror(FAC_UD, UD_SQL, "insert inaddr had no effect [%s]\n", query);
    500  |    die;
    501  |   }
    502  |   return(0);
    503  | }
    504  |
    505  | #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0)
    506  | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
    507  |
    508  |
    509  | /************************************************************
    510  | * auth_member_of()                                          *
    511  | *                                                           *
    512  | * Function that checks the authorization for membership     *
    513  | * (i.e. if the object is authorized to be a memeber by      *
    514  | * mbrs-by-ref attribute of the set is refers by member-of   *
    515  | * attribute).                                               *
    516  | * First checks if 'mbrs-by-ref: ANY'                        *
    517  | * If not then checks that maintner referenced by            *
    518  | * mbrs-by-ref attribute of the set is the one in mnt-by.    *
    519  | *                                                           *
    520  | * Returns:                                                  *
    521  | * 0  success                                                *
    522  | * 1  not allowed                                            *
    523  | * -1 SQL error                                              *
    524  | *                                                           *
    525  | *************************************************************/
    526  | static int auth_member_of(const rpsl_attr_t *attribute, Transaction_t *tr)
    527  | {
    528  | GString *query;
    529  | char *set_name;
    530  | char *qresult;
    531  |
    532  | int attribute_type;
    533  | const gchar *attribute_value;
    534  |
    535  |  attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    536  |  attribute_value = rpsl_attr_get_value(attribute);
    537  |
    538  | /* Check if set has mbrs_by_ref==ANY
    539  |    In such case mbrs_by_ref.mnt_id==0
    540  | */
    541  |
    542  |  if ((query = g_string_sized_new(STR_XL)) == NULL){
    543  |   tr->succeeded=0;
    544  |   tr->error |= ERROR_U_MEM;
    545  |   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
    546  |   die;
    547  |  }
    548  |
    549  |  set_name = get_set_name(tr->class_type);
    550  | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s set name retrieved: %s\n", UD_TAG, set_name);	*/
    551  |
    552  | /* Check if the set protects itself with mbrs-by-ref attribute */
    553  |    g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s "
    554  |    		          "WHERE mbrs_by_ref.object_id=%s.object_id "
    555  | 			  "AND %s.%s='%s' ",
    556  | 			  set_name, set_name, set_name, set_name, attribute_value);
    557  |
    558  |    qresult = get_qresult_str(tr->sql_connection, query->str);
    559  |    /* should be '0' if there is no mbrs-by-ref attribute */
    560  |    if (strcmp(qresult, "0")==0){
    561  | 	   /* there is no mbrs-by-ref attribute - so we cannot go ahead */
    562  | 	   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not allowed (no mbrs-by-ref) [%d:%s]", tr->transaction_id, attribute_type, attribute_value);
    563  | 	   UT_free(qresult);
    564  | 	   g_string_free(query, TRUE);
    565  |            return(1);
    566  |    }
    567  |    else UT_free(qresult);
    568  |
    569  |
    570  | /* Check if membership is protected by the keyword "ANY" */
    571  | /* There is a dummy mntmer object in the database corresponding to "ANY" */
    572  | /* Its object_id==0 */
    573  | /* EXAMPLE:
    574  |
    575  |    SELECT route_set.object_id
    576  |    FROM   mbrs_by_ref, route_set
    577  |    WHERE  mbrs_by_ref.object_id=route_set.object_id
    578  |    AND    route_set.route_set=<setname>
    579  |    AND    mbrs_by_ref.mnt_id=0
    580  | */
    581  |     g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
    582  |                            "WHERE mbrs_by_ref.object_id=%s.object_id "
    583  | 		           "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ",
    584  | 			   set_name, set_name, set_name, set_name, set_name, attribute_value);
    585  |
    586  |     qresult = get_qresult_str(tr->sql_connection, query->str);
    587  |   /* if such record exists - go ahead */
    588  |     if(qresult) {
    589  | 	UT_free(qresult);
    590  | 	g_string_free(query, TRUE);
    591  |         return(0);
    592  |     }
    593  |
    594  | /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */
    595  | /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */
    596  |     g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM %s, mbrs_by_ref, mnt_by "
    597  |  			    "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
    598  |     			    "AND mnt_by.object_id=%ld "
    599  |     			    "AND %s.object_id=mbrs_by_ref.object_id "
    600  |     			    "AND %s.%s='%s' "
    601  |     			    "AND ( mnt_by.thread_id=%d OR mnt_by.thread_id=%d ) ",
    602  |     			    set_name, tr->object_id, set_name, set_name, set_name,
    603  |                             attribute_value, tr->thread_upd, tr->thread_ins);
    604  |
    605  |     qresult = get_qresult_str(tr->sql_connection, query->str);
    606  |     /* If our mntner is listed (non-empty result)  membership is authorized */
    607  |     if (qresult) {
    608  | 	 UT_free(qresult);
    609  |          g_string_free(query, TRUE);
    610  | 	 return(0);
    611  |     } else {
    612  | 	 ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not autorized [%d:%s]", tr->transaction_id, attribute_type, attribute_value);
    613  | 	 g_string_free(query, TRUE);
    614  | 	 return(1);
    615  |     }
    616  |  }/* auth_member_of()  */
    617  |
    618  |
    619  | /************************************************************
    620  | * create_dummy()                                            *
    621  | *                                                           *
    622  | * Function that creates a dummy object (that is one that    *
    623  | * is referenced from an object but does not                 *
    624  | * exist in the database).                                   *
    625  | * Dummy object exists only in relevant main and 'last'      *
    626  | * tables. Its creation is controlled by tr->dummy_allowed.  *
    627  | * Queries for the dummies are defined in Dummy[] array.     *
    628  | *                                                           *
    629  | * Returns:                                                  *
    630  | * 0  success                                                *
    631  | * 1  no rf integrity and dummy not allowed                  *
    632  | * -1 SQL error                                              *
    633  | *                                                           *
    634  | *************************************************************/
    635  | static int create_dummy(const rpsl_attr_t *attribute, Transaction_t *tr)
    636  | {
    637  | const char *query_fmt;
    638  | long dummy_id;
    639  | GString *query;
    640  | int result=0;
    641  | char *set_name;
    642  | char *p_name;
    643  | int query_type;
    644  | long timestamp;
    645  | char str_id[16];
    646  | int sql_err;
    647  | char *token=NULL;
    648  |
    649  | int commit_now;
    650  | nic_handle_t *nh_ptr;
    651  | char *a_value;
    652  |
    653  | int attribute_type;
    654  | const gchar *attribute_value;
    655  |
    656  | /* Determine the attribute type */
    657  |   attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    658  | /* Get attribute value .It is already clean since we process the flattened copy of the object */
    659  |   attribute_value = rpsl_attr_get_value(attribute);
    660  |
    661  |   query_fmt = DF_get_dummy_query(attribute_type);
    662  |   if (strcmp(query_fmt, "") == 0) {
    663  |      ER_perror(FAC_UD, UD_BUG, "empty query string\n");
    664  |      die;
    665  |   }
    666  |  /* for loader we do not perform commits/rollbacks */
    667  |  if(IS_STANDALONE(tr->mode))commit_now = 1; else commit_now = 0;
    668  |
    669  |   /* We allow creating dummy sets in any mode */
    670  |   /* For others attributes return if we are in protected mode */
    671  |   if ((attribute_type!=A_MO) &&  (!IS_DUMMY_ALLOWED(tr->mode))) return(1);
    672  |
    673  | /* Allocate resourses. We cannot use tr->query because it is in use */
    674  |   if ((query = g_string_sized_new(STR_XL)) == NULL){
    675  |         ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
    676  |         die;
    677  |   }
    678  |
    679  |   /* Insert dummy in the last table */
    680  |   /* Calculate the object_id - should be max+1 */
    681  |   dummy_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1;
    682  |  /* Record dummy's object_id, it'll be needed in commit/rollback */
    683  |   tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
    684  |
    685  |   /* Update the TR for crash recovery */
    686  |   /* If we crash before actually creating an entry in last */
    687  |   /* there should be no harm - later in rollback we will just try to delete nonexistent object */
    688  |   TR_update_dummy(tr);
    689  |
    690  |   sprintf(str_id, "%ld", tr->object_id);
    691  |   timestamp=time(NULL);
    692  |   g_string_sprintf(query, "INSERT INTO last SET thread_id=%d, object_id=%ld, timestamp=%ld, object_type=%d, object='DUMMY for %s'",
    693  |                   tr->thread_ins, dummy_id, timestamp, DUMMY_TYPE, str_id);
    694  |
    695  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    696  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    697  |
    698  |   /* Check for errors */
    699  |   if (sql_err) {
    700  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    701  |    die;
    702  |   }
    703  |
    704  |
    705  |   /* compose the query */
    706  |   query_type=DF_get_dummy_query_type(attribute_type);
    707  |   switch (query_type) {
    708  |
    709  | 	 /* person_role */
    710  | 	 case UD_AX_PR:
    711  | 	 /* irt      */
    712  | 	 case UD_AX_IT:
    713  |          /* maintner */
    714  | 	 case UD_AX_MT:
    715  | 	      g_string_sprintf(query, query_fmt, tr->thread_ins, dummy_id, attribute_value, DUMMY_TYPE);
    716  | 	      break;
    717  |
    718  |          /* as_set, route_set */
    719  | 	 case UD_AX_MO:
    720  | 	      set_name = get_set_name(tr->class_type);
    721  | 	      g_string_sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attribute_value);
    722  | 	      break;
    723  |
    724  | 	 default:
    725  | 	      ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute[%d]\n", attribute_type);
    726  | 	      die;
    727  |               break;
    728  |   }
    729  |
    730  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    731  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    732  |   if (sql_err) {
    733  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    734  |    die;
    735  |   }
    736  |
    737  |
    738  |   /* for legacy person/role reference try to allocate a nic handle in NHR, */
    739  |   /* if failied - create records in names table */
    740  |   if(query_type == UD_AX_PR) {
    741  |       if(NH_parse(attribute_value, &nh_ptr)>0) {
    742  |        int nhres;
    743  |       /* go ahead and register */
    744  |         if(NH_check(nh_ptr, tr->sql_connection)>0){
    745  |           nhres = NH_register(nh_ptr, tr->sql_connection, commit_now);
    746  |           if(nhres == -1) {
    747  |            tr->succeeded=0;
    748  |            tr->error |= ERROR_U_DBS;
    749  |            ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle %s", attribute_value);
    750  |            die;
    751  |           }
    752  |           else if(nhres == 0) {
    753  |            tr->succeeded=0;
    754  |            tr->error |= ERROR_U_OBJ;
    755  |            ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] nic handle [%s]: wrong or already in use", tr->transaction_id, attribute_value);
    756  |            g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle wrong or already in use\n", ERROR_U_OBJ, attribute_type, attribute_value);
    757  |            result=-1;
    758  |           }
    759  |         } else {
    760  |            tr->succeeded=0;
    761  |            tr->error |= ERROR_U_OBJ;
    762  |            ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] nic handle [%s]: wrong or already in use", tr->transaction_id, attribute_value);
    763  |            g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle wrong or already in use\n", ERROR_U_OBJ, attribute_type, attribute_value);
    764  |            result=-1;
    765  |         }
    766  |        free_nh(nh_ptr);
    767  |       }
    768  |       else {
    769  |       /* create record in the names table */
    770  |         query_fmt = DF_get_insert_query(A_PN);
    771  |
    772  |         /* we need to copy string as strsep is destructive */
    773  |         a_value = g_strdup(attribute_value);
    774  |         token = a_value;
    775  |
    776  |         while((p_name=strsep(&token, " \t"))){
    777  |           if (*p_name != '\0'){
    778  |              g_string_sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
    779  |              ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    780  |              sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    781  |              if(sql_err && (SQ_errno(tr->sql_connection) != ER_DUP_ENTRY)) {
    782  |                ER_perror(FAC_UD, UD_SQL, "insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    783  |                result=-1;
    784  |              }
    785  |           }
    786  |         }
    787  |         UT_free(a_value);
    788  |       }
    789  |   }
    790  |
    791  |  g_string_free(query, TRUE);
    792  |  return(result);
    793  | }
    794  |
    795  | /************************************************************
    796  | * update_attr()                                             *
    797  | *                                                           *
    798  | * Function that updates an attribute if it already exists.  *
    799  | * Called from each_attribute_proces() function if it        *
    800  | * cannot insert the row.                                    *
    801  | * Queries for the attributes are defined in Update[] array. *
    802  | *                                                           *
    803  | * Returns: Nothing. Error code is stored in tr->error.      *
    804  | *                                                           *
    805  | *************************************************************/
    806  | static void update_attr(const rpsl_attr_t *attribute, Transaction_t *tr)
    807  | {
    808  | int num;
    809  | const char *query_fmt;
    810  | char *set_name;
    811  | unsigned int if_address;
    812  | char * rf_host;
    813  | int rf_port, rf_type;
    814  | char *a_value;
    815  | int sq_info[3];
    816  | char * condition;
    817  | char *sq_error;
    818  | int sql_err;
    819  | char *token;
    820  | char *mu_mntner;
    821  | ip_prefix_t dn_pref;
    822  |
    823  |
    824  |
    825  | int attribute_type;
    826  | const char *attribute_value;
    827  |
    828  |
    829  | /* Determine the attribute type */
    830  |    attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    831  |
    832  | /* For 2-pass loader it may be needed to update second attribute */
    833  | /* stored in the main table, like inetnum, filter-set, etc. */
    834  |    if((IS_STANDALONE(tr->mode))&&(DF_get_update_query_type(attribute_type)!=UD_MA_U2)) return;
    835  |
    836  |
    837  | /* get the value of the attribue. It is already clean since we process the flattened copy of the object */
    838  |    attribute_value = rpsl_attr_get_value(attribute);
    839  |
    840  |
    841  | /* Do some additional processing for reverse domains */
    842  |    /*We need to tag the record in inaddr_arpa or int6 tables dor the commit/rollback */
    843  |    /* Otherwise it will be deleted */
    844  |    /* XXX Later we will implement this under UD_MA_DN case */
    845  |    if ((attribute_type == A_DN) && (IP_revd_a2b(&dn_pref, attribute_value)==IP_OK)) {
    846  |      if(update_reverse_domain(tr, &dn_pref) !=0 ){
    847  |        tr->error|=ERROR_U_DBS;
    848  |        tr->succeeded=0;
    849  |        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
    850  | 			 ERROR_U_DBS, attribute_type, attribute_value, SQ_error(tr->sql_connection));
    851  |      }
    852  |    }
    853  |
    854  |
    855  |
    856  |    /* get query format string */
    857  |    query_fmt =  DF_get_update_query(attribute_type);
    858  |
    859  |    if (strcmp(query_fmt, "") == 0) return;
    860  |
    861  |    switch (DF_get_update_query_type(attribute_type)) {
    862  |          case UD_MAIN_: g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id);
    863  |                         break;
    864  | 	 case UD_MA_PR:
    865  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
    866  | 			break;
    867  | 	 case UD_MA_U2: /* save the new value of the attribute for commit*/
    868  |                   /* this is necessary for filter(filter-set), netname (inet?num), */
    869  | 		  /* local-as(inet-rtr) attributes, as they are another field in the record */
    870  | 		        if(IS_STANDALONE(tr->mode)){
    871  | 		      /* for 2-pass loader we need to update the field as we have no commit */
    872  | 		          g_string_sprintf(tr->query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attribute_value, tr->object_id);
    873  | 		        }
    874  | 		        else {
    875  |                          /* free memory in case U2 attribute appears more than once in the object */
    876  |                          /* this should be spotted by dbupdate, otherwise just write over */
    877  |             	         if(tr->save) UT_free(tr->save);
    878  |                          tr->save=g_strdup(attribute_value);
    879  |                          /* update TR for crash recovery */
    880  | 			 TR_update_save(tr);
    881  |             	         return;
    882  |             	        }
    883  | 			break;
    884  | 	 case UD_AX_PR:
    885  | 	 		if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    886  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    887  | 	 			get_ref_id(tr, "person_role", "nic_hdl", attribute_value, condition));
    888  | 	 		break;
    889  | 	 case UD_AX_MT:
    890  | 	 		if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    891  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    892  | 	 			get_ref_id(tr, "mntner", "mntner", attribute_value, condition));
    893  | 	 		break;
    894  |  	 case UD_AX_IT:
    895  | 	 		if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    896  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    897  | 	 			get_ref_id(tr, "irt", "irt", attribute_value, condition));
    898  | 	 		break;
    899  |         case UD_AX_MU: /* for mnt_routes table*/
    900  |    	                a_value=g_strdup(attribute_value);
    901  |                         token = a_value;
    902  |                         /* we only store the mntner name, don't care about prefixes */
    903  |                         mu_mntner=strsep(&token, " \t");
    904  |                        	if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    905  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    906  | 	 			get_ref_id(tr, "mntner", "mntner", mu_mntner, condition));
    907  | 			UT_free(a_value);
    908  | 			break;
    909  | 	 case UD_AX_MO:
    910  | 			set_name = get_set_name(tr->class_type);
    911  | 			if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    912  | 			g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    913  | 					get_ref_id(tr, set_name, set_name, attribute_value, condition));
    914  | 			break;
    915  |     	 case UD_AX_MR:
    916  |       			if ((g_strcasecmp(attribute_value, "ANY")==0))
    917  |       		 	g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    918  |       		 	 	get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
    919  |       			else {
    920  |       		 	 if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    921  |       		 	 g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id,
    922  |       		 	 	get_ref_id(tr, "mntner", "mntner", attribute_value, condition));
    923  |       		 	}
    924  | 			break;
    925  | 	 case UD_LEAF_:
    926  | 	 		g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id, attribute_value);
    927  | 			break;
    928  | 	 case UD_LF_IF:
    929  | 		/* Convert ascii ip -> numeric one */
    930  |       	                convert_if(attribute_value, &if_address);
    931  | 			g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id, if_address);
    932  |     			break;
    933  | 	 case UD_LF_RF:
    934  | 			rf_host=convert_rf(attribute_value, &rf_type, &rf_port);
    935  | 			if(rf_host == NULL) {
    936  | 				tr->error|=ERROR_U_OBJ;
    937  |   	                        tr->succeeded=0;
    938  |   	                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect refer attribute\n" ,
    939  | 				ERROR_U_OBJ, attribute_type, attribute_value);
    940  | 				return;
    941  | 			}
    942  | 			else {
    943  | 			        g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
    944  | 			        UT_free(rf_host);
    945  | 			}
    946  | 			break;
    947  |   	 case UD_LF_AY:
    948  |                   	g_string_sprintf(tr->query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attribute_value));
    949  |                    	break;
    950  | 	   default:
    951  | 			tr->error|=ERROR_U_BUG;
    952  | 			tr->succeeded=0;
    953  | 			g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attribute_type, attribute_value);
    954  | 			ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attribute_type, attribute_value);
    955  | 			die;
    956  |     			break;
    957  |         }
    958  |    /* Execute the query */
    959  |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query);
    960  |     sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    961  |     if(sql_err) { /* an error occured*/
    962  |      /* Error - copy the error condition and return */
    963  |         sq_error=SQ_error(tr->sql_connection);
    964  | 	ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, tr->query->str);
    965  | 	tr->error|=ERROR_U_DBS;
    966  | 	tr->succeeded=0;
    967  | 	g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attribute_type, attribute_value, sq_error);
    968  | 	die;
    969  |     }
    970  |     else {
    971  |      /* Query OK */
    972  |       num = SQ_get_affected_rows(tr->sql_connection);
    973  |       if(num == 0) { /* check for duplicates*/
    974  |   	SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
    975  |   	if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) {
    976  |   	/* Condition with zero duplicates and matches may occur when the object is a dummy */
    977  |   	/* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
    978  |   	/* In such case we will append "AND dummy=0" to the query, which won't */
    979  |   	/* return a match if the object in question is a dummy */
    980  |   	  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy prevents update: [%s]", tr->transaction_id, tr->query->str);
    981  |   	  tr->error|=ERROR_U_OBJ;
    982  |   	  tr->succeeded=0;
    983  |   	  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:ref integrity: reference cannot be resolved\n" ,
    984  |           ERROR_U_OBJ, attribute_type, attribute_value);
    985  |   	} /* else duplicate entry - silently drop it  */
    986  |       }
    987  |       /* For member_of attribute we need to check membership claim in protected mode */
    988  |       if ((attribute_type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
    989  | 	  if(auth_member_of(attribute, tr)!=0){
    990  | 	  tr->error|=ERROR_U_AUT;
    991  | 	  tr->succeeded=0;
    992  | 	  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership by reference is not allowed [%d:%s]", tr->transaction_id, attribute_type, attribute_value);
    993  | 	  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attribute_type, attribute_value);
    994  | 	}
    995  |       }
    996  |     }
    997  | return;
    998  | }/*  update_attr()  */
    999  |
    1000 |
    1001 | /************************************************************
    1002 | * create_attr()                                             *
    1003 | *                                                           *
    1004 | * A function that tries to create an attribute in a relevant*
    1005 | * sql table. If unsuccessful we check if it's an update     *
    1006 | * For primary keys no creations are attempted               *
    1007 | *                                                           *
    1008 | * Returns:                                                  *
    1009 | *  ATTR_CREATE_OK = ok                                      *
    1010 | *  ATTR_CREATE_NO = this is an update, go to update_attr()  *
    1011 | *  ATTR_CRETE_DONE = no further action is needed, return    *
    1012 | *  ATTR_CREATE_ERR = an sql error occured                   *
    1013 | *                                                           *
    1014 | *************************************************************/
    1015 | static int create_attr(const rpsl_attr_t *attribute, Transaction_t *tr)
    1016 | {
    1017 | const char *query_fmt;
    1018 | int query_type;
    1019 | int do_query;
    1020 | unsigned int prefix, prefix_length, if_address;
    1021 | unsigned int begin_in, end_in;
    1022 | ip_v6word_t  high, low;
    1023 |
    1024 | int begin_as, end_as;
    1025 | char * set_name;
    1026 | char * rf_host; /* needs to be freed after use*/
    1027 | int rf_type, rf_port;
    1028 | char *a_value;
    1029 | char *mu_mntner;
    1030 | int sql_err;
    1031 | int res;
    1032 | char *token;
    1033 | int result;
    1034 |
    1035 | int attribute_type;
    1036 | const gchar *attribute_value;
    1037 |
    1038 |  /* To switch off querying for some types of attributes */
    1039 |   do_query=1;
    1040 |  /* default result */
    1041 |   result = ATTR_CREATE_NO;
    1042 |
    1043 |  /* Determine the query type */
    1044 |   attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    1045 |   /* attribute value is already clean since we have a "flattened" object */
    1046 |   attribute_value = rpsl_attr_get_value(attribute);
    1047 |
    1048 |   query_type=DF_get_insert_query_type(attribute_type);
    1049 |   query_fmt = DF_get_insert_query(attribute_type);
    1050 |
    1051 |  /* compose the query depending on the attribute */
    1052 |   switch (query_type) {
    1053 |    case UD_MAIN_: /* for MAIN tables */
    1054 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1055 |     		else
    1056 |     		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, attribute_value);
    1057 |     		break;
    1058 |    case UD_MA_OR: /* for the origin attribute */
    1059 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1060 |     		else {
    1061 | 		  g_string_sprintf(tr->query, query_fmt, tr->thread_ins, attribute_value, tr->object_id);
    1062 | 		  tr->action |= TA_UPD_RX;
    1063 | 		  RP_pack_set_orig(attribute_type, tr->packptr, attribute_value);
    1064 | 		}
    1065 |     		break;
    1066 |    case UD_MA_PR: /* for person_role table*/
    1067 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1068 |    		else
    1069 |    		 g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attribute_value);
    1070 |
    1071 |    		/* check if we need to update NHR */
    1072 |     		if (ACT_UPD_NHR(tr->action)) {
    1073 | 		 /* Check if we can allocate it */
    1074 | 		  res = NH_check(tr->nh, tr->sql_connection);
    1075 | 		  if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
    1076 | 		     tr->succeeded=0;
    1077 | 		     tr->error |= ERROR_U_DBS;
    1078 | 		     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attribute_type, attribute_value);
    1079 | 		     ER_perror(FAC_UD, UD_SQL, "cannot allocate nic hdl[%s]\n", attribute_value);
    1080 |                      die;
    1081 |                   }
    1082 |                   else
    1083 |                   if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
    1084 | 		    tr->succeeded=0;
    1085 | 		    tr->error |= ERROR_U_OBJ;
    1086 | 		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle wrong or already in use\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1087 | 		    result = ATTR_CREATE_DONE;
    1088 | 		    do_query = 0;
    1089 | 		  }
    1090 | 		}
    1091 |     		break;
    1092 |    case UD_MA_RT: /* for route table*/
    1093 |     		if (ACT_UPDATE(tr->action)) do_query=0;
    1094 |     		else {
    1095 |                   tr->action |= TA_UPD_RX;
    1096 |     		  if(RP_pack_set_pref4(attribute_type, attribute_value, tr->packptr, &prefix, &prefix_length)==IP_OK){
    1097 | 		  /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s route: %u/%u\n", UD_TAG, prefix, prefix_length);     		*/
    1098 | 		    g_string_sprintf(tr->query, query_fmt, tr->thread_ins,
    1099 | 			  tr->object_id, prefix, prefix_length);
    1100 |                   } else {
    1101 |                     tr->succeeded=0;
    1102 | 		    tr->error |= ERROR_U_OBJ;
    1103 | 		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong prefix specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1104 | 		    result = ATTR_CREATE_DONE;
    1105 | 		    do_query = 0;
    1106 |                   }
    1107 | 	    	}
    1108 |     		break;
    1109 |    case UD_MA_IN: /* for inetnum table*/
    1110 |     		if (ACT_UPDATE(tr->action)) do_query=0;
    1111 |     		else {
    1112 |     		  if(RP_pack_set_rang(attribute_type, attribute_value, tr->packptr, &begin_in, &end_in)==IP_OK){
    1113 |                     tr->action |= TA_UPD_RX;
    1114 | 		    g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
    1115 |                   } else {
    1116 |                     tr->succeeded=0;
    1117 | 		    tr->error |= ERROR_U_OBJ;
    1118 | 		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong range specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1119 | 		    result = ATTR_CREATE_DONE;
    1120 | 		    do_query = 0;
    1121 |                   }
    1122 | 		}
    1123 |     		break;
    1124 |    case UD_MA_I6: /* for inet6num table*/
    1125 |                 if (ACT_UPDATE(tr->action)) do_query=0;
    1126 |     		else {
    1127 | 		  if(RP_pack_set_pref6(attribute_type, attribute_value, tr->packptr, &high, &low, &prefix_length)==IP_OK){
    1128 | 		    g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
    1129 |                     tr->action |= TA_UPD_RX;
    1130 |                   }else {
    1131 |                     tr->succeeded=0;
    1132 | 		    tr->error |= ERROR_U_OBJ;
    1133 | 		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong prefix specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1134 | 		    result = ATTR_CREATE_DONE;
    1135 | 		    do_query = 0;
    1136 |                   }
    1137 | 		}
    1138 |     		break;
    1139 |    case UD_MA_U2: /* This is actually an update - go to update_attr - this is more logical */
    1140 |                  do_query=0;
    1141 |             	break;
    1142 |    case UD_MA_AK: /* for as_block table*/
    1143 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1144 |    		else {
    1145 |    		  convert_as_range(attribute_value, &begin_as, &end_as);
    1146 | 		  g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
    1147 |    		}
    1148 |    		break;
    1149 |    case UD_AUX__: /* for AUX tables*/
    1150 |     		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attribute_value);
    1151 |     		if(!IS_DUMMY_ALLOWED(tr->mode))g_string_sprintfa(tr->query, " AND dummy=0 ");
    1152 |     		break;
    1153 |    case UD_AX_MO: /* for member_of table*/
    1154 | 		set_name = get_set_name(tr->class_type);
    1155 | /*    		ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/
    1156 |     		g_string_sprintf(tr->query, query_fmt, tr->thread_ins,
    1157 | 	    	 tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attribute_value);
    1158 |     		break;
    1159 |    case UD_AX_MR: /* for mbrs_by_ref table*/
    1160 |       		if ((g_strcasecmp(attribute_value, "ANY")==0))
    1161 |       		 g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
    1162 |       		else
    1163 |       		 g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attribute_value);
    1164 | 		break;
    1165 |    case UD_AX_MU: /* for mnt_routes table*/
    1166 |    		a_value=g_strdup(attribute_value);
    1167 | 		token = a_value;
    1168 |                 /* we only store the mntner name, don't care about prefixes */
    1169 | 		mu_mntner=strsep(&token, " \t");
    1170 |    		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner);
    1171 |    		UT_free(a_value);
    1172 |    		if(!IS_DUMMY_ALLOWED(tr->mode))g_string_sprintfa(tr->query, " AND dummy=0 ");
    1173 |    		break;
    1174 |    case UD_LEAF_: /* for LEAF tables*/
    1175 |     		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, attribute_value);
    1176 |     		break;
    1177 |    case UD_LF_OT: /* for LEAF tables containing object_type field*/
    1178 |    		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attribute_value);
    1179 |    		break;
    1180 |    case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
    1181 |       		if(!IS_DUMMY_ALLOWED(tr->mode)){
    1182 |       		 if(strncmp("PGPKEY", attribute_value, 6)==0) {
    1183 |       		   if(get_ref_id(tr, "key_cert", "key_cert", attribute_value, NULL)<=0) {
    1184 |       		    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] no key-cert object[%s]", tr->transaction_id, attribute_value);
    1185 |       		    tr->error|=ERROR_U_OBJ;
    1186 |       		    tr->succeeded=0;
    1187 |       		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attribute_type, attribute_value);
    1188 |      		    result = ATTR_CREATE_DONE;
    1189 |      		    do_query = 0;
    1190 |      		    break;
    1191 |       	           }
    1192 |       		 }
    1193 |       		}
    1194 |       		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attribute_value);
    1195 |       		break;
    1196 |    case UD_LF_IF: /* for ifaddr tables*/
    1197 |     		/* Convert ascii ip -> numeric one*/
    1198 |     		convert_if(attribute_value, &if_address);
    1199 | 		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, if_address);
    1200 |     		break;
    1201 |    case UD_LF_RF: /* for refer table*/
    1202 |     		rf_host=convert_rf(attribute_value, &rf_type, &rf_port);
    1203 |                 /*XXX Maybe this is redundant */
    1204 | 		if(rf_host == NULL) {
    1205 | 				tr->error|=ERROR_U_OBJ;
    1206 |   	                        tr->succeeded=0;
    1207 |   	                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect refer attribute\n" ,
    1208 | 				ERROR_U_OBJ, attribute_type, attribute_value);
    1209 | 				result = ATTR_CREATE_DONE;
    1210 | 				do_query = 0;
    1211 | 		}
    1212 | 		else {
    1213 |     		                g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
    1214 |     		                UT_free(rf_host);
    1215 | 		}
    1216 |     		break;
    1217 |    case UD_LF_AY: /* for auth_override table*/
    1218 |    		g_string_sprintf(tr->query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attribute_value));
    1219 |    		break;
    1220 |     	default:
    1221 |                 tr->succeeded=0;
    1222 |                 tr->error |= ERROR_U_BUG;
    1223 |                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attribute_type, attribute_value);
    1224 | 		ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attribute_type, attribute_value);
    1225 |                 die;
    1226 |     		break;
    1227 |   }
    1228 |
    1229 |
    1230 |  /* Make the query. For primary keys go straight to updates if we are updating the object */
    1231 |   if(do_query){
    1232 |    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    1233 |    sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1234 |    if(sql_err) result = ATTR_CREATE_ERR; else result = ATTR_CREATE_OK;
    1235 |   }
    1236 |
    1237 |  return(result);
    1238 |
    1239 | }/* create_attr() */
    1240 |
    1241 | /************************************************************
    1242 | * each_attribute_proces()                                   *
    1243 | *                                                           *
    1244 | * Main function that processes object attributes one by one.*
    1245 | * Called from g_slist_foreach() function.                   *
    1246 | * First it tries to insert an attribute.                    *
    1247 | * If an error it assumes that attribute is already in       *
    1248 | * a table and calls update_attr() to update it.             *
    1249 | * Queries for the attributes are defined in Insert[] array. *
    1250 | *                                                           *
    1251 | * Returns: Nothing. Error code is stored in tr->error.      *
    1252 | *                                                           *
    1253 | *************************************************************/
    1254 | static void each_attribute_process(void *element_data, void *tr_ptr)
    1255 | {
    1256 | int num;
    1257 | const char *query_fmt;
    1258 | int query_type;
    1259 | int do_query;
    1260 | const rpsl_attr_t *attribute = (const rpsl_attr_t *)element_data;
    1261 | Transaction_t *tr = (Transaction_t *)tr_ptr;
    1262 |
    1263 | int sq_info[3];
    1264 | int dummy_err;
    1265 | char *sq_error;
    1266 | ip_prefix_t dn_pref;
    1267 | int sql_err;
    1268 |
    1269 | int attribute_type;
    1270 | const gchar *attribute_value;
    1271 |
    1272 | int result;
    1273 |
    1274 | /* we still want to continue to collect all possible errors*/
    1275 |  /* To switch off querying for some types of attributes */
    1276 |   do_query=1;
    1277 |
    1278 |  /* Determine the query type */
    1279 |   attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    1280 |   query_type=DF_get_insert_query_type(attribute_type);
    1281 |
    1282 | /* For loading pass #1 we need to process only main tables */
    1283 |   if(tr->load_pass==1){
    1284 | 	switch(query_type) {
    1285 | 	 case UD_MAIN_:
    1286 | 	 case UD_MA_U2:
    1287 | 	 case UD_MA_PR:
    1288 | 	 case UD_MA_RT:
    1289 | 	 case UD_MA_IN:
    1290 | 	 case UD_MA_I6:
    1291 | 	 case UD_MA_OR:
    1292 | 	 case UD_MA_AK:
    1293 | 	 		break;
    1294 | 	 default:	return;	/* return for other than MAIN tables*/
    1295 | 	}
    1296 |   }
    1297 |
    1298 |     query_fmt = DF_get_insert_query(attribute_type);
    1299 |
    1300 | /* return if no query is defined for this attribute */
    1301 |   if (strcmp(query_fmt, "") == 0) return;
    1302 |
    1303 | /* Try to create an attribute in SQL database*/
    1304 |   result = create_attr(attribute, tr);
    1305 |
    1306 |
    1307 | /* The value is clean since the object is "flattened" */
    1308 |   attribute_value = rpsl_attr_get_value(attribute);
    1309 |
    1310 |   switch(result) {
    1311 |
    1312 |   case ATTR_CREATE_DONE:
    1313 |      /* no more processing required */
    1314 |      break;
    1315 |
    1316 |   case ATTR_CREATE_NO:
    1317 |      /* for object updates for primary keys go straight to updates */
    1318 |      /* most of the primary keys are just skipped */
    1319 |      /* secod keys are updated, also dummy flag is reset for sets, pn/ro, mt */
    1320 |      update_attr(attribute, tr);
    1321 |      break;
    1322 |
    1323 |
    1324 |   case ATTR_CREATE_ERR:
    1325 |      if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
    1326 |   	if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
    1327 |   		update_attr(attribute, tr);
    1328 |   	}
    1329 |      /* Otherwise this is a duplicate attribute, just ignore it */
    1330 |      /* In the future if we are more stringent, checks may be added here */
    1331 |      }
    1332 |      else { /* Other errors reveal a database/server problem*/
    1333 |         sq_error=SQ_error(tr->sql_connection);
    1334 |         tr->error|=ERROR_U_DBS;
    1335 |         tr->succeeded=0;
    1336 | 	ER_perror(FAC_UD, UD_BUG, "%s[%s]\n", sq_error, tr->query->str);
    1337 |         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attribute_type, attribute_value, sq_error);
    1338 | 	die;
    1339 |      }
    1340 |      break;
    1341 |
    1342 |   case ATTR_CREATE_OK:
    1343 |      /* If the query was successful */
    1344 |      num = SQ_get_affected_rows(tr->sql_connection);
    1345 |      if(num>0){ /* this is OK*/
    1346 |      /* Do some additional processing for member_of attribute  */
    1347 | 	if ((attribute_type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
    1348 | 		if(auth_member_of(attribute, tr)!=0){
    1349 | 		 tr->error|=ERROR_U_AUT;
    1350 | 		 tr->succeeded=0;
    1351 | 		 ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership not allowed [%d:%s]", tr->transaction_id, attribute_type, attribute_value);
    1352 | 		 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attribute_type, attribute_value);
    1353 | 		}
    1354 | 	}
    1355 | 	else
    1356 | 	  /* Do some additional processing for reverse zones domains */
    1357 | 	  if ((attribute_type == A_DN)
    1358 | 	      && IP_revd_a2b(&dn_pref, attribute_value)==IP_OK ) {
    1359 |
    1360 | 	    if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
    1361 | 		tr->error|=ERROR_U_DBS;
    1362 | 		tr->succeeded=0;
    1363 | 		ER_perror(FAC_UD, UD_SQL, "cannot insert inverse domain:[%d:%s]\n", attribute_type, attribute_value);
    1364 | 		die;
    1365 | 	    }
    1366 | 	    else {
    1367 | 	      /* save data for the radix tree update */
    1368 | 	      tr->action |= TA_UPD_RX;
    1369 | 	      RP_pack_set_revd(attribute_type, attribute_value, tr->packptr);
    1370 | 	    }
    1371 | 	  }
    1372 |      }
    1373 |      else { /* if num == 0 */
    1374 |      /* this could be an empty update or a null select */
    1375 |   	SQ_get_info(tr->sql_connection, sq_info);
    1376 |   	if (sq_info[SQL_DUPLICATES]>0) {
    1377 | 	/* INSERT ... SELECT ... affected 0 rows, but there is 1 duplicate */
    1378 | 	/* which means that we already have such record in the table */
    1379 | 	/* this indicates that this is actually an update - update this attribute */
    1380 |   		if (sq_info[SQL_DUPLICATES]>1) {
    1381 |   			tr->error|=ERROR_U_DBS;
    1382 |   			tr->succeeded=0;
    1383 | 			ER_perror(FAC_UD, UD_SQL, "too many duplicates:[%d:%s]\n", attribute_type, attribute_value);
    1384 |   			die;
    1385 |   		}
    1386 |   		update_attr(attribute, tr);
    1387 |   	}
    1388 |   	else {
    1389 | 	/* this is an emty SELECT because there is no referred object */
    1390 | 	/* try to create dummy and repeat the original query*/
    1391 |
    1392 | /*		ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s no ref. integrity. Trying to create dummy\n", UD_TAG);*/
    1393 |
    1394 | 		dummy_err = create_dummy(attribute, tr);
    1395 | 		if (dummy_err == 0) {
    1396 | 		/* Dummy was created */
    1397 | 			g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attribute_type, attribute_value);
    1398 | 			ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    1399 | 			sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1400 | 			num = SQ_get_affected_rows(tr->sql_connection);
    1401 | 			if (sql_err) {
    1402 | 			  sq_error=SQ_error(tr->sql_connection);
    1403 | 		          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, tr->query->str);
    1404 | 			  tr->error|=ERROR_U_DBS;
    1405 | 		          tr->succeeded=0;
    1406 | 		          g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
    1407 | 		                            ERROR_U_DBS, attribute_type, attribute_value, sq_error);
    1408 | 			  die;
    1409 | 		        }
    1410 | 		        if (num==0) {
    1411 | 			  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", tr->query->str);
    1412 | 			  tr->error|=ERROR_U_DBS;
    1413 | 			  tr->succeeded=0;
    1414 | 			  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
    1415 | 			                    ERROR_U_DBS, attribute_type, attribute_value);
    1416 | 			  die;
    1417 | 			}
    1418 | 		}
    1419 | 		else
    1420 | 		 if(dummy_err == 1) {
    1421 | 		 /* dummy not allowed */
    1422 | 		   tr->error |= ERROR_U_OBJ;
    1423 | 		   tr->succeeded=0;
    1424 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:ref integrity: reference cannot be resolved\n" ,
    1425 |                    ERROR_U_OBJ, attribute_type, attribute_value);
    1426 | 		   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy not allowed [%d:%s]", tr->transaction_id, attribute_type, attribute_value);
    1427 | 		 }
    1428 | 		 else {
    1429 | 		 /* SQL problem */
    1430 | 		   tr->error|=ERROR_U_DBS;
    1431 | 		   tr->succeeded=0;
    1432 | 		   ER_perror(FAC_UD, UD_SQL, "dummy cannot be created [%d:%s]", attribute_type, attribute_value);
    1433 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy cannot be created\n" ,ERROR_U_DBS, attribute_type, attribute_value);
    1434 | 		   die;
    1435 | 		}
    1436 |   	}  /* RI*/
    1437 |      }/* if num == 0*/
    1438 |      break;
    1439 |
    1440 |    default:
    1441 |      ER_perror(FAC_UD, UD_BUG, "unknown return code from create_attr()");
    1442 |      die;
    1443 |      break;
    1444 |    } /* switch result from create_attr() */
    1445 |
    1446 |   return;
    1447 | } /* each_attribute_process() */
    1448 |
    1449 |
    1450 | /************************************************************
    1451 | * ud_each_primary_key_select()                              *
    1452 | *                                                           *
    1453 | * Function that forms a query for an object (w prinary keys)*
    1454 | * Called from g_slist_foreach() function.                   *
    1455 | * Primary keys are defined in Select[] array.               *
    1456 | *                                                           *
    1457 | * Returns: Nothing.                                         *
    1458 | *                                                           *
    1459 | *************************************************************/
    1460 | void ud_each_primary_key_select(void *element_data, void *result_ptr)
    1461 | {
    1462 | const rpsl_attr_t *attribute = (const rpsl_attr_t *)element_data;
    1463 | Transaction_t *tr = (Transaction_t *)result_ptr;
    1464 | const char *query_fmt;
    1465 | unsigned int prefix, prefix_length;
    1466 | unsigned int begin_in, end_in;
    1467 | int begin_as, end_as;
    1468 | ip_prefix_t prefstr;
    1469 | ip_range_t  rangstr;
    1470 | ip_v6word_t i6_msb, i6_lsb;
    1471 |
    1472 | int attribute_type;
    1473 | const gchar * attribute_value;
    1474 | int do_query;
    1475 |
    1476 |    /* get type the attribute */
    1477 |    attribute_type = rpsl_get_attr_id(rpsl_attr_get_name(attribute));
    1478 |
    1479 |    query_fmt = DF_get_select_query(attribute_type);
    1480 |
    1481 |    /* For a 1/2 pass fill tr->K only (used in loader 1 pass) */
    1482 |    if (tr->load_pass == 1) do_query = 0; else do_query=1;
    1483 |
    1484 |
    1485 |   if (strcmp(query_fmt, "") != 0) {
    1486 |     /* get value of the attribute. It is already clean since the object is "flattened" */
    1487 |     attribute_value = rpsl_attr_get_value(attribute);
    1488 |
    1489 |     switch (DF_get_select_query_type(attribute_type)) {
    1490 |      case UD_MAIN_:
    1491 |      		if(do_query)g_string_sprintfa(tr->query, query_fmt, attribute_value);
    1492 | 		g_string_sprintfa(tr->K, attribute_value);
    1493 |     		break;
    1494 |      case UD_MA_RT:
    1495 |                 if(IP_pref_a2v4(attribute_value, &prefstr, &prefix, &prefix_length)==IP_OK){
    1496 |     		  if(do_query)g_string_sprintfa(tr->query, query_fmt, prefix, prefix_length);
    1497 |     		  g_string_sprintfa(tr->K, attribute_value);
    1498 |                 } else {
    1499 |                   tr->succeeded = 0;
    1500 |                   tr->error |= ERROR_U_OBJ;
    1501 |                   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong prefix specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1502 |                 }
    1503 |                 break;
    1504 |      case UD_MA_IN:
    1505 | 		if(IP_rang_a2v4(attribute_value, &rangstr, &begin_in, &end_in)==IP_OK){
    1506 | 		  if(do_query)g_string_sprintfa(tr->query, query_fmt, begin_in, end_in);
    1507 |     		  g_string_sprintfa(tr->K, attribute_value);
    1508 |                 } else {
    1509 |                   tr->succeeded = 0;
    1510 |                   tr->error |= ERROR_U_OBJ;
    1511 |                   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong range specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1512 |                 }
    1513 |                 break;
    1514 |      case UD_MA_I6:
    1515 |                 if(IP_pref_a2v6(attribute_value, &prefstr, &i6_msb, &i6_lsb, &prefix_length)==IP_OK){
    1516 | 		  if(do_query)g_string_sprintfa(tr->query, query_fmt, i6_msb, i6_lsb, prefix_length);
    1517 | 		  g_string_sprintfa(tr->K, attribute_value);
    1518 |                 } else {
    1519 |                   tr->succeeded = 0;
    1520 |                   tr->error |= ERROR_U_OBJ;
    1521 |                   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:wrong prefix specified\n", ERROR_U_OBJ, attribute_type, attribute_value);
    1522 |                 }
    1523 |     		break;
    1524 |      case UD_MA_AK:
    1525 |      		convert_as_range(attribute_value, &begin_as, &end_as);
    1526 |      		if(do_query)g_string_sprintfa(tr->query, query_fmt, begin_as, end_as);
    1527 | 		g_string_sprintfa(tr->K, attribute_value);
    1528 | 		break;
    1529 |      default:
    1530 | 		ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attribute_type, attribute_value);
    1531 |                 die;
    1532 |
    1533 |     	break;
    1534 |     }
    1535 |   }
    1536 | }
    1537 |
    1538 | /************************************************************
    1539 | * perform_create(const Object_t *obj, Transaction_t *tr)    *
    1540 | *                                                           *
    1541 | * Procedure for creating a new object.                      *
    1542 | * First inserts object into 'last' table and gets object_id.*
    1543 | * Then processes all attributes.                            *
    1544 | *                                                           *
    1545 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1546 | * Error code is stored in tr->error.                        *
    1547 | *                                                           *
    1548 | *************************************************************/
    1549 | static int perform_create(Transaction_t *tr)
    1550 | {
    1551 |  long timestamp;
    1552 |  int sql_err;
    1553 |
    1554 |       timestamp=time(NULL);
    1555 |       tr->sequence_id=1; /* we start with 1*/
    1556 |   /* Calculate the object_id - should be max+1 */
    1557 |   /* XXX we cannot use autoincrement with MyISAM tables */
    1558 |   /* XXX because they keep the max inserted id even if  */
    1559 |   /* XXX it was deleted later, thus causing gaps we don't want */
    1560 |
    1561 |       tr->object_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1;
    1562 |       TR_update_id(tr);
    1563 |
    1564 |       g_string_sprintf(tr->query, "INSERT INTO last SET thread_id=%d, object_id=%ld, "
    1565 |                               "timestamp=%ld, sequence_id=1, object_type=%d, object='%s', pkey='%s' ",
    1566 |       	              tr->thread_ins, tr->object_id, timestamp, tr->class_type, tr->object_txt, tr->K->str);
    1567 |
    1568 |       ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    1569 |       sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1570 |
    1571 |      /* Check for affected rows. One row should be affected . */
    1572 |       if (sql_err) {
    1573 |         tr->error|=ERROR_U_DBS;
    1574 |         tr->succeeded=0;
    1575 | 	ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    1576 | 	die;
    1577 |       }
    1578 |       else {
    1579 |         g_list_foreach((GList *)rpsl_object_get_all_attr(tr->object), each_attribute_process, tr);
    1580 |       }
    1581 |
    1582 |  return(tr->succeeded);
    1583 | } /* perform_create() */
    1584 |
    1585 | /************************************************************
    1586 | * perform_update(Transaction_t *tr)                         *
    1587 | *                                                           *
    1588 | * Procedure for updating (existing) object.                 *
    1589 | * First processes all attributes.                           *
    1590 | * Then saves previous object in 'history' and updates       *
    1591 | * 'last' table.                                             *
    1592 | *                                                           *
    1593 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1594 | * Error code is stored in tr->error.                        *
    1595 | *                                                           *
    1596 | *************************************************************/
    1597 | static int perform_update(Transaction_t *tr)
    1598 | {
    1599 | int num;
    1600 | long sequence_id;
    1601 | long timestamp;
    1602 | char *sq_error;
    1603 | int sql_err;
    1604 |
    1605 |    /* get sequence number */
    1606 |    sequence_id = get_sequence_id(tr);
    1607 |    if(sequence_id==-1) {
    1608 |       tr->error|=ERROR_U_DBS;
    1609 |       tr->succeeded=0;
    1610 |       ER_perror(FAC_UD, UD_SQL, "cannot get sequence_id");
    1611 |       die;
    1612 |    }
    1613 |    else tr->sequence_id=sequence_id; /* save it for rollback*/
    1614 |    /* Update TR record */
    1615 |    TR_update_id(tr);
    1616 |
    1617 |    /* GET a timestamp */
    1618 |    timestamp=time(NULL);
    1619 |
    1620 |
    1621 |
    1622 |   /* process each attribute one by one */
    1623 |   g_list_foreach((GList *)rpsl_object_get_all_attr(tr->object), each_attribute_process, tr);
    1624 |
    1625 |   /* If we've already failed or this is 2-pass load - just return */
    1626 |   if((tr->succeeded == 0) || (tr->load_pass == 1) || (tr->load_pass == 2)) return(tr->succeeded);
    1627 |
    1628 | /*XXX */
    1629 |   if(IS_STANDALONE(tr->mode)){
    1630 |       g_string_sprintf(tr->query, "REPLACE last "
    1631 |                    "SET thread_id=%d, object_id=%ld, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s', pkey='%s' ",
    1632 |                    tr->thread_ins, tr->object_id, tr->sequence_id, timestamp, tr->class_type, tr->object_txt, tr->K->str);
    1633 |   }else
    1634 |   {
    1635 |     /* No return: thread_id=0 */
    1636 |     /* Do it only if previous transactions finished well */
    1637 |     /* copy object to the history table */
    1638 |     g_string_sprintf(tr->query,"INSERT history "
    1639 |                   "SELECT %d, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
    1640 |                   "FROM last "
    1641 |                   "WHERE object_id=%ld ", tr->thread_ins, tr->object_id);
    1642 |   }
    1643 |
    1644 |
    1645 |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    1646 |     sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1647 |
    1648 |    /* Check for affected rows. One row should be affected . */
    1649 |     num = SQ_get_affected_rows(tr->sql_connection);
    1650 |     if (num < 1) {
    1651 |          tr->error|=ERROR_U_DBS;
    1652 |          tr->succeeded=0;
    1653 |          if (sql_err) {
    1654 |           sq_error=SQ_error(tr->sql_connection);
    1655 | 	  ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    1656 | 	  die;
    1657 |          }
    1658 |          else {
    1659 | 	  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", tr->query->str);
    1660 | 	/* This is to check that this really could happen */
    1661 | 	  die;
    1662 |          }
    1663 |          return(tr->succeeded);
    1664 |     }
    1665 |
    1666 |
    1667 |   if(IS_STANDALONE(tr->mode)){
    1668 |   /* for pn, mt, rs, as update dummy field */
    1669 |
    1670 |    if((tr->class_type==C_PN)  || (tr->class_type==C_RO)){
    1671 |     /* this table has object_type field which is set to 100 for dummies - need to update too */
    1672 |          g_string_sprintf(tr->query, "UPDATE %s SET thread_id=0, object_type=%d, dummy=0 WHERE object_id=%ld ",
    1673 |                                       DF_get_class_sql_table(tr->class_type), tr->class_type, tr->object_id);
    1674 |    }else if((tr->class_type==C_AS)  || (tr->class_type==C_RS) ||
    1675 |             (tr->class_type==C_MT)  || (tr->class_type==C_IT)){
    1676 |          g_string_sprintf(tr->query, "UPDATE %s SET thread_id=0, dummy=0 WHERE object_id=%ld ",
    1677 |                                       DF_get_class_sql_table(tr->class_type), tr->object_id);
    1678 |    }
    1679 |    sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1680 |    if (sql_err) {
    1681 |        sq_error=SQ_error(tr->sql_connection);
    1682 |        ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    1683 |        die;
    1684 |    }
    1685 |   }
    1686 |   else {
    1687 |     /* Insert new version into the last */
    1688 |
    1689 | /* update last for commit/rollback */
    1690 |
    1691 |     g_string_sprintf(tr->query, "INSERT last "
    1692 |                    "SET thread_id=%d, object_id=%ld, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s', pkey='%s' ",
    1693 |                    tr->thread_ins, tr->object_id, tr->sequence_id+1, timestamp, tr->class_type, tr->object_txt, tr->K->str);
    1694 |
    1695 |
    1696 |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    1697 |     sql_err = SQ_execute_query(tr->sql_connection, tr->query->str, (SQ_result_set_t **)NULL);
    1698 |
    1699 |     /* Check for affected rows. One row should be affected */
    1700 |     num = SQ_get_affected_rows(tr->sql_connection);
    1701 |     if (num < 1) {
    1702 |          tr->error|=ERROR_U_DBS;
    1703 |          tr->succeeded=0;
    1704 |          if(sql_err) {
    1705 |           g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
    1706 | 	  ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    1707 | 	  die;
    1708 |          }
    1709 |          else {
    1710 | 	  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", tr->query->str);
    1711 | 	  /* This is to check that this is really could happen */
    1712 | 	  die;
    1713 |          }
    1714 |     }
    1715 |   }
    1716 |
    1717 |
    1718 |  return(tr->succeeded);
    1719 | } /* perform_update() */
    1720 |
    1721 |
    1722 |
    1723 |
    1724 | /************************************************************
    1725 | * int object_process(Transaction_t *tr)                     *
    1726 | *                                                           *
    1727 | * This is the interface between core and upper layer        *
    1728 | * All it gets is Transaction *tr, which contains all        *
    1729 | * necessary information, including the object in its        *
    1730 | * internal representation.                                  *
    1731 | *                                                           *
    1732 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1733 | * Error code is stored in tr->error.                        *
    1734 | *                                                           *
    1735 | *************************************************************/
    1736 | int object_process(Transaction_t *tr)
    1737 | {
    1738 | int res;
    1739 | char *nic;
    1740 | int commit_now;
    1741 |
    1742 |
    1743 |  /* for loader we do not perform commits/rollbacks */
    1744 |   if(IS_STANDALONE(tr->mode))commit_now = 1; else commit_now = 0;
    1745 |
    1746 |    /* create and initialize TR record for crash recovery */
    1747 |    TR_create_record(tr);
    1748 |
    1749 |    if(ACT_DELETE(tr->action)){
    1750 | 	 	ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: delete", UD_TAG);
    1751 | 		/* check referential integrity of deletion */
    1752 | 		UD_check_ref(tr);
    1753 | 	        /* for person & role - free the nic-handle in the NHR */
    1754 |                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
    1755 |       	         res = NH_free(tr->nh, tr->sql_connection, commit_now);
    1756 |
    1757 | 		 if(res == -1) {
    1758 | 		   tr->succeeded=0;
    1759 | 		   tr->error |= ERROR_U_DBS;
    1760 | 		   ER_perror(FAC_UD, UD_SQL, "cannot delete nic handle");
    1761 | 		   die;
    1762 | 	         }
    1763 | 		 else if(res == 0) {
    1764 | 		   tr->succeeded=0;
    1765 | 		   tr->error |= ERROR_U_OBJ;
    1766 | 		   ER_perror(FAC_UD, UD_SQL, "nic handle not found");
    1767 | 		   die;
    1768 | 	         }
    1769 | 	        }
    1770 | 		/* if everything is Ok we are ready to commit */
    1771 | 		if (tr->succeeded){
    1772 | 		 /* update object_id and sequence_id fields */
    1773 |                  tr->sequence_id = get_sequence_id(tr);
    1774 |                  if(tr->sequence_id==-1) {
    1775 |                    tr->error|=ERROR_U_DBS;
    1776 |                    tr->succeeded=0;
    1777 |                    ER_perror(FAC_UD, UD_SQL, "cannot get sequence_id");
    1778 |                    die;
    1779 |                  }
    1780 |
    1781 | 		 TR_update_id(tr);
    1782 |
    1783 | 		 /* checkpoint the TR  - we are going to commit*/
    1784 | 		 CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);
    1785 |
    1786 | 		 /* send an ack */
    1787 | 		 UD_ack(tr);
    1788 |
    1789 | 		 /* delete the object and checkpoint it*/
    1790 | 	 	 UD_delete(tr);
    1791 | 		 UD_update_rx(tr, RX_OPER_DEL);
    1792 |
    1793 |                  /* we need to update sequence_id because it was changed during update */
    1794 | 		 CP_DELETE_PASSED(tr->action); TR_update_id(tr); TR_update_status(tr);
    1795 |
    1796 | 		 /* Commit nic-handle deletion to the repository */
    1797 |                  NH_commit(tr->sql_connection);
    1798 |
    1799 | 		 CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
    1800 |
    1801 | 		}
    1802 | 		else { /* just send an ack */
    1803 | 		 UD_ack(tr);
    1804 | 		}
    1805 | 		return(tr->succeeded); /*commit is not needed*/
    1806 |     }
    1807 |     else if(ACT_UPDATE(tr->action)){
    1808 | 	 	ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: update\n", UD_TAG);
    1809 | 	 	perform_update(tr);
    1810 |
    1811 |     }
    1812 |     else if(ACT_CREATE(tr->action)){
    1813 | 	 	ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s object: create", UD_TAG);
    1814 | 	 	perform_create(tr);
    1815 |
    1816 | 		/* Commit nic-handle allocation (if any) to the repository */
    1817 |                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
    1818 |                  /* convert nh to DB nIC handle before registration */
    1819 |       	         nic = NH_convert(tr->nh);
    1820 |
    1821 | 		 if(nic==NULL){
    1822 | 		  res=0;
    1823 | 		  nic="N/A";
    1824 | 		 }
    1825 | 		 else res = NH_register(tr->nh, tr->sql_connection, commit_now);
    1826 |
    1827 | 		 if(res == -1) {
    1828 | 		  tr->succeeded=0;
    1829 | 		  tr->error |= ERROR_U_DBS;
    1830 | 		  ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle");
    1831 | 		  die;
    1832 | 	         }
    1833 | 		 else if(res == 0) {
    1834 | 		  tr->succeeded=0;
    1835 | 		  tr->error |= ERROR_U_OBJ;
    1836 | 		  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] nic handle [%s] wrong or already in use", tr->transaction_id, nic);
    1837 | 		  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle wrong or already in use\n", ERROR_U_OBJ, A_NH, nic);
    1838 | 	         }
    1839 | 	         else { /* copy the NH to the report to return to DBupdate */
    1840 | 	          g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
    1841 | 		  UT_free(nic);
    1842 | 	         }
    1843 |                 }
    1844 |
    1845 |      }
    1846 |      else {
    1847 | 	 	ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: unknown action", tr->transaction_id);
    1848 | 	 	tr->succeeded=0;
    1849 | 	 	tr->error|=ERROR_U_BADOP;
    1850 | 	 	return(tr->succeeded);
    1851 |      }
    1852 |
    1853 |    if(!IS_STANDALONE(tr->mode)) { /* not for loader*/
    1854 |       /* update object_id and sequence_id fields */
    1855 |       TR_update_id(tr);
    1856 |
    1857 |       if (tr->succeeded) {
    1858 |         /* checkpoint the TR  - we are going to commit*/
    1859 | 	CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);
    1860 |
    1861 | 	/* send an ack */
    1862 |         UD_ack(tr);
    1863 |         /* commit the transaction and checkpoint it */
    1864 |
    1865 |         UD_commit(tr);
    1866 | 	/* Commit nic-handle modifications to the repository */
    1867 |
    1868 |         NH_commit(tr->sql_connection);
    1869 |
    1870 | 	CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
    1871 | 	/* TR will be marked as clean in UD_create_serial() */
    1872 |       }
    1873 |       else {
    1874 |         /* send an ack */
    1875 |         UD_ack(tr);
    1876 |         UD_rollback(tr);
    1877 |
    1878 | 	CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr);
    1879 |
    1880 | 	/* rollback nic-handle modifications to the repository */
    1881 |         NH_rollback(tr->sql_connection);
    1882 |
    1883 |
    1884 | 	CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr);
    1885 | 	/* Delete TR record if in update mode. Next time (if any) DBupdate tries to submit, we'll start from scratch */
    1886 | 	/* In NRTM mode we create serial anyway, so the record will be deleted  */
    1887 | 	/* after serial is created TR record will be deleted in */
    1888 |
    1889 |       }
    1890 |     }
    1891 |  return(tr->succeeded);
    1892 | } /* object_process() */
    1893 |