1 | /***************************************
2 | $Revision: 1.13 $
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 NETNAME "^[A-Z][A-Z0-9-]*$"
69 |
70 | #define MAINTAINER "^[A-Z][A-Z0-9-]*$"
71 |
72 | #define LIMERICK "^LIM-[A-Z0-9-]+$"
73 |
74 | #define KEYCERT "^PGPKEY-[0-9A-F]{8}$"
75 |
76 | #define ROUTESETNAME "^RS-[A-Z0-9-]*$"
77 |
78 | #define ASSETNAME "^AS-[A-Z0-9-]*$"
79 |
80 | #define AUTONICPREFIXREGULAR "^AUTO-"
81 |
82 | #define IPRANGE "^[0-9]{1,3}(\\.[0-9]{1,3}){0,3}[ ]+-[ ]+[0-9]{1,3}(\\.[0-9]{1,3}){0,3}$"
83 |
84 | #define IPADDRESS "^[0-9.]+$"
85 |
86 | #define IPPREFIX "^[0-9.]+/[0-9]+$"
87 |
88 | /*
89 | XXX This seems to be the same as the Perl code. But I don't see where a " " is allowed for.
90 | I.e. Perl -> ^[a-zA-Z][\w\-\.\'\|\`]*$
91 | Does \w include [ ;:,?/}{()+*#] ?
92 | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`-]*$"
93 | */
94 | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`;:,?/}{()+*#&-]*$"
95 |
96 | #define VALIDIP4PREFIX
97 |
98 | #define EMAIL "^[.a-zA-Z0-9--]*@[a-zA-Z0-9--]*(\\.[a-zA-Z0-9--]+)*$"
99 |
100 | static int perform_regex_test(const char *pattern, char *string) {
101 | int match;
102 |
103 | char *re;
104 |
105 | re = regcmp(pattern, (char*)0);
106 | if (regex(re, string) == NULL) {
107 | match = 0;
108 | }
109 | else {
110 | match = 1;
111 | }
112 |
113 | free(re); /* not a wrapper, because we have not allocated it */
114 |
115 | return match;
116 | } /* perform_regex_test() */
117 |
118 | static int isasnum(char *string) {
119 | int result='-';
120 | int as_value;
121 |
122 | /* First check if the string matches an ASNUM */
123 | result = perform_regex_test(ASNUM, string);
124 |
125 | /* Then check if the value is between ASNUM_MIN and ASNUM_MAX */
126 | if (result == 1) {
127 | as_value = atoi(string+ASNUM_NUMOFFSET);
128 | if ((as_value < ASNUM_MIN) || (as_value > ASNUM_MAX)) {
129 | /* an invalid value */
130 | result=0;
131 | }
132 | }
133 |
134 | return result;
135 | }
136 |
137 | /*******************************************************
138 | # the problem is as follows:
139 | #
140 | # we can never find out which NIC handles are possible on the
141 | # globe since we don't know that they exist
142 | #
143 | # we want to solve this with once with DNS :
144 | #
145 | # RIPE.registries.int CNAME whois.ripe.net
146 | # InterNIC.registries.int CNAME whois.internic.net
147 | # and so on...
148 |
149 | #
150 | # 1) it first does a basic syntax check
151 | #
152 | # notes:
153 | #
154 | # - catches InterNIC handles
155 | # - catches the JP|JP-JP APNIC exceptions
156 | # - limits the number of initials to three with a good reason:
157 | # we have a much better chance to find syntax errors like:
158 | # RIPE-DK13 and other problems like this
159 | #
160 | # 2) checks for valid suffixes
161 | # - all 'source:' attribute values from sites that we mirror
162 | # are allowed
163 | # - country codes are allowed for APNIC compatibility
164 | # - APNIC AP|CC-AU exceptions are handled correctly
165 | # - -ORG organization InterNIC handles
166 | # - -ARIN ARIN handles
167 | # - -ORG-ARIN ARIN handles
168 | ********************************************************/
169 | static int isnichandle(char *nichdl) {
170 |
171 | char *regexp, *match;
172 | char ret[1024];
173 | char *suffix;
174 |
175 | int i;
176 |
177 | /* set ret to the empty string */
178 | ret[0]='\0';
179 |
180 | /*
181 | # Japanese NIC handles
182 | #
183 | # leading zeros in the number part *are* allowed
184 | #
185 | # e.g. AB021JP AB199JP-JP
186 | #
187 | */
188 | regexp = regcmp("[A-Z]{2}[0-9]{3}JP(-JP){0,1}",(char *)0);
189 | match = regex(regexp,nichdl);
190 | free(regexp); /* not a wrapper, because we have not allocated it */
191 | if (match) return 1;
192 |
193 | /*
194 | # Standard NIC handles
195 | #
196 | # leading zeros in the number part are *not* allowed
197 | #
198 | # InterNIC - TBQ, IP4
199 | # RIPE format - AB1-RIPE
200 | # APNIC use two letter country code suffix
201 | # Austraila have used -1-AU, -2-AU, -CC-AU suffix.
202 | # Internic used -ORG suffix
203 | # ARIN use -ARIN suffix
204 | # ARIN also use -ORG-ARIN suffix
205 | #
206 | */
207 | regexp = regcmp("^[A-Z]{2,4}([1-9][0-9]{0,5}){0,1}((-[^ ]+){0,1})$0$",(char *)0);
208 | match = regex(regexp,nichdl,ret);
209 |
210 | free(regexp); /* not a wrapper, because we have not allocated it */
211 |
212 | if (match == NULL) {
213 | return 0;
214 | } else {
215 | if (ret[0] == '\0') {
216 | return 1;
217 | } else {
218 | /* strip leading '-' */
219 | suffix = ret+1;
220 | /* suffix of local sources */
221 | for (i=0;i<=NUM_NICPOSTFIX;i++) {
222 | if ( !strcmp(suffix,nicpostfix[i]) ) {
223 | return 1;
224 | }
225 | }
226 | /* country codes */
227 | for (i=0;i<NUM_COUNTRIES;i++) {
228 | if ( !strcmp(suffix,countries[i]) ) {
229 | return 1;
230 | }
231 | }
232 | /* special suffix */
233 | for (i=0;i<NUM_SPECIAL;i++) {
234 | if ( !strcmp(suffix,special[i]) ) {
235 | return 1;
236 | }
237 | }
238 | }
239 | }
240 | return 0;
241 | } /* isnichandle() */
242 |
243 | static int isdomname(char *string) {
244 | return ( perform_regex_test(DOMAINNAME, string)
245 | && perform_regex_test(DOMAINALPHA, string));
246 | }
247 |
248 | /*
249 | I split the isname up into isname_a & isname_b. And created isname_ab to join them together.
250 | - So I can test it properly. -ottrey
251 | */
252 | static int isname_a(char *string) {
253 | return perform_regex_test(AUTONICPREFIXREGULAR, string);
254 | }
255 |
256 | static int isname_b(char *string) {
257 | return perform_regex_test(NAME_B, string);
258 | }
259 |
260 | static int isname_ab(char *string) {
261 | return (isname_a(string) || isname_b(string));
262 | }
263 |
264 | static int isnetname(char *string) {
265 | return perform_regex_test(NETNAME, string);
266 | } /* wk_is_netname() */
267 |
268 |
269 |
270 | /* ****** The new bunch ******* */
271 |
272 | static int wk_is_name(char *key) {
273 | /* Everything matches to name */
274 | return 1;
275 | } /* wk_is_name() */
276 |
277 | static int wk_is_nic_hdl(char *key) {
278 | return isnichandle(key);
279 | } /* wk_is_nic_hdl() */
280 |
281 | static int wk_is_email(char *key) {
282 | return perform_regex_test(EMAIL, key);
283 | } /* wk_is_email() */
284 |
285 | static int wk_is_mntner(char *key) {
286 | return perform_regex_test(MAINTAINER, key);
287 | } /* wk_is_mntner() */
288 |
289 | static int wk_is_key_cert(char *key) {
290 | return perform_regex_test(KEYCERT, key);
291 | } /* wk_is_key_cert() */
292 |
293 | static int wk_is_ipaddress(char *key) {
294 | return perform_regex_test(IPADDRESS, key);
295 | } /* wk_is_key_cert() */
296 |
297 | static int wk_is_iprange(char *key) {
298 | return perform_regex_test(IPRANGE, key);
299 | } /* wk_is_iprange() */
300 |
301 | static int wk_is_ipprefix(char *key) {
302 | return perform_regex_test(IPPREFIX, key);
303 | } /* wk_is_iprange() */
304 |
305 | static int wk_is_ip6prefix(char *key) {
306 | return perform_regex_test(VALIDIP6PREFIX, key);
307 | } /* wk_is_ip6prefix() */
308 |
309 | static int wk_is_netname(char *key) {
310 | return isnetname(key);
311 | } /* wk_is_netname() */
312 |
313 | /* XXX Note: This function uses the same call as wk_is_netname(). */
314 | static int wk_is_net6name(char *key) {
315 | return isnetname(key);
316 | } /* wk_is_netname() */
317 |
318 | static int wk_is_autnum(char *key) {
319 | return isasnum(key);
320 | } /* wk_is_autnum() */
321 |
322 | static int wk_is_assetname(char *key) {
323 | return perform_regex_test(ASSETNAME, key);
324 | } /* wk_is_assetname() */
325 |
326 | static int wk_is_routesetname(char *key) {
327 | return perform_regex_test(ROUTESETNAME, key);
328 | } /* wk_is_routesetname() */
329 |
330 | static int wk_is_domain(char *key) {
331 | return isdomname(key);
332 | } /* wk_is_domname() */
333 |
334 | static int wk_is_hostname(char *key) {
335 | /* XXX Why is there a hostname & a domainname? */
336 | /* Answer - hostname can be a domainname or an IP */
337 | return (isdomname(key) || wk_is_iprange(key));
338 | } /* wk_is_hostname() */
339 |
340 | static int wk_is_limerick(char *key) {
341 | return perform_regex_test(LIMERICK, key);
342 | } /* wk_is_limerick() */
343 |
344 |
345 | /* WK_to_string() */
346 | /*++++++++++++++++++++++++++++++++++++++
347 | Convert the which keytypes bitmap into a string.
348 |
349 | mask_t wk The which keytypes mask to be converted.
350 |
351 | More:
352 | +html+ <PRE>
353 | Authors:
354 | ottrey
355 | +html+ </PRE><DL COMPACT>
356 | +html+ <DT>Online References:
357 | +html+ <DD><UL>
358 | +html+ </UL></DL>
359 |
360 | ++++++++++++++++++++++++++++++++++++++*/
361 | char *WK_to_string(mask_t wk) {
362 |
363 | return MA_to_string(wk, Keytypes);
364 |
365 | } /* WK_to_string() */
366 |
367 | /* WK_new() */
368 | /*++++++++++++++++++++++++++++++++++++++
369 | Create a new which keytypes bitmap.
370 |
371 | char *key The key to be examined.
372 |
373 | More:
374 | +html+ <PRE>
375 | Authors:
376 | ottrey
377 | +html+ </PRE><DL COMPACT>
378 | +html+ <DT>Online References:
379 | +html+ <DD><UL>
380 | +html+ </UL></DL>
381 |
382 | ++++++++++++++++++++++++++++++++++++++*/
383 | mask_t WK_new(char *key) {
384 | mask_t wk;
385 |
386 | wk = MA_new(MA_END);
387 |
388 | MA_set(&wk, WK_NAME, wk_is_name(key));
389 | MA_set(&wk, WK_NIC_HDL, wk_is_nic_hdl(key));
390 | MA_set(&wk, WK_EMAIL, wk_is_email(key));
391 | MA_set(&wk, WK_MNTNER, wk_is_mntner(key));
392 | MA_set(&wk, WK_KEY_CERT, wk_is_key_cert(key));
393 | MA_set(&wk, WK_IPADDRESS, wk_is_ipaddress(key));
394 | MA_set(&wk, WK_IPRANGE, wk_is_iprange(key));
395 | MA_set(&wk, WK_IPPREFIX, wk_is_ipprefix(key));
396 | MA_set(&wk, WK_IP6PREFIX, wk_is_ip6prefix(key));
397 | MA_set(&wk, WK_NETNAME, wk_is_netname(key));
398 | MA_set(&wk, WK_NET6NAME, wk_is_net6name(key));
399 | MA_set(&wk, WK_AUTNUM, wk_is_autnum(key));
400 | MA_set(&wk, WK_ASSETNAME, wk_is_assetname(key));
401 | MA_set(&wk, WK_ROUTESETNAME, wk_is_routesetname(key));
402 | MA_set(&wk, WK_DOMAIN, wk_is_domain(key));
403 | MA_set(&wk, WK_HOSTNAME, wk_is_hostname(key));
404 | MA_set(&wk, WK_LIMERICK, wk_is_limerick(key));
405 |
406 | return wk;
407 |
408 | } /* WK_new() */