389 lines
10 KiB
C
389 lines
10 KiB
C
/*
|
|
* acl.c - managing access control list.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2000 Japan Network Information Center. All rights reserved.
|
|
*
|
|
* By using this file, you agree to the terms and conditions set forth bellow.
|
|
*
|
|
* LICENSE TERMS AND CONDITIONS
|
|
*
|
|
* The following License Terms and Conditions apply, unless a different
|
|
* license is obtained from Japan Network Information Center ("JPNIC"),
|
|
* a Japanese association, Fuundo Bldg., 1-2 Kanda Ogawamachi, Chiyoda-ku,
|
|
* Tokyo, Japan.
|
|
*
|
|
* 1. Use, Modification and Redistribution (including distribution of any
|
|
* modified or derived work) in source and/or binary forms is permitted
|
|
* under this License Terms and Conditions.
|
|
*
|
|
* 2. Redistribution of source code must retain the copyright notices as they
|
|
* appear in each source code file, this License Terms and Conditions.
|
|
*
|
|
* 3. Redistribution in binary form must reproduce the Copyright Notice,
|
|
* this License Terms and Conditions, in the documentation and/or other
|
|
* materials provided with the distribution. For the purposes of binary
|
|
* distribution the "Copyright Notice" refers to the following language:
|
|
* "Copyright (c) Japan Network Information Center. All rights reserved."
|
|
*
|
|
* 4. Neither the name of JPNIC may be used to endorse or promote products
|
|
* derived from this Software without specific prior written approval of
|
|
* JPNIC.
|
|
*
|
|
* 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
*
|
|
* 6. Indemnification by Licensee
|
|
* Any person or entities using and/or redistributing this Software under
|
|
* this License Terms and Conditions shall defend indemnify and hold
|
|
* harmless JPNIC from and against any and all judgements damages,
|
|
* expenses, settlement liabilities, cost and other liabilities of any
|
|
* kind as a result of use and redistribution of this Software or any
|
|
* claim, suite, action, litigation or proceeding by any third party
|
|
* arising out of or relates to this License Terms and Conditions.
|
|
*
|
|
* 7. Governing Law, Jurisdiction and Venue
|
|
* This License Terms and Conditions shall be governed by and and
|
|
* construed in accordance with the law of Japan. Any person or entities
|
|
* using and/or redistributing this Software under this License Terms and
|
|
* Conditions hereby agrees and consent to the personal and exclusive
|
|
* jurisdiction and venue of Tokyo District Court of Japan.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char *rcsid = "$Id: acl.c,v 1.1 2001/06/09 00:30:35 tale Exp $";
|
|
#endif
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <winsock.h>
|
|
#else /* for normal systems */
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#include "mdnsproxy.h"
|
|
|
|
#ifdef TEST
|
|
#undef WARN
|
|
#define WARN printf
|
|
#endif
|
|
|
|
/*
|
|
* Entry in an access control list.
|
|
*/
|
|
typedef struct _acl acl_t;
|
|
struct _acl {
|
|
struct in_addr address; /* IP address */
|
|
struct in_addr netmask; /* net mask */
|
|
acl_t *next; /* pointer to a next entry */
|
|
};
|
|
|
|
/*
|
|
* Access control list.
|
|
*/
|
|
static acl_t *acl = NULL;
|
|
|
|
|
|
/*
|
|
* Internal functions.
|
|
*/
|
|
static BOOL
|
|
acl_parse_address(const char *pattern, struct in_addr *address,
|
|
struct in_addr *netmask, int lineNo);
|
|
|
|
/*
|
|
* Initialize the access control list `acl'.
|
|
*/
|
|
int
|
|
acl_initialize(void)
|
|
{
|
|
struct in_addr address;
|
|
struct in_addr netmask;
|
|
config_ctx_t config_ctx;
|
|
acl_t *new_entry;
|
|
acl_t *last_entry;
|
|
int value_count;
|
|
char **values;
|
|
int lineNo;
|
|
int i;
|
|
|
|
TRACE("acl_initialize()\n");
|
|
|
|
acl = NULL;
|
|
last_entry = NULL;
|
|
|
|
config_ctx = config_query_open(KW_ALLOW_ACCESS, &value_count, &values,
|
|
&lineNo);
|
|
|
|
while (config_ctx != NULL) {
|
|
if (value_count < 2) {
|
|
WARN("acl_initialize - wrong # of args for \"%s\", line %d\n",
|
|
KW_ALLOW_ACCESS, lineNo);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 1; i < value_count; i++) {
|
|
if (!acl_parse_address(values[i], &address, &netmask, lineNo))
|
|
return FALSE;
|
|
|
|
new_entry = (acl_t *)malloc(sizeof(acl_t));
|
|
if (new_entry == NULL) {
|
|
WARN("acl_initialize - cannot allocate memory\n");
|
|
return FALSE;
|
|
}
|
|
new_entry->address.s_addr = address.s_addr;
|
|
new_entry->netmask.s_addr = netmask.s_addr;
|
|
new_entry->next = NULL;
|
|
|
|
if (last_entry == NULL)
|
|
acl = new_entry;
|
|
else
|
|
last_entry->next = new_entry;
|
|
last_entry = new_entry;
|
|
}
|
|
config_ctx = config_query_more(config_ctx, &value_count, &values,
|
|
&lineNo);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* netmask length to netmask conversion table.
|
|
*/
|
|
static const unsigned long netmasks_by_mask_length[] = {
|
|
0x00000000UL, 0x80000000UL, 0xc0000000UL, 0xe0000000UL, /* 0.. 3 */
|
|
0xf0000000UL, 0xf8000000UL, 0xfc000000UL, 0xfe000000UL, /* 4.. 7 */
|
|
0xff000000UL, 0xff800000UL, 0xffc00000UL, 0xffe00000UL, /* 8..12 */
|
|
0xfff00000UL, 0xfff80000UL, 0xfffc0000UL, 0xfffe0000UL, /* 13..15 */
|
|
0xffff0000UL, 0xffff8000UL, 0xffffc000UL, 0xffffe000UL, /* 16..19 */
|
|
0xfffff000UL, 0xfffff800UL, 0xfffffc00UL, 0xfffffe00UL, /* 20..23 */
|
|
0xffffff00UL, 0xffffff80UL, 0xffffffc0UL, 0xffffffe0UL, /* 24..27 */
|
|
0xfffffff0UL, 0xfffffff8UL, 0xfffffffcUL, 0xfffffffeUL, /* 28..31 */
|
|
0xffffffffUL, /* 32 */
|
|
};
|
|
|
|
/*
|
|
* Parse an ACL address pattern (e.g. 192.168.100/24), and put the result
|
|
* into `address' and `netmask'. It returns TRUE upon success.
|
|
*
|
|
* We accepts the following address patterns:
|
|
*
|
|
* octet.octet.octet.octet
|
|
* octet.octet.octet.octet/netmask
|
|
* octet.octet.octet/netmask
|
|
* octet.octet/netmask
|
|
* octet/netmask
|
|
*
|
|
* Ommited octets are regarded as `0'.
|
|
*/
|
|
static BOOL
|
|
acl_parse_address(const char *pattern, struct in_addr *address,
|
|
struct in_addr *netmask, int lineNo)
|
|
{
|
|
unsigned int octets[4];
|
|
int netmask_length;
|
|
int digit_count;
|
|
int octet_count;
|
|
const char *p = pattern;
|
|
|
|
octets[1] = 0;
|
|
octets[2] = 0;
|
|
octets[3] = 0;
|
|
netmask_length = 32;
|
|
|
|
/*
|
|
* Parse an dot noted IP address.
|
|
*/
|
|
octet_count = 0;
|
|
while (octet_count < 4) {
|
|
octets[octet_count] = 0;
|
|
if (*p == '0' && '0' <= *(p + 1) && *(p + 1) <= '9') {
|
|
WARN("acl_parse_address - invalid address \"%.100s\", line %d\n",
|
|
pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
for (digit_count = 0; '0' <= *p && *p <= '9'; p++, digit_count++)
|
|
octets[octet_count] = octets[octet_count] * 10 + (*p - '0');
|
|
if (digit_count == 0 || digit_count > 3 || octets[octet_count] > 255) {
|
|
WARN("acl_parse_address - invalid address \"%.100s\", line %d\n",
|
|
pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
|
|
octet_count++;
|
|
if (*p != '.')
|
|
break;
|
|
p++;
|
|
}
|
|
|
|
if (*p == '\0' && octet_count != 4) {
|
|
WARN("acl_parse_address - malformed address \"%.100s\", line %d\n",
|
|
pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Parse an optional netmask length preceded by `/'.
|
|
*/
|
|
if (*p == '/') {
|
|
netmask_length = 0;
|
|
p++;
|
|
if (*p == '0' && '0' <= *(p + 1) && *(p + 1) <= '9') {
|
|
WARN("acl_parse_address - invalid netmask length \"%.100s\", "
|
|
"line %d\n", pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
for (digit_count = 0; '0' <= *p && *p <= '9'; p++, digit_count++)
|
|
netmask_length = netmask_length * 10 + (*p - '0');
|
|
if (digit_count == 0 || digit_count > 2 || netmask_length > 32) {
|
|
WARN("acl_parse_address - invalid netmask length \"%.100s\", "
|
|
"line %d\n", pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (*p != '\0') {
|
|
WARN("acl_parse_address - invalid address \"%.100s\", line %d\n",
|
|
pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Put the result into `address' and `netmask'.
|
|
*/
|
|
address->s_addr = htonl((octets[0] << 24) + (octets[1] << 16)
|
|
+ (octets[2] << 8) + octets[3]);
|
|
netmask->s_addr = htonl(netmasks_by_mask_length[netmask_length]);
|
|
|
|
/*
|
|
* Check address/netmask mismatch. (e.g. 192.168.10.8/16)
|
|
*/
|
|
if ((address->s_addr & netmask->s_addr) != address->s_addr) {
|
|
WARN("acl_parse_address - address/netmask mismatch \"%.100s\", "
|
|
"line %d\n", pattern, lineNo);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Return TRUE if access from `address' is permitted or not.
|
|
* Note that we returns TRUE if no access control pattern is registered.
|
|
*/
|
|
BOOL
|
|
acl_test(struct sockaddr *address)
|
|
{
|
|
acl_t *acl_entry;
|
|
struct in_addr inet_address;
|
|
|
|
if (acl == NULL)
|
|
return TRUE;
|
|
|
|
inet_address.s_addr = ((struct sockaddr_in *)address)->sin_addr.s_addr;
|
|
|
|
for (acl_entry = acl; acl_entry != NULL; acl_entry = acl_entry->next) {
|
|
if ((inet_address.s_addr & acl_entry->netmask.s_addr)
|
|
== acl_entry->address.s_addr) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Finalize the access control list `acl'.
|
|
*/
|
|
void
|
|
acl_finalize(void)
|
|
{
|
|
acl_t *acl_entry;
|
|
acl_t *saved_next;
|
|
|
|
acl_entry = acl;
|
|
while (acl_entry != NULL) {
|
|
saved_next = acl_entry->next;
|
|
free(acl_entry);
|
|
acl_entry = saved_next;
|
|
}
|
|
|
|
acl = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* main for test.
|
|
* `proxycnf.o' and `logging.o' are reuqired to build this test program.
|
|
*/
|
|
#ifdef TEST
|
|
|
|
#include <string.h>
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
char line[512];
|
|
char *newline;
|
|
struct sockaddr_in address;
|
|
|
|
printf("ACL allow/deny test program\n");
|
|
fflush(stdout);
|
|
|
|
if (config_load(argc, argv) != TRUE) {
|
|
printf("failed to load configurations\n");
|
|
return 1 ;
|
|
}
|
|
printf("loaded configuration.\n");
|
|
|
|
if (!acl_initialize()) {
|
|
printf("failed to initialize ACL\n");
|
|
return 1;
|
|
}
|
|
|
|
for (;;) {
|
|
printf("input address> ");
|
|
fflush(stdout);
|
|
if (fgets(line, 512, stdin) == NULL)
|
|
break;
|
|
|
|
newline = strpbrk(line, "\r\n");
|
|
if (newline != NULL)
|
|
*newline = '\0';
|
|
|
|
if (!inet_aton(line, &address.sin_addr)) {
|
|
printf("invalid address\n");
|
|
continue;
|
|
}
|
|
|
|
if (acl_test((struct sockaddr *)&address))
|
|
printf("access from %s is allowed.\n", line);
|
|
else
|
|
printf("access from %s is denied.\n", line);
|
|
}
|
|
|
|
acl_finalize();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* TEST */
|