diff --git a/acl.c b/acl.c new file mode 100644 index 0000000..6d59edd --- /dev/null +++ b/acl.c @@ -0,0 +1,113 @@ +/* + * These are ACL routines for the main module of CNTLM + * + * CNTLM 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 of the License, or (at your option) any later + * version. + * + * CNTLM 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + * St, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2007 David Kubicek + * + */ + +#include +#include +#include +#include +#include +#include + +#include "acl.h" +#include "socket.h" +#include "swap.h" + +/* + * TODO: retest ACLs on big-endian + */ + +/* + * Add the rule spec to the ACL list. + */ +int acl_add(plist_t *rules, char *spec, enum acl_t acl) { + struct in_addr source; + network_t *aux; + int i, mask = 32; + char *tmp; + + if (rules == NULL) + return 0; + + spec = strdupl(spec); + aux = (network_t *)new(sizeof(network_t)); + i = strcspn(spec, "/"); + if (i < strlen(spec)) { + spec[i] = 0; + mask = strtol(spec+i+1, &tmp, 10); + if (mask < 0 || mask > 32 || spec[i+1] == 0 || *tmp != 0) { + syslog(LOG_ERR, "ACL netmask for %s is invalid\n", spec); + free(aux); + free(spec); + return 0; + } + } + + if (!strcmp("*", spec)) { + source.s_addr = 0; + mask = 0; + } else { + if (!so_resolv(&source, spec)) { + syslog(LOG_ERR, "ACL source address %s is invalid\n", spec); + free(aux); + free(spec); + return 0; + } + } + + aux->ip = source.s_addr; + aux->mask = mask; + mask = swap32(~(((uint64_t)1 << (32-mask)) - 1)); + if ((source.s_addr & mask) != source.s_addr) + syslog(LOG_WARNING, "Subnet definition might be incorrect: %s/%d\n", inet_ntoa(source), aux->mask); + + syslog(LOG_INFO, "New ACL rule: %s %s/%d\n", (acl == ACL_ALLOW ? "allow" : "deny"), inet_ntoa(source), aux->mask); + *rules = plist_add(*rules, acl, (char *)aux); + + free(spec); + return 1; +} + +/* + * Takes client IP address (network order) and walks the + * ACL rules until a match is found, returning ACL_ALLOW + * or ACL_DENY accordingly. If no rule matches, connection + * is allowed (such is the case with no ACLs). + * + * Proper policy should always end with a default rule, + * targetting either "*" or "0/0" to explicitly express + * one's intentions. + */ +enum acl_t acl_check(plist_t rules, struct in_addr naddr) { + network_t *aux; + int mask; + + while (rules) { + aux = (network_t *)rules->aux; + mask = swap32(~(((uint64_t)1 << (32-aux->mask)) - 1)); + + if ((naddr.s_addr & mask) == (aux->ip & mask)) + return rules->key; + + rules = rules->next; + } + + return ACL_ALLOW; +} diff --git a/acl.h b/acl.h new file mode 100644 index 0000000..f44bc6b --- /dev/null +++ b/acl.h @@ -0,0 +1,45 @@ +/* + * These are ACL routines for the main module of CNTLM + * + * CNTLM 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 of the License, or (at your option) any later + * version. + * + * CNTLM 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + * St, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2007 David Kubicek + * + */ + +#ifndef _ACL_H +#define _ACL_H + +#include + +#include "utils.h" + +/* + * ACL rule datatypes. + */ +enum acl_t { + ACL_ALLOW = 0, + ACL_DENY +}; + +typedef struct { + unsigned int ip; + int mask; +} network_t; + +extern int acl_add(plist_t *rules, char *spec, enum acl_t acl); +extern enum acl_t acl_check(plist_t rules, struct in_addr naddr); + +#endif /* _ACL_H */