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