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