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