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

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