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

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