]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / acl / external / eDirectory_userip / ext_edirectory_userip_acl.cc
CommitLineData
ca02e0ec 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
ca02e0ec
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * Copyright (C) 2009-2011 Chad E. Naugle
f86504f1
AJ
11 *
12 ********************************************************************************
13 *
14 * This file is part of ext_edirectory_userip_acl.
15 *
16 * ext_edirectory_userip_acl is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * ext_edirectory_userip_acl is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with squid_edir_iplookup. If not, see <http://www.gnu.org/licenses/>.
28 *
29 ********************************************************************************
30 *
915c866f
CN
31 * ext_edirectory_userip_acl.cc -- Rev 2011-03-28
32 *
33 * - Misc code cleanups using "static", and 64-bit SLES fix for SearchFilterLDAP()
f86504f1
AJ
34 *
35 */
36
f86504f1 37/* Squid-3.X includes */
f7f3304a 38#include "squid.h"
079b1d0f 39#include "helper/protocol_defines.h"
f86504f1
AJ
40#include "rfc1738.h"
41#include "util.h"
f86504f1 42
f53969cc
SM
43#define EDUI_PROGRAM_NAME "ext_edirectory_userip_acl"
44#define EDUI_PROGRAM_VERSION "2.1"
f86504f1
AJ
45
46/* System includes */
88f2cf55 47#ifndef _GNU_SOURCE
f86504f1 48#define _GNU_SOURCE
88f2cf55
AJ
49#endif
50#ifndef __USE_GNU
f86504f1 51#define __USE_GNU
88f2cf55 52#endif
074d6a40
AJ
53#include <cctype>
54#include <cerrno>
55#include <csignal>
074d6a40
AJ
56#include <cstdlib>
57#include <cstring>
58#include <ctime>
f86504f1
AJ
59#ifdef HAVE_ARPA_INET_H
60#include <arpa/inet.h>
61#endif
62#define LDAP_DEPRECATED 1 /* Set flag for enabling classic ldap functions */
63#ifdef HAVE_LBER_H
64#include <lber.h>
65#endif
66#ifdef HAVE_LDAP_H
67#include <ldap.h>
68#endif
d08caf47
AJ
69#ifdef HAVE_NETDB_H
70#include <netdb.h>
71#endif
05fdfe0d
AR
72#ifdef HAVE_SYS_SOCKET_H
73#include <sys/socket.h>
74#endif
75#ifdef HAVE_NETINET_IN_H
76#include <netinet/in.h>
77#endif
f86504f1
AJ
78
79#ifdef HELPER_INPUT_BUFFER
f53969cc 80#define EDUI_MAXLEN HELPER_INPUT_BUFFER
f86504f1 81#else
f53969cc 82#define EDUI_MAXLEN 4096 /* Modified to improve performance, unless HELPER_INPUT_BUFFER exists */
f86504f1
AJ
83#endif
84
85/* ldap compile options */
86#define USE_LDAP_INIT
87#ifndef NETSCAPE_SSL
88# define NETSCAPE_SSL
89#endif
90
915c866f
CN
91/* define LDAP_AUTH_TLS
92 * - ldap.h Hack for cleaner code, if it does not provide it.
93 */
f86504f1
AJ
94#ifdef NETSCAPE_SSL
95# ifndef LDAP_AUTH_TLS
96# define LDAP_AUTH_TLS ((ber_tag_t) 0xb3U)
97# endif
98#endif
99
100/* conf_t - status flags */
f53969cc
SM
101#define EDUI_MODE_INIT 0x01
102#define EDUI_MODE_DEBUG 0x02 /* Replace with Squid's debug system */
103#define EDUI_MODE_TLS 0x04
104#define EDUI_MODE_IPV4 0x08
105#define EDUI_MODE_IPV6 0x10
106#define EDUI_MODE_GROUP 0x20 /* Group is REQUIRED */
107#define EDUI_MODE_PERSIST 0x40 /* Persistent LDAP connections */
108#define EDUI_MODE_KILL 0x80
f86504f1
AJ
109
110/* conf_t - Program configuration struct typedef */
111typedef struct {
112 char program[EDUI_MAXLEN];
113 char basedn[EDUI_MAXLEN];
114 char host[EDUI_MAXLEN];
115 char attrib[EDUI_MAXLEN];
116 char dn[EDUI_MAXLEN];
117 char passwd[EDUI_MAXLEN];
f53969cc 118 char search_filter[EDUI_MAXLEN]; /* Base search_filter that gets copied to edui_ldap_t */
f86504f1
AJ
119 int ver;
120 int scope;
121 int port;
122 time_t persist_timeout;
123 unsigned int mode;
124} edui_conf_t;
125
126/* edui_ldap_t - status flags */
127#define LDAP_INIT_S 0x0001
128#define LDAP_OPEN_S 0x0002
129#define LDAP_BIND_S 0x0004
130#define LDAP_SEARCH_S 0x0008 /* We got data */
131#define LDAP_VAL_S 0x0010 /* Data has been copied to l->val */
132#define LDAP_CLOSE_S 0x0020
133#define LDAP_PERSIST_S 0x0040 /* Persistent connection */
134#define LDAP_IDLE_S 0x0080 /* Connection is idle */
135#define LDAP_SSL_S 0x0100
136#define LDAP_TLS_S 0x0200
137#define LDAP_IPV4_S 0x0400 /* Search IP is IPv4 */
138#define LDAP_IPV6_S 0x0800 /* Search IP is IPv6 */
139
140/* edui_ldap_t - Meaningful error codes */
141#define LDAP_ERR_NULL -1 /* Null edui_ldap_t pointer */
142#define LDAP_ERR_POINTER -2 /* Null l->lp pointer */
143#define LDAP_ERR_PARAM -3 /* Null or Missing parameters */
2f8abb64 144#define LDAP_ERR_INIT -4 /* Not initialized */
f86504f1
AJ
145#define LDAP_ERR_OPEN -5 /* Not open */
146#define LDAP_ERR_CONNECT -6 /* Unable to connect */
147#define LDAP_ERR_BIND -7 /* Not bound */
148#define LDAP_ERR_SEARCHED -8 /* Already Searched */
149#define LDAP_ERR_NOT_SEARCHED -9 /* Not searching */
150#define LDAP_ERR_INVALID -10 /* Invalid parameter */
151#define LDAP_ERR_OOB -11 /* Out of bounds value */
152#define LDAP_ERR_PERSIST -12 /* Persistent mode is not active */
153#define LDAP_ERR_DATA -13 /* Required data missing */
154#define LDAP_ERR_NOTFOUND -14 /* Item not found */
155#define LDAP_ERR_OTHER -15 /* Other Generic Error condition */
156#define LDAP_ERR_FAILED -16 /* Operation failed */
157#define LDAP_ERR_SUCCESS -17 /* Operation successful */
158
159/* edui_ldap_t - struct typedef */
160typedef struct {
161 LDAP *lp;
162 LDAPMessage *lm;
163 struct berval **val;
164 char basedn[EDUI_MAXLEN];
165 char host[EDUI_MAXLEN];
166 char dn[EDUI_MAXLEN];
167 char passwd[EDUI_MAXLEN];
f53969cc
SM
168 char search_filter[EDUI_MAXLEN]; /* search_group gets appended here by GroupLDAP */
169 char search_ip[EDUI_MAXLEN]; /* Could be IPv4 or IPv6, set by ConvertIP */
7a545fdb 170 char userid[EDUI_MAXLEN]; /* Resulting userid */
f86504f1
AJ
171 unsigned int status;
172 unsigned int port;
f53969cc 173 unsigned long type; /* Type of bind */
f86504f1
AJ
174 int ver;
175 int scope;
f53969cc 176 int err; /* LDAP error code */
f86504f1
AJ
177 time_t idle_time;
178 int num_ent; /* Number of entry's found via search */
179 int num_val; /* Number of value's found via getval */
180} edui_ldap_t;
181
6ca7324f 182/* Global function prototypes */
915c866f
CN
183static void local_printfx(const char *,...);
184static int StringSplit(char *, char, char *, size_t);
185static int BinarySplit(void *, size_t, char, void *, size_t);
6ca7324f
AJ
186static void DisplayVersion();
187static void DisplayUsage();
188static void InitConf();
189static void DisplayConf();
190static void InitLDAP(edui_ldap_t *);
915c866f
CN
191static int OpenLDAP(edui_ldap_t *, char *, unsigned int);
192static int CloseLDAP(edui_ldap_t *);
193static int SetVerLDAP(edui_ldap_t *, int);
194static int BindLDAP(edui_ldap_t *, char *, char *, unsigned int);
195static int ConvertIP(edui_ldap_t *, char *);
196static int ResetLDAP(edui_ldap_t *);
197static int SearchFilterLDAP(edui_ldap_t *, char *);
198static int SearchLDAP(edui_ldap_t *, int, char *, char **);
199static int SearchIPLDAP(edui_ldap_t *);
6ca7324f 200const char *ErrLDAP(int);
5cd16654 201extern "C" void SigTrap(int);
6ca7324f 202
f86504f1 203/* Global variables */
6ca7324f 204const char *search_attrib[] = { "cn", "uid", "networkAddress", "groupMembership", NULL };
915c866f
CN
205static edui_conf_t edui_conf;
206static edui_ldap_t edui_ldap;
f86504f1
AJ
207time_t edui_now;
208time_t edui_elap;
209
f86504f1
AJ
210/* local_printfx() -
211 *
212 * Print formatted message to stderr AND stdout, without preformatting.
213 *
915c866f
CN
214 * - Exists as a hack, because SEND_OK() does not appear to work here.
215 *
f86504f1 216 */
915c866f
CN
217static void
218local_printfx(const char *msg,...)
f86504f1
AJ
219{
220 char prog[EDUI_MAXLEN], dbuf[EDUI_MAXLEN];
221 size_t sz, x;
222 va_list ap;
223
224 if (edui_conf.program[0] == '\0')
bcdce702 225 xstrncpy(prog, EDUI_PROGRAM_NAME, sizeof(prog));
f86504f1 226 else
bcdce702 227 xstrncpy(prog, edui_conf.program, sizeof(prog));
f86504f1 228
915c866f 229 if (msg == NULL) {
f86504f1 230 /* FAIL */
915c866f 231 debug("local_printfx() FAILURE, no data.\n");
f86504f1
AJ
232 return;
233 }
234 sz = sizeof(dbuf);
235 va_start(ap, msg);
236 x = vsnprintf(dbuf, sz, msg, ap);
237 va_end(ap);
238 if (x > 0) {
239 dbuf[x] = '\0';
755494da 240 ++x;
f86504f1 241 fputs(dbuf, stdout);
9c76c145 242 *(dbuf) = '\0';
f86504f1
AJ
243 } else {
244 /* FAIL */
fe1e5c91 245 debug("local_printfx() FAILURE: %" PRIuSIZE "\n", x);
f86504f1
AJ
246 }
247
248 /* stdout needs to be flushed for it to work with Squid */
249 fflush(stdout);
250}
251
252/*
7a545fdb 253 * StringSplit() - <string-to-split> <char> <split-object> <obj-size>
f86504f1
AJ
254 *
255 * Breaks down string, splitting out element <char> into <split-object>, and removing it from string.
256 * Will not exceed size tolerances.
257 *
f86504f1 258 */
915c866f 259static int
9c2c41b2 260StringSplit(char *In_Str, char chr, char *Out_Str, size_t Out_Sz)
f86504f1 261{
9c2c41b2
AJ
262 if ((In_Str == NULL) || (Out_Str == NULL))
263 return (-1);
264
265 size_t In_Len = strlen(In_Str) + 1;
266
267 // find the char delimiter position...
268 char *p = In_Str;
269 while (*p != chr && *p != '\0' && (In_Str+In_Len) > p) {
755494da 270 ++p;
f86504f1 271 }
9c2c41b2
AJ
272
273 size_t i = (p-In_Str);
274
275 // token to big for the output buffer
276 if (i >= Out_Sz)
277 return (-2);
278
279 // wipe the unused Out_Obj area
280 memset(Out_Str+i, 0, Out_Sz-i);
281 // copy token from In_Str to Out_Str
282 memcpy(Out_Str, In_Str, i);
283
284 // omit the delimiter
285 if (*p == chr) {
755494da
FC
286 ++p;
287 ++i;
9c2c41b2
AJ
288 } else {
289 // chr not found (or \0 found first). Wipe whole input buffer.
290 memset(In_Str, 0, In_Len);
acbf414b
AJ
291// return (-3);
292// Returning <0 breaks current ConvertIP() code for last object
90737510 293 return (i);
9c2c41b2
AJ
294 }
295
296 // move the unused In_Str forward
297 memmove(In_Str, p, In_Len-i);
298 // wipe the end of In_Str
299 memset(In_Str+In_Len-i, 0, i);
300 return (i-1);
f86504f1
AJ
301}
302
7a545fdb
AJ
303/*
304 * BinarySplit() - <binary-to-split> <bin-size> <char> <split-object> <obj-size>
305 *
306 * Breaks down Binary Block, splitting out element <char> into <split-object>, and removing it from Block, padding remainder with '\0'.
307 * Will not exceed size tolerances.
308 *
309 */
915c866f 310static int
9c2c41b2 311BinarySplit(void *In_Obj, size_t In_Sz, char chr, void *Out_Obj, size_t Out_Sz)
7a545fdb 312{
9c2c41b2
AJ
313 // check tolerances
314 if ((In_Obj == NULL) || (Out_Obj == NULL))
315 return (-1);
316
317 char *in = static_cast<char*>(In_Obj);
318 char *out = static_cast<char*>(Out_Obj);
319
320 // find the char delimiter position...
321 char *p = static_cast<char*>(In_Obj);
322 while (*p != chr && (in+In_Sz) > p) {
755494da 323 ++p;
9c2c41b2
AJ
324 }
325
326 size_t i = (p-in);
327
328 // token to big for the output buffer
329 if (i > Out_Sz)
330 return (-2);
331
332 // wipe the unused Out_Obj area
333 memset(out+i, 0, Out_Sz-i);
334 // copy token from In_Obj to Out_Obj
335 memcpy(Out_Obj, In_Obj, i);
336
337 // omit the delimiter
338 if (*p == chr) {
755494da
FC
339 ++p;
340 ++i;
9c2c41b2
AJ
341 } else {
342 // chr not found
343 memset(In_Obj, 0, In_Sz);
acbf414b
AJ
344// return (-3);
345// Returning <0 breaks current code for last object
90737510 346 return (i);
7a545fdb 347 }
9c2c41b2
AJ
348
349 // move the unused In_Obj forward
350 memmove(In_Obj, p, In_Sz-i);
351 // wipe the end of In_Obj
352 memset(in+In_Sz-i, 0, i);
353 return (i-1);
7a545fdb 354}
9c2c41b2 355
f86504f1 356/* Displays version information */
915c866f
CN
357static void
358DisplayVersion()
f86504f1 359{
915c866f 360 local_printfx("Squid eDirectory IP Lookup Helper %s. Copyright (C) 2009-2011 Chad E. Naugle\n", EDUI_PROGRAM_VERSION);
f86504f1
AJ
361}
362
363/* Displays program usage information */
915c866f
CN
364static void
365DisplayUsage()
f86504f1
AJ
366{
367 DisplayVersion();
368 local_printfx("\n");
369 local_printfx("Usage: %s\n", edui_conf.program);
370 local_printfx(" -H <host> -p <port> [-Z] [-P] [-v 3] -b <basedn> -s <scope>\n");
371 local_printfx(" -D <binddn> -W <bindpass> -F <search-filter> [-G] \n\n");
372 local_printfx(" -d : Debug Mode.\n");
373 local_printfx(" -4 : Force Addresses to be in IPv4 (127.0.0.1 format).\n");
374 local_printfx(" -6 : Force Addresses to be in IPv6 (::1 format).\n");
375 local_printfx(" -H <host> : Specify hostname/ip of server.\n");
376 local_printfx(" -p <port> : Specify port number. (Range 1-65535)\n");
377 local_printfx(" -Z : Enable TLS security.\n");
378 local_printfx(" -P : Use persistent connections.\n");
379 local_printfx(" -t <sec> : Timeout factor for persistent connections. (Default is 60 sec, set to 0 for never timeout)\n");
380 local_printfx(" -v <1,2,3> : Set LDAP version to 1, 2, or 3.\n");
381 local_printfx(" -b <base> : Specify Base DN. (ie. \"o=ORG\")\n");
6ca7324f 382 local_printfx(" -s <scope> : Specify LDAP Search Scope (base, one, sub; defaults to 'one').\n");
f86504f1
AJ
383 local_printfx(" -D <dn> : Specify Binding DN. (ie. cn=squid,o=ORG)\n");
384 local_printfx(" -W <pass> : Specify Binding password.\n");
385 local_printfx(" -u <attrib> : Set userid attribute (Defaults to \"cn\").\n");
386 local_printfx(" -F <filter> : Specify LDAP search filter. (ie. \"(objectClass=User)\")\n");
387 local_printfx(" -G : Specify if LDAP search group is required. (ie. \"groupMembership=\")\n");
388 local_printfx(" -V : Display version & exit.\n");
389 local_printfx(" -h : This screen & exit.\n");
390 local_printfx("\n");
391}
392
2f8abb64 393/* Initializes program's configuration parameters */
915c866f
CN
394static void
395InitConf()
f86504f1 396{
7a545fdb
AJ
397 *(edui_conf.program) = '\0';
398 *(edui_conf.basedn) = '\0';
399 *(edui_conf.host) = '\0';
400 *(edui_conf.attrib) = '\0';
401 *(edui_conf.dn) = '\0';
402 *(edui_conf.passwd) = '\0';
403 *(edui_conf.search_filter) = '\0';
f86504f1
AJ
404 edui_conf.scope = -1;
405 edui_conf.ver = -1;
406 edui_conf.port = -1;
407 edui_conf.persist_timeout = -1;
408 edui_conf.mode = 0;
409 edui_conf.mode |= EDUI_MODE_INIT;
410
915c866f 411 /* Set defaults from compile-time-options, if provided, but depriciated. */
f86504f1 412#ifdef EDUI_BASE_DN
6ca7324f 413 xstrncpy(edui_conf.basedn, EDUI_BASE_DN, sizeof(edui_conf.basedn));
f86504f1
AJ
414#endif
415#ifdef EDUI_DEFAULT_HOST
6ca7324f 416 xstrncpy(edui_conf.host, EDUI_DEFAULT_HOST, sizeof(edui_conf.host));
f86504f1
AJ
417#endif
418#ifdef EDUI_BIND_DN
6ca7324f 419 xstrncpy(edui_conf.dn, EDUI_BIND_DN, sizeof(edui_conf.dn));
f86504f1
AJ
420#endif
421#ifdef EDUI_BIND_PASS
6ca7324f 422 xstrncpy(edui_conf.passwd, EDUI_BIND_PASS, sizeof(edui_conf.passwd));
f86504f1
AJ
423#endif
424#ifdef EDUI_USER_ATTRIB
6ca7324f 425 xstrncpy(edui_conf.attrib, EDUI_USER_ATTRIB, sizeof(edui_conf.attrib));
f86504f1
AJ
426#endif
427#ifdef EDUI_SEARCH_FILTER
6ca7324f 428 xstrncpy(edui_conf.search_filter, EDUI_SEARCH_FILTER, sizeof(edui_conf.search_filter));
f86504f1
AJ
429#endif
430#ifdef EDUI_SEARCH_SCOPE
431 if (!strcmp(EDUI_SEARCH_SCOPE, "base"))
432 edui_conf.scope = 0;
433 else if (!strcmp(EDUI_SEARCH_SCOPE, "one"))
434 edui_conf.scope = 1;
435 else if (!strcmp(EDUI_SEARCH_SCOPE, "sub"))
436 edui_conf.scope = 2;
437 else
438 edui_conf.scope = 1;
439#endif
440#ifdef EDUI_LDAP_VERSION
441 edui_conf.ver = EDUI_LDAP_VERSION;
442#endif
443#ifdef EDUI_DEFAULT_PORT
444 edui_conf.port = EDUI_DEFAULT_PORT;
445#endif
446#ifdef EDUI_FORCE_IPV4
447 edui_conf.mode |= EDUI_MODE_IPV4;
448#endif
449#ifdef EDUI_FORCE_IPV6
450 edui_conf.mode |= EDUI_MODE_IPV6;
451#endif
452#ifdef EDUI_USE_TLS
453 edui_conf.mode |= EDUI_MODE_TLS;
454#endif
455#ifdef EDUI_USE_PERSIST
456 edui_conf.mode |= EDUI_MODE_PERSIST;
457#endif
458#ifdef EDUI_PERSIST_TIMEOUT
459 edui_conf.persist_timeout = EDUI_PERSIST_TIMEOUT;
460#endif
461#ifdef EDUI_GROUP_REQUIRED
462 edui_conf.mode |= EDUI_MODE_GROUP;
463#endif
464#ifdef EDUI_DEBUG
465 edui_conf.mode |= EDUI_MODE_DEBUG;
466#endif
467}
468
469/* Displays running configuration */
915c866f
CN
470static void
471DisplayConf()
f86504f1
AJ
472{
473 if (!(edui_conf.mode & EDUI_MODE_DEBUG))
474 return;
475 DisplayVersion();
476 local_printfx("\n");
477 local_printfx("Configuration:\n");
fe1e5c91 478 local_printfx(" EDUI_MAXLEN: %u\n", EDUI_MAXLEN);
f86504f1
AJ
479 if (edui_conf.mode & EDUI_MODE_DEBUG)
480 local_printfx(" Debug mode: ON\n");
481 else
482 local_printfx(" Debug mode: OFF\n");
483 if (edui_conf.mode & EDUI_MODE_IPV4)
484 local_printfx(" Address format: IPv4 (127.0.0.1)\n");
485 else if (edui_conf.mode & EDUI_MODE_IPV6)
486 local_printfx(" Address format: IPv6 (::1)\n");
487 else
488 local_printfx(" Address format: Not enforced.\n");
489 if (edui_conf.host[0] != '\0')
490 local_printfx(" Hostname: %s\n", edui_conf.host);
491 else
492 local_printfx(" Hostname: localhost\n");
493 if (edui_conf.port > 0)
494 local_printfx(" Port: %d\n", edui_conf.port);
495 else
496 local_printfx(" Port: %d\n", LDAP_PORT);
497 if (edui_conf.mode & EDUI_MODE_TLS)
498 local_printfx(" TLS mode: ON\n");
499 else
500 local_printfx(" TLS mode: OFF\n");
501 if (edui_conf.mode & EDUI_MODE_PERSIST) {
502 local_printfx(" Persistent mode: ON\n");
503 if (edui_conf.persist_timeout > 0)
504 local_printfx(" Persistent mode idle timeout: %d\n", edui_conf.persist_timeout);
505 else
506 local_printfx(" Persistent mode idle timeout: OFF\n");
507 } else
508 local_printfx(" Persistent mode: OFF\n");
509 local_printfx(" LDAP Version: %d\n", edui_conf.ver);
510 if (edui_conf.basedn[0] != '\0')
511 local_printfx(" Base DN: %s\n", edui_conf.basedn);
512 else
513 local_printfx(" Base DN: None\n");
514 if (edui_conf.dn[0] != '\0')
515 local_printfx(" Binding DN: %s\n", edui_conf.dn);
516 else
517 local_printfx(" Binding DN: Anonymous\n");
518 if (edui_conf.passwd[0] != '\0')
519 local_printfx(" Binding Password: %s\n", edui_conf.passwd);
520 else
521 local_printfx(" Binding Password: None\n");
522 switch (edui_conf.scope) {
523 case 0:
524 local_printfx(" Search Scope: base\n");
525 break;
526 case 1:
527 local_printfx(" Search Scope: one level\n");
528 break;
529 case 2:
530 local_printfx(" Search Scope: subtree\n");
531 break;
532 default:
533 local_printfx(" Search Scope: base\n");
534 break;
535 }
6ca7324f
AJ
536 if (edui_conf.attrib[0] != '\0')
537 local_printfx(" Search Attribute: %s\n", edui_conf.attrib);
538 else
539 local_printfx(" Search Attribute: cn\n");
f86504f1
AJ
540 if (edui_conf.search_filter[0] != '\0')
541 local_printfx(" Search Filter: %s\n", edui_conf.search_filter);
542 else
543 local_printfx(" Search Filter: (&(objectClass=User)(networkAddress=*))\n");
544 if (edui_conf.mode & EDUI_MODE_GROUP)
545 local_printfx(" Search Group Required: Yes\n");
546 else
547 local_printfx(" Search Group Required: No\n");
548 local_printfx("\n");
549}
550
551/* InitLDAP() - <edui_ldap_t>
552 *
2f8abb64 553 * Initialize LDAP structure for use, zeroing out all variables.
f86504f1
AJ
554 *
555 */
915c866f
CN
556static void
557InitLDAP(edui_ldap_t *l)
f86504f1 558{
7a545fdb 559 if (l == NULL) return;
f86504f1
AJ
560
561 l->lp = NULL;
562 if (l->lm != NULL)
563 ldap_msgfree(l->lm);
564 if (l->val != NULL)
565 ldap_value_free_len(l->val);
566 l->lm = NULL;
567 l->val = NULL;
7a545fdb
AJ
568 *(l->basedn) = '\0';
569 *(l->host) = '\0';
570 *(l->dn) = '\0';
571 *(l->passwd) = '\0';
572 *(l->search_filter) = '\0';
573 *(l->userid) = '\0';
f86504f1 574 memset(l->search_ip, '\0', sizeof(l->search_ip));
f86504f1
AJ
575 l->status = 0;
576 l->status |= LDAP_INIT_S;
577 l->port = 0;
578 l->scope = -1;
579 l->type = 0;
f53969cc 580 l->err = -1; /* Set error to LDAP_SUCCESS by default */
f86504f1
AJ
581 l->ver = 0;
582 l->idle_time = 0;
f53969cc
SM
583 l->num_ent = 0; /* Number of entries in l->lm */
584 l->num_val = 0; /* Number of entries in l->val */
f86504f1
AJ
585
586 /* Set default settings from conf */
587 if (edui_conf.basedn[0] != '\0')
6ca7324f 588 xstrncpy(l->basedn, edui_conf.basedn, sizeof(l->basedn));
f86504f1 589 if (edui_conf.host[0] != '\0')
6ca7324f 590 xstrncpy(l->host, edui_conf.host, sizeof(l->host));
f86504f1
AJ
591 if (edui_conf.port != 0)
592 l->port = edui_conf.port;
593 if (edui_conf.dn[0] != '\0')
6ca7324f 594 xstrncpy(l->dn, edui_conf.dn, sizeof(l->dn));
f86504f1 595 if (edui_conf.passwd[0] != '\0')
6ca7324f 596 xstrncpy(l->passwd, edui_conf.passwd, sizeof(l->passwd));
f86504f1 597 if (edui_conf.search_filter[0] != '\0')
6ca7324f 598 xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter));
f86504f1
AJ
599 if (!(edui_conf.scope < 0))
600 l->scope = edui_conf.scope;
f86504f1
AJ
601}
602
603/* OpenLDAP() - <edui_ldap_t> <host> <port>
604 *
605 * Build LDAP struct with hostname and port, and ready it for binding.
606 *
607 */
915c866f
CN
608static int
609OpenLDAP(edui_ldap_t *l, char *h, unsigned int p)
f86504f1
AJ
610{
611 if ((l == NULL) || (h == NULL)) return LDAP_ERR_NULL;
2f8abb64 612 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized, or might be in use */
f53969cc
SM
613 if (l->status & LDAP_OPEN_S) return LDAP_ERR_OPEN; /* Already open */
614 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
f86504f1 615
6ca7324f 616 xstrncpy(l->host, h, sizeof(l->host));
f86504f1
AJ
617 if (p > 0)
618 l->port = p;
619 else
f53969cc 620 l->port = LDAP_PORT; /* Default is port 389 */
f86504f1
AJ
621
622#ifdef NETSCAPE_SSL
623 if (l->port == LDAPS_PORT)
f53969cc 624 l->status |= (LDAP_SSL_S | LDAP_TLS_S); /* SSL Port: 636 */
f86504f1
AJ
625#endif
626
627#ifdef USE_LDAP_INIT
628 l->lp = ldap_init(l->host, l->port);
629#else
630 l->lp = ldap_open(l->host, l->port);
631#endif
632 if (l->lp == NULL) {
633 l->err = LDAP_CONNECT_ERROR;
f53969cc 634 return LDAP_ERR_CONNECT; /* Unable to connect */
f86504f1
AJ
635 } else {
636 /* set status */
637// l->status &= ~(LDAP_INIT_S);
638 l->status |= LDAP_OPEN_S;
639 l->err = LDAP_SUCCESS;
640 return LDAP_ERR_SUCCESS;
641 }
642}
643
644/* CloseLDAP() - <edui_ldap_t>
645 *
646 * Close LDAP connection, and clean up data structure.
647 *
648 */
915c866f
CN
649static int
650CloseLDAP(edui_ldap_t *l)
f86504f1
AJ
651{
652 int s;
653 if (l == NULL) return LDAP_ERR_NULL;
654 if (l->lp == NULL) return LDAP_ERR_NULL;
2f8abb64 655 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Connection not initialized */
f53969cc 656 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Connection not open */
f86504f1
AJ
657
658 if (l->lm != NULL) {
659 ldap_msgfree(l->lm);
660 l->lm = NULL;
661 }
662 if (l->val != NULL) {
663 ldap_value_free_len(l->val);
664 l->val = NULL;
665 }
666
667 /* okay, so it's open, close it - No need to check other criteria */
668 s = ldap_unbind(l->lp);
669 if (s == LDAP_SUCCESS) {
670 l->status = LDAP_INIT_S;
f86504f1 671 l->idle_time = 0;
f53969cc 672 l->err = s; /* Set LDAP error code */
f86504f1
AJ
673 return LDAP_ERR_SUCCESS;
674 } else {
f53969cc 675 l->err = s; /* Set LDAP error code */
f86504f1
AJ
676 return LDAP_ERR_FAILED;
677 }
678}
679
680/* SetVerLDAP() - <edui_ldap_t> <version>
681 *
682 * Set LDAP version number for connection to <version> of 1, 2, or 3
683 *
684 */
915c866f
CN
685static int
686SetVerLDAP(edui_ldap_t *l, int v)
f86504f1
AJ
687{
688 int x;
689 if (l == NULL) return LDAP_ERR_NULL;
690 if ((v > 3) || (v < 1)) return LDAP_ERR_PARAM;
691 if (l->lp == NULL) return LDAP_ERR_POINTER;
2f8abb64 692 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
693 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
694 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
f86504f1
AJ
695
696 /* set version */
697 x = ldap_set_option(l->lp, LDAP_OPT_PROTOCOL_VERSION, &v);
698 if (x == LDAP_SUCCESS) {
699 l->ver = v;
f53969cc 700 l->err = x; /* Set LDAP error code */
f86504f1
AJ
701 return LDAP_ERR_SUCCESS;
702 } else {
f53969cc 703 l->err = x; /* Set LDAP error code */
f86504f1
AJ
704 return LDAP_ERR_FAILED;
705 }
706}
707
708/* BindLDAP() - <edui_ldap_t> <use-dn> <use-password> <type>
709 *
710 * Bind LDAP connection (Open) using optional dn and password, of <type>
711 *
712 */
915c866f
CN
713static int
714BindLDAP(edui_ldap_t *l, char *dn, char *pw, unsigned int t)
f86504f1
AJ
715{
716 int s;
717 if (l == NULL) return LDAP_ERR_NULL;
2f8abb64 718 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
719 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
720 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
721 if (l->lp == NULL) return LDAP_ERR_POINTER; /* Error */
f86504f1
AJ
722
723 /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */
724 if (dn != NULL) {
d08caf47
AJ
725 if (strlen(dn) >= sizeof(l->dn))
726 return LDAP_ERR_OOB; /* DN too large */
727
f86504f1
AJ
728 if ((l->basedn[0] != '\0') && (strstr(dn, l->basedn) == NULL)) {
729 /* We got a basedn, but it's not part of dn */
d08caf47
AJ
730 const int x = snprintf(l->dn, sizeof(l->dn)-1, "%s,%s", dn, l->basedn);
731 if (x < 0 || static_cast<size_t>(x) >= sizeof(l->dn))
732 return LDAP_ERR_OOB; /* DN too large */
f86504f1 733 } else
6ca7324f 734 xstrncpy(l->dn, dn, sizeof(l->dn));
f86504f1
AJ
735 }
736 if (pw != NULL)
6ca7324f 737 xstrncpy(l->passwd, pw, sizeof(l->passwd));
f86504f1 738
7a545fdb 739 /* Type */
f86504f1
AJ
740 switch (t) {
741 case LDAP_AUTH_NONE:
742 l->type = t;
743 break;
744 case LDAP_AUTH_SIMPLE:
745 l->type = t;
746 break;
747 case LDAP_AUTH_SASL:
748 l->type = t;
749 break;
67245b81 750#ifdef LDAP_AUTH_KRBV4
f86504f1
AJ
751 case LDAP_AUTH_KRBV4:
752 l->type = t;
753 break;
67245b81
AJ
754#endif
755#ifdef LDAP_AUTH_KRBV41
f86504f1
AJ
756 case LDAP_AUTH_KRBV41:
757 l->type = t;
758 break;
67245b81
AJ
759#endif
760#ifdef LDAP_AUTH_KRBV42
f86504f1
AJ
761 case LDAP_AUTH_KRBV42:
762 l->type = t;
763 break;
67245b81 764#endif
f86504f1 765#ifdef LDAP_AUTH_TLS
f53969cc 766 case LDAP_AUTH_TLS: /* Added for chicken switch to TLS-enabled without using SSL */
f86504f1
AJ
767 l->type = t;
768 break;
769#endif
770 default:
771 l->type = LDAP_AUTH_NONE;
f53969cc 772 break; /* Default to anonymous bind */
f86504f1
AJ
773 }
774
775 /* Bind */
60727a6f 776#if defined(LDAP_AUTH_TLS) && defined(NETSCAPE_SSL) && HAVE_LDAP_START_TLS_S
f86504f1
AJ
777 if (l->type == LDAP_AUTH_TLS)
778 s = ldap_start_tls_s(l->lp, NULL, NULL);
779 else
780#endif
781 s = ldap_bind_s(l->lp, l->dn, l->passwd, l->type);
782 if (s == LDAP_SUCCESS) {
f53969cc
SM
783 l->status |= LDAP_BIND_S; /* Success */
784 l->err = s; /* Set LDAP error code */
f86504f1
AJ
785 return LDAP_ERR_SUCCESS;
786 } else {
f53969cc 787 l->err = s; /* Set LDAP error code */
f86504f1
AJ
788 return LDAP_ERR_FAILED;
789 }
790}
791
d08caf47
AJ
792// XXX: duplicate (partial) of Ip::Address::lookupHostIp
793/**
794 * Convert the IP address string representation in src to
795 * its binary representation.
796 *
797 * \return binary representation of the src IP address.
798 * Must be free'd using freeaddrinfo().
799 */
800static struct addrinfo *
801makeIpBinary(const char *src)
802{
803 struct addrinfo want;
804 memset(&want, 0, sizeof(want));
805 want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups!
806
807 struct addrinfo *dst = nullptr;
808 if (getaddrinfo(src, nullptr, &want, &dst) != 0) {
809 // not an IP address
810 /* free any memory getaddrinfo() dynamically allocated. */
811 if (dst)
812 freeaddrinfo(dst);
813 return nullptr;
814 }
815
816 return dst;
817}
818
819/**
820 * Convert srcLen bytes from src into HEX and store into dst, which
821 * has a maximum content size of dstSize including c-string terminator.
822 * The dst value produced will be a 0-terminated c-string.
823 *
824 * \retval N length of dst written (excluding c-string terminator)
825 * \retval -11 (LDAP_ERR_OOB) buffer overflow detected
826 */
827static int
828makeHexString(char *dst, const int dstSize, const char *src, const int srcLen)
829{
830 // HEX encoding doubles the amount of bytes/octets copied
831 if ((srcLen*2) >= dstSize)
832 return LDAP_ERR_OOB; // cannot copy that many
833
834 *dst = 0;
835
836 for (int k = 0; k < srcLen; ++k) {
837 int c = static_cast<int>(src[k]);
838 if (c < 0)
839 c = c + 256;
840 char hexc[4];
841 const int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
842 if (hlen < 0 || static_cast<size_t>(hlen) > sizeof(hexc)) // should be impossible
843 return LDAP_ERR_OOB;
844 strcat(dst, hexc);
845 }
846 return strlen(dst);
847}
848
f86504f1
AJ
849/*
850 * ConvertIP() - <edui_ldap_t> <ip>
851 *
852 * Take an IPv4 address in dot-decimal or IPv6 notation, and convert to 2-digit HEX stored in l->search_ip
853 * This is the networkAddress that we search LDAP for.
f86504f1 854 */
915c866f
CN
855static int
856ConvertIP(edui_ldap_t *l, char *ip)
f86504f1 857{
f86504f1 858 void *y, *z;
f86504f1
AJ
859 if (l == NULL) return LDAP_ERR_NULL;
860 if (ip == NULL) return LDAP_ERR_PARAM;
2f8abb64 861 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
862 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
863 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
f86504f1
AJ
864
865 y = memchr((void *)ip, ':', EDUI_MAXLEN);
866 z = memchr((void *)ip, '.', EDUI_MAXLEN);
867 if ((y != NULL) && (z != NULL)) {
314b9463
A
868 y = NULL;
869 z = NULL;
870 return LDAP_ERR_INVALID;
f86504f1
AJ
871 }
872 if ((y != NULL) && (edui_conf.mode & EDUI_MODE_IPV4)) {
314b9463
A
873 /* IPv4 Mode forced */
874 return LDAP_ERR_INVALID;
875 } else if (y != NULL) {
876 /* Set IPv6 mode */
314b9463
A
877 if (l->status & LDAP_IPV4_S)
878 l->status &= ~(LDAP_IPV4_S);
879 if (!(l->status & LDAP_IPV6_S))
880 l->status |= (LDAP_IPV6_S);
881 y = NULL;
f86504f1
AJ
882 }
883 if ((z != NULL) && (edui_conf.mode & EDUI_MODE_IPV6)) {
314b9463
A
884 /* IPv6 Mode forced */
885 return LDAP_ERR_INVALID;
886 } else if (z != NULL) {
314b9463
A
887 /* Set IPv4 mode */
888 if (l->status & LDAP_IPV6_S)
889 l->status &= ~(LDAP_IPV6_S);
890 if (!(l->status & LDAP_IPV4_S))
891 l->status |= (LDAP_IPV4_S);
892 z = NULL;
f86504f1 893 }
f86504f1 894
d08caf47
AJ
895 size_t s = LDAP_ERR_INVALID;
896 if (struct addrinfo *dst = makeIpBinary(ip)) {
897 if (dst->ai_family == AF_INET6) {
898 struct sockaddr_in6 *sia = reinterpret_cast<struct sockaddr_in6 *>(dst->ai_addr);
899 const char *ia = reinterpret_cast<const char *>(sia->sin6_addr.s6_addr);
900 s = makeHexString(l->search_ip, sizeof(l->search_ip), ia, 16); // IPv6 = 16-byte address
901
902 } else if (dst->ai_family == AF_INET) {
903 struct sockaddr_in *sia = reinterpret_cast<struct sockaddr_in *>(dst->ai_addr);
904 const char *ia = reinterpret_cast<const char *>(&(sia->sin_addr));
905 s = makeHexString(l->search_ip, sizeof(l->search_ip), ia, 4); // IPv4 = 4-byte address
906 } // else leave s with LDAP_ERR_INVALID value
907 freeaddrinfo(dst);
f86504f1
AJ
908 }
909
f86504f1
AJ
910 return s;
911}
912
913/* ResetLDAP() - <edui_ldap_t>
914 *
915 * Resets LDAP connection for next search query.
916 *
917 */
915c866f
CN
918static int
919ResetLDAP(edui_ldap_t *l)
314b9463
A
920{
921 if (l == NULL) return LDAP_ERR_NULL;
2f8abb64 922 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
314b9463
A
923 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
924 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
925 if (!(l->status & LDAP_PERSIST_S)) return LDAP_ERR_PERSIST; /* Not persistent */
926
927 /* Cleanup data struct */
314b9463
A
928 if (l->status & LDAP_VAL_S)
929 l->status &= ~(LDAP_VAL_S);
930 if (l->status & LDAP_SEARCH_S)
931 l->status &= ~(LDAP_SEARCH_S);
932 if (l->status & LDAP_IPV4_S)
933 l->status &= ~(LDAP_IPV4_S);
934 if (l->status & LDAP_IPV6_S)
935 l->status &= ~(LDAP_IPV6_S);
936 if (l->lm != NULL) {
937 ldap_msgfree(l->lm);
938 l->lm = NULL;
939 }
940 if (l->val != NULL) {
941 ldap_value_free_len(l->val);
942 l->val = NULL;
943 }
944 memset(l->search_ip, '\0', sizeof(l->search_ip));
7a545fdb 945 *(l->search_filter) = '\0';
6ca7324f 946 xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter));
7a545fdb 947 *(l->userid) = '\0';
314b9463
A
948 if (!(l->status & LDAP_IDLE_S))
949 l->status |= LDAP_IDLE_S; /* Set idle mode */
950 l->num_ent = 0;
951 l->num_val = 0;
314b9463
A
952 l->err = LDAP_SUCCESS;
953 return LDAP_ERR_SUCCESS;
f86504f1
AJ
954}
955
956/*
957 * SearchFilterLDAP() - <edui_ldap_t> <IP> <group>
958 *
959 * Build LDAP Search Filter string and copy to l->search_filter
960 *
961 */
915c866f
CN
962static int
963SearchFilterLDAP(edui_ldap_t *l, char *group)
f86504f1
AJ
964{
965 size_t i, j, s;
966 int swi;
967 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], bufc[EDUI_MAXLEN], bufd[EDUI_MAXLEN], bufg[EDUI_MAXLEN];
968 if (l == NULL) return LDAP_ERR_NULL;
2f8abb64 969 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
970 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
971 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not Bound */
972 if (l->search_ip[0] == '\0') return LDAP_ERR_DATA; /* Search IP is required */
f86504f1
AJ
973
974 /* Zero out if not already */
915c866f
CN
975 memset(bufa, '\0', sizeof(bufa));
976 // using memset() for 'bufa' fixes the 64-bit issue
7a545fdb
AJ
977 *(bufb) = '\0';
978 *(bufc) = '\0';
979 *(bufd) = '\0';
980 *(bufg) = '\0';
f86504f1 981
f86504f1
AJ
982 s = strlen(l->search_ip);
983 bufc[0] = '\134';
984 swi = 0;
985 j = 1;
eb62585f 986 for (i = 0; i < s; ++i) {
f86504f1
AJ
987 if (swi == 2) {
988 bufc[j] = '\134';
755494da 989 ++j;
f86504f1 990 bufc[j] = l->search_ip[i];
755494da 991 ++j;
f86504f1
AJ
992 swi = 1;
993 } else {
994 bufc[j] = l->search_ip[i];
755494da
FC
995 ++j;
996 ++swi;
f86504f1
AJ
997 }
998 }
999 if (group == NULL) {
1000 /* No groupMembership= to add, yay! */
f86504f1 1001 /* networkAddress */
314b9463 1002 if (l->status & LDAP_IPV4_S) {
d08caf47
AJ
1003 const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", bufc, bufc);
1004 if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd))
1005 return LDAP_ERR_OOB;
1006
f86504f1 1007 } else if (l->status & LDAP_IPV6_S) {
d08caf47
AJ
1008 const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s)", bufc, bufc);
1009 if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd))
1010 return LDAP_ERR_OOB;
1011 }
1012 const int x = snprintf(bufa, sizeof(bufa), "(&%s(|(networkAddress=1\\23%s)%s))", edui_conf.search_filter, bufc, bufd);
1013 if (x < 0 || static_cast<size_t>(x) >= sizeof(bufa))
1014 return LDAP_ERR_OOB;
1015
f86504f1
AJ
1016 } else {
1017 /* Needs groupMembership= to add... */
f86504f1 1018 /* groupMembership -- NOTE: Squid *MUST* provide "cn=" from squid.conf */
f86504f1 1019 if ((l->basedn[0] != '\0') && (strstr(group, l->basedn) == NULL)) {
d08caf47
AJ
1020 const int ln = snprintf(bufg, sizeof(bufg), ",%s", l->basedn);
1021 if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd))
1022 return LDAP_ERR_OOB;
f86504f1 1023 }
f86504f1 1024 /* networkAddress */
314b9463 1025 if (l->status & LDAP_IPV4_S) {
d08caf47
AJ
1026 const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", bufc, bufc);
1027 if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd))
1028 return LDAP_ERR_OOB;
f86504f1 1029 } else if (l->status & LDAP_IPV6_S) {
d08caf47
AJ
1030 const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s)", bufc, bufc);
1031 if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd))
1032 return LDAP_ERR_OOB;
1033 }
1034 const int x = snprintf(bufa, sizeof(bufa), "(&(&%s(groupMembership=%s%s)(|(networkAddress=1\\23%s)%s)))", edui_conf.search_filter, group, bufg, bufc, bufd);
1035 if (x < 0 || static_cast<size_t>(x) >= sizeof(bufa))
1036 return LDAP_ERR_OOB;
f86504f1
AJ
1037 }
1038 s = strlen(bufa);
bcdce702 1039 xstrncpy(l->search_filter, bufa, sizeof(l->search_filter));
f86504f1
AJ
1040 return s;
1041}
1042
1043/*
1044 * SearchLDAP() - <edui_ldap_t> <scope> <filter> <attrib>
1045 *
1046 * Initate LDAP query, under <scope> levels, filtering matches with <filter> and optionally <attrib>
1047 * <attrib> will generally be networkAddress ...
1048 *
1049 */
915c866f
CN
1050static int
1051SearchLDAP(edui_ldap_t *l, int scope, char *filter, char **attrs)
f86504f1
AJ
1052{
1053 int s;
1054 char ft[EDUI_MAXLEN];
1055 if (l == NULL) return LDAP_ERR_NULL;
f53969cc 1056 if ((scope < 0) || (filter == NULL)) return LDAP_ERR_PARAM; /* If attrs is NULL, then all attrs will return */
f86504f1 1057 if (l->lp == NULL) return LDAP_ERR_POINTER;
2f8abb64 1058 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
1059 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1060 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
1061 if (l->status & LDAP_SEARCH_S) return LDAP_ERR_SEARCHED; /* Already searching */
1062 if (l->basedn[0] == '\0') return LDAP_ERR_DATA; /* We require a basedn */
f86504f1 1063 if (l->lm != NULL)
f53969cc 1064 ldap_msgfree(l->lm); /* Make sure l->lm is empty */
f86504f1 1065
0fbf9a8f 1066 xstrncpy(ft, filter, sizeof(ft));
f86504f1
AJ
1067
1068 /* We have a binded connection, with a free l->lm, so let's get this done */
1069 switch (scope) {
1070 case 0:
1071 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_BASE, ft, attrs, 0, &(l->lm));
1072 break;
1073 case 1:
1074 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm));
1075 break;
1076 case 2:
1077 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_SUBTREE, ft, attrs, 0, &(l->lm));
1078 break;
1079 default:
6ca7324f
AJ
1080 /* Only search ONE by default */
1081 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm));
f86504f1
AJ
1082 break;
1083 }
1084 if (s == LDAP_SUCCESS) {
f53969cc 1085 l->status |= (LDAP_SEARCH_S); /* Mark as searched */
f86504f1 1086 l->err = s;
f53969cc
SM
1087 l->idle_time = 0; /* Connection in use, reset idle timer */
1088 l->num_ent = ldap_count_entries(l->lp, l->lm); /* Counted */
f86504f1
AJ
1089 return LDAP_ERR_SUCCESS;
1090 } else {
1091 l->err = s;
1092 l->num_ent = (-1);
1093 return LDAP_ERR_FAILED;
1094 }
1095}
1096
1097/*
7a545fdb 1098 * SearchIPLDAP() - <edui_ldap_t>
f86504f1
AJ
1099 *
1100 * Scan LDAP and get all networkAddress Values, and see if they match l->search_ip
1101 * Actual IP matching routine for eDirectory
1102 *
1103 */
915c866f
CN
1104static int
1105SearchIPLDAP(edui_ldap_t *l)
f86504f1
AJ
1106{
1107 ber_len_t i, x;
d08caf47
AJ
1108 ber_len_t j;
1109 ber_len_t z;
1110 char bufa[EDUI_MAXLEN];
1111 char bufb[EDUI_MAXLEN];
f86504f1 1112 LDAPMessage *ent;
f86504f1 1113 if (l == NULL) return LDAP_ERR_NULL;
f86504f1 1114 if (l->lp == NULL) return LDAP_ERR_POINTER;
2f8abb64 1115 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */
f53969cc
SM
1116 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1117 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
1118 if (!(l->status & LDAP_SEARCH_S)) return LDAP_ERR_NOT_SEARCHED; /* Not searched */
9c76c145
A
1119 if (l->num_ent <= 0) {
1120 debug("l->num_ent: %d\n", l->num_ent);
f53969cc 1121 return LDAP_ERR_DATA; /* No entries found */
7a545fdb 1122 }
f86504f1 1123 if (l->val != NULL)
f53969cc 1124 ldap_value_free_len(l->val); /* Clear data before populating */
f86504f1
AJ
1125 l->num_val = 0;
1126 if (l->status & LDAP_VAL_S)
f53969cc 1127 l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */
f86504f1 1128 if (edui_conf.attrib[0] == '\0')
f53969cc 1129 xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); /* Make sure edui_conf.attrib is set */
f86504f1
AJ
1130
1131 /* Sift through entries */
9d70add4 1132 struct berval **ber = NULL;
f86504f1
AJ
1133 for (ent = ldap_first_entry(l->lp, l->lm); ent != NULL; ent = ldap_next_entry(l->lp, ent)) {
1134 l->val = ldap_get_values_len(l->lp, ent, "networkAddress");
f53969cc 1135 ber = ldap_get_values_len(l->lp, ent, edui_conf.attrib); /* edui_conf.attrib is the <userid> mapping */
f86504f1 1136 if (l->val != NULL) {
f53969cc 1137 x = ldap_count_values_len(l->val); /* We got x values ... */
f86504f1
AJ
1138 l->num_val = x;
1139 if (x > 0) {
1140 /* Display all values */
eb62585f 1141 for (i = 0; i < x; ++i) {
f86504f1
AJ
1142 j = l->val[i]->bv_len;
1143 memcpy(bufa, l->val[i]->bv_val, j);
7a545fdb 1144 z = BinarySplit(bufa, j, '#', bufb, sizeof(bufb));
9c76c145 1145 /* BINARY DEBUGGING *
f53969cc
SM
1146 local_printfx("value[%" PRIuSIZE "]: BinarySplit(", (size_t) i);
1147 for (k = 0; k < z; ++k) {
1148 c = (int) bufb[k];
1149 if (c < 0)
1150 c = c + 256;
1151 local_printfx("%02X", c);
1152 }
1153 local_printfx(", ");
1154 for (k = 0; k < (j - z - 1); ++k) {
1155 c = (int) bufa[k];
1156 if (c < 0)
1157 c = c + 256;
1158 local_printfx("%02X", c);
1159 }
1160 local_printfx("): %" PRIuSIZE "\n", (size_t) z);
9c76c145 1161 * BINARY DEBUGGING */
f86504f1 1162 z = j - z - 1;
9c76c145 1163 j = atoi(bufb);
7a545fdb 1164 if (j == 1) {
9c76c145 1165 /* IPv4 address (eDirectory 8.7 and below) */
f86504f1
AJ
1166 /* bufa is the address, just compare it */
1167 if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S))
f53969cc 1168 break; /* Not looking for IPv4 */
d08caf47
AJ
1169 const int blen = makeHexString(bufb, sizeof(bufb), bufa, z);
1170 if (blen < 0)
1171 return blen;
f86504f1 1172 /* Compare value with IP */
d08caf47 1173 if (memcmp(l->search_ip, bufb, blen) == 0) {
f86504f1
AJ
1174 /* We got a match! - Scan 'ber' for 'cn' values */
1175 z = ldap_count_values_len(ber);
eb62585f 1176 for (j = 0; j < z; ++j) {
7a545fdb
AJ
1177// broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1178 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
9c76c145
A
1179 /* Using bv_len of min() breaks the result by 2 chars */
1180 }
f86504f1
AJ
1181 ldap_value_free_len(l->val);
1182 l->val = NULL;
1183 ldap_value_free_len(ber);
1184 ber = NULL;
1185 l->num_val = 0;
1186 l->err = LDAP_SUCCESS;
1187 l->status &= ~(LDAP_SEARCH_S);
f53969cc 1188 return LDAP_ERR_SUCCESS; /* We got our userid */
f86504f1
AJ
1189 }
1190 /* Not matched, continue */
9c76c145
A
1191 } else if ((j == 8) || (j == 9)) {
1192 /* IPv4 (UDP/TCP) address (eDirectory 8.8 and higher) */
f86504f1
AJ
1193 /* bufa + 2 is the address (skip 2 digit port) */
1194 if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S))
f53969cc 1195 break; /* Not looking for IPv4 */
d08caf47
AJ
1196 const int blen = makeHexString(bufb, sizeof(bufb), &bufa[2], z);
1197 if (blen < 0)
1198 return blen;
f86504f1 1199 /* Compare value with IP */
d08caf47 1200 if (memcmp(l->search_ip, bufb, blen) == 0) {
f86504f1
AJ
1201 /* We got a match! - Scan 'ber' for 'cn' values */
1202 z = ldap_count_values_len(ber);
eb62585f 1203 for (j = 0; j < z; ++j) {
7a545fdb
AJ
1204// broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1205 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
915c866f 1206 /* Using bv_len of min() breaks the result by 2 chars */
2c3d5aec 1207 }
f86504f1
AJ
1208 ldap_value_free_len(l->val);
1209 l->val = NULL;
1210 ldap_value_free_len(ber);
1211 ber = NULL;
1212 l->num_val = 0;
1213 l->err = LDAP_SUCCESS;
1214 l->status &= ~(LDAP_SEARCH_S);
f53969cc 1215 return LDAP_ERR_SUCCESS; /* We got our userid */
f86504f1
AJ
1216 }
1217 /* Not matched, continue */
9c76c145 1218 } else if ((j == 10) || (j == 11)) {
7a545fdb 1219 /* IPv6 (UDP/TCP) address (eDirectory 8.8 and higher) */
f86504f1
AJ
1220 /* bufa + 2 is the address (skip 2 digit port) */
1221 if (!(l->status & LDAP_IPV6_S))
f53969cc 1222 break; /* Not looking for IPv6 */
d08caf47
AJ
1223 const int blen = makeHexString(bufb, sizeof(bufb), &bufa[2], z);
1224 if (blen < 0)
1225 return blen;
f86504f1 1226 /* Compare value with IP */
d08caf47 1227 if (memcmp(l->search_ip, bufb, blen) == 0) {
f86504f1
AJ
1228 /* We got a match! - Scan 'ber' for 'cn' values */
1229 z = ldap_count_values_len(ber);
eb62585f 1230 for (j = 0; j < z; ++j) {
7a545fdb
AJ
1231// broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1232 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
915c866f 1233 /* Using bv_len of min() breaks the result by 2 chars */
2c3d5aec 1234 }
f86504f1
AJ
1235 ldap_value_free_len(l->val);
1236 l->val = NULL;
1237 ldap_value_free_len(ber);
1238 ber = NULL;
1239 l->num_val = 0;
1240 l->err = LDAP_SUCCESS;
1241 l->status &= ~(LDAP_SEARCH_S);
f53969cc 1242 return LDAP_ERR_SUCCESS; /* We got our userid */
f86504f1
AJ
1243 }
1244 /* Not matched, continue */
9c76c145 1245 }
f53969cc 1246// else {
9c76c145 1247 /* Others are unsupported */
7a545fdb 1248// }
f86504f1
AJ
1249 }
1250 if (ber != NULL) {
1251 ldap_value_free_len(ber);
1252 ber = NULL;
1253 }
1254 }
1255 ldap_value_free_len(l->val);
1256 l->val = NULL;
1257 }
1258 if (ber != NULL) {
1259 ldap_value_free_len(ber);
1260 ber = NULL;
1261 }
1262 /* Attr not found, continue */
1263 }
1264 /* No entries found using given attr */
1265 if (l->val != NULL) {
1266 ldap_value_free_len(l->val);
1267 l->val = NULL;
1268 }
f86504f1
AJ
1269 if (l->lm != NULL) {
1270 ldap_msgfree(l->lm);
1271 l->lm = NULL;
1272 }
1273 l->num_ent = 0;
1274 l->num_val = 0;
1275 l->err = LDAP_NO_SUCH_OBJECT;
1276 l->status &= ~(LDAP_SEARCH_S);
f53969cc 1277 return LDAP_ERR_NOTFOUND; /* Not found ... Sorry :) */
f86504f1
AJ
1278}
1279
915c866f
CN
1280/*
1281 * ErrLDAP() - <errno>
1282 *
1283 * Returns error description of error code
1284 *
1285 */
1286const char
1287*ErrLDAP(int e)
f86504f1
AJ
1288{
1289 switch (e) {
1290 case LDAP_ERR_NULL:
1291 return "Null pointer provided";
1292 case LDAP_ERR_POINTER:
1293 return "Null LDAP pointer";
1294 case LDAP_ERR_PARAM:
2f8abb64 1295 return "Null or Missing parameter(s)";
f86504f1 1296 case LDAP_ERR_INIT:
2f8abb64 1297 return "LDAP data not initialized";
f86504f1
AJ
1298 case LDAP_ERR_OPEN:
1299 return "LDAP connection is not active";
1300 case LDAP_ERR_CONNECT:
1301 return "Unable to connect to LDAP host";
1302 case LDAP_ERR_BIND:
1303 return "LDAP connection is not bound";
1304 case LDAP_ERR_SEARCHED:
1305 return "LDAP connection has already been searched";
1306 case LDAP_ERR_NOT_SEARCHED:
1307 return "LDAP connection has not been searched";
1308 case LDAP_ERR_INVALID:
2f8abb64 1309 return "Invalid parameters";
f86504f1 1310 case LDAP_ERR_OOB:
2f8abb64 1311 return "Parameter is out of bounds";
f86504f1
AJ
1312 case LDAP_ERR_PERSIST:
1313 return "Persistent mode is not active";
1314 case LDAP_ERR_DATA:
1315 return "Required data has not been found";
1316 case LDAP_ERR_NOTFOUND:
1317 return "Item or object has not been found";
1318 case LDAP_ERR_OTHER:
61beade2 1319 return "An unknown error has occurred";
f86504f1
AJ
1320 case LDAP_ERR_FAILED:
1321 return "Operation has failed";
1322 case LDAP_ERR_SUCCESS:
1323 return "Operation is successful";
1324 default:
61beade2 1325 return "An unknown error has occurred";
f86504f1
AJ
1326 }
1327}
1328
915c866f
CN
1329/*
1330 * SigTrap() - <signal>
1331 *
1332 * Traps signal codes by number, and gracefully shuts down.
1333 *
1334 */
1335extern "C" void
1336SigTrap(int s)
f86504f1
AJ
1337{
1338 if (!(edui_conf.mode & EDUI_MODE_KILL))
1339 edui_conf.mode |= EDUI_MODE_KILL;
1340
1341 /* Clean Up */
1342 if (edui_ldap.status & LDAP_OPEN_S)
1343 CloseLDAP(&edui_ldap);
1344
6ca7324f 1345 debug("Terminating, Signal: %d\n", s);
24885773 1346 exit(EXIT_SUCCESS);
f86504f1
AJ
1347}
1348
915c866f
CN
1349/*
1350 * MainSafe() - <argc> <argv>
1351 *
1352 * "Safe" version of main()
1353 *
1354 */
1355static int
1356MainSafe(int argc, char **argv)
f86504f1
AJ
1357{
1358 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], *p = NULL;
1359 char bufc[EDUI_MAXLEN];
1360 char sfmod[EDUI_MAXLEN];
1361 int x;
1362 size_t i, j, s, k;
1363 time_t t;
1364 struct sigaction sv;
1365
1366 /* Init */
1367 k = (size_t) argc;
1368 memset(bufa, '\0', sizeof(bufa));
1369 memset(bufb, '\0', sizeof(bufb));
1370 memset(bufc, '\0', sizeof(bufc));
1371 memset(sfmod, '\0', sizeof(sfmod));
3ea9e875 1372 memset(&sv, 0, sizeof(sv));
7a545fdb 1373
f86504f1 1374 InitConf();
6ca7324f 1375 xstrncpy(edui_conf.program, argv[0], sizeof(edui_conf.program));
f86504f1
AJ
1376 edui_now = -1;
1377 t = -1;
f86504f1
AJ
1378
1379 /* Scan args */
1380 if (k > 1) {
eb62585f 1381 for (i = 1; i < k; ++i) {
f86504f1
AJ
1382 /* Classic / novelty usage schemes */
1383 if (!strcmp(argv[i], "--help")) {
1384 DisplayUsage();
1385 return 1;
1386 } else if (!strcmp(argv[i], "--usage")) {
1387 DisplayUsage();
1388 return 1;
1389 } else if (!strcmp(argv[i], "--version")) {
1390 DisplayVersion();
1391 return 1;
1392 } else if (argv[i][0] == '-') {
1393 s = strlen(argv[i]);
eb62585f 1394 for (j = 1; j < s; ++j) {
f86504f1
AJ
1395 switch (argv[i][j]) {
1396 case 'h':
1397 DisplayUsage();
1398 return 1;
1399 case 'V':
1400 DisplayVersion();
1401 return 1;
1402 case 'd':
1403 if (!(edui_conf.mode & EDUI_MODE_DEBUG))
f53969cc
SM
1404 edui_conf.mode |= EDUI_MODE_DEBUG; /* Don't set mode more than once */
1405 debug_enabled = 1; /* Official Squid-3 Debug Mode */
f86504f1
AJ
1406 break;
1407 case '4':
1408 if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6))
f53969cc 1409 edui_conf.mode |= EDUI_MODE_IPV4; /* Don't set mode more than once */
f86504f1
AJ
1410 break;
1411 case '6':
1412 if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6))
f53969cc 1413 edui_conf.mode |= EDUI_MODE_IPV6; /* Don't set mode more than once */
f86504f1
AJ
1414 break;
1415 case 'Z':
1416 if (!(edui_conf.mode & EDUI_MODE_TLS))
f53969cc 1417 edui_conf.mode |= EDUI_MODE_TLS; /* Don't set mode more than once */
f86504f1
AJ
1418 break;
1419 case 'P':
1420 if (!(edui_conf.mode & EDUI_MODE_PERSIST))
f53969cc 1421 edui_conf.mode |= EDUI_MODE_PERSIST; /* Don't set mode more than once */
f86504f1
AJ
1422 break;
1423 case 'v':
f53969cc 1424 ++i; /* Set LDAP version */
f86504f1
AJ
1425 if (argv[i] != NULL) {
1426 edui_conf.ver = atoi(argv[i]);
1427 if (edui_conf.ver < 1)
1428 edui_conf.ver = 1;
1429 else if (edui_conf.ver > 3)
1430 edui_conf.ver = 3;
1431 } else {
1432 local_printfx("No parameters given for 'v'.\n");
1433 DisplayUsage();
1434 return 1;
1435 }
1436 break;
1437 case 't':
f53969cc 1438 ++i; /* Set Persistent timeout */
f86504f1
AJ
1439 if (argv[i] != NULL) {
1440 edui_conf.persist_timeout = atoi(argv[i]);
1441 if (edui_conf.persist_timeout < 0)
1442 edui_conf.persist_timeout = 0;
1443 } else {
1444 local_printfx("No parameters given for 't'.\n");
1445 DisplayUsage();
1446 return 1;
1447 }
1448 break;
1449 case 'b':
f53969cc 1450 ++i; /* Set Base DN */
f86504f1 1451 if (argv[i] != NULL)
6ca7324f 1452 xstrncpy(edui_conf.basedn, argv[i], sizeof(edui_conf.basedn));
f86504f1
AJ
1453 else {
1454 local_printfx("No parameters given for 'b'.\n");
1455 DisplayUsage();
1456 return 1;
1457 }
1458 break;
1459 case 'H':
f53969cc 1460 ++i; /* Set Hostname */
f86504f1 1461 if (argv[i] != NULL)
6ca7324f 1462 xstrncpy(edui_conf.host, argv[i], sizeof(edui_conf.host));
f86504f1
AJ
1463 else {
1464 local_printfx("No parameters given for 'H'.\n");
1465 DisplayUsage();
1466 return 1;
1467 }
1468 break;
1469 case 'p':
f53969cc 1470 ++i; /* Set port */
f86504f1
AJ
1471 if (argv[i] != NULL)
1472 edui_conf.port = atoi(argv[i]);
1473 else {
1474 local_printfx("No parameters given for 'p'.\n");
1475 DisplayUsage();
1476 return 1;
1477 }
1478 break;
1479 case 'D':
f53969cc 1480 ++i; /* Set Bind DN */
f86504f1 1481 if (argv[i] != NULL)
6ca7324f 1482 xstrncpy(edui_conf.dn, argv[i], sizeof(edui_conf.dn));
f86504f1
AJ
1483 else {
1484 local_printfx("No parameters given for 'D'.\n");
1485 DisplayUsage();
1486 return 1;
1487 }
1488 break;
1489 case 'W':
f53969cc 1490 ++i; /* Set Bind PWD */
f86504f1 1491 if (argv[i] != NULL)
6ca7324f 1492 xstrncpy(edui_conf.passwd, argv[i], sizeof(edui_conf.passwd));
f86504f1
AJ
1493 else {
1494 local_printfx("No parameters given for 'W'.\n");
1495 DisplayUsage();
1496 return 1;
1497 }
1498 break;
1499 case 'F':
f53969cc 1500 ++i; /* Set Search Filter */
f86504f1 1501 if (argv[i] != NULL)
6ca7324f 1502 xstrncpy(edui_conf.search_filter, argv[i], sizeof(edui_conf.search_filter));
f86504f1
AJ
1503 else {
1504 local_printfx("No parameters given for 'F'.\n");
1505 DisplayUsage();
1506 return 1;
1507 }
1508 break;
1509 case 'G':
1510 if (!(edui_conf.mode & EDUI_MODE_GROUP))
f53969cc 1511 edui_conf.mode |= EDUI_MODE_GROUP; /* Don't set mode more than once */
f86504f1
AJ
1512 break;
1513 case 's':
f53969cc 1514 ++i; /* Set Scope Level */
f86504f1
AJ
1515 if (argv[i] != NULL) {
1516 if (!strncmp(argv[i], "base", 4))
1517 edui_conf.scope = 0;
1518 else if (!strncmp(argv[i], "one", 4))
1519 edui_conf.scope = 1;
1520 else if (!strncmp(argv[i], "sub", 4))
1521 edui_conf.scope = 2;
1522 else
f53969cc 1523 edui_conf.scope = 1; /* Default is 'one' */
f86504f1
AJ
1524 } else {
1525 local_printfx("No parameters given for 's'.\n");
1526 DisplayUsage();
1527 return 1;
1528 }
1529 break;
6ca7324f 1530 case 'u':
f53969cc 1531 ++i; /* Set Search Attribute */
6ca7324f 1532 if (argv[i] != NULL) {
ab745b44 1533 xstrncpy(edui_conf.attrib, argv[i], sizeof(edui_conf.attrib));
6ca7324f
AJ
1534 } else {
1535 local_printfx("No parameters given for 'u'.\n");
1536 DisplayUsage();
1537 return 1;
1538 }
1539 break;
f53969cc 1540 case '-': /* We got a second '-' ... ignore */
f86504f1
AJ
1541 break;
1542 default:
1543 local_printfx("Invalid parameter - '%c'.\n", argv[i][j]);
1544 break;
1545 }
1546 }
1547 } else {
1548 /* Incorrect parameter, display usage */
1549 DisplayUsage();
1550 return 1;
1551 }
1552 }
1553 }
1554
2f8abb64 1555 /* Set predefined required parameters if none are given, localhost:LDAP_PORT, etc */
f53969cc 1556 if (edui_conf.host[0] == '\0') /* Default to localhost */
6ca7324f 1557 xstrncpy(edui_conf.host, "localhost", sizeof(edui_conf.host));
f86504f1 1558 if (edui_conf.port < 0)
f53969cc 1559 edui_conf.port = LDAP_PORT; /* Default: LDAP_PORT */
f86504f1 1560 if ((edui_conf.mode & EDUI_MODE_IPV4) && (edui_conf.mode & EDUI_MODE_IPV6))
f53969cc 1561 edui_conf.mode &= ~(EDUI_MODE_IPV6); /* Default to IPv4 */
f86504f1
AJ
1562 if (edui_conf.ver < 0)
1563 edui_conf.ver = 2;
1564 if (!(edui_conf.mode & EDUI_MODE_TLS))
f53969cc 1565 edui_conf.mode |= EDUI_MODE_TLS; /* eDirectory requires TLS mode */
f86504f1 1566 if ((edui_conf.mode & EDUI_MODE_TLS) && (edui_conf.ver < 3))
f53969cc 1567 edui_conf.ver = 3; /* TLS requires version 3 */
f86504f1 1568 if (edui_conf.persist_timeout < 0)
f53969cc 1569 edui_conf.persist_timeout = 600; /* Default: 600 seconds (10 minutes) */
f86504f1 1570 if (edui_conf.scope < 0)
f53969cc 1571 edui_conf.scope = 1; /* Default: one */
f86504f1 1572 if (edui_conf.search_filter[0] == '\0')
6ca7324f 1573 xstrncpy(edui_conf.search_filter, "(&(objectclass=User)(networkAddress=*))", sizeof(edui_conf.search_filter));
f86504f1 1574 if (edui_conf.attrib[0] == '\0')
6ca7324f 1575 xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib));
f86504f1 1576 if (edui_conf.basedn[0] == '\0') {
314b9463
A
1577 local_printfx("FATAL: No '-b' option provided (Base DN).\n");
1578 DisplayUsage();
1579 return 1;
f86504f1 1580 }
f86504f1
AJ
1581 /* Trap the following signals */
1582 sigemptyset(&sv.sa_mask);
1583 sv.sa_handler = SigTrap;
1584 sigaction(SIGTERM, &sv, NULL);
1585 sv.sa_handler = SigTrap;
1586 sigaction(SIGHUP, &sv, NULL);
1587 sv.sa_handler = SigTrap;
1588 sigaction(SIGABRT, &sv, NULL);
1589 sv.sa_handler = SigTrap;
1590 sigaction(SIGINT, &sv, NULL);
1591 sv.sa_handler = SigTrap;
1592 sigaction(SIGSEGV, &sv, NULL);
7a545fdb
AJ
1593
1594 DisplayConf();
1595 /* Done with arguments */
f86504f1
AJ
1596
1597 /* Set elap timer */
1598 time(&edui_now);
1599 t = edui_now;
f86504f1
AJ
1600 /* Main loop -- Waits for stdin input before action */
1601 while (fgets(bufa, sizeof(bufa), stdin) != NULL) {
1602 if (edui_conf.mode & EDUI_MODE_KILL)
1603 break;
1604 time(&edui_now);
1605 if (t < edui_now) {
1606 /* Elapse seconds */
1607 edui_elap = edui_now - t;
f86504f1
AJ
1608 t = edui_now;
1609 } else
1610 edui_elap = 0;
1611 k = strlen(bufa);
9c76c145 1612 /* BINARY DEBUGGING *
fe1e5c91 1613 local_printfx("while() -> bufa[%" PRIuSIZE "]: %s", k, bufa);
eb62585f 1614 for (i = 0; i < k; ++i)
9c76c145
A
1615 local_printfx("%02X", bufa[i]);
1616 local_printfx("\n");
1617 * BINARY DEBUGGING */
f86504f1
AJ
1618 /* Check for CRLF */
1619 p = strchr(bufa, '\n');
1620 if (p != NULL)
1621 *p = '\0';
1622 p = strchr(bufa, '\r');
1623 if (p != NULL)
1624 *p = '\0';
1625 p = strchr(bufa, ' ');
1626
1627 /* No space given, but group string is required --> ERR */
1628 if ((edui_conf.mode & EDUI_MODE_GROUP) && (p == NULL)) {
6ca7324f 1629 debug("while() -> Search group is missing. (required)\n");
194ccc9c 1630 local_printfx("BH message=\"(Search Group Required)\"\n");
f86504f1
AJ
1631 continue;
1632 }
1633 x = 0;
1634
1635 /* Open LDAP connection */
1636 if (!(edui_ldap.status & LDAP_INIT_S)) {
1637 InitLDAP(&edui_ldap);
6ca7324f 1638 debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS));
2f8abb64 1639 if (edui_conf.mode & EDUI_MODE_PERSIST) /* Setup persistent mode */
f86504f1
AJ
1640 edui_ldap.status |= LDAP_PERSIST_S;
1641 }
1642 if ((edui_ldap.status & LDAP_IDLE_S) && (edui_elap > 0)) {
1643 edui_ldap.idle_time = edui_ldap.idle_time + edui_elap;
1644 }
1645 if ((edui_ldap.status & LDAP_PERSIST_S) && (edui_ldap.status & LDAP_IDLE_S) && (edui_ldap.idle_time > edui_conf.persist_timeout)) {
6ca7324f 1646 debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap.idle_time));
f86504f1 1647 x = CloseLDAP(&edui_ldap);
6ca7324f 1648 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
f86504f1
AJ
1649 }
1650 edui_ldap.err = -1;
1651 if (!(edui_ldap.status & LDAP_OPEN_S)) {
1652 x = OpenLDAP(&edui_ldap, edui_conf.host, edui_conf.port);
1653 if (x != LDAP_ERR_SUCCESS) {
1654 /* Failed to connect */
6ca7324f 1655 debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
f86504f1 1656 } else {
6ca7324f 1657 debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf.host, edui_conf.port, ErrLDAP(x));
f86504f1
AJ
1658 x = SetVerLDAP(&edui_ldap, edui_conf.ver);
1659 if (x != LDAP_ERR_SUCCESS) {
1660 /* Failed to set version */
6ca7324f 1661 debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
f86504f1 1662 } else
6ca7324f 1663 debug("SetVerLDAP(-, %d) -> %s\n", edui_conf.ver, ErrLDAP(x));
f86504f1
AJ
1664 }
1665 }
1666 edui_ldap.err = -1;
1667 if (!(edui_ldap.status & LDAP_BIND_S) && (edui_conf.mode & EDUI_MODE_TLS)) {
1668 /* TLS binding */
1669 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_TLS);
1670 if (x != LDAP_ERR_SUCCESS) {
1671 /* Unable to bind */
6ca7324f 1672 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
194ccc9c 1673 local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
ab745b44 1674 continue;
f86504f1 1675 } else
6ca7324f 1676 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
f86504f1
AJ
1677 } else if (!(edui_ldap.status & LDAP_BIND_S)) {
1678 if (edui_conf.dn[0] != '\0') {
1679 /* Simple binding - using dn / passwd for authorization */
1680 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_SIMPLE);
1681 if (x != LDAP_ERR_SUCCESS) {
1682 /* Unable to bind */
6ca7324f 1683 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
194ccc9c 1684 local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
ab745b44 1685 continue;
f86504f1 1686 } else
6ca7324f 1687 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
f86504f1
AJ
1688 } else {
1689 /* Anonymous binding */
1690 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_NONE);
1691 if (x != LDAP_ERR_SUCCESS) {
1692 /* Unable to bind */
6ca7324f 1693 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
194ccc9c 1694 local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
ab745b44 1695 continue;
f86504f1 1696 } else
6ca7324f 1697 debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x));
f86504f1
AJ
1698 }
1699 }
1700 edui_ldap.err = -1;
1701 if (edui_ldap.status & LDAP_PERSIST_S) {
1702 x = ResetLDAP(&edui_ldap);
1703 if (x != LDAP_ERR_SUCCESS) {
1704 /* Unable to reset */
6ca7324f 1705 debug("ResetLDAP() -> %s\n", ErrLDAP(x));
f86504f1 1706 } else
6ca7324f 1707 debug("ResetLDAP() -> %s\n", ErrLDAP(x));
f86504f1
AJ
1708 }
1709 if (x != LDAP_ERR_SUCCESS) {
1710 /* Everything failed --> ERR */
6ca7324f 1711 debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
f86504f1 1712 CloseLDAP(&edui_ldap);
194ccc9c 1713 local_printfx("BH message=\"(General Failure: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1714 continue;
1715 }
1716 edui_ldap.err = -1;
1717 /* If we got a group string, split it */
1718 if (p != NULL) {
1719 /* Split string */
fe1e5c91 1720 debug("StringSplit(%s, ' ', %s, %" PRIuSIZE ")\n", bufa, bufb, sizeof(bufb));
7a545fdb 1721 i = StringSplit(bufa, ' ', bufb, sizeof(bufb));
f86504f1 1722 if (i > 0) {
fe1e5c91 1723 debug("StringSplit(%s, %s) done. Result: %" PRIuSIZE "\n", bufa, bufb, i);
f86504f1
AJ
1724 /* Got a group to match against */
1725 x = ConvertIP(&edui_ldap, bufb);
1726 if (x < 0) {
6ca7324f 1727 debug("ConvertIP() -> %s\n", ErrLDAP(x));
194ccc9c 1728 local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1729 } else {
1730 edui_ldap.err = -1;
88f2cf55 1731 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb, x, edui_ldap.search_ip);
f86504f1
AJ
1732 x = SearchFilterLDAP(&edui_ldap, bufa);
1733 if (x < 0) {
6ca7324f 1734 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
194ccc9c 1735 local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1736 } else {
1737 /* Do Search */
1738 edui_ldap.err = -1;
6ca7324f
AJ
1739 debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa, x);
1740 x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
f86504f1 1741 if (x != LDAP_ERR_SUCCESS) {
6ca7324f 1742 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
194ccc9c 1743 local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1744 } else {
1745 edui_ldap.err = -1;
6ca7324f 1746 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
7a545fdb 1747 x = SearchIPLDAP(&edui_ldap);
194ccc9c
CT
1748 if (x == LDAP_ERR_NOTFOUND) {
1749 debug("SearchIPLDAP() -> %s\n", ErrLDAP(x));
c55b0902 1750 local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
194ccc9c 1751 } else if (x == LDAP_ERR_SUCCESS) {
7a545fdb 1752 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
f53969cc 1753 local_printfx("OK user=%s\n", edui_ldap.userid); /* Got userid --> OK user=<userid> */
194ccc9c
CT
1754 } else {
1755 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1756 local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1757 }
1758 }
1759 /* Clear for next query */
7a545fdb 1760 memset(bufc, '\0', sizeof(bufc));
f86504f1
AJ
1761 }
1762 }
1763 } else {
fe1e5c91 1764 debug("StringSplit() -> Error: %" PRIuSIZE "\n", i);
194ccc9c 1765 local_printfx("BH message=\"(StringSplit Error %" PRIuSIZE ")\"\n", i);
f86504f1
AJ
1766 }
1767 } else {
1768 /* No group to match against, only an IP */
1769 x = ConvertIP(&edui_ldap, bufa);
1770 if (x < 0) {
6ca7324f 1771 debug("ConvertIP() -> %s\n", ErrLDAP(x));
194ccc9c 1772 local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
f86504f1 1773 } else {
88f2cf55 1774 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa, x, edui_ldap.search_ip);
f86504f1
AJ
1775 /* Do search */
1776 x = SearchFilterLDAP(&edui_ldap, NULL);
1777 if (x < 0) {
6ca7324f 1778 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
194ccc9c 1779 local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1780 } else {
1781 edui_ldap.err = -1;
6ca7324f
AJ
1782 debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x);
1783 x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
f86504f1 1784 if (x != LDAP_ERR_SUCCESS) {
6ca7324f 1785 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(x));
194ccc9c 1786 local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1787 } else {
1788 edui_ldap.err = -1;
6ca7324f 1789 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
7a545fdb 1790 x = SearchIPLDAP(&edui_ldap);
194ccc9c
CT
1791 if (x == LDAP_ERR_NOTFOUND) {
1792 debug("SearchIPLDAP() -> %s\n", ErrLDAP(x));
c55b0902 1793 local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
194ccc9c 1794 } else if (x == LDAP_ERR_SUCCESS) {
7a545fdb 1795 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
f53969cc 1796 local_printfx("OK user=%s\n", edui_ldap.userid); /* Got a userid --> OK user=<userid> */
194ccc9c
CT
1797 } else if (x != LDAP_ERR_SUCCESS) {
1798 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1799 local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
f86504f1
AJ
1800 }
1801 }
1802 }
1803 /* Clear for next query */
7a545fdb 1804 memset(bufc, '\0', sizeof(bufc));
f86504f1
AJ
1805 }
1806 }
1807
1808 /* Clear buffer and close for next data, if not persistent */
1809 edui_ldap.err = -1;
7a545fdb 1810 memset(bufa, '\0', sizeof(bufa));
f86504f1
AJ
1811 if (!(edui_ldap.status & LDAP_PERSIST_S)) {
1812 x = CloseLDAP(&edui_ldap);
6ca7324f 1813 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
f86504f1
AJ
1814 }
1815 }
1816
6ca7324f 1817 debug("Terminating.\n");
915c866f
CN
1818 return 1;
1819}
1820
1821/* "main()" - function */
1822int
1823main(int argc, char **argv)
1824{
2c3d5aec
A
1825 int x;
1826 x = MainSafe(argc, argv);
1827 return x;
f86504f1 1828}
f53969cc 1829