GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ypserv/ypserv/acl.c Lines: 0 260 0.0 %
Date: 2017-11-13 Branches: 0 218 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: acl.c,v 1.15 2013/12/04 02:18:05 deraadt Exp $ */
2
3
/*
4
 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <netinet/in.h>
32
#include <arpa/inet.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <ctype.h>
36
#include <string.h>
37
#include <netdb.h>
38
#include "acl.h"
39
40
#define TRUE 1
41
#define FALSE 0
42
43
static	struct aclent *acl_root = NULL;
44
45
static int
46
acl_read_line(FILE *fp, char *buf, int size)
47
{
48
	int	 len = 0;
49
	char *c, *p, l;
50
51
	/* Read a line, and remove any comment, trim space */
52
53
	do {
54
		while (fgets(buf, size, fp)) {
55
			c = buf;
56
			while (*c != '\0') {
57
				if (*c == '#' || *c == '\n') {
58
					*c = '\0';
59
				} else {
60
					c++;
61
				}
62
			}
63
64
			c = p = buf; l = ' ';
65
			while (*c != '\0') {
66
				if (isspace((unsigned char)l) &&
67
				    isspace((unsigned char)*c)) {
68
					c++;
69
				} else {
70
					l = *c++; *p = l; p++;
71
				}
72
			}
73
			*p = '\0';
74
75
			if (p != buf) {
76
				--p;
77
				if (isspace((unsigned char)*p) != 0) {
78
					*p = '\0';
79
				}
80
			}
81
82
			len = strlen(buf);
83
			return len + 1;
84
		}
85
	} while (size > 0 && !feof(fp));
86
	return len;
