modules/ud/ud_core.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. convert_if
  2. convert_rf
  3. convert_as
  4. convert_as_range
  5. convert_time
  6. get_set_name
  7. get_object_id
  8. get_qresult_str
  9. get_field_str
  10. get_sequence_id
  11. get_ref_id
  12. isdummy
  13. isnichandle
  14. process_reverse_domain
  15. insert_reverse_domain
  16. update_reverse_domain
  17. auth_member_of
  18. create_dummy
  19. update_attr
  20. each_attribute_process
  21. each_primary_key_select
  22. perform_create
  23. perform_update
  24. object_process

   1 /***************************************
   2   
   3   $Revision: 1.27 $
   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                              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 #include "ud.h"
  35 #include "ud_int.h"
  36 
  37 static int perform_update(Transaction_t *tr);
  38 
  39 static int perform_create(Transaction_t *tr);
  40 
  41 static void each_primary_key_select(void *element_data, void *result_ptr);
  42 
  43 static void each_attribute_process(void *element_data, void *tr_ptr);
  44 
  45 static void update_attr(Attribute_t *attr, Transaction_t *tr);
  46 
  47 static int create_dummy(Attribute_t *attr, Transaction_t *tr);
  48 
  49 static int auth_member_of(Attribute_t *attr, Transaction_t *tr);
  50 
  51 /***************************************************
  52 * char *s_split(char *line)                        *
  53 *                                                  *
  54 * Consequently returns words of the 'line'         * 
  55 * When there are no words it returns NULL          *
  56 * You need to retreive all words !                 *
  57 *                                                  *
  58 * NB This function damages 'line' replacing        *
  59 * whitespace with '\0'                             *
  60 * *************************************************/
  61 #define ATTR_DELIMITERS " ,"
  62 
  63 
  64 /**********************************************************
  65 * Attribute expansion/conversion functions                *
  66 ***********************************************************/
  67 /* Convert ifaddr attribute into numbers */
  68 er_ret_t convert_if(char *avalue, unsigned int *pif_address)
     /* [<][>][^][v][top][bottom][index][help] */
  69 {
  70 char *delim;
  71 ip_addr_t ip_addr;
  72 er_ret_t ret;
  73 
  74   if ((delim=index(avalue, ' '))!=NULL) *delim='\0';
  75   ret=IP_addr_a2v4(avalue, &ip_addr,  pif_address );
  76   return(ret);
  77 }
  78 
  79 
  80 /* Convert refer attribute. Free host after use ! */
  81 char *convert_rf(char *avalue, int *type, int *port)
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83 char *delim, *token;
  84 char buff[STR_M];
  85 char *host;
  86 
  87   host=NULL;
  88   strcpy(buff, avalue);
  89   g_strchug(buff);
  90   delim=index(buff, ' ');
  91   *delim='\0';
  92   delim++; 
  93 
  94 /* convert the type      */
  95   if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE;
  96    else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
  97     else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;
  98      else if(strcmp(buff, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS;
  99 
 100   token=delim;
 101   g_strchug(token);
 102   delim=index(token, ' ');
 103   if(delim){
 104    *delim='\0';
 105    delim++; 
 106   }           
 107 /* convert the hostname      */
 108   host = g_strdup(token);
 109       
 110 /* convert port number      */
 111   if(delim){
 112     token=delim;        
 113     *port = atoi(token);
 114     if (*port==0) *port=RF_DEF_PORT; /* default port number*/
 115   } else *port=RF_DEF_PORT;
 116   return(host);
 117 }
 118 
 119 
 120 /* Convert AS# into integer */
 121 static int convert_as(char *as)
     /* [<][>][^][v][top][bottom][index][help] */
 122 {
 123 char *ptr;
 124  ptr=as; ptr++; ptr++; 
 125  return(atoi(ptr));   
 126 }
 127 
 128 /* Convert AS range (AS4321 - AS5672) into numbers */
 129 int convert_as_range(const char *as_range, int *begin, int *end)
     /* [<][>][^][v][top][bottom][index][help] */
 130 {
 131 char *range;
 132 char *token=as_range;
 133   
 134   range=g_strdup(as_range);
 135   token=range;
 136   *begin=convert_as(strsep(&token, " -"));
 137   *end=convert_as(strsep(&token, " -"));
 138   free(range);
 139   return(0);
 140 }
 141 
 142 /* Convert time in ASCII format (19991224) into time_t unix time */
 143 time_t convert_time(char *asc_time)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145 struct tm tm;
 146 char buf[STR_S];
 147 char *ptr;
 148 
 149   
 150   bzero(&tm, sizeof(tm));
 151   
 152   strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
 153   tm.tm_year = atoi(buf) - 1900;
 154   
 155   strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
 156   tm.tm_mon = atoi(buf) - 1;
 157   
 158   strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
 159   tm.tm_mday = atoi(buf);
 160   
 161   return(mktime(&tm));
 162 
 163 }     
 164 
 165 
 166 /************************************************************
 167 *  char *get_set_name()                                     *
 168 *                                                           *
 169 * Returns set name for the specified object class           *
 170 *                                                           *
 171 * **********************************************************/
 172 static char *get_set_name(C_Type_t class_type)
     /* [<][>][^][v][top][bottom][index][help] */
 173 {
 174  switch(class_type){
 175   case C_RT:   return("route_set");
 176   case C_AN:   return("as_set");
 177   default:     return(NULL);
 178  }
 179 }
 180 
 181 
 182 /************************************************************
 183 * long get_object_id()                                      *
 184 * Queries the database for an object.                       *
 185 * For constructing a query uses each_primary_key_select()   *
 186 *                                                           *
 187 * Returns:                                                  *
 188 * >0 - object exists, returns object_id                     *
 189 * 0  - object does not exist                                *
 190 * -1 - error (f.e. more than one object with the same PK)   *
 191 * Error code is stored in tr->error                         *
 192 *                                                           *
 193 * **********************************************************/
 194 long get_object_id(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 195 {
 196 Object_t *obj;
 197 SQ_result_set_t *sql_result;
 198 SQ_row_t *sql_row;
 199 char *sql_str;
 200 GString *query;
 201 long object_id=0;
 202 int sql_err;
 203 
 204  obj=tr->object;
 205 
 206  if ((query = g_string_sized_new(STR_XL)) == NULL){ 
 207   fprintf(stderr, "E: cannot allocate gstring\n"); 
 208   tr->succeeded=0;
 209   tr->error |= ERROR_U_MEM;
 210   die; 
 211  }
 212  
 213 /* compose query */
 214  g_string_sprintf(query, "SELECT object_id FROM %s WHERE",DF_get_class_sql_table(obj->type));
 215  /* add all primary keys */ 
 216  g_slist_foreach(obj->attributes, each_primary_key_select, query);
 217  /* truncate the last ' AND '*/
 218  g_string_truncate(query, (query->len) - 4); 
 219         
 220 /* execute query */
 221  sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
 222  g_string_free(query, TRUE);
 223  
 224 /* in case of an error copy error code and return */ 
 225  if(sql_err) {
 226    fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
 227    tr->succeeded=0;
 228    tr->error |= ERROR_U_DBS;
 229    die;
 230  }
 231 
 232 /* Fetch the row */ 
 233  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 234 /* Object exists */
 235 #define OBJECT_ID 0
 236    sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
 237    if (sql_str != NULL) {
 238      object_id = atol(sql_str);
 239      free(sql_str);
 240    }
 241 
 242 /* We must process all the rows of the result */
 243 /* otherwise we'll have them as part of the next qry */      
 244    while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
 245  } else 
 246       object_id=0;  /* object does not exist*/
 247    
 248  SQ_free_result(sql_result);
 249  return(object_id);
 250 }
 251 
 252 
 253 /************************************************************
 254 * get_qresult_str()                                         *
 255 *                                                           *
 256 * Returns string containing query result                    *
 257 *                                                           *
 258 *                                                           *
 259 * Returns:                                                  *
 260 *  String containing the result.Needs to be freed after use *
 261 *  NULL in case of an error                                 *
 262 *  - SQL error                                              *
 263 *  - if query returns more than one string (row)            *
 264 *                                                           *
 265 *************************************************************/
 266 char *get_qresult_str(SQ_connection_t *sql_connection, char *query)
     /* [<][>][^][v][top][bottom][index][help] */
 267 {
 268 SQ_result_set_t *sql_result;
 269 SQ_row_t *sql_row;
 270 char *sql_str;
 271 int sql_err;
 272 
 273 
 274 /*fprintf(stderr, "D:<get_field_str>:query: %s\n", query);*/
 275  sql_err=SQ_execute_query(sql_connection, query, &sql_result);
 276  
 277  if(sql_err) {
 278     fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
 279     die;
 280  }
 281         
 282          
 283  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 284         sql_str = SQ_get_column_string(sql_result, sql_row, 0);
 285 
 286      /* We must process all the rows of the result,*/
 287      /* otherwise we'll have them as part of the next qry */
 288         while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
 289           fprintf(stderr, "E:<get_field_str> error : Dupl PK[%s]\n", query);
 290           if(sql_str)free(sql_str); sql_str=NULL;
 291         }
 292  }
 293  else sql_str=NULL;
 294  
 295  SQ_free_result(sql_result);
 296  return(sql_str);
 297 }
 298 
 299 
 300 
 301 /************************************************************
 302 * get_field_str()                                           *
 303 *                                                           *
 304 * Returns string containing the field.                      *
 305 *  field - field name to be retrieved                       *
 306 *  ref_tbl_name - name of the table containing the field    *
 307 *  ref_name - reference name                                *
 308 *  attr_value - reference value                             *
 309 *  condition - additional condition ( f.e. 'AND dummy=0'    *
 310 *                                                           *
 311 * Returns:                                                  *
 312 *  String containing the field. Needs to be freed after use *
 313 *  NULL in case of an error                                 *
 314 *                                                           *
 315 *************************************************************/
 316 char *get_field_str(SQ_connection_t *sql_connection, char *field, 
     /* [<][>][^][v][top][bottom][index][help] */
 317                            char *ref_tbl_name, char *ref_name, 
 318                            char * attr_value, char *condition)
 319 {
 320 char query[STR_L];
 321 
 322  sprintf(query, "SELECT %s FROM %s "
 323                 "WHERE %s='%s' ",
 324                 field, ref_tbl_name, ref_name, attr_value);
 325  if (condition)strcat(query, condition);
 326 
 327  return( get_qresult_str(sql_connection, query));
 328 
 329 } 
 330 
 331 /************************************************************
 332 * long get_sequence_id(Transaction_t *tr)
 333 * >0 - success
 334 * -1 - sql error
 335 *
 336 * **********************************************************/
 337 
 338 long get_sequence_id(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 339 {
 340 char *sql_str;
 341 char str_id[STR_M];
 342 long sequence_id=-1;
 343 
 344 
 345   sprintf(str_id, "%ld", tr->object_id);
 346   sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL);
 347   if(sql_str) {
 348           sequence_id = atol(sql_str);
 349 /*                fprintf(stderr, "D: Retrieved set serial id = %ld\n", sequence_id);*/
 350           free(sql_str);
 351   }
 352   
 353   return(sequence_id);
 354 
 355 }
 356 
 357 
 358 /************************************************************
 359 * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
 360 * >0 - success
 361 * -1 - sql error
 362 *
 363 * **********************************************************/
 364 
 365 static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition)
     /* [<][>][^][v][top][bottom][index][help] */
 366 {
 367 char *sql_str;
 368 long ref_id=-1;
 369 
 370 /*fprintf(stderr, "D:<get_ref_id>: entering...\n");*/
 371 
 372         sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition);
 373         if(sql_str) {
 374                  ref_id = atol(sql_str);
 375 /*               fprintf(stderr, "D: Retrieved set serial id = %ld\n", ref_id);*/
 376                  free(sql_str);
 377         }
 378         return(ref_id); 
 379 }
 380 
 381 
 382 /************************************************************
 383 * int isdummy()
 384 *
 385 * Returns 1 if the object in question is a dummy, 
 386 * otherwise returns 0.
 387 * 
 388 * In case of error:
 389 * -1 - sql error or object does not exist
 390 *
 391 ***********************************************************/
 392 
 393 int isdummy(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 394 {
 395 char *sql_str;
 396 char str_id[STR_M];
 397 int object_type=-1;
 398 
 399   sprintf(str_id, "%ld", tr->object_id);
 400   sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL);
 401   if(sql_str) {
 402           object_type = atoi(sql_str);
 403           free(sql_str);
 404   }
 405   
 406   if (object_type==-1) die;
 407   if (object_type==DUMMY_TYPE) return(1);
 408   else return(0);
 409 
 410 }
 411 
 412 /* it may be either a legacy name reference, or a nic-handle  */
 413 /* we rely on other parsers/syntax checkers, so no surprises  */
 414 /* thus, the check is simple - if there is a space - not a nh */
 415 static int isnichandle(char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 416 {
 417  if(index(name, ' ')) return(0);
 418  else return(1);        
 419 /* return(MA_isset(WK_new(name), WK_NIC_HDL)); */
 420 }
 421 
 422 
 423 /************************************************************
 424 * process_reverse_domain()                                  *
 425 *                                                           *
 426 * Tries to insert additional data for reverse domains       *
 427 * This data includes prefix and perfix length for reverse   *
 428 * delegation block. It is stored in inaddr_arpa table for   *
 429 * IPv4 and ip6int table for IPv6 address spaces             *
 430 *                                                           *
 431 * Returns:                                                  *
 432 * 0  success                                                *
 433 * -1 sql error                                              *
 434 *                                                           *
 435 *************************************************************/
 436 
 437 static int process_reverse_domain(Transaction_t *tr, 
     /* [<][>][^][v][top][bottom][index][help] */
 438                                   ip_prefix_t *prefptr,
 439                                   int op)
 440 {
 441   unsigned prefix, prefix_length; /* ipv4 */
 442   ip_v6word_t high, low;          /* ipv6 */
 443   char query[STR_L];
 444   int num;
 445   int sql_err;
 446 
 447                                   
 448   if( IP_pref_b2_space(prefptr) == IP_V4 ) {  /* ipv4 */
 449     if(op==0) { /* insert record */
 450       IP_revd_b2v4(prefptr, &prefix, &prefix_length);
 451       sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ", 
 452               tr->thread_ins, tr->object_id, prefix, prefix_length);
 453     }
 454     else {
 455       /* update record */
 456       sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ", 
 457               tr->thread_upd, tr->object_id);
 458     }
 459   }
 460   else { /* ipv6 */
 461     if(op==0) { /* insert record */   
 462       IP_revd_b2v6(prefptr, &high, &low, &prefix_length);
 463       sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, high=%llu, low=%llu, prefix_length=%d ", 
 464               tr->thread_ins, tr->object_id, high, low, prefix_length);
 465     }
 466     else {
 467       /* update record */
 468       sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ", 
 469               tr->thread_upd, tr->object_id);
 470     }
 471   }
 472 
 473   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 474   num = mysql_affected_rows(tr->sql_connection); 
 475   
 476   /* Check for errors */
 477   if (sql_err) {
 478    fprintf(stderr, "E: insert inaddr:%s[%s]\n", SQ_error(tr->sql_connection), query);
 479    die;
 480   }
 481   /* If nothing was affected then WHERE clause returned nothing - DB error */
 482   if(num == 0) {
 483    fprintf(stderr, "E: insert inaddr:no effect [%s]\n", query);
 484    die;
 485   }       
 486   return(0);
 487 }
 488 
 489 #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0)
     /* [<][>][^][v][top][bottom][index][help] */
 490 #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
     /* [<][>][^][v][top][bottom][index][help] */
 491 
 492 
 493 /************************************************************
 494 * auth_member_of()                                          *
 495 *                                                           *
 496 * Function that checks the authorization for membership     *
 497 * (i.e. if the object is authorized to be a memeber by      *
 498 * mbrs-by-ref attribute of the set is refers by member-of   *
 499 * attribute).                                               *
 500 * First checks if 'mbrs-by-ref: ANY'                        *
 501 * If not then checks that maintner referenced by            *
 502 * mbrs-by-ref attribute of the set is the one in mnt-by.    *
 503 *                                                           *
 504 * Returns:                                                  *
 505 * 0  success                                                *
 506 * 1  not allowed                                            *
 507 * -1 SQL error                                              *  
 508 *                                                           *
 509 *************************************************************/
 510 static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 511 {
 512 GString *query;
 513 char *set_name;
 514 char *qresult;
 515 
 516 /* Check if set has mbrs_by_ref==ANY 
 517    In such case mbrs_by_ref.mnt_id==0 
 518 */
 519 
 520  if ((query = g_string_sized_new(STR_XL)) == NULL){
 521   tr->succeeded=0;
 522   tr->error |= ERROR_U_MEM; 
 523   fprintf(stderr, "E: cannot allocate gstring\n"); 
 524   die; 
 525  }
 526  
 527  set_name = get_set_name(tr->class_type);
 528 /* fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name); */
 529 
 530 /* Check if the set protects itself with mbrs-by-ref attribute */
 531    g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s "
 532                           "WHERE mbrs_by_ref.object_id=%s.object_id "
 533                           "AND %s.%s='%s' ",
 534                           set_name, set_name, set_name, set_name, attr->value);
 535 
 536    qresult = get_qresult_str(tr->sql_connection, query->str);
 537    /* should be '0' if there is no mbrs-by-ref attribute */
 538    if (strcmp(qresult, "0")==0){
 539            /* there is no mbrs-by-ref attribute - so we cannot go ahead */
 540            fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n",query->str);
 541            g_string_free(query, TRUE);
 542            return(1);
 543    }
 544    else free(qresult);
 545 
 546 /* Check if membership is protected by the keyword "ANY" */
 547 /* There is a dummy mntmer object in the database corresponding to "ANY" */
 548 /* Its object_id==0 */
 549 /* EXAMPLE:
 550 
 551    SELECT route_set.object_id 
 552    FROM   mbrs_by_ref, route_set
 553    WHERE  mbrs_by_ref.object_id=route_set.object_id
 554    AND    route_set.route_set=<setname>
 555    AND    mbrs_by_ref.mnt_id=0
 556 */   
 557     g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
 558                            "WHERE mbrs_by_ref.object_id=%s.object_id "
 559                            "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 
 560                            set_name, set_name, set_name, set_name, set_name, attr->value);
 561 /* fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);*/
 562   
 563     qresult = get_qresult_str(tr->sql_connection, query->str);
 564   /* if such record exists - go ahead */
 565     if(qresult) {
 566         free(qresult);  
 567         g_string_free(query, TRUE);
 568         return(0);  
 569     }
 570 
 571 /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */
 572 /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */
 573     g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by "
 574                             "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
 575                             "AND mnt_by.object_id=%ld "
 576                             "AND %s.object_id=mbrs_by_ref.object_id "
 577                             "AND %s.%s='%s' "
 578                             "AND mnt_by.thread_id!=0 ",
 579                             tr->object_id, set_name, set_name, set_name, attr->value);
 580 
 581 /*  fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);                                             */
 582 
 583     qresult = get_qresult_str(tr->sql_connection, query->str);
 584     /* If our mntner is listed (non-empty result)  membership is authorized */
 585     if (qresult) {
 586          free(qresult);g_string_free(query, TRUE);
 587          return(0);
 588     } else {
 589          fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str);
 590          g_string_free(query, TRUE);
 591          return(1);
 592     }
 593  }/* auth_member_of()  */
 594         
 595 
 596 /************************************************************
 597 * create_dummy()                                            *
 598 *                                                           *
 599 * Function that creates a dummy object (that is one that    *
 600 * is referenced from an object but does not                 *
 601 * exist in the database).                                   *
 602 * Dummy object exists only in relevant main and 'last'      *
 603 * tables. Its creation is controlled by tr->dummy_allowed.  *
 604 * Queries for the dummies are defined in Dummy[] array.     *
 605 *                                                           *
 606 * Returns:                                                  *
 607 * 0  success                                                *
 608 * 1  no rf integrity and dummy not allowed                  *
 609 * -1 SQL error                                              *
 610 *                                                           *
 611 *************************************************************/
 612 static int create_dummy(Attribute_t *attr, Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 613 {
 614 const char *query_fmt;
 615 long dummy_id;
 616 char query[STR_L];
 617 int result=0;
 618 char *set_name;
 619 char *p_name;
 620 int query_type;
 621 long timestamp;
 622 char str_id[STR_M];
 623 gchar *attr_value=NULL;
 624 int sql_err;
 625 char *token=NULL;
 626 
 627   query_fmt = DF_get_dummy_query(attr->type);
 628   if (strcmp(query_fmt, "") == 0) { 
 629      fprintf(stderr, "E:<create_dummy>: empty query string\n"); 
 630      return(1); 
 631   }
 632   
 633   /* We allow creating dummy sets in any mode */
 634   /* For others attributes return if we are in protected mode */
 635   if ((attr->type!=A_MO) &&  (tr->dummy != 1)) return(1);
 636 
 637   /* Insert dummy in the last table */
 638   sprintf(str_id, "%ld", tr->object_id);
 639   timestamp=time(NULL);
 640   sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 
 641                   tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
 642 /* fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query);*/
 643   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 644   
 645   /* Check for errors */
 646   if (sql_err) {
 647    fprintf(stderr, "E: dummy->last:[%s]\n", query);
 648    die;
 649   }     
 650         
 651   /* insert dummy in the main table */
 652   dummy_id=mysql_insert_id(tr->sql_connection); 
 653   /* Record dummy's object_id, it'll be needed in commit/rollback */
 654   tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
 655   
 656   /* compose the query */
 657   query_type=DF_get_dummy_query_type(attr->type);
 658   switch (query_type) { 
 659          
 660          /* person_role */
 661          case UD_AX_PR:
 662               sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
 663               break;
 664          
 665          /* maintner */
 666          case UD_AX_MT: 
 667               sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
 668               break;
 669          
 670          /* as_set, route_set */
 671          case UD_AX_MO: 
 672               set_name = get_set_name(tr->class_type);
 673               sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);       
 674               break;
 675               
 676          default:
 677               fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type);
 678               die;
 679               break;
 680   }
 681         
 682   /*fprintf(stderr, "D: query: %s\n", query);*/
 683   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 684   /*fprintf(stderr, "D: query: %d rows affected\n", num);*/
 685   if (sql_err) {
 686    fprintf(stderr, "E: dummy->main:%s[%s]\n", SQ_error(tr->sql_connection), query);
 687    die;
 688   }
 689   
 690   /* for legacy person/role reference (without nic-handle) create records in names table */
 691   if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){
 692    /* parse the names */
 693     /*fprintf(stderr,"adding names for dummy\n");*/
 694     query_fmt = DF_get_insert_query(A_PN);
 695     attr_value = g_strdup(attr->value); 
 696     token = attr_value;
 697     while((p_name=strsep(&token, " "))){
 698                 sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
 699 /*              fprintf(stderr, "D: query: %s\n", query);*/
 700                 sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 701                 if (sql_err)
 702                  if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) {
 703                   fprintf(stderr, "E: insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query);
 704                   result=-1;
 705                  }
 706     }
 707     free(attr_value);
 708   }
 709  return(result);
 710 }
 711 
 712 /************************************************************
 713 * update_attr()                                             *
 714 *                                                           *
 715 * Function that updates an attribute if it already exists.  *
 716 * Called from each_attribute_proces() function if it        *
 717 * cannot insert the row.                                    *
 718 * Queries for the attributes are defined in Update[] array. *
 719 *                                                           *
 720 * Returns: Nothing. Error code is stored in tr->error.      *
 721 *                                                           *
 722 *************************************************************/
 723 static void update_attr(Attribute_t *attr, Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 724 {
 725 int num;
 726 const char *query_fmt;
 727 char *set_name;
 728 unsigned int if_address;
 729 char * rf_host;
 730 int rf_port, rf_type;
 731 char *a_value;
 732 int sq_info[3];
 733 char * condition;
 734 char *sq_error;
 735 char query[STR_XL];
 736 ip_prefix_t dn_pref;
 737 int sql_err;
 738 char *token;
 739 char *mu_mntner;
 740 
 741 
 742 /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */
 743  if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return;
 744 
 745 /*      fprintf(stderr, "D: updating attribute...\n");*/
 746 
 747    /* Do some additional processing for reverse domains */
 748    /* XXX Later we will implement this under UD_MA_DN case */
 749    if ((attr->type == A_DN) && (IP_revd_e2b(&dn_pref, attr->value)==IP_OK)) {
 750      if(update_reverse_domain(tr, &dn_pref) !=0 ){
 751        tr->error|=ERROR_U_DBS;
 752        tr->succeeded=0;
 753        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
 754                          ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection));   
 755      }
 756    }
 757    
 758 /*   query_fmt = Update[attr->type].qry; */
 759    query_fmt =  DF_get_update_query(attr->type);
 760 
 761    if (strcmp(query_fmt, "") == 0) return;
 762 
 763    switch (DF_get_update_query_type(attr->type)) {
 764          case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
 765                         break;
 766          case UD_MA_PR: 
 767                         sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
 768                         break;  
 769          case UD_MA_U2: /* save the new value of the attribute for commit*/
 770                   /* this is necessary for filter(filter-set), netname (inet?num), */
 771                   /* local-as(inet-rtr) attributes, as they are another field in the record */
 772                         if((tr->load_pass != 0)){
 773                       /* for fast loader we need to update the field as we have no commit */
 774                           sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id);
 775                         }
 776                         else {
 777                          tr->save=g_strdup(attr->value);
 778 /*                       fprintf(stderr, "ALLOCATED [%s]\n", tr->save); */
 779                          return;
 780                         }        
 781                         break;                  
 782          case UD_AX_PR:
 783                         /* This is for non-conformant admin-c, etc.*/
 784                         a_value=attr->value;
 785                         if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
 786                         
 787                         if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
 788                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 789                                 get_ref_id(tr, "person_role", "nic_hdl", attr->value, condition));
 790                         break;
 791          case UD_AX_MT: 
 792                         if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
 793                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 794                                 get_ref_id(tr, "mntner", "mntner", attr->value, condition));
 795                         break;
 796          case UD_AX_MU: /* for mnt_routes table*/
 797                         a_value=g_strdup(attr->value); 
 798                         token = a_value;
 799                         mu_mntner=strsep(&token, " ");
 800                         if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
 801                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 802                                 get_ref_id(tr, "mntner", "mntner", mu_mntner, condition));
 803                         free(a_value);
 804                         break;
 805          case UD_AX_MO: 
 806                         set_name = get_set_name(tr->class_type);
 807 /*                    fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
 808                         if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
 809                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 810                                         get_ref_id(tr, set_name, set_name, attr->value, condition));
 811                         break;                          
 812          case UD_AX_MR:
 813                         if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
 814                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 815                                 get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
 816                         else {  
 817                          if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
 818                          sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 819                                 get_ref_id(tr, "mntner", "mntner", attr->value, condition));
 820                         }
 821                         break;
 822          case UD_LEAF_: 
 823                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
 824                         break;
 825          case UD_LF_IF:
 826                 /* Convert ascii ip -> numeric one */
 827                         convert_if(attr->value, &if_address);
 828                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
 829                         break;
 830          case UD_LF_RF:
 831                         rf_host=convert_rf(attr->value, &rf_type, &rf_port);
 832                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
 833                         if(rf_host)free(rf_host);
 834                         break;                  
 835          case UD_LF_AY:
 836                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
 837                         break;          
 838            default:
 839                 fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type);
 840                         tr->error|=ERROR_U_BUG;
 841                         tr->succeeded=0;
 842                         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
 843                         break;
 844         }
 845 /* fprintf(stderr, "D: update: [%s]", query); */
 846    
 847    /* Execute the query */
 848     sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 849     if(sql_err) { /* an error occured*/
 850      /* Error - copy the error condition and return */
 851         sq_error=SQ_error(tr->sql_connection);
 852         fprintf(stderr, "E:<each_attribute_create> %s:[%s]\n", sq_error, query);
 853         tr->error|=ERROR_U_DBS;
 854         tr->succeeded=0;
 855         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
 856         die;
 857     }
 858     else {
 859      /* Query OK */
 860       num = mysql_affected_rows(tr->sql_connection);
 861       if(num == 0) { /* check for duplicates*/
 862         SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
 863         if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { 
 864         /* Condition with zero duplicates and matches may occur when the object is a dummy */
 865         /* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
 866         /* In such case we will append "AND dummy=0" to the query, which won't */
 867         /* return a match if the object in question is a dummy */
 868           fprintf(stderr, "E: Dummy prevents update: [%s]\n", query);
 869           tr->error|=ERROR_U_OBJ;
 870           tr->succeeded=0;
 871           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value);
 872         } /* else duplicate entry - silently drop it  */
 873       } 
 874       /* For member_of attribute we need to check membership claim in protected mode */
 875       if ((attr->type == A_MO) && (tr->dummy!=1)){
 876 /*      fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
 877           if(auth_member_of(attr, tr)!=0){
 878           tr->error|=ERROR_U_AUT;
 879           tr->succeeded=0;
 880           fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
 881           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);    
 882         }
 883       }
 884     }  
 885 return;
 886 }/*  update_attr()  */
 887 
 888 
 889 /************************************************************
 890 * each_attribute_proces()                                   *
 891 *                                                           *
 892 * Main function that processes object attributes one by one.*
 893 * Called from g_slist_foreach() function.                   * 
 894 * First it tries to insert an attribute.                    *
 895 * If an error it assumes that attribute is already in       *
 896 * a table and calls update_attr() to update it.             *
 897 * Queries for the attributes are defined in Insert[] array. * 
 898 *                                                           *
 899 * Returns: Nothing. Error code is stored in tr->error.      *
 900 *                                                           *
 901 *************************************************************/
 902 static void each_attribute_process(void *element_data, void *tr_ptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 903 {
 904 int num;
 905 const char *query_fmt;
 906 int query_type;
 907 int do_query;
 908 Attribute_t *attr = element_data;
 909 Transaction_t *tr = (Transaction_t *)tr_ptr;
 910 unsigned int prefix, prefix_length, if_address;
 911 unsigned int begin_in, end_in;
 912 ip_v6word_t  high, low;
 913 
 914 int begin_as, end_as;
 915 char query[STR_XL];
 916 char * set_name;
 917 char * rf_host; /* needs to be freed after use*/
 918 int rf_type, rf_port;
 919 char *a_value;
 920 int sq_info[3];
 921 char *mu_mntner, *mu_prefix;
 922 int dummy_err;
 923 char *sq_error;
 924 ip_prefix_t dn_pref;
 925 int sql_err;
 926 int res;
 927 char *token;
 928 
 929 /* In this structure we keep data for the radix tree */
 930 /* XXX now we are keeping this in tr structure */
 931 
 932 /* we still want to continue to collect all possible errors*/
 933 /*  if(tr->succeeded == 0) return; */
 934  
 935  /* To switch off querying for some types of attributes */
 936   do_query=1;
 937   
 938  /* Determine the query type */ 
 939   query_type=DF_get_insert_query_type(attr->type);
 940 
 941 /* For loadind pass #1 we need to process only main tables */
 942   if(tr->load_pass==1){ 
 943         switch(query_type) {
 944          case UD_MAIN_:
 945          case UD_MA_U2:
 946          case UD_MA_PR:
 947          case UD_MA_RT:
 948          case UD_MA_IN:
 949          case UD_MA_I6:
 950          case UD_MA_OR:
 951          case UD_MA_AK:
 952                         break;
 953          default:       return; /* return for other than MAIN tables*/
 954         }
 955   }
 956   
 957     query_fmt = DF_get_insert_query(attr->type);
 958 
 959 /* return if no query is defined for this attribute */
 960   if (strcmp(query_fmt, "") == 0) return;
 961 
 962  /* compose the query depending on the attribute */
 963   switch (query_type) {
 964    case UD_MAIN_: /* for MAIN tables */
 965                 if (ACT_UPDATE(tr->action)) do_query=0;
 966                 else
 967                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
 968                 break;
 969    case UD_MA_OR: /* for the origin attribute */
 970                 if (ACT_UPDATE(tr->action)) do_query=0;
 971                 else {
 972                   sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
 973                   tr->action |= TA_UPD_RX;
 974                   RP_pack_set_orig(attr->type, tr->packptr, attr->value);
 975                 }
 976                 break;
 977    case UD_MA_PR: /* for person_role table*/
 978                 if (ACT_UPDATE(tr->action)) do_query=0;
 979                 else
 980                  sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attr->value);
 981                 
 982                 /* check if we need to update NHR */
 983                 if (ACT_UPD_NHR(tr->action)) {
 984                  /* Check if we can allocate it */       
 985                   res = NH_check(tr->nh, tr->sql_connection);
 986                   if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
 987                      tr->succeeded=0;
 988                      tr->error |= ERROR_U_DBS;
 989                      g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value);
 990                      die; 
 991                   }
 992                   else 
 993                   if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
 994                     tr->succeeded=0; 
 995                     tr->error |= ERROR_U_OBJ;
 996                     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value); 
 997                     return;
 998                   }
 999                 }
