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