87
}
88
89
int
90
acl_check_host(struct in_addr *addr)
91
{
92
	struct aclent *p;
93
94
	p = acl_root;
95
	while (p != NULL) {
96
		if ((addr->s_addr & p->s_mask) == p->s_addr)
97
			return(p->allow);
98
		p = p->next;
99
	}
100
	return(TRUE);
101
}
102
103
static void
104
acl_add_net(int	allow, struct in_addr *addr, struct in_addr *mask)
105
{
106
	struct aclent *acl, *p;
107
108
	acl = malloc(sizeof(struct aclent));
109
	acl->next	 = NULL;
110
	acl->allow	= allow;
111
	acl->s_addr = addr->s_addr;
112
	acl->s_mask = mask->s_addr;
113
114
	if (acl_root == NULL) {
115
		acl_root = acl;
116
	} else {
117
		p = acl_root;
118
		while (p->next != NULL)
119
			p = p->next;
120
		p->next = acl;
121
	}
122
}
123
124
static void
125
acl_add_host(int allow, struct in_addr *addr)
126
{
127
	struct in_addr mask;
128
129
	mask.s_addr = htonl(0xffffffff);
130
	acl_add_net(allow, addr, &mask);
131
}
132
133
int
134
acl_init(char *file)
135
{
136
	char data_line[1024], *p, *k;
137
	int line_no = 0, len, i, state;
138
	int allow = TRUE, error_cnt = 0;
139
	struct in_addr addr, mask, *host_addr;
140
	struct hostent *host;
141
	struct netent *net;
142
	FILE *data_file = NULL;
143
144
	if (file != NULL)
145
		data_file = fopen(file, "r");
146
147
	while (data_file != NULL &&
148
	    acl_read_line(data_file, data_line, sizeof(data_line))) {
149
150
		line_no++;
151
		len = strlen(data_line);
152
		if (len == 0)
153
			continue;
154
		p = (char *) &data_line;
155
156
		/* State 1: Initial State */
157
158
		state = ACLS_INIT;
159
		addr.s_addr = mask.s_addr = 0;
160
161
		k = p;			/* save start of verb */
162
		i = 0;
163
		while (*p != '\0' &&
164
		    !isspace((*p = tolower(*p)))) {
165
			p++;
166
			i++;
167
		}
168
169
		if (*p != '\0')
170
			*p++ = '\0';
171
172
		if (strcmp(k, "allow") == 0) {
173
			allow = TRUE;
174
			state = ACLS_ALLOW;
175
		}
176
177
		if (strcmp(k, "deny") == 0) {
178
			allow = FALSE;
179
			state = ACLS_DENY;
180
		}
181
182
		if (state == ACLS_INIT)
183
			state = ACLE_UVERB;
184
185
		/* State 2: allow row */
186
		/* State 3: deny row */
187
188
		if (*p != '\0' &&
189
		    (state == ACLS_ALLOW || state == ACLS_DENY)) {
190
			k = p;			/* save start of verb */
191
			i = 0;
192
			while (*p != '\0' &&
193
			    !isspace((*p = tolower(*p)))) {
194
				p++;
195
				i++;
196
			}
197
198
			if (*p != '\0')
199
				*p++ = '\0';
200
201
			if (strcmp(k, "all") == 0)
202
				state = state + ACLD_ALL;
203
204
			if (strcmp(k, "host") == 0)
205
				state = state + ACLD_HOST;
206
207
			if (strcmp(k, "net") == 0)
208
				state = state + ACLD_NET;
209
210
			if (state == ACLS_ALLOW || state == ACLS_DENY)
211
				state = ACLE_U2VERB;
212
		}
213
214
		if (state == ACLS_ALLOW || state == ACLS_DENY)
215
			state = ACLE_UEOL;
216
217
		/* State 4 & 5: all state, remove any comment */
218
219
		if (*p == '\0' &&
220
		    (state == ACLS_ALLOW_ALL || state == ACLS_DENY_ALL)) {
221
			acl_add_net(allow, &addr, &mask);
222
			state = ACLE_OK;
223
		}
224
225
		/* State 6 & 7: host line */
226
		/* State 8 & 9: net line */
227
228
		if (*p != '\0' &&
229
		    state >= ACLS_ALLOW_HOST && state <= ACLS_DENY_NET) {
230
231
			k = p;			/* save start of verb */
232
			i = 0;
233
			while (*p != '\0' &&
234
			    !isspace((*p = tolower(*p)))) {
235
				p++;
236
				i++;
237
			}
238
239
			if (*p != '\0')
240
				*p++ = '\0';
241
242
			if (state == ACLS_ALLOW_HOST || state == ACLS_DENY_HOST) {
243
				if (*k >= '0' && *k <= '9') {
244
					(void)inet_aton(k, &addr);
245
					acl_add_host(allow, &addr);
246
					state = state + ACLD_HOST_DONE;
247
				} else {
248
					host = gethostbyname(k);
249
					if (host == NULL) {
250
						state = ACLE_NOHOST;
251
					} else {
252
						if (host->h_addrtype == AF_INET) {
253
							while ((host_addr = (struct in_addr *) *host->h_addr_list++) != NULL)
254
								acl_add_host(allow, host_addr);
255
						}
256
						state = state + ACLD_HOST_DONE;
257
					}
258
				}
259
			}
260
261
			if (state == ACLS_ALLOW_NET || state == ACLS_DENY_NET) {
262
				if (*k >= '0' && *k <= '9') {
263
					(void)inet_aton(k, &addr);
264
					state = state + ACLD_NET_DONE;
265
				} else {
266
					net = getnetbyname(k);
267
					if (net == NULL) {
268
						state = ACLE_NONET;
269
					} else {
270
						addr.s_addr = ntohl(net->n_net);
271
						state = state + ACLD_NET_DONE;
272
					}
273
				}
274
			}
275
276
		}
277
278
		if (state >= ACLS_ALLOW_HOST && state <= ACLS_DENY_NET)
279
			state = ACLE_UEOL;
280
281
282
		/* State 10 & 11: allow/deny host line */
283
		if (*p == '\0' &&
284
		    (state == ACLS_ALLOW_HOST_DONE || state == ACLS_DENY_HOST_DONE))
285
			state = ACLE_OK;
286
287
		/* State 12 & 13: allow/deny net line */
288
		if (*p == '\0' &&
289
		    (state == ACLS_ALLOW_NET_DONE || state == ACLS_DENY_NET_DONE)) {
290
			mask.s_addr = htonl(0xffffff00);
291
			if (ntohl(addr.s_addr) < 0xc0000000)
292
				mask.s_addr = htonl(0xffff0000);
293
			if (ntohl(addr.s_addr) < 0x80000000)
294
				mask.s_addr = htonl(0xff000000);
295
			acl_add_net(allow, &addr, &mask);
296
			state = ACLE_OK;
297
		}
298
299
		if (*p != '\0' &&
300
		    (state == ACLS_ALLOW_NET_DONE || state == ACLS_DENY_NET_DONE)) {
301
302
			k = p;			/* save start of verb */
303
			i = 0;
304
			while (*p != '\0' &&
305
			    !isspace((*p = tolower(*p)))) {
306
				p++;
307
				i++;
308
			}
309
310
			if (*p != '\0')
311
				*p++ = '\0';
312
313
			if (strcmp(k, "netmask") == 0)
314
				state = state + ACLD_NET_MASK;
315
316
			if (state == ACLS_ALLOW_NET_DONE ||
317
			    state == ACLS_DENY_NET_DONE)
318
				state = ACLE_NONETMASK;
319
		}
320
321
		/* State 14 & 15: allow/deny net netmask line */
322
		if (*p != '\0' &&
323
		    (state == ACLS_ALLOW_NET_MASK || state == ACLS_DENY_NET_MASK)) {
324
325
			k = p;		/* save start of verb */
326
			i = 0;
327
			while (*p != '\0' &&
328
			    !isspace((*p = tolower(*p)))) {
329
				p++;
330
				i++;
331
			}
332
333
			if (*p != '\0')
334
				*p++ = '\0';
335
336
			if (state == ACLS_ALLOW_NET_MASK ||
337
			    state == ACLS_DENY_NET_MASK) {
338
				if (*k >= '0' && *k <= '9') {
339
					(void)inet_aton(k, &mask);
340
					state = state + ACLD_NET_EOL;
341
				} else {
342
					net = getnetbyname(k);
343
					if (net == NULL) {
344
						state = ACLE_NONET;
345
					} else {
346
						mask.s_addr = ntohl(net->n_net);
347
						state = state + ACLD_NET_EOL;
348
					}
349
				}
350
			}
351
352
		}
353
354
		if (state == ACLS_ALLOW_NET_MASK || state == ACLS_DENY_NET_MASK)
355
			state = ACLE_UEOL;
356
357
		/* State 16 & 17: allow/deny host line */
358
		if (*p == '\0' &&
359
		    (state == ACLS_ALLOW_NET_EOL || state == ACLS_DENY_NET_EOL)) {
360
			acl_add_net(allow, &addr, &mask);
361
			state = ACLE_OK;
362
		}
363
364
		switch (state) {
365
		case ACLE_NONETMASK:
366
			fprintf(stderr,
367
			    "acl: excpected \"netmask\" missing at line %d\n",
368
			    line_no);
369
			break;
370
		case ACLE_NONET:
371
			error_cnt++;
372
			fprintf(stderr, "acl: unknown network at line %d\n",
373
			    line_no);
374
			break;
375
		case ACLE_NOHOST:
376
			error_cnt++;
377
			fprintf(stderr, "acl: unknown host at line %d\n",
378
			    line_no);
379
			break;
380
		case ACLE_UVERB:
381
			error_cnt++;
382
			fprintf(stderr, "acl: unknown verb at line %d\n",
383
			    line_no);
384
			break;
385
		case ACLE_U2VERB:
386
			error_cnt++;
387
			fprintf(stderr,
388
			    "acl: unknown secondary verb at line %d\n",
389
			    line_no);
390
			break;
391
		case ACLE_UEOL:
392
			error_cnt++;
393
			fprintf(stderr,
394
			    "acl: unexpected end of line at line %d\n",
395
			    line_no);
396
			break;
397
		case ACLE_OK:
398
			break;
399
		default:
400
			error_cnt++;
401
			fprintf(stderr, "acl: unexpected state %d %s\n",
402
			    state, k);
403
		}
404
405
	}
406
407
	if (data_file != NULL) {
408
		(void)fflush(stderr);
409
		(void)fclose(data_file);
410
	}
411
412
	/* Always add a last allow all if file don't exists or */
413
	/* the file doesn't cover all cases. */
414
	addr.s_addr = mask.s_addr = 0;
415
	allow = TRUE;
416
	acl_add_net(allow, &addr, &mask);
417
	return(error_cnt);
418
}
419
420
int
421
acl_securenet(char *file)
422
{
423
	char data_line[1024], *p, *k;
424
	int line_no = 0, len, i, allow = TRUE, state;
425
	int error_cnt = 0;
426
	struct in_addr addr, mask;
427
	struct netent *net;
428
	FILE *data_file = NULL;
429
430
	if (file != NULL)
431
		data_file = fopen(file, "r");
432
433
	/* Always add a localhost allow first, to be compatible with sun */
434
	addr.s_addr = htonl(0x7f000001);
435
	mask.s_addr = htonl(0xffffffff);
436
	allow = TRUE;
437
	acl_add_net(allow, &addr, &mask);
438
439
	while (data_file != NULL &&
440
	    acl_read_line(data_file, data_line, sizeof(data_line))) {
441
		line_no++;
442
		len = strlen(data_line);
443
		if (len == 0)
444
			continue;
445
		p = (char *) &data_line;
446
447
		/* State 1: Initial State */
448
		state = ACLS_INIT;
449
		addr.s_addr = mask.s_addr = 0;
450
451
		k = p;				/* save start of verb */
452
		i = 0;
453
		while (*p != '\0' &&
454
		    !isspace((*p = tolower(*p)))) {
455
			p++;
456
			i++;
457
		}
458
459
		if (*p != '\0') {
460
			*p++ = '\0';
461
			state = ACLS_ALLOW_NET_MASK;
462
		}
463
464
		if (state == ACLS_INIT)
465
			state = ACLE_UEOL;
466
467
		if (state == ACLS_ALLOW_NET_MASK) {
468
			if (*k >= '0' && *k <= '9') {
469
				(void)inet_aton(k, &mask);
470
				state = ACLS_ALLOW_NET;
471
			} else {
472
				net = getnetbyname(k);
473
				if (net == NULL) {
474
					state = ACLE_NONET;
475
				} else {
476
					mask.s_addr = ntohl(net->n_net);
477
					state = ACLS_ALLOW_NET;
478
				}
479
			}
480
481
			k = p;				/* save start of verb */
482
			i = 0;
483
			while (*p != '\0' &&
484
			    !isspace((*p = tolower(*p)))) {
485
				p++;
486
				i++;
487
			}
488
489
			if (*p != '\0')
490
				*p++ = '\0';
491
		}
492
493
		if (state == ACLS_ALLOW_NET_MASK)
494
			state = ACLE_UEOL;
495
496
		if (state == ACLS_ALLOW_NET) {
497
			if (*k >= '0' && *k <= '9') {
498
				(void)inet_aton(k, &addr);
499
				state = ACLS_ALLOW_NET_EOL;
500
			} else {
501
				net = getnetbyname(k);
502
				if (net == NULL) {
503
					state = ACLE_NONET;
504
				} else {
505
					addr.s_addr = ntohl(net->n_net);
506
					state = ACLS_ALLOW_NET_EOL;
507
				}
508
			}
509
		}
510
511
		if (state == ACLS_ALLOW_NET)
512
			state = ACLE_UEOL;
513
514
		if (*p == '\0' && state == ACLS_ALLOW_NET_EOL) {
515
			acl_add_net(allow, &addr, &mask);
516
			state = ACLE_OK;
517
		}
518
519
		switch (state) {
520
		case ACLE_NONET:
521
			error_cnt++;
522
			fprintf(stderr,
523
			    "securenet: unknown network at line %d\n",
524
			    line_no);
525
			break;
526
		case ACLE_UEOL:
527
			error_cnt++;
528
			fprintf(stderr,
529
			    "securenet: unexpected end of line at line %d\n",
530
			    line_no);
531
			break;
532
		case ACLE_OK:
533
			break;
534
		default:
535
			error_cnt++;
536
			fprintf(stderr, "securenet: unexpected state %d %s\n",
537
			    state, k);
538
		}
539
	}
540
541
	if (data_file != NULL) {
542
		(void)fflush(stderr);
543
		(void)fclose(data_file);
544
545
		/* Always add a last deny all if file exists */
546
		addr.s_addr = mask.s_addr = 0;
547
		allow = FALSE;
548
		acl_add_net(allow, &addr, &mask);
549
	}
550
551
	/* Always add a last allow all if file don't exists */
552
553
	addr.s_addr = mask.s_addr = 0;
554
	allow = TRUE;
555
	acl_add_net(allow, &addr, &mask);
556
	return(error_cnt);
557
}
558
559
void
560
acl_reset(void)
561
{
562
	struct aclent *p;
563
564
	while (acl_root != NULL) {
565
		p = acl_root->next;
566
		free(acl_root);
567
		acl_root = p;
568
	}
569
}