1000                 break;  
1001    case UD_MA_RT: /* for route table*/
1002                 if (ACT_UPDATE(tr->action)) do_query=0;
1003                 else {
1004                   tr->action |= TA_UPD_RX;
1005                   RP_pack_set_pref4(attr->type, attr->value, tr->packptr, &prefix, &prefix_length);
1006                   /*fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length);                */
1007                   sprintf(query, query_fmt, tr->thread_ins,  
1008                           tr->object_id, prefix, prefix_length);
1009                 }
1010                 break;
1011    case UD_MA_IN: /* for inetnum table*/
1012                 if (ACT_UPDATE(tr->action)) do_query=0;
1013                 else {
1014                   tr->action |= TA_UPD_RX;
1015                   RP_pack_set_rang(attr->type, attr->value, tr->packptr, &begin_in, &end_in);
1016                   /* XXX error handling ? */
1017                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
1018                 }       
1019                 break;
1020    case UD_MA_I6: /* for inet6num table*/
1021                 if (ACT_UPDATE(tr->action)) do_query=0;
1022                 else {
1023                   tr->action |= TA_UPD_RX;
1024                   RP_pack_set_pref6(attr->type, attr->value, tr->packptr, &high, &low, &prefix_length);
1025                   /* XXX error handling ? */
1026                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
1027                 }       
1028                 break;  
1029    case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */
1030                  do_query=0;
1031                 break;
1032    case UD_MA_AK: /* for as_block table*/
1033                 if (ACT_UPDATE(tr->action)) do_query=0;
1034                 else {
1035                   convert_as_range(attr->value, &begin_as, &end_as);
1036                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
1037                 }
1038                 break;                          
1039    case UD_AUX__: /* for AUX tables*/
1040                 if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
1041                  if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
1042 
1043                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1044                 if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1045                 break;
1046    case UD_AX_MO: /* for member_of table*/
1047                 set_name = get_set_name(tr->class_type);
1048 /*              fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
1049                 sprintf(query, query_fmt, tr->thread_ins,  
1050                  tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
1051                 break;  
1052    case UD_AX_MR: /* for mbrs_by_ref table*/
1053                 if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
1054                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
1055                 else  
1056                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1057                 break;  
1058    case UD_AX_MU: /* for mnt_routes table*/
1059                 a_value=g_strdup(attr->value); 
1060                 token = a_value;
1061                 mu_mntner=strsep(&token, " ");
1062                 mu_prefix=token;
1063                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner);
1064                 free(a_value);
1065                 if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1066                 break;
1067    case UD_LEAF_: /* for LEAF tables*/
1068                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1069                 break;
1070    case UD_LF_OT: /* for LEAF tables containing object_type field*/
1071                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1072                 break;                          
1073    case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
1074                 if(tr->dummy!=1){
1075                  if(strncmp("PGPKEY", attr->value, 6)==0) {
1076                    if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 
1077                     fprintf(stderr, "E:<e_a_p>: No key-cert object.\n");
1078                     tr->error|=ERROR_U_OBJ;
1079                     tr->succeeded=0;
1080                     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
1081                     return;
1082                    }
1083                  }
1084                 } 
1085                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1086                 break;      
1087    case UD_LF_IF: /* for ifaddr tables*/
1088                 /* Convert ascii ip -> numeric one*/
1089                 convert_if(attr->value, &if_address);
1090                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address);
1091                 break;
1092    case UD_LF_RF: /* for refer table*/
1093                 rf_host=convert_rf(attr->value, &rf_type, &rf_port);
1094                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
1095                 if(rf_host)free(rf_host);
1096                 break;  
1097    case UD_LF_AY: /* for auth_override table*/
1098                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
1099                 break;
1100         default:
1101                 fprintf(stderr, "E: query not defined for this type of attribute\n");
1102                 tr->succeeded=0;
1103                 tr->error |= ERROR_U_BUG;
1104                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value);
1105                 die;
1106                 break;
1107   }
1108   
1109 /* fprintf(stderr, "D: insert: [%s]", query); */
1110 
1111 
1112  /* Make the query. For primary keys go straight to updates if we are updating the object */
1113   if(do_query){
1114    sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1115   } 
1116   else {
1117    update_attr(attr, tr);
1118    return;
1119   }
1120   
1121 /*  fprintf(stderr, "D: query: %d rows affected\n", num);*/
1122   if (sql_err)  {
1123   /* we received an error */
1124    if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
1125         if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
1126                 update_attr(attr, tr);
1127                 return;
1128         }       
1129      /* Otherwise this is a duplicate attribute, just ignore it */
1130      /* In the future if we are more stringent, checks may be added here */     
1131    }
1132    else { /* Other errors reveal a database/server problem*/
1133         sq_error=SQ_error(tr->sql_connection);
1134         tr->error|=ERROR_U_DBS;
1135         tr->succeeded=0;
1136         fprintf(stderr, "E:<each_attribute_create>: %s: [%s]\n", sq_error, query);
1137         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
1138    }
1139   } /* if error occured */
1140   else { 
1141  /* If the query was successful */
1142    num = mysql_affected_rows(tr->sql_connection);
1143    if(num>0){ /* this is OK*/
1144  /* Do some additional processing for member_of attribute  */
1145         if ((attr->type == A_MO) && (tr->dummy!=1)){
1146 /*              fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
1147                 if(auth_member_of(attr, tr)!=0){
1148                  tr->error|=ERROR_U_AUT;
1149                  tr->succeeded=0;
1150                  fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
1151                  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);     
1152                 }
1153         }
1154         else
1155           /* Do some additional processing for reverse zones domains */
1156           if ((attr->type == A_DN) 
1157               && IP_revd_e2b(&dn_pref, attr->value)==IP_OK ) {
1158             
1159             if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
1160                 tr->error|=ERROR_U_DBS;
1161                 tr->succeeded=0;
1162                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1163                                   ERROR_U_DBS, attr->type, attr->value, 
1164                                   SQ_error(tr->sql_connection));
1165                 die;    
1166             }
1167             else {
1168               /* save data for the radix tree update */
1169               tr->action |= TA_UPD_RX;
1170               RP_pack_set_revd(attr->type, attr->value, tr->packptr);
1171             }
1172           }
1173         return;
1174    }
1175    if(num == 0) {
1176 /* this could be an empty update or a null select */        
1177         SQ_get_info(tr->sql_connection, sq_info); 
1178         if (sq_info[SQL_DUPLICATES]>0) { 
1179                 if (sq_info[SQL_DUPLICATES]>1) { 
1180                         fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query);
1181                         tr->error|=ERROR_U_DBS;
1182                         tr->succeeded=0;
1183                         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value);
1184                         die;
1185                 }
1186                 update_attr(attr, tr);
1187         }
1188         else { 
1189                 
1190                 /* try to create dummy and repeat original query*/
1191                 
1192 /*              fprintf(stderr, "W: no ref. integrity. Trying to create dummy...");*/
1193 
1194                 dummy_err = create_dummy(attr, tr);
1195                 if (dummy_err == 0) {
1196 /*                      fprintf(stderr, "D: ... dummy OK\n");*/
1197                         g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
1198 /*                      fprintf(stderr, "D: repeating query: %s\n", query);*/
1199                         sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1200                         num = mysql_affected_rows(tr->sql_connection);
1201                         if (sql_err) {
1202                           sq_error=SQ_error(tr->sql_connection);
1203                           fprintf(stderr, "E: re-insert query:%s[%s]\n", sq_error, query);
1204                           tr->error|=ERROR_U_DBS;
1205                           tr->succeeded=0;
1206                           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1207                                             ERROR_U_DBS, attr->type, attr->value, sq_error);
1208                         }                    
1209                         if (num==0) {
1210                           fprintf(stderr, "E: re-insert query:%s[%s]\n", "", query);
1211                           tr->error|=ERROR_U_DBS;
1212                           tr->succeeded=0;
1213                           fprintf(stderr, "E: re-insert query: [%s]\n", query);
1214                           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
1215                                             ERROR_U_DBS, attr->type, attr->value);
1216                         }
1217                 }
1218                 else 
1219                  if(dummy_err == 1) {
1220                    tr->error |= ERROR_U_OBJ;
1221                    tr->succeeded=0;
1222                    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value);
1223                  }
1224                  else {
1225                    tr->error|=ERROR_U_DBS;
1226                    tr->succeeded=0;
1227                    fprintf(stderr, "E:<each_attribute_create>: dummy not created\n");
1228                    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value);
1229                 }       
1230         }  /* RI*/
1231    }/* if num == 0*/
1232   } /* if the query was successful */
1233   
1234   return;
1235 } /* each_attribute_process() */
1236 
1237 
1238 
1239 /************************************************************
1240 * each_primary_key_select()                                 *
1241 *                                                           *
1242 * Function that forms a query for an object (w prinary keys)*
1243 * Called from g_slist_foreach() function.                   *
1244 * Primary keys are defined in Select[] array.               *
1245 *                                                           *
1246 * Returns: Nothing.                                         *
1247 *                                                           *
1248 *************************************************************/ 
1249 static void each_primary_key_select(void *element_data, void *result_ptr) 
     /* [<][>][^][v][top][bottom][index][help] */
