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