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