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