From: Amos Jeffries Date: Tue, 20 Jul 2010 14:16:00 +0000 (+1200) Subject: Author: Chad E. Naugle X-Git-Tag: SQUID_3_2_0_1~46 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf1a7ece574ba696a111e941af3c1c3eb964f449;p=thirdparty%2Fsquid.git Author: Chad E. Naugle Bug 2905: eDirectory (8.7 & 8.8) IPv4/IPv6->Username external ACL helper Original code import. --- diff --git a/helpers/external_acl/eDirectory_userip/INSTALL b/helpers/external_acl/eDirectory_userip/INSTALL new file mode 100644 index 0000000000..4c1e1ae81c --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/INSTALL @@ -0,0 +1,38 @@ +* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle +* +******************************************************************************** +* +* INSTALL -- +* + +To install squid_edir_lookup, you need to do the following. + +1- Unpack this tarball. +2- Port? + (See PORTING, program was written under a SuSe Linux Enterprise Server 10 SP2 + + Open Enterprise Server 2 SP1 environment) +3- Run 'make'. +4- Run 'make install'. (Or optionally copy 'squid_edir_iplookup' to somewhere. +5- Edit squid.conf with the following lines as an example: + +# Setup External ACL Helper with parameters (if required) +external_acl_type IPUser ttl=1800 negative_ttl=30 children=10 %SRC /usr/sbin/squid_edir_iplookup + +# Next line sets how long the credentials last before re-authentication is required. +auth_param basic credentialsttl 30 minutes + +# Next lines are required, and the actual ACL's may be customized to suit your needs. +# In this example, the 'Internet_Allowed' and 'Internet_Denied' are Groups that users may +# be used to control internet access, which can also be stacked against other ACL's. +# Use of the groups is NOT REQUIRED. +acl edirectory_users_allowed external IPUser Internet_Allowed +acl edirectory_users_denied external IPUser Internet_Denied + +# Next lines are used to bind ACL's to what they actually do. Remember that Squid's +# Default is to ALLOW ALL. +http_access deny edirectory_users_denied +http_access allow edirectory_users_allowed +http_access deny all + +6- START Squid. With some luck, you should have a blind eDirectory authenticator, + That is, without the Users' knowledge that there even *IS* a proxy server! diff --git a/helpers/external_acl/eDirectory_userip/ISSUES b/helpers/external_acl/eDirectory_userip/ISSUES new file mode 100644 index 0000000000..ac854ca860 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/ISSUES @@ -0,0 +1,29 @@ +* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle +* +******************************************************************************** +* +* ISSUES -- +* + +- Possible Spelling errors :) + +- IPv6 support has yet to be TESTED in a real IPv6 environment, but the code is in place to read IPv6 + networkAddress fields, please attempt this in a TESTING environment first. Please read the + README file to contact me regarding IPv6 support development. + +- There is a known issue regarding Novell's Client for Windows, that is mostly fixed by using + version 4.91 SP3+, with the 'Auto-Reconnect' feature not re-populating the networkAddress + field in eDirectory. + +- I have also expereinced an issue related to using NetWare 6.5 (SP6 and lower?) and connection licsensing. + It appears that whenever a server runs low on connection licsenes, that it SOMETIMES does + NOT populate the networkAddress fields correctly. + +- I *STRONGLY RECOMMEND* using the latest version of the Novell Client in all situations *BEFORE* + seeking support! You may also want to MAKE SURE your servers also have the latest service packs. + +- Majority of Proxy Authentication issues can be resolved by having the users' REBOOT if their networkAddress + is not correct, or using squid_auth_ldap as a fallback. Check ConsoleOne, etc to verify thier + networkAddress fields to troubleshoot. + +- More PROBLEMS using the helper? Check README for contact information. diff --git a/helpers/external_acl/eDirectory_userip/Makefile b/helpers/external_acl/eDirectory_userip/Makefile new file mode 100644 index 0000000000..51388299d3 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/Makefile @@ -0,0 +1,41 @@ +# squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle +# +#******************************************************************************* +# +# Makefile -- +# +# Builds squid_edir_lookup when run. PORTING NEEDED. +# + +CC = gcc +LD = gcc +CFLAGS = -O2 -Wall -Wextra +PROGNAME = squid_edir_iplookup +UID = squid +GID = nogroup +OBJECTS = main.o iplookup.o util.o +LIBS = -lldap -llber +HEADERS = config.h main.h util.h iplookup.h + +all: ${PROGNAME} + +${PROGNAME}: ${OBJECTS} + ${LD} ${CFLAGS} -o ${PROGNAME} ${OBJECTS} ${LIBS} + chmod 0550 ${PROGNAME} + chown ${UID} ${PROGNAME} + chgrp ${GID} ${PROGNAME} + +clean: + rm -f *.o ${PROGNAME} + +install: ${PROGNAME} + cp ${PROGNAME} /usr/sbin + +main.o: ${HEADERS} main.c + ${CC} ${CFLAGS} -c main.c + +iplookup.o: ${HEADERS} iplookup.c + ${CC} ${CFLAGS} -c iplookup.c + +util.o: ${HEADERS} util.c + ${CC} ${CFLAGS} -c util.c diff --git a/helpers/external_acl/eDirectory_userip/README b/helpers/external_acl/eDirectory_userip/README new file mode 100644 index 0000000000..b31aad030c --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/README @@ -0,0 +1,23 @@ +* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle +* +******************************************************************************** +* +* README -- +* + +This program has been written in order to solve the problems associated with running the +Perl squid_ip_lookup.pl as a squid external helper that has been provided by various +sources, including Novell, Inc. + +The limitations of the Perl script involved memory/cpu utilization, speed, and the lack +of eDirectory 8.8 support, and IPv6 support. + +This program is being provided to the Squid Cache Developers as a donation of code to +help further develop Squid, and it's seamless integration with a Novell Open Enterprise Server +deployment. Hopefully one day Novell will include updated versions of squid into their +mainstream OES releases, such as the 3.1.x code tree. + +This program has been used in a STABLE PRODUCTION ENTERPRISE environment for months before +being released to the Squid Development team, but that does not mean that bugs do not exist. + +If they do, please contact myself for right now. chad.naugle@travimp.com. diff --git a/helpers/external_acl/eDirectory_userip/config.h b/helpers/external_acl/eDirectory_userip/config.h new file mode 100644 index 0000000000..c3421e4239 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/config.h @@ -0,0 +1,76 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * config.h -- + * + * Runtime default configuration. + * + */ + +#ifndef _HAVE_CONFIG_H +#define _HAVE_CONFIG_H + +/* Default program name */ +#define DEFAULT_PROGRAM_NAME "squid_edir_iplookup" + +/* Hostname or IP address of LDAP server, default is IPv4 localhost (127.0.0.1) */ +/* #define DEFAULT_LDAP_HOST */ + +/* Should be 389 or 636 for SSL, but you can change it here */ +/* #define DEFAULT_LDAP_PORT */ + +/* Default LDAP protocol version, 1, 2, or 3 -- 3 for TLS/SSL is defaulted */ +/* #define DEFAULT_LDAP_VERSION */ + +/* Base DN to search from, Ie. o=TREE */ +/* #define DEFAULT_BASE_DN */ + +/* Bind DN to perform searches, Base DN will be appended, or you can specify it here */ +/* #define DEFAULT_BIND_DN */ + +/* Binding password to perform searches */ +/* #define DEFAULT_BIND_PASS */ + +/* 0 - base, 1 - one level, 2 - subtree */ +/* #define DEFAULT_SEARCH_SCOPE 2 */ + +/* Base search filter. Ie. (&(objectClass=Person)(networkAddress=*)) */ +/* #define DEFAULT_SEARCH_FILTER "(&(objectClass=User)(networkAddress=*))" */ + +/* Default maximum length of all generic array variables */ +#define DEFAULT_MAXLEN 1024 + +/* Default to IPv4 enabled? */ +#define DEFAULT_USE_IPV4 + +/* Default to IPv6 enabled? (Enable both for IPv4-in-IPv6) */ +/* #define DEFAULT_USE_IPV6 */ + +/* Default to REQUIRE a groupMembership? */ +/* #define DEFAULT_GROUP_REQUIRED */ + +/* Default to TLS enabled? */ +#define DEFAULT_USE_TLS + +/* Default to debugging output? (ie. No -d required) */ +/* #define DEFAULT_DEBUG */ + +#endif diff --git a/helpers/external_acl/eDirectory_userip/iplookup.c b/helpers/external_acl/eDirectory_userip/iplookup.c new file mode 100644 index 0000000000..41ccbb45ff --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/iplookup.c @@ -0,0 +1,937 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * iplookup.c -- + * + * ldap_t data struct manipulation, and LDAP server communication. + * + */ + +#include "main.h" +#include "util.h" +#include "iplookup.h" + +/* InitLDAP() - + * + * Initalize LDAP structure for use, zeroing out all variables. + * + */ +void InitLDAP(ldap_t *l) { + if (l == NULL) return; + + l->lp = NULL; + if (l->lm != NULL) + ldap_msgfree(l->lm); + if (l->val != NULL) + ldap_value_free_len(l->val); + l->lm = NULL; + l->val = NULL; + memset(l->basedn, '\0', sizeof(l->basedn)); + memset(l->host, '\0', sizeof(l->host)); + memset(l->dn, '\0', sizeof(l->dn)); + memset(l->passwd, '\0', sizeof(l->passwd)); + memset(l->search_filter, '\0', sizeof(l->search_filter)); + memset(l->search_ip, '\0', sizeof(l->search_ip)); + memset(l->userid, '\0', sizeof(l->userid)); + l->status = 0; + l->status |= LDAP_INIT_S; + l->port = 0; + l->scope = -1; + l->type = 0; + l->ver = 0; + l->num_ent = 0; /* Number of entries in l->lm */ + l->num_val = 0; /* Number of entries in l->val */ + + /* Set default settings from conf */ + if (conf.basedn[0] != '\0') + strncpy(l->basedn, conf.basedn, sizeof(l->basedn)); + if (conf.host[0] != '\0') + strncpy(l->host, conf.host, sizeof(l->host)); + if (conf.port != 0) + l->port = conf.port; + if (conf.dn[0] != '\0') + strncpy(l->dn, conf.dn, sizeof(l->dn)); + if (conf.passwd[0] != '\0') + strncpy(l->passwd, conf.passwd, sizeof(l->passwd)); + if (conf.search_filter[0] != '\0') + strncpy(l->search_filter, conf.search_filter, sizeof(l->search_filter)); + if (!(conf.scope < 0)) + l->scope = conf.scope; + if (conf.mode & MODE_IPV4) + l->status |= LDAP_IPV4_S; + if (conf.mode & MODE_IPV6) + l->status |= LDAP_IPV6_S; +} + +/* OpenLDAP() - + * + * Build LDAP struct with hostname and port, and ready it for binding. + * + */ +int OpenLDAP(ldap_t *l, char *h, unsigned int p) { + if ((l == NULL) || (h == NULL)) return -1; + if (!(l->status & LDAP_INIT_S)) return -2; /* Not initalized, or might be in use */ + + strncpy(l->host, h, sizeof(l->host)); + if (p > 0) + l->port = p; + else + l->port = LDAP_PORT; /* Default is port 389 */ + +#ifdef NETSCAPE_SSL + if (l->port == LDAPS_PORT) + l->status |= (LDAP_SSL_S | LDAP_TLS_S); /* SSL Port: 636 */ +#endif + +#ifdef USE_LDAP_INIT + l->lp = ldap_init(l->host, l->port); +#else + l->lp = ldap_open(l->host, l->port); +#endif + if (l->lp == NULL) return -3; /* Unable to connect */ + + /* set status */ + l->status &= ~(LDAP_INIT_S); + l->status |= LDAP_OPEN_S; + return LDAP_SUCCESS; +} + +/* CloseLDAP() - + * + * Close LDAP connection, and clean up data structure. + * + */ +int CloseLDAP(ldap_t *l) { + int s; + if (l == NULL) return -1; + if (l->lp == NULL) return -2; + if (!(l->status & LDAP_OPEN_S)) return -3; /* Connection not open */ + if (l->lp == NULL) return -4; /* Error */ + + if (l->lm != NULL) { + ldap_msgfree(l->lm); + l->lm = NULL; + } + + if (l->val != NULL) { + ldap_value_free_len(l->val); + l->val = NULL; + } + + /* okay, so it's open, close it - No need to check other criteria */ + s = ldap_unbind(l->lp); + if (s == LDAP_SUCCESS) + l->status &= ~(LDAP_OPEN_S | LDAP_BIND_S); + return s; /* returns unbind result */ +} + +/* SetVerLDAP() - + * + * Set LDAP version number for connection to of 1, 2, or 3 + * + */ +int SetVerLDAP(ldap_t *l, int v) { + int x; + if ((l == NULL) || (v > 3) || (v < 1)) return -1; + if (l->lp == NULL) return -2; + if (l->status & LDAP_BIND_S) return -3; /* Already binded */ + if (!(l->status & LDAP_OPEN_S)) return -4; /* Not open */ + + /* set version */ + x = ldap_set_option(l->lp, LDAP_OPT_PROTOCOL_VERSION, &v); + return x; /* returns result code */ +} + +/* BindLDAP() - + * + * Bind LDAP connection (Open) using optional dn and password, of + * + */ +int BindLDAP(ldap_t *l, char *dn, char *pw, unsigned int t) { + int s; + if (l == NULL) return -1; + if (!(l->status & LDAP_OPEN_S)) return -2; /* Not open */ + if (l->status & LDAP_BIND_S) return -3; /* Already binded */ + if (l->lp == NULL) return -4; /* Error */ + + /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */ + if (dn != NULL) { + if ((l->basedn[0] != '\0') && (strstr(dn, l->basedn) == NULL)) { + /* We got a basedn, but it's not part of dn */ + strncpy(l->dn, dn, sizeof(l->dn)); + strcat(l->dn, ","); + strncat(l->dn, l->basedn, sizeof(l->dn)); + } + else + strncpy(l->dn, dn, sizeof(l->dn)); + } + if (pw != NULL) + strncpy(l->passwd, pw, sizeof(l->passwd)); + + /* Type ? */ + switch (t) { + case LDAP_AUTH_NONE: + l->type = t; + break; + case LDAP_AUTH_SIMPLE: + l->type = t; + break; + case LDAP_AUTH_SASL: + l->type = t; + break; + case LDAP_AUTH_KRBV4: + l->type = t; + break; + case LDAP_AUTH_KRBV41: + l->type = t; + break; + case LDAP_AUTH_KRBV42: + l->type = t; + break; +#ifdef LDAP_AUTH_TLS + case LDAP_AUTH_TLS: /* Added for chicken switch to TLS-enabled without using SSL */ + l->type = t; + break; +#endif + default: + l->type = LDAP_AUTH_NONE; + break; /* Default to anonymous bind */ + } + + /* Bind */ +#ifdef NETSCAPE_SSL + if (l->type == LDAP_AUTH_TLS) + s = ldap_start_tls_s(l->lp, NULL, NULL); + else +#endif + s = ldap_bind_s(l->lp, l->dn, l->passwd, l->type); + if (s == LDAP_SUCCESS) + l->status |= LDAP_BIND_S; /* Success */ + return s; /* LDAP Error code */ +} + +/* + * ConvertIP() - + * + * Take an IPv4 address in dot-decimal or IPv6 notation, and convert to 2-digit HEX stored in l->search_ip + * This is the networkAddress that we search LDAP for. + * + */ +int ConvertIP(ldap_t *l, char *ip) { + char bufa[MAXLEN], bufb[MAXLEN], obj[MAXLEN]; + char hexc[4], *p; + size_t s; + long x; + int i, j, t, swi; /* IPv6 "::" cut over toggle */ + if ((l == NULL) || (ip == NULL)) return -1; + if (!(l->status & LDAP_BIND_S)) return -2; /* Not binded */ + + s = strlen(ip); + memset(bufa, '\0', sizeof(bufa)); + memset(bufb, '\0', sizeof(bufb)); + memset(obj, '\0', sizeof(obj)); + /* SplitString() will zero out bufa & obj at each call */ + memset(l->search_ip, '\0', sizeof(l->search_ip)); + strncpy(bufa, ip, s); /* To avoid segfaults, use bufa instead of ip */ + swi = 0; + + if ((conf.mode & MODE_IPV6) && (conf.mode & MODE_IPV4)) { + if (strcasestr(bufa, ":FFFF:") == NULL) + return -3; /* Unable to find IPv4-in-IPv6 notation */ + } + if (conf.mode & MODE_IPV6) { + /* Search for :: in string */ + if ((bufa[0] == ':') && (bufa[1] == ':')) { + /* bufa starts with a ::, so just copy and clear */ + strncpy(bufb, bufa, sizeof(bufa)); + memset(bufa, '\0', strlen(bufa)); + swi++; /* Indicates that there is a bufb */ + } + else if ((bufa[0] == ':') && (bufa[1] != ':')) { + /* bufa starts with a :, a typo so just fill in a ':', cat and clear */ + bufb[0] = ':'; + strncat(bufb, bufa, sizeof(bufa)); + memset(bufa, '\0', strlen(bufa)); + swi++; /* Indicates that there is a bufb */ + } + else { + p = strstr(bufa, "::"); + if (p != NULL) { + /* Found it, break bufa down and split into bufb here */ + memset(bufb, '\0', strlen(bufb)); + i = strlen(p); + memcpy(bufb, p, i); + *p = '\0'; + bufb[i] = '\0'; + swi++; /* Indicates that there is a bufb */ + } + } + } + s = strlen(bufa); + if (s < 1) + s = strlen(bufb); + while (s > 0) { + if ((conf.mode & MODE_IPV4) && (conf.mode & MODE_IPV6) && (swi > 1)) { + if (strchr(bufb, ':') != NULL) { + /* Split Off leading :ffff: */ + t = SplitString(bufb, s, ':', obj, sizeof(obj)); + if (t > 0) { + strcpy(hexc, "FFFF"); + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + } + else + break; /* reached end */ + } + else { + /* Break down IPv4 address nested in the IPv6 address */ + t = SplitString(bufb, s, '.', obj, sizeof(obj)); + if (t > 0) { + errno = 0; + x = strtol(obj, (char **)NULL, 10); + if (((x < 0) || (x > 255)) || ((errno != 0) && (x == 0)) || ((obj[0] != '0') && (x == 0))) + return -4; /* Out of bounds -- Invalid address */ + memset(hexc, '\0', sizeof(hexc)); + snprintf(hexc, sizeof(hexc), "%.2X", (int)x); + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + } + else + break; /* reached end of octet */ + } + } + else if ((conf.mode & MODE_IPV4) && (swi == 0)) { + /* Break down IPv4 address */ + t = SplitString(bufa, s, '.', obj, sizeof(obj)); + if (t > 0) { + errno = 0; + x = strtol(obj, (char **)NULL, 10); + if (((x < 0) || (x > 255)) || ((errno != 0) && (x == 0)) || ((obj[0] != '0') && (x == 0))) + return -4; /* Out of bounds -- Invalid address */ + memset(hexc, '\0', sizeof(hexc)); + snprintf(hexc, sizeof(hexc), "%.2X", (int)x); + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + } + else + break; /* reached end of octet */ + } + else if (conf.mode & MODE_IPV6) { + /* Break down IPv6 address */ + if (swi > 1) + t = SplitString(bufb, s, ':', obj, sizeof(obj)); /* After "::" */ + else + t = SplitString(bufa, s, ':', obj, sizeof(obj)); /* Before "::" */ + /* Convert octet by size (t) - and fill 0's */ + switch (t) { /* IPv6 is already in HEX, copy contents */ + case 4: + hexc[0] = (char) toupper((int)obj[0]); + i = (int)hexc[0]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[1] = (char) toupper((int)obj[1]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + hexc[0] = (char) toupper((int)obj[2]); + i = (int)hexc[0]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[1] = (char) toupper((int)obj[3]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + break; + case 3: + hexc[0] = '0'; + hexc[1] = (char) toupper((int)obj[0]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + hexc[0] = (char) toupper((int)obj[1]); + i = (int)hexc[0]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[1] = (char) toupper((int)obj[2]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + break; + case 2: + strncat(l->search_ip, "00", sizeof(l->search_ip)); + hexc[0] = (char) toupper((int)obj[0]); + i = (int)hexc[0]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[1] = (char) toupper((int)obj[1]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + break; + case 1: + strncat(l->search_ip, "00", sizeof(l->search_ip)); + hexc[0] = '0'; + hexc[1] = (char) toupper((int)obj[0]); + i = (int)hexc[1]; + if (!isxdigit(i)) + return -5; /* Out of bounds */ + hexc[2] = '\0'; + strncat(l->search_ip, hexc, sizeof(l->search_ip)); + break; + default: + if (t > 4) + return -5; + break; + } + /* Code to pad the address with 0's between a '::' */ + if ((strlen(bufa) == 0) && (swi == 1)) { + /* We are *AT* the split, pad in some 0000 */ + if ((conf.mode & MODE_IPV4) && (conf.mode & MODE_IPV6)) + t = 5; /* IPv4-in-IPv6 mode, 5 blocks only */ + else { + t = strlen(bufb); + /* How many ':' exist in bufb ? */ + j = 0; + for (i = 0; i < t; i++) { + if (bufb[i] == ':') + j++; + } + j--; /* Preceeding "::" doesn't count */ + t = 8 - (strlen(l->search_ip) / 4) - j; /* Remainder */ + } + if (t > 0) { + for (i = 0; i < t; i++) + strncat(l->search_ip, "0000", sizeof(l->search_ip)); + } + } + } + if ((bufa[0] == '\0') && (swi > 0)) { + s = strlen(bufb); + swi++; + } + else + s = strlen(bufa); + } + s = strlen(l->search_ip); + + /* CHECK sizes of address, truncate or pad */ + /* if "::" is at end of ip, then pad another block or two */ + while ((conf.mode & MODE_IPV6) && (s < 32)) { + strncat(l->search_ip, "0000", sizeof(l->search_ip)); + s = strlen(l->search_ip); + } + if ((conf.mode & MODE_IPV6) && (s > 32)) { + /* Too long, truncate */ + l->search_ip[32] = '\0'; + s = strlen(l->search_ip); + } + /* If at end of ip, and its not long enough, then pad another block or two */ + while ((conf.mode & MODE_IPV4) && (s < 8)) { + strncat(l->search_ip, "00", sizeof(l->search_ip)); + s = strlen(l->search_ip); + } + if ((conf.mode & MODE_IPV4) && !(conf.mode & MODE_IPV6) && (s > 8)) { + /* Too long, truncate */ + l->search_ip[8] = '\0'; + s = strlen(l->search_ip); + } + + /* Completed, s is length of address in HEX */ + return s; +} + +/* + * SearchFilterLDAP() - + * + * Build LDAP Search Filter string and copy to l->search_filter + * + */ +int SearchFilterLDAP(ldap_t *l, char *group) { + size_t i, j, s; + int swi; + char bufa[MAXLEN], bufb[MAXLEN], bufc[MAXLEN], bufd[MAXLEN], bufg[MAXLEN]; + if (l == NULL) return -1; + if (!(l->status & LDAP_BIND_S)) return -2; /* Must be Bound first */ + if (l->search_ip[0] == '\0') return -3; /* Search IP is required */ + + /* Zero out if not already */ + memset(bufa, '\0', strlen(bufa)); + memset(bufb, '\0', strlen(bufb)); + memset(bufc, '\0', strlen(bufc)); + memset(bufd, '\0', strlen(bufd)); + memset(bufg, '\0', strlen(bufg)); + +// debug("SearchFilterLDAP", "Building... (Adding '\\' to IP...) "); + s = strlen(l->search_ip); + bufc[0] = '\134'; + swi = 0; + j = 1; + for (i = 0; i < s; i++) { + if (swi == 2) { + bufc[j] = '\134'; + j++; + bufc[j] = l->search_ip[i]; + j++; + swi = 1; + } + else { + bufc[j] = l->search_ip[i]; + j++; + swi++; + } + } + if (group == NULL) { + /* No groupMembership= to add, yay! */ + strcpy(bufa, "(&"); + strncat(bufa, conf.search_filter, sizeof(bufa)); + /* networkAddress */ + snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", \ + bufc, bufc, bufc); + if (conf.mode & MODE_IPV6) { + snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \ + bufc, bufc); + strncat(bufb, bufd, sizeof(bufb)); + } + else + strncat(bufb, ")", sizeof(bufb)); + debug("SearchFilterLDAP", "bufb: %s\n", bufb); + strncat(bufa, bufb, sizeof(bufa)); + strncat(bufa, ")", sizeof(bufa)); + } + else { + /* Needs groupMembership= to add... */ + strcpy(bufa, "(&(&"); + strncat(bufa, conf.search_filter, sizeof(bufa)); + /* groupMembership */ + snprintf(bufg, sizeof(bufg), "(groupMembership=cn=%s", group); + if ((l->basedn[0] != '\0') && (strstr(group, l->basedn) == NULL)) { + strncat(bufg, ",", sizeof(bufg)); + strncat(bufg, l->basedn, sizeof(bufg)); + } + strncat(bufg, ")", sizeof(bufg)); + debug("SearchFilterLDAP", "bufg: %s\n", bufg); + strncat(bufa, bufg, sizeof(bufa)); + /* networkAddress */ + snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", \ + bufc, bufc, bufc); + if (conf.mode & MODE_IPV6) { + snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \ + bufc, bufc); + strncat(bufb, bufd, sizeof(bufb)); + } + else + strncat(bufb, ")", sizeof(bufb)); + debug("SearchFilterLDAP", "bufb: %s\n", bufb); + strncat(bufa, bufb, sizeof(bufa)); + strncat(bufa, "))", sizeof(bufa)); + } + s = strlen(bufa); + strcpy(l->search_filter, bufa); + return s; +} + +/* + * SearchLDAP() - + * + * Initate LDAP query, under levels, filtering matches with and optionally + * will generally be networkAddress ... + * + */ +int SearchLDAP(ldap_t *l, int scope, char *filter, char **attrs) { + int s; + char ft[MAXLEN]; + if ((l == NULL) || (filter == NULL)) return -1; /* If attrs is NULL, then all attrs will return */ + if (scope < 0) return -2; /* We require a scope */ + if (l->lp == NULL) return -3; + if (!(l->status & LDAP_BIND_S)) return -4; /* Must be bound */ + if (l->status & LDAP_SEARCH_S) return -5; /* Must not already be searching */ + if (l->basedn[0] == '\0') return -6; /* We require a basedn */ + if (l->lm != NULL) + ldap_msgfree(l->lm); /* Make sure l->lm is empty */ + + /* FIX IT -- ?? Narrow results to include the IP Address ?? */ + + if (filter == NULL) /* if filter is NULL, then return ALL networkAddress */ + strcpy(ft, "(&(objectClass=User)(networkAddress=*))"); + else + strncpy(ft, filter, sizeof(ft)); + + /* We have a binded connection, with a free l->lm, so let's get this done */ + switch (scope) { + case 0: + s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_BASE, ft, attrs, 0, &(l->lm)); + break; + case 1: + s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm)); + break; + case 2: + s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_SUBTREE, ft, attrs, 0, &(l->lm)); + break; + default: + /* Only search BASE by default */ + s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_BASE, ft, attrs, 0, &(l->lm)); + break; + } + + /* FIX IT -- ?? Narrow results to include the IP Address ?? */ + + if (s == LDAP_SUCCESS) { + l->status |= (LDAP_SEARCH_S); /* Mark as searched */ + l->num_ent = ldap_count_entries(l->lp, l->lm); /* Counted */ + } + else + l->num_ent = (-1); + return s; /* Return search value */ +} + +/* + * GetValLDAP() - + * + * Scan LDAP and look for search-attr, then return results in l->val + * + */ +int GetValLDAP(ldap_t *l, char *attr) { + ber_len_t i, j; + ber_len_t x; + int c; + LDAPMessage *ent; + if ((l == NULL) || (attr == NULL)) return -1; + if (l->lp == NULL) return -2; + if (!(l->status & LDAP_SEARCH_S)) return -3; /* Not searched */ + if (l->num_ent <= 0) return -4; /* No entries found */ + if (l->val != NULL) + ldap_value_free_len(l->val); /* Clear data before populating */ + l->num_val = 0; + if (l->status & LDAP_VAL_S) + l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */ + + /* Sift through entries -- Look for matches */ + for (ent = ldap_first_entry(l->lp, l->lm); ent != NULL; ent = ldap_next_entry(l->lp, ent)) { + l->val = ldap_get_values_len(l->lp, ent, attr); + if (l->val != NULL) { + x = ldap_count_values_len(l->val); /* We got x values ... */ + l->num_val = x; + if (x > 0) { + /* Display all values */ + for (i = 0; i < x; i++) { + debug("GetValLDAP", "value[%zd]: \"%s\"\n", i, l->val[i]->bv_val); + debug("GetValLDAP", "value[%zd]: ", i); + for (j = 0; j < (l->val[i]->bv_len); j++) { + c = (int) l->val[i]->bv_val[j]; + if (c < 0) + c = c + 256; + debugx("%.2X", c); + } + debugx("\n"); + } +/* CRASHES?!?! + if (ent != NULL) + ldap_msgfree(ent); +*/ + if (l->lm != NULL) { + ldap_msgfree(l->lm); + l->lm = NULL; + } + l->num_ent = 0; + l->status &= ~(LDAP_SEARCH_S); + l->status |= LDAP_VAL_S; + return LDAP_SUCCESS; /* Found it */ + } + } + /* Attr not found, continue */ + } + /* No entries found using attr */ + if (l->val != NULL) + ldap_value_free_len(l->val); +/* + if (ent != NULL) + ldap_msgfree(ent); +*/ + if (l->lm != NULL) { + ldap_msgfree(l->lm); + l->lm = NULL; + } + l->num_ent = 0; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return -5; /* Not found */ +} + +/* + * SearchIPLDAP() - + * + * Scan LDAP and get all networkAddress Values, and see if they match l->search_ip + * Actual IP matching routine for eDirectory + * + */ +int SearchIPLDAP(ldap_t *l, char *uid) { + ber_len_t i, x; + ber_len_t j, k; + ber_len_t y, z; + int c; + char bufa[MAXLEN], bufb[MAXLEN], hexc[4]; + LDAPMessage *ent; + struct berval **ber; + if ((l == NULL) || (uid == NULL)) return -1; + if (l->lp == NULL) return -2; + if (!(l->status & LDAP_SEARCH_S)) return -3; /* Not searched */ + if (l->num_ent <= 0) return -4; /* No entries found */ + if (l->val != NULL) + ldap_value_free_len(l->val); /* Clear data before populating */ + l->num_val = 0; + if (l->status & LDAP_VAL_S) + l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */ + + /* Sift through entries */ + for (ent = ldap_first_entry(l->lp, l->lm); ent != NULL; ent = ldap_next_entry(l->lp, ent)) { + l->val = ldap_get_values_len(l->lp, ent, "networkAddress"); + ber = ldap_get_values_len(l->lp, ent, "cn"); + if (l->val != NULL) { + x = ldap_count_values_len(l->val); /* We got x values ... */ + l->num_val = x; + if (x > 0) { + /* Display all values */ + for (i = 0; i < x; i++) { + j = l->val[i]->bv_len; + memcpy(bufa, l->val[i]->bv_val, j); + z = SplitString(bufa, j, '#', bufb, sizeof(bufb)); + debug("SearchIPLDAP", "value[%zd]: SplitString(", i); + for (k = 0; k < z; k++) { + c = (int) bufb[k]; + if (c < 0) + c = c + 256; + debugx("%.2X", c); + } + debugx(", "); + for (k = 0; k < (j - z - 1); k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + debugx("%.2X", c); + } + debugx("): %zd\n", z); + z = j - z - 1; + j = atoi(bufb); + switch (j) { + case 0: /* IPX address (We don't support these right now) */ + break; + case 1: /* IPv4 address (eDirectory 8.7 and below) */ + /* bufa is the address, just compare it */ + if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S)) + break; /* Not looking for IPv4 */ + for (k = 0; k < z; k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + snprintf(hexc, sizeof(hexc), "%.2X", c); + if (k == 0) + strncpy(bufb, hexc, sizeof(bufb)); + else + strncat(bufb, hexc, sizeof(bufb)); + } + y = strlen(bufb); + /* Compare value with IP */ + if (bcmp(l->search_ip, bufb, y) == 0) { + /* We got a match! - Scan 'ber' for 'cn' values */ + z = ldap_count_values_len(ber); + for (j = 0; j < z; j++) + strncpy(uid, ber[j]->bv_val, ber[j]->bv_len); + ldap_value_free_len(l->val); + l->val = NULL; + ldap_value_free_len(ber); + ber = NULL; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return LDAP_SUCCESS; /* We got our userid */ + } + /* Not matched, continue */ + break; + case 8: /* IPv4 (UDP) address (eDirectory 8.8 and higher) */ + /* bufa + 2 is the address (skip 2 digit port) */ + if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S)) + break; /* Not looking for IPv4 */ + for (k = 2; k < z; k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + snprintf(hexc, sizeof(hexc), "%.2X", c); + if (k == 2) + strncpy(bufb, hexc, sizeof(bufb)); + else + strncat(bufb, hexc, sizeof(bufb)); + } + y = strlen(bufb); + /* Compare value with IP */ + if (bcmp(l->search_ip, bufb, y) == 0) { + /* We got a match! - Scan 'ber' for 'cn' values */ + z = ldap_count_values_len(ber); + for (j = 0; j < z; j++) + strncpy(uid, ber[j]->bv_val, ber[j]->bv_len); + ldap_value_free_len(l->val); + l->val = NULL; + ldap_value_free_len(ber); + ber = NULL; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return LDAP_SUCCESS; /* We got our userid */ + } + /* Not matched, continue */ + break; + case 9: /* IPv4 (TCP) address (eDirectory 8.8 and higher) */ + /* bufa + 2 is the address (skip 2 digit port) */ + if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S)) + break; /* Not looking for IPv4 */ + for (k = 2; k < z; k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + snprintf(hexc, sizeof(hexc), "%.2X", c); + if (k == 2) + strncpy(bufb, hexc, sizeof(bufb)); + else + strncat(bufb, hexc, sizeof(bufb)); + } + y = strlen(bufb); + /* Compare value with IP */ + if (bcmp(l->search_ip, bufb, y) == 0) { + /* We got a match! - Scan 'ber' for 'cn' values */ + z = ldap_count_values_len(ber); + for (j = 0; j < z; j++) + strncpy(uid, ber[j]->bv_val, ber[j]->bv_len); + ldap_value_free_len(l->val); + l->val = NULL; + ldap_value_free_len(ber); + ber = NULL; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return LDAP_SUCCESS; /* We got our userid */ + } + /* Not matched, continue */ + break; + case 10: /* IPv6 (UDP) address (eDirectory 8.8 and higher) */ + /* bufa + 2 is the address (skip 2 digit port) */ + if (!(l->status & LDAP_IPV6_S)) + break; /* Not looking for IPv6 */ + for (k = 2; k < z; k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + snprintf(hexc, sizeof(hexc), "%.2X", c); + if (k == 2) + strncpy(bufb, hexc, sizeof(bufb)); + else + strncat(bufb, hexc, sizeof(bufb)); + } + y = strlen(bufb); + /* Compare value with IP */ + if (bcmp(l->search_ip, bufb, y) == 0) { + /* We got a match! - Scan 'ber' for 'cn' values */ + z = ldap_count_values_len(ber); + for (j = 0; j < z; j++) + strncpy(uid, ber[j]->bv_val, ber[j]->bv_len); + ldap_value_free_len(l->val); + l->val = NULL; + ldap_value_free_len(ber); + ber = NULL; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return LDAP_SUCCESS; /* We got our userid */ + } + /* Not matched, continue */ + break; + case 11: /* IPv6 (TCP) address (eDirectory 8.8 and higher) */ + /* bufa + 2 is the address (skip 2 digit port) */ + if (!(l->status & LDAP_IPV6_S)) + break; /* Not looking for IPv6 */ + for (k = 2; k < z; k++) { + c = (int) bufa[k]; + if (c < 0) + c = c + 256; + snprintf(hexc, sizeof(hexc), "%.2X", c); + if (k == 2) + strncpy(bufb, hexc, sizeof(bufb)); + else + strncat(bufb, hexc, sizeof(bufb)); + } + y = strlen(bufb); + /* Compare value with IP */ + if (bcmp(l->search_ip, bufb, y) == 0) { + /* We got a match! - Scan 'ber' for 'cn' values */ + z = ldap_count_values_len(ber); + for (j = 0; j < z; j++) + strncpy(uid, ber[j]->bv_val, ber[j]->bv_len); + ldap_value_free_len(l->val); + l->val = NULL; + ldap_value_free_len(ber); + ber = NULL; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return LDAP_SUCCESS; /* We gout our userid */ + } + /* Not matched, continue */ + break; + default: /* Other, unsupported */ + break; + } + } + if (ber != NULL) { + ldap_value_free_len(ber); + ber = NULL; + } + } + ldap_value_free_len(l->val); + l->val = NULL; + } + if (ber != NULL) { + ldap_value_free_len(ber); + ber = NULL; + } + /* Attr not found, continue */ + } + /* No entries found using given attr */ + if (l->val != NULL) { + ldap_value_free_len(l->val); + l->val = NULL; + } + if (ber != NULL) { + ldap_value_free_len(ber); + ber = NULL; + } + if (ent != NULL) { + ldap_msgfree(ent); + ent = NULL; + } + if (l->lm != NULL) { + ldap_msgfree(l->lm); + l->lm = NULL; + } + l->num_ent = 0; + l->num_val = 0; + l->status &= ~(LDAP_SEARCH_S); + return -5; /* Not found ... Sorry :) */ +} diff --git a/helpers/external_acl/eDirectory_userip/iplookup.h b/helpers/external_acl/eDirectory_userip/iplookup.h new file mode 100644 index 0000000000..b92e77f075 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/iplookup.h @@ -0,0 +1,95 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * iplookup.h -- + * + * ldap_t data struct typedef and related functions. + * + */ + +#ifndef _HAVE_IPLOOKUP_H +#define _HAVE_IPLOOKUP_H +#ifndef _HAVE_MAIN_H +#include "main.h" +#endif +#include +#define LDAP_DEPRECATED 1 /* Set flag for enabling classic ldap functions */ +#include +#include + +/* compile options */ +#define USE_LDAP_INIT +#ifndef NETSCAPE_SSL +# define NETSCAPE_SSL +#endif + +/* define LDAP_AUTH_TLS */ +#ifdef NETSCAPE_SSL +# ifndef LDAP_AUTH_TLS +# define LDAP_AUTH_TLS ((ber_tag_t) 0xb3U) +# endif +#endif + +/* status flags */ +#define LDAP_INIT_S 0x0001 +#define LDAP_OPEN_S 0x0002 +#define LDAP_BIND_S 0x0004 +#define LDAP_SEARCH_S 0x0008 /* We got data */ +#define LDAP_VAL_S 0x0010 /* Data has been copied to l->val */ +#define LDAP_CLOSE_S 0x0020 +#define LDAP_SSL_S 0x0040 +#define LDAP_TLS_S 0x0080 +#define LDAP_IPV4_S 0x0100 /* Search IP is IPv4 */ +#define LDAP_IPV6_S 0x0200 /* Search IP is IPv6 */ + +/* ldap_t struct typedef */ +typedef struct { + LDAP *lp; + LDAPMessage *lm; + struct berval **val; + char basedn[MAXLEN]; + char host[MAXLEN]; + char dn[MAXLEN]; + char passwd[MAXLEN]; + char search_filter[MAXLEN]; /* search_group gets appended here by GroupLDAP */ + char search_ip[MAXLEN]; /* Could be IPv4 or IPv6, set by ConvertIP */ + char userid[MAXLEN]; /* Resulting cn */ + unsigned int status; + unsigned int port; + unsigned long type; /* Type of bind */ + int ver; + int scope; + int num_ent; /* Number of entry's found via search */ + int num_val; /* Number of value's found via getval */ +} ldap_t; + +/* iplookup.c - Functions */ +void InitLDAP(ldap_t *); +int OpenLDAP(ldap_t *, char *, unsigned int); +int CloseLDAP(ldap_t *); +int SetVerLDAP(ldap_t *, int); +int BindLDAP(ldap_t *, char *, char *, unsigned int); +int ConvertIP(ldap_t *, char *); +int SearchFilterLDAP(ldap_t *, char *); +int SearchLDAP(ldap_t *, int, char *, char **); +int GetValLDAP(ldap_t *, char *); +int SearchIPLDAP(ldap_t *, char *); +#endif diff --git a/helpers/external_acl/eDirectory_userip/main.c b/helpers/external_acl/eDirectory_userip/main.c new file mode 100644 index 0000000000..4bae78d969 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/main.c @@ -0,0 +1,592 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * main.c -- + * + * Main program functions. + * + */ + +#include "main.h" +#include "util.h" +#include "iplookup.h" + +char *search_attrib[] = { "cn", "uid", "networkAddress", "groupMembership", NULL }; +conf_t conf; +ldap_t ldap; + +/* Displays version information */ +void DisplayVersion() { + printfx("Squid eDirectory IP Lookup Helper v1.2. Copyright (C) 2009, 2010 Chad E. Naugle\n"); +} + +/* Displays program usage information */ +void DisplayUsage() { + DisplayVersion(); + printfx("\n"); + printfx("Usage: %s\n", conf.program); + printfx(" -H -p [-Z] [-2/3] -b -s \n"); + printfx(" -D -W -F -G \n\n"); + printfx(" -d : Debug Mode.\n"); + printfx(" -4 : Address is IPv4 (127.0.0.1 format).\n"); + printfx(" -6 : Address is IPv6 (::1 format).\n"); + printfx(" -46 : Address is IPv4-in-IPv6 (::ffff:127.0.0.1 format).\n"); + printfx(" -H : Specify hostname/ip of server.\n"); + printfx(" -p : Specify port number. (Range 1-65535)\n"); + printfx(" -Z : Enable TLS security.\n"); + printfx(" -1 : Set LDAP version 1.\n"); + printfx(" -2 : Set LDAP version 2.\n"); + printfx(" -3 : Set LDAP version 3.\n"); + printfx(" -b : Specify Base DN. (ie. o=ORG)\n"); + printfx(" -s : Specify LDAP Search Scope (base, one, sub; defaults to 'base').\n"); + printfx(" -D : Specify Binding DN. (ie. cn=squid,o=ORG)\n"); + printfx(" -W : Specify Binding password.\n"); + printfx(" -F : Specify LDAP search filter. (ie. \"(objectClass=User)\")\n"); + printfx(" -G : Specify if LDAP search group is required.\n"); + printfx(" -v : Display version & exit.\n"); + printfx(" -h : This screen & exit.\n"); + printfx("\n"); +} + +/* Initalizes program's configuration paremeters */ +void InitConf() { + memset(conf.program, '\0', sizeof(conf.program)); + memset(conf.basedn, '\0', sizeof(conf.basedn)); + memset(conf.host, '\0', sizeof(conf.host)); + memset(conf.dn, '\0', sizeof(conf.dn)); + memset(conf.passwd, '\0', sizeof(conf.passwd)); + memset(conf.search_filter, '\0', sizeof(conf.search_filter)); + conf.scope = -1; + conf.ver = -1; + conf.port = -1; + conf.mode = 0; + conf.mode |= MODE_INIT; + + /* Set defaults from config.h */ +#ifdef DEFAULT_BASE_DN + strcpy(conf.basedn, DEFAULT_BASE_DN); +#endif +#ifdef DEFAULT_HOST + strcpy(conf.host, DEFAULT_HOST); +#endif +#ifdef DEFAULT_BIND_DN + strcpy(conf.dn, DEFAULT_BIND_DN); +#endif +#ifdef DEFAULT_BIND_PASS + strcpy(conf.passwd, DEFAULT_BIND_PASS); +#endif +#ifdef DEFAULT_SEARCH_FILTER + strcpy(conf.search_filter, DEFAULT_SEARCH_FILTER); +#endif +#ifdef DEFAULT_SEARCH_SCOPE + conf.scope = DEFAULT_SEARCH_SCOPE; +#endif +#ifdef DEFAULT_LDAP_VERSION + conf.ver = DEFAULT_LDAP_VERSION; +#endif +#ifdef DEFAULT_PORT + conf.port = DEFAULT_PORT; +#endif +#ifdef DEFAULT_USE_IPV4 + conf.mode |= MODE_IPV4; +#endif +#ifdef DEFAULT_USE_IPV6 + conf.mode |= MODE_IPV6; +#endif +#ifdef DEFAULT_USE_TLS + conf.mode |= MODE_TLS; +#endif +#ifdef DEFAULT_DEBUG + conf.mode |= MODE_DEBUG; +#endif +#ifdef DEFAULT_GROUP_REQUIRED + conf.mode |= MODE_GROUP; +#endif +} + +/* Displays running configuration */ +void DisplayConf() { + if (!(conf.mode & MODE_DEBUG)) + return; + DisplayVersion(); + printfx("\n"); + printfx("Configuration:\n"); + if (conf.mode & MODE_DEBUG) + printfx(" Debug mode: ON\n"); + else + printfx(" Debug mode: OFF\n"); + if ((conf.mode & MODE_IPV4) && (conf.mode & MODE_IPV6)) + printfx(" Address format: IPv4-in-IPv6 (::ffff:127.0.0.1)\n"); + else if (conf.mode & MODE_IPV6) + printfx(" Address format: IPv6 (::1)\n"); + else + printfx(" Address format: IPv4 (127.0.0.1)\n"); + if (conf.host[0] != '\0') + printfx(" Hostname: %s\n", conf.host); + else + printfx(" Hostname: 127.0.0.1\n"); + if (conf.port > 0) + printfx(" Port: %d\n", conf.port); + else + printfx(" Port: %d\n", LDAP_PORT); + if (conf.mode & MODE_TLS) + printfx(" TLS mode: ON\n"); + else + printfx(" TLS mode: OFF\n"); + printfx(" LDAP Version: %d\n", conf.ver); + if (conf.basedn[0] != '\0') + printfx(" Base DN: %s\n", conf.basedn); + else + printfx(" Base DN: None\n"); + if (conf.dn[0] != '\0') + printfx(" Binding DN: %s\n", conf.dn); + else + printfx(" Binding DN: Anonymous\n"); + if (conf.passwd[0] != '\0') + printfx(" Binding Password: %s\n", conf.passwd); + else + printfx(" Binding Password: None\n"); + switch (conf.scope) { + case 0: + printfx(" Search Scope: base\n"); + break; + case 1: + printfx(" Search Scope: one level\n"); + break; + case 2: + printfx(" Search Scope: subtree\n"); + break; + default: + printfx(" Search Scope: base\n"); + break; + } + if (conf.search_filter[0] != '\0') + printfx(" Search Filter: %s\n", conf.search_filter); + else + printfx(" Search Filter: (&(objectClass=User)(networkAddress=*))\n"); + if (conf.mode & MODE_GROUP) + printfx(" Search Group Required: Yes\n"); + else + printfx(" Search Group Required: No\n"); + printfx("\n"); +} + +/* Signal Trap routine */ +static void SigTrap(int s) { + if (!(conf.mode & MODE_KILL)) + conf.mode |= MODE_KILL; + + /* Clean Up */ + if (ldap.status & LDAP_OPEN_S) + CloseLDAP(&ldap); + + debug("SigTrap", "Terminating, Signal: %d\n", s); + exit(0); +} + +/* main() - function */ +int main(int argc, char **argv) { + char bufa[MAXLEN], bufb[MAXLEN], *p = NULL; + char bufc[MAXLEN]; + char sfmod[MAXLEN]; + int x; + size_t i, j, s, k; + struct sigaction sv; + + /* Init */ + k = (size_t) argc; + memset(bufa, '\0', sizeof(bufa)); + memset(bufb, '\0', sizeof(bufb)); + memset(bufc, '\0', sizeof(bufc)); + memset(sfmod, '\0', sizeof(sfmod)); + InitConf(&conf); + strncpy(conf.program, argv[0], sizeof(conf.program)); + debug("main", "InitConf() done.\n"); + + /* Scan args */ + if (k > 1) { + for (i = 1; i < k; i++) { + /* Classic / novelty usage schemes */ + if (!strcmp(argv[i], "--help")) { + DisplayUsage(); + return 1; + } + else if (!strcmp(argv[i], "--usage")) { + DisplayUsage(); + return 1; + } + else if (!strcmp(argv[i], "--version")) { + DisplayVersion(); + return 1; + } + else if (argv[i][0] == '-') { + s = strlen(argv[i]); + for (j = 1; j < s; j++) { + switch (argv[i][j]) { + case 'v': + DisplayVersion(); + return 1; + case 'V': + DisplayVersion(); + return 1; + case 'd': + if (!(conf.mode & MODE_DEBUG)) + conf.mode |= MODE_DEBUG; /* Don't set mode more than once */ + break; + case '4': + if (!(conf.mode & MODE_IPV4)) + conf.mode |= MODE_IPV4; /* Don't set mode more than once */ + break; + case '6': + if (!(conf.mode & MODE_IPV6)) + conf.mode |= MODE_IPV6; /* Don't set mode more than once */ + break; + case 'Z': + if (!(conf.mode & MODE_TLS)) + conf.mode |= MODE_TLS; /* Don't set mode more than once */ + break; + case '1': + conf.ver = 1; + break; + case '2': + conf.ver = 2; + break; + case '3': + conf.ver = 3; + break; + case 'b': + i++; /* Set Base DN */ + if (argv[i] != NULL) + strncpy(conf.basedn, argv[i], sizeof(conf.basedn)); + else { + printfx("No parameters given to 'b'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'H': + i++; /* Set Hostname */ + if (argv[i] != NULL) + strncpy(conf.host, argv[i], sizeof(conf.host)); + else { + printfx("No parameters given to 'H'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'p': + i++; /* Set port */ + if (argv[i] != NULL) + conf.port = atoi(argv[i]); + else { + printfx("No parameters given to 'p'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'D': + i++; /* Set Bind DN */ + if (argv[i] != NULL) + strncpy(conf.dn, argv[i], sizeof(conf.dn)); + else { + printfx("No parameters given to 'D'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'W': + i++; /* Set Bind PWD */ + if (argv[i] != NULL) + strncpy(conf.passwd, argv[i], sizeof(conf.passwd)); + else { + printfx("No parameters given to 'W'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'F': + i++; /* Set Search Filter */ + if (argv[i] != NULL) + strncpy(conf.search_filter, argv[i], sizeof(conf.search_filter)); + else { + printfx("No parameters given to 'F'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'G': + if (!(conf.mode & MODE_GROUP)) + conf.mode |= MODE_GROUP; /* Don't set mode more than once */ + break; + case 's': + i++; /* Set Scope Level */ + if (argv[i] != NULL) { + strncpy(bufa, argv[i], sizeof(bufa)); + if (!strcmp(bufa, "base")) + conf.scope = 0; + else if (!strcmp(bufa, "one")) + conf.scope = 1; + else if (!strcmp(bufa, "sub")) + conf.scope = 2; + else + conf.scope = 0; + } + else { + printfx("No parameters given to 's'.\n"); + DisplayUsage(); + return 1; + } + break; + case 'h': + DisplayUsage(); + return 1; + case '-': /* We got a second '-' ... ignore */ + break; + default: + printfx("Invalid parameter - '%c'.\n", argv[i][j]); + break; + } + } + } + else { + /* Incorrect parameter, display usage */ + DisplayUsage(); + return 1; + } + } + } + + /* Set predefined required paremeters if none are given, localhost:LDAP_PORT, etc */ + if (conf.host[0] == '\0') /* Default to 127.0.0.1 */ + strcpy(conf.host, "127.0.0.1"); + if (conf.port < 0) + conf.port = LDAP_PORT; /* Default: LDAP_PORT */ + if (!(conf.mode & MODE_IPV4) && !(conf.mode & MODE_IPV6)) + conf.mode |= MODE_IPV4; /* Default to IPv4 */ + if (conf.ver < 0) + conf.ver = 2; + if ((conf.mode & MODE_TLS) && (conf.ver < 3)) + conf.ver = 3; /* TLS requires version 3 */ + if (conf.scope < 0) + conf.scope = 0; /* Default: base */ + if (conf.search_filter[0] == '\0') + strcpy(conf.search_filter, "(&(objectclass=User)(networkAddress=*))"); + debug("main", "Configuration done.\n"); + + DisplayConf(); + /* Done with arguments */ + + /* Trap the following signals */ + sigemptyset(&sv.sa_mask); + sv.sa_handler = SigTrap; + sigaction(SIGTERM, &sv, NULL); + sv.sa_handler = SigTrap; + sigaction(SIGHUP, &sv, NULL); + sv.sa_handler = SigTrap; + sigaction(SIGABRT, &sv, NULL); + sv.sa_handler = SigTrap; + sigaction(SIGINT, &sv, NULL); + sv.sa_handler = SigTrap; + sigaction(SIGSEGV, &sv, NULL); + debug("main", "Signals trapped.\n"); + + /* Main loop -- Waits for stdin input before action */ + while (fgets(bufa, sizeof(bufa), stdin) != NULL) { + if (conf.mode & MODE_KILL) + break; + k = strlen(bufa); + debug("main", "while() bufa[%zd]: %s", k, bufa); + debug("main", "while() bufa[%zd]: "); + for (i = 0; i < k; i++) + debugx("%.2X", bufa[i]); + debugx("\n"); + /* Check for CRLF */ + p = strchr(bufa, '\n'); + if (p != NULL) + *p = '\0'; + p = strchr(bufa, '\r'); + if (p != NULL) + *p = '\0'; + p = strchr(bufa, ' '); + + /* No space given, but group string is required --> ERR */ + if ((conf.mode & MODE_GROUP) && (p == NULL)) { + printfx("ERR\n"); + continue; + } + + /* Open LDAP connection */ + InitLDAP(&ldap); + debug("main", "InitLDAP() done.\n"); + x = OpenLDAP(&ldap, conf.host, conf.port); + if (x != LDAP_SUCCESS) { + /* Failed to connect */ + debug("main", "Failed to connect. Error: %d (%s)\n", x, ldap_err2string(x)); + } + else { + debug("main", "OpenLDAP(-, %s, %d) done. Result: %d\n", conf.host, conf.port, x); + x = SetVerLDAP(&ldap, conf.ver); + if (x != LDAP_SUCCESS) { + /* Failed to set version */ + debug("main", "Failed to set version. Error: %d (%s)\n", x, ldap_err2string(x)); + } + else { + debug("main", "SetVerLDAP(-, %d) done. Result: %d\n", conf.ver, x); + if (conf.mode & MODE_TLS) { + /* TLS binding */ + x = BindLDAP(&ldap, conf.dn, conf.passwd, LDAP_AUTH_TLS); + if (x != LDAP_SUCCESS) { + /* Unable to bind */ + debug("main", "Failed to bind. Error: %d (%s)\n", x, ldap_err2string(x)); + } + else + debug("main", "BindLDAP(-, %s, %s, %ul) done. Result: %d\n", conf.dn, conf.passwd, LDAP_AUTH_TLS, x); + } + else if (conf.dn[0] != '\0') { + /* Simple binding - using dn / passwd for authorization */ + x = BindLDAP(&ldap, conf.dn, conf.passwd, LDAP_AUTH_SIMPLE); + if (x != LDAP_SUCCESS) { + /* Unable to bind */ + debug("main", "Failed to bind. Error: %d (%s)\n", x, ldap_err2string(x)); + } + else + debug("main", "BindLDAP(-, %s, %s, %ul) done. Result: %d\n", conf.dn, conf.passwd, LDAP_AUTH_SIMPLE, x); + } + else { + /* Anonymous binding */ + x = BindLDAP(&ldap, conf.dn, conf.passwd, LDAP_AUTH_NONE); + if (x != LDAP_SUCCESS) { + /* Unable to bind */ + debug("main", "Failed to bind. Error: %d (%s)\n", x, ldap_err2string(x)); + } + else + debug("main", "BindLDAP(-, -, -, %ul) done. Result: %d\n", LDAP_AUTH_NONE, x); + } + } + } + /* Everything failed --> ERR */ + if (x != LDAP_SUCCESS) { + printfx("ERR\n"); + memset(bufa, '\0', strlen(bufa)); + CloseLDAP(&ldap); + continue; + } + else { + /* We got a group string -- split it */ + if (p != NULL) { + /* Split string */ + debug("main", "SplitString(%s, %zd, ' ', %s, %zd)\n", bufa, strlen(bufa), bufb, sizeof(bufb)); + i = SplitString(bufa, strlen(bufa), ' ', bufb, sizeof(bufb)); + if (i > 0) { + debug("main", "SplitString(%s, %s) done. Result: %zd\n", bufa, bufb, i); + /* Got a group to match against */ + x = ConvertIP(&ldap, bufb); + if (x < 0) { + debug("main", "Failed to ConvertIP(). Error: %d\n", x); + printfx("ERR (ConvertIP %d)\n", x); + } + else { + debug("main", "ConvertIP(-, %s) done. Result[%zd]: %s\n", bufb, x, ldap.search_ip); + x = SearchFilterLDAP(&ldap, bufa); + if (x < 0) { + debug("main", "Failed to SearchFilterLDAP(). Error: %d\n", x); + printfx("ERR\n"); + } + else { + /* Do Search */ + debug("main", "IP: %s, Search Filter: %s\n", ldap.search_ip, ldap.search_filter); + x = SearchLDAP(&ldap, ldap.scope, ldap.search_filter, search_attrib); + if (x != LDAP_SUCCESS) { + debug("main", "Failed to SearchLDAP(). Error: %d (%s)\n", x, ldap_err2string(x)); + printfx("ERR\n"); + } + else { + debug("main", "SearchLDAP(-, %d, %s, -) done. Result: %d\n", conf.scope, ldap.search_filter, x); + x = SearchIPLDAP(&ldap, bufc); + if (x != LDAP_SUCCESS) { + debug("main", "Failed to SearchIPLDAP(). Error: %d\n", x); + printfx("ERR\n"); + } + else { + debug("main", "SearchIPLDAP(-, %s) done. Result: %d\n", bufc, x); + printfx("OK user=%s\n", bufc); /* Got userid --> OK user= */ + } + } + + /* Clear for next query */ + memset(bufc, '\0', strlen(bufc)); + } + } + } + else { + debug("main", "Failed to SplitString(). Error: %d\n", i); + printfx("ERR\n"); + } + } + else { + /* No group to match against, only an IP */ + x = ConvertIP(&ldap, bufa); + if (x < 0) { + debug("main", "Failed to ConvertIP(). Error: %d\n", x); + printfx("ERR (ConvertIP %d)\n", x); + } + else { + debug("main", "ConvertIP(-, %s) done. Result[%zd]: %s\n", bufa, x, ldap.search_ip); + /* Do search */ + x = SearchFilterLDAP(&ldap, NULL); + if (x < 0) { + debug("main", "Failed to SearchFilterLDAP(). Error: %d\n", x); + printfx("ERR\n"); + } + else { + debug("main", "IP: %s, Search Filter: %s\n", ldap.search_ip, ldap.search_filter); + x = SearchLDAP(&ldap, ldap.scope, ldap.search_filter, search_attrib); + if (x != LDAP_SUCCESS) { + debug("main", "Failed to SearchLDAP(). Error: %d (%s)\n", x, ldap_err2string(x)); + printfx("ERR\n"); + } + else { + debug("main", "SearchLDAP(-, %d, %s, -) done. Result: %d\n", conf.scope, ldap.search_filter, x); + x = SearchIPLDAP(&ldap, bufc); + if (x != LDAP_SUCCESS) { + debug("main", "Failed to SearchIPLDAP(). Error: %d\n", x); + printfx("ERR\n"); + } + else { + debug("main", "SearchIPLDAP(-, %s) done. Result: %d\n", bufc, x); + printfx("OK user=%s\n", bufc); /* Got a userid --> OK user= */ + } + } + } + /* Clear for next query */ + memset(bufc, '\0', strlen(bufc)); + } + } + } + + /* Clear buffer and close for next data */ + memset(bufa, '\0', strlen(bufa)); + CloseLDAP(&ldap); + } + + debug("main", "Terminating.\n"); + exit(1); +} diff --git a/helpers/external_acl/eDirectory_userip/main.h b/helpers/external_acl/eDirectory_userip/main.h new file mode 100644 index 0000000000..39126b0855 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/main.h @@ -0,0 +1,78 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * main.h -- + * + * Main program includes & conf_t struct typedef for program configuration. + * + */ + +#ifndef _HAVE_MAIN_H +#define _HAVE_MAIN_H + +#ifndef _HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef DEFAULT_PROGRAM_NAME +#define DEFAULT_PROGRAM_NAME "squid_edir_iplookup" +#endif + +/* Must ... include ... these ... */ +#include +#define _GNU_SOURCE +#define __USE_GNU +#include +#include +#include +#include +#include + +#ifdef DEFAULT_MAXLEN +#define MAXLEN DEFAULT_MAXLEN +#else +#define MAXLEN 1024 +#endif +#define MODE_INIT 0x01 +#define MODE_DEBUG 0x02 +#define MODE_TLS 0x04 +#define MODE_IPV4 0x08 +#define MODE_IPV6 0x10 +#define MODE_KILL 0x20 +#define MODE_GROUP 0x40 /* Group is REQUIRED */ + +/* conf_t - Program configuration struct typedef */ +typedef struct { + char program[MAXLEN]; + char basedn[MAXLEN]; + char host[MAXLEN]; + char dn[MAXLEN]; + char passwd[MAXLEN]; + char search_filter[MAXLEN]; /* Base search_filter that gets copied to ldap_t */ + int ver; + int scope; + int port; + unsigned int mode; +} conf_t; + +/* extern the struct */ +extern conf_t conf; /* Main configuration struct */ +#endif diff --git a/helpers/external_acl/eDirectory_userip/util.c b/helpers/external_acl/eDirectory_userip/util.c new file mode 100644 index 0000000000..6be3578eac --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/util.c @@ -0,0 +1,219 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * util.c -- + * + * Program utility functions. + * + */ + +#include "main.h" +#include "util.h" + +/* debug() - + * + * Print formatted message of func() to stderr if MODE_DEBUG is set. + * + */ +void debug(char *func, const char *msg,...) { + char prog[MAXLEN], dbuf[MAXLEN], cbuf[MAXLEN]; + size_t sz, x; + va_list ap; + if (!(conf.mode & MODE_DEBUG)) + return; + + if (conf.program[0] == '\0') + strcpy(prog, DEFAULT_PROGRAM_NAME); + else + strncpy(prog, conf.program, sizeof(prog)); + if ((func == NULL) || (msg == NULL) || (strlen(prog) > 256)) { + /* FAIL */ + snprintf(dbuf, sizeof(dbuf), "%s: debug() EPIC FAILURE.\n", prog); + fputs(dbuf, stderr); + return; + } + sz = sizeof(dbuf); + strncpy(cbuf, prog, sizeof(cbuf)); + strcat(cbuf, ": [DB] "); + strncat(cbuf, func, sizeof(cbuf)); + strcat(cbuf, "() - "); + va_start(ap, msg); + x = vsnprintf(dbuf, sz, msg, ap); + va_end(ap); + if (x > 0) { + strncat(cbuf, dbuf, x); + fputs(cbuf, stderr); + memset(dbuf, '\0', strlen(dbuf)); + } + else { + /* FAIL */ + snprintf(dbuf, sz, "%s: debug(%s) FAILURE: %zd\n", prog, dbuf, x); + fputs(dbuf, stderr); + } +} + +/* debugx() - + * + * Print formatted message to stderr if MODE_DEBUG is set, without preformatting. + * + */ +void debugx(const char *msg,...) { + char prog[MAXLEN], dbuf[MAXLEN]; + size_t sz, x; + va_list ap; + if (!(conf.mode & MODE_DEBUG)) + return; + + if (conf.program[0] == '\0') + strcpy(prog, DEFAULT_PROGRAM_NAME); + else + strncpy(prog, conf.program, sizeof(prog)); + if ((msg == NULL) || (strlen(prog) > 256)) { + /* FAIL */ + snprintf(dbuf, sizeof(dbuf), "%s: debugx() EPIC FAILURE.\n", prog); + fputs(dbuf, stderr); + return; + } + sz = sizeof(dbuf); + va_start(ap, msg); + x = vsnprintf(dbuf, sz, msg, ap); + va_end(ap); + if (x > 0) { + fputs(dbuf, stderr); + memset(dbuf, '\0', strlen(dbuf)); + } + else { + /* FAIL */ + snprintf(dbuf, sz, "%s: debug(%s) FAILURE: %zd\n", prog, dbuf, x); + fputs(dbuf, stderr); + } +} + +/* printfx() - + * + * Print formatted message to stderr AND stdout, without preformatting. + * + */ +void printfx(const char *msg,...) { + char prog[MAXLEN], dbuf[MAXLEN]; + size_t sz, x; + va_list ap; + + if (conf.program[0] == '\0') + strcpy(prog, DEFAULT_PROGRAM_NAME); + else + strncpy(prog, conf.program, sizeof(prog)); + + if ((msg == NULL) || (strlen(prog) > 256)) { + /* FAIL */ + snprintf(dbuf, sizeof(dbuf), "%s: printfx() EPIC FAILURE.\n", prog); + fputs(dbuf, stderr); + return; + } + sz = sizeof(dbuf); + va_start(ap, msg); + x = vsnprintf(dbuf, sz, msg, ap); + va_end(ap); + if (x > 0) { + dbuf[x] = '\0'; + x++; + fputs(dbuf, stdout); +// debug("printfx", "DATA: %s", dbuf); + memset(dbuf, '\0', strlen(dbuf)); + } + else { + /* FAIL */ + snprintf(dbuf, sz, "%s: printfx(%s) FAILURE: %zd\n", prog, dbuf, x); + fputs(dbuf, stderr); + } + + /* stdout needs to be flushed for it to work with Squid */ + fflush(stdout); +} + +/* + * SplitString() - + * + * Breaks down string, splitting out element into , and removing it from string. + * Will not exceed size tolerances. + * + * NOTE: We could have used a strchr() pointer, but then '\0' would break it. + * (Which DOES commonly exist in IP Addressing) + * + */ +int SplitString(char *input, size_t insz, char c, char *obj, size_t objsz) { + size_t i, j; + int swi; + char buf[MAXLEN]; + if ((input == NULL) || (obj == NULL) || (insz <= 0) || (objsz <= 0)) return -1; + + /* Copy input, and clear */ + memset(buf, '\0', sizeof(buf)); + memcpy(buf, input, insz); + memset(input, '\0', insz); + memset(obj, '\0', objsz); + j = 0; /* obj position */ + swi = 0; /* found data yet ? */ + + /* Scan for data, and copy */ + for (i = 0; i < insz; i++) { + /* Scan input for first non-space character */ + if (buf[i] != c) { + if (swi == 0) { + swi++; /* Data found, begin copying. */ + obj[j] = buf[i]; + j++; + } + else if (swi == 1) { + obj[j] = buf[i]; + j++; + } + else + break; /* end of data */ + } + else { + /* Found a character c */ + if (swi == 1) + swi++; + else if (swi == 2) + break; /* end of data */ + } + } + obj[j] = '\0'; /* Terminate, i = point of split */ + + j = 0; /* Position of input */ + for (; i < insz; i++) { +/* Commented out for BINARY MODE, ie. May have '\0' as legit data * + if (buf[i] == '\0') + break; +*/ + input[j] = buf[i]; + j++; + } + /* Should be correctly split back into input, and + * split object in obj. memset() at next call will + * clear array data. + */ + i = strlen(input); + j = strlen(obj); + + return j; +} diff --git a/helpers/external_acl/eDirectory_userip/util.h b/helpers/external_acl/eDirectory_userip/util.h new file mode 100644 index 0000000000..92f395f276 --- /dev/null +++ b/helpers/external_acl/eDirectory_userip/util.h @@ -0,0 +1,40 @@ +/* squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle + * + ******************************************************************************** + * + * This file is part of squid_edir_iplookup. + * + * squid_edir_iplookup 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 3 of the License, or + * (at your option) any later version. + * + * squid_edir_iplookup 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 squid_edir_iplookup. If not, see . + * + ******************************************************************************** + * + * util.h -- + * + * Program utility functions. + * + */ + +#ifndef _HAVE_UTIL_H +#define _HAVE_UTIL_H +#ifndef _HAVE_MAIN_H +#include "main.h" +#endif +#include + +/* util.c - Functions */ +void debug(char *, const char *,...); +void debugx(const char *,...); +void printfx(const char *,...); +int SplitString(char *, size_t, char, char *, size_t); +#endif