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