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