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