summaryrefslogtreecommitdiff
path: root/src/acl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/acl.c')
-rw-r--r--src/acl.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/acl.c b/src/acl.c
new file mode 100644
index 0000000..88f25b2
--- /dev/null
+++ b/src/acl.c
@@ -0,0 +1,214 @@
+/* $Id: acl.c,v 1.1 2000-09-12 00:08:48 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 <ctype.h>
+
+#include "acl.h"
+#include "log.h"
+#include "sock.h"
+
+struct acl_s {
+ acl_access_t 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. Somebody please clean this up. :)
+ */
+static in_addr_t make_netmask(int netmask_num)
+{
+ in_addr_t netmasks[] = {
+ 0x00000000, 0x80000000, 0xc0000000, 0xe0000000,
+ 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
+ 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
+ 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
+ 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000,
+ 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
+ 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0,
+ 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe,
+ 0xffffffff
+ };
+
+ return htonl(netmasks[netmask_num]);
+}
+
+/*
+ * 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)
+{
+ unsigned int i;
+ struct acl_s **rev_acl_ptr, *acl_ptr, *new_acl_ptr;
+ char *nptr;
+
+ /*
+ * First check to see if the location is a string or numeric.
+ */
+ for (i = 0; i < strlen(location); i++) {
+ if (isdigit(location[i]) != 0 && 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 = malloc(sizeof(struct acl_s));
+ if (!new_acl_ptr) {
+ return -1;
+ }
+
+ new_acl_ptr->access = access_type;
+
+ if (i != strlen(location)) {
+ /* We did 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 = atoi(nptr);
+ if (new_acl_ptr->netmask < 0 || new_acl_ptr->netmask > 32) {
+ free(new_acl_ptr);
+ return -1;
+ }
+ } else {
+ new_acl_ptr->netmask = 32;
+ }
+ } else {
+ new_acl_ptr->type = ACL_STRING;
+ new_acl_ptr->netmask = 32;
+ }
+
+ new_acl_ptr->location = strdup(location);
+ if (!new_acl_ptr->location) {
+ free(new_acl_ptr);
+ return -1;
+ }
+
+ *rev_acl_ptr = new_acl_ptr;
+ new_acl_ptr->next = acl_ptr;
+
+ return 0;
+}
+
+/*
+ * Checks where file descriptor is allowed.
+ *
+ * Returns:
+ * 1 if allowed
+ * 0 if denied
+ * -1 if error
+ */
+int check_acl(int fd)
+{
+ struct acl_s *aclptr;
+ char ip_address[PEER_IP_LENGTH];
+ char string_address[PEER_STRING_LENGTH];
+
+ /*
+ * If there is no access list allow everything.
+ */
+ aclptr = access_list;
+ if (!aclptr)
+ return 1;
+
+ /*
+ * Get the IP address and the string domain.
+ */
+ getpeer_ip(fd, ip_address);
+ getpeer_string(fd, string_address);
+
+ while (aclptr) {
+ if (aclptr->type == ACL_STRING) {
+ int test_length = strlen(string_address);
+ int 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->access == ACL_DENY) {
+ log(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->access == ACL_DENY) {
+ log(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(LOG_NOTICE, "Unauthorized connection from %s [%s]", string_address, ip_address);
+ return 0;
+}