]>
Commit | Line | Data |
---|---|---|
ca02e0ec | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
ca02e0ec AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | /* | |
10 | * Copyright (C) 2009-2011 Chad E. Naugle | |
f86504f1 AJ |
11 | * |
12 | ******************************************************************************** | |
13 | * | |
14 | * This file is part of ext_edirectory_userip_acl. | |
15 | * | |
16 | * ext_edirectory_userip_acl is free software: you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation, either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * ext_edirectory_userip_acl is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with squid_edir_iplookup. If not, see <http://www.gnu.org/licenses/>. | |
28 | * | |
29 | ******************************************************************************** | |
30 | * | |
915c866f CN |
31 | * ext_edirectory_userip_acl.cc -- Rev 2011-03-28 |
32 | * | |
33 | * - Misc code cleanups using "static", and 64-bit SLES fix for SearchFilterLDAP() | |
f86504f1 AJ |
34 | * |
35 | */ | |
36 | ||
f86504f1 | 37 | /* Squid-3.X includes */ |
f7f3304a | 38 | #include "squid.h" |
079b1d0f | 39 | #include "helper/protocol_defines.h" |
f86504f1 AJ |
40 | #include "rfc1738.h" |
41 | #include "util.h" | |
f86504f1 | 42 | |
f53969cc SM |
43 | #define EDUI_PROGRAM_NAME "ext_edirectory_userip_acl" |
44 | #define EDUI_PROGRAM_VERSION "2.1" | |
f86504f1 AJ |
45 | |
46 | /* System includes */ | |
88f2cf55 | 47 | #ifndef _GNU_SOURCE |
f86504f1 | 48 | #define _GNU_SOURCE |
88f2cf55 AJ |
49 | #endif |
50 | #ifndef __USE_GNU | |
f86504f1 | 51 | #define __USE_GNU |
88f2cf55 | 52 | #endif |
074d6a40 AJ |
53 | #include <cctype> |
54 | #include <cerrno> | |
55 | #include <csignal> | |
074d6a40 AJ |
56 | #include <cstdlib> |
57 | #include <cstring> | |
58 | #include <ctime> | |
f86504f1 AJ |
59 | #ifdef HAVE_ARPA_INET_H |
60 | #include <arpa/inet.h> | |
61 | #endif | |
62 | #define LDAP_DEPRECATED 1 /* Set flag for enabling classic ldap functions */ | |
63 | #ifdef HAVE_LBER_H | |
64 | #include <lber.h> | |
65 | #endif | |
66 | #ifdef HAVE_LDAP_H | |
67 | #include <ldap.h> | |
68 | #endif | |
d08caf47 AJ |
69 | #ifdef HAVE_NETDB_H |
70 | #include <netdb.h> | |
71 | #endif | |
05fdfe0d AR |
72 | #ifdef HAVE_SYS_SOCKET_H |
73 | #include <sys/socket.h> | |
74 | #endif | |
75 | #ifdef HAVE_NETINET_IN_H | |
76 | #include <netinet/in.h> | |
77 | #endif | |
f86504f1 AJ |
78 | |
79 | #ifdef HELPER_INPUT_BUFFER | |
f53969cc | 80 | #define EDUI_MAXLEN HELPER_INPUT_BUFFER |
f86504f1 | 81 | #else |
f53969cc | 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 */ | |
f53969cc SM |
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 | |
f86504f1 AJ |
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]; | |
f53969cc | 118 | char search_filter[EDUI_MAXLEN]; /* Base search_filter that gets copied to edui_ldap_t */ |
f86504f1 AJ |
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 */ | |
2f8abb64 | 144 | #define LDAP_ERR_INIT -4 /* Not initialized */ |
f86504f1 AJ |
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]; | |
f53969cc SM |
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; | |
f53969cc | 173 | unsigned long type; /* Type of bind */ |
f86504f1 AJ |
174 | int ver; |
175 | int scope; | |
f53969cc | 176 | int err; /* LDAP error code */ |
f86504f1 AJ |
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 | ||
2f8abb64 | 393 | /* Initializes program's configuration parameters */ |
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 | * | |
2f8abb64 | 553 | * Initialize LDAP structure for use, zeroing out all variables. |
f86504f1 AJ |
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; | |
f53969cc | 580 | l->err = -1; /* Set error to LDAP_SUCCESS by default */ |
f86504f1 AJ |
581 | l->ver = 0; |
582 | l->idle_time = 0; | |
f53969cc SM |
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; | |
2f8abb64 | 612 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized, or might be in use */ |
f53969cc SM |
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 | |
f53969cc | 620 | l->port = LDAP_PORT; /* Default is port 389 */ |
f86504f1 AJ |
621 | |
622 | #ifdef NETSCAPE_SSL | |
623 | if (l->port == LDAPS_PORT) | |
f53969cc | 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; | |
f53969cc | 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; | |
2f8abb64 | 655 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Connection not initialized */ |
f53969cc | 656 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Connection not open */ |
f86504f1 AJ |
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 | 671 | l->idle_time = 0; |
f53969cc | 672 | l->err = s; /* Set LDAP error code */ |
f86504f1 AJ |
673 | return LDAP_ERR_SUCCESS; |
674 | } else { | |
f53969cc | 675 | l->err = s; /* Set LDAP error code */ |
f86504f1 AJ |
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; | |
2f8abb64 | 692 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
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 */ | |
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; | |
f53969cc | 700 | l->err = x; /* Set LDAP error code */ |
f86504f1 AJ |
701 | return LDAP_ERR_SUCCESS; |
702 | } else { | |
f53969cc | 703 | l->err = x; /* Set LDAP error code */ |
f86504f1 AJ |
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; | |
2f8abb64 | 718 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
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 */ | |
f86504f1 AJ |
722 | |
723 | /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */ | |
724 | if (dn != NULL) { | |
d08caf47 AJ |
725 | if (strlen(dn) >= sizeof(l->dn)) |
726 | return LDAP_ERR_OOB; /* DN too large */ | |
727 | ||
f86504f1 AJ |
728 | if ((l->basedn[0] != '\0') && (strstr(dn, l->basedn) == NULL)) { |
729 | /* We got a basedn, but it's not part of dn */ | |
d08caf47 AJ |
730 | const int x = snprintf(l->dn, sizeof(l->dn)-1, "%s,%s", dn, l->basedn); |
731 | if (x < 0 || static_cast<size_t>(x) >= sizeof(l->dn)) | |
732 | return LDAP_ERR_OOB; /* DN too large */ | |
f86504f1 | 733 | } else |
6ca7324f | 734 | xstrncpy(l->dn, dn, sizeof(l->dn)); |
f86504f1 AJ |
735 | } |
736 | if (pw != NULL) | |
6ca7324f | 737 | xstrncpy(l->passwd, pw, sizeof(l->passwd)); |
f86504f1 | 738 | |
7a545fdb | 739 | /* Type */ |
f86504f1 AJ |
740 | switch (t) { |
741 | case LDAP_AUTH_NONE: | |
742 | l->type = t; | |
743 | break; | |
744 | case LDAP_AUTH_SIMPLE: | |
745 | l->type = t; | |
746 | break; | |
747 | case LDAP_AUTH_SASL: | |
748 | l->type = t; | |
749 | break; | |
67245b81 | 750 | #ifdef LDAP_AUTH_KRBV4 |
f86504f1 AJ |
751 | case LDAP_AUTH_KRBV4: |
752 | l->type = t; | |
753 | break; | |
67245b81 AJ |
754 | #endif |
755 | #ifdef LDAP_AUTH_KRBV41 | |
f86504f1 AJ |
756 | case LDAP_AUTH_KRBV41: |
757 | l->type = t; | |
758 | break; | |
67245b81 AJ |
759 | #endif |
760 | #ifdef LDAP_AUTH_KRBV42 | |
f86504f1 AJ |
761 | case LDAP_AUTH_KRBV42: |
762 | l->type = t; | |
763 | break; | |
67245b81 | 764 | #endif |
f86504f1 | 765 | #ifdef LDAP_AUTH_TLS |
f53969cc | 766 | case LDAP_AUTH_TLS: /* Added for chicken switch to TLS-enabled without using SSL */ |
f86504f1 AJ |
767 | l->type = t; |
768 | break; | |
769 | #endif | |
770 | default: | |
771 | l->type = LDAP_AUTH_NONE; | |
f53969cc | 772 | break; /* Default to anonymous bind */ |
f86504f1 AJ |
773 | } |
774 | ||
775 | /* Bind */ | |
60727a6f | 776 | #if defined(LDAP_AUTH_TLS) && defined(NETSCAPE_SSL) && HAVE_LDAP_START_TLS_S |
f86504f1 AJ |
777 | if (l->type == LDAP_AUTH_TLS) |
778 | s = ldap_start_tls_s(l->lp, NULL, NULL); | |
779 | else | |
780 | #endif | |
781 | s = ldap_bind_s(l->lp, l->dn, l->passwd, l->type); | |
782 | if (s == LDAP_SUCCESS) { | |
f53969cc SM |
783 | l->status |= LDAP_BIND_S; /* Success */ |
784 | l->err = s; /* Set LDAP error code */ | |
f86504f1 AJ |
785 | return LDAP_ERR_SUCCESS; |
786 | } else { | |
f53969cc | 787 | l->err = s; /* Set LDAP error code */ |
f86504f1 AJ |
788 | return LDAP_ERR_FAILED; |
789 | } | |
790 | } | |
791 | ||
d08caf47 AJ |
792 | // XXX: duplicate (partial) of Ip::Address::lookupHostIp |
793 | /** | |
794 | * Convert the IP address string representation in src to | |
795 | * its binary representation. | |
796 | * | |
797 | * \return binary representation of the src IP address. | |
798 | * Must be free'd using freeaddrinfo(). | |
799 | */ | |
800 | static struct addrinfo * | |
801 | makeIpBinary(const char *src) | |
802 | { | |
803 | struct addrinfo want; | |
804 | memset(&want, 0, sizeof(want)); | |
805 | want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups! | |
806 | ||
807 | struct addrinfo *dst = nullptr; | |
808 | if (getaddrinfo(src, nullptr, &want, &dst) != 0) { | |
809 | // not an IP address | |
810 | /* free any memory getaddrinfo() dynamically allocated. */ | |
811 | if (dst) | |
812 | freeaddrinfo(dst); | |
813 | return nullptr; | |
814 | } | |
815 | ||
816 | return dst; | |
817 | } | |
818 | ||
819 | /** | |
820 | * Convert srcLen bytes from src into HEX and store into dst, which | |
821 | * has a maximum content size of dstSize including c-string terminator. | |
822 | * The dst value produced will be a 0-terminated c-string. | |
823 | * | |
824 | * \retval N length of dst written (excluding c-string terminator) | |
825 | * \retval -11 (LDAP_ERR_OOB) buffer overflow detected | |
826 | */ | |
827 | static int | |
828 | makeHexString(char *dst, const int dstSize, const char *src, const int srcLen) | |
829 | { | |
830 | // HEX encoding doubles the amount of bytes/octets copied | |
831 | if ((srcLen*2) >= dstSize) | |
832 | return LDAP_ERR_OOB; // cannot copy that many | |
833 | ||
834 | *dst = 0; | |
835 | ||
836 | for (int k = 0; k < srcLen; ++k) { | |
837 | int c = static_cast<int>(src[k]); | |
838 | if (c < 0) | |
839 | c = c + 256; | |
840 | char hexc[4]; | |
841 | const int hlen = snprintf(hexc, sizeof(hexc), "%02X", c); | |
842 | if (hlen < 0 || static_cast<size_t>(hlen) > sizeof(hexc)) // should be impossible | |
843 | return LDAP_ERR_OOB; | |
844 | strcat(dst, hexc); | |
845 | } | |
846 | return strlen(dst); | |
847 | } | |
848 | ||
f86504f1 AJ |
849 | /* |
850 | * ConvertIP() - <edui_ldap_t> <ip> | |
851 | * | |
852 | * Take an IPv4 address in dot-decimal or IPv6 notation, and convert to 2-digit HEX stored in l->search_ip | |
853 | * This is the networkAddress that we search LDAP for. | |
f86504f1 | 854 | */ |
915c866f CN |
855 | static int |
856 | ConvertIP(edui_ldap_t *l, char *ip) | |
f86504f1 | 857 | { |
f86504f1 | 858 | void *y, *z; |
f86504f1 AJ |
859 | if (l == NULL) return LDAP_ERR_NULL; |
860 | if (ip == NULL) return LDAP_ERR_PARAM; | |
2f8abb64 | 861 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
862 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */ |
863 | if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */ | |
f86504f1 AJ |
864 | |
865 | y = memchr((void *)ip, ':', EDUI_MAXLEN); | |
866 | z = memchr((void *)ip, '.', EDUI_MAXLEN); | |
867 | if ((y != NULL) && (z != NULL)) { | |
314b9463 A |
868 | y = NULL; |
869 | z = NULL; | |
870 | return LDAP_ERR_INVALID; | |
f86504f1 AJ |
871 | } |
872 | if ((y != NULL) && (edui_conf.mode & EDUI_MODE_IPV4)) { | |
314b9463 A |
873 | /* IPv4 Mode forced */ |
874 | return LDAP_ERR_INVALID; | |
875 | } else if (y != NULL) { | |
876 | /* Set IPv6 mode */ | |
314b9463 A |
877 | if (l->status & LDAP_IPV4_S) |
878 | l->status &= ~(LDAP_IPV4_S); | |
879 | if (!(l->status & LDAP_IPV6_S)) | |
880 | l->status |= (LDAP_IPV6_S); | |
881 | y = NULL; | |
f86504f1 AJ |
882 | } |
883 | if ((z != NULL) && (edui_conf.mode & EDUI_MODE_IPV6)) { | |
314b9463 A |
884 | /* IPv6 Mode forced */ |
885 | return LDAP_ERR_INVALID; | |
886 | } else if (z != NULL) { | |
314b9463 A |
887 | /* Set IPv4 mode */ |
888 | if (l->status & LDAP_IPV6_S) | |
889 | l->status &= ~(LDAP_IPV6_S); | |
890 | if (!(l->status & LDAP_IPV4_S)) | |
891 | l->status |= (LDAP_IPV4_S); | |
892 | z = NULL; | |
f86504f1 | 893 | } |
f86504f1 | 894 | |
d08caf47 AJ |
895 | size_t s = LDAP_ERR_INVALID; |
896 | if (struct addrinfo *dst = makeIpBinary(ip)) { | |
897 | if (dst->ai_family == AF_INET6) { | |
898 | struct sockaddr_in6 *sia = reinterpret_cast<struct sockaddr_in6 *>(dst->ai_addr); | |
899 | const char *ia = reinterpret_cast<const char *>(sia->sin6_addr.s6_addr); | |
900 | s = makeHexString(l->search_ip, sizeof(l->search_ip), ia, 16); // IPv6 = 16-byte address | |
901 | ||
902 | } else if (dst->ai_family == AF_INET) { | |
903 | struct sockaddr_in *sia = reinterpret_cast<struct sockaddr_in *>(dst->ai_addr); | |
904 | const char *ia = reinterpret_cast<const char *>(&(sia->sin_addr)); | |
905 | s = makeHexString(l->search_ip, sizeof(l->search_ip), ia, 4); // IPv4 = 4-byte address | |
906 | } // else leave s with LDAP_ERR_INVALID value | |
907 | freeaddrinfo(dst); | |
f86504f1 AJ |
908 | } |
909 | ||
f86504f1 AJ |
910 | return s; |
911 | } | |
912 | ||
913 | /* ResetLDAP() - <edui_ldap_t> | |
914 | * | |
915 | * Resets LDAP connection for next search query. | |
916 | * | |
917 | */ | |
915c866f CN |
918 | static int |
919 | ResetLDAP(edui_ldap_t *l) | |
314b9463 A |
920 | { |
921 | if (l == NULL) return LDAP_ERR_NULL; | |
2f8abb64 | 922 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
314b9463 A |
923 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */ |
924 | if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */ | |
925 | if (!(l->status & LDAP_PERSIST_S)) return LDAP_ERR_PERSIST; /* Not persistent */ | |
926 | ||
927 | /* Cleanup data struct */ | |
314b9463 A |
928 | if (l->status & LDAP_VAL_S) |
929 | l->status &= ~(LDAP_VAL_S); | |
930 | if (l->status & LDAP_SEARCH_S) | |
931 | l->status &= ~(LDAP_SEARCH_S); | |
932 | if (l->status & LDAP_IPV4_S) | |
933 | l->status &= ~(LDAP_IPV4_S); | |
934 | if (l->status & LDAP_IPV6_S) | |
935 | l->status &= ~(LDAP_IPV6_S); | |
936 | if (l->lm != NULL) { | |
937 | ldap_msgfree(l->lm); | |
938 | l->lm = NULL; | |
939 | } | |
940 | if (l->val != NULL) { | |
941 | ldap_value_free_len(l->val); | |
942 | l->val = NULL; | |
943 | } | |
944 | memset(l->search_ip, '\0', sizeof(l->search_ip)); | |
7a545fdb | 945 | *(l->search_filter) = '\0'; |
6ca7324f | 946 | xstrncpy(l->search_filter, edui_conf.search_filter, sizeof(l->search_filter)); |
7a545fdb | 947 | *(l->userid) = '\0'; |
314b9463 A |
948 | if (!(l->status & LDAP_IDLE_S)) |
949 | l->status |= LDAP_IDLE_S; /* Set idle mode */ | |
950 | l->num_ent = 0; | |
951 | l->num_val = 0; | |
314b9463 A |
952 | l->err = LDAP_SUCCESS; |
953 | return LDAP_ERR_SUCCESS; | |
f86504f1 AJ |
954 | } |
955 | ||
956 | /* | |
957 | * SearchFilterLDAP() - <edui_ldap_t> <IP> <group> | |
958 | * | |
959 | * Build LDAP Search Filter string and copy to l->search_filter | |
960 | * | |
961 | */ | |
915c866f CN |
962 | static int |
963 | SearchFilterLDAP(edui_ldap_t *l, char *group) | |
f86504f1 AJ |
964 | { |
965 | size_t i, j, s; | |
966 | int swi; | |
967 | char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], bufc[EDUI_MAXLEN], bufd[EDUI_MAXLEN], bufg[EDUI_MAXLEN]; | |
968 | if (l == NULL) return LDAP_ERR_NULL; | |
2f8abb64 | 969 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
970 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */ |
971 | if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not Bound */ | |
972 | if (l->search_ip[0] == '\0') return LDAP_ERR_DATA; /* Search IP is required */ | |
f86504f1 AJ |
973 | |
974 | /* Zero out if not already */ | |
915c866f CN |
975 | memset(bufa, '\0', sizeof(bufa)); |
976 | // using memset() for 'bufa' fixes the 64-bit issue | |
7a545fdb AJ |
977 | *(bufb) = '\0'; |
978 | *(bufc) = '\0'; | |
979 | *(bufd) = '\0'; | |
980 | *(bufg) = '\0'; | |
f86504f1 | 981 | |
f86504f1 AJ |
982 | s = strlen(l->search_ip); |
983 | bufc[0] = '\134'; | |
984 | swi = 0; | |
985 | j = 1; | |
eb62585f | 986 | for (i = 0; i < s; ++i) { |
f86504f1 AJ |
987 | if (swi == 2) { |
988 | bufc[j] = '\134'; | |
755494da | 989 | ++j; |
f86504f1 | 990 | bufc[j] = l->search_ip[i]; |
755494da | 991 | ++j; |
f86504f1 AJ |
992 | swi = 1; |
993 | } else { | |
994 | bufc[j] = l->search_ip[i]; | |
755494da FC |
995 | ++j; |
996 | ++swi; | |
f86504f1 AJ |
997 | } |
998 | } | |
999 | if (group == NULL) { | |
1000 | /* No groupMembership= to add, yay! */ | |
f86504f1 | 1001 | /* networkAddress */ |
314b9463 | 1002 | if (l->status & LDAP_IPV4_S) { |
d08caf47 AJ |
1003 | const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", bufc, bufc); |
1004 | if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd)) | |
1005 | return LDAP_ERR_OOB; | |
1006 | ||
f86504f1 | 1007 | } else if (l->status & LDAP_IPV6_S) { |
d08caf47 AJ |
1008 | const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s)", bufc, bufc); |
1009 | if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd)) | |
1010 | return LDAP_ERR_OOB; | |
1011 | } | |
1012 | const int x = snprintf(bufa, sizeof(bufa), "(&%s(|(networkAddress=1\\23%s)%s))", edui_conf.search_filter, bufc, bufd); | |
1013 | if (x < 0 || static_cast<size_t>(x) >= sizeof(bufa)) | |
1014 | return LDAP_ERR_OOB; | |
1015 | ||
f86504f1 AJ |
1016 | } else { |
1017 | /* Needs groupMembership= to add... */ | |
f86504f1 | 1018 | /* groupMembership -- NOTE: Squid *MUST* provide "cn=" from squid.conf */ |
f86504f1 | 1019 | if ((l->basedn[0] != '\0') && (strstr(group, l->basedn) == NULL)) { |
d08caf47 AJ |
1020 | const int ln = snprintf(bufg, sizeof(bufg), ",%s", l->basedn); |
1021 | if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd)) | |
1022 | return LDAP_ERR_OOB; | |
f86504f1 | 1023 | } |
f86504f1 | 1024 | /* networkAddress */ |
314b9463 | 1025 | if (l->status & LDAP_IPV4_S) { |
d08caf47 AJ |
1026 | const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s)", bufc, bufc); |
1027 | if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd)) | |
1028 | return LDAP_ERR_OOB; | |
f86504f1 | 1029 | } else if (l->status & LDAP_IPV6_S) { |
d08caf47 AJ |
1030 | const int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s)", bufc, bufc); |
1031 | if (ln < 0 || static_cast<size_t>(ln) >= sizeof(bufd)) | |
1032 | return LDAP_ERR_OOB; | |
1033 | } | |
1034 | const int x = snprintf(bufa, sizeof(bufa), "(&(&%s(groupMembership=%s%s)(|(networkAddress=1\\23%s)%s)))", edui_conf.search_filter, group, bufg, bufc, bufd); | |
1035 | if (x < 0 || static_cast<size_t>(x) >= sizeof(bufa)) | |
1036 | return LDAP_ERR_OOB; | |
f86504f1 AJ |
1037 | } |
1038 | s = strlen(bufa); | |
bcdce702 | 1039 | xstrncpy(l->search_filter, bufa, sizeof(l->search_filter)); |
f86504f1 AJ |
1040 | return s; |
1041 | } | |
1042 | ||
1043 | /* | |
1044 | * SearchLDAP() - <edui_ldap_t> <scope> <filter> <attrib> | |
1045 | * | |
1046 | * Initate LDAP query, under <scope> levels, filtering matches with <filter> and optionally <attrib> | |
1047 | * <attrib> will generally be networkAddress ... | |
1048 | * | |
1049 | */ | |
915c866f CN |
1050 | static int |
1051 | SearchLDAP(edui_ldap_t *l, int scope, char *filter, char **attrs) | |
f86504f1 AJ |
1052 | { |
1053 | int s; | |
1054 | char ft[EDUI_MAXLEN]; | |
1055 | if (l == NULL) return LDAP_ERR_NULL; | |
f53969cc | 1056 | if ((scope < 0) || (filter == NULL)) return LDAP_ERR_PARAM; /* If attrs is NULL, then all attrs will return */ |
f86504f1 | 1057 | if (l->lp == NULL) return LDAP_ERR_POINTER; |
2f8abb64 | 1058 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
1059 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */ |
1060 | if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */ | |
1061 | if (l->status & LDAP_SEARCH_S) return LDAP_ERR_SEARCHED; /* Already searching */ | |
1062 | if (l->basedn[0] == '\0') return LDAP_ERR_DATA; /* We require a basedn */ | |
f86504f1 | 1063 | if (l->lm != NULL) |
f53969cc | 1064 | ldap_msgfree(l->lm); /* Make sure l->lm is empty */ |
f86504f1 | 1065 | |
0fbf9a8f | 1066 | xstrncpy(ft, filter, sizeof(ft)); |
f86504f1 AJ |
1067 | |
1068 | /* We have a binded connection, with a free l->lm, so let's get this done */ | |
1069 | switch (scope) { | |
1070 | case 0: | |
1071 | s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_BASE, ft, attrs, 0, &(l->lm)); | |
1072 | break; | |
1073 | case 1: | |
1074 | s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm)); | |
1075 | break; | |
1076 | case 2: | |
1077 | s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_SUBTREE, ft, attrs, 0, &(l->lm)); | |
1078 | break; | |
1079 | default: | |
6ca7324f AJ |
1080 | /* Only search ONE by default */ |
1081 | s = ldap_search_s(l->lp, l->basedn, LDAP_SCOPE_ONELEVEL, ft, attrs, 0, &(l->lm)); | |
f86504f1 AJ |
1082 | break; |
1083 | } | |
1084 | if (s == LDAP_SUCCESS) { | |
f53969cc | 1085 | l->status |= (LDAP_SEARCH_S); /* Mark as searched */ |
f86504f1 | 1086 | l->err = s; |
f53969cc SM |
1087 | l->idle_time = 0; /* Connection in use, reset idle timer */ |
1088 | l->num_ent = ldap_count_entries(l->lp, l->lm); /* Counted */ | |
f86504f1 AJ |
1089 | return LDAP_ERR_SUCCESS; |
1090 | } else { | |
1091 | l->err = s; | |
1092 | l->num_ent = (-1); | |
1093 | return LDAP_ERR_FAILED; | |
1094 | } | |
1095 | } | |
1096 | ||
1097 | /* | |
7a545fdb | 1098 | * SearchIPLDAP() - <edui_ldap_t> |
f86504f1 AJ |
1099 | * |
1100 | * Scan LDAP and get all networkAddress Values, and see if they match l->search_ip | |
1101 | * Actual IP matching routine for eDirectory | |
1102 | * | |
1103 | */ | |
915c866f CN |
1104 | static int |
1105 | SearchIPLDAP(edui_ldap_t *l) | |
f86504f1 AJ |
1106 | { |
1107 | ber_len_t i, x; | |
d08caf47 AJ |
1108 | ber_len_t j; |
1109 | ber_len_t z; | |
1110 | char bufa[EDUI_MAXLEN]; | |
1111 | char bufb[EDUI_MAXLEN]; | |
f86504f1 | 1112 | LDAPMessage *ent; |
f86504f1 | 1113 | if (l == NULL) return LDAP_ERR_NULL; |
f86504f1 | 1114 | if (l->lp == NULL) return LDAP_ERR_POINTER; |
2f8abb64 | 1115 | if (!(l->status & LDAP_INIT_S)) return LDAP_ERR_INIT; /* Not initialized */ |
f53969cc SM |
1116 | if (!(l->status & LDAP_OPEN_S)) return LDAP_ERR_OPEN; /* Not open */ |
1117 | if (!(l->status & LDAP_BIND_S)) return LDAP_ERR_BIND; /* Not bound */ | |
1118 | if (!(l->status & LDAP_SEARCH_S)) return LDAP_ERR_NOT_SEARCHED; /* Not searched */ | |
9c76c145 A |
1119 | if (l->num_ent <= 0) { |
1120 | debug("l->num_ent: %d\n", l->num_ent); | |
f53969cc | 1121 | return LDAP_ERR_DATA; /* No entries found */ |
7a545fdb | 1122 | } |
f86504f1 | 1123 | if (l->val != NULL) |
f53969cc | 1124 | ldap_value_free_len(l->val); /* Clear data before populating */ |
f86504f1 AJ |
1125 | l->num_val = 0; |
1126 | if (l->status & LDAP_VAL_S) | |
f53969cc | 1127 | l->status &= ~(LDAP_VAL_S); /* Clear VAL bit */ |
f86504f1 | 1128 | if (edui_conf.attrib[0] == '\0') |
f53969cc | 1129 | xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); /* Make sure edui_conf.attrib is set */ |
f86504f1 AJ |
1130 | |
1131 | /* Sift through entries */ | |
9d70add4 | 1132 | struct berval **ber = NULL; |
f86504f1 AJ |
1133 | for (ent = ldap_first_entry(l->lp, l->lm); ent != NULL; ent = ldap_next_entry(l->lp, ent)) { |
1134 | l->val = ldap_get_values_len(l->lp, ent, "networkAddress"); | |
f53969cc | 1135 | ber = ldap_get_values_len(l->lp, ent, edui_conf.attrib); /* edui_conf.attrib is the <userid> mapping */ |
f86504f1 | 1136 | if (l->val != NULL) { |
f53969cc | 1137 | x = ldap_count_values_len(l->val); /* We got x values ... */ |
f86504f1 AJ |
1138 | l->num_val = x; |
1139 | if (x > 0) { | |
1140 | /* Display all values */ | |
eb62585f | 1141 | for (i = 0; i < x; ++i) { |
f86504f1 AJ |
1142 | j = l->val[i]->bv_len; |
1143 | memcpy(bufa, l->val[i]->bv_val, j); | |
7a545fdb | 1144 | z = BinarySplit(bufa, j, '#', bufb, sizeof(bufb)); |
9c76c145 | 1145 | /* BINARY DEBUGGING * |
f53969cc SM |
1146 | local_printfx("value[%" PRIuSIZE "]: BinarySplit(", (size_t) i); |
1147 | for (k = 0; k < z; ++k) { | |
1148 | c = (int) bufb[k]; | |
1149 | if (c < 0) | |
1150 | c = c + 256; | |
1151 | local_printfx("%02X", c); | |
1152 | } | |
1153 | local_printfx(", "); | |
1154 | for (k = 0; k < (j - z - 1); ++k) { | |
1155 | c = (int) bufa[k]; | |
1156 | if (c < 0) | |
1157 | c = c + 256; | |
1158 | local_printfx("%02X", c); | |
1159 | } | |
1160 | local_printfx("): %" PRIuSIZE "\n", (size_t) z); | |
9c76c145 | 1161 | * BINARY DEBUGGING */ |
f86504f1 | 1162 | z = j - z - 1; |
9c76c145 | 1163 | j = atoi(bufb); |
7a545fdb | 1164 | if (j == 1) { |
9c76c145 | 1165 | /* IPv4 address (eDirectory 8.7 and below) */ |
f86504f1 AJ |
1166 | /* bufa is the address, just compare it */ |
1167 | if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S)) | |
f53969cc | 1168 | break; /* Not looking for IPv4 */ |
d08caf47 AJ |
1169 | const int blen = makeHexString(bufb, sizeof(bufb), bufa, z); |
1170 | if (blen < 0) | |
1171 | return blen; | |
f86504f1 | 1172 | /* Compare value with IP */ |
d08caf47 | 1173 | if (memcmp(l->search_ip, bufb, blen) == 0) { |
f86504f1 AJ |
1174 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1175 | z = ldap_count_values_len(ber); | |
eb62585f | 1176 | for (j = 0; j < z; ++j) { |
7a545fdb AJ |
1177 | // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len))); |
1178 | xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid)); | |
9c76c145 A |
1179 | /* Using bv_len of min() breaks the result by 2 chars */ |
1180 | } | |
f86504f1 AJ |
1181 | ldap_value_free_len(l->val); |
1182 | l->val = NULL; | |
1183 | ldap_value_free_len(ber); | |
1184 | ber = NULL; | |
1185 | l->num_val = 0; | |
1186 | l->err = LDAP_SUCCESS; | |
1187 | l->status &= ~(LDAP_SEARCH_S); | |
f53969cc | 1188 | return LDAP_ERR_SUCCESS; /* We got our userid */ |
f86504f1 AJ |
1189 | } |
1190 | /* Not matched, continue */ | |
9c76c145 A |
1191 | } else if ((j == 8) || (j == 9)) { |
1192 | /* IPv4 (UDP/TCP) address (eDirectory 8.8 and higher) */ | |
f86504f1 AJ |
1193 | /* bufa + 2 is the address (skip 2 digit port) */ |
1194 | if (!(l->status & LDAP_IPV4_S) || (l->status & LDAP_IPV6_S)) | |
f53969cc | 1195 | break; /* Not looking for IPv4 */ |
d08caf47 AJ |
1196 | const int blen = makeHexString(bufb, sizeof(bufb), &bufa[2], z); |
1197 | if (blen < 0) | |
1198 | return blen; | |
f86504f1 | 1199 | /* Compare value with IP */ |
d08caf47 | 1200 | if (memcmp(l->search_ip, bufb, blen) == 0) { |
f86504f1 AJ |
1201 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1202 | z = ldap_count_values_len(ber); | |
eb62585f | 1203 | for (j = 0; j < z; ++j) { |
7a545fdb AJ |
1204 | // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len))); |
1205 | xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid)); | |
915c866f | 1206 | /* Using bv_len of min() breaks the result by 2 chars */ |
2c3d5aec | 1207 | } |
f86504f1 AJ |
1208 | ldap_value_free_len(l->val); |
1209 | l->val = NULL; | |
1210 | ldap_value_free_len(ber); | |
1211 | ber = NULL; | |
1212 | l->num_val = 0; | |
1213 | l->err = LDAP_SUCCESS; | |
1214 | l->status &= ~(LDAP_SEARCH_S); | |
f53969cc | 1215 | return LDAP_ERR_SUCCESS; /* We got our userid */ |
f86504f1 AJ |
1216 | } |
1217 | /* Not matched, continue */ | |
9c76c145 | 1218 | } else if ((j == 10) || (j == 11)) { |
7a545fdb | 1219 | /* IPv6 (UDP/TCP) address (eDirectory 8.8 and higher) */ |
f86504f1 AJ |
1220 | /* bufa + 2 is the address (skip 2 digit port) */ |
1221 | if (!(l->status & LDAP_IPV6_S)) | |
f53969cc | 1222 | break; /* Not looking for IPv6 */ |
d08caf47 AJ |
1223 | const int blen = makeHexString(bufb, sizeof(bufb), &bufa[2], z); |
1224 | if (blen < 0) | |
1225 | return blen; | |
f86504f1 | 1226 | /* Compare value with IP */ |
d08caf47 | 1227 | if (memcmp(l->search_ip, bufb, blen) == 0) { |
f86504f1 AJ |
1228 | /* We got a match! - Scan 'ber' for 'cn' values */ |
1229 | z = ldap_count_values_len(ber); | |
eb62585f | 1230 | for (j = 0; j < z; ++j) { |
7a545fdb AJ |
1231 | // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len))); |
1232 | xstrncpy(l->userid, ber[j]->bv_val, sizeof(l->userid)); | |
915c866f | 1233 | /* Using bv_len of min() breaks the result by 2 chars */ |
2c3d5aec | 1234 | } |
f86504f1 AJ |
1235 | ldap_value_free_len(l->val); |
1236 | l->val = NULL; | |
1237 | ldap_value_free_len(ber); | |
1238 | ber = NULL; | |
1239 | l->num_val = 0; | |
1240 | l->err = LDAP_SUCCESS; | |
1241 | l->status &= ~(LDAP_SEARCH_S); | |
f53969cc | 1242 | return LDAP_ERR_SUCCESS; /* We got our userid */ |
f86504f1 AJ |
1243 | } |
1244 | /* Not matched, continue */ | |
9c76c145 | 1245 | } |
f53969cc | 1246 | // else { |
9c76c145 | 1247 | /* Others are unsupported */ |
7a545fdb | 1248 | // } |
f86504f1 AJ |
1249 | } |
1250 | if (ber != NULL) { | |
1251 | ldap_value_free_len(ber); | |
1252 | ber = NULL; | |
1253 | } | |
1254 | } | |
1255 | ldap_value_free_len(l->val); | |
1256 | l->val = NULL; | |
1257 | } | |
1258 | if (ber != NULL) { | |
1259 | ldap_value_free_len(ber); | |
1260 | ber = NULL; | |
1261 | } | |
1262 | /* Attr not found, continue */ | |
1263 | } | |
1264 | /* No entries found using given attr */ | |
1265 | if (l->val != NULL) { | |
1266 | ldap_value_free_len(l->val); | |
1267 | l->val = NULL; | |
1268 | } | |
f86504f1 AJ |
1269 | if (l->lm != NULL) { |
1270 | ldap_msgfree(l->lm); | |
1271 | l->lm = NULL; | |
1272 | } | |
1273 | l->num_ent = 0; | |
1274 | l->num_val = 0; | |
1275 | l->err = LDAP_NO_SUCH_OBJECT; | |
1276 | l->status &= ~(LDAP_SEARCH_S); | |
f53969cc | 1277 | return LDAP_ERR_NOTFOUND; /* Not found ... Sorry :) */ |
f86504f1 AJ |
1278 | } |
1279 | ||
915c866f CN |
1280 | /* |
1281 | * ErrLDAP() - <errno> | |
1282 | * | |
1283 | * Returns error description of error code | |
1284 | * | |
1285 | */ | |
1286 | const char | |
1287 | *ErrLDAP(int e) | |
f86504f1 AJ |
1288 | { |
1289 | switch (e) { | |
1290 | case LDAP_ERR_NULL: | |
1291 | return "Null pointer provided"; | |
1292 | case LDAP_ERR_POINTER: | |
1293 | return "Null LDAP pointer"; | |
1294 | case LDAP_ERR_PARAM: | |
2f8abb64 | 1295 | return "Null or Missing parameter(s)"; |
f86504f1 | 1296 | case LDAP_ERR_INIT: |
2f8abb64 | 1297 | return "LDAP data not initialized"; |
f86504f1 AJ |
1298 | case LDAP_ERR_OPEN: |
1299 | return "LDAP connection is not active"; | |
1300 | case LDAP_ERR_CONNECT: | |
1301 | return "Unable to connect to LDAP host"; | |
1302 | case LDAP_ERR_BIND: | |
1303 | return "LDAP connection is not bound"; | |
1304 | case LDAP_ERR_SEARCHED: | |
1305 | return "LDAP connection has already been searched"; | |
1306 | case LDAP_ERR_NOT_SEARCHED: | |
1307 | return "LDAP connection has not been searched"; | |
1308 | case LDAP_ERR_INVALID: | |
2f8abb64 | 1309 | return "Invalid parameters"; |
f86504f1 | 1310 | case LDAP_ERR_OOB: |
2f8abb64 | 1311 | return "Parameter is out of bounds"; |
f86504f1 AJ |
1312 | case LDAP_ERR_PERSIST: |
1313 | return "Persistent mode is not active"; | |
1314 | case LDAP_ERR_DATA: | |
1315 | return "Required data has not been found"; | |
1316 | case LDAP_ERR_NOTFOUND: | |
1317 | return "Item or object has not been found"; | |
1318 | case LDAP_ERR_OTHER: | |
61beade2 | 1319 | return "An unknown error has occurred"; |
f86504f1 AJ |
1320 | case LDAP_ERR_FAILED: |
1321 | return "Operation has failed"; | |
1322 | case LDAP_ERR_SUCCESS: | |
1323 | return "Operation is successful"; | |
1324 | default: | |
61beade2 | 1325 | return "An unknown error has occurred"; |
f86504f1 AJ |
1326 | } |
1327 | } | |
1328 | ||
915c866f CN |
1329 | /* |
1330 | * SigTrap() - <signal> | |
1331 | * | |
1332 | * Traps signal codes by number, and gracefully shuts down. | |
1333 | * | |
1334 | */ | |
1335 | extern "C" void | |
1336 | SigTrap(int s) | |
f86504f1 AJ |
1337 | { |
1338 | if (!(edui_conf.mode & EDUI_MODE_KILL)) | |
1339 | edui_conf.mode |= EDUI_MODE_KILL; | |
1340 | ||
1341 | /* Clean Up */ | |
1342 | if (edui_ldap.status & LDAP_OPEN_S) | |
1343 | CloseLDAP(&edui_ldap); | |
1344 | ||
6ca7324f | 1345 | debug("Terminating, Signal: %d\n", s); |
24885773 | 1346 | exit(EXIT_SUCCESS); |
f86504f1 AJ |
1347 | } |
1348 | ||
915c866f CN |
1349 | /* |
1350 | * MainSafe() - <argc> <argv> | |
1351 | * | |
1352 | * "Safe" version of main() | |
1353 | * | |
1354 | */ | |
1355 | static int | |
1356 | MainSafe(int argc, char **argv) | |
f86504f1 AJ |
1357 | { |
1358 | char bufa[EDUI_MAXLEN], bufb[EDUI_MAXLEN], *p = NULL; | |
1359 | char bufc[EDUI_MAXLEN]; | |
1360 | char sfmod[EDUI_MAXLEN]; | |
1361 | int x; | |
1362 | size_t i, j, s, k; | |
1363 | time_t t; | |
1364 | struct sigaction sv; | |
1365 | ||
1366 | /* Init */ | |
1367 | k = (size_t) argc; | |
1368 | memset(bufa, '\0', sizeof(bufa)); | |
1369 | memset(bufb, '\0', sizeof(bufb)); | |
1370 | memset(bufc, '\0', sizeof(bufc)); | |
1371 | memset(sfmod, '\0', sizeof(sfmod)); | |
3ea9e875 | 1372 | memset(&sv, 0, sizeof(sv)); |
7a545fdb | 1373 | |
f86504f1 | 1374 | InitConf(); |
6ca7324f | 1375 | xstrncpy(edui_conf.program, argv[0], sizeof(edui_conf.program)); |
f86504f1 AJ |
1376 | edui_now = -1; |
1377 | t = -1; | |
f86504f1 AJ |
1378 | |
1379 | /* Scan args */ | |
1380 | if (k > 1) { | |
eb62585f | 1381 | for (i = 1; i < k; ++i) { |
f86504f1 AJ |
1382 | /* Classic / novelty usage schemes */ |
1383 | if (!strcmp(argv[i], "--help")) { | |
1384 | DisplayUsage(); | |
1385 | return 1; | |
1386 | } else if (!strcmp(argv[i], "--usage")) { | |
1387 | DisplayUsage(); | |
1388 | return 1; | |
1389 | } else if (!strcmp(argv[i], "--version")) { | |
1390 | DisplayVersion(); | |
1391 | return 1; | |
1392 | } else if (argv[i][0] == '-') { | |
1393 | s = strlen(argv[i]); | |
eb62585f | 1394 | for (j = 1; j < s; ++j) { |
f86504f1 AJ |
1395 | switch (argv[i][j]) { |
1396 | case 'h': | |
1397 | DisplayUsage(); | |
1398 | return 1; | |
1399 | case 'V': | |
1400 | DisplayVersion(); | |
1401 | return 1; | |
1402 | case 'd': | |
1403 | if (!(edui_conf.mode & EDUI_MODE_DEBUG)) | |
f53969cc SM |
1404 | edui_conf.mode |= EDUI_MODE_DEBUG; /* Don't set mode more than once */ |
1405 | debug_enabled = 1; /* Official Squid-3 Debug Mode */ | |
f86504f1 AJ |
1406 | break; |
1407 | case '4': | |
1408 | if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6)) | |
f53969cc | 1409 | edui_conf.mode |= EDUI_MODE_IPV4; /* Don't set mode more than once */ |
f86504f1 AJ |
1410 | break; |
1411 | case '6': | |
1412 | if (!(edui_conf.mode & EDUI_MODE_IPV4) || !(edui_conf.mode & EDUI_MODE_IPV6)) | |
f53969cc | 1413 | edui_conf.mode |= EDUI_MODE_IPV6; /* Don't set mode more than once */ |
f86504f1 AJ |
1414 | break; |
1415 | case 'Z': | |
1416 | if (!(edui_conf.mode & EDUI_MODE_TLS)) | |
f53969cc | 1417 | edui_conf.mode |= EDUI_MODE_TLS; /* Don't set mode more than once */ |
f86504f1 AJ |
1418 | break; |
1419 | case 'P': | |
1420 | if (!(edui_conf.mode & EDUI_MODE_PERSIST)) | |
f53969cc | 1421 | edui_conf.mode |= EDUI_MODE_PERSIST; /* Don't set mode more than once */ |
f86504f1 AJ |
1422 | break; |
1423 | case 'v': | |
f53969cc | 1424 | ++i; /* Set LDAP version */ |
f86504f1 AJ |
1425 | if (argv[i] != NULL) { |
1426 | edui_conf.ver = atoi(argv[i]); | |
1427 | if (edui_conf.ver < 1) | |
1428 | edui_conf.ver = 1; | |
1429 | else if (edui_conf.ver > 3) | |
1430 | edui_conf.ver = 3; | |
1431 | } else { | |
1432 | local_printfx("No parameters given for 'v'.\n"); | |
1433 | DisplayUsage(); | |
1434 | return 1; | |
1435 | } | |
1436 | break; | |
1437 | case 't': | |
f53969cc | 1438 | ++i; /* Set Persistent timeout */ |
f86504f1 AJ |
1439 | if (argv[i] != NULL) { |
1440 | edui_conf.persist_timeout = atoi(argv[i]); | |
1441 | if (edui_conf.persist_timeout < 0) | |
1442 | edui_conf.persist_timeout = 0; | |
1443 | } else { | |
1444 | local_printfx("No parameters given for 't'.\n"); | |
1445 | DisplayUsage(); | |
1446 | return 1; | |
1447 | } | |
1448 | break; | |
1449 | case 'b': | |
f53969cc | 1450 | ++i; /* Set Base DN */ |
f86504f1 | 1451 | if (argv[i] != NULL) |
6ca7324f | 1452 | xstrncpy(edui_conf.basedn, argv[i], sizeof(edui_conf.basedn)); |
f86504f1 AJ |
1453 | else { |
1454 | local_printfx("No parameters given for 'b'.\n"); | |
1455 | DisplayUsage(); | |
1456 | return 1; | |
1457 | } | |
1458 | break; | |
1459 | case 'H': | |
f53969cc | 1460 | ++i; /* Set Hostname */ |
f86504f1 | 1461 | if (argv[i] != NULL) |
6ca7324f | 1462 | xstrncpy(edui_conf.host, argv[i], sizeof(edui_conf.host)); |
f86504f1 AJ |
1463 | else { |
1464 | local_printfx("No parameters given for 'H'.\n"); | |
1465 | DisplayUsage(); | |
1466 | return 1; | |
1467 | } | |
1468 | break; | |
1469 | case 'p': | |
f53969cc | 1470 | ++i; /* Set port */ |
f86504f1 AJ |
1471 | if (argv[i] != NULL) |
1472 | edui_conf.port = atoi(argv[i]); | |
1473 | else { | |
1474 | local_printfx("No parameters given for 'p'.\n"); | |
1475 | DisplayUsage(); | |
1476 | return 1; | |
1477 | } | |
1478 | break; | |
1479 | case 'D': | |
f53969cc | 1480 | ++i; /* Set Bind DN */ |
f86504f1 | 1481 | if (argv[i] != NULL) |
6ca7324f | 1482 | xstrncpy(edui_conf.dn, argv[i], sizeof(edui_conf.dn)); |
f86504f1 AJ |
1483 | else { |
1484 | local_printfx("No parameters given for 'D'.\n"); | |
1485 | DisplayUsage(); | |
1486 | return 1; | |
1487 | } | |
1488 | break; | |
1489 | case 'W': | |
f53969cc | 1490 | ++i; /* Set Bind PWD */ |
f86504f1 | 1491 | if (argv[i] != NULL) |
6ca7324f | 1492 | xstrncpy(edui_conf.passwd, argv[i], sizeof(edui_conf.passwd)); |
f86504f1 AJ |
1493 | else { |
1494 | local_printfx("No parameters given for 'W'.\n"); | |
1495 | DisplayUsage(); | |
1496 | return 1; | |
1497 | } | |
1498 | break; | |
1499 | case 'F': | |
f53969cc | 1500 | ++i; /* Set Search Filter */ |
f86504f1 | 1501 | if (argv[i] != NULL) |
6ca7324f | 1502 | xstrncpy(edui_conf.search_filter, argv[i], sizeof(edui_conf.search_filter)); |
f86504f1 AJ |
1503 | else { |
1504 | local_printfx("No parameters given for 'F'.\n"); | |
1505 | DisplayUsage(); | |
1506 | return 1; | |
1507 | } | |
1508 | break; | |
1509 | case 'G': | |
1510 | if (!(edui_conf.mode & EDUI_MODE_GROUP)) | |
f53969cc | 1511 | edui_conf.mode |= EDUI_MODE_GROUP; /* Don't set mode more than once */ |
f86504f1 AJ |
1512 | break; |
1513 | case 's': | |
f53969cc | 1514 | ++i; /* Set Scope Level */ |
f86504f1 AJ |
1515 | if (argv[i] != NULL) { |
1516 | if (!strncmp(argv[i], "base", 4)) | |
1517 | edui_conf.scope = 0; | |
1518 | else if (!strncmp(argv[i], "one", 4)) | |
1519 | edui_conf.scope = 1; | |
1520 | else if (!strncmp(argv[i], "sub", 4)) | |
1521 | edui_conf.scope = 2; | |
1522 | else | |
f53969cc | 1523 | edui_conf.scope = 1; /* Default is 'one' */ |
f86504f1 AJ |
1524 | } else { |
1525 | local_printfx("No parameters given for 's'.\n"); | |
1526 | DisplayUsage(); | |
1527 | return 1; | |
1528 | } | |
1529 | break; | |
6ca7324f | 1530 | case 'u': |
f53969cc | 1531 | ++i; /* Set Search Attribute */ |
6ca7324f | 1532 | if (argv[i] != NULL) { |
ab745b44 | 1533 | xstrncpy(edui_conf.attrib, argv[i], sizeof(edui_conf.attrib)); |
6ca7324f AJ |
1534 | } else { |
1535 | local_printfx("No parameters given for 'u'.\n"); | |
1536 | DisplayUsage(); | |
1537 | return 1; | |
1538 | } | |
1539 | break; | |
f53969cc | 1540 | case '-': /* We got a second '-' ... ignore */ |
f86504f1 AJ |
1541 | break; |
1542 | default: | |
1543 | local_printfx("Invalid parameter - '%c'.\n", argv[i][j]); | |
1544 | break; | |
1545 | } | |
1546 | } | |
1547 | } else { | |
1548 | /* Incorrect parameter, display usage */ | |
1549 | DisplayUsage(); | |
1550 | return 1; | |
1551 | } | |
1552 | } | |
1553 | } | |
1554 | ||
2f8abb64 | 1555 | /* Set predefined required parameters if none are given, localhost:LDAP_PORT, etc */ |
f53969cc | 1556 | if (edui_conf.host[0] == '\0') /* Default to localhost */ |
6ca7324f | 1557 | xstrncpy(edui_conf.host, "localhost", sizeof(edui_conf.host)); |
f86504f1 | 1558 | if (edui_conf.port < 0) |
f53969cc | 1559 | edui_conf.port = LDAP_PORT; /* Default: LDAP_PORT */ |
f86504f1 | 1560 | if ((edui_conf.mode & EDUI_MODE_IPV4) && (edui_conf.mode & EDUI_MODE_IPV6)) |
f53969cc | 1561 | edui_conf.mode &= ~(EDUI_MODE_IPV6); /* Default to IPv4 */ |
f86504f1 AJ |
1562 | if (edui_conf.ver < 0) |
1563 | edui_conf.ver = 2; | |
1564 | if (!(edui_conf.mode & EDUI_MODE_TLS)) | |
f53969cc | 1565 | edui_conf.mode |= EDUI_MODE_TLS; /* eDirectory requires TLS mode */ |
f86504f1 | 1566 | if ((edui_conf.mode & EDUI_MODE_TLS) && (edui_conf.ver < 3)) |
f53969cc | 1567 | edui_conf.ver = 3; /* TLS requires version 3 */ |
f86504f1 | 1568 | if (edui_conf.persist_timeout < 0) |
f53969cc | 1569 | edui_conf.persist_timeout = 600; /* Default: 600 seconds (10 minutes) */ |
f86504f1 | 1570 | if (edui_conf.scope < 0) |
f53969cc | 1571 | edui_conf.scope = 1; /* Default: one */ |
f86504f1 | 1572 | if (edui_conf.search_filter[0] == '\0') |
6ca7324f | 1573 | xstrncpy(edui_conf.search_filter, "(&(objectclass=User)(networkAddress=*))", sizeof(edui_conf.search_filter)); |
f86504f1 | 1574 | if (edui_conf.attrib[0] == '\0') |
6ca7324f | 1575 | xstrncpy(edui_conf.attrib, "cn", sizeof(edui_conf.attrib)); |
f86504f1 | 1576 | if (edui_conf.basedn[0] == '\0') { |
314b9463 A |
1577 | local_printfx("FATAL: No '-b' option provided (Base DN).\n"); |
1578 | DisplayUsage(); | |
1579 | return 1; | |
f86504f1 | 1580 | } |
f86504f1 AJ |
1581 | /* Trap the following signals */ |
1582 | sigemptyset(&sv.sa_mask); | |
1583 | sv.sa_handler = SigTrap; | |
1584 | sigaction(SIGTERM, &sv, NULL); | |
1585 | sv.sa_handler = SigTrap; | |
1586 | sigaction(SIGHUP, &sv, NULL); | |
1587 | sv.sa_handler = SigTrap; | |
1588 | sigaction(SIGABRT, &sv, NULL); | |
1589 | sv.sa_handler = SigTrap; | |
1590 | sigaction(SIGINT, &sv, NULL); | |
1591 | sv.sa_handler = SigTrap; | |
1592 | sigaction(SIGSEGV, &sv, NULL); | |
7a545fdb AJ |
1593 | |
1594 | DisplayConf(); | |
1595 | /* Done with arguments */ | |
f86504f1 AJ |
1596 | |
1597 | /* Set elap timer */ | |
1598 | time(&edui_now); | |
1599 | t = edui_now; | |
f86504f1 AJ |
1600 | /* Main loop -- Waits for stdin input before action */ |
1601 | while (fgets(bufa, sizeof(bufa), stdin) != NULL) { | |
1602 | if (edui_conf.mode & EDUI_MODE_KILL) | |
1603 | break; | |
1604 | time(&edui_now); | |
1605 | if (t < edui_now) { | |
1606 | /* Elapse seconds */ | |
1607 | edui_elap = edui_now - t; | |
f86504f1 AJ |
1608 | t = edui_now; |
1609 | } else | |
1610 | edui_elap = 0; | |
1611 | k = strlen(bufa); | |
9c76c145 | 1612 | /* BINARY DEBUGGING * |
fe1e5c91 | 1613 | local_printfx("while() -> bufa[%" PRIuSIZE "]: %s", k, bufa); |
eb62585f | 1614 | for (i = 0; i < k; ++i) |
9c76c145 A |
1615 | local_printfx("%02X", bufa[i]); |
1616 | local_printfx("\n"); | |
1617 | * BINARY DEBUGGING */ | |
f86504f1 AJ |
1618 | /* Check for CRLF */ |
1619 | p = strchr(bufa, '\n'); | |
1620 | if (p != NULL) | |
1621 | *p = '\0'; | |
1622 | p = strchr(bufa, '\r'); | |
1623 | if (p != NULL) | |
1624 | *p = '\0'; | |
1625 | p = strchr(bufa, ' '); | |
1626 | ||
1627 | /* No space given, but group string is required --> ERR */ | |
1628 | if ((edui_conf.mode & EDUI_MODE_GROUP) && (p == NULL)) { | |
6ca7324f | 1629 | debug("while() -> Search group is missing. (required)\n"); |
194ccc9c | 1630 | local_printfx("BH message=\"(Search Group Required)\"\n"); |
f86504f1 AJ |
1631 | continue; |
1632 | } | |
1633 | x = 0; | |
1634 | ||
1635 | /* Open LDAP connection */ | |
1636 | if (!(edui_ldap.status & LDAP_INIT_S)) { | |
1637 | InitLDAP(&edui_ldap); | |
6ca7324f | 1638 | debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS)); |
2f8abb64 | 1639 | if (edui_conf.mode & EDUI_MODE_PERSIST) /* Setup persistent mode */ |
f86504f1 AJ |
1640 | edui_ldap.status |= LDAP_PERSIST_S; |
1641 | } | |
1642 | if ((edui_ldap.status & LDAP_IDLE_S) && (edui_elap > 0)) { | |
1643 | edui_ldap.idle_time = edui_ldap.idle_time + edui_elap; | |
1644 | } | |
1645 | if ((edui_ldap.status & LDAP_PERSIST_S) && (edui_ldap.status & LDAP_IDLE_S) && (edui_ldap.idle_time > edui_conf.persist_timeout)) { | |
6ca7324f | 1646 | debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap.idle_time)); |
f86504f1 | 1647 | x = CloseLDAP(&edui_ldap); |
6ca7324f | 1648 | debug("CloseLDAP(-) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1649 | } |
1650 | edui_ldap.err = -1; | |
1651 | if (!(edui_ldap.status & LDAP_OPEN_S)) { | |
1652 | x = OpenLDAP(&edui_ldap, edui_conf.host, edui_conf.port); | |
1653 | if (x != LDAP_ERR_SUCCESS) { | |
1654 | /* Failed to connect */ | |
6ca7324f | 1655 | debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1656 | } else { |
6ca7324f | 1657 | debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf.host, edui_conf.port, ErrLDAP(x)); |
f86504f1 AJ |
1658 | x = SetVerLDAP(&edui_ldap, edui_conf.ver); |
1659 | if (x != LDAP_ERR_SUCCESS) { | |
1660 | /* Failed to set version */ | |
6ca7324f | 1661 | debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1662 | } else |
6ca7324f | 1663 | debug("SetVerLDAP(-, %d) -> %s\n", edui_conf.ver, ErrLDAP(x)); |
f86504f1 AJ |
1664 | } |
1665 | } | |
1666 | edui_ldap.err = -1; | |
1667 | if (!(edui_ldap.status & LDAP_BIND_S) && (edui_conf.mode & EDUI_MODE_TLS)) { | |
1668 | /* TLS binding */ | |
1669 | x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_TLS); | |
1670 | if (x != LDAP_ERR_SUCCESS) { | |
1671 | /* Unable to bind */ | |
6ca7324f | 1672 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
194ccc9c | 1673 | local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 | 1674 | continue; |
f86504f1 | 1675 | } else |
6ca7324f | 1676 | debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x)); |
f86504f1 AJ |
1677 | } else if (!(edui_ldap.status & LDAP_BIND_S)) { |
1678 | if (edui_conf.dn[0] != '\0') { | |
1679 | /* Simple binding - using dn / passwd for authorization */ | |
1680 | x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_SIMPLE); | |
1681 | if (x != LDAP_ERR_SUCCESS) { | |
1682 | /* Unable to bind */ | |
6ca7324f | 1683 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
194ccc9c | 1684 | local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 | 1685 | continue; |
f86504f1 | 1686 | } else |
6ca7324f | 1687 | debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x)); |
f86504f1 AJ |
1688 | } else { |
1689 | /* Anonymous binding */ | |
1690 | x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_NONE); | |
1691 | if (x != LDAP_ERR_SUCCESS) { | |
1692 | /* Unable to bind */ | |
6ca7324f | 1693 | debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
194ccc9c | 1694 | local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
ab745b44 | 1695 | continue; |
f86504f1 | 1696 | } else |
6ca7324f | 1697 | debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1698 | } |
1699 | } | |
1700 | edui_ldap.err = -1; | |
1701 | if (edui_ldap.status & LDAP_PERSIST_S) { | |
1702 | x = ResetLDAP(&edui_ldap); | |
1703 | if (x != LDAP_ERR_SUCCESS) { | |
1704 | /* Unable to reset */ | |
6ca7324f | 1705 | debug("ResetLDAP() -> %s\n", ErrLDAP(x)); |
f86504f1 | 1706 | } else |
6ca7324f | 1707 | debug("ResetLDAP() -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1708 | } |
1709 | if (x != LDAP_ERR_SUCCESS) { | |
1710 | /* Everything failed --> ERR */ | |
6ca7324f | 1711 | debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
f86504f1 | 1712 | CloseLDAP(&edui_ldap); |
194ccc9c | 1713 | local_printfx("BH message=\"(General Failure: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1714 | continue; |
1715 | } | |
1716 | edui_ldap.err = -1; | |
1717 | /* If we got a group string, split it */ | |
1718 | if (p != NULL) { | |
1719 | /* Split string */ | |
fe1e5c91 | 1720 | debug("StringSplit(%s, ' ', %s, %" PRIuSIZE ")\n", bufa, bufb, sizeof(bufb)); |
7a545fdb | 1721 | i = StringSplit(bufa, ' ', bufb, sizeof(bufb)); |
f86504f1 | 1722 | if (i > 0) { |
fe1e5c91 | 1723 | debug("StringSplit(%s, %s) done. Result: %" PRIuSIZE "\n", bufa, bufb, i); |
f86504f1 AJ |
1724 | /* Got a group to match against */ |
1725 | x = ConvertIP(&edui_ldap, bufb); | |
1726 | if (x < 0) { | |
6ca7324f | 1727 | debug("ConvertIP() -> %s\n", ErrLDAP(x)); |
194ccc9c | 1728 | local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1729 | } else { |
1730 | edui_ldap.err = -1; | |
88f2cf55 | 1731 | debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb, x, edui_ldap.search_ip); |
f86504f1 AJ |
1732 | x = SearchFilterLDAP(&edui_ldap, bufa); |
1733 | if (x < 0) { | |
6ca7324f | 1734 | debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x)); |
194ccc9c | 1735 | local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1736 | } else { |
1737 | /* Do Search */ | |
1738 | edui_ldap.err = -1; | |
6ca7324f AJ |
1739 | debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa, x); |
1740 | x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib); | |
f86504f1 | 1741 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f | 1742 | debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); |
194ccc9c | 1743 | local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1744 | } else { |
1745 | edui_ldap.err = -1; | |
6ca7324f | 1746 | debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x)); |
7a545fdb | 1747 | x = SearchIPLDAP(&edui_ldap); |
194ccc9c CT |
1748 | if (x == LDAP_ERR_NOTFOUND) { |
1749 | debug("SearchIPLDAP() -> %s\n", ErrLDAP(x)); | |
c55b0902 | 1750 | local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x)); |
194ccc9c | 1751 | } else if (x == LDAP_ERR_SUCCESS) { |
7a545fdb | 1752 | debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x)); |
f53969cc | 1753 | local_printfx("OK user=%s\n", edui_ldap.userid); /* Got userid --> OK user=<userid> */ |
194ccc9c CT |
1754 | } else { |
1755 | debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); | |
1756 | local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x)); | |
f86504f1 AJ |
1757 | } |
1758 | } | |
1759 | /* Clear for next query */ | |
7a545fdb | 1760 | memset(bufc, '\0', sizeof(bufc)); |
f86504f1 AJ |
1761 | } |
1762 | } | |
1763 | } else { | |
fe1e5c91 | 1764 | debug("StringSplit() -> Error: %" PRIuSIZE "\n", i); |
194ccc9c | 1765 | local_printfx("BH message=\"(StringSplit Error %" PRIuSIZE ")\"\n", i); |
f86504f1 AJ |
1766 | } |
1767 | } else { | |
1768 | /* No group to match against, only an IP */ | |
1769 | x = ConvertIP(&edui_ldap, bufa); | |
1770 | if (x < 0) { | |
6ca7324f | 1771 | debug("ConvertIP() -> %s\n", ErrLDAP(x)); |
194ccc9c | 1772 | local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x)); |
f86504f1 | 1773 | } else { |
88f2cf55 | 1774 | debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa, x, edui_ldap.search_ip); |
f86504f1 AJ |
1775 | /* Do search */ |
1776 | x = SearchFilterLDAP(&edui_ldap, NULL); | |
1777 | if (x < 0) { | |
6ca7324f | 1778 | debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x)); |
194ccc9c | 1779 | local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1780 | } else { |
1781 | edui_ldap.err = -1; | |
6ca7324f AJ |
1782 | debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x); |
1783 | x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib); | |
f86504f1 | 1784 | if (x != LDAP_ERR_SUCCESS) { |
6ca7324f | 1785 | debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(x)); |
194ccc9c | 1786 | local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x)); |
f86504f1 AJ |
1787 | } else { |
1788 | edui_ldap.err = -1; | |
6ca7324f | 1789 | debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x)); |
7a545fdb | 1790 | x = SearchIPLDAP(&edui_ldap); |
194ccc9c CT |
1791 | if (x == LDAP_ERR_NOTFOUND) { |
1792 | debug("SearchIPLDAP() -> %s\n", ErrLDAP(x)); | |
c55b0902 | 1793 | local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x)); |
194ccc9c | 1794 | } else if (x == LDAP_ERR_SUCCESS) { |
7a545fdb | 1795 | debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x)); |
f53969cc | 1796 | local_printfx("OK user=%s\n", edui_ldap.userid); /* Got a userid --> OK user=<userid> */ |
194ccc9c CT |
1797 | } else if (x != LDAP_ERR_SUCCESS) { |
1798 | debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err)); | |
1799 | local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x)); | |
f86504f1 AJ |
1800 | } |
1801 | } | |
1802 | } | |
1803 | /* Clear for next query */ | |
7a545fdb | 1804 | memset(bufc, '\0', sizeof(bufc)); |
f86504f1 AJ |
1805 | } |
1806 | } | |
1807 | ||
1808 | /* Clear buffer and close for next data, if not persistent */ | |
1809 | edui_ldap.err = -1; | |
7a545fdb | 1810 | memset(bufa, '\0', sizeof(bufa)); |
f86504f1 AJ |
1811 | if (!(edui_ldap.status & LDAP_PERSIST_S)) { |
1812 | x = CloseLDAP(&edui_ldap); | |
6ca7324f | 1813 | debug("CloseLDAP(-) -> %s\n", ErrLDAP(x)); |
f86504f1 AJ |
1814 | } |
1815 | } | |
1816 | ||
6ca7324f | 1817 | debug("Terminating.\n"); |
915c866f CN |
1818 | return 1; |
1819 | } | |
1820 | ||
1821 | /* "main()" - function */ | |
1822 | int | |
1823 | main(int argc, char **argv) | |
1824 | { | |
2c3d5aec A |
1825 | int x; |
1826 | x = MainSafe(argc, argv); | |
1827 | return x; | |
f86504f1 | 1828 | } |
f53969cc | 1829 |