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) 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) 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) 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) 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) 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) 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) 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) 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, 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) 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) 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) 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) 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, 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) 489 | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1) 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) 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) 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) 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) 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) 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) 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) 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) 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 |