1    | /***************************************
2    |   $Revision: 1.12 $
3    | 
4    |   UP external syntax checks
5    | 
6    |   Status: REVIEWED, NOT TESTED
7    | 
8    |   Author(s):       Engin Gunduz
9    | 
10   |   ******************/ /******************
11   |   Modification History:
12   |         engin (15/12/2000) Created.
13   |         denis (31/08/2001) Modified for new API
14   |   ******************/ /******************
15   |   Copyright (c) 2001,2002                         RIPE NCC
16   |  
17   |   All Rights Reserved
18   |   
19   |   Permission to use, copy, modify, and distribute this software and its
20   |   documentation for any purpose and without fee is hereby granted,
21   |   provided that the above copyright notice appear in all copies and that
22   |   both that copyright notice and this permission notice appear in
23   |   supporting documentation, and that the name of the author not be
24   |   used in advertising or publicity pertaining to distribution of the
25   |   software without specific, written prior permission.
26   |   
27   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
29   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
30   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
31   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33   |  ***************************************/
34   | 
35   | 
36   | /*#include "rpsl/object.hh"*/
37   | #include "UP_extrnl_syntax.h"
38   | #include "dbupdate.h"
39   | 
40   | #define UP_DATE_OK      0
41   | #define UP_DATE_SYNERR  1
42   | #define UP_DATE_FUTURE  2
43   | #define UP_DATE_TOOSMALL        3
44   | #define UP_DATE_INVMONTH        4
45   | #define UP_DATE_INVDAY  5
46   | #define UP_DATE_WRONGFORMAT 6
47   | #define UP_DATE_NOK    7
48   | 
49   | char * up_date_errmsgs[]=
50   | {
51   | 
52   |   "OK",
53   |   "Syntax error in date of 'changed' attribute",
54   |   "Date in the future in 'changed' attribute",
55   |   "Date is older than the database itself in 'changed' attribute",
56   |   "Invalid month in date in 'changed' attribute",
57   |   "Invalid day in date in 'changed' attribute",
58   |   "Date must be in YYYYMMDD format in 'change' attribute",
59   |   "Syntax error in date of 'changed' attribute"
60   | };
61   | 
62   | 
63   | extern int tracing;
64   | 
65   | extern char * fingerprint;
66   | extern char * keyowner;
67   | 
68   | extern char * allocmnt;
69   | 
70   | extern char    *sources[];
71   | extern char    *countries[];
72   | extern char    *nicsuffixes[];
73   | 
74   | 
75   | /* void up_check_source_attr 
76   |    checks for a valid source in the 'source' attributes */
77   | void up_check_source_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
78   | {
79   |   int valid,i ;
80   |   char *source_name;
81   |   char *temp;
82   |   GList *source_list;
83   |  
84   |   source_list = rpsl_object_get_attr(external_syntax_obj, "source");
85   | 
86   |   valid = i = 0 ;
87   |   if ( source_list )
88   |   {
89   |     source_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(source_list->data) );
90   |     while(sources[i])
91   |     {
92   |       if(strcasecmp(sources[i++],source_name) == 0)
93   |       {
94   |         valid = 1;
95   |         break;
96   |       }
97   |     }
98   |     free(source_name);
99   |     g_list_free(source_list);
100  |   }
101  | 
102  |   if (!valid)
103  |   {
104  |     /* the source is not recognised */
105  |     if (result->error_str == NULL)
106  | 	{
107  |       result->error_str = strdup("***Error: No such source");
108  |     }
109  | 	else
110  | 	{
111  |       temp = (char *)malloc(strlen(result->error_str) 
112  |               + strlen("***Error: No such source") + 2);
113  |       sprintf(temp, "%s\n%s", result->error_str, 
114  |               "***Error: No such source");
115  |       free(result->error_str);
116  |       result->error_str = temp;
117  |     }
118  |     /* and here we have to change the result code of "result" here ... */
119  |     switch (result->result)
120  | 	{
121  |       case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
122  |       case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
123  |       case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
124  |       case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
125  |       default: ;
126  |     }
127  |   }
128  | }
129  | 
130  | 
131  | /* void up_check_country_attr 
132  |    checks for a valid country in the 'country' attributes */
133  | void up_check_country_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
134  | {
135  |   int valid,i, matched ;
136  |   char *country_name;
137  |   char *temp;
138  |   GList *country_list = NULL;
139  |   GList *country_item = NULL;
140  |  
141  |   country_list = rpsl_object_get_attr(external_syntax_obj, "country");
142  |   
143  |   if ( country_list == NULL )
144  |     return;		/* only check if there is one */
145  | 
146  |   valid = 1 ;
147  |   for ( country_item = country_list; country_item != NULL ; country_item = g_list_next(country_item) )
148  |   {
149  |     country_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(country_item->data) );
150  |     matched = 0 ;
151  |     i = 0 ;
152  |     while(countries[i])
153  |     {
154  |       if(strcasecmp(countries[i++],country_name) == 0)
155  |       {
156  |         matched = 1;
157  |         break;
158  |       }
159  |     }
160  | 
161  |     if ( ! matched )
162  |     {
163  |       valid = 0 ;
164  |       break;
165  |     }
166  |     free(country_name);
167  |   }
168  |   g_list_free(country_list);
169  | 
170  |   if (!valid)
171  |   {
172  |     /* the country is not recognised */
173  |     if (result->error_str == NULL)
174  | 	{
175  |       result->error_str = malloc(strlen("***Error: No such country []") + strlen(country_name) +2);
176  |       sprintf(result->error_str, "***Error: No such country [%s]", country_name);
177  |     }
178  | 	else
179  | 	{
180  |       temp = (char *)malloc(strlen(result->error_str) 
181  |               + strlen("***Error: No such country []") + strlen(country_name) + 2);
182  |       sprintf(temp, "%s\n***Error: No such country [%s]", result->error_str, 
183  |               country_name);
184  |       free(result->error_str);
185  |       result->error_str = temp;
186  |     }
187  | 
188  |     free(country_name);
189  | 
190  |     /* and here we have to change the result code of "result" here ... */
191  |     switch (result->result)
192  | 	{
193  |       case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
194  |       case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
195  |       case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
196  |       case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
197  |       default: ;
198  |     }
199  |   }
200  | }
201  | 
202  | /* void up_check_nicsuffixes 
203  |    checks for a valid suffix at the end of a 'nic-hdl' attributes */
204  | void up_check_nicsuffixes(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
205  | {
206  |   int valid,i ;
207  |   char *name;
208  |   char *temp;
209  |   GList *list;
210  |  
211  |   list = rpsl_object_get_attr(external_syntax_obj, "nic-hdl");
212  | 
213  |   valid = i = 0 ;
214  |   if ( list )
215  |   {
216  |     name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(list->data) );
217  |     if ( !strchr(name,'-') || strncasecmp(name,"AUTO-",strlen("AUTO-")) == 0 )
218  |     {
219  |       valid = 1;
220  |     }
221  |     else
222  |     {
223  |       while (nicsuffixes[i])
224  |       {
225  |         if ( strcasecmp(nicsuffixes[i++],strchr(name,'-')+1) == 0 )
226  |         {
227  |           valid = 1;
228  |           break;
229  |         }
230  |       }
231  |       if ( ! valid )
232  |       {
233  |         i = 0;
234  |         while (sources[i])
235  |         {
236  |           if (strcasecmp(sources[i++],strchr(name,'-')+1) == 0 )
237  |           {
238  |             valid = 1;
239  |             break;
240  |           }
241  |         }
242  |         if ( ! valid )
243  |         {
244  |           i = 0;
245  |           while (countries[i])
246  |           {
247  |             if ( strcasecmp(countries[i++],strchr(name,'-')+1) == 0 )
248  |             {
249  |               valid = 1;
250  |               break;
251  |             }
252  |           }
253  |         }
254  |       }
255  |     }
256  |     free(name);
257  |     g_list_free(list);
258  | 
259  |     if (!valid)
260  |     {
261  |       /* the nicsuffix is not recognised */
262  |       if (result->error_str == NULL)
263  | 	  {
264  |         result->error_str = strdup("***Error: Invalid nic-hdl suffix");
265  |       }
266  | 	  else
267  | 	  {
268  |         temp = (char *)malloc(strlen(result->error_str) 
269  |                 + strlen("***Error: Invalid nic-hdl suffix") + 2);
270  |         sprintf(temp, "%s\n%s", result->error_str, 
271  |                 "***Error: Invalid nic-hdl suffix");
272  |         free(result->error_str);
273  |         result->error_str = temp;
274  |       }
275  |       /* and here we have to change the result code of "result" here ... */
276  |       switch (result->result)
277  | 	  {
278  |         case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
279  |         case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
280  |         case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
281  |         case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
282  |         default: ;
283  |       }
284  |     }
285  |   }
286  | }
287  | 
288  | 
289  | /* obtains a list of dates in the given 
290  |    list of attributes  */
291  | GList * up_get_dates(GList * attribute_list)
292  | {
293  |   GList * item;
294  |   char * str, *temp; 
295  |   GList * list = NULL;
296  | 
297  |   for ( item = attribute_list; item != NULL ; item = g_list_next(item) )
298  |   {
299  |     /* is this a 'changed' attribute? */
300  |     if ( strcmp(rpsl_attr_get_name((rpsl_attr_t *)(item->data)), "changed") == 0 )
301  | 	{
302  |       str = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
303  | 
304  | 
305  |       /* now, we have the 'changed' attribute's content in "normalized" form 
306  |          We are sure it contains a date. So, it must be the second (and last)
307  |          word in the attrib. */
308  |       assert(index(str,' ') != NULL);
309  |       temp = (char *)malloc(strlen(str) - (index(str,' ') - str ));
310  |       temp = strncpy(temp, index(str,' ') + 1, strlen(str) - (index(str,' ') - str ) - 1);
311  |       temp[strlen(str) - (index(str,' ') - str ) - 1] = '\0'; /* NULL terminate it */
312  |       list = g_list_append (list, temp);   
313  |     }
314  |   }
315  |   
316  |   return list;
317  | }
318  | 
319  | 
320  | 
321  | 
322  | /* Does the 'changed' attribute we got have a date already?
323  |    Returns 1 if it does, 0 if not. */
324  | int up_changed_has_date(char * value)
325  | {
326  |   /* now, if there is still a white space, then we have a date in the string
327  |      (it has to be something like "ripe-dbm@ripe.net 20001210") */
328  |   if (index(value, ' ') != NULL)
329  |   {
330  |     return 1; 
331  |   }
332  |   else
333  |   {
334  |     return 0;
335  |   }
336  | }
337  | 
338  | 
339  | 
340  | 
341  | /* supplies the current date in YYYYMMDD format (for example 20011010) */
342  | char * UP_get_current_date()
343  | {
344  |   /* We will use Glib's functions here */
345  | 
346  |   char * date;
347  |   struct tm * time_struct;
348  |   
349  |   time_t * time_loc;
350  | 
351  |   time_loc = (time_t *)malloc(sizeof(time_t));
352  |   time(time_loc);
353  |   
354  |   time_struct = localtime(time_loc);
355  | 
356  | 
357  |   date = (char *)malloc(9);
358  |   sprintf(date, "%04i%02i%02i", 
359  |           time_struct->tm_year + 1900, 
360  |           time_struct->tm_mon + 1,
361  |           time_struct->tm_mday);
362  |   return date;
363  | }
364  | 
365  | 
366  | 
367  | 
368  | /* int up_add_dates: adds dates to 'changed' attributes which 
369  |      are missing one.
370  |      Returns 1 if no problems encountered
371  |      Returns 0 if a problem encountered, and the error string is set */
372  | int up_add_dates(rpsl_object_t *external_syntax_obj, GList *attribute_list, char ** warning_str, char ** error_str)
373  | {
374  |   GList * item;
375  |   char * current_date;
376  |   int count_no_date = 0; 
377  |   char * temp;
378  |   rpsl_attr_t *changed;
379  |   char *value;
380  |   int pos;
381  |   
382  |   *warning_str = NULL;
383  |   *error_str   = NULL;
384  | 
385  |   /* get the current date in YYYYMMDD format (for example 20011010) */
386  |   current_date = UP_get_current_date();
387  |   
388  |   for ( item = attribute_list; item != NULL ; item = g_list_next(item) )
389  |   {
390  |     /* is this a 'changed' attribute? */
391  |     if (strcmp(rpsl_attr_get_name((rpsl_attr_t *)(item->data)), "changed") == 0)
392  | 	{
393  |       /* if this attribute does not have a date in it, add it. Also add 
394  |           a warning message about this */
395  | 	  value = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
396  |       if ( !up_changed_has_date(value) )
397  | 	  {
398  |         count_no_date++;
399  | 		/* create a copy of this changed attribute and add the date to the value */
400  | 		changed = rpsl_attr_copy((rpsl_attr_t *)(item->data));
401  |         temp = (char *)malloc(strlen(value) + strlen(current_date) + 2 );
402  |         sprintf(temp, "%s %s", value, current_date);
403  |         rpsl_attr_replace_value(changed, temp);
404  |         free(temp);
405  | 		/* delete the original attribute from the object */
406  | 		pos = rpsl_attr_get_ofs(changed);
407  | 		rpsl_object_remove_attr(external_syntax_obj, pos, NULL);
408  | 		/* add the new changed attribute in the same position */
409  | 		rpsl_object_add_attr(external_syntax_obj, changed, pos, NULL);
410  |         /* add a warning message */
411  |         if ( *warning_str == NULL)
412  | 		{
413  |           *warning_str = (char *)malloc(strlen("WARNING  date '' added to 'changed' attribute") + 9 );
414  |           sprintf(*warning_str, "WARNING  date '%s' added to 'changed' attribute", current_date);
415  |         }
416  | 		else
417  | 		{
418  |           temp = (char *)malloc(strlen(*warning_str) + 1 
419  |                                        + strlen("WARNING  date '' added to 'changed' attribute") + 9 );
420  |           sprintf(temp, "%s\nWARNING  date '%s' added to 'changed' attribute", 
421  |                               *warning_str, current_date);
422  |           free(*warning_str);
423  |           *warning_str = temp; 
424  |         }
425  |       }
426  | 	  free(value);
427  |     }
428  |   }
429  |   
430  |   if (count_no_date > 1)
431  |   { 
432  |     *error_str = strdup("***Error: More than one 'changed' attributes without dates");
433  |     return 0;
434  |   }
435  |   else
436  |   {
437  |     return 1;
438  |   }
439  | }
440  | 
441  | 
442  | 
443  | 
444  | /* Checks the order of dates in the given list. 
445  |    If they are in order, returns 1, 
446  |    if not, returns 0 */
447  | int up_check_date_order(GList * list)
448  | {
449  |   GList * item;
450  |   char * previous;
451  |   char *value;
452  | 
453  |   /* if list is empty, return 1 immediately */
454  |   if (list == NULL)
455  |   {
456  |     return 1;
457  |   }
458  | 
459  |   /* initialize the 'previous' date */
460  |   previous = strdup("00000000");
461  |    
462  |   for ( item = list; item != NULL ; item = g_list_next(item))
463  |   {
464  |     assert((item->data) != NULL);
465  |     /* if the new date is smaller than the previous */
466  | 	value = (char *)(item->data);
467  |     if ( strcmp(value, previous) < 0 )
468  | 	{
469  |       free(previous);
470  |       return 0;
471  |     }
472  |     free(previous);
473  |     previous = strdup(value);
474  |   }
475  |    
476  |   free(previous);
477  |   /* Reached the end, without finding out-of-order date. Return 1, then */
478  |   return 1; 
479  | }
480  | 
481  | 
482  | 
483  | 
484  | 
485  | /* up_check_date: checks the syntax of the date, given as the only
486  |    argument (char *). The argument is checked if it is in YYYYMMDD
487  |    format, and returns an error code accordingly */
488  | int up_check_date(const char * arg)
489  | {
490  |   int date_int; /* integer representation of the date (arg) */
491  |   char * current_date;
492  |   int year, month, day; /* integers for the components of the date */
493  | 
494  |   errno = 0;
495  |   date_int = atoi(arg);
496  |       
497  |   if (errno != 0)
498  |   { /* there was an error in the conversion, syntax error */
499  |     return UP_DATE_SYNERR;
500  |   }
501  |     
502  |   /* wrong format */
503  |   if (date_int <= 10000000 )
504  |   { /* the date is not in YYYYMMDD format */
505  |     return UP_DATE_WRONGFORMAT;
506  |   }
507  | 
508  |   /* check if it is too small */  
509  |   if (date_int <= 19880000 )
510  |   { /* the date is older than the DB itself! */
511  |     return UP_DATE_TOOSMALL;
512  |   }
513  | 
514  |   /* check if it is too big */
515  |   if (date_int >= 100000000 )
516  |   {/* too big: syntax error */
517  |     return UP_DATE_SYNERR;
518  |   }
519  | 
520  |   /* and now check year, month and day components */
521  |   year = date_int / 10000;
522  |   month = (date_int - (year * 10000) ) / 100;
523  |   day = (date_int % 100);
524  |   
525  |   /* check year */
526  |   if (year < 1988 )
527  |   {
528  |     return UP_DATE_TOOSMALL;
529  |   }
530  | 
531  |   /* check month */
532  |   if (month < 1 || month > 12)
533  |   {
534  |     return UP_DATE_INVMONTH;
535  |   }
536  | 
537  |   /* check day */
538  |   if (day < 1 || day > 31)
539  |   {
540  |     return UP_DATE_INVDAY;
541  |   }
542  | 
543  |   switch ( month )
544  |   {
545  |     case 1: case 3: case 5: case 7:
546  |     case 8: case 10: case 12:
547  |          if (day > 31)
548  | 		 {
549  |            return UP_DATE_INVDAY;
550  |          };
551  |          break;
552  |     case 2: 
553  |          if ( (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) && (day > 29 ))
554  | 		 { /* leap year */
555  |            return UP_DATE_INVDAY;
556  |          }
557  | 		 else if( (!(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) && (day > 28) )
558  | 		 { /* non-leap year */
559  |            return UP_DATE_INVDAY;
560  |          };
561  |          break;
562  |     case 4: case 6: case 9: case 11:
563  |          if (day > 30)
564  | 		 {
565  |            return UP_DATE_INVDAY;
566  |          };
567  |          break;
568  |     default: return UP_DATE_INVMONTH;
569  |   }
570  | 
571  |   /* check if the arg is in the future or not */
572  |   current_date = UP_get_current_date();
573  |   if (strcmp(current_date, arg) < 0 )
574  |   { /* arg is in the future */
575  |     free(current_date);
576  |     return UP_DATE_FUTURE;
577  |   }
578  |   free(current_date);
579  |     
580  |   return UP_DATE_OK;
581  | }
582  | 
583  | 
584  | 
585  | /* Checks the syntax of the dates in the list */
586  | date_syntax_struct * up_check_dates_syntax(GList * list)
587  | {
588  |   GList * item;
589  |   date_syntax_struct * result;
590  |   int res;
591  | 
592  |   /* initialize the result struct */
593  |   result = (date_syntax_struct *)malloc(sizeof(date_syntax_struct));
594  |   result->result = UP_DATE_OK;
595  |   result->error_str = NULL;
596  | 
597  |   /* if list is empty, return immediately */
598  |   if (list == NULL)
599  |   {
600  |     return result;
601  |   }
602  | 
603  |   /* loop through the members of the list, check each of them */
604  |   for ( item = list; item != NULL ; item = g_list_next(item))
605  |   {
606  |     assert((item->data) != NULL);
607  |     
608  |     /* check the date */
609  |     res = up_check_date((char *)(item->data));
610  |     switch (res)
611  | 	{
612  |       case UP_DATE_OK: break;
613  |       
614  |       case UP_DATE_FUTURE:
615  |       case UP_DATE_TOOSMALL:
616  |       case UP_DATE_INVDAY:
617  |       case UP_DATE_INVMONTH:
618  |       case UP_DATE_WRONGFORMAT:
619  | 
620  |              if (result->error_str == NULL)
621  | 			 {
622  |                result->error_str = (char *)malloc(strlen("***Error: ") + strlen(up_date_errmsgs[res]) 
623  |                                                   + strlen(": ") + strlen((char *)(item->data)) + 1);
624  |                sprintf(result->error_str, "***Error: %s: %s", up_date_errmsgs[res],
625  |                        (char *)(item->data));
626  |              }
627  | 			 else
628  | 			 {
629  |                result->error_str = (char *)realloc(result->error_str, strlen(result->error_str) + 1 
630  |                                                    + strlen("***Error: ") + strlen(up_date_errmsgs[res]) 
631  |                                                    + strlen(": ") + strlen((char *)(item->data)) + 1);
632  |                sprintf(result->error_str, "%s\n***Error: %s: %s",
633  |                        result->error_str, up_date_errmsgs[res], (char *)(item->data));
634  |              }
635  |              result->result = UP_DATE_NOK; /* Not OK */
636  | 
637  |              break;
638  |              
639  |              
640  |       case UP_DATE_SYNERR: /* syntax error in the date */
641  | 
642  |       default:
643  |              if (result->error_str == NULL)
644  | 			 {
645  |                result->error_str = (char *)malloc(strlen("***Error: ") + strlen(up_date_errmsgs[UP_DATE_SYNERR]) 
646  |                                                   + strlen(": ") + strlen((char *)(item->data)) + 1);
647  |                sprintf(result->error_str, "***Error: %s: %s", up_date_errmsgs[UP_DATE_SYNERR],
648  |                        (char *)(item->data));
649  |              }
650  | 			 else
651  | 			 {
652  |                result->error_str = (char *)realloc(result->error_str, strlen(result->error_str) + 1 
653  |                                                    + strlen("***Error: ") + strlen(up_date_errmsgs[UP_DATE_SYNERR]) 
654  |                                                    + strlen(": ") + strlen((char *)(item->data)) + 1);
655  |                sprintf(result->error_str, "%s\n***Error: %s: %s",
656  |                        result->error_str, up_date_errmsgs[UP_DATE_SYNERR], (char *)(item->data));
657  |              }
658  |              result->result = UP_DATE_NOK; /* Not OK */
659  |              break;
660  |     }
661  |   }
662  |   
663  |   return result;
664  | }
665  | 
666  | 
667  | 
668  | /* void up_check_changed_attr 
669  |    checks the order of dates in the 'changed' attributes */
670  | void up_check_changed_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
671  | {
672  |   GList * date_list;
673  |   int res;
674  |   char ** warning, **error;
675  |   char * temp;
676  |   date_syntax_struct * date_check_res;
677  |   GList *changed_list;
678  | 
679  |   warning = (char **)malloc(sizeof(char **));
680  |   error   = (char **)malloc(sizeof(char **));
681  |   changed_list = rpsl_object_get_attr(external_syntax_obj, "changed");
682  | 
683  |   /* Now, add dates to the "changed" attributes */
684  |   res = up_add_dates(external_syntax_obj, changed_list, warning, error);
685  |   if (!res)
686  |   {
687  |     /* so, add the error string to result's error string */
688  |     if (result->error_str == NULL)
689  | 	{
690  |       result->error_str = strdup(*error);
691  |     }
692  | 	else
693  | 	{
694  |       temp = (char *)malloc(strlen(result->error_str) + strlen(*error) + 2);
695  |       sprintf(temp, "%s\n%s", result->error_str, *error);
696  |       free(result->error_str);
697  |       result->error_str = temp;
698  |     }
699  |   }
700  | 
701  |   /* and get the list of dates, we must check their order */
702  |   /* we may have added a date to one of the changed attrs so get the list again */
703  |   rpsl_attr_delete_list(changed_list);
704  |   changed_list = rpsl_object_get_attr(external_syntax_obj, "changed");
705  |   date_list = up_get_dates(changed_list);
706  |   /* and check the order */ 
707  |   res = up_check_date_order(date_list);
708  |   if (!res)
709  |   {
710  |     /* so, add the error string to result's error string */
711  |     if (result->error_str == NULL)
712  | 	{
713  |       result->error_str = strdup("***Error: The dates in the 'changed' attributes should be in order");
714  |     }
715  | 	else
716  | 	{
717  |       temp = (char *)malloc(strlen(result->error_str) 
718  |               + strlen("***Error: The dates in the 'changed' attributes should be in order") + 2);
719  |       sprintf(temp, "%s\n%s", result->error_str, 
720  |               "***Error: The dates in the 'changed' attributes should be in order");
721  |       free(result->error_str);
722  |       result->error_str = temp;
723  |     }
724  |     /* and here we have to change the result code of "result" here ... */
725  |     switch (result->result)
726  | 	{
727  |       case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
728  |       case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
729  |       case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
730  |       case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
731  |       default: ;
732  |     }
733  |   }
734  | 
735  |   /* check the syntax of dates */
736  |   date_check_res = up_check_dates_syntax(date_list);
737  |   if (date_check_res->result != UP_DATE_OK)
738  |   {
739  |     /* so, add the error string to result's error string */
740  |     if (result->error_str == NULL)
741  | 	{
742  |       result->error_str = strdup(date_check_res->error_str);
743  |     }
744  | 	else
745  | 	{
746  |       temp = (char *)malloc(strlen(result->error_str) 
747  |               + strlen(date_check_res->error_str) + 2);
748  |       sprintf(temp, "%s\n%s", result->error_str, 
749  |               date_check_res->error_str);
750  |       free(result->error_str);
751  |       result->error_str = temp;
752  |     }
753  |     /* and here we have to change the result code of "result" here ... */
754  |     switch (result->result)
755  | 	{
756  |       case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
757  |       case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
758  |       case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
759  |       case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
760  |       default: ;
761  |     }
762  |   }
763  | }
764  | 
765  | 
766  | /* performs a simple check on a inetnum attribute. Assumes that
767  |    the RPSL parser has already checked it. Tries to see if the attr
768  |    is a range or not  */
769  | int up_check_an_inetnum_attr(const char * arg){
770  |   
771  | 
772  |   char * str;
773  |   char * pos;
774  | 
775  |   str = strdup(arg);
776  | 
777  |   while((pos = index(str, '\n')) != NULL){
778  |     *pos = ' ';
779  |   }
780  | 
781  |   /* strip off the comment */
782  |   if((pos = index(str, '#')) != NULL){
783  |     *pos = '\0';
784  |   }
785  |    
786  |    
787  |   /* Most of the syntax check is done by RPSL parser. We only need to check
788  |      that the argument is a _range_ of IPv4 addresses. So it suffices to
789  |      check the existence of '-' in the arg */
790  |   if(index(str, '-') != NULL){
791  |     
792  |     free(str);
793  |     return 1;
794  |     
795  |   }else{
796  | 
797  |     free(str);
798  |     return 0;
799  | 
800  |   }
801  | }
802  | 
803  | 
804  | 
805  | /* Performs a check on status attribute. It can be
806  |    ALLOCATED PI or ALLOCATED PA only if the maintainers in the
807  |    mnt-by attribute contain at least one of the names mentioned in
808  |    ALLOCMNT config variable. 
809  | */
810  | int up_check_a_status_attr(const char * arg, GList * mnt_by_list)
811  | {
812  |   GList * item;
813  |   int result;
814  |   char * status, * mnt_by_attrib;
815  |   char ** allocmnt_list;
816  |   int i;
817  | 
818  |   status = strdup(arg);
819  |   g_strdown(status);
820  |  
821  |   /* construct a list of mntners that are in allocmnt */
822  |   allocmnt_list = g_strsplit(allocmnt, " ", 0); /* delimited by " " */
823  |    
824  |   if (strstr(status, "allocated") != NULL)
825  |   { 
826  |     result = 1; /* initialize */
827  |     
828  |     for ( item = mnt_by_list; item != NULL ; item = g_list_next(item) )
829  | 	{
830  |       mnt_by_attrib = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
831  |       for (i=0; allocmnt_list[i] != NULL; i++)
832  | 	  { /* loop thru the list of allocmnt maintainers */
833  |         if ((strlen(allocmnt_list[i]) != 0) && strcasecmp(mnt_by_attrib, allocmnt_list[i]) == 0)
834  | 		{
835  |           result = 0; 
836  |         }
837  |       }  
838  |       free(mnt_by_attrib);
839  |     }
840  |     
841  |     free(status);
842  |     g_strfreev(allocmnt_list);
843  |     return result;
844  |  
845  |   }
846  |   else
847  |   {  /* the status attribute is not allocated */
848  |     free(status);
849  |     g_strfreev(allocmnt_list);
850  |     return 0; /* so there is no problem */
851  | 
852  |   }
853  | 
854  | }
855  | 
856  | 
857  | 
858  | 
859  | 
860  | /* check for status attribute here: The status attribute can be
861  |    ALLOCATED PI or ALLOCATED PA only if the maintainers in the
862  |    mnt-by attribute contain at least one of the names mentioned in
863  |    ALLOCMNT config variable. 
864  | */
865  | void up_check_status_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
866  | {
867  |   int res;
868  |   char * temp;
869  |   char *value;
870  |   GList * item;
871  |   GList * mnt_by_list = NULL;
872  |   GList *status_list = NULL;
873  | 
874  |   /* Gather a list of mnt-by attributes */
875  |   mnt_by_list = rpsl_object_get_attr(external_syntax_obj, "mnt-by");
876  |   status_list = rpsl_object_get_attr(external_syntax_obj, "status");
877  | 
878  |   /* check the syntax */
879  |   for ( item = status_list; item != NULL ; item = g_list_next(item) )
880  |   {
881  |       value = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
882  |       res = up_check_a_status_attr(value, mnt_by_list);
883  |       if (res != 0)
884  | 	  { /* there was a problem */
885  |         /* so, add the error string to result's error string */
886  |         if (result->error_str == NULL)
887  | 		{
888  |           result->error_str = (char *)UT_malloc(strlen("***Error: Status ALLOCATED can be set only by the following mntner(s):\n")
889  |                                                 +strlen("***Error:    ") + strlen(allocmnt) + 2);
890  |           sprintf(result->error_str, "%s%s%s", "***Error: Status ALLOCATED can be set only by the following mntner(s):\n",
891  |                                                "***Error:    ", allocmnt);
892  |         }
893  | 		else
894  | 		{
895  |           temp = (char *)malloc(strlen(result->error_str) 
896  |                   + strlen("***Error: Status ALLOCATED can be set only by the following mntner(s):\n") 
897  |                   + strlen("***Error:    ") + strlen(allocmnt) + 2);
898  |           sprintf(temp, "%s\n%s%s%s", result->error_str, 
899  |                   "***Error: Status ALLOCATED can be set only by the following mntner(s):\n",
900  |                   "***Error:    ", allocmnt);
901  |           free(result->error_str);
902  |           result->error_str = temp;
903  |         }
904  |         /* and here we have to change the result code of "result" here ... */
905  |         switch (result->result)
906  | 		{
907  |           case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
908  |           case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
909  |           case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
910  |           case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
911  |           default: ;
912  |         }
913  |       }
914  | 	  free(value);
915  |   }
916  |   rpsl_attr_delete_list(mnt_by_list);
917  |   rpsl_attr_delete_list(status_list);
918  | }
919  | 
920  | 
921  | 
922  | 
923  | /* void up_add_keycert_attrs
924  |    adds the generated attrs of key-cert objects */
925  | void up_add_keycert_attrs(rpsl_object_t *generated_obj)
926  | {
927  |   const char *type;
928  |   char *attr_str;
929  |   rpsl_attr_t *method_attr;
930  |   rpsl_attr_t *owner_attr;
931  |   rpsl_attr_t *fingerpr_attr;
932  | 
933  |   if (tracing)
934  |   {
935  |     printf("TRACING: UP_add_keycert_attrs: is running\n");
936  |   }
937  |   
938  |   /* if this is a key-cert object */
939  |   type = rpsl_object_get_class(generated_obj);
940  |   if ( strcmp(type, "key-cert") == 0 )
941  |   {
942  |       method_attr = rpsl_attr_init("method: PGP", type);
943  | 	  if ( method_attr )
944  |       {
945  |     	rpsl_object_add_attr(generated_obj, method_attr, 1, NULL);
946  | 	  }
947  | 
948  |       attr_str = (char *)malloc( sizeof("owner: ") + strlen(keyowner) +1 );
949  | 	  strcpy(attr_str, "owner: ");
950  | 	  strcat(attr_str, keyowner);
951  |       if (tracing)
952  |       {
953  |         printf("TRACING: UP_add_keycert_attrs: owner attr_str [%s]\n", attr_str);
954  |       }
955  |       owner_attr = rpsl_attr_init(attr_str, "key-cert");
956  | 	  if ( owner_attr )
957  |       {
958  |     	rpsl_object_add_attr(generated_obj, owner_attr, 2, NULL);
959  | 	  }
960  |       free(attr_str);
961  | 
962  |       attr_str = (char *)malloc( sizeof("fingerpr: ") + strlen(fingerprint) +1 );
963  | 	  strcpy(attr_str, "fingerpr: ");
964  | 	  strcat(attr_str, fingerprint);
965  |       if (tracing)
966  |       {
967  |         printf("TRACING: UP_add_keycert_attrs: fingerprint attr_str [%s]\n", attr_str);
968  |       }
969  |       fingerpr_attr = rpsl_attr_init(attr_str, "key-cert");
970  | 	  if ( fingerpr_attr )
971  |       {
972  |     	rpsl_object_add_attr(generated_obj, fingerpr_attr, 3, NULL);
973  | 	  }
974  |       free(attr_str);
975  |   }
976  | }
977  | 
978  | 
979  | 
980  | /* Constructs a list of all attributes of an object, and returns it
981  |    as a list of attribute_struct */
982  | /*GSList * up_get_attribute_list(Object * o, char * text){
983  | 
984  |   char * value = NULL;
985  |   char * type = NULL;
986  |   Attr *attr;
987  |   GSList *list_of_attributes = NULL;
988  |   attribute_struct * attribute;
989  |   
990  |   for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
991  |     value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
992  |     strncpy(value, (char *)(text+attr->offset) + strlen(attr->type->name())+1,
993  |         attr->len - strlen(attr->type->name()) -2 );
994  |     value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
995  |       if(tracing) {
996  |         cout << "TRACING: up_get_attributes: adding " << g_strstrip(value) << endl;
997  |       }
998  |       attribute = (attribute_struct *)malloc(sizeof(attribute_struct)); 
999  |       attribute->content = value;
1000 |       type = strdup(attr->type->name());
1001 |       g_strdown(type);
1002 |       attribute->type = type;
1003 |       list_of_attributes = g_slist_append(list_of_attributes, attribute);
1004 |   }
1005 | 
1006 |   
1007 |   return list_of_attributes; 
1008 | 
1009 | }
1010 | */
1011 | 
1012 | 
1013 | /* up_reconstruct_object: Reconstructs the object's text representation
1014 |      using the parsed object */
1015 | void up_reconstruct_object(rpsl_object_t *external_syntax_obj, external_syntax_struct *result)
1016 | {
1017 |   char * recons_obj = NULL;
1018 |   
1019 |   recons_obj = rpsl_object_get_text(external_syntax_obj,RPSL_STD_COLUMN);
1020 | 
1021 |   result->new_obj = recons_obj;
1022 | }
1023 | 
1024 | 
1025 | 
1026 | /*  UP_check_external_syntax: Checks the syntax of attributes which are not checked
1027 |        by RAToolSet syntax checker. */
1028 | external_syntax_struct * UP_check_external_syntax(rpsl_object_t *external_syntax_obj)
1029 | {
1030 |   external_syntax_struct *result;
1031 |   
1032 |   if (tracing)
1033 |   {                                
1034 | 	printf("TRACING: UP_check_external_syntax running\n");
1035 |   }
1036 | 
1037 |   result = (external_syntax_struct *)malloc(sizeof(external_syntax_struct));
1038 | 
1039 |   /* initialize the struct */
1040 |   result->result = 0;
1041 |   result->error_str = strdup(""); 
1042 |   result->warning_str = strdup("");
1043 | 
1044 |   up_check_source_attr(external_syntax_obj, result);
1045 | 
1046 |   up_check_country_attr(external_syntax_obj, result);
1047 | 
1048 |   up_check_nicsuffixes(external_syntax_obj, result);
1049 | 
1050 |   up_check_changed_attr(external_syntax_obj, result);
1051 | 
1052 | /* this will be done by the new API parser */
1053 | /*  up_check_auth_attr   (arg, obj_text, attribute_list, result);  */ 
1054 | 
1055 | /* this will be done by the new API parser */
1056 | /*  up_check_inetnum_attr(arg, obj_text, attribute_list, result); */
1057 | 
1058 |   up_check_status_attr(external_syntax_obj, result);
1059 |   
1060 |   
1061 |   up_reconstruct_object(external_syntax_obj, result);
1062 | 
1063 |   if (tracing)
1064 |   {
1065 |     printf("TRACING: UP_check_external_syntax: the reconstructed object is=[%s]\n", result->new_obj);
1066 |     printf("TRACING: UP_check_external_syntax: ... and the result code is=[%i]\n", result->result);
1067 |   }
1068 | 
1069 |   return result;  
1070 | }
1071 | 
1072 | 
1073 | 
1074 | /* generates the "generated" attributes of a key-cert object. Returns the 
1075 |    new object string*/
1076 | char *UP_generate_kc_attrs(rpsl_object_t *generated_obj)
1077 | {
1078 |   external_syntax_struct *result;
1079 |   char *obj_str;
1080 | 
1081 |   if (tracing)
1082 |   {
1083 |     printf("TRACING: UP_generate_kc_attrs: is running\n");
1084 |   }
1085 | 
1086 |   result = (external_syntax_struct *)malloc(sizeof(external_syntax_struct));
1087 | 
1088 |   /* initialize the struct */
1089 |   result->result = 0;
1090 |   result->error_str = strdup(""); 
1091 |   result->warning_str = strdup("");
1092 | 
1093 |   up_check_changed_attr(generated_obj, result);
1094 |   up_add_keycert_attrs(generated_obj); 
1095 |   
1096 |   up_reconstruct_object(generated_obj, result);
1097 | 
1098 |   if (tracing)
1099 |   {
1100 |     printf("TRACING: UP_generate_kc_attrs: the reconstructed object is=[%s]\n", result->new_obj);
1101 |     printf("TRACING: UP_generate_kc_attrs: ... and the result code is=[%i]\n", result->result);
1102 |   }
1103 | 
1104 |   obj_str = strdup(result->new_obj);
1105 |   free(result);
1106 |   return obj_str;  
1107 | }
1108 | 
1109 | 
1110 | 
1111 | /* char * up_assign_i6_status: Determines the status attribute of
1112 |     an inet6num object. It takes the inet6num attribute of the
1113 |     object as its only argument. If prefix length is less than
1114 |     4, then returns NULL */
1115 | char * up_assign_i6_status(const char * inet6num_attr)
1116 | {
1117 | 
1118 |   char ** split_str;
1119 |   int prefix_length;
1120 |   int result;
1121 | 
1122 |   /* we need the prefix length here.*/
1123 |   split_str = g_strsplit(inet6num_attr, "/", 0);
1124 |   if(split_str[1] != NULL){
1125 | 
1126 |     result = sscanf(split_str[1], "%i", &prefix_length);
1127 |     if(result != 0 && result != EOF){
1128 | 
1129 |       if(prefix_length >= 0 && prefix_length <= 3){
1130 | 
1131 |         g_strfreev(split_str); 
1132 |         return NULL;
1133 |         
1134 |       }else if(prefix_length >= 4 && prefix_length <= 15){
1135 | 
1136 |         g_strfreev(split_str); 
1137 |         return strdup("TLA");
1138 |         
1139 |       }else if(prefix_length >= 16 && prefix_length <= 35){
1140 | 
1141 |         g_strfreev(split_str); 
1142 |         return strdup("SUBTLA");
1143 |         
1144 |       }else if(prefix_length >= 36 && prefix_length <= 48){
1145 | 
1146 |         g_strfreev(split_str); 
1147 |         return strdup("NLA");
1148 |    
1149 |       }else if(prefix_length >= 48 && prefix_length <= 64){
1150 | 
1151 |         g_strfreev(split_str); 
1152 |         return strdup("SLA");
1153 |         
1154 |       }else{
1155 | 
1156 |         /* "default" status */
1157 |         g_strfreev(split_str); 
1158 |         return strdup("SLA");
1159 |         
1160 |       }
1161 |       
1162 |     }else{
1163 |       
1164 |       /* return "default" status */
1165 |       g_strfreev(split_str);
1166 |       return strdup("SLA");
1167 |       
1168 |     }
1169 |   }else{
1170 |     
1171 |     /* return "default" status */
1172 |     g_strfreev(split_str);
1173 |     return strdup("SLA");
1174 | 
1175 |   }
1176 |   
1177 | }
1178 | 
1179 | 
1180 | 
1181 | /* GSList * up_add_inet6num_attrs
1182 |    adds the generated attrs of inet6num objects */
1183 | /*GSList * up_add_inet6num_attrs(Object * obj, char * obj_text, GSList * attribute_list, 
1184 |                                external_syntax_struct * result)*/
1185 | void up_add_inet6num_attrs(rpsl_object_t *generated_obj)                               
1186 | {
1187 | 
1188 |   int attribute_no;
1189 |   char *status_value;
1190 |   rpsl_attr_t * status_attr;
1191 |   char *inet6num_attr_str, *status_attr_str;
1192 |   const char *type;
1193 |   GList *attributes_changed;
1194 |   
1195 | 
1196 | 
1197 |   /* if this is an inet6num  object */
1198 |   type = rpsl_object_get_class(generated_obj);
1199 |   if( ! strcmp(type, "inet6num") )
1200 |   {
1201 |       inet6num_attr_str = get_search_key(generated_obj, "inet6num");
1202 |       status_value = up_assign_i6_status(inet6num_attr_str);
1203 |       status_attr_str = (char *)UT_malloc(strlen("status: ") + strlen(status_value) + 1);
1204 |       strcpy(status_attr_str, "status: ");
1205 |       strcat(status_attr_str, status_value);
1206 |       status_attr = rpsl_attr_init(status_attr_str, type);
1207 | 	  free(status_attr_str);
1208 | 	  if ( status_attr )
1209 |       {
1210 |     	/* we will put the status attribute before the first 'changed' attribute */
1211 |     	attribute_no = 1; /* a default position (the second attribute) in case we cannot find
1212 |                         	 a 'changed' attribute */    
1213 |     	attributes_changed = rpsl_object_get_attr(generated_obj, "changed");    
1214 |     	if ( attributes_changed != NULL )
1215 | 		{
1216 |           attribute_no = ((rpsl_attr_t *)(attributes_changed->data))->num;
1217 |     	}
1218 |     	rpsl_object_add_attr(generated_obj, status_attr, attribute_no, NULL);
1219 |       }
1220 |   }
1221 | }
1222 | 
1223 | 
1224 | 
1225 | /* generates the "generated" attribute (status) of an inet6num object. Returns the 
1226 |    new object as a char * */
1227 | char *UP_generate_i6_attrs(rpsl_object_t *generated_obj)
1228 | {
1229 |   
1230 |   external_syntax_struct *result;
1231 |   char *obj_str; 
1232 | 
1233 |   result = (external_syntax_struct *)malloc(sizeof(external_syntax_struct));
1234 | 
1235 |   /* initialize the struct */
1236 |   result->result = 0;
1237 |   result->error_str = strdup("");
1238 |   result->warning_str = strdup("");
1239 | 
1240 | 
1241 |   up_check_changed_attr(generated_obj, result);
1242 |   up_add_inet6num_attrs(generated_obj);
1243 |   
1244 |   up_reconstruct_object(generated_obj, result);
1245 | 
1246 |   if (tracing)
1247 |   {
1248 |     printf("TRACING: UP_generate_i6_attrs: the reconstructed object is=[%s]\n", result->new_obj);
1249 |     printf("TRACING: UP_generate_i6_attrs: ... and the result code is=[%i]\n", result->result);
1250 |   }
1251 | 
1252 |   obj_str = strdup(result->new_obj);
1253 |   free(result->error_str);
1254 |   free(result->warning_str);
1255 |   free(result->new_obj);
1256 |   free(result);
1257 |   return obj_str;
1258 | }
1259 |