1    | /***************************************
2    |   $Revision: 1.15 $
3    | 
4    |   Example code: Determine which keys to look for.
5    |   
6    |   This is based on the C code that was reversed engineered from existing Perl
7    |   code.  (~ottrey/which_table/which_table.c)
8    | 
9    |   ******************/ /******************
10   |   Copyright (c) 1999                              RIPE NCC
11   |  
12   |   All Rights Reserved
13   |   
14   |   Permission to use, copy, modify, and distribute this software and its
15   |   documentation for any purpose and without fee is hereby granted,
16   |   provided that the above copyright notice appear in all copies and that
17   |   both that copyright notice and this permission notice appear in
18   |   supporting documentation, and that the name of the author not be
19   |   used in advertising or publicity pertaining to distribution of the
20   |   software without specific, written prior permission.
21   |   
22   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
24   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
25   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
26   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
27   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28   |   ***************************************/
29   | #include <stdio.h>
30   | #include <stdlib.h>
31   | #include <strings.h>
32   | #include <libgen.h>
33   | #include <glib.h>
34   | 
35   | #include "isnic.h"
36   | #include "bitmask.h"
37   | #include "memwrap.h"
38   | 
39   | #define  WK_IMPL
40   | #include "which_keytypes.h"
41   | 
42   | 
43   | 
44   | #define DOMAINNAME "^[ ]*[a-zA-Z0-9--]*(\\.[a-zA-Z0-9--]+)*[ ]*$"
45   | /* add a constraint: there must be at least one character in the domain name
46   |    because the TLD must not be composed of digits only */
47   | #define DOMAINALPHA  "[a-zA-Z]"
48   | 
49   | #define LEN_MIN 0
50   | #define LEN_MAX 32
51   | 
52   | #define NETLEN 16
53   | #define NETQUADS 4
54   | #define NETQUAD_MIN 0
55   | #define NETQUAD_MAX 255
56   | 
57   | #define ASNUM_MIN 1
58   | #define ASNUM_MAX 65535
59   | #define ASNUM_NUMOFFSET 2   /* XXX - (This is really kludgy!) Offset to the number bit of ASNUM */
60   | 
61   | #define VALIDIP6PREFIX "^[0-9A-F:]*:[0-9A-F:/]*$"     /* at least one colon */
62   | /* "^[0-9A-F]{1,4}(:[0-9A-F]{1,4}){7}$"*/
63   | 
64   | #define NET "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
65   | 
66   | #define ASNUM "^AS[1-9]+[0-9]*$"
67   | 
68   | #define ASRANGE "^AS[0-9]+[ ]*([-][ ]*AS[0-9]+){0,1}$"   /* [ ]*(-[ ]*AS[0-9]+)?   */
69   | 
70   | #define NETNAME "^[A-Z][A-Z0-9-]*$"
71   | 
72   | #define MAINTAINER "^[A-Z][A-Z0-9-]*$"
73   | 
74   | #define LIMERICK "^LIM-[A-Z0-9-]+$"
75   | 
76   | #define KEYCERT "^PGPKEY-[0-9A-F]{8}$"
77   | 
78   | #define ROUTESETNAME "^RS-[A-Z0-9-_]*$"
79   | 
80   | #define ASSETNAME "^AS-[A-Z0-9-_]*$"
81   | 
82   | #define AUTONICPREFIXREGULAR "^AUTO-"
83   | 
84   | #define IPRANGE "^[0-9]{1,3}(\\.[0-9]{1,3}){0,3}[ ]*-[ ]*[0-9]{1,3}(\\.[0-9]{1,3}){0,3}$"
85   | 
86   | #define IPADDRESS "^[0-9.]+$"
87   | 
88   | #define IPPREFIX "^[0-9.]+/[0-9]+$"
89   | 
90   | #define PEERINGSET "^PRNG-"
91   | 
92   | #define FILTERSET  "^FLTR-"
93   | 
94   | #define RTRSET     "^RTRS-"
95   | 
96   | /*
97   |   XXX This seems to be the same as the Perl code.  But I don't see where a " " is allowed for.
98   |   I.e. Perl -> ^[a-zA-Z][\w\-\.\'\|\`]*$
99   |   Does \w include [ ;:,?/}{()+*#] ?
100  | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`-]*$"
101  | */
102  | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`;:,?/}{()+*#&-]*$"
103  | 
104  | #define VALIDIP4PREFIX
105  | 
106  | #define EMAIL "^[.a-zA-Z0-9--]*@[a-zA-Z0-9--]*(\\.[a-zA-Z0-9--]+)*$"
107  | 
108  | static int perform_regex_test(const char *pattern, char *string) {
109  |   int match;
110  | 
111  |   char *re;
112  | 
113  |   re = regcmp(pattern, (char*)0);
114  |   if (regex(re, string) == NULL) {
115  |     match = 0;
116  |   }
117  |   else {
118  |     match = 1;
119  |   }
120  | 
121  |   free(re); /* not a wrapper, because we have not allocated it */
122  | 
123  |   return match;
124  | } /* perform_regex_test() */
125  | 
126  | static int isasnum(char *string) {
127  |   int result='-';
128  |   int as_value;
129  | 
130  |   /* First check if the string matches an ASNUM */
131  |   result = perform_regex_test(ASNUM, string);
132  | 
133  |   /* Then check if the value is between ASNUM_MIN and ASNUM_MAX */
134  |   if (result == 1) {
135  |     as_value = atoi(string+ASNUM_NUMOFFSET);
136  |     if ((as_value < ASNUM_MIN) || (as_value > ASNUM_MAX)) {
137  |       /* an invalid value */
138  |       result=0;
139  |     }
140  |   }
141  |   
142  |   return result;
143  | }
144  | 
145  | /*******************************************************
146  |     # the problem is as follows:
147  |     #
148  |     # we can never find out which NIC handles are possible on the
149  |     # globe since we don't know that they exist
150  |     #
151  |     # we want to solve this with once with DNS :
152  |     #
153  |     # RIPE.registries.int     CNAME whois.ripe.net
154  |     # InterNIC.registries.int CNAME whois.internic.net
155  |     # and so on...
156  | 
157  |     #
158  |     # 1) it first does a basic syntax check
159  |     #
160  |     #    notes:
161  |     #
162  |     #    - catches InterNIC handles
163  |     #    - catches the JP|JP-JP APNIC exceptions
164  |     #    - limits the number of initials to three with a good reason:
165  |     #      we have a much better chance to find syntax errors like:
166  |     #      RIPE-DK13 and other problems like this
167  |     #
168  |     # 2) checks for valid suffixes
169  |     #    - all 'source:' attribute values from sites that we mirror
170  |     #      are allowed
171  |     #    - country codes are allowed for APNIC compatibility
172  |     #    - APNIC AP|CC-AU exceptions are handled correctly
173  |     #    - -ORG organization InterNIC handles
174  |     #    - -ARIN ARIN handles
175  |     #    - -ORG-ARIN ARIN handles
176  | ********************************************************/
177  | static int isnichandle(char *nichdl) {
178  | 
179  |   char *regexp, *match;
180  |   char ret[1024];
181  |   char *suffix;
182  | 
183  |   int i;
184  | 
185  | /* set ret to the empty string */
186  |   ret[0]='\0';
187  | 
188  | /* 
189  |   # Japanese NIC handles
190  |   #
191  |   # leading zeros in the number part *are* allowed
192  |   #
193  |   # e.g. AB021JP AB199JP-JP
194  |   #
195  | */
196  |   regexp = regcmp("[A-Z]{2}[0-9]{3}JP(-JP){0,1}",(char *)0);
197  |   match =  regex(regexp,nichdl);
198  |   free(regexp); /* not a wrapper, because we have not allocated it */
199  |   if (match) return 1;
200  | 
201  | /*
202  |   # Standard NIC handles
203  |   #
204  |   # leading zeros in the number part are *not* allowed
205  |   #
206  |   # InterNIC - TBQ, IP4
207  |   # RIPE format - AB1-RIPE
208  |   # APNIC use two letter country code suffix
209  |   # Austraila have used -1-AU, -2-AU, -CC-AU suffix.
210  |   # Internic used -ORG suffix
211  |   # ARIN use -ARIN suffix
212  |   # ARIN also use -ORG-ARIN suffix
213  |   #
214  | */
215  |   regexp = regcmp("^[A-Z]{2,4}([1-9][0-9]{0,5}){0,1}((-[^ ]+){0,1})$0$",(char *)0);
216  |   match =  regex(regexp,nichdl,ret);
217  | 
218  |   free(regexp); /* not a wrapper, because we have not allocated it */
219  | 
220  |   if (match == NULL) {
221  |     return 0;
222  |   } else {
223  |     if (ret[0] == '\0') {
224  |       return 1;
225  |     } else {
226  | /*   strip leading '-' */
227  |       suffix = ret+1;
228  | /* suffix of local sources */
229  |       for (i=0;i<=NUM_NICPOSTFIX;i++) {
230  |         if ( !strcmp(suffix,nicpostfix[i]) ) {
231  |           return 1;
232  |         }
233  |       }
234  | /* country codes */
235  |       for (i=0;i<NUM_COUNTRIES;i++) {
236  |         if ( !strcmp(suffix,countries[i]) ) {
237  |           return 1;
238  |         }
239  |       }
240  | /* special suffix */
241  |       for (i=0;i<NUM_SPECIAL;i++) {
242  |         if ( !strcmp(suffix,special[i]) ) {
243  |           return 1;
244  |         }
245  |       }
246  |     }
247  |   }
248  |   return 0;
249  | } /* isnichandle() */
250  | 
251  | static int isdomname(char *string) {
252  |     return (    perform_regex_test(DOMAINNAME, string)
253  | 	     && perform_regex_test(DOMAINALPHA, string));
254  | }
255  | 
256  | /*
257  |  I split the isname up into isname_a & isname_b.  And created isname_ab to join them together.
258  |   - So I can test it properly.  -ottrey
259  |  */
260  | static int isname_a(char *string) {
261  |     return perform_regex_test(AUTONICPREFIXREGULAR, string);
262  | }
263  | 
264  | static int isname_b(char *string) {
265  |     return perform_regex_test(NAME_B, string);
266  | }
267  | 
268  | static int isname_ab(char *string) {
269  |     return (isname_a(string) || isname_b(string));
270  | }
271  | 
272  | static int isnetname(char *string) {
273  |     return perform_regex_test(NETNAME, string);
274  | } /* wk_is_netname() */
275  | 
276  | static int wk_is_name(char *key) {
277  |     /* Everything matches to name */
278  |     return 1;
279  | } /* wk_is_name() */
280  | 
281  | static int wk_is_nic_hdl(char *key) {
282  |     return isnichandle(key);
283  | } /* wk_is_nic_hdl() */
284  | 
285  | static int wk_is_email(char *key) {
286  |     return perform_regex_test(EMAIL, key);
287  | } /* wk_is_email() */
288  | 
289  | static int wk_is_mntner(char *key) {
290  |     return perform_regex_test(MAINTAINER, key); 
291  | } /* wk_is_mntner() */
292  | 
293  | static int wk_is_key_cert(char *key) {
294  |     return perform_regex_test(KEYCERT, key);
295  | } /* wk_is_key_cert() */
296  | 
297  | static int wk_is_ipaddress(char *key) {
298  |     return perform_regex_test(IPADDRESS, key);
299  | } /* wk_is_key_cert() */
300  | 
301  | static int wk_is_iprange(char *key) {
302  |     return perform_regex_test(IPRANGE, key);
303  | } /* wk_is_iprange() */
304  | 
305  | static int wk_is_ipprefix(char *key) {
306  |     return perform_regex_test(IPPREFIX, key);
307  | } /* wk_is_iprange() */
308  | 
309  | static int wk_is_ip6prefix(char *key) {
310  |     return perform_regex_test(VALIDIP6PREFIX, key);
311  | } /* wk_is_ip6prefix() */
312  | 
313  | static int wk_is_netname(char *key) {
314  |     return isnetname(key);
315  | } /* wk_is_netname() */
316  | 
317  | /* XXX Note: This function uses the same call as wk_is_netname(). */
318  | static int wk_is_net6name(char *key) {
319  |     return isnetname(key);
320  | } /* wk_is_netname() */
321  | 
322  | static int wk_is_autnum(char *key) {
323  |     return isasnum(key);
324  | } /* wk_is_autnum() */
325  | 
326  | static int wk_is_asrange(char *key) {
327  |     return perform_regex_test(ASRANGE, key);
328  | } /* wk_is_autnum() */
329  | 
330  | static int wk_is_assetname(char *key) {
331  |     return perform_regex_test(ASSETNAME, key);
332  | } /* wk_is_assetname() */
333  | 
334  | static int wk_is_routesetname(char *key) {
335  |     return perform_regex_test(ROUTESETNAME, key);
336  | } /* wk_is_routesetname() */
337  | 
338  | static int wk_is_domain(char *key) {
339  |     return isdomname(key);
340  | } /* wk_is_domname() */
341  | 
342  | static int wk_is_hostname(char *key) {
343  |   /* XXX Why is there a hostname & a domainname? */
344  |   /* Answer - hostname can be a domainname or an IP */
345  |     return (isdomname(key) || wk_is_iprange(key));
346  | } /* wk_is_hostname() */
347  | 
348  | static int wk_is_limerick(char *key) {
349  |     return perform_regex_test(LIMERICK, key);
350  | } /* wk_is_limerick() */
351  | 
352  | static int wk_is_peeringset(char *key) {
353  |     return perform_regex_test(PEERINGSET, key);
354  | } /* wk_is_peeringset() */
355  | 
356  | static int wk_is_rtrset(char *key) {
357  |     return perform_regex_test(RTRSET, key);
358  | } /* wk_is_rtrset() */
359  | 
360  | static int wk_is_filterset(char *key) {
361  |     return perform_regex_test(FILTERSET, key);
362  | } /* wk_is_filterset() */
363  | 
364  | /* WK_to_string() */
365  | /*++++++++++++++++++++++++++++++++++++++
366  |   Convert the which keytypes bitmap into a string.
367  | 
368  |   mask_t wk The which keytypes mask to be converted.
369  | 
370  |   More:
371  |   +html+ <PRE>
372  |   Authors:
373  |         ottrey
374  |   +html+ </PRE><DL COMPACT>
375  |   +html+ <DT>Online References:
376  |   +html+ <DD><UL>
377  |   +html+ </UL></DL>
378  | 
379  |   ++++++++++++++++++++++++++++++++++++++*/
380  | char *WK_to_string(mask_t wk) {
381  | 
382  |   return MA_to_string(wk, Keytypes);
383  | 
384  | } /* WK_to_string() */
385  | 
386  | /* WK_new() */
387  | /*++++++++++++++++++++++++++++++++++++++
388  |   Create a new which keytypes bitmap.
389  | 
390  |   char *key The key to be examined.
391  | 
392  |   More:
393  |   +html+ <PRE>
394  |   Authors:
395  |         ottrey
396  |   +html+ </PRE><DL COMPACT>
397  |   +html+ <DT>Online References:
398  |   +html+ <DD><UL>
399  |   +html+ </UL></DL>
400  | 
401  |   ++++++++++++++++++++++++++++++++++++++*/
402  | mask_t WK_new(char *key) {
403  |   mask_t wk; 
404  | 
405  |   wk = MA_new(MA_END);
406  | 
407  |   MA_set(&wk, WK_NAME,         wk_is_name(key));
408  |   MA_set(&wk, WK_NIC_HDL,      wk_is_nic_hdl(key));
409  |   MA_set(&wk, WK_EMAIL,        wk_is_email(key));
410  |   MA_set(&wk, WK_MNTNER,       wk_is_mntner(key));
411  |   MA_set(&wk, WK_KEY_CERT,     wk_is_key_cert(key));
412  |   MA_set(&wk, WK_IPADDRESS,    wk_is_ipaddress(key));
413  |   MA_set(&wk, WK_IPRANGE,      wk_is_iprange(key));
414  |   MA_set(&wk, WK_IPPREFIX,     wk_is_ipprefix(key));
415  |   MA_set(&wk, WK_IP6PREFIX,    wk_is_ip6prefix(key));
416  |   MA_set(&wk, WK_NETNAME,      wk_is_netname(key));
417  |   MA_set(&wk, WK_NET6NAME,     wk_is_net6name(key));
418  |   MA_set(&wk, WK_AUTNUM,       wk_is_autnum(key));
419  |   MA_set(&wk, WK_ASSETNAME,    wk_is_assetname(key));
420  |   MA_set(&wk, WK_ROUTESETNAME, wk_is_routesetname(key));
421  |   MA_set(&wk, WK_DOMAIN,       wk_is_domain(key));
422  |   MA_set(&wk, WK_HOSTNAME,     wk_is_hostname(key));
423  |   MA_set(&wk, WK_LIMERICK,     wk_is_limerick(key));
424  |   MA_set(&wk, WK_ASRANGE,      wk_is_asrange(key));
425  |   MA_set(&wk, WK_PEERINGSET,   wk_is_peeringset(key));
426  |   MA_set(&wk, WK_FILTERSET,    wk_is_filterset(key));
427  |   MA_set(&wk, WK_RTRSET,       wk_is_rtrset(key));
428  |   
429  |   return wk;
430  | 
431  | } /* WK_new() */