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