## modules/ud/ud_core.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. convert_if
2. convert_rf
3. convert_as
4. convert_as_range
5. convert_time
6. get_set_name
7. get_object_id
8. get_qresult_str
9. get_field_str
10. get_sequence_id
11. get_ref_id
12. isdummy
13. isnichandle
14. process_reverse_domain
15. insert_reverse_domain
16. update_reverse_domain
17. auth_member_of
18. create_dummy
19. update_attr
20. each_attribute_process
21. each_primary_key_select
22. perform_create
23. perform_update
24. object_process

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

/* [<][>][^][v][top][bottom][index][help] */