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