]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Author: Chad E. Naugle <chad.naugle@travimp.com>
authorAmos Jeffries <squid3@treenet.co.nz>
Tue, 20 Jul 2010 14:16:00 +0000 (02:16 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 20 Jul 2010 14:16:00 +0000 (02:16 +1200)
Bug 2905: eDirectory (8.7 & 8.8) IPv4/IPv6->Username external ACL helper

Original code import.

helpers/external_acl/eDirectory_userip/INSTALL [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/ISSUES [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/Makefile [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/README [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/config.h [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/iplookup.c [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/iplookup.h [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/main.c [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/main.h [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/util.c [new file with mode: 0644]
helpers/external_acl/eDirectory_userip/util.h [new file with mode: 0644]

diff --git a/helpers/external_acl/eDirectory_userip/INSTALL b/helpers/external_acl/eDirectory_userip/INSTALL
new file mode 100644 (file)
index 0000000..4c1e1ae
--- /dev/null
@@ -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 (file)
index 0000000..ac854ca
--- /dev/null
@@ -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 (file)
index 0000000..5138829
--- /dev/null
@@ -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 (file)
index 0000000..b31aad0
--- /dev/null
@@ -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 (file)
index 0000000..c3421e4
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * 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 (file)
index 0000000..41ccbb4
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * iplookup.c --
+ *
+ * ldap_t data struct manipulation, and LDAP server communication.
+ *
+ */
+
+#include "main.h"
+#include "util.h"
+#include "iplookup.h"
+
+/* InitLDAP() - <ldap_t>
+ *
+ * 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() - <ldap_t> <host> <port>
+ *
+ * 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() - <ldap_t>
+ *
+ * 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() - <ldap_t> <version>
+ *
+ * Set LDAP version number for connection to <version> 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() - <ldap_t> <use-dn> <use-password> <type>
+ *
+ * Bind LDAP connection (Open) using optional dn and password, of <type>
+ *
+ */
+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() - <ldap_t> <ip>
+ *
+ * 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() - <ldap_t> <IP> <group>
+ *
+ * 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() - <ldap_t> <scope> <filter> <attrib>
+ *
+ * Initate LDAP query, under <scope> levels, filtering matches with <filter> and optionally <attrib>
+ * <attrib> 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() - <ldap_t> <search-attr>
+ *
+ * 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() - <ldap_t> <result-uid>
+ *
+ * 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 (file)
index 0000000..b92e77f
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * 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 <ctype.h>
+#define LDAP_DEPRECATED 1      /* Set flag for enabling classic ldap functions */
+#include <lber.h>
+#include <ldap.h>
+
+/* 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 (file)
index 0000000..4bae78d
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * 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 <host> -p <port> [-Z] [-2/3] -b <basedn> -s <scope>\n");
+  printfx("            -D <binddn> -W <bindpass> -F <search-filter> -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 <host>   : Specify hostname/ip of server.\n");
+  printfx("    -p <port>   : 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 <base>   : Specify Base DN. (ie. o=ORG)\n");
+  printfx("    -s <scope>  : Specify LDAP Search Scope (base, one, sub; defaults to 'base').\n");
+  printfx("    -D <dn>     : Specify Binding DN. (ie. cn=squid,o=ORG)\n");
+  printfx("    -W <pass>   : Specify Binding password.\n");
+  printfx("    -F <filter> : 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=<userid> */
+               }
+             }
+               
+             /* 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=<userid> */
+             }
+           }
+         }
+         /* 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 (file)
index 0000000..39126b0
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * 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 <stdio.h>
+#define _GNU_SOURCE
+#define __USE_GNU
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+
+#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 (file)
index 0000000..6be3578
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * 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() - <string> <string-size> <char> <split-object> <obj-size>
+ *
+ * Breaks down string, splitting out element <char> into <split-object>, 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 (file)
index 0000000..92f395f
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************************
+ *
+ * util.h --
+ *
+ * Program utility functions.
+ *
+ */
+
+#ifndef _HAVE_UTIL_H
+#define _HAVE_UTIL_H
+#ifndef _HAVE_MAIN_H
+#include "main.h"
+#endif
+#include <stdarg.h>
+
+/* 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