Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / auth / netrestrict.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /*
11 * Network utility functions
12 * Parsing NetRestrict file and filtering IP addresses
13 */
14
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 #include <roken.h>
19 #include <ctype.h>
20
21 #include <afs/opr.h>
22
23 #include <rx/rx.h>
24 #include <afs/dirpath.h>
25
26 #include "cellconfig.h"
27
28 #define AFS_IPINVALID -1 /* invalid IP address */
29 #define AFS_IPINVALIDIGNORE -2 /* no input given to extractAddr */
30 #define MAX_NETFILE_LINE 2048 /* length of a line in the NetRestrict file */
31 #define MAXIPADDRS 1024 /* from afsd.c */
32
33 static int ParseNetInfoFile_int(afs_uint32 *, afs_uint32 *, afs_uint32 *,
34 int, char reason[], const char *,
35 int);
36
37 /**
38 * The line parameter is a pointer to a buffer containing a string of
39 * bytes of the form:
40 *
41 * w.x.y.z[/n] # machineName
42 *
43 * Returns an IPv4 address and mask in network byte order. Optionally,
44 * a '/' may be used to specify a subnet mask length.
45 *
46 * @param[in] line
47 * Pointer to a string of bytes
48 * @param[out] maxSize
49 * Length to search in line for addresses
50 * @param[out] addr
51 * IPv4 address in network byte order
52 * @param[out] mask
53 * IPv4 subnet mask in network byte order, default to 0xffffffff
54 *
55 * @return
56 * @retval 0 success
57 * @retval AFS_IPINVALID the address is invalid or parsing failed
58 * @retval AFS_IPINVALIDIGNORE blank line that can be ignored
59 */
60 static int
61 extract_Addr(char *line, int maxSize, afs_uint32 *addr, afs_uint32 *mask)
62 {
63 char bytes[4][32];
64 int i = 0, n = 0;
65 char *endPtr;
66 afs_uint32 val[4];
67 int subnet_len = 32;
68
69 /* skip empty spaces */
70 while (isspace(*line) && maxSize) {
71 line++;
72 maxSize--;
73 }
74 /* skip empty lines */
75 if (!maxSize || !*line)
76 return AFS_IPINVALIDIGNORE;
77
78 /* init to 0.0.0.0 for strtol() */
79 for (n = 0; n < 4; n++) {
80 bytes[n][0] = '0';
81 bytes[n][1] = '\0';
82 }
83
84 for (n = 0; n < 4; n++) {
85 while ((*line != '.') && !isspace(*line)
86 && (*line != '/') && maxSize) { /* extract nth byte */
87 if (!isdigit(*line))
88 return AFS_IPINVALID;
89 if (i > 31)
90 return AFS_IPINVALID; /* no space */
91 bytes[n][i++] = *line++;
92 maxSize--;
93 } /* while */
94 if (!maxSize)
95 return AFS_IPINVALID;
96 bytes[n][i] = '\0';
97 if (*line == '/')
98 break;
99 i = 0;
100 line++;
101 }
102
103 if (*line == '.')
104 ++line; /* single trailing . allowed */
105
106 if (*line == '/') { /* have a subnet length */
107 line++;
108 subnet_len = 0;
109 while (isdigit(*line)) {
110 subnet_len = subnet_len * 10 + (*line - '0');
111 if (subnet_len > 32)
112 return AFS_IPINVALID; /* subnet length too long */
113 ++line;
114 }
115 if (subnet_len == 0)
116 return AFS_IPINVALID; /* subnet length too short */
117 }
118
119 if (!isspace(*line) && (*line != '\0'))
120 return AFS_IPINVALID; /* improperly formed comment */
121
122 for (n = 0; n < 4; n++) {
123 errno = 0;
124 val[n] = strtol(bytes[n], &endPtr, 10);
125 if ((val[n] == 0) && (errno != 0 || bytes[n] == endPtr)) /* no conversion */
126 return AFS_IPINVALID;
127 }
128
129 *mask = 0;
130 while (subnet_len--) {
131 *mask = (*mask >> 1) | 0x80000000;
132 }
133
134 *mask = htonl(*mask);
135 *addr = htonl((val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3]);
136 return 0;
137 }
138
139 /**
140 * Get a list of IP addresses for this host removing any address found
141 * in the config file (fileName parameter): /usr/vice/etc/NetRestrict
142 * for clients and /usr/afs/local/NetRestrict for servers.
143 *
144 * Returns the number of valid addresses in outAddrs[] and count in
145 * nAddrs. Returns 0 on success; or 1 if the config file was not
146 * there or empty (we still return the host's IP addresses). Returns
147 * -1 on fatal failure with reason in the reason argument (so the
148 * caller can choose to ignore the entire file but should write
149 * something to a log file).
150 *
151 * All addresses should be in network byte order as returned by
152 * rx_getAllAddrMaskMtu() and parsed by extract_Addr().
153 *
154 * @param[out] outAddrs
155 * All the address that are found to be valid.
156 * @param[out] outMask
157 * Optional associated netmask for address
158 * @param[out] outMtu
159 * Optional associated MTU for address
160 * @param[in] maxAddres
161 * Length of the above output arrays
162 * @param[out] nAddrs
163 * Count of valid addresses
164 * @param[out] reason
165 * Reason (if any) for the parsing failure
166 * @param[in] fileName
167 * Configuration file to parse
168 *
169 * @return
170 * 0 on success; 1 if the config file was not used; -1 on
171 * fatal failure.
172 */
173 static int
174 parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[],
175 afs_uint32 outMtu[], afs_uint32 maxAddrs,
176 afs_uint32 *nAddrs, char reason[],
177 const char *fileName, const char *fileName_ni)
178 {
179 FILE *fp;
180 char line[MAX_NETFILE_LINE];
181 int lineNo, usedfile = 0;
182 afs_uint32 i, neaddrs, nOutaddrs;
183 afs_uint32 addr, mask, eAddrs[MAXIPADDRS], eMask[MAXIPADDRS], eMtu[MAXIPADDRS];
184 int retval;
185
186 opr_Assert(outAddrs);
187 opr_Assert(reason);
188 opr_Assert(fileName);
189 opr_Assert(nAddrs);
190 if (outMask)
191 opr_Assert(outMtu);
192
193 /* Initialize */
194 *nAddrs = 0;
195 for (i = 0; i < maxAddrs; i++)
196 outAddrs[i] = 0;
197 strcpy(reason, "");
198
199 /* get all network interfaces from the kernel */
200 neaddrs = rx_getAllAddrMaskMtu(eAddrs, eMask, eMtu, MAXIPADDRS);
201 if (neaddrs <= 0) {
202 sprintf(reason, "No existing IP interfaces found");
203 return -1;
204 }
205 i = 0;
206 if ((neaddrs < MAXIPADDRS) && fileName_ni)
207 i = ParseNetInfoFile_int(&(eAddrs[neaddrs]), &(eMask[neaddrs]),
208 &(eMtu[neaddrs]), MAXIPADDRS-neaddrs, reason,
209 fileName_ni, 1);
210
211 if (i > 0)
212 neaddrs += i;
213
214 if ((fp = fopen(fileName, "r")) == 0) {
215 sprintf(reason, "Could not open file %s for reading:%s", fileName,
216 strerror(errno));
217 goto done;
218 }
219
220 /* For each line in the NetRestrict file */
221 lineNo = 0;
222 usedfile = 0;
223 while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
224 lineNo++; /* input line number */
225 retval = extract_Addr(line, strlen(line), &addr, &mask);
226 if (retval == AFS_IPINVALID) { /* syntactically invalid */
227 fprintf(stderr, "%s : line %d : parse error - invalid IP\n",
228 fileName, lineNo);
229 continue;
230 }
231 if (retval == AFS_IPINVALIDIGNORE) { /* ignore error */
232 fprintf(stderr, "%s : line %d : invalid address ... ignoring\n",
233 fileName, lineNo);
234 continue;
235 }
236 usedfile = 1;
237
238 /* Check if we need to exclude this address */
239 for (i = 0; i < neaddrs; i++) {
240 if (eAddrs[i] && ((eAddrs[i] & mask) == (addr & mask))) {
241 eAddrs[i] = 0; /* Yes - exclude it by zeroing it for now */
242 }
243 }
244 } /* while */
245
246 fclose(fp);
247
248 if (!usedfile) {
249 sprintf(reason, "No valid IP addresses in %s\n", fileName);
250 goto done;
251 }
252
253 done:
254 /* Collect the addresses we have left to return */
255 nOutaddrs = 0;
256 for (i = 0; i < neaddrs; i++) {
257 if (!eAddrs[i])
258 continue;
259 outAddrs[nOutaddrs] = eAddrs[i];
260 if (outMask) {
261 outMask[nOutaddrs] = eMask[i];
262 outMtu[nOutaddrs] = eMtu[i];
263 }
264 if (++nOutaddrs >= maxAddrs)
265 break;
266 }
267 if (nOutaddrs == 0) {
268 sprintf(reason, "No addresses to use after parsing %s", fileName);
269 return -1;
270 }
271 *nAddrs = nOutaddrs;
272 return (usedfile ? 0 : 1); /* 0=>used the file. 1=>didn't use file */
273 }
274
275 int
276 afsconf_ParseNetRestrictFile(afs_uint32 outAddrs[], afs_uint32 outMask[],
277 afs_uint32 outMtu[], afs_uint32 maxAddrs,
278 afs_uint32 * nAddrs, char reason[],
279 const char *fileName)
280 {
281 return parseNetRestrictFile_int(outAddrs, outMask, outMtu, maxAddrs, nAddrs, reason, fileName, 0);
282 }
283
284 /**
285 * Get a list of IP addresses for this host allowing only addresses found
286 * in the config file (fileName parameter): /usr/vice/etc/NetInfo for
287 * clients and /usr/afs/local/NetInfo for servers.
288 *
289 * All addresses should be in network byte order as returned by
290 * rx_getAllAddrMaskMtu() and parsed by extract_Addr().
291 *
292 * @param[out] outAddrs
293 * All the address that are found to be valid.
294 * @param[out] outMask
295 * Associated netmask for interface
296 * @param[out] outMtu
297 * Associated MTU for interface
298 * @param[in] max
299 * Length of the output above arrays
300 * @param[out] reason
301 * Reason for the parsing failure
302 * @param[in] fileName
303 * File to parse
304 * @param[in] fakeonly
305 * Only return addresses if they are marked as fake
306 *
307 * @return
308 * The number of valid address on success or < 0 on fatal failure.
309 */
310 static int
311 ParseNetInfoFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], afs_uint32 outMtu[],
312 int max, char reason[], const char *fileName,
313 int fakeonly)
314 {
315
316 afs_uint32 existingAddr[MAXIPADDRS], existingMask[MAXIPADDRS],
317 existingMtu[MAXIPADDRS];
318 char line[MAX_NETFILE_LINE];
319 FILE *fp;
320 int i, existNu, count = 0;
321 afs_uint32 addr, mask;
322 int lineNo = 0;
323 int l;
324 int retval;
325
326 opr_Assert(fileName);
327 opr_Assert(outAddrs);
328 opr_Assert(outMask);
329 opr_Assert(outMtu);
330 opr_Assert(reason);
331
332 /* get all network interfaces from the kernel */
333 existNu =
334 rx_getAllAddrMaskMtu(existingAddr, existingMask, existingMtu,
335 MAXIPADDRS);
336 if (existNu < 0)
337 return existNu;
338
339 if ((fp = fopen(fileName, "r")) == 0) {
340 /* If file does not exist or is not readable, then
341 * use all interface addresses.
342 */
343 sprintf(reason,
344 "Failed to open %s(%s)\nUsing all configured addresses\n",
345 fileName, strerror(errno));
346 for (i = 0; i < existNu; i++) {
347 outAddrs[i] = existingAddr[i];
348 outMask[i] = existingMask[i];
349 outMtu[i] = existingMtu[i];
350 }
351 return existNu;
352 }
353
354 /* For each line in the NetInfo file */
355 while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
356 int fake = 0;
357
358 /* See if first char is an 'F' for fake */
359 /* Added to allow the fileserver to advertise fake IPS for use with
360 * the translation tables for NAT-like firewalls - defect 12462 */
361 for (fake = 0; ((fake < strlen(line)) && isspace(line[fake]));
362 fake++);
363 if ((fake < strlen(line))
364 && ((line[fake] == 'f') || (line[fake] == 'F'))) {
365 fake++;
366 } else {
367 fake = 0;
368 }
369
370 lineNo++; /* input line number */
371 retval = extract_Addr(&line[fake], strlen(&line[fake]), &addr, &mask);
372
373 if (retval == AFS_IPINVALID) { /* syntactically invalid */
374 fprintf(stderr, "afs:%s : line %d : parse error\n", fileName,
375 lineNo);
376 continue;
377 }
378 if (fake && ntohl(mask) != 0xffffffff) {
379 fprintf(stderr, "afs:%s : line %d : bad fake address\n", fileName,
380 lineNo);
381 continue;
382 }
383 if (retval == AFS_IPINVALIDIGNORE) { /* ignore error */
384 continue;
385 }
386
387 /* See if it is an address that really exists */
388 for (i = 0; i < existNu; i++) {
389 if ((existingAddr[i] & mask) == (addr & mask))
390 break;
391 }
392 if ((i >= existNu) && (!fake))
393 continue; /* not found/fake - ignore */
394
395 /* Check if it is a duplicate address we alread have */
396 for (l = 0; l < count; l++) {
397 if ((outAddrs[l] & mask) == (addr & mask))
398 break;
399 }
400 if (l < count) {
401 fprintf(stderr, "afs:%x matched more than once in NetInfo file\n",
402 ntohl(outAddrs[l]));
403 continue; /* duplicate addr - ignore */
404 }
405
406 if (count > max) { /* no more space */
407 fprintf(stderr,
408 "afs:Too many interfaces. The current kernel configuration supports a maximum of %d interfaces\n",
409 max);
410 } else if (fake) {
411 if (!fake)
412 fprintf(stderr, "Client (2) also has address %s\n", line);
413 outAddrs[count] = addr;
414 outMask[count] = 0xffffffff;
415 outMtu[count] = htonl(1500);
416 count++;
417 } else if (!fakeonly) {
418 outAddrs[count] = existingAddr[i];
419 outMask[count] = existingMask[i];
420 outMtu[count] = existingMtu[i];
421 count++;
422 }
423 } /* while */
424
425 /* in case of any error, we use all the interfaces present */
426 if (count <= 0) {
427 sprintf(reason,
428 "Error in reading/parsing Interface file\nUsing all configured interface addresses \n");
429 for (i = 0; i < existNu; i++) {
430 outAddrs[i] = existingAddr[i];
431 outMask[i] = existingMask[i];
432 outMtu[i] = existingMtu[i];
433 }
434 return existNu;
435 }
436 return count;
437 }
438
439 int
440 afsconf_ParseNetInfoFile(afs_uint32 outAddrs[], afs_uint32 outMask[], afs_uint32 outMtu[],
441 int max, char reason[], const char *fileName)
442 {
443 return ParseNetInfoFile_int(outAddrs, outMask, outMtu, max, reason, fileName, 0);
444 }
445
446 /*
447 * Given two arrays of addresses, masks and mtus find the common ones
448 * and return them in the first buffer. Return number of common
449 * entries.
450 */
451 static int
452 filterAddrs(afs_uint32 addr1[], afs_uint32 addr2[], afs_uint32 mask1[],
453 afs_uint32 mask2[], afs_uint32 mtu1[], afs_uint32 mtu2[], int n1,
454 int n2)
455 {
456 afs_uint32 taddr[MAXIPADDRS];
457 afs_uint32 tmask[MAXIPADDRS];
458 afs_uint32 tmtu[MAXIPADDRS];
459 int count = 0, i = 0, j = 0, found = 0;
460
461 opr_Assert(addr1);
462 opr_Assert(addr2);
463 opr_Assert(mask1);
464 opr_Assert(mask2);
465 opr_Assert(mtu1);
466 opr_Assert(mtu2);
467
468 for (i = 0; i < n1; i++) {
469 found = 0;
470 for (j = 0; j < n2; j++) {
471 if (addr1[i] == addr2[j]) {
472 found = 1;
473 break;
474 }
475 }
476
477 /* Always mask loopback address */
478 if (found && rx_IsLoopbackAddr(addr1[i]))
479 found = 0;
480
481 if (found) {
482 taddr[count] = addr1[i];
483 tmask[count] = mask1[i];
484 tmtu[count] = mtu1[i];
485 count++;
486 }
487 }
488 /* copy everything into addr1, mask1 and mtu1 */
489 for (i = 0; i < count; i++) {
490 addr1[i] = taddr[i];
491 if (mask1) {
492 mask1[i] = tmask[i];
493 mtu1[i] = tmtu[i];
494 }
495 }
496 /* and zero out the rest */
497 for (i = count; i < n1; i++) {
498 addr1[i] = 0;
499 if (mask1) {
500 mask1[i] = 0;
501 mtu1[i] = 0;
502 }
503 }
504 return count;
505 }
506
507 /*
508 * parse both NetInfo and NetRestrict files and return the final
509 * set of IP addresses to use
510 */
511 /* max - Entries in addrbuf, maskbuf and mtubuf */
512 int
513 afsconf_ParseNetFiles(afs_uint32 addrbuf[], afs_uint32 maskbuf[],
514 afs_uint32 mtubuf[], afs_uint32 max, char reason[],
515 const char *niFileName, const char *nrFileName)
516 {
517 afs_uint32 addrbuf1[MAXIPADDRS], maskbuf1[MAXIPADDRS],
518 mtubuf1[MAXIPADDRS];
519 afs_uint32 addrbuf2[MAXIPADDRS], maskbuf2[MAXIPADDRS],
520 mtubuf2[MAXIPADDRS];
521 int nAddrs1 = 0;
522 afs_uint32 nAddrs2 = 0;
523 int code, i;
524
525 nAddrs1 =
526 afsconf_ParseNetInfoFile(addrbuf1, maskbuf1, mtubuf1, MAXIPADDRS,
527 reason, niFileName);
528 code =
529 parseNetRestrictFile_int(addrbuf2, maskbuf2, mtubuf2, MAXIPADDRS,
530 &nAddrs2, reason, nrFileName, niFileName);
531 if ((nAddrs1 < 0) && (code)) {
532 /* both failed */
533 return -1;
534 } else if ((nAddrs1 > 0) && (code)) {
535 /* NetInfo succeeded and NetRestrict failed */
536 for (i = 0; ((i < nAddrs1) && (i < max)); i++) {
537 addrbuf[i] = addrbuf1[i];
538 if (maskbuf) {
539 maskbuf[i] = maskbuf1[i];
540 mtubuf[i] = mtubuf1[i];
541 }
542 }
543 return i;
544 } else if ((!code) && (nAddrs1 < 0)) {
545 /* NetRestrict succeeded and NetInfo failed */
546 for (i = 0; ((i < nAddrs2) && (i < max)); i++) {
547 addrbuf[i] = addrbuf2[i];
548 if (maskbuf) {
549 maskbuf[i] = maskbuf2[i];
550 mtubuf[i] = mtubuf2[i];
551 }
552 }
553 return i;
554 } else if ((!code) && (nAddrs1 >= 0)) {
555 /* both succeeded */
556 /* take the intersection of addrbuf1 and addrbuf2 */
557 code =
558 filterAddrs(addrbuf1, addrbuf2, maskbuf1, maskbuf2, mtubuf1,
559 mtubuf2, nAddrs1, nAddrs2);
560 for (i = 0; ((i < code) && (i < max)); i++) {
561 addrbuf[i] = addrbuf1[i];
562 if (maskbuf) {
563 maskbuf[i] = maskbuf1[i];
564 mtubuf[i] = mtubuf1[i];
565 }
566 }
567 return i;
568 }
569 return 0;
570 }