1 | /***************************************
2 | $Revision: 1.16 $
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 | return(NULL);
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,
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)
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)
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)
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)
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,
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)
532 | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
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)
553 | {
554 | GString *query;
555 | SQ_result_set_t *sql_result;
556 | SQ_row_t *sql_row;
557 | /*char *sql_str;*/
558 | char *set_name;
559 | /*long set_id;*/
560 | /*my_ulonglong num;*/
561 | int error;
562 | char *sq_error;
563 | int sql_err;
564 |
565 |
566 | error=0;
567 |
568 | /* Check if set has mbrs_by_ref==ANY
569 | In such case mbrs_by_ref.mnt_id==0
570 | */
571 |
572 | if ((query = g_string_sized_new(STR_XL)) == NULL){
573 | tr->succeeded=0;
574 | tr->error |= ERROR_U_MEM;
575 | fprintf(stderr, "E: cannot allocate gstring\n");
576 | return(-1);
577 | }
578 |
579 | set_name = get_set_name(tr->class_type);
580 | /* fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name); */
581 | /* Check if membership is protected by the keyword "ANY" */
582 | /* There is a dummy mntmer object in the database corresponding to "ANY" */
583 | /* Its object_id==0 */
584 | g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
585 | "WHERE mbrs_by_ref.object_id=%s.object_id "
586 | "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ",
587 | set_name, set_name, set_name, set_name, set_name, attr->value);
588 | /* fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);*/
589 |
590 | sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
591 | if (sql_err) { /*An error occured*/
592 | sq_error=SQ_error(tr->sql_connection);
593 | fprintf(stderr, "E:<auth_member_of>:[%s]:%s\n", query->str, sq_error);
594 | g_string_free(query, TRUE);
595 | return(-1);
596 | }
597 |
598 | /* If empty result has been returned than there is no "ANY" protection */
599 | if ((sql_row = SQ_row_next(sql_result))==NULL){
600 | SQ_free_result(sql_result);
601 |
602 | /* Check if our mnt_by belongs to mbrs_by_ref list of the set */
603 | g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by "
604 | "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
605 | "AND mnt_by.object_id=%ld "
606 | "AND %s.object_id=mbrs_by_ref.object_id "
607 | "AND %s.%s='%s' "
608 | "AND mnt_by.thread_id!=0 ",
609 | tr->object_id, set_name, set_name, set_name, attr->value);
610 |
611 | /* fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str); */
612 |
613 | sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
614 |
615 | if(sql_err) {
616 | fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
617 | g_string_free(query, TRUE);
618 | return(-1);
619 | }
620 |
621 | if ((sql_row = SQ_row_next(sql_result)) == NULL) {
622 | /* Membership is not authorized */
623 | fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str);
624 | SQ_free_result(sql_result);
625 | g_string_free(query, TRUE);
626 | return(1);
627 | }
628 | }
629 |
630 | /* sql_str = SQ_get_column_string(sql_result, sql_row, 0);*/
631 | /* We must process all the rows of the result, otherwise we'll have them as part of the next qry */
632 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
633 | fprintf(stderr, "E:<auth_member_of> error : More than one object with the same PK\n");
634 | error=-1;
635 | }
636 | SQ_free_result(sql_result);
637 | g_string_free(query, TRUE);
638 | return(0);
639 | }/* auth_member_of() */
640 |
641 |
642 | /************************************************************
643 | * create_dummy() *
644 | * *
645 | * Function that creates a dummy object (that is one that *
646 | * is referenced from an object but does not *
647 | * exist in the database). *
648 | * Dummy object exists only in relevant main and 'last' *
649 | * tables. Its creation is controlled by tr->dummy_allowed. *
650 | * Queries for the dummies are defined in Dummy[] array. *
651 | * *
652 | * Returns: *
653 | * 0 success *
654 | * 1 no rf integrity and dummy not allowed
655 | * -1 SQL error *
656 | * *
657 | *************************************************************/
658 | static int create_dummy(Attribute_t *attr, Transaction_t *tr)
659 | {
660 | /*SQ_result_set_t *sql_result;*/
661 | const char *query_fmt;
662 | long dummy_id;
663 | char query[STR_L];
664 | int result=0;
665 | char *set_name;
666 | char *p_name;
667 | int query_type;
668 | long timestamp;
669 | char str_id[STR_M];
670 | gchar *attr_value=NULL;
671 | int sql_err;
672 |
673 |
674 | /* query_fmt = Dummy[attr->type].qry; */
675 | query_fmt = DF_get_dummy_query(attr->type);
676 | if (strcmp(query_fmt, "") == 0) {
677 | fprintf(stderr, "E:<create_dummy>: empty query string\n");
678 | return(1);
679 | }
680 |
681 | /* We allow creating dummy sets in any mode */
682 | /* For others attributes return if we are in protected mode */
683 | if ((attr->type!=A_MO) && (tr->dummy != 1)) return(1);
684 |
685 | /* Insert dummy in the last table */
686 | sprintf(str_id, "%ld", tr->object_id);
687 | timestamp=time(NULL);
688 | sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'",
689 | tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
690 | /* fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query);*/
691 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
692 | /* num = mysql_affected_rows(tr->sql_connection);*/
693 |
694 | /* Check for errors */
695 | if (sql_err) {
696 | fprintf(stderr, "E: dummy->last:[%s]\n", query);
697 | return(-1);
698 | }
699 |
700 | /* insert dummy in the main table */
701 | dummy_id=mysql_insert_id(tr->sql_connection);
702 | /* Record dummy's object_id, it'll be needed in commit/rollback */
703 | tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
704 |
705 | /* compose the query */
706 | /* query_type=Dummy[attr->type].qtype; */
707 | query_type=DF_get_dummy_query_type(attr->type);
708 | switch (query_type) {
709 |
710 | /* person_role */
711 | case UD_AX_PR:
712 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
713 | break;
714 |
715 | /* maintner */
716 | case UD_AX_MT:
717 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
718 | break;
719 |
720 | /* as_set, route_set */
721 | case UD_AX_MO:
722 | set_name = get_set_name(tr->class_type);
723 | sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);
724 | break;
725 |
726 | default:
727 | fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type);
728 | return(-1);
729 | break;
730 | }
731 |
732 | /*fprintf(stderr, "D: query: %s\n", query);*/
733 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
734 | /* num = mysql_affected_rows(tr->sql_connection); */
735 | /*fprintf(stderr, "D: query: %d rows affected\n", num);*/
736 | if (sql_err) {
737 | fprintf(stderr, "E: dummy->main:%s[%s]\n", SQ_error(tr->sql_connection), query);
738 | return(-1);
739 | }
740 |
741 |
742 | if( query_type == UD_AX_MO ){
743 | /* for dummy sets (as_set, route_set) create a record in mbrs_by_ref table with attribute value ANY */
744 | sprintf(query, " INSERT mbrs_by_ref SET thread_id=%d, object_id=%ld, mnt_id=0, object_type=%d ",
745 | tr->thread_ins,dummy_id, DUMMY_TYPE);
746 | /*fprintf(stderr, "D: query: %s\n", query);*/
747 |
748 | /* Execute query and check for errors */
749 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
750 | /* num = mysql_affected_rows(tr->sql_connection);*/
751 | if (sql_err) {
752 | fprintf(stderr, "E: dummy->main:%s[%s]\n", SQ_error(tr->sql_connection), query);
753 | return(-1);
754 | }
755 | }
756 | else
757 | /* for legacy person/role reference (without nic-handle) create records in names table */
758 | if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){
759 | /* parse the names */
760 | /*fprintf(stderr,"adding names for dummy\n");*/
761 | query_fmt = DF_get_insert_query(A_PN);
762 | attr_value = g_strdup(attr->value);
763 | while((p_name=s_split(attr_value))){
764 | sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
765 | /* fprintf(stderr, "D: query: %s\n", query);*/
766 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
767 | /* num = mysql_affected_rows(tr->sql_connection); */
768 | if (sql_err)
769 | if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) {
770 | fprintf(stderr, "E: insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query);
771 | result=-1;
772 | }
773 | /* if (num==0) {
774 | fprintf(stderr, "E: insert dummy names:%s[%s]\n", "", query);
775 | result=-1;
776 | } */
777 | }
778 | free(attr_value);
779 | }
780 | return(result);
781 | }
782 |
783 | /************************************************************
784 | * update_attr() *
785 | * *
786 | * Function that updates an attribute if it already exists. *
787 | * Called from each_attribute_proces() function if it *
788 | * cannot insert the row. *
789 | * Queries for the attributes are defined in Update[] array. *
790 | * *
791 | * Returns: Nothing. Error code is stored in tr->error. *
792 | * *
793 | *************************************************************/
794 | static void update_attr(Attribute_t *attr, Transaction_t *tr)
795 | {
796 | /*SQ_result_set_t * sql_result;*/
797 | int num;
798 | const char *query_fmt;
799 | /*GString *query;*/
800 | char *set_name;
801 | unsigned int if_address;
802 | char * rf_host;
803 | int rf_port, rf_type;
804 | char *a_value;
805 | /*int dupl;*/
806 | int sq_info[3];
807 | char * condition;
808 | char *sq_error;
809 | char query[STR_XL];
810 | ip_prefix_t dn_pref;
811 | int sql_err;
812 |
813 | /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */
814 | if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return;
815 |
816 | /* fprintf(stderr, "D: updating attribute...\n");*/
817 |
818 | /* Do some additional processing for reverse domains */
819 | /* XXX Later we will implement this under UD_MA_DN case */
820 | if ((attr->type == A_DN) && (IP_revd_e2b(&dn_pref, attr->value)==IP_OK)) {
821 | if(update_reverse_domain(tr, &dn_pref) !=0 ){
822 | tr->error|=ERROR_U_DBS;
823 | tr->succeeded=0;
824 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
825 | ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection));
826 | }
827 | }
828 |
829 | /* query_fmt = Update[attr->type].qry; */
830 | query_fmt = DF_get_update_query(attr->type);
831 |
832 | if (strcmp(query_fmt, "") == 0) return;
833 |
834 | switch (DF_get_update_query_type(attr->type)) {
835 | case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
836 | break;
837 | case UD_MA_PR:
838 | sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
839 | break;
840 | case UD_MA_U2: /* save the new value of the attribute for commit*/
841 | /* this is necessary for filter(filter-set), netname (inet?num), */
842 | /* local-as(inet-rtr) attributes, as they are another field in the record */
843 | if((tr->load_pass != 0)){
844 | /* for fast loader we need to update the field as we have no commit */
845 | sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id);
846 | }
847 | else {
848 | tr->save=g_strdup(attr->value);
849 | /* fprintf(stderr, "D:<e_a_p> attribute saved: %s\n", tr->save);*/
850 | return;
851 | }
852 | break;
853 | case UD_AX_PR:
854 | /* This is for non-conformant admin-c, etc.*/
855 | a_value=attr->value;
856 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
857 |
858 | if (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, "person_role", "nic_hdl", attr->value, condition));
861 | break;
862 | case UD_AX_MT:
863 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
864 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
865 | get_ref_id(tr, "mntner", "mntner", attr->value, condition));
866 | break;
867 | case UD_AX_MO:
868 | set_name = get_set_name(tr->class_type);
869 | /* fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
870 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
871 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
872 | get_ref_id(tr, set_name, set_name, attr->value, condition));
873 | break;
874 | case UD_AX_MR:
875 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
876 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
877 | get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
878 | else {
879 | if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
880 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
881 | get_ref_id(tr, "mntner", "mntner", attr->value, condition));
882 | }
883 | break;
884 | case UD_LEAF_:
885 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
886 | break;
887 | case UD_LF_IF:
888 | /* Convert ascii ip -> numeric one */
889 | convert_if(attr->value, &if_address);
890 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
891 | break;
892 | case UD_LF_RF:
893 | rf_host=convert_rf(attr->value, &rf_type, &rf_port);
894 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
895 | if(rf_host)free(rf_host);
896 | break;
897 | case UD_LF_AY:
898 | sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
899 | break;
900 | default:
901 | fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type);
902 | tr->error|=ERROR_U_BUG;
903 | tr->succeeded=0;
904 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
905 | break;
906 | }
907 | /* fprintf(stderr, "D: update: [%s]", query); */
908 |
909 | /* Execute the query */
910 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
911 | if(sql_err) { /* an error occured*/
912 | /* Error - copy the error condition and return */
913 | sq_error=SQ_error(tr->sql_connection);
914 | fprintf(stderr, "E:<each_attribute_create> %s:[%s]\n", sq_error, query);
915 | tr->error|=ERROR_U_DBS;
916 | tr->succeeded=0;
917 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
918 | return;
919 | }
920 | else {
921 | /* Query OK */
922 | num = mysql_affected_rows(tr->sql_connection);
923 | if(num == 0) { /* check for duplicates*/
924 | SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
925 | if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) {
926 | /* Condition with zero duplicates and matches may occur when the object is a dummy */
927 | /* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
928 | /* In such case we will append "AND dummy=0" to the query, which won't */
929 | /* return a match if the object in question is a dummy */
930 | fprintf(stderr, "E: Dummy prevents update: [%s]\n", query);
931 | tr->error|=ERROR_U_OBJ;
932 | tr->succeeded=0;
933 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value);
934 | } /* else duplicate entry - silently drop it */
935 | }
936 | /* For member_of attribute we need to check membership claim in protected mode */
937 | if ((attr->type == A_MO) && (tr->dummy!=1)){
938 | /* fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
939 | if(auth_member_of(attr, tr)!=0){
940 | tr->error|=ERROR_U_AUT;
941 | tr->succeeded=0;
942 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
943 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
944 | }
945 | }
946 | }
947 | return;
948 | }/* update_attr() */
949 |
950 |
951 | /************************************************************
952 | * each_attribute_proces() *
953 | * *
954 | * Main function that processes object attributes one by one.*
955 | * Called from g_slist_foreach() function. *
956 | * First it tries to insert an attribute. *
957 | * If an error it assumes that attribute is already in *
958 | * a table and calls update_attr() to update it. *
959 | * Queries for the attributes are defined in Insert[] array. *
960 | * *
961 | * Returns: Nothing. Error code is stored in tr->error. *
962 | * *
963 | *************************************************************/
964 | static void each_attribute_process(void *element_data, void *tr_ptr)
965 | {
966 | /*SQ_result_set_t * sql_result;*/
967 | int num;
968 | const char *query_fmt;
969 | int query_type;
970 | int do_query;
971 | Attribute_t *attr = element_data;
972 | Transaction_t *tr = (Transaction_t *)tr_ptr;
973 | unsigned int prefix, prefix_length, if_address;
974 | unsigned int begin_in, end_in;
975 | ip_v6word_t high, low;
976 |
977 | int begin_as, end_as;
978 | char query[STR_XL];
979 | char * set_name;
980 | char * rf_host; /* needs to be deleted after use*/
981 | int rf_type, rf_port;
982 | char *a_value;
983 | int sq_info[3];
984 | char *mu_mntner, *mu_prefix;
985 | int dummy_err;
986 | char *sq_error;
987 | ip_prefix_t dn_pref;
988 | int sql_err;
989 | int res;
990 |
991 | /* In this structure we keep data for the radix tree */
992 | static rp_upd_pack_t data_pack;
993 |
994 | /* we still want to continue to collect all possible errors*/
995 | /* if(tr->succeeded == 0) return; // no sense to continue*/
996 |
997 | /* To switch off querying for some types of attributes */
998 | do_query=1;
999 |
1000 | /* Determine the query type */
1001 | /* query_type=Insert[attr->type].qtype; */
1002 | query_type=DF_get_insert_query_type(attr->type);
1003 |
1004 | /* For loadind pass #1 we need to process only main tables */
1005 | if(tr->load_pass==1){
1006 | switch(query_type) {
1007 | case UD_MAIN_:
1008 | case UD_MA_U2:
1009 | case UD_MA_PR:
1010 | case UD_MA_RT:
1011 | case UD_MA_IN:
1012 | case UD_MA_I6:
1013 | case UD_MA_OR:
1014 | case UD_MA_AK:
1015 | break;
1016 | default: return; /* return for other than MAIN tables*/
1017 | }
1018 | }
1019 |
1020 | query_fmt = DF_get_insert_query(attr->type);
1021 |
1022 | /* return if no query is defined for this attribute */
1023 | if (strcmp(query_fmt, "") == 0) return;
1024 |
1025 | /* compose the query depending on the attribute */
1026 | switch (query_type) {
1027 | case UD_MAIN_: /* for MAIN tables */
1028 | if (ACT_UPDATE(tr->action)) do_query=0;
1029 | else
1030 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1031 | break;
1032 | case UD_MA_OR: /* for the origin attribute */
1033 | if (ACT_UPDATE(tr->action)) do_query=0;
1034 | else {
1035 | sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
1036 | /* if(attr->type == A_OR) { */
1037 | RP_pack_set_orig(attr->type, &data_pack, attr->value);
1038 | tr->packptr = &data_pack; /* just in case*/
1039 | /* } */
1040 | }
1041 | break;
1042 | case UD_MA_PR: /* for person_role table*/
1043 | if (ACT_UPDATE(tr->action)) do_query=0;
1044 | else
1045 | sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id, attr->value);
1046 |
1047 | /* check if we need to update NHR */
1048 | if (ACT_UPD_NHR(tr->action)) {
1049 | /* Check if we can allocate it */
1050 | res = NH_check(tr->nh, tr->sql_connection);
1051 | if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
1052 | tr->succeeded=0;
1053 | tr->error |= ERROR_U_DBS;
1054 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value);
1055 | return;
1056 | }
1057 | else
1058 | if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
1059 | tr->succeeded=0;
1060 | tr->error |= ERROR_U_OBJ;
1061 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value);
1062 | return;
1063 | }
1064 | }
1065 | break;
1066 | case UD_MA_RT: /* for route table*/
1067 | if (ACT_UPDATE(tr->action)) do_query=0;
1068 | else {
1069 |
1070 | RP_pack_set_pref4(attr->type, attr->value, &data_pack, &prefix, &prefix_length);
1071 | /*fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length); */
1072 | sprintf(query, query_fmt, tr->thread_ins,
1073 | tr->object_id, prefix, prefix_length);
1074 | /* save stuff for radix update*/
1075 | tr->packptr = &data_pack;
1076 | }
1077 | break;
1078 | case UD_MA_IN: /* for inetnum table*/
1079 | if (ACT_UPDATE(tr->action)) do_query=0;
1080 | else {
1081 | RP_pack_set_rang(attr->type, attr->value, &data_pack, &begin_in, &end_in);
1082 | /* XXX error handling ? */
1083 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
1084 | tr->packptr = &data_pack;
1085 | }
1086 | break;
1087 | case UD_MA_I6: /* for inet6num table*/
1088 | if (ACT_UPDATE(tr->action)) do_query=0;
1089 | else {
1090 | RP_pack_set_pref6(attr->type, attr->value, &data_pack, &high, &low, &prefix_length);
1091 | /* XXX error handling ? */
1092 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
1093 | tr->packptr = &data_pack;
1094 | }
1095 | break;
1096 | case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */
1097 | do_query=0;
1098 | break;
1099 | case UD_MA_AK: /* for as_block table*/
1100 | if (ACT_UPDATE(tr->action)) do_query=0;
1101 | else {
1102 | convert_as_range(attr->value, &begin_as, &end_as);
1103 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
1104 | }
1105 | break;
1106 | case UD_AUX__: /* for AUX tables*/
1107 | if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
1108 | if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
1109 |
1110 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1111 | if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1112 | break;
1113 | case UD_AX_MO: /* for member_of table*/
1114 | set_name = get_set_name(tr->class_type);
1115 | /* fprintf(stderr, "D: retrieved set name: %s\n", set_name);*/
1116 | sprintf(query, query_fmt, tr->thread_ins,
1117 | tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
1118 | break;
1119 | case UD_AX_MR: /* for mbrs_by_ref table*/
1120 | if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
1121 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
1122 | else
1123 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1124 | break;
1125 | case UD_AX_MU: /* for mnt_routes table*/
1126 | a_value=g_strdup(attr->value);
1127 | mu_mntner=s_splitn(a_value, 1);
1128 | mu_prefix=s_splitn(a_value, 1);
1129 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, mu_prefix, tr->class_type, mu_mntner);
1130 | free(a_value);
1131 | if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
1132 | break;
1133 | case UD_LEAF_: /* for LEAF tables*/
1134 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1135 | break;
1136 | case UD_LF_OT: /* for LEAF tables containing object_type field*/
1137 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1138 | break;
1139 | case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
1140 | if(tr->dummy!=1){
1141 | if(strncmp("PGPKEY", attr->value, 6)==0) {
1142 | if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) {
1143 | fprintf(stderr, "E:<e_a_p>: No key-cert object.\n");
1144 | tr->error|=ERROR_U_OBJ;
1145 | tr->succeeded=0;
1146 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
1147 | return;
1148 | }
1149 | }
1150 | }
1151 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1152 | break;
1153 | case UD_LF_IF: /* for ifaddr tables*/
1154 | /* Convert ascii ip -> numeric one*/
1155 | convert_if(attr->value, &if_address);
1156 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address);
1157 | break;
1158 | case UD_LF_RF: /* for refer table*/
1159 | rf_host=convert_rf(attr->value, &rf_type, &rf_port);
1160 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
1161 | if(rf_host)free(rf_host);
1162 | break;
1163 | case UD_LF_AY: /* for auth_override table*/
1164 | sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
1165 | break;
1166 | default:
1167 | fprintf(stderr, "E: query not defined for this type of attribute\n");
1168 | tr->succeeded=0;
1169 | tr->error |= ERROR_U_BUG;
1170 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value);
1171 | return;
1172 | break;
1173 | }
1174 |
1175 | /* fprintf(stderr, "D: insert: [%s]", query); */
1176 |
1177 |
1178 | /* Make the query. For primary keys go straight to updates if we are updating the object */
1179 | if(do_query){
1180 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1181 | }
1182 | else {
1183 | update_attr(attr, tr);
1184 | return;
1185 | }
1186 |
1187 | /* fprintf(stderr, "D: query: %d rows affected\n", num);*/
1188 | if (sql_err) {
1189 | /* we received an error */
1190 | if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
1191 | if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
1192 | update_attr(attr, tr);
1193 | return;
1194 | }
1195 | /* Otherwise this is a duplicate attribute, just ignore it */
1196 | /* In the future if we are more stringent, checks may be added here */
1197 | }
1198 | else { /* Other errors reveal a database/server problem*/
1199 | sq_error=SQ_error(tr->sql_connection);
1200 | tr->error|=ERROR_U_DBS;
1201 | tr->succeeded=0;
1202 | fprintf(stderr, "E:<each_attribute_create>: %s: [%s]\n", sq_error, query);
1203 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
1204 | }
1205 | } /* if error occured */
1206 | else {
1207 | /* If the query was successful */
1208 | num = mysql_affected_rows(tr->sql_connection);
1209 | if(num>0){ /* this is OK*/
1210 | /* Do some additional processing for member_of attribute */
1211 | if ((attr->type == A_MO) && (tr->dummy!=1)){
1212 | /* fprintf(stderr, "D:<e_a_p>: need to auth membership\n");*/
1213 | if(auth_member_of(attr, tr)!=0){
1214 | tr->error|=ERROR_U_AUT;
1215 | tr->succeeded=0;
1216 | fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
1217 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
1218 | }
1219 | }
1220 | else
1221 | /* Do some additional processing for reverse zones domains */
1222 | if ((attr->type == A_DN)
1223 | && IP_revd_e2b(&dn_pref, attr->value)==IP_OK ) {
1224 |
1225 | if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
1226 | tr->error|=ERROR_U_DBS;
1227 | tr->succeeded=0;
1228 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1229 | ERROR_U_DBS, attr->type, attr->value,
1230 | SQ_error(tr->sql_connection));
1231 | }
1232 | else {
1233 | /* save data for the radix tree update */
1234 | RP_pack_set_revd(attr->type, attr->value, &data_pack);
1235 | tr->packptr = &data_pack;
1236 | }
1237 | }
1238 | return;
1239 | }
1240 | if(num == 0) {
1241 | /* this could be an empty update or a null select */
1242 | SQ_get_info(tr->sql_connection, sq_info);
1243 | if (sq_info[SQL_DUPLICATES]>0) {
1244 | if (sq_info[SQL_DUPLICATES]>1) {
1245 | fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query);
1246 | tr->error|=ERROR_U_DBS;
1247 | tr->succeeded=0;
1248 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value);
1249 | return;
1250 | }
1251 | update_attr(attr, tr);
1252 | }
1253 | else {
1254 |
1255 | /* try to create dummy and repeat original query*/
1256 |
1257 | /* fprintf(stderr, "W: no ref. integrity. Trying to create dummy...");*/
1258 |
1259 | dummy_err = create_dummy(attr, tr);
1260 | if (dummy_err == 0) {
1261 | /* fprintf(stderr, "D: ... dummy OK\n");*/
1262 | g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
1263 | /* fprintf(stderr, "D: repeating query: %s\n", query);*/
1264 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1265 | num = mysql_affected_rows(tr->sql_connection);
1266 | if (sql_err) {
1267 | sq_error=SQ_error(tr->sql_connection);
1268 | fprintf(stderr, "E: re-insert query:%s[%s]\n", sq_error, query);
1269 | tr->error|=ERROR_U_DBS;
1270 | tr->succeeded=0;
1271 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1272 | ERROR_U_DBS, attr->type, attr->value, sq_error);
1273 | }
1274 | if (num==0) {
1275 | fprintf(stderr, "E: re-insert query:%s[%s]\n", "", query);
1276 | tr->error|=ERROR_U_DBS;
1277 | tr->succeeded=0;
1278 | fprintf(stderr, "E: re-insert query: [%s]\n", query);
1279 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
1280 | ERROR_U_DBS, attr->type, attr->value);
1281 | }
1282 | }
1283 | else
1284 | if(dummy_err == 1) {
1285 | tr->error |= ERROR_U_OBJ;
1286 | tr->succeeded=0;
1287 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value);
1288 | }
1289 | else {
1290 | tr->error|=ERROR_U_DBS;
1291 | tr->succeeded=0;
1292 | fprintf(stderr, "E:<each_attribute_create>: dummy not created\n");
1293 | g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value);
1294 | }
1295 | } /* RI*/
1296 | }/* if num == 0*/
1297 | } /* if the query was successful */
1298 |
1299 | return;
1300 | } /* each_attribute_process() */
1301 |
1302 |
1303 |
1304 | /************************************************************
1305 | * each_primary_key_select() *
1306 | * *
1307 | * Function that forms a query for an object (w prinary keys)*
1308 | * Called from g_slist_foreach() function. *
1309 | * Primary keys are defined in Select[] array. *
1310 | * *
1311 | * Returns: Nothing. *
1312 | * *
1313 | *************************************************************/
1314 | static void each_primary_key_select(void *element_data, void *result_ptr)
1315 | {
1316 | Attribute_t *attr = element_data;
1317 | GString *result = (GString *)result_ptr;
1318 | const char *query_fmt;
1319 | unsigned int prefix, prefix_length;
1320 | unsigned int begin_in, end_in;
1321 | int begin_as, end_as;
1322 | ip_prefix_t prefstr;
1323 | ip_range_t rangstr;
1324 | ip_v6word_t i6_msb, i6_lsb;
1325 |
1326 | /* query_fmt = Select[attr->type].qry; */
1327 | query_fmt = DF_get_select_query(attr->type);
1328 |
1329 | /* fprintf(stderr, "D: qry fmt: %s\n", query_fmt);*/
1330 |
1331 | if (strcmp(query_fmt, "") != 0) {
1332 | switch (DF_get_select_query_type(attr->type)) {
1333 | case UD_MAIN_:
1334 | g_string_sprintfa(result, query_fmt, attr->value);
1335 | break;
1336 | case UD_MA_RT:
1337 | IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length);
1338 | g_string_sprintfa(result, query_fmt, prefix, prefix_length);
1339 | break;
1340 | case UD_MA_IN:
1341 | IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in);
1342 | g_string_sprintfa(result, query_fmt, begin_in, end_in);
1343 | break;
1344 | case UD_MA_I6:
1345 | IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length);
1346 | g_string_sprintfa(result, query_fmt, i6_msb, i6_lsb, prefix_length);
1347 | break;
1348 | case UD_MA_AK:
1349 | convert_as_range(attr->value, &begin_as, &end_as);
1350 | g_string_sprintfa(result, query_fmt, begin_as, end_as);
1351 | break;
1352 | default:
1353 | fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type);
1354 | die;
1355 |
1356 | break;
1357 | }
1358 | /* fprintf(stderr, "D: each_primary_key_select(): %s\n",result->str); */
1359 | }
1360 | }
1361 |
1362 | /************************************************************
1363 | * perform_create(const Object_t *obj, Transaction_t *tr) *
1364 | * *
1365 | * Procedure for creating a new object. *
1366 | * First inserts object into 'last' table and gets object_id.*
1367 | * Then processes all attributes. *
1368 | * *
1369 | * Returns: tr->succeeded: >0 success, 0 - error *
1370 | * Error code is stored in tr->error. *
1371 | * *
1372 | *************************************************************/
1373 | static int perform_create(Transaction_t *tr)
1374 | {
1375 | Object_t *obj=tr->object;
1376 | /* SQ_result_set_t *sql_result;*/
1377 | char *str;
1378 | static char query[STR_XXXL];
1379 | long timestamp;
1380 | int sql_err;
1381 |
1382 | str = (obj->object)->str;
1383 | timestamp=time(NULL);
1384 | tr->sequence_id=1; /* we start with 1*/
1385 | sprintf(query, "INSERT INTO last SET thread_id=0, timestamp=%ld, sequence_id=1, object_type=%d, object='%s' ",
1386 | timestamp, tr->class_type, str);
1387 |
1388 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1389 |
1390 | /* Check for affected rows. One row should be affected . */
1391 | /* num = mysql_affected_rows(tr->sql_connection); */
1392 | if (sql_err) {
1393 | tr->error|=ERROR_U_DBS;
1394 | tr->succeeded=0;
1395 | fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%s\n", SQ_error(tr->sql_connection));
1396 | g_string_sprintfa(tr->error_script,"E[%d][:]:%s\n" ,ERROR_U_DBS, SQ_error(tr->sql_connection));
1397 | }
1398 | else {
1399 | /* Get generated (autoincrement) object_id */
1400 | tr->object_id=mysql_insert_id(tr->sql_connection);
1401 | g_slist_foreach(obj->attributes, each_attribute_process, tr);
1402 | }
1403 | return(tr->succeeded);
1404 | } /* perform_create() */
1405 |
1406 | /************************************************************
1407 | * perform_update(Transaction_t *tr) *
1408 | * *
1409 | * Procedure for updating (existing) object. *
1410 | * First processes all attributes. *
1411 | * Then saves previous object in 'history' and updates *
1412 | * 'last' table. *
1413 | * *
1414 | * Returns: tr->succeeded: >0 success, 0 - error *
1415 | * Error code is stored in tr->error. *
1416 | * *
1417 | *************************************************************/
1418 | static int perform_update(Transaction_t *tr)
1419 | {
1420 | Object_t *obj=tr->object;
1421 | /*SQ_result_set_t * sql_result;*/
1422 | char *str;
1423 | static char query[STR_XXXL];
1424 | int num;
1425 | long sequence_id;
1426 | long timestamp;
1427 | char *sq_error;
1428 | int sql_err;
1429 |
1430 | /* process each attribute one by one */
1431 | g_slist_foreach(obj->attributes, each_attribute_process, tr);
1432 |
1433 | /* If we've already failed or this is fast load - just return */
1434 | if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded);
1435 |
1436 | /* No return: thread_id=0 */
1437 | /* Do it only if previous transactions finished well */
1438 |
1439 | /* copy object to the history table */
1440 | /*fprintf(stderr, "INSERT history\n"); */
1441 | sprintf(query,"INSERT history "
1442 | "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
1443 | "FROM last "
1444 | "WHERE object_id=%ld ", tr->object_id);
1445 |
1446 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1447 |
1448 | /* Check for affected rows. One row should be affected . */
1449 | num = mysql_affected_rows(tr->sql_connection);
1450 | if (num < 1) {
1451 | tr->error|=ERROR_U_DBS;
1452 | tr->succeeded=0;
1453 | if (sql_err) {
1454 | sq_error=SQ_error(tr->sql_connection);
1455 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]%s\n", num, query, sq_error);
1456 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed:%s\n" ,ERROR_U_DBS, sq_error);
1457 | }
1458 | else {
1459 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query);
1460 | g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS);
1461 | /* This is to check that this is really could happen */
1462 | die;
1463 | }
1464 | return(tr->succeeded);
1465 | }
1466 |
1467 | /* get sequence number */
1468 |
1469 | sequence_id = get_sequence_id(tr);
1470 | if(sequence_id==-1) {
1471 | fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id\n");
1472 | tr->error|=ERROR_U_DBS;
1473 | tr->succeeded=0;
1474 | g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS);
1475 | return(tr->succeeded);
1476 | }
1477 | else tr->sequence_id=sequence_id; /* save it for rollback*/
1478 |
1479 |
1480 | /* Insert new version into the last */
1481 |
1482 | /* Put a timestamp */
1483 | str = (obj->object)->str;
1484 | timestamp=time(NULL);
1485 | tr->sequence_id++;
1486 |
1487 | /*fprintf(stderr, "UPDATE last\n"); */
1488 | /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */
1489 | sprintf(query, "UPDATE last "
1490 | "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' "
1491 | "WHERE object_id=%ld ",
1492 | tr->sequence_id, timestamp, tr->class_type, str, tr->object_id);
1493 |
1494 | sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1495 |
1496 | /* Check for affected rows. One row should be affected */
1497 | num = mysql_affected_rows(tr->sql_connection);
1498 | if (num < 1) {
1499 | tr->error|=ERROR_U_DBS;
1500 | tr->succeeded=0;
1501 | if(sql_err) {
1502 | fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]%s\n", num, query, SQ_error(tr->sql_connection));
1503 | g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
1504 | }
1505 | else {
1506 | fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query);
1507 | g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed\n" ,ERROR_U_DBS);
1508 | /* This is to check that this is really could happen */
1509 | die;
1510 | }
1511 | return(tr->succeeded);
1512 | }
1513 | return(tr->succeeded);
1514 | } /* perform_update() */
1515 |
1516 |
1517 |
1518 |
1519 | /************************************************************
1520 | * int object_process(Transaction_t *tr) *
1521 | * *
1522 | * This is the interface between core and upper layer *
1523 | * All it gets is Transaction *tr, which contains all *
1524 | * necessary information, including the object in its *
1525 | * internal representation. *
1526 | * *
1527 | * Returns: tr->succeeded: >0 success, 0 - error *
1528 | * Error code is stored in tr->error. *
1529 | * *
1530 | *************************************************************/
1531 | int object_process(Transaction_t *tr)
1532 | {
1533 | int res;
1534 | char nic[MAX_NH_LENGTH];
1535 |
1536 | if(ACT_DELETE(tr->action)){
1537 | fprintf(stderr, "D: Action: Delete...");
1538 | delete(tr);
1539 | /* Commit nic-handle deletion to the repository */
1540 | if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1541 | res = NH_free(tr->nh, tr->sql_connection);
1542 | if(res == -1) {
1543 | tr->succeeded=0;
1544 | tr->error |= ERROR_U_DBS;
1545 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot delete nic-handle\n", ERROR_U_DBS);
1546 | return(tr->succeeded);
1547 | }
1548 | else if(res == 0) {
1549 | tr->succeeded=0;
1550 | tr->error |= ERROR_U_OBJ;
1551 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle not found\n", ERROR_U_OBJ);
1552 | return(tr->succeeded);
1553 | }
1554 | }
1555 | return(tr->succeeded); /*commit is not needed*/
1556 | }
1557 | else if(ACT_UPDATE(tr->action)){
1558 | fprintf(stderr, "D: Action: Update...");
1559 | perform_update(tr);
1560 | /* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/
1561 | if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1562 | /* convert nh to DB nIC handle before registration */
1563 | /* because there nh will bee freed */
1564 | NH_convert(nic, tr->nh);
1565 | res = NH_register(tr->nh, tr->sql_connection);
1566 | if(res == -1) {
1567 | tr->succeeded=0;
1568 | tr->error |= ERROR_U_DBS;
1569 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS);
1570 | }
1571 | else if(res == 0) {
1572 | tr->succeeded=0;
1573 | tr->error |= ERROR_U_OBJ;
1574 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ);
1575 | }
1576 | else { /* copy the NH to the report to return to DBupdate */
1577 | /* Convert nh to the database format */
1578 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1579 | }
1580 | }
1581 | }
1582 | else if(ACT_CREATE(tr->action)){
1583 | fprintf(stderr, "D: Action: Create...");
1584 | perform_create(tr);
1585 | /* Commit nic-handle allocation (if any) to the repository */
1586 | if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1587 | /* convert nh to DB nIC handle before registration */
1588 | /* because there nh will bee freed */
1589 | NH_convert(nic, tr->nh);
1590 | res = NH_register(tr->nh, tr->sql_connection);
1591 | if(res == -1) {
1592 | tr->succeeded=0;
1593 | tr->error |= ERROR_U_DBS;
1594 | g_string_sprintfa(tr->error_script,"E[%d][]:cannot allocate nic-handle\n", ERROR_U_DBS);
1595 | }
1596 | else if(res == 0) {
1597 | tr->succeeded=0;
1598 | tr->error |= ERROR_U_OBJ;
1599 | g_string_sprintfa(tr->error_script,"E[%d][]:nic-handle already in use\n", ERROR_U_OBJ);
1600 | }
1601 | else { /* copy the NH to the report to return to DBupdate */
1602 | g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1603 | }
1604 | }
1605 |
1606 | }
1607 | else {
1608 | fprintf(stderr, "D: Action: Unknown...");
1609 | tr->succeeded=0;
1610 | tr->error|=ERROR_U_BADOP;
1611 | return(tr->succeeded);
1612 | }
1613 |
1614 | if(tr->load_pass == 0) { /* not for fast loader*/
1615 | if (tr->succeeded == 1) {
1616 | /*fprintf(stderr, "D: Commit transaction...\n"); */
1617 | commit(tr);
1618 | }
1619 | else {
1620 | /*fprintf(stderr, "D: Roll back transaction...\n"); */
1621 | rollback(tr);
1622 | }
1623 | }
1624 | return(tr->succeeded);
1625 | } /* object_process() */
1626 |