]>
Commit | Line | Data |
---|---|---|
915c866f | 1 | /* ext_edirectory_userip_acl - Copyright (C) 2009-2011 Chad E. Naugle |
f86504f1 AJ |
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 | * | |
915c866f CN |
22 | * ext_edirectory_userip_acl.cc -- Rev 2011-03-28 |
23 | * | |
24 | * - Misc code cleanups using "static", and 64-bit SLES fix for SearchFilterLDAP() | |
f86504f1 AJ |
25 | * |
26 | */ | |
27 | ||
f86504f1 | 28 | /* Squid-3.X includes */ |
f7f3304a | 29 | #include "squid.h" |
f86504f1 AJ |
30 | #include "helpers/defines.h" |
31 | #include "rfc1738.h" | |
32 | #include "util.h" | |
f86504f1 AJ |
33 | |
34 | #define EDUI_PROGRAM_NAME "ext_edirectory_userip_acl" | |
915c866f | 35 | #define EDUI_PROGRAM_VERSION "2.1" |
f86504f1 AJ |
36 | |
37 | /* System includes */ | |
38 | #ifdef HAVE_STDIO_H | |
39 | #include <stdio.h> | |
40 | #endif | |
88f2cf55 | 41 | #ifndef _GNU_SOURCE |
f86504f1 | 42 | #define _GNU_SOURCE |
88f2cf55 AJ |
43 | #endif |
44 | #ifndef __USE_GNU | |
f86504f1 | 45 | #define __USE_GNU |
88f2cf55 | 46 | #endif |
f86504f1 AJ |
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 | |
915c866f | 82 | #define EDUI_MAXLEN 4096 /* Modified to improve performance, unless HELPER_INPUT_BUFFER exists */ |
f86504f1 AJ |
83 | #endif |
84 | ||
85 | /* ldap compile options */ | |
86 | #define USE_LDAP_INIT | |
87 | #ifndef NETSCAPE_SSL | |
88 | # define NETSCAPE_SSL | |
89 | #endif | |
90 | ||
915c866f CN |
91 | /* define LDAP_AUTH_TLS |
92 | * - ldap.h Hack for cleaner code, if it does not provide it. | |
93 | */ | |
f86504f1 AJ |
94 | #ifdef NETSCAPE_SSL |
95 | # ifndef LDAP_AUTH_TLS | |
96 | # define LDAP_AUTH_TLS ((ber_tag_t) 0xb3U) | |
97 | # endif | |
98 | #endif | |
99 | ||
100 | /* conf_t - status flags */ | |
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 */ | |
7a545fdb | 170 | char userid[EDUI_MAXLEN]; /* Resulting userid */ |
f86504f1 AJ |
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 | ||
6ca7324f | 182 | /* Global function prototypes */ |
915c866f CN |
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); | |
6ca7324f AJ |
186 | static void DisplayVersion(); |
187 | static void DisplayUsage(); | |
188 | static void InitConf(); | |
189 | static void DisplayConf(); | |
190 | static void InitLDAP(edui_ldap_t *); | |
915c866f CN |
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 *); | |
6ca7324f | 200 | const char *ErrLDAP(int); |
5cd16654 | 201 | extern "C" void SigTrap(int); |
6ca7324f | 202 | |
f86504f1 | 203 | /* Global variables */ |
6ca7324f | 204 | const char *search_attrib[] = { "cn", "uid", "networkAddress", "groupMembership", NULL }; |
915c866f CN |
205 | static edui_conf_t edui_conf; |
206 | static edui_ldap_t edui_ldap; | |
f86504f1 AJ |
207 | time_t edui_now; |
208 | time_t edui_elap; | |
209 | ||
f86504f1 AJ |
210 | /* local_printfx() - |
211 | * | |
212 | * Print formatted message to stderr AND stdout, without preformatting. | |
213 | * | |
915c866f CN |
214 | * - Exists as a hack, because SEND_OK() does not appear to work here. |
215 | * | |
f86504f1 | 216 | */ |
915c866f CN |
217 | static void |
218 | local_printfx(const char *msg,...) | |
f86504f1 AJ |
219 | { |
220 | char prog[EDUI_MAXLEN], dbuf[EDUI_MAXLEN]; | |
221 | size_t sz, x; | |
222 | va_list ap; | |
223 | ||
224 | if (edui_conf.program[0] == '\0') | |
bcdce702 | 225 | xstrncpy(prog, EDUI_PROGRAM_NAME, sizeof(prog)); |
f86504f1 | 226 | else |
bcdce702 | 227 | xstrncpy(prog, edui_conf.program, sizeof(prog)); |
f86504f1 | 228 | |
915c866f | 229 | if (msg == NULL) { |
f86504f1 | 230 | /* FAIL */ |
915c866f | 231 | debug("local_printfx() FAILURE, no data.\n"); |
f86504f1 AJ |
232 | return; |
233 | } | |
234 | sz = sizeof(dbuf); | |
235 | va_start(ap, msg); | |
236 | x = vsnprintf(dbuf, sz, msg, ap); | |
237 | va_end(ap); | |
238 | if (x > 0) { | |
239 | dbuf[x] = '\0'; | |
755494da | 240 | ++x; |
f86504f1 | 241 | fputs(dbuf, stdout); |
9c76c145 | 242 | *(dbuf) = '\0'; |
f86504f1 AJ |
243 | } else { |
244 | /* FAIL */ | |
fe1e5c91 | 245 | debug("local_printfx() FAILURE: %" PRIuSIZE "\n", x); |
f86504f1 AJ |
246 | } |
247 | ||
248 | /* stdout needs to be flushed for it to work with Squid */ | |
249 | fflush(stdout); | |
250 | } | |
251 | ||
252 | /* | |
7a545fdb | 253 | * StringSplit() - <string-to-split> <char> <split-object> <obj-size> |
f86504f1 AJ |
254 | * |
255 | * Breaks down string, splitting out element <char> into <split-object>, and removing it from string. | |
256 | * Will not exceed size tolerances. | |
257 | * | |
f86504f1 | 258 | */ |
915c866f | 259 | static int |
9c2c41b2 | 260 | StringSplit(char *In_Str, char chr, char *Out_Str, size_t Out_Sz) |
f86504f1 | 261 | { |
9c2c41b2 AJ |
262 | if ((In_Str == NULL) || (Out_Str == NULL)) |
263 | return (-1); | |
264 | ||
265 | size_t In_Len = strlen(In_Str) + 1; | |
266 | ||
267 | // find the char delimiter position... | |
268 | char *p = In_Str; | |
269 | while (*p != chr && *p != '\0' && (In_Str+In_Len) > p) { | |
755494da | 270 | ++p; |
f86504f1 | 271 | } |
9c2c41b2 AJ |
272 | |
273 | size_t i = (p-In_Str); | |
274 | ||
275 | // token to big for the output buffer | |
276 | if (i >= Out_Sz) | |
277 | return (-2); | |
278 | ||
279 | // wipe the unused Out_Obj area | |
280 | memset(Out_Str+i, 0, Out_Sz-i); | |
281 | // copy token from In_Str to Out_Str | |
282 | memcpy(Out_Str, In_Str, i); | |
283 | ||
284 | // omit the delimiter | |
285 | if (*p == chr) { | |
755494da FC |
286 | ++p; |
287 | ++i; | |
9c2c41b2 AJ |
288 | } else { |
289 | // chr not found (or \0 found first). Wipe whole input buffer. | |
290 | memset(In_Str, 0, In_Len); | |
acbf414b AJ |
291 | // return (-3); |
292 | // Returning <0 breaks current ConvertIP() code for last object | |
90737510 | 293 | return (i); |
9c2c41b2 AJ |
294 | } |
295 | ||
296 | // move the unused In_Str forward | |
297 | memmove(In_Str, p, In_Len-i); | |
298 | // wipe the end of In_Str | |
299 | memset(In_Str+In_Len-i, 0, i); | |
300 | return (i-1); | |
f86504f1 AJ |
301 | } |
302 | ||
7a545fdb AJ |
303 | /* |
304 | * BinarySplit() - <binary-to-split> <bin-size> <char> <split-object> <obj-size> | |
305 | * | |
306 | * Breaks down Binary Block, splitting out element <char> into <split-object>, and removing it from Block, padding remainder with '\0'. | |
307 | * Will not exceed size tolerances. | |
308 | * | |
309 | */ | |
915c866f | 310 | static int |
9c2c41b2 | 311 | BinarySplit(void *In_Obj, size_t In_Sz, char chr, void *Out_Obj, size_t Out_Sz) |
7a545fdb | 312 | { |
9c2c41b2 AJ |
313 | // check tolerances |
314 | if ((In_Obj == NULL) || (Out_Obj == NULL)) | |
315 | return (-1); | |
316 | ||
317 | char *in = static_cast<char*>(In_Obj); | |
318 | char *out = static_cast<char*>(Out_Obj); | |
319 | ||
320 | // find the char delimiter position... | |
321 | char *p = static_cast<char*>(In_Obj); | |
322 | while (*p != chr && (in+In_Sz) > p) { | |
755494da | 323 | ++p; |
9c2c41b2 AJ |
324 | } |
325 | ||
326 | size_t i = (p-in); | |
327 | ||
328 | // token to big for the output buffer | |
329 | if (i > Out_Sz) | |
330 | return (-2); | |
331 | ||
332 | // wipe the unused Out_Obj area | |
333 | memset(out+i, 0, Out_Sz-i); | |
334 | // copy token from In_Obj to Out_Obj | |
335 | memcpy(Out_Obj, In_Obj, i); | |
336 | ||
337 | // omit the delimiter | |
338 | if (*p == chr) { | |
755494da FC |
339 | ++p; |
340 | ++i; | |
9c2c41b2 AJ |
341 | } else { |
342 | // chr not found | |
343 | memset(In_Obj, 0, In_Sz); | |
acbf414b AJ |
344 | // return (-3); |
345 | // Returning <0 breaks current code for last object | |
90737510 | 346 | return (i); |
7a545fdb | 347 | } |
9c2c41b2 AJ |
348 | |
349 | // move the unused In_Obj forward | |
350 | memmove(In_Obj, p, In_Sz-i); | |
351 | // wipe the end of In_Obj | |
352 | memset(in+In_Sz-i, 0, i); | |
353 | return (i-1); | |
7a545fdb | 354 | } |
9c2c41b2 | 355 | |
f86504f1 | 356 | /* Displays version information */ |
915c866f CN |
357 | static void |
358 | DisplayVersion() | |
f86504f1 | 359 | { |
915c866f | 360 | local_printfx("Squid eDirectory IP Lookup Helper %s. Copyright (C) 2009-2011 Chad E. Naugle\n", EDUI_PROGRAM_VERSION); |
f86504f1 AJ |
361 | } |
362 | ||
363 | /* Displays program usage information */ | |
915c866f CN |
364 | static void |
365 | DisplayUsage() | |
f86504f1 AJ |
366 | { |
367 | DisplayVersion(); | |
368 | local_printfx("\n"); | |
369 | local_printfx("Usage: %s\n", edui_conf.program); | |
370 | local_printfx(" -H <host> -p <port> [-Z] [-P] [-v 3] -b <basedn> -s <scope>\n"); | |
371 | local_printfx(" -D <binddn> -W <bindpass> -F <search-filter> [-G] \n\n"); | |
372 | local_printfx(" -d : Debug Mode.\n"); | |
373 | local_printfx(" -4 : Force Addresses to be in IPv4 (127.0.0.1 format).\n"); | |
374 | local_printfx(" -6 : Force Addresses to be in IPv6 (::1 format).\n"); | |
375 | local_printfx(" -H <host> : Specify hostname/ip of server.\n"); | |
376 | local_printfx(" -p <port> : Specify port number. (Range 1-65535)\n"); | |
377 | local_printfx(" -Z : Enable TLS security.\n"); | |
378 | local_printfx(" -P : Use persistent connections.\n"); | |
379 | local_printfx(" -t <sec> : Timeout factor for persistent connections. (Default is 60 sec, set to 0 for never timeout)\n"); | |
380 | local_printfx(" -v <1,2,3> : Set LDAP version to 1, 2, or 3.\n"); | |
381 | local_printfx(" -b <base> : Specify Base DN. (ie. \"o=ORG\")\n"); | |
6ca7324f | 382 | local_printfx(" -s <scope> : Specify LDAP Search Scope (base, one, sub; defaults to 'one').\n"); |
f86504f1 AJ |
383 | local_printfx(" -D <dn> : Specify Binding DN. (ie. cn=squid,o=ORG)\n"); |
384 | local_printfx(" -W <pass> : Specify Binding password.\n"); | |
385 | local_printfx(" -u <attrib> : Set userid attribute (Defaults to \"cn\").\n"); | |
386 | local_printfx(" -F <filter> : Specify LDAP search filter. (ie. \"(objectClass=User)\")\n"); | |
387 | local_printfx(" -G : Specify if LDAP search group is required. (ie. \"groupMembership=\")\n"); | |
388 | local_printfx(" -V : Display version & exit.\n"); | |
389 | local_printfx(" -h : This screen & exit.\n"); | |
390 | local_printfx("\n"); | |
391 | } | |
392 | ||
393 | /* Initalizes program's configuration paremeters */ | |
915c866f CN |
394 | static void |
395 | InitConf() | |
f86504f1 | 396 | { |
7a545fdb AJ |
397 | *(edui_conf.program) = '\0'; |
398 | *(edui_conf.basedn) = '\0'; | |
399 | *(edui_conf.host) = '\0'; | |
400 | *(edui_conf.attrib) = '\0'; | |
401 | *(edui_conf.dn) = '\0'; | |
402 | *(edui_conf.passwd) = '\0'; | |
403 | *(edui_conf.search_filter) = '\0'; | |
f86504f1 AJ |
404 | edui_conf.scope = -1; |
405 | edui_conf.ver = -1; | |
406 | edui_conf.port = -1; | |
407 | edui_conf.persist_timeout = -1; | |
408 | edui_conf.mode = 0; | |
409 | edui_conf.mode |= EDUI_MODE_INIT; | |
410 | ||
915c866f | 411 | /* Set defaults from compile-time-options, if provided, but depriciated. */ |
f86504f1 | 412 | #ifdef EDUI_BASE_DN |
6ca7324f | 413 | xstrncpy(edui_conf.basedn, EDUI_BASE_DN, sizeof(edui_conf.basedn)); |
f86504f1 AJ |
414 | #endif |
415 | #ifdef EDUI_DEFAULT_HOST | |
6ca7324f | 416 | xstrncpy(edui_conf.host, EDUI_DEFAULT_HOST, sizeof(edui_conf.host)); |
f86504f1 AJ |
417 | #endif |
418 | #ifdef EDUI_BIND_DN | |
6ca7324f | 419 | xstrncpy(edui_conf.dn, EDUI_BIND_DN, sizeof(edui_conf.dn)); |
f86504f1 AJ |
420 | #endif |
421 | #ifdef EDUI_BIND_PASS | |
6ca7324f | 422 | xstrncpy(edui_conf.passwd, EDUI_BIND_PASS, sizeof(edui_conf.passwd)); |
f86504f1 AJ |
423 | #endif |
424 | #ifdef EDUI_USER_ATTRIB | |
6ca7324f | 425 | xstrncpy(edui_conf.attrib, EDUI_USER_ATTRIB, sizeof(edui_conf.attrib)); |
f86504f1 AJ |
426 | #endif |
427 | #ifdef EDUI_SEARCH_FILTER | |
6ca7324f | 428 | xstrncpy(edui_conf.search_filter, EDUI_SEARCH_FILTER, sizeof(edui_conf.search_filter)); |
f86504f1 AJ |
429 | #endif |
430 | #ifdef EDUI_SEARCH_SCOPE | |
431 | if (!strcmp(EDUI_SEARCH_SCOPE, "base")) | |
432 | edui_conf.scope = 0; | |
433 | else if (!strcmp(EDUI_SEARCH_SCOPE, "one")) | |
434 | edui_conf.scope = 1; | |
435 | else if (!strcmp(EDUI_SEARCH_SCOPE, "sub")) | |
436 | edui_conf.scope = 2; | |
437 | else | |
438 | edui_conf.scope = 1; | |
439 | #endif | |
440 | #ifdef EDUI_LDAP_VERSION | |
441 | edui_conf.ver = EDUI_LDAP_VERSION; | |
442 | #endif | |
443 | #ifdef EDUI_DEFAULT_PORT | |
444 | edui_conf.port = EDUI_DEFAULT_PORT; | |
445 | #endif | |
446 | #ifdef EDUI_FORCE_IPV4 | |
447 | edui_conf.mode |= EDUI_MODE_IPV4; | |
448 | #endif | |
449 | #ifdef EDUI_FORCE_IPV6 | |
450 | edui_conf.mode |= EDUI_MODE_IPV6; | |
451 | #endif | |
452 | #ifdef EDUI_USE_TLS | |
453 | edui_conf.mode |= EDUI_MODE_TLS; | |
454 | #endif | |
455 | #ifdef EDUI_USE_PERSIST | |
456 | edui_conf.mode |= EDUI_MODE_PERSIST; | |
457 | #endif | |
458 | #ifdef EDUI_PERSIST_TIMEOUT | |
459 | edui_conf.persist_timeout = EDUI_PERSIST_TIMEOUT; | |
460 | #endif | |
461 | #ifdef EDUI_GROUP_REQUIRED | |
462 | edui_conf.mode |= EDUI_MODE_GROUP; | |
463 | #endif | |
464 | #ifdef EDUI_DEBUG | |
465 | edui_conf.mode |= EDUI_MODE_DEBUG; | |
466 | #endif | |
467 | } | |
468 | ||
469 | /* Displays running configuration */ | |
915c866f CN |
470 | static void |
471 | DisplayConf() | |
f86504f1 AJ |
472 | { |
473 | if (!(edui_conf.mode & EDUI_MODE_DEBUG)) | |
474 | return; | |
475 | DisplayVersion(); | |
476 | local_printfx("\n"); | |
477 | local_printfx("Configuration:\n"); | |
fe1e5c91 | 478 | local_printfx(" EDUI_MAXLEN: %u\n", EDUI_MAXLEN); |
f86504f1 AJ |
479 | if (edui_conf.mode & EDUI_MODE_DEBUG) |
480 | local_printfx(" Debug mode: ON\n"); | |
481 | else | |
482 | local_printfx(" Debug mode: OFF\n"); | |
483 | if (edui_conf.mode & EDUI_MODE_IPV4) | |
484 | local_printfx(" Address format: IPv4 (127.0.0.1)\n"); | |
485 | else if (edui_conf.mode & EDUI_MODE_IPV6) | |
486 | local_printfx(" Address format: IPv6 (::1)\n"); | |
487 | else | |
488 | local_printfx(" Address format: Not enforced.\n"); | |
489 | if (edui_conf.host[0] != '\0') | |
490 | local_printfx(" Hostname: %s\n", edui_conf.host); | |
491 | else | |
492 | local_printfx(" Hostname: localhost\n"); | |
493 | if (edui_conf.port > 0) | |
494 | local_printfx(" Port: %d\n", edui_conf.port); | |
495 | else | |
496 | local_printfx(" Port: %d\n", LDAP_PORT); | |
497 | if (edui_conf.mode & EDUI_MODE_TLS) | |
498 | local_printfx(" TLS mode: ON\n"); | |
499 | else | |
500 | local_printfx(" TLS mode: OFF\n"); | |
501 | if (edui_conf.mode & EDUI_MODE_PERSIST) { | |
502 | local_printfx(" Persistent mode: ON\n"); | |
503 | if (edui_conf.persist_timeout > 0) | |
504 | local_printfx(" Persistent mode idle timeout: %d\n", edui_conf.persist_timeout); | |
505 | else | |
506 | local_printfx(" Persistent mode idle timeout: OFF\n"); | |
507 | } else | |
508 | local_printfx(" Persistent mode: OFF\n"); | |
509 | local_printfx(" LDAP Version: %d\n", edui_conf.ver); | |
510 | if (edui_conf.basedn[0] != '\0') | |
511 | local_printfx(" Base DN: %s\n", edui_conf.basedn); | |
512 | else | |
513 | local_printfx(" Base DN: None\n"); | |
514 | if (edui_conf.dn[0] != '\0') | |
515 | local_printfx(" Binding DN: %s\n", edui_conf.dn); | |
516 | else | |
517 | local_printfx(" Binding DN: Anonymous\n"); | |
518 | if (edui_conf.passwd[0] != '\0') | |
519 | local_printfx(" Binding Password: %s\n", edui_conf.passwd); | |
520 | else | |
521 | local_printfx(" Binding Password: None\n"); | |
522 | switch (edui_conf.scope) { | |
523 | case 0: | |
524 | local_printfx(" Search Scope: base\n"); | |
525 | break; | |
526 | case 1: | |
527 | local_printfx(" Search Scope: one level\n"); | |
528 | break; | |
529 | case 2: | |
530 | local_printfx(" Search Scope: subtree\n"); | |
531 | break; | |
532 | default: | |
533 | local_printfx(" Search Scope: base\n"); | |
534 | break; | |
535 | } | |
6ca7324f AJ |
536 | if (edui_conf.attrib[0] != '\0') |
537 | local_printfx(" Search Attribute: %s\n", edui_conf.attrib); | |
538 | else | |
539 | local_printfx(" Search Attribute: cn\n"); | |
f86504f1 AJ |
540 | if (edui_conf.search_filter[0] != '\0') |
541 | local_printfx(" Search Filter: %s\n", edui_conf.search_filter); | |
542 | else | |
543 | local_printfx(" Search Filter: (&(objectClass=User)(networkAddress=*))\n"); | |
544 | if (edui_conf.mode & EDUI_MODE_GROUP) | |
545 | local_printfx(" Search Group Required: Yes\n"); | |
546 | else | |
547 | local_printfx(" Search Group Required: No\n"); | |
548 | local_printfx("\n"); | |
549 | } | |
550 | ||
551 | /* InitLDAP() - <edui_ldap_t> | |
552 | * | |
553 | * Initalize LDAP structure for use, zeroing out all variables. | |
554 | * | |
555 | */ | |
915c866f CN |
556 | static void |
557 | InitLDAP(edui_ldap_t *l) | |
f86504f1 | 558 | { |
7a545fdb | 559 | if (l == NULL) return; |
f86504f1 AJ |
560 | |
561 | l->lp = NULL; | |
562 | if (l->lm != NULL) | |
563 | ldap_msgfree(l->lm); | |
564 | if (l->val != NULL) | |
565 | ldap_value_free_len(l->val); | |
566 | l->lm = NULL; | |
567 | l->val = NULL; | |
7a545fdb AJ |
568 | *(l->basedn) = '\0'; |
569 | *(l->host) = '\0'; | |
570 | *(l->dn) = '\0'; | |
571 | *(l->passwd) = '\0'; | |
572 | *(l->search_filter) = '\0'; | |
573 | *(l->userid) = '\0'; | |
f86504f1 | 574 | memset(l->search_ip, '\0', sizeof(l->search_ip)); |
f86504f1 AJ |
575 | l->status = 0; |
576 | l->status |= LDAP_INIT_S; | |
577 | l->port = 0; | |
578 | l->scope = -1; | |
579 | l->type = 0; | |
580 | l->err = -1; /* Set error to LDAP_SUCCESS by default */ | |
581 | l->ver = 0; | |
582 | l->idle_time = 0; | |
7a545fdb AJ |
583 | l->num_ent = 0; /* Number of entries in l->lm */ |
584 | l->num_val = 0; /* Number of entries in l->val */ | |
f86504f1 AJ |
585 | |
586 | /* Set default settings from conf */ | |
587 | if (edui_conf.basedn[0] != '\0') | |
6ca7324f | 588 | xstrncpy(l->basedn, edui_conf.basedn, sizeof(l->basedn)); |
f86504f1 | 589 | if (edui_conf.host[0] != '\0') |
6ca7324f | 590 | xstrncpy(l->host, edui_conf.host, sizeof(l->host)); |
f86504f1 AJ |
591 | if (edui_conf.port != 0) |
592 | l->port = edui_conf.port; | |
593 | if (edui_conf.dn[0] != '\0') | |
6ca7324f | 594 | xstrncpy(l->dn, edui_conf.dn, sizeof(l->dn)); |
f86504f1 | 595 | if (edui_conf.passwd[0] != '\0') |
6ca7324f | 596 | xstrncpy(l->passwd, edui_conf.passwd, sizeof(l->passwd)); |
f86504f1 | 597 | if (edui_conf.search_filter[0] != '\0') |
6ca7324f | 598 | xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter)); |
f86504f1 AJ |
599 | if (!(edui_conf.scope < 0)) |
600 | l->scope = edui_conf.scope; | |
f86504f1 AJ |
601 | } |
602 | ||
603 | /* OpenLDAP() - <edui_ldap_t> <host> <port> | |
604 | * | |
605 | * Build LDAP struct with hostname and port, and ready it for binding. | |
606 | * | |
607 | */ | |
915c866f CN |
608 | static int |
609 | OpenLDAP(edui_ldap_t *l, char *h, unsigned int p) | |
f86504f1 AJ |
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 */ | |
7a545fdb AJ |
613 | if (l->status & LDAP_OPEN_S) return LDAP_ERR_OPEN; /* Already open */ |
614 | if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */ | |
f86504f1 | 615 | |
6ca7324f | 616 | xstrncpy(l->host, h, sizeof(l->host)); |
f86504f1 AJ |
617 | if (p > 0) |
618 | l->port = p; | |
619 | else | |
7a545fdb | 620 | l->port = LDAP_PORT; /* Default is port 389 */ |
f86504f1 AJ |
621 | |
622 | #ifdef NETSCAPE_SSL | |
623 | if (l->port == LDAPS_PORT) | |
7a545fdb | 624 | l->status |= (LDAP_SSL_S | LDAP_TLS_S); /* SSL Port: 636 */ |
f86504f1 AJ |
625 | #endif |
626 | ||
627 | #ifdef USE_LDAP_INIT | |
628 | l->lp = ldap_init(l->host, l->port); | |
629 | #else | |
630 | l->lp = ldap_open(l->host, l->port); | |
631 | #endif | |
632 | if (l->lp == NULL) { | |
633 | l->err = LDAP_CONNECT_ERROR; | |
7a545fdb | 634 | return LDAP_ERR_CONNECT; /* Unable to connect */ |
f86504f1 AJ |
635 | } else { |
636 | /* set status */ | |
637 | // l->status &= ~(LDAP_INIT_S); | |
638 | l->status |= LDAP_OPEN_S; | |
639 | l->err = LDAP_SUCCESS; | |
640 | return LDAP_ERR_SUCCESS; | |
641 | } | |
642 | } | |
643 | ||
644 | /* CloseLDAP() - <edui_ldap_t> | |
645 | * | |
646 | * Close LDAP connection, and clean up data structure. | |
647 | * | |
648 | */ | |
915c866f CN |
649 | static int |
650 | CloseLDAP(edui_ldap_t *l) | |
f86504f1 AJ |
651 | { |
652 | int s; | |
653 | if (l == NULL) return LDAP_ERR_NULL; | |
654 | if (l->lp == NULL) return LDAP_ERR_NULL; | |
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; | |
f86504f1 AJ |
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 | */ | |
915c866f CN |
685 | static int |
686 | SetVerLDAP(edui_ldap_t *l, int v) | |
f86504f1 AJ |
687 | { |
688 | int x; | |
689 | if (l == NULL) return LDAP_ERR_NULL; | |
690 | if ((v > 3) || (v < 1)) return LDAP_ERR_PARAM; | |
691 | if (l->lp == NULL) return LDAP_ERR_POINTER; | |
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 */ | |
7a545fdb | 694 | if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */ |
f86504f1 AJ |
695 | |
696 | /* set version */ | |
697 | x = ldap_set_option(l->lp, LDAP_OPT_PROTOCOL_VERSION, &v); | |
698 | if (x == LDAP_SUCCESS) { | |
699 | l->ver = v; | |
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 | */ | |
915c866f CN |
713 | static int |
714 | BindLDAP(edui_ldap_t *l, char *dn, char *pw, unsigned int t) | |
f86504f1 AJ |
715 | { |
716 | int s; | |
717 | if (l == NULL) return LDAP_ERR_NULL; | |
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 */ | |
7a545fdb AJ |
720 | if (l->status & LDAP_BIND_S) return LDAP_ERR_BIND; /* Already bound */ |
721 | if (l->lp == NULL) return LDAP_ERR_POINTER; /* Error */ | |
f86504f1 AJ |
722 | |
723 | /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */ | |
724 | if (dn != NULL) { | |
725 | if ((l->basedn[0] != '\0') && (strstr(dn, l->basedn) == NULL)) { | |
726 | /* We got a basedn, but it's not part of dn */ | |
6ca7324f | 727 | xstrncpy(l->dn, dn, sizeof(l->dn)); |
9d37c286 AJ |
728 | strncat(l->dn, ",", 1); |
729 | strncat(l->dn, l->basedn, strlen(l->basedn)); | |
f86504f1 | 730 | } else |
6ca7324f | 731 | xstrncpy(l->dn, dn, sizeof(l->dn)); |
f86504f1 AJ |
732 | } |
733 | if (pw != NULL) | |
6ca7324f | 734 | xstrncpy(l->passwd, pw, sizeof(l->passwd)); |
f86504f1 | 735 | |
7a545fdb | 736 | /* Type */ |
f86504f1 AJ |
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; | |
67245b81 | 747 | #ifdef LDAP_AUTH_KRBV4 |
f86504f1 AJ |
748 | case LDAP_AUTH_KRBV4: |
749 | l->type = t; | |
750 | break; | |
67245b81 AJ |
751 | #endif |
752 | #ifdef LDAP_AUTH_KRBV41 | |
f86504f1 AJ |
753 | case LDAP_AUTH_KRBV41: |
754 | l->type = t; | |
755 | break; | |
67245b81 AJ |
756 | #endif |
757 | #ifdef LDAP_AUTH_KRBV42 | |
f86504f1 AJ |
758 | case LDAP_AUTH_KRBV42: |
759 | l->type = t; | |
760 | break; | |
67245b81 | 761 | #endif |
f86504f1 | 762 | #ifdef LDAP_AUTH_TLS |
7a545fdb | 763 | case LDAP_AUTH_TLS: /* Added for chicken switch to TLS-enabled without using SSL */ |
f86504f1 AJ |
764 | l->type = t; |
765 | break; | |
766 | #endif | |
767 | default: | |
768 | l->type = LDAP_AUTH_NONE; | |
7a545fdb | 769 | break; /* Default to anonymous bind */ |
f86504f1 AJ |
770 | } |
771 | ||
772 | /* Bind */ | |
60727a6f | 773 | #if defined(LDAP_AUTH_TLS) && defined(NETSCAPE_SSL) && HAVE_LDAP_START_TLS_S |
f86504f1 AJ |
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 | * | |
915c866f | 795 | * PENDING -- CHANGE OVER TO inet*_pton, but inet6_pton does not provide the correct syntax |
f86504f1 AJ |
796 | * |
797 | */ | |
915c866f CN |
798 | static int |
799 | ConvertIP(edui_ldap_t *l, char *ip) | |
f86504f1 AJ |
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; | |
7a545fdb | 806 | int i, j, t, swi; /* IPv6 "::" cut over toggle */ |
f86504f1 AJ |
807 | if (l == NULL) return LDAP_ERR_NULL; |
808 | if (ip == NULL) return LDAP_ERR_PARAM; | |
7a545fdb AJ |
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 */ | |
f86504f1 AJ |
812 | |
813 | y = memchr((void *)ip, ':', EDUI_MAXLEN); | |
814 | z = memchr((void *)ip, '.', EDUI_MAXLEN); | |
815 | if ((y != NULL) && (z != NULL)) { | |
314b9463 A |
816 | y = NULL; |
817 | z = NULL; | |
818 | return LDAP_ERR_INVALID; | |
f86504f1 AJ |
819 | } |
820 | if ((y != NULL) && (edui_conf.mode & EDUI_MODE_IPV4)) { | |
314b9463 A |
821 | /* IPv4 Mode forced */ |
822 | return LDAP_ERR_INVALID; | |
823 | } else if (y != NULL) { | |
824 | /* Set IPv6 mode */ | |
314b9463 A |
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; | |
f86504f1 AJ |
830 | } |
831 | if ((z != NULL) && (edui_conf.mode & EDUI_MODE_IPV6)) { | |
314b9463 A |
832 | /* IPv6 Mode forced */ |
833 | return LDAP_ERR_INVALID; | |
834 | } else if (z != NULL) { | |
314b9463 A |
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; | |
f86504f1 AJ |
841 | } |
842 | s = strlen(ip); | |
7a545fdb AJ |
843 | *(bufa) = '\0'; |
844 | *(bufb) = '\0'; | |
845 | *(obj) = '\0'; | |
846 | /* StringSplit() will zero out bufa & obj at each call */ | |
f86504f1 | 847 | memset(l->search_ip, '\0', sizeof(l->search_ip)); |
9d37c286 | 848 | xstrncpy(bufa, ip, sizeof(bufa)); /* To avoid segfaults, use bufa instead of ip */ |
f86504f1 AJ |
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 */ | |
bcdce702 | 854 | xstrncpy(bufb, bufa, sizeof(bufb)); |
9c76c145 | 855 | *(bufa) = '\0'; |
755494da | 856 | ++swi; /* Indicates that there is a bufb */ |
f86504f1 AJ |
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] = ':'; | |
9d37c286 | 860 | strncat(bufb, bufa, strlen(bufa)); |
9c76c145 | 861 | *(bufa) = '\0'; |
755494da | 862 | ++swi; /* Indicates that there is a bufb */ |
f86504f1 AJ |
863 | } else { |
864 | p = strstr(bufa, "::"); | |
865 | if (p != NULL) { | |
866 | /* Found it, break bufa down and split into bufb here */ | |
9c76c145 | 867 | *(bufb) = '\0'; |
f86504f1 AJ |
868 | i = strlen(p); |
869 | memcpy(bufb, p, i); | |
870 | *p = '\0'; | |
871 | bufb[i] = '\0'; | |
755494da | 872 | ++swi; /* Indicates that there is a bufb */ |
f86504f1 AJ |
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 */ | |
7a545fdb | 882 | t = StringSplit(bufa, '.', obj, sizeof(obj)); |
f86504f1 AJ |
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)); | |
7a545fdb | 889 | int hlen = snprintf(hexc, sizeof(hexc), "%02X", (int)x); |
9d37c286 | 890 | strncat(l->search_ip, hexc, hlen); |
f86504f1 AJ |
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) | |
7a545fdb | 896 | t = StringSplit(bufb, ':', obj, sizeof(obj)); /* After "::" */ |
f86504f1 | 897 | else |
7a545fdb | 898 | t = StringSplit(bufa, ':', obj, sizeof(obj)); /* Before "::" */ |
f86504f1 AJ |
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'; | |
9d37c286 | 911 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
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'; | |
9d37c286 | 921 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
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'; | |
9d37c286 | 930 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
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'; | |
9d37c286 | 940 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
941 | break; |
942 | case 2: | |
9d37c286 | 943 | strncat(l->search_ip, "00", 2); |
f86504f1 AJ |
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'; | |
9d37c286 | 953 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
954 | break; |
955 | case 1: | |
9d37c286 | 956 | strncat(l->search_ip, "00", 2); |
f86504f1 AJ |
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'; | |
9d37c286 | 963 | strncat(l->search_ip, hexc, 2); |
f86504f1 AJ |
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)) { | |
314b9463 A |
972 | /* We are *AT* the split, pad in some 0000 */ |
973 | t = strlen(bufb); | |
974 | /* How many ':' exist in bufb ? */ | |
975 | j = 0; | |
755494da | 976 | for (i = 0; i < t; ++i) { |
314b9463 | 977 | if (bufb[i] == ':') |
755494da | 978 | ++j; |
314b9463 | 979 | } |
755494da | 980 | --j; /* Preceeding "::" doesn't count */ |
314b9463 A |
981 | t = 8 - (strlen(l->search_ip) / 4) - j; /* Remainder */ |
982 | if (t > 0) { | |
755494da | 983 | for (i = 0; i < t; ++i) |
9d37c286 | 984 | strncat(l->search_ip, "0000", 4); |
314b9463 | 985 | } |
f86504f1 AJ |
986 | } |
987 | } | |
988 | if ((bufa[0] == '\0') && (swi > 0)) { | |
989 | s = strlen(bufb); | |
755494da | 990 | ++swi; |
f86504f1 AJ |
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)) { | |
9d37c286 | 999 | strncat(l->search_ip, "0000", 4); |
f86504f1 AJ |
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)) { | |
9d37c286 | 1009 | strncat(l->search_ip, "00", 2); |
f86504f1 AJ |
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 | */ | |
915c866f CN |
1027 | static int |
1028 | ResetLDAP(edui_ldap_t *l) | |
314b9463 A |
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 */ | |
314b9463 A |
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)); | |
7a545fdb | 1054 | *(l->search_filter) = '\0'; |
6ca7324f | 1055 | xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter)); |
7a545fdb | 1056 | *(l->userid) = '\0'; |
314b9463 A |
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; | |
314b9463 A |
1061 | l->err = LDAP_SUCCESS; |
1062 | return LDAP_ERR_SUCCESS; | |
f86504f1 AJ |
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 | */ | |
915c866f CN |
1071 | static int |
1072 | SearchFilterLDAP(edui_ldap_t *l, char *group) | |
f86504f1 AJ |
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; | |
f86504f1 AJ |
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 */ | |
6ca7324f | 1081 | if (l->search_ip[0] == '\0') return LDAP_ERR_DATA; /* Search IP is required */ |
f86504f1 AJ |
1082 | |
1083 | /* Zero out if not already */ | |
915c866f CN |
1084 | memset(bufa, '\0', sizeof(bufa)); |
1085 | // using memset() for 'bufa' fixes the 64-bit issue | |
7a545fdb AJ |
1086 | *(bufb) = '\0'; |
1087 | *(bufc) = '\0'; | |
1088 | *(bufd) = '\0'; | |
1089 | *(bufg) = '\0'; | |
f86504f1 | 1090 | |
f86504f1 AJ |
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'; | |
755494da | 1098 | ++j; |
f86504f1 | 1099 | bufc[j] = l->search_ip[i]; |
755494da | 1100 | ++j; |
f86504f1 AJ |
1101 | swi = 1; |
1102 | } else { | |
1103 | bufc[j] = l->search_ip[i]; | |
755494da FC |
1104 | ++j; |
1105 | ++swi; | |
f86504f1 AJ |
1106 | } |
1107 | } | |
1108 | if (group == NULL) { | |
1109 | /* No groupMembership= to add, yay! */ | |
bcdce702 | 1110 | xstrncpy(bufa, "(&", sizeof(bufa)); |
9d37c286 | 1111 | strncat(bufa, edui_conf.search_filter, strlen(edui_conf.search_filter)); |
f86504f1 | 1112 | /* networkAddress */ |
9d37c286 | 1113 | snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)", bufc); |
314b9463 | 1114 | if (l->status & LDAP_IPV4_S) { |
9d37c286 | 1115 | int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \ |
7023a59a | 1116 | bufc, bufc); |
9d37c286 | 1117 | strncat(bufb, bufd, ln); |
f86504f1 | 1118 | } else if (l->status & LDAP_IPV6_S) { |
9d37c286 | 1119 | int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \ |
7023a59a | 1120 | bufc, bufc); |
9d37c286 | 1121 | strncat(bufb, bufd, ln); |
f86504f1 | 1122 | } else |
9d37c286 AJ |
1123 | strncat(bufb, ")", 1); |
1124 | strncat(bufa, bufb, strlen(bufb)); | |
1125 | strncat(bufa, ")", 1); | |
f86504f1 AJ |
1126 | } else { |
1127 | /* Needs groupMembership= to add... */ | |
bcdce702 | 1128 | xstrncpy(bufa, "(&(&", sizeof(bufa)); |
9d37c286 | 1129 | strncat(bufa, edui_conf.search_filter, strlen(edui_conf.search_filter)); |
f86504f1 AJ |
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)) { | |
9d37c286 AJ |
1133 | strncat(bufg, ",", 1); |
1134 | strncat(bufg, l->basedn, strlen(l->basedn)); | |
f86504f1 | 1135 | } |
9d37c286 AJ |
1136 | strncat(bufg, ")", 1); |
1137 | strncat(bufa, bufg, strlen(bufg)); | |
f86504f1 | 1138 | /* networkAddress */ |
9d37c286 | 1139 | snprintf(bufb, sizeof(bufb), "(|(networkAddress=1\\23%s)", bufc); |
314b9463 | 1140 | if (l->status & LDAP_IPV4_S) { |
9d37c286 | 1141 | int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \ |
7023a59a | 1142 | bufc, bufc); |
9d37c286 | 1143 | strncat(bufb, bufd, ln); |
f86504f1 | 1144 | } else if (l->status & LDAP_IPV6_S) { |
9d37c286 | 1145 | int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \ |
7023a59a | 1146 | bufc, bufc); |
9d37c286 | 1147 | strncat(bufb, bufd, ln); |
f86504f1 | 1148 | } else |
9d37c286 AJ |
1149 | strncat(bufb, ")", 1); |
1150 | strncat(bufa, bufb, strlen(bufb)); | |
1151 | strncat(bufa, "))", 2); | |
f86504f1 AJ |
1152 | } |
1153 | s = strlen(bufa); | |
bcdce702 | 1154 | xstrncpy(l->search_filter, bufa, sizeof(l->search_filter)); |
f86504f1 AJ |
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 | */ | |
915c866f CN |
1165 | static int |
1166 | SearchLDAP(edui_ldap_t *l, int scope, char *filter, char **attrs) | |
f86504f1 AJ |
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; | |
7a545fdb AJ |
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 */ | |
f86504f1 AJ |
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 */ | |
6ca7324f | 1182 | xstrncpy(ft, "(&(objectClass=User)(networkAddress=*))", sizeof(ft)); |
f86504f1 | 1183 | else |
6ca7324f | 1184 | xstrncpy(ft, filter, sizeof(ft)); |
f86504f1 AJ |
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: | |
6ca7324f AJ |
1198 | /* Only search ONE by default */ |
1199 | s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm)); | |
f86504f1 AJ |
1200 | break; |
1201 | } | |
1202 | if (s == LDAP_SUCCESS) { | |
1203 | l->status |= (LDAP_SEARCH_S); /* Mark as searched */ | |
1204 | l->err = s; | |
7a545fdb | 1205 | l->idle_time = 0; /* Connection in use, reset idle timer */ |
f86504f1 AJ |
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 | /* | |
7a545fdb | 1216 | * SearchIPLDAP() - <edui_ldap_t> |
f86504f1 AJ |
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 | */ | |
915c866f CN |
1222 | static int |
1223 | SearchIPLDAP(edui_ldap_t *l) | |
f86504f1 AJ |
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; | |
f86504f1 | 1231 | if (l == NULL) return LDAP_ERR_NULL; |
f86504f1 | 1232 | if (l->lp == NULL) return LDAP_ERR_POINTER; |
6ca7324f AJ |
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 */ | |
9c76c145 A |
1237 | if (l->num_ent <= 0) { |
1238 | debug("l->num_ent: %d\n", l->num_ent); | |
1239 | return LDAP_ERR_DATA; /* No entries found */ | |
7a545fdb | 1240 | } |
f86504f1 | 1241 | if (l->val != NULL) |
6ca7324f | 1242 | ldap_value_free_len(l->val); /* Clear data before populating */ |
f86504f1 AJ |
1243 | l->num_val = 0; |
1244 | if (l->status & LDAP_VAL_S) | |
6ca7324f | 1245 | l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */ |
f86504f1 | 1246 | if (edui_conf.attrib[0] == '\0') |
7a545fdb | 1247 | xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); /* Make sure edui_conf.attrib is set */ |
f86504f1 AJ |
1248 | |
1249 | /* Sift through entries */ | |
9d70add4 | 1250 | struct berval **ber = NULL; |
f86504f1 AJ |
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) { | |
6ca7324f | 1255 | x = ldap_count_values_len(l->val); /* We got x values ... */ |
f86504f1 AJ |
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); | |
7a545fdb | 1262 | z = BinarySplit(bufa, j, '#', bufb, sizeof(bufb)); |
9c76c145 | 1263 | /* BINARY DEBUGGING * |
fe1e5c91 | 1264 | local_printfx("value[%" PRIuSIZE "]: BinarySplit(", (size_t) i); |
9c76c145 A |
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 | } | |
fe1e5c91 | 1278 | local_printfx("): %" PRIuSIZE "\n", (size_t) z); |
9c76c145 | 1279 | * BINARY DEBUGGING */ |
f86504f1 | 1280 | z = j - z - 1; |
9c76c145 | 1281 | j = atoi(bufb); |
7a545fdb | 1282 | if (j == 1) { |
9c76c145 | 1283 | /* IPv4 address (eDirectory 8.7 and below) */ |
f86504f1 AJ |
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; | |
7a545fdb | 1291 | int hlen = snprintf(hexc, sizeof(hexc), "%02X", c); |
f86504f1 | 1292 | if (k == 0) |
bcdce702 | 1293 | xstrncpy(bufb, hexc, sizeof(bufb)); |
f86504f1 | 1294 | else |
9d37c286 | 1295 | strncat(bufb, hexc, hlen); |
f86504f1 AJ |
1296 | } |
1297 | y = strlen(bufb); | |
1298 | /* Compare value with IP */ | |
67245b81 | 1299 | if (memcmp(l->search_ip, bufb, y) == 0) { |
f86504f1 AJ |
1300 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1301 | z = ldap_count_values_len(ber); | |
7a545fdb AJ |
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)); | |
9c76c145 A |
1305 | /* Using bv_len of min() breaks the result by 2 chars */ |
1306 | } | |
f86504f1 AJ |
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 */ | |
9c76c145 A |
1317 | } else if ((j == 8) || (j == 9)) { |
1318 | /* IPv4 (UDP/TCP) address (eDirectory 8.8 and higher) */ | |
f86504f1 AJ |
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; | |
7a545fdb | 1326 | int hlen = snprintf(hexc, sizeof(hexc), "%02X", c); |
f86504f1 | 1327 | if (k == 2) |
bcdce702 | 1328 | xstrncpy(bufb, hexc, sizeof(bufb)); |
f86504f1 | 1329 | else |
9d37c286 | 1330 | strncat(bufb, hexc, hlen); |
f86504f1 AJ |
1331 | } |
1332 | y = strlen(bufb); | |
1333 | /* Compare value with IP */ | |
67245b81 | 1334 | if (memcmp(l->search_ip, bufb, y) == 0) { |
f86504f1 AJ |
1335 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1336 | z = ldap_count_values_len(ber); | |
915c866f | 1337 | for (j = 0; j < z; j++) { |
7a545fdb AJ |
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)); | |
915c866f | 1340 | /* Using bv_len of min() breaks the result by 2 chars */ |
2c3d5aec | 1341 | } |
f86504f1 AJ |
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 */ | |
9c76c145 | 1352 | } else if ((j == 10) || (j == 11)) { |
7a545fdb | 1353 | /* IPv6 (UDP/TCP) address (eDirectory 8.8 and higher) */ |
f86504f1 AJ |
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; | |
7a545fdb | 1361 | int hlen = snprintf(hexc, sizeof(hexc), "%02X", c); |
f86504f1 | 1362 | if (k == 2) |
bcdce702 | 1363 | xstrncpy(bufb, hexc, sizeof(bufb)); |
f86504f1 | 1364 | else |
9d37c286 | 1365 | strncat(bufb, hexc, hlen); |
f86504f1 AJ |
1366 | } |
1367 | y = strlen(bufb); | |
1368 | /* Compare value with IP */ | |
67245b81 | 1369 | if (memcmp(l->search_ip, bufb, y) == 0) { |
f86504f1 AJ |
1370 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1371 | z = ldap_count_values_len(ber); | |
915c866f | 1372 | for (j = 0; j < z; j++) { |
7a545fdb AJ |
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)); | |
915c866f | 1375 | /* Using bv_len of min() breaks the result by 2 chars */ |
2c3d5aec | 1376 | } |
f86504f1 AJ |
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 */ | |
9c76c145 | 1387 | } |
7a545fdb | 1388 | // else { |
9c76c145 | 1389 | /* Others are unsupported */ |
7a545fdb | 1390 | // } |
f86504f1 AJ |
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 | ||
915c866f CN |
1430 | /* |
1431 | * ErrLDAP() - <errno> | |
1432 | * | |
1433 | * Returns error description of error code | |
1434 | * | |
1435 | */ | |
1436 | const char | |
1437 | *ErrLDAP(int e) | |
f86504f1 AJ |
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 | ||
915c866f CN |
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) | |
f86504f1 AJ |
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 | ||
6ca7324f | 1495 | debug("Terminating, Signal: %d\n", s); |
f86504f1 AJ |
1496 | exit(0); |
1497 | } | |
1498 | ||
915c866f CN |
1499 | /* |
1500 | * MainSafe() - <argc> <argv> | |
1501 | * | |
1502 | * "Safe" version of main() | |
1503 | * | |
1504 | */ | |
1505 | static int | |
1506 | MainSafe(int argc, char **argv) | |
f86504f1 AJ |
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)); | |
7a545fdb | 1522 | |
f86504f1 | 1523 | InitConf(); |
6ca7324f | 1524 | xstrncpy(edui_conf.program, argv[0], sizeof(edui_conf.program)); |
f86504f1 AJ |
1525 | edui_now = -1; |
1526 | t = -1; | |
f86504f1 AJ |
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 */ | |
7a545fdb | 1554 | debug_enabled = 1; /* Official Squid-3 Debug Mode */ |
f86504f1 AJ |
1555 | break; |
1556 | case '4': | |
1557 | if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6)) | |
7a545fdb | 1558 | edui_conf.mode |= EDUI_MODE_IPV4; /* Don't set mode more than once */ |
f86504f1 AJ |
1559 | break; |
1560 | case '6': | |
1561 | if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6)) | |
7a545fdb | 1562 | edui_conf.mode |= EDUI_MODE_IPV6; /* Don't set mode more than once */ |
f86504f1 AJ |
1563 | break; |
1564 | case 'Z': | |
1565 | if (!(edui_conf.mode & EDUI_MODE_TLS)) | |
7a545fdb | 1566 | edui_conf.mode |= EDUI_MODE_TLS; /* Don't set mode more than once */ |
f86504f1 AJ |
1567 | break; |
1568 | case 'P': | |
1569 | if (!(edui_conf.mode & EDUI_MODE_PERSIST)) | |
7a545fdb | 1570 | edui_conf.mode |= EDUI_MODE_PERSIST; /* Don't set mode more than once */ |
f86504f1 AJ |
1571 | break; |
1572 | case 'v': | |
755494da | 1573 | ++i; /* Set LDAP version */ |
f86504f1 AJ |
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': | |
755494da | 1587 | ++i; /* Set Persistent timeout */ |
f86504f1 AJ |
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': | |
755494da | 1599 | ++i; /* Set Base DN */ |
f86504f1 | 1600 | if (argv[i] != NULL) |
6ca7324f | 1601 | xstrncpy(edui_conf.basedn, argv[i], sizeof(edui_conf.basedn)); |
f86504f1 AJ |
1602 | else { |
1603 | local_printfx("No parameters given for 'b'.\n"); | |
1604 | DisplayUsage(); | |
1605 | return 1; | |
1606 | } | |
1607 | break; | |
1608 | case 'H': | |
755494da | 1609 | ++i; /* Set Hostname */ |
f86504f1 | 1610 | if (argv[i] != NULL) |
6ca7324f | 1611 | xstrncpy(edui_conf.host, argv[i], sizeof(edui_conf.host)); |
f86504f1 AJ |
1612 | else { |
1613 | local_printfx("No parameters given for 'H'.\n"); | |
1614 | DisplayUsage(); | |
1615 | return 1; | |
1616 | } | |
1617 | break; | |
1618 | case 'p': | |
755494da | 1619 | ++i; /* Set port */ |
f86504f1 AJ |
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': | |
755494da | 1629 | ++i; /* Set Bind DN */ |
f86504f1 | 1630 | if (argv[i] != NULL) |
6ca7324f | 1631 | xstrncpy(edui_conf.dn, argv[i], sizeof(edui_conf.dn)); |
f86504f1 AJ |
1632 | else { |
1633 | local_printfx("No parameters given for 'D'.\n"); | |
1634 | DisplayUsage(); | |
1635 | return 1; | |
1636 | } | |
1637 | break; | |
1638 | case 'W': | |
755494da | 1639 | ++i; /* Set Bind PWD */ |
f86504f1 | 1640 | if (argv[i] != NULL) |
6ca7324f | 1641 | xstrncpy(edui_conf.passwd, argv[i], sizeof(edui_conf.passwd)); |
f86504f1 AJ |
1642 | else { |
1643 | local_printfx("No parameters given for 'W'.\n"); | |
1644 | DisplayUsage(); | |
1645 | return 1; | |
1646 | } | |
1647 | break; | |
1648 | case 'F': | |
755494da | 1649 | ++i; /* Set Search Filter */ |
f86504f1 | 1650 | if (argv[i] != NULL) |
6ca7324f | 1651 | xstrncpy(edui_conf.search_filter, argv[i], sizeof(edui_conf.search_filter)); |
f86504f1 AJ |
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': | |
755494da | 1663 | ++i; /* Set Scope Level */ |
f86504f1 AJ |
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; | |
6ca7324f | 1679 | case 'u': |
755494da | 1680 | ++i; /* Set Search Attribute */ |
6ca7324f | 1681 | if (argv[i] != NULL) { |
ab745b44 | 1682 | xstrncpy(edui_conf.attrib, argv[i], sizeof(edui_conf.attrib)); |
6ca7324f AJ |
1683 | } else { |
1684 | local_printfx("No parameters given for 'u'.\n"); | |
1685 | DisplayUsage(); | |
1686 | return 1; | |
1687 | } | |
1688 | break; | |
7a545fdb | 1689 | case '-': /* We got a second '-' ... ignore */ |
f86504f1 AJ |
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 */ | |
6ca7324f | 1706 | xstrncpy(edui_conf.host, "localhost", sizeof(edui_conf.host)); |
f86504f1 AJ |
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)) | |
314b9463 | 1714 | edui_conf.mode |= EDUI_MODE_TLS; /* eDirectory requires TLS mode */ |
f86504f1 AJ |
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') | |
6ca7324f | 1722 | xstrncpy(edui_conf.search_filter, "(&(objectclass=User)(networkAddress=*))", sizeof(edui_conf.search_filter)); |
f86504f1 | 1723 | if (edui_conf.attrib[0] == '\0') |
6ca7324f | 1724 | xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); |
f86504f1 | 1725 | if (edui_conf.basedn[0] == '\0') { |
314b9463 A |
1726 | local_printfx("FATAL: No '-b' option provided (Base DN).\n"); |
1727 | DisplayUsage(); | |
1728 | return 1; | |
f86504f1 | 1729 | } |
f86504f1 AJ |
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); | |
7a545fdb AJ |
1742 | |
1743 | DisplayConf(); | |
1744 | /* Done with arguments */ | |
f86504f1 AJ |
1745 | |
1746 | /* Set elap timer */ | |
1747 | time(&edui_now); | |
1748 | t = edui_now; | |
f86504f1 AJ |
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; | |
f86504f1 AJ |
1757 | t = edui_now; |
1758 | } else | |
1759 | edui_elap = 0; | |
1760 | k = strlen(bufa); | |
9c76c145 | 1761 | /* BINARY DEBUGGING * |
fe1e5c91 | 1762 | local_printfx("while() -> bufa[%" PRIuSIZE "]: %s", k, bufa); |
9c76c145 A |
1763 | for (i = 0; i < k; i++) |
1764 | local_printfx("%02X", bufa[i]); | |
1765 | local_printfx("\n"); | |
1766 | * BINARY DEBUGGING */ | |
f86504f1 AJ |
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)) { | |
6ca7324f AJ |
1778 | debug("while() -> Search group is missing. (required)\n"); |
1779 | local_printfx("ERR (Search Group Required)\n"); | |
f86504f1 AJ |
1780 | continue; |
1781 | } | |
1782 | x = 0; | |
1783 | ||
1784 | /* Open LDAP connection */ | |
1785 | if (!(edui_ldap.status & LDAP_INIT_S)) { | |
1786 | InitLDAP(&edui_ldap); | |
6ca7324f | 1787 | debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS)); |
f86504f1 AJ |
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)) { | |
6ca7324f | 1795 | debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap.idle_time)); |
f86504f1 | 1796 | x = CloseLDAP(&edui_ldap); |
6ca7324f | 1797 | debug("CloseLDAP(-) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
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 */ | |
6ca7324f | 1804 | debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1805 | } else { |
6ca7324f | 1806 | debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf.host, edui_conf.port, ErrLDAP(x)); |
f86504f1 AJ |
1807 | x = SetVerLDAP(&edui_ldap, edui_conf.ver); |
1808 | if (x != LDAP_ERR_SUCCESS) { | |
1809 | /* Failed to set version */ | |
6ca7324f | 1810 | debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1811 | } else |
6ca7324f | 1812 | debug("SetVerLDAP(-, %d) -> %s\n", edui_conf.ver, ErrLDAP(x)); |
f86504f1 AJ |
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 */ | |
6ca7324f | 1821 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 A |
1822 | local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1823 | continue; | |
f86504f1 | 1824 | } else |
6ca7324f | 1825 | debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x)); |
f86504f1 AJ |
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 */ | |
6ca7324f | 1832 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 A |
1833 | local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1834 | continue; | |
f86504f1 | 1835 | } else |
6ca7324f | 1836 | debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x)); |
f86504f1 AJ |
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 */ | |
6ca7324f | 1842 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 A |
1843 | local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1844 | continue; | |
f86504f1 | 1845 | } else |
6ca7324f | 1846 | debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
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 */ | |
6ca7324f | 1854 | debug("ResetLDAP() -> %s\n", ErrLDAP(x)); |
f86504f1 | 1855 | } else |
6ca7324f | 1856 | debug("ResetLDAP() -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1857 | } |
1858 | if (x != LDAP_ERR_SUCCESS) { | |
1859 | /* Everything failed --> ERR */ | |
6ca7324f | 1860 | debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1861 | CloseLDAP(&edui_ldap); |
6ca7324f | 1862 | local_printfx("ERR (General Failure: %s)\n", ErrLDAP(x)); |
f86504f1 AJ |
1863 | continue; |
1864 | } | |
1865 | edui_ldap.err = -1; | |
1866 | /* If we got a group string, split it */ | |
1867 | if (p != NULL) { | |
1868 | /* Split string */ | |
fe1e5c91 | 1869 | debug("StringSplit(%s, ' ', %s, %" PRIuSIZE ")\n", bufa, bufb, sizeof(bufb)); |
7a545fdb | 1870 | i = StringSplit(bufa, ' ', bufb, sizeof(bufb)); |
f86504f1 | 1871 | if (i > 0) { |
fe1e5c91 | 1872 | debug("StringSplit(%s, %s) done. Result: %" PRIuSIZE "\n", bufa, bufb, i); |
f86504f1 AJ |
1873 | /* Got a group to match against */ |
1874 | x = ConvertIP(&edui_ldap, bufb); | |
1875 | if (x < 0) { | |
6ca7324f AJ |
1876 | debug("ConvertIP() -> %s\n", ErrLDAP(x)); |
1877 | local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x)); | |
f86504f1 AJ |
1878 | } else { |
1879 | edui_ldap.err = -1; | |
88f2cf55 | 1880 | debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb, x, edui_ldap.search_ip); |
f86504f1 AJ |
1881 | x = SearchFilterLDAP(&edui_ldap, bufa); |
1882 | if (x < 0) { | |
6ca7324f AJ |
1883 | debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x)); |
1884 | local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 AJ |
1885 | } else { |
1886 | /* Do Search */ | |
1887 | edui_ldap.err = -1; | |
6ca7324f AJ |
1888 | debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa, x); |
1889 | x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib); | |
f86504f1 | 1890 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f AJ |
1891 | debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1892 | local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 AJ |
1893 | } else { |
1894 | edui_ldap.err = -1; | |
6ca7324f | 1895 | debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x)); |
7a545fdb | 1896 | x = SearchIPLDAP(&edui_ldap); |
f86504f1 | 1897 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f AJ |
1898 | debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1899 | local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 | 1900 | } else { |
7a545fdb AJ |
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> */ | |
f86504f1 AJ |
1903 | } |
1904 | } | |
1905 | /* Clear for next query */ | |
7a545fdb | 1906 | memset(bufc, '\0', sizeof(bufc)); |
f86504f1 AJ |
1907 | } |
1908 | } | |
1909 | } else { | |
fe1e5c91 AJ |
1910 | debug("StringSplit() -> Error: %" PRIuSIZE "\n", i); |
1911 | local_printfx("ERR (StringSplit Error %" PRIuSIZE ")\n", i); | |
f86504f1 AJ |
1912 | } |
1913 | } else { | |
1914 | /* No group to match against, only an IP */ | |
1915 | x = ConvertIP(&edui_ldap, bufa); | |
1916 | if (x < 0) { | |
6ca7324f AJ |
1917 | debug("ConvertIP() -> %s\n", ErrLDAP(x)); |
1918 | local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x)); | |
f86504f1 | 1919 | } else { |
88f2cf55 | 1920 | debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa, x, edui_ldap.search_ip); |
f86504f1 AJ |
1921 | /* Do search */ |
1922 | x = SearchFilterLDAP(&edui_ldap, NULL); | |
1923 | if (x < 0) { | |
6ca7324f AJ |
1924 | debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x)); |
1925 | local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 AJ |
1926 | } else { |
1927 | edui_ldap.err = -1; | |
6ca7324f AJ |
1928 | debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x); |
1929 | x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib); | |
f86504f1 | 1930 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f AJ |
1931 | debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(x)); |
1932 | local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 AJ |
1933 | } else { |
1934 | edui_ldap.err = -1; | |
6ca7324f | 1935 | debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x)); |
7a545fdb | 1936 | x = SearchIPLDAP(&edui_ldap); |
f86504f1 | 1937 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f AJ |
1938 | debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
1939 | local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x)); | |
f86504f1 | 1940 | } else { |
7a545fdb AJ |
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> */ | |
f86504f1 AJ |
1943 | } |
1944 | } | |
1945 | } | |
1946 | /* Clear for next query */ | |
7a545fdb | 1947 | memset(bufc, '\0', sizeof(bufc)); |
f86504f1 AJ |
1948 | } |
1949 | } | |
1950 | ||
1951 | /* Clear buffer and close for next data, if not persistent */ | |
1952 | edui_ldap.err = -1; | |
7a545fdb | 1953 | memset(bufa, '\0', sizeof(bufa)); |
f86504f1 AJ |
1954 | if (!(edui_ldap.status & LDAP_PERSIST_S)) { |
1955 | x = CloseLDAP(&edui_ldap); | |
6ca7324f | 1956 | debug("CloseLDAP(-) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1957 | } |
1958 | } | |
1959 | ||
6ca7324f | 1960 | debug("Terminating.\n"); |
915c866f CN |
1961 | return 1; |
1962 | } | |
1963 | ||
1964 | /* "main()" - function */ | |
1965 | int | |
1966 | main(int argc, char **argv) | |
1967 | { | |
2c3d5aec A |
1968 | int x; |
1969 | x = MainSafe(argc, argv); | |
1970 | return x; | |
f86504f1 | 1971 | } |