1250 {
1251 Attribute_t *attr = element_data;
1252 GString *result = (GString *)result_ptr;
1253 const char *query_fmt;
1254 unsigned int prefix, prefix_length;
1255 unsigned int begin_in, end_in;
1256 int begin_as, end_as;
1257 ip_prefix_t prefstr;
1258 ip_range_t  rangstr;
1259 ip_v6word_t i6_msb, i6_lsb;
1260 
1261    query_fmt = DF_get_select_query(attr->type);
1262 
1263   if (strcmp(query_fmt, "") != 0) {
1264     switch (DF_get_select_query_type(attr->type)) {
1265      case UD_MAIN_: 
1266                 g_string_sprintfa(result, query_fmt, attr->value);
1267                 break;
1268      case UD_MA_RT:
1269                 IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length);
1270                 g_string_sprintfa(result, query_fmt, prefix, prefix_length);
1271                 break;
1272      case UD_MA_IN:
1273                 IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in);
1274                 g_string_sprintfa(result, query_fmt, begin_in, end_in);
1275                 break;
1276      case UD_MA_I6:
1277                 IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length);
1278                 g_string_sprintfa(result, query_fmt, i6_msb, i6_lsb, prefix_length);
1279                 break;                                          
1280      case UD_MA_AK:
1281                 convert_as_range(attr->value, &begin_as, &end_as);
1282                 g_string_sprintfa(result, query_fmt, begin_as, end_as);
1283                 break;
1284      default:
1285 fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type);
1286                 die;
1287 
1288         break;
1289     } 
1290   }
1291 } 
1292 
1293 /************************************************************
1294 * perform_create(const Object_t *obj, Transaction_t *tr)    * 
1295 *                                                           *
1296 * Procedure for creating a new object.                      *
1297 * First inserts object into 'last' table and gets object_id.*
1298 * Then processes all attributes.                            *
1299 *                                                           *
1300 * Returns: tr->succeeded: >0 success, 0 - error             *
1301 * Error code is stored in tr->error.                        *
1302 *                                                           *
1303 *************************************************************/ 
1304 static int perform_create(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1305 {
1306  Object_t *obj;
1307  char *str;
1308  GString *query;
1309  long timestamp;
1310  int sql_err;
1311   
1312   
1313  if ((query = g_string_sized_new(STR_XL)) == NULL){
1314   tr->succeeded=0;
1315   tr->error |= ERROR_U_MEM; 
1316   fprintf(stderr, "E: cannot allocate gstring\n"); 
1317   die; 
1318  }
1319  
1320  
1321  obj=tr->object;
1322   
1323       str = (obj->object)->str;
1324       timestamp=time(NULL);
1325       tr->sequence_id=1; /* we start with 1*/
1326       g_string_sprintf(query, "INSERT INTO last SET thread_id=0, timestamp=%ld, sequence_id=1, object_type=%d, object='%s' ",
1327                       timestamp, tr->class_type, str);
1328 
1329       sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1330       
1331      /* Check for affected rows. One row should be affected . */ 
1332       if (sql_err) {
1333         tr->error|=ERROR_U_DBS;
1334         tr->succeeded=0; 
1335         fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%s\n", SQ_error(tr->sql_connection));
1336         g_string_sprintfa(tr->error_script,"E[%d][:]:%s\n" ,ERROR_U_DBS, SQ_error(tr->sql_connection));
1337       }
1338       else {
1339       /* Get generated (autoincrement) object_id */
1340         tr->object_id=mysql_insert_id(tr->sql_connection);
1341         g_slist_foreach(obj->attributes, each_attribute_process, tr);
1342       }
1343     g_string_free(query, TRUE);
1344     return(tr->succeeded);  
1345 } /* perform_create() */
1346 
1347 /************************************************************
1348 * perform_update(Transaction_t *tr)                         * 
1349 *                                                           *
1350 * Procedure for updating (existing) object.                 *
1351 * First processes all attributes.                           *
1352 * Then saves previous object in 'history' and updates       *
1353 * 'last' table.                                             *
1354 *                                                           *
1355 * Returns: tr->succeeded: >0 success, 0 - error             *
1356 * Error code is stored in tr->error.                        *
1357 *                                                           *
1358 *************************************************************/ 
1359 static int perform_update(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1360 {
1361 Object_t *obj;
1362 char *str;
1363 GString *query;
1364 int num;
1365 long sequence_id;
1366 long timestamp;
1367 char *sq_error;
1368 int sql_err;
1369  
1370 
1371  obj=tr->object;
1372 
1373   /* process each attribute one by one */
1374   g_slist_foreach(obj->attributes, each_attribute_process, tr);
1375 
1376   /* If we've already failed or this is fast load - just return */
1377   if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded);
1378   
1379     /* No return: thread_id=0 */
1380     /* Do it only if previous transactions finished well */
1381   if ((query = g_string_sized_new(STR_XL)) == NULL){
1382    tr->succeeded=0;
1383    tr->error |= ERROR_U_MEM; 
1384    fprintf(stderr, "E: cannot allocate gstring\n"); 
1385    die; 
1386   }     
1387     /* copy object to the history table */
1388 /*fprintf(stderr, "INSERT history\n");    */
1389     g_string_sprintf(query,"INSERT history "
1390                   "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
1391                   "FROM last "
1392                   "WHERE object_id=%ld ", tr->object_id);
1393 
1394     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1395     
1396    /* Check for affected rows. One row should be affected . */
1397     num = mysql_affected_rows(tr->sql_connection);
1398     if (num < 1) {
1399          tr->error|=ERROR_U_DBS;
1400          tr->succeeded=0;
1401          if (sql_err) {
1402           sq_error=SQ_error(tr->sql_connection);
1403           fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]%s\n", num, query, sq_error);
1404           g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed:%s\n" ,ERROR_U_DBS, sq_error);
1405          }
1406          else {
1407           fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query);
1408           g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS);
1409         /* This is to check that this is really could happen */  
1410           die;
1411          } 
1412          g_string_free(query, TRUE);
1413          return(tr->succeeded);
1414     }
1415 
1416     /* get sequence number */
1417     
1418     sequence_id = get_sequence_id(tr);
1419     if(sequence_id==-1) {
1420       fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id\n");
1421       tr->error|=ERROR_U_DBS;
1422       tr->succeeded=0;
1423       g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS);
1424       g_string_free(query, TRUE);
1425       return(tr->succeeded);
1426     } 
1427     else tr->sequence_id=sequence_id; /* save it for rollback*/
1428         
1429        
1430     /* Insert new version into the last */
1431     
1432     /* Put a timestamp */
1433     str = (obj->object)->str;
1434     timestamp=time(NULL);
1435     tr->sequence_id++;
1436        
1437 /*fprintf(stderr, "UPDATE last\n");       */
1438     /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */
1439     g_string_sprintf(query, "UPDATE last "
1440                    "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' "
1441                    "WHERE object_id=%ld ",
1442                    tr->sequence_id, timestamp, tr->class_type, str, tr->object_id);
1443 
1444     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1445     
1446     /* Check for affected rows. One row should be affected */
1447     num = mysql_affected_rows(tr->sql_connection);
1448     if (num < 1) {
1449          tr->error|=ERROR_U_DBS;
1450          tr->succeeded=0;
1451          if(sql_err) {
1452           fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]%s\n", num, query, SQ_error(tr->sql_connection));
1453           g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
1454          }
1455          else {
1456           fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query);
1457           g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed\n" ,ERROR_U_DBS);
1458           /* This is to check that this is really could happen */  
1459           die;
1460          } 
1461          g_string_free(query, TRUE);
1462          return(tr->succeeded);
1463     }
1464  g_string_free(query, TRUE);
1465  return(tr->succeeded);   
1466 } /* perform_update() */
1467 
1468 
1469 
1470 
1471 /************************************************************
1472 * int object_process(Transaction_t *tr)                     *
1473 *                                                           *
1474 * This is the interface between core and upper layer        *
1475 * All it gets is Transaction *tr, which contains all        *
1476 * necessary information, including the object in its        *
1477 * internal representation.                                  *
1478 *                                                           *
1479 * Returns: tr->succeeded: >0 success, 0 - error             *
1480 * Error code is stored in tr->error.                        *
1481 *                                                           *
1482 *************************************************************/ 
1483 int object_process(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1484 {
1485 int res;
1486 char nic[MAX_NH_LENGTH];
1487 
1488    if(ACT_DELETE(tr->action)){
1489                 fprintf(stderr, "D: Action: Delete...");
1490                 delete(tr);
1491                 /* Commit nic-handle deletion to the repository */
1492                 if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1493                  res = NH_free(tr->nh, tr->sql_connection);
1494                  if(res == -1) { 
1495                   tr->succeeded=0; 
1496                   tr->error |= ERROR_U_DBS;
1497                   g_string_sprintfa(tr->error_script,"E[%d][]:cannot delete nic-handle\n", ERROR_U_DBS); 
1498                   return(tr->succeeded);
1499                  }
1500                  else if(res == 0) { 
1501                   tr->succeeded=0; 
1502                   tr->error |= ERROR_U_OBJ;
1503                   g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle not found\n", ERROR_U_OBJ); 
1504                   return(tr->succeeded);
1505                  }
1506                 }
1507                 return(tr->succeeded); /*commit is not needed*/
1508     }
1509     else if(ACT_UPDATE(tr->action)){            
1510                 fprintf(stderr, "D: Action: Update...");
1511                 perform_update(tr);
1512                 /* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/
1513                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1514                  /* convert nh to DB nIC handle before registration */
1515                  /* because there nh will bee freed */
1516                  NH_convert(nic, tr->nh);
1517                  res = NH_register(tr->nh, tr->sql_connection);
1518                  if(res == -1) { 
1519                   tr->succeeded=0; 
1520                   tr->error |= ERROR_U_DBS;
1521                   g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS); 
1522                  }
1523                  else if(res == 0) { 
1524                   tr->succeeded=0; 
1525                   tr->error |= ERROR_U_OBJ;
1526                   g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ); 
1527                  }
1528                  else { /* copy the NH to the report to return to DBupdate */
1529                  /* Convert nh to the database format */     
1530                   g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1531                  }               
1532                 }
1533     }
1534     else if(ACT_CREATE(tr->action)){
1535                 fprintf(stderr, "D: Action: Create...");
1536                 perform_create(tr);
1537                 /* Commit nic-handle allocation (if any) to the repository */
1538                 if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1539                  /* convert nh to DB nIC handle before registration */
1540                  /* because there nh will bee freed */
1541                  NH_convert(nic, tr->nh);
1542                  res = NH_register(tr->nh, tr->sql_connection);
1543                  if(res == -1) { 
1544                   tr->succeeded=0; 
1545                   tr->error |= ERROR_U_DBS;
1546                   g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS); 
1547                  }
1548                  else if(res == 0) { 
1549                   tr->succeeded=0; 
1550                   tr->error |= ERROR_U_OBJ;
1551                   g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ); 
1552                  }
1553                  else { /* copy the NH to the report to return to DBupdate */
1554                   g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1555                  }
1556                 }
1557         
1558      }
1559      else {
1560                 fprintf(stderr, "D: Action: Unknown...");
1561                 tr->succeeded=0;
1562                 tr->error|=ERROR_U_BADOP;
1563                 return(tr->succeeded);
1564      }          
1565 
1566    if(tr->load_pass == 0) { /* not for fast loader*/
1567       if (tr->succeeded == 1) {
1568 /*fprintf(stderr, "D: Commit transaction...\n");      */
1569         commit(tr);
1570       }
1571       else {
1572 /*fprintf(stderr, "D: Roll back transaction...\n");      */
1573         rollback(tr);
1574       }
1575     }  
1576  return(tr->succeeded);   
1577 } /* object_process() */
1578 

/* [<][>][^][v][top][bottom][index][help] */