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