]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/eDirectory_userip/ext_edirectory_userip_acl.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / helpers / external_acl / eDirectory_userip / ext_edirectory_userip_acl.cc
1 /* ext_edirectory_userip_acl - Copyright (C) 2009-2011 Chad E. Naugle
2 *
3 ********************************************************************************
4 *
5 * This file is part of ext_edirectory_userip_acl.
6 *
7 * ext_edirectory_userip_acl is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ext_edirectory_userip_acl is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with squid_edir_iplookup. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ********************************************************************************
21 *
22 * ext_edirectory_userip_acl.cc -- Rev 2011-03-28
23 *
24 * - Misc code cleanups using "static", and 64-bit SLES fix for SearchFilterLDAP()
25 *
26 */
27
28 /* Squid-3.X includes */
29 #include "squid.h"
30 #include "helpers/defines.h"
31 #include "rfc1738.h"
32 #include "util.h"
33
34 #define EDUI_PROGRAM_NAME "ext_edirectory_userip_acl"
35 #define EDUI_PROGRAM_VERSION "2.1"
36
37 /* System includes */
38 #ifdef HAVE_STDIO_H
39 #include <stdio.h>
40 #endif
41 #ifndef _GNU_SOURCE
42 #define _GNU_SOURCE
43 #endif
44 #ifndef __USE_GNU
45 #define __USE_GNU
46 #endif
47 #ifdef HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif
50 #ifdef HAVE_STRING_H
51 #include <string.h>
52 #endif
53 #ifdef HAVE_CTYPE_H
54 #include <ctype.h>
55 #endif
56 #ifdef HAVE_ERRNO_H
57 #include <errno.h>
58 #endif
59 #ifdef HAVE_SIGNAL_H
60 #include <signal.h>
61 #endif
62 #ifdef HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
64 #endif
65 #define LDAP_DEPRECATED 1 /* Set flag for enabling classic ldap functions */
66 #ifdef HAVE_LBER_H
67 #include <lber.h>
68 #endif
69 #ifdef HAVE_LDAP_H
70 #include <ldap.h>
71 #endif
72 #ifdef HAVE_STDARG_H
73 #include <stdarg.h>
74 #endif
75 #ifdef HAVE_TIME_H
76 #include <time.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 initalized */
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", NULL };
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 == NULL) {
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: %zd\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 == NULL) || (Out_Str == NULL))
263 return (-1);
264
265 size_t In_Len = strlen(In_Str) + 1;
266
267 // find the char delimiter position...
268 char *p = In_Str;
269 while (*p != chr && *p != '\0' && (In_Str+In_Len) > p) {
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 == NULL) || (Out_Obj == NULL))
315 return (-1);
316
317 char *in = static_cast<char*>(In_Obj);
318 char *out = static_cast<char*>(Out_Obj);
319
320 // find the char delimiter position...
321 char *p = static_cast<char*>(In_Obj);
322 while (*p != chr && (in+In_Sz) > p) {
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 /* Initalizes program's configuration paremeters */
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 /* Set defaults from compile-time-options, if provided, but depriciated. */
412 #ifdef EDUI_BASE_DN
413 xstrncpy(edui_conf.basedn, EDUI_BASE_DN, sizeof(edui_conf.basedn));
414 #endif
415 #ifdef EDUI_DEFAULT_HOST
416 xstrncpy(edui_conf.host, EDUI_DEFAULT_HOST, sizeof(edui_conf.host));
417 #endif
418 #ifdef EDUI_BIND_DN
419 xstrncpy(edui_conf.dn, EDUI_BIND_DN, sizeof(edui_conf.dn));
420 #endif
421 #ifdef EDUI_BIND_PASS
422 xstrncpy(edui_conf.passwd, EDUI_BIND_PASS, sizeof(edui_conf.passwd));
423 #endif
424 #ifdef EDUI_USER_ATTRIB
425 xstrncpy(edui_conf.attrib, EDUI_USER_ATTRIB, sizeof(edui_conf.attrib));
426 #endif
427 #ifdef EDUI_SEARCH_FILTER
428 xstrncpy(edui_conf.search_filter, EDUI_SEARCH_FILTER, sizeof(edui_conf.search_filter));
429 #endif
430 #ifdef EDUI_SEARCH_SCOPE
431 if (!strcmp(EDUI_SEARCH_SCOPE, "base"))
432 edui_conf.scope = 0;
433 else if (!strcmp(EDUI_SEARCH_SCOPE, "one"))
434 edui_conf.scope = 1;
435 else if (!strcmp(EDUI_SEARCH_SCOPE, "sub"))
436 edui_conf.scope = 2;
437 else
438 edui_conf.scope = 1;
439 #endif
440 #ifdef EDUI_LDAP_VERSION
441 edui_conf.ver = EDUI_LDAP_VERSION;
442 #endif
443 #ifdef EDUI_DEFAULT_PORT
444 edui_conf.port = EDUI_DEFAULT_PORT;
445 #endif
446 #ifdef EDUI_FORCE_IPV4
447 edui_conf.mode |= EDUI_MODE_IPV4;
448 #endif
449 #ifdef EDUI_FORCE_IPV6
450 edui_conf.mode |= EDUI_MODE_IPV6;
451 #endif
452 #ifdef EDUI_USE_TLS
453 edui_conf.mode |= EDUI_MODE_TLS;
454 #endif
455 #ifdef EDUI_USE_PERSIST
456 edui_conf.mode |= EDUI_MODE_PERSIST;
457 #endif
458 #ifdef EDUI_PERSIST_TIMEOUT
459 edui_conf.persist_timeout = EDUI_PERSIST_TIMEOUT;
460 #endif
461 #ifdef EDUI_GROUP_REQUIRED
462 edui_conf.mode |= EDUI_MODE_GROUP;
463 #endif
464 #ifdef EDUI_DEBUG
465 edui_conf.mode |= EDUI_MODE_DEBUG;
466 #endif
467 }
468
469 /* Displays running configuration */
470 static void
471 DisplayConf()
472 {
473 if (!(edui_conf.mode & EDUI_MODE_DEBUG))
474 return;
475 DisplayVersion();
476 local_printfx("\n");
477 local_printfx("Configuration:\n");
478 local_printfx(" EDUI_MAXLEN: %zd\n", EDUI_MAXLEN);
479 if (edui_conf.mode & EDUI_MODE_DEBUG)
480 local_printfx(" Debug mode: ON\n");
481 else
482 local_printfx(" Debug mode: OFF\n");
483 if (edui_conf.mode & EDUI_MODE_IPV4)
484 local_printfx(" Address format: IPv4 (127.0.0.1)\n");
485 else if (edui_conf.mode & EDUI_MODE_IPV6)
486 local_printfx(" Address format: IPv6 (::1)\n");
487 else
488 local_printfx(" Address format: Not enforced.\n");
489 if (edui_conf.host[0] != '\0')
490 local_printfx(" Hostname: %s\n", edui_conf.host);
491 else
492 local_printfx(" Hostname: localhost\n");
493 if (edui_conf.port > 0)
494 local_printfx(" Port: %d\n", edui_conf.port);
495 else
496 local_printfx(" Port: %d\n", LDAP_PORT);
497 if (edui_conf.mode & EDUI_MODE_TLS)
498 local_printfx(" TLS mode: ON\n");
499 else
500 local_printfx(" TLS mode: OFF\n");
501 if (edui_conf.mode & EDUI_MODE_PERSIST) {
502 local_printfx(" Persistent mode: ON\n");
503 if (edui_conf.persist_timeout > 0)
504 local_printfx(" Persistent mode idle timeout: %d\n", edui_conf.persist_timeout);
505 else
506 local_printfx(" Persistent mode idle timeout: OFF\n");
507 } else
508 local_printfx(" Persistent mode: OFF\n");
509 local_printfx(" LDAP Version: %d\n", edui_conf.ver);
510 if (edui_conf.basedn[0] != '\0')
511 local_printfx(" Base DN: %s\n", edui_conf.basedn);
512 else
513 local_printfx(" Base DN: None\n");
514 if (edui_conf.dn[0] != '\0')
515 local_printfx(" Binding DN: %s\n", edui_conf.dn);
516 else
517 local_printfx(" Binding DN: Anonymous\n");
518 if (edui_conf.passwd[0] != '\0')
519 local_printfx(" Binding Password: %s\n", edui_conf.passwd);
520 else
521 local_printfx(" Binding Password: None\n");
522 switch (edui_conf.scope) {
523 case 0:
524 local_printfx(" Search Scope: base\n");
525 break;
526 case 1:
527 local_printfx(" Search Scope: one level\n");
528 break;
529 case 2:
530 local_printfx(" Search Scope: subtree\n");
531 break;
532 default:
533 local_printfx(" Search Scope: base\n");
534 break;
535 }
536 if (edui_conf.attrib[0] != '\0')
537 local_printfx(" Search Attribute: %s\n", edui_conf.attrib);
538 else
539 local_printfx(" Search Attribute: cn\n");
540 if (edui_conf.search_filter[0] != '\0')
541 local_printfx(" Search Filter: %s\n", edui_conf.search_filter);
542 else
543 local_printfx(" Search Filter: (&(objectClass=User)(networkAddress=*))\n");
544 if (edui_conf.mode & EDUI_MODE_GROUP)
545 local_printfx(" Search Group Required: Yes\n");
546 else
547 local_printfx(" Search Group Required: No\n");
548 local_printfx("\n");
549 }
550
551 /* InitLDAP() - <edui_ldap_t>
552 *
553 * Initalize LDAP structure for use, zeroing out all variables.
554 *
555 */
556 static void
557 InitLDAP(edui_ldap_t *l)
558 {
559 if (l == NULL) return;
560
561 l->lp = NULL;
562 if (l->lm != NULL)
563 ldap_msgfree(l->lm);
564 if (l->val != NULL)
565 ldap_value_free_len(l->val);
566 l->lm = NULL;
567 l->val = NULL;
568 *(l->basedn) = '\0';
569 *(l->host) = '\0';
570 *(l->dn) = '\0';
571 *(l->passwd) = '\0';
572 *(l->search_filter) = '\0';
573 *(l->userid) = '\0';
574 memset(l->search_ip, '\0', sizeof(l->search_ip));
575 l->status = 0;
576 l->status |= LDAP_INIT_S;
577 l->port = 0;
578 l->scope = -1;
579 l->type = 0;
580 l->err = -1; /* Set error to LDAP_SUCCESS by default */
581 l->ver = 0;
582 l->idle_time = 0;
583 l->num_ent = 0; /* Number of entries in l->lm */
584 l->num_val = 0; /* Number of entries in l->val */
585
586 /* Set default settings from conf */
587 if (edui_conf.basedn[0] != '\0')
588 xstrncpy(l->basedn, edui_conf.basedn, sizeof(l->basedn));
589 if (edui_conf.host[0] != '\0')
590 xstrncpy(l->host, edui_conf.host, sizeof(l->host));
591 if (edui_conf.port != 0)
592 l->port = edui_conf.port;
593 if (edui_conf.dn[0] != '\0')
594 xstrncpy(l->dn, edui_conf.dn, sizeof(l->dn));
595 if (edui_conf.passwd[0] != '\0')
596 xstrncpy(l->passwd, edui_conf.passwd, sizeof(l->passwd));
597 if (edui_conf.search_filter[0] != '\0')
598 xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter));
599 if (!(edui_conf.scope < 0))
600 l->scope = edui_conf.scope;
601 }
602
603 /* OpenLDAP() - <edui_ldap_t> <host> <port>
604 *
605 * Build LDAP struct with hostname and port, and ready it for binding.
606 *
607 */
608 static int
609 OpenLDAP(edui_ldap_t *l, char *h, unsigned int p)
610 {
611 if ((l == NULL) || (h == NULL)) return LDAP_ERR_NULL;
612 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized, or might be in use */
613 if (l->status & LDAP_OPEN_S) return LDAP_ERR_OPEN; /* Already open */
614 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
615
616 xstrncpy(l->host, h, sizeof(l->host));
617 if (p > 0)
618 l->port = p;
619 else
620 l->port = LDAP_PORT; /* Default is port 389 */
621
622 #ifdef NETSCAPE_SSL
623 if (l->port == LDAPS_PORT)
624 l->status |= (LDAP_SSL_S | LDAP_TLS_S); /* SSL Port: 636 */
625 #endif
626
627 #ifdef USE_LDAP_INIT
628 l->lp = ldap_init(l->host, l->port);
629 #else
630 l->lp = ldap_open(l->host, l->port);
631 #endif
632 if (l->lp == NULL) {
633 l->err = LDAP_CONNECT_ERROR;
634 return LDAP_ERR_CONNECT; /* Unable to connect */
635 } else {
636 /* set status */
637 // l->status &= ~(LDAP_INIT_S);
638 l->status |= LDAP_OPEN_S;
639 l->err = LDAP_SUCCESS;
640 return LDAP_ERR_SUCCESS;
641 }
642 }
643
644 /* CloseLDAP() - <edui_ldap_t>
645 *
646 * Close LDAP connection, and clean up data structure.
647 *
648 */
649 static int
650 CloseLDAP(edui_ldap_t *l)
651 {
652 int s;
653 if (l == NULL) return LDAP_ERR_NULL;
654 if (l->lp == NULL) return LDAP_ERR_NULL;
655 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Connection not initalized */
656 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Connection not open */
657
658 if (l->lm != NULL) {
659 ldap_msgfree(l->lm);
660 l->lm = NULL;
661 }
662 if (l->val != NULL) {
663 ldap_value_free_len(l->val);
664 l->val = NULL;
665 }
666
667 /* okay, so it's open, close it - No need to check other criteria */
668 s = ldap_unbind(l->lp);
669 if (s == LDAP_SUCCESS) {
670 l->status = LDAP_INIT_S;
671 l->idle_time = 0;
672 l->err = s; /* Set LDAP error code */
673 return LDAP_ERR_SUCCESS;
674 } else {
675 l->err = s; /* Set LDAP error code */
676 return LDAP_ERR_FAILED;
677 }
678 }
679
680 /* SetVerLDAP() - <edui_ldap_t> <version>
681 *
682 * Set LDAP version number for connection to <version> of 1, 2, or 3
683 *
684 */
685 static int
686 SetVerLDAP(edui_ldap_t *l, int v)
687 {
688 int x;
689 if (l == NULL) return LDAP_ERR_NULL;
690 if ((v > 3) || (v < 1)) return LDAP_ERR_PARAM;
691 if (l->lp == NULL) return LDAP_ERR_POINTER;
692 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
693 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
694 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
695
696 /* set version */
697 x = ldap_set_option(l->lp, LDAP_OPT_PROTOCOL_VERSION, &v);
698 if (x == LDAP_SUCCESS) {
699 l->ver = v;
700 l->err = x; /* Set LDAP error code */
701 return LDAP_ERR_SUCCESS;
702 } else {
703 l->err = x; /* Set LDAP error code */
704 return LDAP_ERR_FAILED;
705 }
706 }
707
708 /* BindLDAP() - <edui_ldap_t> <use-dn> <use-password> <type>
709 *
710 * Bind LDAP connection (Open) using optional dn and password, of <type>
711 *
712 */
713 static int
714 BindLDAP(edui_ldap_t *l, char *dn, char *pw, unsigned int t)
715 {
716 int s;
717 if (l == NULL) return LDAP_ERR_NULL;
718 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
719 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
720 if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */
721 if (l->lp == NULL) return LDAP_ERR_POINTER; /* Error */
722
723 /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */
724 if (dn != NULL) {
725 if ((l->basedn[0] != '\0') && (strstr(dn, l->basedn) == NULL)) {
726 /* We got a basedn, but it's not part of dn */
727 xstrncpy(l->dn, dn, sizeof(l->dn));
728 strncat(l->dn, ",", 1);
729 strncat(l->dn, l->basedn, strlen(l->basedn));
730 } else
731 xstrncpy(l->dn, dn, sizeof(l->dn));
732 }
733 if (pw != NULL)
734 xstrncpy(l->passwd, pw, sizeof(l->passwd));
735
736 /* Type */
737 switch (t) {
738 case LDAP_AUTH_NONE:
739 l->type = t;
740 break;
741 case LDAP_AUTH_SIMPLE:
742 l->type = t;
743 break;
744 case LDAP_AUTH_SASL:
745 l->type = t;
746 break;
747 #ifdef LDAP_AUTH_KRBV4
748 case LDAP_AUTH_KRBV4:
749 l->type = t;
750 break;
751 #endif
752 #ifdef LDAP_AUTH_KRBV41
753 case LDAP_AUTH_KRBV41:
754 l->type = t;
755 break;
756 #endif
757 #ifdef LDAP_AUTH_KRBV42
758 case LDAP_AUTH_KRBV42:
759 l->type = t;
760 break;
761 #endif
762 #ifdef LDAP_AUTH_TLS
763 case LDAP_AUTH_TLS: /* Added for chicken switch to TLS-enabled without using SSL */
764 l->type = t;
765 break;
766 #endif
767 default:
768 l->type = LDAP_AUTH_NONE;
769 break; /* Default to anonymous bind */
770 }
771
772 /* Bind */
773 #if defined(LDAP_AUTH_TLS) && defined(NETSCAPE_SSL) && HAVE_LDAP_START_TLS_S
774 if (l->type == LDAP_AUTH_TLS)
775 s = ldap_start_tls_s(l->lp, NULL, NULL);
776 else
777 #endif
778 s = ldap_bind_s(l->lp, l->dn, l->passwd, l->type);
779 if (s == LDAP_SUCCESS) {
780 l->status |= LDAP_BIND_S; /* Success */
781 l->err = s; /* Set LDAP error code */
782 return LDAP_ERR_SUCCESS;
783 } else {
784 l->err = s; /* Set LDAP error code */
785 return LDAP_ERR_FAILED;
786 }
787 }
788
789 /*
790 * ConvertIP() - <edui_ldap_t> <ip>
791 *
792 * Take an IPv4 address in dot-decimal or IPv6 notation, and convert to 2-digit HEX stored in l->search_ip
793 * This is the networkAddress that we search LDAP for.
794 *
795 * PENDING -- CHANGE OVER TO inet*_pton, but inet6_pton does not provide the correct syntax
796 *
797 */
798 static int
799 ConvertIP(edui_ldap_t *l, char *ip)
800 {
801 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], obj[EDUI_MAXLEN];
802 char hexc[4], *p;
803 void *y, *z;
804 size_t s;
805 long x;
806 int i, j, t, swi; /* IPv6 "::" cut over toggle */
807 if (l == NULL) return LDAP_ERR_NULL;
808 if (ip == NULL) return LDAP_ERR_PARAM;
809 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
810 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
811 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
812
813 y = memchr((void *)ip, ':', EDUI_MAXLEN);
814 z = memchr((void *)ip, '.', EDUI_MAXLEN);
815 if ((y != NULL) && (z != NULL)) {
816 y = NULL;
817 z = NULL;
818 return LDAP_ERR_INVALID;
819 }
820 if ((y != NULL) && (edui_conf.mode & EDUI_MODE_IPV4)) {
821 /* IPv4 Mode forced */
822 return LDAP_ERR_INVALID;
823 } else if (y != NULL) {
824 /* Set IPv6 mode */
825 if (l->status & LDAP_IPV4_S)
826 l->status &= ~(LDAP_IPV4_S);
827 if (!(l->status & LDAP_IPV6_S))
828 l->status |= (LDAP_IPV6_S);
829 y = NULL;
830 }
831 if ((z != NULL) && (edui_conf.mode & EDUI_MODE_IPV6)) {
832 /* IPv6 Mode forced */
833 return LDAP_ERR_INVALID;
834 } else if (z != NULL) {
835 /* Set IPv4 mode */
836 if (l->status & LDAP_IPV6_S)
837 l->status &= ~(LDAP_IPV6_S);
838 if (!(l->status & LDAP_IPV4_S))
839 l->status |= (LDAP_IPV4_S);
840 z = NULL;
841 }
842 s = strlen(ip);
843 *(bufa) = '\0';
844 *(bufb) = '\0';
845 *(obj) = '\0';
846 /* StringSplit() will zero out bufa & obj at each call */
847 memset(l->search_ip, '\0', sizeof(l->search_ip));
848 xstrncpy(bufa, ip, sizeof(bufa)); /* To avoid segfaults, use bufa instead of ip */
849 swi = 0;
850 if (l->status & LDAP_IPV6_S) {
851 /* Search for :: in string */
852 if ((bufa[0] == ':') && (bufa[1] == ':')) {
853 /* bufa starts with a ::, so just copy and clear */
854 xstrncpy(bufb, bufa, sizeof(bufb));
855 *(bufa) = '\0';
856 swi++; /* Indicates that there is a bufb */
857 } else if ((bufa[0] == ':') && (bufa[1] != ':')) {
858 /* bufa starts with a :, a typo so just fill in a ':', cat and clear */
859 bufb[0] = ':';
860 strncat(bufb, bufa, strlen(bufa));
861 *(bufa) = '\0';
862 swi++; /* Indicates that there is a bufb */
863 } else {
864 p = strstr(bufa, "::");
865 if (p != NULL) {
866 /* Found it, break bufa down and split into bufb here */
867 *(bufb) = '\0';
868 i = strlen(p);
869 memcpy(bufb, p, i);
870 *p = '\0';
871 bufb[i] = '\0';
872 swi++; /* Indicates that there is a bufb */
873 }
874 }
875 }
876 s = strlen(bufa);
877 if (s < 1)
878 s = strlen(bufb);
879 while (s > 0) {
880 if ((l->status & LDAP_IPV4_S) && (swi == 0)) {
881 /* Break down IPv4 address */
882 t = StringSplit(bufa, '.', obj, sizeof(obj));
883 if (t > 0) {
884 errno = 0;
885 x = strtol(obj, (char **)NULL, 10);
886 if (((x < 0) || (x > 255)) || ((errno != 0) && (x == 0)) || ((obj[0] != '0') && (x == 0)))
887 return LDAP_ERR_OOB; /* Out of bounds -- Invalid address */
888 memset(hexc, '\0', sizeof(hexc));
889 int hlen = snprintf(hexc, sizeof(hexc), "%02X", (int)x);
890 strncat(l->search_ip, hexc, hlen);
891 } else
892 break; /* reached end of octet */
893 } else if (l->status & LDAP_IPV6_S) {
894 /* Break down IPv6 address */
895 if (swi > 1)
896 t = StringSplit(bufb, ':', obj, sizeof(obj)); /* After "::" */
897 else
898 t = StringSplit(bufa, ':', obj, sizeof(obj)); /* Before "::" */
899 /* Convert octet by size (t) - and fill 0's */
900 switch (t) { /* IPv6 is already in HEX, copy contents */
901 case 4:
902 hexc[0] = (char) toupper((int)obj[0]);
903 i = (int)hexc[0];
904 if (!isxdigit(i))
905 return LDAP_ERR_OOB; /* Out of bounds */
906 hexc[1] = (char) toupper((int)obj[1]);
907 i = (int)hexc[1];
908 if (!isxdigit(i))
909 return LDAP_ERR_OOB; /* Out of bounds */
910 hexc[2] = '\0';
911 strncat(l->search_ip, hexc, 2);
912 hexc[0] = (char) toupper((int)obj[2]);
913 i = (int)hexc[0];
914 if (!isxdigit(i))
915 return LDAP_ERR_OOB; /* Out of bounds */
916 hexc[1] = (char) toupper((int)obj[3]);
917 i = (int)hexc[1];
918 if (!isxdigit(i))
919 return LDAP_ERR_OOB; /* Out of bounds */
920 hexc[2] = '\0';
921 strncat(l->search_ip, hexc, 2);
922 break;
923 case 3:
924 hexc[0] = '0';
925 hexc[1] = (char) toupper((int)obj[0]);
926 i = (int)hexc[1];
927 if (!isxdigit(i))
928 return LDAP_ERR_OOB; /* Out of bounds */
929 hexc[2] = '\0';
930 strncat(l->search_ip, hexc, 2);
931 hexc[0] = (char) toupper((int)obj[1]);
932 i = (int)hexc[0];
933 if (!isxdigit(i))
934 return LDAP_ERR_OOB; /* Out of bounds */
935 hexc[1] = (char) toupper((int)obj[2]);
936 i = (int)hexc[1];
937 if (!isxdigit(i))
938 return LDAP_ERR_OOB; /* Out of bounds */
939 hexc[2] = '\0';
940 strncat(l->search_ip, hexc, 2);
941 break;
942 case 2:
943 strncat(l->search_ip, "00", 2);
944 hexc[0] = (char) toupper((int)obj[0]);
945 i = (int)hexc[0];
946 if (!isxdigit(i))
947 return LDAP_ERR_OOB; /* Out of bounds */
948 hexc[1] = (char) toupper((int)obj[1]);
949 i = (int)hexc[1];
950 if (!isxdigit(i))
951 return LDAP_ERR_OOB; /* Out of bounds */
952 hexc[2] = '\0';
953 strncat(l->search_ip, hexc, 2);
954 break;
955 case 1:
956 strncat(l->search_ip, "00", 2);
957 hexc[0] = '0';
958 hexc[1] = (char) toupper((int)obj[0]);
959 i = (int)hexc[1];
960 if (!isxdigit(i))
961 return LDAP_ERR_OOB; /* Out of bounds */
962 hexc[2] = '\0';
963 strncat(l->search_ip, hexc, 2);
964 break;
965 default:
966 if (t > 4)
967 return LDAP_ERR_OOB;
968 break;
969 }
970 /* Code to pad the address with 0's between a '::' */
971 if ((strlen(bufa) == 0) && (swi == 1)) {
972 /* We are *AT* the split, pad in some 0000 */
973 t = strlen(bufb);
974 /* How many ':' exist in bufb ? */
975 j = 0;
976 for (i = 0; i < t; i++) {
977 if (bufb[i] == ':')
978 j++;
979 }
980 j--; /* Preceeding "::" doesn't count */
981 t = 8 - (strlen(l->search_ip) / 4) - j; /* Remainder */
982 if (t > 0) {
983 for (i = 0; i < t; i++)
984 strncat(l->search_ip, "0000", 4);
985 }
986 }
987 }
988 if ((bufa[0] == '\0') && (swi > 0)) {
989 s = strlen(bufb);
990 swi++;
991 } else
992 s = strlen(bufa);
993 }
994 s = strlen(l->search_ip);
995
996 /* CHECK sizes of address, truncate or pad */
997 /* if "::" is at end of ip, then pad another block or two */
998 while ((l->status & LDAP_IPV6_S) && (s < 32)) {
999 strncat(l->search_ip, "0000", 4);
1000 s = strlen(l->search_ip);
1001 }
1002 if ((l->status & LDAP_IPV6_S) && (s > 32)) {
1003 /* Too long, truncate */
1004 l->search_ip[32] = '\0';
1005 s = strlen(l->search_ip);
1006 }
1007 /* If at end of ip, and its not long enough, then pad another block or two */
1008 while ((l->status & LDAP_IPV4_S) && (s < 8)) {
1009 strncat(l->search_ip, "00", 2);
1010 s = strlen(l->search_ip);
1011 }
1012 if ((l->status & LDAP_IPV4_S) && (s > 8)) {
1013 /* Too long, truncate */
1014 l->search_ip[8] = '\0';
1015 s = strlen(l->search_ip);
1016 }
1017
1018 /* Completed, s is length of address in HEX */
1019 return s;
1020 }
1021
1022 /* ResetLDAP() - <edui_ldap_t>
1023 *
1024 * Resets LDAP connection for next search query.
1025 *
1026 */
1027 static int
1028 ResetLDAP(edui_ldap_t *l)
1029 {
1030 if (l == NULL) return LDAP_ERR_NULL;
1031 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
1032 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1033 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
1034 if (!(l->status & LDAP_PERSIST_S)) return LDAP_ERR_PERSIST; /* Not persistent */
1035
1036 /* Cleanup data struct */
1037 if (l->status & LDAP_VAL_S)
1038 l->status &= ~(LDAP_VAL_S);
1039 if (l->status & LDAP_SEARCH_S)
1040 l->status &= ~(LDAP_SEARCH_S);
1041 if (l->status & LDAP_IPV4_S)
1042 l->status &= ~(LDAP_IPV4_S);
1043 if (l->status & LDAP_IPV6_S)
1044 l->status &= ~(LDAP_IPV6_S);
1045 if (l->lm != NULL) {
1046 ldap_msgfree(l->lm);
1047 l->lm = NULL;
1048 }
1049 if (l->val != NULL) {
1050 ldap_value_free_len(l->val);
1051 l->val = NULL;
1052 }
1053 memset(l->search_ip, '\0', sizeof(l->search_ip));
1054 *(l->search_filter) = '\0';
1055 xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter));
1056 *(l->userid) = '\0';
1057 if (!(l->status & LDAP_IDLE_S))
1058 l->status |= LDAP_IDLE_S; /* Set idle mode */
1059 l->num_ent = 0;
1060 l->num_val = 0;
1061 l->err = LDAP_SUCCESS;
1062 return LDAP_ERR_SUCCESS;
1063 }
1064
1065 /*
1066 * SearchFilterLDAP() - <edui_ldap_t> <IP> <group>
1067 *
1068 * Build LDAP Search Filter string and copy to l->search_filter
1069 *
1070 */
1071 static int
1072 SearchFilterLDAP(edui_ldap_t *l, char *group)
1073 {
1074 size_t i, j, s;
1075 int swi;
1076 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], bufc[EDUI_MAXLEN], bufd[EDUI_MAXLEN], bufg[EDUI_MAXLEN];
1077 if (l == NULL) return LDAP_ERR_NULL;
1078 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
1079 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1080 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not Bound */
1081 if (l->search_ip[0] == '\0') return LDAP_ERR_DATA; /* Search IP is required */
1082
1083 /* Zero out if not already */
1084 memset(bufa, '\0', sizeof(bufa));
1085 // using memset() for 'bufa' fixes the 64-bit issue
1086 *(bufb) = '\0';
1087 *(bufc) = '\0';
1088 *(bufd) = '\0';
1089 *(bufg) = '\0';
1090
1091 s = strlen(l->search_ip);
1092 bufc[0] = '\134';
1093 swi = 0;
1094 j = 1;
1095 for (i = 0; i < s; i++) {
1096 if (swi == 2) {
1097 bufc[j] = '\134';
1098 j++;
1099 bufc[j] = l->search_ip[i];
1100 j++;
1101 swi = 1;
1102 } else {
1103 bufc[j] = l->search_ip[i];
1104 j++;
1105 swi++;
1106 }
1107 }
1108 if (group == NULL) {
1109 /* No groupMembership= to add, yay! */
1110 xstrncpy(bufa, "(&", sizeof(bufa));
1111 strncat(bufa, edui_conf.search_filter, strlen(edui_conf.search_filter));
1112 /* networkAddress */
1113 snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)", bufc);
1114 if (l->status & LDAP_IPV4_S) {
1115 int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
1116 bufc, bufc);
1117 strncat(bufb, bufd, ln);
1118 } else if (l->status & LDAP_IPV6_S) {
1119 int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
1120 bufc, bufc);
1121 strncat(bufb, bufd, ln);
1122 } else
1123 strncat(bufb, ")", 1);
1124 strncat(bufa, bufb, strlen(bufb));
1125 strncat(bufa, ")", 1);
1126 } else {
1127 /* Needs groupMembership= to add... */
1128 xstrncpy(bufa, "(&(&", sizeof(bufa));
1129 strncat(bufa, edui_conf.search_filter, strlen(edui_conf.search_filter));
1130 /* groupMembership -- NOTE: Squid *MUST* provide "cn=" from squid.conf */
1131 snprintf(bufg, sizeof(bufg), "(groupMembership=%s", group);
1132 if ((l->basedn[0] != '\0') && (strstr(group, l->basedn) == NULL)) {
1133 strncat(bufg, ",", 1);
1134 strncat(bufg, l->basedn, strlen(l->basedn));
1135 }
1136 strncat(bufg, ")", 1);
1137 strncat(bufa, bufg, strlen(bufg));
1138 /* networkAddress */
1139 snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)", bufc);
1140 if (l->status & LDAP_IPV4_S) {
1141 int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
1142 bufc, bufc);
1143 strncat(bufb, bufd, ln);
1144 } else if (l->status & LDAP_IPV6_S) {
1145 int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
1146 bufc, bufc);
1147 strncat(bufb, bufd, ln);
1148 } else
1149 strncat(bufb, ")", 1);
1150 strncat(bufa, bufb, strlen(bufb));
1151 strncat(bufa, "))", 2);
1152 }
1153 s = strlen(bufa);
1154 xstrncpy(l->search_filter, bufa, sizeof(l->search_filter));
1155 return s;
1156 }
1157
1158 /*
1159 * SearchLDAP() - <edui_ldap_t> <scope> <filter> <attrib>
1160 *
1161 * Initate LDAP query, under <scope> levels, filtering matches with <filter> and optionally <attrib>
1162 * <attrib> will generally be networkAddress ...
1163 *
1164 */
1165 static int
1166 SearchLDAP(edui_ldap_t *l, int scope, char *filter, char **attrs)
1167 {
1168 int s;
1169 char ft[EDUI_MAXLEN];
1170 if (l == NULL) return LDAP_ERR_NULL;
1171 if ((scope < 0) || (filter == NULL)) return LDAP_ERR_PARAM; /* If attrs is NULL, then all attrs will return */
1172 if (l->lp == NULL) return LDAP_ERR_POINTER;
1173 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
1174 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1175 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
1176 if (l->status & LDAP_SEARCH_S) return LDAP_ERR_SEARCHED; /* Already searching */
1177 if (l->basedn[0] == '\0') return LDAP_ERR_DATA; /* We require a basedn */
1178 if (l->lm != NULL)
1179 ldap_msgfree(l->lm); /* Make sure l->lm is empty */
1180
1181 if (filter == NULL) /* if filter is NULL, then return ALL networkAddress */
1182 xstrncpy(ft, "(&(objectClass=User)(networkAddress=*))", sizeof(ft));
1183 else
1184 xstrncpy(ft, filter, sizeof(ft));
1185
1186 /* We have a binded connection, with a free l->lm, so let's get this done */
1187 switch (scope) {
1188 case 0:
1189 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_BASE, ft, attrs, 0, &(l->lm));
1190 break;
1191 case 1:
1192 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm));
1193 break;
1194 case 2:
1195 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_SUBTREE, ft, attrs, 0, &(l->lm));
1196 break;
1197 default:
1198 /* Only search ONE by default */
1199 s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm));
1200 break;
1201 }
1202 if (s == LDAP_SUCCESS) {
1203 l->status |= (LDAP_SEARCH_S); /* Mark as searched */
1204 l->err = s;
1205 l->idle_time = 0; /* Connection in use, reset idle timer */
1206 l->num_ent = ldap_count_entries(l->lp, l->lm); /* Counted */
1207 return LDAP_ERR_SUCCESS;
1208 } else {
1209 l->err = s;
1210 l->num_ent = (-1);
1211 return LDAP_ERR_FAILED;
1212 }
1213 }
1214
1215 /*
1216 * SearchIPLDAP() - <edui_ldap_t>
1217 *
1218 * Scan LDAP and get all networkAddress Values, and see if they match l->search_ip
1219 * Actual IP matching routine for eDirectory
1220 *
1221 */
1222 static int
1223 SearchIPLDAP(edui_ldap_t *l)
1224 {
1225 ber_len_t i, x;
1226 ber_len_t j, k;
1227 ber_len_t y, z;
1228 int c;
1229 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], hexc[4];
1230 LDAPMessage *ent;
1231 if (l == NULL) return LDAP_ERR_NULL;
1232 if (l->lp == NULL) return LDAP_ERR_POINTER;
1233 if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initalized */
1234 if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */
1235 if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */
1236 if (!(l->status & LDAP_SEARCH_S)) return LDAP_ERR_NOT_SEARCHED; /* Not searched */
1237 if (l->num_ent <= 0) {
1238 debug("l->num_ent: %d\n", l->num_ent);
1239 return LDAP_ERR_DATA; /* No entries found */
1240 }
1241 if (l->val != NULL)
1242 ldap_value_free_len(l->val); /* Clear data before populating */
1243 l->num_val = 0;
1244 if (l->status & LDAP_VAL_S)
1245 l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */
1246 if (edui_conf.attrib[0] == '\0')
1247 xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); /* Make sure edui_conf.attrib is set */
1248
1249 /* Sift through entries */
1250 struct berval **ber = NULL;
1251 for (ent = ldap_first_entry(l->lp, l->lm); ent != NULL; ent = ldap_next_entry(l->lp, ent)) {
1252 l->val = ldap_get_values_len(l->lp, ent, "networkAddress");
1253 ber = ldap_get_values_len(l->lp, ent, edui_conf.attrib); /* edui_conf.attrib is the <userid> mapping */
1254 if (l->val != NULL) {
1255 x = ldap_count_values_len(l->val); /* We got x values ... */
1256 l->num_val = x;
1257 if (x > 0) {
1258 /* Display all values */
1259 for (i = 0; i < x; i++) {
1260 j = l->val[i]->bv_len;
1261 memcpy(bufa, l->val[i]->bv_val, j);
1262 z = BinarySplit(bufa, j, '#', bufb, sizeof(bufb));
1263 /* BINARY DEBUGGING *
1264 local_printfx("value[%zd]: BinarySplit(", (size_t) i);
1265 for (k = 0; k < z; k++) {
1266 c = (int) bufb[k];
1267 if (c < 0)
1268 c = c + 256;
1269 local_printfx("%02X", c);
1270 }
1271 local_printfx(", ");
1272 for (k = 0; k < (j - z - 1); k++) {
1273 c = (int) bufa[k];
1274 if (c < 0)
1275 c = c + 256;
1276 local_printfx("%02X", c);
1277 }
1278 local_printfx("): %zd\n", (size_t) z);
1279 * BINARY DEBUGGING */
1280 z = j - z - 1;
1281 j = atoi(bufb);
1282 if (j == 1) {
1283 /* IPv4 address (eDirectory 8.7 and below) */
1284 /* bufa is the address, just compare it */
1285 if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S))
1286 break; /* Not looking for IPv4 */
1287 for (k = 0; k < z; k++) {
1288 c = (int) bufa[k];
1289 if (c < 0)
1290 c = c + 256;
1291 int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
1292 if (k == 0)
1293 xstrncpy(bufb, hexc, sizeof(bufb));
1294 else
1295 strncat(bufb, hexc, hlen);
1296 }
1297 y = strlen(bufb);
1298 /* Compare value with IP */
1299 if (memcmp(l->search_ip, bufb, y) == 0) {
1300 /* We got a match! - Scan 'ber' for 'cn' values */
1301 z = ldap_count_values_len(ber);
1302 for (j = 0; j < z; j++) {
1303 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1304 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
1305 /* Using bv_len of min() breaks the result by 2 chars */
1306 }
1307 ldap_value_free_len(l->val);
1308 l->val = NULL;
1309 ldap_value_free_len(ber);
1310 ber = NULL;
1311 l->num_val = 0;
1312 l->err = LDAP_SUCCESS;
1313 l->status &= ~(LDAP_SEARCH_S);
1314 return LDAP_ERR_SUCCESS; /* We got our userid */
1315 }
1316 /* Not matched, continue */
1317 } else if ((j == 8) || (j == 9)) {
1318 /* IPv4 (UDP/TCP) address (eDirectory 8.8 and higher) */
1319 /* bufa + 2 is the address (skip 2 digit port) */
1320 if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S))
1321 break; /* Not looking for IPv4 */
1322 for (k = 2; k < z; k++) {
1323 c = (int) bufa[k];
1324 if (c < 0)
1325 c = c + 256;
1326 int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
1327 if (k == 2)
1328 xstrncpy(bufb, hexc, sizeof(bufb));
1329 else
1330 strncat(bufb, hexc, hlen);
1331 }
1332 y = strlen(bufb);
1333 /* Compare value with IP */
1334 if (memcmp(l->search_ip, bufb, y) == 0) {
1335 /* We got a match! - Scan 'ber' for 'cn' values */
1336 z = ldap_count_values_len(ber);
1337 for (j = 0; j < z; j++) {
1338 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1339 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
1340 /* Using bv_len of min() breaks the result by 2 chars */
1341 }
1342 ldap_value_free_len(l->val);
1343 l->val = NULL;
1344 ldap_value_free_len(ber);
1345 ber = NULL;
1346 l->num_val = 0;
1347 l->err = LDAP_SUCCESS;
1348 l->status &= ~(LDAP_SEARCH_S);
1349 return LDAP_ERR_SUCCESS; /* We got our userid */
1350 }
1351 /* Not matched, continue */
1352 } else if ((j == 10) || (j == 11)) {
1353 /* IPv6 (UDP/TCP) address (eDirectory 8.8 and higher) */
1354 /* bufa + 2 is the address (skip 2 digit port) */
1355 if (!(l->status & LDAP_IPV6_S))
1356 break; /* Not looking for IPv6 */
1357 for (k = 2; k < z; k++) {
1358 c = (int) bufa[k];
1359 if (c < 0)
1360 c = c + 256;
1361 int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
1362 if (k == 2)
1363 xstrncpy(bufb, hexc, sizeof(bufb));
1364 else
1365 strncat(bufb, hexc, hlen);
1366 }
1367 y = strlen(bufb);
1368 /* Compare value with IP */
1369 if (memcmp(l->search_ip, bufb, y) == 0) {
1370 /* We got a match! - Scan 'ber' for 'cn' values */
1371 z = ldap_count_values_len(ber);
1372 for (j = 0; j < z; j++) {
1373 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1374 xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid));
1375 /* Using bv_len of min() breaks the result by 2 chars */
1376 }
1377 ldap_value_free_len(l->val);
1378 l->val = NULL;
1379 ldap_value_free_len(ber);
1380 ber = NULL;
1381 l->num_val = 0;
1382 l->err = LDAP_SUCCESS;
1383 l->status &= ~(LDAP_SEARCH_S);
1384 return LDAP_ERR_SUCCESS; /* We got our userid */
1385 }
1386 /* Not matched, continue */
1387 }
1388 // else {
1389 /* Others are unsupported */
1390 // }
1391 }
1392 if (ber != NULL) {
1393 ldap_value_free_len(ber);
1394 ber = NULL;
1395 }
1396 }
1397 ldap_value_free_len(l->val);
1398 l->val = NULL;
1399 }
1400 if (ber != NULL) {
1401 ldap_value_free_len(ber);
1402 ber = NULL;
1403 }
1404 /* Attr not found, continue */
1405 }
1406 /* No entries found using given attr */
1407 if (l->val != NULL) {
1408 ldap_value_free_len(l->val);
1409 l->val = NULL;
1410 }
1411 if (ber != NULL) {
1412 ldap_value_free_len(ber);
1413 ber = NULL;
1414 }
1415 if (ent != NULL) {
1416 ldap_msgfree(ent);
1417 ent = NULL;
1418 }
1419 if (l->lm != NULL) {
1420 ldap_msgfree(l->lm);
1421 l->lm = NULL;
1422 }
1423 l->num_ent = 0;
1424 l->num_val = 0;
1425 l->err = LDAP_NO_SUCH_OBJECT;
1426 l->status &= ~(LDAP_SEARCH_S);
1427 return LDAP_ERR_NOTFOUND; /* Not found ... Sorry :) */
1428 }
1429
1430 /*
1431 * ErrLDAP() - <errno>
1432 *
1433 * Returns error description of error code
1434 *
1435 */
1436 const char
1437 *ErrLDAP(int e)
1438 {
1439 switch (e) {
1440 case LDAP_ERR_NULL:
1441 return "Null pointer provided";
1442 case LDAP_ERR_POINTER:
1443 return "Null LDAP pointer";
1444 case LDAP_ERR_PARAM:
1445 return "Null or Missing paremeter(s)";
1446 case LDAP_ERR_INIT:
1447 return "LDAP data not initalized";
1448 case LDAP_ERR_OPEN:
1449 return "LDAP connection is not active";
1450 case LDAP_ERR_CONNECT:
1451 return "Unable to connect to LDAP host";
1452 case LDAP_ERR_BIND:
1453 return "LDAP connection is not bound";
1454 case LDAP_ERR_SEARCHED:
1455 return "LDAP connection has already been searched";
1456 case LDAP_ERR_NOT_SEARCHED:
1457 return "LDAP connection has not been searched";
1458 case LDAP_ERR_INVALID:
1459 return "Invalid paremeters";
1460 case LDAP_ERR_OOB:
1461 return "Paremeter is out of bounds";
1462 case LDAP_ERR_PERSIST:
1463 return "Persistent mode is not active";
1464 case LDAP_ERR_DATA:
1465 return "Required data has not been found";
1466 case LDAP_ERR_NOTFOUND:
1467 return "Item or object has not been found";
1468 case LDAP_ERR_OTHER:
1469 return "An unknown error has occured";
1470 case LDAP_ERR_FAILED:
1471 return "Operation has failed";
1472 case LDAP_ERR_SUCCESS:
1473 return "Operation is successful";
1474 default:
1475 return "An unknown error has occured";
1476 }
1477 }
1478
1479 /*
1480 * SigTrap() - <signal>
1481 *
1482 * Traps signal codes by number, and gracefully shuts down.
1483 *
1484 */
1485 extern "C" void
1486 SigTrap(int s)
1487 {
1488 if (!(edui_conf.mode & EDUI_MODE_KILL))
1489 edui_conf.mode |= EDUI_MODE_KILL;
1490
1491 /* Clean Up */
1492 if (edui_ldap.status & LDAP_OPEN_S)
1493 CloseLDAP(&edui_ldap);
1494
1495 debug("Terminating, Signal: %d\n", s);
1496 exit(0);
1497 }
1498
1499 /*
1500 * MainSafe() - <argc> <argv>
1501 *
1502 * "Safe" version of main()
1503 *
1504 */
1505 static int
1506 MainSafe(int argc, char **argv)
1507 {
1508 char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], *p = NULL;
1509 char bufc[EDUI_MAXLEN];
1510 char sfmod[EDUI_MAXLEN];
1511 int x;
1512 size_t i, j, s, k;
1513 time_t t;
1514 struct sigaction sv;
1515
1516 /* Init */
1517 k = (size_t) argc;
1518 memset(bufa, '\0', sizeof(bufa));
1519 memset(bufb, '\0', sizeof(bufb));
1520 memset(bufc, '\0', sizeof(bufc));
1521 memset(sfmod, '\0', sizeof(sfmod));
1522
1523 InitConf();
1524 xstrncpy(edui_conf.program, argv[0], sizeof(edui_conf.program));
1525 edui_now = -1;
1526 t = -1;
1527
1528 /* Scan args */
1529 if (k > 1) {
1530 for (i = 1; i < k; i++) {
1531 /* Classic / novelty usage schemes */
1532 if (!strcmp(argv[i], "--help")) {
1533 DisplayUsage();
1534 return 1;
1535 } else if (!strcmp(argv[i], "--usage")) {
1536 DisplayUsage();
1537 return 1;
1538 } else if (!strcmp(argv[i], "--version")) {
1539 DisplayVersion();
1540 return 1;
1541 } else if (argv[i][0] == '-') {
1542 s = strlen(argv[i]);
1543 for (j = 1; j < s; j++) {
1544 switch (argv[i][j]) {
1545 case 'h':
1546 DisplayUsage();
1547 return 1;
1548 case 'V':
1549 DisplayVersion();
1550 return 1;
1551 case 'd':
1552 if (!(edui_conf.mode & EDUI_MODE_DEBUG))
1553 edui_conf.mode |= EDUI_MODE_DEBUG; /* Don't set mode more than once */
1554 debug_enabled = 1; /* Official Squid-3 Debug Mode */
1555 break;
1556 case '4':
1557 if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6))
1558 edui_conf.mode |= EDUI_MODE_IPV4; /* Don't set mode more than once */
1559 break;
1560 case '6':
1561 if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6))
1562 edui_conf.mode |= EDUI_MODE_IPV6; /* Don't set mode more than once */
1563 break;
1564 case 'Z':
1565 if (!(edui_conf.mode & EDUI_MODE_TLS))
1566 edui_conf.mode |= EDUI_MODE_TLS; /* Don't set mode more than once */
1567 break;
1568 case 'P':
1569 if (!(edui_conf.mode & EDUI_MODE_PERSIST))
1570 edui_conf.mode |= EDUI_MODE_PERSIST; /* Don't set mode more than once */
1571 break;
1572 case 'v':
1573 i++; /* Set LDAP version */
1574 if (argv[i] != NULL) {
1575 edui_conf.ver = atoi(argv[i]);
1576 if (edui_conf.ver < 1)
1577 edui_conf.ver = 1;
1578 else if (edui_conf.ver > 3)
1579 edui_conf.ver = 3;
1580 } else {
1581 local_printfx("No parameters given for 'v'.\n");
1582 DisplayUsage();
1583 return 1;
1584 }
1585 break;
1586 case 't':
1587 i++; /* Set Persistent timeout */
1588 if (argv[i] != NULL) {
1589 edui_conf.persist_timeout = atoi(argv[i]);
1590 if (edui_conf.persist_timeout < 0)
1591 edui_conf.persist_timeout = 0;
1592 } else {
1593 local_printfx("No parameters given for 't'.\n");
1594 DisplayUsage();
1595 return 1;
1596 }
1597 break;
1598 case 'b':
1599 i++; /* Set Base DN */
1600 if (argv[i] != NULL)
1601 xstrncpy(edui_conf.basedn, argv[i], sizeof(edui_conf.basedn));
1602 else {
1603 local_printfx("No parameters given for 'b'.\n");
1604 DisplayUsage();
1605 return 1;
1606 }
1607 break;
1608 case 'H':
1609 i++; /* Set Hostname */
1610 if (argv[i] != NULL)
1611 xstrncpy(edui_conf.host, argv[i], sizeof(edui_conf.host));
1612 else {
1613 local_printfx("No parameters given for 'H'.\n");
1614 DisplayUsage();
1615 return 1;
1616 }
1617 break;
1618 case 'p':
1619 i++; /* Set port */
1620 if (argv[i] != NULL)
1621 edui_conf.port = atoi(argv[i]);
1622 else {
1623 local_printfx("No parameters given for 'p'.\n");
1624 DisplayUsage();
1625 return 1;
1626 }
1627 break;
1628 case 'D':
1629 i++; /* Set Bind DN */
1630 if (argv[i] != NULL)
1631 xstrncpy(edui_conf.dn, argv[i], sizeof(edui_conf.dn));
1632 else {
1633 local_printfx("No parameters given for 'D'.\n");
1634 DisplayUsage();
1635 return 1;
1636 }
1637 break;
1638 case 'W':
1639 i++; /* Set Bind PWD */
1640 if (argv[i] != NULL)
1641 xstrncpy(edui_conf.passwd, argv[i], sizeof(edui_conf.passwd));
1642 else {
1643 local_printfx("No parameters given for 'W'.\n");
1644 DisplayUsage();
1645 return 1;
1646 }
1647 break;
1648 case 'F':
1649 i++; /* Set Search Filter */
1650 if (argv[i] != NULL)
1651 xstrncpy(edui_conf.search_filter, argv[i], sizeof(edui_conf.search_filter));
1652 else {
1653 local_printfx("No parameters given for 'F'.\n");
1654 DisplayUsage();
1655 return 1;
1656 }
1657 break;
1658 case 'G':
1659 if (!(edui_conf.mode & EDUI_MODE_GROUP))
1660 edui_conf.mode |= EDUI_MODE_GROUP; /* Don't set mode more than once */
1661 break;
1662 case 's':
1663 i++; /* Set Scope Level */
1664 if (argv[i] != NULL) {
1665 if (!strncmp(argv[i], "base", 4))
1666 edui_conf.scope = 0;
1667 else if (!strncmp(argv[i], "one", 4))
1668 edui_conf.scope = 1;
1669 else if (!strncmp(argv[i], "sub", 4))
1670 edui_conf.scope = 2;
1671 else
1672 edui_conf.scope = 1; /* Default is 'one' */
1673 } else {
1674 local_printfx("No parameters given for 's'.\n");
1675 DisplayUsage();
1676 return 1;
1677 }
1678 break;
1679 case 'u':
1680 i++; /* Set Search Attribute */
1681 if (argv[i] != NULL) {
1682 xstrncpy(edui_conf.attrib, argv[i], sizeof(edui_conf.attrib));
1683 } else {
1684 local_printfx("No parameters given for 'u'.\n");
1685 DisplayUsage();
1686 return 1;
1687 }
1688 break;
1689 case '-': /* We got a second '-' ... ignore */
1690 break;
1691 default:
1692 local_printfx("Invalid parameter - '%c'.\n", argv[i][j]);
1693 break;
1694 }
1695 }
1696 } else {
1697 /* Incorrect parameter, display usage */
1698 DisplayUsage();
1699 return 1;
1700 }
1701 }
1702 }
1703
1704 /* Set predefined required paremeters if none are given, localhost:LDAP_PORT, etc */
1705 if (edui_conf.host[0] == '\0') /* Default to localhost */
1706 xstrncpy(edui_conf.host, "localhost", sizeof(edui_conf.host));
1707 if (edui_conf.port < 0)
1708 edui_conf.port = LDAP_PORT; /* Default: LDAP_PORT */
1709 if ((edui_conf.mode & EDUI_MODE_IPV4) && (edui_conf.mode & EDUI_MODE_IPV6))
1710 edui_conf.mode &= ~(EDUI_MODE_IPV6); /* Default to IPv4 */
1711 if (edui_conf.ver < 0)
1712 edui_conf.ver = 2;
1713 if (!(edui_conf.mode & EDUI_MODE_TLS))
1714 edui_conf.mode |= EDUI_MODE_TLS; /* eDirectory requires TLS mode */
1715 if ((edui_conf.mode & EDUI_MODE_TLS) && (edui_conf.ver < 3))
1716 edui_conf.ver = 3; /* TLS requires version 3 */
1717 if (edui_conf.persist_timeout < 0)
1718 edui_conf.persist_timeout = 600; /* Default: 600 seconds (10 minutes) */
1719 if (edui_conf.scope < 0)
1720 edui_conf.scope = 1; /* Default: one */
1721 if (edui_conf.search_filter[0] == '\0')
1722 xstrncpy(edui_conf.search_filter, "(&(objectclass=User)(networkAddress=*))", sizeof(edui_conf.search_filter));
1723 if (edui_conf.attrib[0] == '\0')
1724 xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib));
1725 if (edui_conf.basedn[0] == '\0') {
1726 local_printfx("FATAL: No '-b' option provided (Base DN).\n");
1727 DisplayUsage();
1728 return 1;
1729 }
1730 /* Trap the following signals */
1731 sigemptyset(&sv.sa_mask);
1732 sv.sa_handler = SigTrap;
1733 sigaction(SIGTERM, &sv, NULL);
1734 sv.sa_handler = SigTrap;
1735 sigaction(SIGHUP, &sv, NULL);
1736 sv.sa_handler = SigTrap;
1737 sigaction(SIGABRT, &sv, NULL);
1738 sv.sa_handler = SigTrap;
1739 sigaction(SIGINT, &sv, NULL);
1740 sv.sa_handler = SigTrap;
1741 sigaction(SIGSEGV, &sv, NULL);
1742
1743 DisplayConf();
1744 /* Done with arguments */
1745
1746 /* Set elap timer */
1747 time(&edui_now);
1748 t = edui_now;
1749 /* Main loop -- Waits for stdin input before action */
1750 while (fgets(bufa, sizeof(bufa), stdin) != NULL) {
1751 if (edui_conf.mode & EDUI_MODE_KILL)
1752 break;
1753 time(&edui_now);
1754 if (t < edui_now) {
1755 /* Elapse seconds */
1756 edui_elap = edui_now - t;
1757 t = edui_now;
1758 } else
1759 edui_elap = 0;
1760 k = strlen(bufa);
1761 /* BINARY DEBUGGING *
1762 local_printfx("while() -> bufa[%zd]: %s", k, bufa);
1763 for (i = 0; i < k; i++)
1764 local_printfx("%02X", bufa[i]);
1765 local_printfx("\n");
1766 * BINARY DEBUGGING */
1767 /* Check for CRLF */
1768 p = strchr(bufa, '\n');
1769 if (p != NULL)
1770 *p = '\0';
1771 p = strchr(bufa, '\r');
1772 if (p != NULL)
1773 *p = '\0';
1774 p = strchr(bufa, ' ');
1775
1776 /* No space given, but group string is required --> ERR */
1777 if ((edui_conf.mode & EDUI_MODE_GROUP) && (p == NULL)) {
1778 debug("while() -> Search group is missing. (required)\n");
1779 local_printfx("ERR (Search Group Required)\n");
1780 continue;
1781 }
1782 x = 0;
1783
1784 /* Open LDAP connection */
1785 if (!(edui_ldap.status & LDAP_INIT_S)) {
1786 InitLDAP(&edui_ldap);
1787 debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS));
1788 if (edui_conf.mode & EDUI_MODE_PERSIST) /* Setup persistant mode */
1789 edui_ldap.status |= LDAP_PERSIST_S;
1790 }
1791 if ((edui_ldap.status & LDAP_IDLE_S) && (edui_elap > 0)) {
1792 edui_ldap.idle_time = edui_ldap.idle_time + edui_elap;
1793 }
1794 if ((edui_ldap.status & LDAP_PERSIST_S) && (edui_ldap.status & LDAP_IDLE_S) && (edui_ldap.idle_time > edui_conf.persist_timeout)) {
1795 debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap.idle_time));
1796 x = CloseLDAP(&edui_ldap);
1797 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
1798 }
1799 edui_ldap.err = -1;
1800 if (!(edui_ldap.status & LDAP_OPEN_S)) {
1801 x = OpenLDAP(&edui_ldap, edui_conf.host, edui_conf.port);
1802 if (x != LDAP_ERR_SUCCESS) {
1803 /* Failed to connect */
1804 debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1805 } else {
1806 debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf.host, edui_conf.port, ErrLDAP(x));
1807 x = SetVerLDAP(&edui_ldap, edui_conf.ver);
1808 if (x != LDAP_ERR_SUCCESS) {
1809 /* Failed to set version */
1810 debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1811 } else
1812 debug("SetVerLDAP(-, %d) -> %s\n", edui_conf.ver, ErrLDAP(x));
1813 }
1814 }
1815 edui_ldap.err = -1;
1816 if (!(edui_ldap.status & LDAP_BIND_S) && (edui_conf.mode & EDUI_MODE_TLS)) {
1817 /* TLS binding */
1818 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_TLS);
1819 if (x != LDAP_ERR_SUCCESS) {
1820 /* Unable to bind */
1821 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1822 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1823 continue;
1824 } else
1825 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
1826 } else if (!(edui_ldap.status & LDAP_BIND_S)) {
1827 if (edui_conf.dn[0] != '\0') {
1828 /* Simple binding - using dn / passwd for authorization */
1829 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_SIMPLE);
1830 if (x != LDAP_ERR_SUCCESS) {
1831 /* Unable to bind */
1832 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1833 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1834 continue;
1835 } else
1836 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
1837 } else {
1838 /* Anonymous binding */
1839 x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_NONE);
1840 if (x != LDAP_ERR_SUCCESS) {
1841 /* Unable to bind */
1842 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1843 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1844 continue;
1845 } else
1846 debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x));
1847 }
1848 }
1849 edui_ldap.err = -1;
1850 if (edui_ldap.status & LDAP_PERSIST_S) {
1851 x = ResetLDAP(&edui_ldap);
1852 if (x != LDAP_ERR_SUCCESS) {
1853 /* Unable to reset */
1854 debug("ResetLDAP() -> %s\n", ErrLDAP(x));
1855 } else
1856 debug("ResetLDAP() -> %s\n", ErrLDAP(x));
1857 }
1858 if (x != LDAP_ERR_SUCCESS) {
1859 /* Everything failed --> ERR */
1860 debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1861 CloseLDAP(&edui_ldap);
1862 local_printfx("ERR (General Failure: %s)\n", ErrLDAP(x));
1863 continue;
1864 }
1865 edui_ldap.err = -1;
1866 /* If we got a group string, split it */
1867 if (p != NULL) {
1868 /* Split string */
1869 debug("StringSplit(%s, ' ', %s, %zd)\n", bufa, bufb, sizeof(bufb));
1870 i = StringSplit(bufa, ' ', bufb, sizeof(bufb));
1871 if (i > 0) {
1872 debug("StringSplit(%s, %s) done. Result: %zd\n", bufa, bufb, i);
1873 /* Got a group to match against */
1874 x = ConvertIP(&edui_ldap, bufb);
1875 if (x < 0) {
1876 debug("ConvertIP() -> %s\n", ErrLDAP(x));
1877 local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x));
1878 } else {
1879 edui_ldap.err = -1;
1880 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb, x, edui_ldap.search_ip);
1881 x = SearchFilterLDAP(&edui_ldap, bufa);
1882 if (x < 0) {
1883 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
1884 local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x));
1885 } else {
1886 /* Do Search */
1887 edui_ldap.err = -1;
1888 debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa, x);
1889 x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
1890 if (x != LDAP_ERR_SUCCESS) {
1891 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1892 local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x));
1893 } else {
1894 edui_ldap.err = -1;
1895 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
1896 x = SearchIPLDAP(&edui_ldap);
1897 if (x != LDAP_ERR_SUCCESS) {
1898 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1899 local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x));
1900 } else {
1901 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
1902 local_printfx("OK user=%s\n", edui_ldap.userid); /* Got userid --> OK user=<userid> */
1903 }
1904 }
1905 /* Clear for next query */
1906 memset(bufc, '\0', sizeof(bufc));
1907 }
1908 }
1909 } else {
1910 debug("StringSplit() -> Error: %Zu\n", i);
1911 local_printfx("ERR (StringSplit Error %d)\n", i);
1912 }
1913 } else {
1914 /* No group to match against, only an IP */
1915 x = ConvertIP(&edui_ldap, bufa);
1916 if (x < 0) {
1917 debug("ConvertIP() -> %s\n", ErrLDAP(x));
1918 local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x));
1919 } else {
1920 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa, x, edui_ldap.search_ip);
1921 /* Do search */
1922 x = SearchFilterLDAP(&edui_ldap, NULL);
1923 if (x < 0) {
1924 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
1925 local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x));
1926 } else {
1927 edui_ldap.err = -1;
1928 debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x);
1929 x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
1930 if (x != LDAP_ERR_SUCCESS) {
1931 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(x));
1932 local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x));
1933 } else {
1934 edui_ldap.err = -1;
1935 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
1936 x = SearchIPLDAP(&edui_ldap);
1937 if (x != LDAP_ERR_SUCCESS) {
1938 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
1939 local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x));
1940 } else {
1941 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
1942 local_printfx("OK user=%s\n", edui_ldap.userid); /* Got a userid --> OK user=<userid> */
1943 }
1944 }
1945 }
1946 /* Clear for next query */
1947 memset(bufc, '\0', sizeof(bufc));
1948 }
1949 }
1950
1951 /* Clear buffer and close for next data, if not persistent */
1952 edui_ldap.err = -1;
1953 memset(bufa, '\0', sizeof(bufa));
1954 if (!(edui_ldap.status & LDAP_PERSIST_S)) {
1955 x = CloseLDAP(&edui_ldap);
1956 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
1957 }
1958 }
1959
1960 debug("Terminating.\n");
1961 return 1;
1962 }
1963
1964 /* "main()" - function */
1965 int
1966 main(int argc, char **argv)
1967 {
1968 int x;
1969 x = MainSafe(argc, argv);
1970 return x;
1971 }