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