9a8d732a13
memory usage tracking.
221 lines
4.8 KiB
C
221 lines
4.8 KiB
C
/* $Id: acl.c,v 1.14 2002-04-18 17:59:21 rjkaes Exp $
|
|
*
|
|
* This system handles Access Control for use of this daemon. A list of
|
|
* domains, or IP addresses (including IP blocks) are stored in a list
|
|
* which is then used to compare incoming connections.
|
|
*
|
|
* Copyright (C) 2000 Robert James Kaes (rjkaes@flarenet.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
|
|
#include "tinyproxy.h"
|
|
|
|
#include "acl.h"
|
|
#include "log.h"
|
|
#include "sock.h"
|
|
#include "utils.h"
|
|
|
|
struct acl_s {
|
|
acl_access_t acl_access;
|
|
enum { ACL_STRING, ACL_NUMERIC } type;
|
|
char *location;
|
|
int netmask;
|
|
struct acl_s *next;
|
|
};
|
|
|
|
static struct acl_s *access_list = NULL;
|
|
|
|
/*
|
|
* Take a netmask number (between 0 and 32) and returns a network ordered
|
|
* value for comparison.
|
|
*/
|
|
static in_addr_t
|
|
make_netmask(int netmask_num)
|
|
{
|
|
assert(netmask_num >= 0 && netmask_num <= 32);
|
|
|
|
return htonl(~((1 << (32 - netmask_num)) - 1));
|
|
}
|
|
|
|
/*
|
|
* Inserts a new access control into the list. The function will figure out
|
|
* whether the location is an IP address (with optional netmask) or a
|
|
* domain name.
|
|
*
|
|
* Returns:
|
|
* -1 on failure
|
|
* 0 otherwise.
|
|
*/
|
|
int
|
|
insert_acl(char *location, acl_access_t access_type)
|
|
{
|
|
size_t i;
|
|
struct acl_s **rev_acl_ptr, *acl_ptr, *new_acl_ptr;
|
|
char *nptr;
|
|
|
|
assert(location != NULL);
|
|
|
|
/*
|
|
* First check to see if the location is a string or numeric.
|
|
*/
|
|
for (i = 0; location[i] != '\0'; i++) {
|
|
/*
|
|
* Numeric strings can not contain letters, so test on it.
|
|
*/
|
|
if (isalpha((unsigned char) location[i])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add a new ACL to the list.
|
|
*/
|
|
rev_acl_ptr = &access_list;
|
|
acl_ptr = access_list;
|
|
while (acl_ptr) {
|
|
rev_acl_ptr = &acl_ptr->next;
|
|
acl_ptr = acl_ptr->next;
|
|
}
|
|
new_acl_ptr = safemalloc(sizeof(struct acl_s));
|
|
if (!new_acl_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
new_acl_ptr->acl_access = access_type;
|
|
|
|
if (location[i] == '\0') {
|
|
DEBUG2("ACL \"%s\" is a number.", location);
|
|
|
|
/*
|
|
* We did not break early, so this a numeric location.
|
|
* Check for a netmask.
|
|
*/
|
|
new_acl_ptr->type = ACL_NUMERIC;
|
|
nptr = strchr(location, '/');
|
|
if (nptr) {
|
|
*nptr++ = '\0';
|
|
|
|
new_acl_ptr->netmask = strtol(nptr, NULL, 10);
|
|
if (new_acl_ptr->netmask < 0
|
|
|| new_acl_ptr->netmask > 32) {
|
|
safefree(new_acl_ptr);
|
|
return -1;
|
|
}
|
|
} else {
|
|
new_acl_ptr->netmask = 32;
|
|
}
|
|
} else {
|
|
DEBUG2("ACL \"%s\" is a string.", location);
|
|
|
|
new_acl_ptr->type = ACL_STRING;
|
|
new_acl_ptr->netmask = 32;
|
|
}
|
|
|
|
new_acl_ptr->location = safestrdup(location);
|
|
if (!new_acl_ptr->location) {
|
|
safefree(new_acl_ptr);
|
|
return -1;
|
|
}
|
|
|
|
*rev_acl_ptr = new_acl_ptr;
|
|
new_acl_ptr->next = acl_ptr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Checks whether file descriptor is allowed.
|
|
*
|
|
* Returns:
|
|
* 1 if allowed
|
|
* 0 if denied
|
|
* -1 if error
|
|
*/
|
|
int
|
|
check_acl(int fd, const char* ip_address, const char* string_address)
|
|
{
|
|
struct acl_s *aclptr;
|
|
|
|
assert(fd >= 0);
|
|
assert(ip_address != NULL);
|
|
assert(string_address != NULL);
|
|
|
|
/*
|
|
* If there is no access list allow everything.
|
|
*/
|
|
aclptr = access_list;
|
|
if (!aclptr)
|
|
return 1;
|
|
|
|
while (aclptr) {
|
|
if (aclptr->type == ACL_STRING) {
|
|
size_t test_length = strlen(string_address);
|
|
size_t match_length = strlen(aclptr->location);
|
|
|
|
if (test_length < match_length) {
|
|
aclptr = aclptr->next;
|
|
continue;
|
|
}
|
|
|
|
if (strcasecmp
|
|
(string_address + (test_length - match_length),
|
|
aclptr->location) == 0) {
|
|
if (aclptr->acl_access == ACL_DENY) {
|
|
log_message(LOG_NOTICE,
|
|
"Unauthorized access from \"%s\"",
|
|
string_address);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
} else {
|
|
struct in_addr test_addr, match_addr;
|
|
in_addr_t netmask_addr;
|
|
|
|
if (ip_address[0] == 0) {
|
|
aclptr = aclptr->next;
|
|
continue;
|
|
}
|
|
|
|
inet_aton(ip_address, &test_addr);
|
|
inet_aton(aclptr->location, &match_addr);
|
|
|
|
netmask_addr = make_netmask(aclptr->netmask);
|
|
|
|
if ((test_addr.s_addr & netmask_addr) ==
|
|
(match_addr.s_addr & netmask_addr)) {
|
|
if (aclptr->acl_access == ACL_DENY) {
|
|
log_message(LOG_NOTICE,
|
|
"Unauthorized access from [%s].",
|
|
ip_address);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Dropped through... go on to the next one.
|
|
*/
|
|
aclptr = aclptr->next;
|
|
}
|
|
|
|
/*
|
|
* Deny all connections by default.
|
|
*/
|
|
log_message(LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].",
|
|
string_address, ip_address);
|
|
return 0;
|
|
}
|