]>
Commit | Line | Data |
---|---|---|
7ed0602b | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
7ed0602b | 3 | * |
ca02e0ec AJ |
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 | /* | |
7ed0602b | 10 | * AUTHOR: Flavio Pescuma, MARA Systems AB <flavio@marasystems.com> |
11 | */ | |
ca02e0ec | 12 | |
f7f3304a | 13 | #include "squid.h" |
bb85e424 | 14 | #include "util.h" |
46962e36 | 15 | |
16 | #define LDAP_DEPRECATED 1 | |
17 | ||
d4d7f6dd | 18 | #include "auth/digest/LDAP/ldap_backend.h" |
7ed0602b | 19 | |
7aa9bb3e | 20 | #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_ |
7ed0602b | 21 | |
22 | #define snprintf _snprintf | |
23 | #include <windows.h> | |
24 | #include <winldap.h> | |
25 | #ifndef LDAPAPI | |
26 | #define LDAPAPI __cdecl | |
27 | #endif | |
28 | #ifdef LDAP_VERSION3 | |
29 | #ifndef LDAP_OPT_X_TLS | |
30 | #define LDAP_OPT_X_TLS 0x6000 | |
31 | #endif | |
32 | /* Some tricks to allow dynamic bind with ldap_start_tls_s entry point at | |
068d42c5 | 33 | * run time. |
7ed0602b | 34 | */ |
35 | #undef ldap_start_tls_s | |
36 | #if LDAP_UNICODE | |
37 | #define LDAP_START_TLS_S "ldap_start_tls_sW" | |
068d42c5 | 38 | typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *); |
7ed0602b | 39 | #else |
40 | #define LDAP_START_TLS_S "ldap_start_tls_sA" | |
068d42c5 | 41 | typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *); |
7ed0602b | 42 | #endif /* LDAP_UNICODE */ |
43 | PFldap_start_tls_s Win32_ldap_start_tls_s; | |
44 | #define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l,NULL,NULL,s,c) | |
45 | #endif /* LDAP_VERSION3 */ | |
46 | ||
47 | #else | |
48 | ||
49 | #include <lber.h> | |
50 | #include <ldap.h> | |
51 | ||
52 | #endif | |
53 | #define PROGRAM_NAME "digest_pw_auth(LDAP_backend)" | |
54 | ||
55 | /* Globals */ | |
56 | ||
57 | static LDAP *ld = NULL; | |
e9505fad | 58 | static const char *passattr = NULL; |
7ed0602b | 59 | static char *ldapServer = NULL; |
e9505fad | 60 | static const char *userbasedn = NULL; |
61 | static const char *userdnattr = NULL; | |
62 | static const char *usersearchfilter = NULL; | |
63 | static const char *binddn = NULL; | |
64 | static const char *bindpasswd = NULL; | |
65 | static const char *delimiter = ":"; | |
46e791c6 | 66 | static const char *frealm = ""; |
7ed0602b | 67 | static int encrpass = 0; |
68 | static int searchscope = LDAP_SCOPE_SUBTREE; | |
69 | static int persistent = 0; | |
70 | static int noreferrals = 0; | |
7ed0602b | 71 | static int port = LDAP_PORT; |
72 | static int strip_nt_domain = 0; | |
73 | static int aliasderef = LDAP_DEREF_NEVER; | |
74 | #if defined(NETSCAPE_SSL) | |
75 | static char *sslpath = NULL; | |
76 | static int sslinit = 0; | |
77 | #endif | |
78 | static int connect_timeout = 0; | |
79 | static int timelimit = LDAP_NO_LIMIT; | |
80 | ||
81 | #ifdef LDAP_VERSION3 | |
82 | /* Added for TLS support and version 3 */ | |
83 | static int use_tls = 0; | |
84 | static int version = -1; | |
85 | #endif | |
86 | ||
87 | static void ldapconnect(void); | |
e9505fad | 88 | static int readSecret(const char *filename); |
7ed0602b | 89 | |
90 | /* Yuck.. we need to glue to different versions of the API */ | |
91 | ||
92 | #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823 | |
93 | static void | |
94 | squid_ldap_set_aliasderef(int deref) | |
95 | { | |
96 | ldap_set_option(ld, LDAP_OPT_DEREF, &deref); | |
97 | } | |
98 | static void | |
99 | squid_ldap_set_referrals(int referrals) | |
100 | { | |
56ff4687 | 101 | int *value = static_cast<int*>(referrals ? LDAP_OPT_ON :LDAP_OPT_OFF); |
7ed0602b | 102 | ldap_set_option(ld, LDAP_OPT_REFERRALS, value); |
103 | } | |
104 | static void | |
d5f8d05f | 105 | squid_ldap_set_timelimit(int aTimeLimit) |
7ed0602b | 106 | { |
d5f8d05f | 107 | ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &aTimeLimit); |
7ed0602b | 108 | } |
109 | static void | |
d5f8d05f | 110 | squid_ldap_set_connect_timeout(int aTimeLimit) |
7ed0602b | 111 | { |
112 | #if defined(LDAP_OPT_NETWORK_TIMEOUT) | |
113 | struct timeval tv; | |
d5f8d05f | 114 | tv.tv_sec = aTimeLimit; |
7ed0602b | 115 | tv.tv_usec = 0; |
116 | ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); | |
117 | #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT) | |
d5f8d05f FC |
118 | aTimeLimit *= 1000; |
119 | ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &aTimeLimit); | |
7ed0602b | 120 | #endif |
121 | } | |
122 | ||
123 | #else | |
124 | static int | |
125 | squid_ldap_errno(LDAP * ld) | |
126 | { | |
127 | return ld->ld_errno; | |
128 | } | |
129 | static void | |
130 | squid_ldap_set_aliasderef(int deref) | |
131 | { | |
132 | ld->ld_deref = deref; | |
133 | } | |
134 | static void | |
135 | squid_ldap_set_referrals(int referrals) | |
136 | { | |
137 | if (referrals) | |
26ac0430 | 138 | ld->ld_options |= ~LDAP_OPT_REFERRALS; |
7ed0602b | 139 | else |
26ac0430 | 140 | ld->ld_options &= ~LDAP_OPT_REFERRALS; |
7ed0602b | 141 | } |
142 | static void | |
d5f8d05f | 143 | squid_ldap_set_timelimit(int aTimeLimit) |
7ed0602b | 144 | { |
d5f8d05f | 145 | ld->ld_timelimit = aTimeLimit; |
7ed0602b | 146 | } |
147 | static void | |
d5f8d05f | 148 | squid_ldap_set_connect_timeout(int aTimeLimit) |
7ed0602b | 149 | { |
150 | fprintf(stderr, "Connect timeouts not supported in your LDAP library\n"); | |
151 | } | |
152 | static void | |
153 | squid_ldap_memfree(char *p) | |
154 | { | |
155 | free(p); | |
156 | } | |
157 | ||
158 | #endif | |
159 | ||
160 | #ifdef LDAP_API_FEATURE_X_OPENLDAP | |
161 | #if LDAP_VENDOR_VERSION > 194 | |
162 | #define HAS_URI_SUPPORT 1 | |
163 | #endif | |
164 | #endif | |
165 | ||
166 | static int | |
167 | ldap_escape_value(char *escaped, int size, const char *src) | |
168 | { | |
169 | int n = 0; | |
170 | while (size > 4 && *src) { | |
26ac0430 AJ |
171 | switch (*src) { |
172 | case '*': | |
173 | case '(': | |
174 | case ')': | |
175 | case '\\': | |
176 | n += 3; | |
177 | size -= 3; | |
178 | if (size > 0) { | |
f207fe64 FC |
179 | *escaped = '\\'; |
180 | ++escaped; | |
14942edd FC |
181 | snprintf(escaped, 3, "%02x", (int) *src); |
182 | ++src; | |
26ac0430 AJ |
183 | escaped += 2; |
184 | } | |
185 | break; | |
186 | default: | |
14942edd FC |
187 | *escaped = *src; |
188 | ++escaped; | |
189 | ++src; | |
755494da FC |
190 | ++n; |
191 | --size; | |
26ac0430 | 192 | } |
7ed0602b | 193 | } |
194 | *escaped = '\0'; | |
195 | return n; | |
196 | } | |
197 | ||
198 | static char * | |
199 | getpassword(char *login, char *realm) | |
200 | { | |
201 | LDAPMessage *res = NULL; | |
202 | LDAPMessage *entry; | |
203 | char **values = NULL; | |
204 | char **value = NULL; | |
205 | char *password = NULL; | |
206 | int retry = 0; | |
207 | char filter[8192]; | |
208 | char searchbase[8192]; | |
209 | int rc = -1; | |
210 | if (ld) { | |
26ac0430 AJ |
211 | if (usersearchfilter) { |
212 | char escaped_login[1024]; | |
213 | snprintf(searchbase, sizeof(searchbase), "%s", userbasedn); | |
214 | ldap_escape_value(escaped_login, sizeof(escaped_login), login); | |
215 | snprintf(filter, sizeof(filter), usersearchfilter, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login); | |
216 | ||
217 | retrysrch: | |
56ff4687 | 218 | debug("user filter '%s', searchbase '%s'\n", filter, searchbase); |
26ac0430 AJ |
219 | |
220 | rc = ldap_search_s(ld, searchbase, searchscope, filter, NULL, 0, &res); | |
221 | if (rc != LDAP_SUCCESS) { | |
222 | if (noreferrals && rc == LDAP_PARTIAL_RESULTS) { | |
223 | /* Everything is fine. This is expected when referrals | |
224 | * are disabled. | |
225 | */ | |
226 | rc = LDAP_SUCCESS; | |
227 | } else { | |
228 | fprintf(stderr, PROGRAM_NAME " WARNING, LDAP search error '%s'\n", ldap_err2string(rc)); | |
7ed0602b | 229 | #if defined(NETSCAPE_SSL) |
26ac0430 AJ |
230 | if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) { |
231 | int sslerr = PORT_GetError(); | |
232 | fprintf(stderr, PROGRAM_NAME ": WARNING, SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr)); | |
233 | } | |
7ed0602b | 234 | #endif |
26ac0430 AJ |
235 | fprintf(stderr, PROGRAM_NAME " WARNING, LDAP search error, trying to recover'%s'\n", ldap_err2string(rc)); |
236 | ldap_msgfree(res); | |
2f8abb64 | 237 | /* try to connect to the LDAP server again, maybe my persistent conexion failed. */ |
26ac0430 | 238 | if (!retry) { |
755494da | 239 | ++retry; |
26ac0430 AJ |
240 | ldap_unbind(ld); |
241 | ld = NULL; | |
242 | ldapconnect(); | |
243 | goto retrysrch; | |
244 | } | |
245 | return NULL; | |
246 | ||
247 | } | |
248 | } | |
249 | } else if (userdnattr) { | |
0e0f1358 | 250 | snprintf(filter,8192,"%s=%s",userdnattr,login); |
26ac0430 AJ |
251 | |
252 | retrydnattr: | |
0e0f1358 AJ |
253 | debug("searchbase '%s'\n", userbasedn); |
254 | rc = ldap_search_s(ld, userbasedn, searchscope, filter, NULL, 0, &res); | |
26ac0430 AJ |
255 | } |
256 | if (rc == LDAP_SUCCESS) { | |
257 | entry = ldap_first_entry(ld, res); | |
258 | if (entry) | |
259 | values = ldap_get_values(ld, entry, passattr); | |
260 | else { | |
261 | ldap_msgfree(res); | |
262 | return NULL; | |
263 | } | |
264 | if (!values) { | |
56ff4687 | 265 | debug("No attribute value found\n"); |
26ac0430 AJ |
266 | ldap_msgfree(res); |
267 | return NULL; | |
268 | } | |
269 | value = values; | |
270 | while (*value) { | |
46e791c6 | 271 | if (encrpass && *delimiter ) { |
aa8c6def AJ |
272 | const char *t = strtok(*value, delimiter); |
273 | if (t && strcmp(t, realm) == 0) { | |
26ac0430 AJ |
274 | password = strtok(NULL, delimiter); |
275 | break; | |
276 | } | |
277 | } else { | |
278 | password = *value; | |
279 | break; | |
280 | } | |
755494da | 281 | ++value; |
26ac0430 | 282 | } |
56ff4687 | 283 | debug("password: %s\n", password); |
26ac0430 | 284 | if (password) |
bb85e424 | 285 | password = xstrdup(password); |
26ac0430 AJ |
286 | ldap_value_free(values); |
287 | ldap_msgfree(res); | |
288 | return password; | |
289 | } else { | |
290 | fprintf(stderr, PROGRAM_NAME " WARNING, LDAP error '%s'\n", ldap_err2string(rc)); | |
2f8abb64 | 291 | /* try to connect to the LDAP server again, maybe my persistent conexion failed. */ |
26ac0430 | 292 | if (!retry) { |
755494da | 293 | ++retry; |
26ac0430 AJ |
294 | ldap_unbind(ld); |
295 | ld = NULL; | |
296 | ldapconnect(); | |
297 | goto retrydnattr; | |
298 | } | |
299 | return NULL; | |
300 | } | |
7ed0602b | 301 | } |
302 | return NULL; | |
303 | } | |
304 | ||
7ed0602b | 305 | static void |
306 | ldapconnect(void) | |
307 | { | |
308 | int rc; | |
309 | ||
26ac0430 AJ |
310 | /* On Windows ldap_start_tls_s is available starting from Windows XP, |
311 | * so we need to bind at run-time with the function entry point | |
312 | */ | |
7aa9bb3e | 313 | #if _SQUID_WINDOWS_ |
7ed0602b | 314 | if (use_tls) { |
315 | ||
26ac0430 | 316 | HMODULE WLDAP32Handle; |
7ed0602b | 317 | |
26ac0430 AJ |
318 | WLDAP32Handle = GetModuleHandle("wldap32"); |
319 | if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) { | |
320 | fprintf(stderr, PROGRAM_NAME ": ERROR: TLS (-Z) not supported on this platform.\n"); | |
24885773 | 321 | exit(EXIT_FAILURE); |
26ac0430 | 322 | } |
7ed0602b | 323 | } |
324 | #endif | |
325 | ||
326 | if (ld == NULL) { | |
327 | #if HAS_URI_SUPPORT | |
26ac0430 AJ |
328 | if (strstr(ldapServer, "://") != NULL) { |
329 | rc = ldap_initialize(&ld, ldapServer); | |
330 | if (rc != LDAP_SUCCESS) { | |
331 | fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer); | |
332 | } | |
333 | } else | |
7ed0602b | 334 | #endif |
335 | #if NETSCAPE_SSL | |
26ac0430 AJ |
336 | if (sslpath) { |
337 | if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) { | |
338 | fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n", | |
339 | sslpath); | |
24885773 | 340 | exit(EXIT_FAILURE); |
26ac0430 | 341 | } else { |
755494da | 342 | ++sslinit; |
26ac0430 AJ |
343 | } |
344 | if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) { | |
345 | fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n", | |
346 | ldapServer, port); | |
24885773 | 347 | exit(EXIT_FAILURE); |
26ac0430 AJ |
348 | } |
349 | } else | |
7ed0602b | 350 | #endif |
26ac0430 AJ |
351 | if ((ld = ldap_init(ldapServer, port)) == NULL) { |
352 | fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n", ldapServer, port); | |
353 | } | |
354 | if (connect_timeout) | |
355 | squid_ldap_set_connect_timeout(connect_timeout); | |
7ed0602b | 356 | |
357 | #ifdef LDAP_VERSION3 | |
26ac0430 AJ |
358 | if (version == -1) { |
359 | version = LDAP_VERSION2; | |
360 | } | |
361 | if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) | |
362 | != LDAP_SUCCESS) { | |
363 | fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", | |
364 | version); | |
365 | ldap_unbind(ld); | |
366 | ld = NULL; | |
367 | } | |
368 | if (use_tls) { | |
e11ffec3 | 369 | #ifdef LDAP_OPT_X_TLS |
59bce1e8 AJ |
370 | if (version != LDAP_VERSION3) { |
371 | fprintf(stderr, "TLS requires LDAP version 3\n"); | |
24885773 | 372 | exit(EXIT_FAILURE); |
59bce1e8 | 373 | } else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) { |
26ac0430 | 374 | fprintf(stderr, "Could not Activate TLS connection\n"); |
24885773 | 375 | exit(EXIT_FAILURE); |
26ac0430 | 376 | } |
e11ffec3 | 377 | #else |
26ac0430 AJ |
378 | fprintf(stderr, "TLS not supported with your LDAP library\n"); |
379 | ldap_unbind(ld); | |
380 | ld = NULL; | |
e11ffec3 | 381 | #endif |
26ac0430 | 382 | } |
7ed0602b | 383 | #endif |
26ac0430 AJ |
384 | squid_ldap_set_timelimit(timelimit); |
385 | squid_ldap_set_referrals(!noreferrals); | |
386 | squid_ldap_set_aliasderef(aliasderef); | |
387 | if (binddn && bindpasswd && *binddn && *bindpasswd) { | |
388 | rc = ldap_simple_bind_s(ld, binddn, bindpasswd); | |
389 | if (rc != LDAP_SUCCESS) { | |
390 | fprintf(stderr, PROGRAM_NAME " WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc)); | |
391 | ldap_unbind(ld); | |
392 | ld = NULL; | |
393 | } | |
394 | } | |
56ff4687 | 395 | debug("Connected OK\n"); |
7ed0602b | 396 | } |
397 | } | |
398 | int | |
399 | LDAPArguments(int argc, char **argv) | |
400 | { | |
401 | setbuf(stdout, NULL); | |
402 | ||
403 | while (argc > 1 && argv[1][0] == '-') { | |
26ac0430 AJ |
404 | const char *value = ""; |
405 | char option = argv[1][1]; | |
406 | switch (option) { | |
407 | case 'P': | |
408 | case 'R': | |
409 | case 'z': | |
410 | case 'Z': | |
411 | case 'g': | |
412 | case 'e': | |
413 | case 'S': | |
414 | break; | |
415 | default: | |
416 | if (strlen(argv[1]) > 2) { | |
417 | value = argv[1] + 2; | |
418 | } else if (argc > 2) { | |
419 | value = argv[2]; | |
755494da FC |
420 | ++argv; |
421 | --argc; | |
26ac0430 AJ |
422 | } else |
423 | value = ""; | |
424 | break; | |
425 | } | |
755494da FC |
426 | ++argv; |
427 | --argc; | |
26ac0430 AJ |
428 | switch (option) { |
429 | case 'H': | |
7ed0602b | 430 | #if !HAS_URI_SUPPORT |
26ac0430 AJ |
431 | fprintf(stderr, "ERROR: Your LDAP library does not have URI support\n"); |
432 | return 1; | |
7ed0602b | 433 | #endif |
f53969cc | 434 | /* Fall thru to -h */ |
26ac0430 AJ |
435 | case 'h': |
436 | if (ldapServer) { | |
437 | int len = strlen(ldapServer) + 1 + strlen(value) + 1; | |
c14fb378 | 438 | char *newhost = static_cast<char*>(xmalloc(len)); |
26ac0430 AJ |
439 | snprintf(newhost, len, "%s %s", ldapServer, value); |
440 | free(ldapServer); | |
441 | ldapServer = newhost; | |
442 | } else { | |
bb85e424 | 443 | ldapServer = xstrdup(value); |
26ac0430 AJ |
444 | } |
445 | break; | |
446 | case 'A': | |
447 | passattr = value; | |
448 | break; | |
449 | case 'e': | |
450 | encrpass = 1; | |
451 | break; | |
452 | case 'l': | |
453 | delimiter = value; | |
454 | break; | |
46e791c6 EF |
455 | case 'r': |
456 | frealm = value; | |
457 | break; | |
26ac0430 AJ |
458 | case 'b': |
459 | userbasedn = value; | |
460 | break; | |
461 | case 'F': | |
462 | usersearchfilter = value; | |
463 | break; | |
464 | case 'u': | |
465 | userdnattr = value; | |
466 | break; | |
467 | case 's': | |
468 | if (strcmp(value, "base") == 0) | |
469 | searchscope = LDAP_SCOPE_BASE; | |
470 | else if (strcmp(value, "one") == 0) | |
471 | searchscope = LDAP_SCOPE_ONELEVEL; | |
472 | else if (strcmp(value, "sub") == 0) | |
473 | searchscope = LDAP_SCOPE_SUBTREE; | |
474 | else { | |
475 | fprintf(stderr, PROGRAM_NAME " ERROR: Unknown search scope '%s'\n", value); | |
476 | return 1; | |
477 | } | |
478 | break; | |
479 | case 'S': | |
7ed0602b | 480 | #if defined(NETSCAPE_SSL) |
26ac0430 AJ |
481 | sslpath = value; |
482 | if (port == LDAP_PORT) | |
483 | port = LDAPS_PORT; | |
7ed0602b | 484 | #else |
26ac0430 AJ |
485 | fprintf(stderr, PROGRAM_NAME " ERROR: -E unsupported with this LDAP library\n"); |
486 | return 1; | |
7ed0602b | 487 | #endif |
26ac0430 AJ |
488 | break; |
489 | case 'c': | |
490 | connect_timeout = atoi(value); | |
491 | break; | |
492 | case 't': | |
493 | timelimit = atoi(value); | |
494 | break; | |
495 | case 'a': | |
496 | if (strcmp(value, "never") == 0) | |
497 | aliasderef = LDAP_DEREF_NEVER; | |
498 | else if (strcmp(value, "always") == 0) | |
499 | aliasderef = LDAP_DEREF_ALWAYS; | |
500 | else if (strcmp(value, "search") == 0) | |
501 | aliasderef = LDAP_DEREF_SEARCHING; | |
502 | else if (strcmp(value, "find") == 0) | |
503 | aliasderef = LDAP_DEREF_FINDING; | |
504 | else { | |
505 | fprintf(stderr, PROGRAM_NAME " ERROR: Unknown alias dereference method '%s'\n", value); | |
506 | return 1; | |
507 | } | |
508 | break; | |
509 | case 'D': | |
510 | binddn = value; | |
511 | break; | |
512 | case 'w': | |
513 | bindpasswd = value; | |
514 | break; | |
515 | case 'W': | |
516 | readSecret(value); | |
517 | break; | |
518 | case 'P': | |
519 | persistent = !persistent; | |
520 | break; | |
521 | case 'p': | |
522 | port = atoi(value); | |
523 | break; | |
524 | case 'R': | |
525 | noreferrals = !noreferrals; | |
526 | break; | |
7ed0602b | 527 | #ifdef LDAP_VERSION3 |
26ac0430 AJ |
528 | case 'v': |
529 | switch (atoi(value)) { | |
530 | case 2: | |
531 | version = LDAP_VERSION2; | |
532 | break; | |
533 | case 3: | |
534 | version = LDAP_VERSION3; | |
535 | break; | |
536 | default: | |
537 | fprintf(stderr, "Protocol version should be 2 or 3\n"); | |
538 | return 1; | |
539 | } | |
540 | break; | |
541 | case 'Z': | |
542 | if (version == LDAP_VERSION2) { | |
543 | fprintf(stderr, "TLS (-Z) is incompatible with version %d\n", | |
544 | version); | |
545 | return 1; | |
546 | } | |
547 | version = LDAP_VERSION3; | |
548 | use_tls = 1; | |
549 | break; | |
7ed0602b | 550 | #endif |
26ac0430 | 551 | case 'd': |
56ff4687 | 552 | debug_enabled = 1; |
26ac0430 AJ |
553 | break; |
554 | case 'E': | |
555 | strip_nt_domain = 1; | |
556 | break; | |
557 | default: | |
558 | fprintf(stderr, PROGRAM_NAME " ERROR: Unknown command line option '%c'\n", option); | |
559 | return 1; | |
560 | } | |
7ed0602b | 561 | } |
562 | ||
563 | while (argc > 1) { | |
26ac0430 AJ |
564 | char *value = argv[1]; |
565 | if (ldapServer) { | |
566 | int len = strlen(ldapServer) + 1 + strlen(value) + 1; | |
c14fb378 | 567 | char *newhost = static_cast<char*>(xmalloc(len)); |
26ac0430 AJ |
568 | snprintf(newhost, len, "%s %s", ldapServer, value); |
569 | free(ldapServer); | |
570 | ldapServer = newhost; | |
571 | } else { | |
bb85e424 | 572 | ldapServer = xstrdup(value); |
26ac0430 | 573 | } |
755494da FC |
574 | --argc; |
575 | ++argv; | |
7ed0602b | 576 | } |
577 | ||
578 | if (!ldapServer) | |
26ac0430 | 579 | ldapServer = (char *) "localhost"; |
7ed0602b | 580 | |
46e791c6 EF |
581 | if (!userbasedn || !passattr || (!*delimiter && !*frealm)) { |
582 | fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -F filter [options] ldap_server_name\n\n"); | |
26ac0430 | 583 | fprintf(stderr, "\t-A password attribute(REQUIRED)\t\tUser attribute that contains the password\n"); |
46e791c6 EF |
584 | fprintf(stderr, "\t-l password realm delimiter(REQUIRED)\tCharacter(s) that divides the password attribute\n\t\t\t\t\t\tin realm and password tokens, default ':' realm:password, could be\n\t\t\t\t\t\tempty string if the password is alone in the password attribute\n"); |
585 | fprintf(stderr, "\t-r filtered realm\t\t\tonly honor Squid requests for this realm. Mandatory if the password is alone in\n\t\t\t\t\t\tthe password attribute, acting as the implicit realm\n"); | |
26ac0430 AJ |
586 | fprintf(stderr, "\t-b basedn (REQUIRED)\t\t\tbase dn under where to search for users\n"); |
587 | fprintf(stderr, "\t-e Encrypted passwords(REQUIRED)\tPassword are stored encrypted using HHA1\n"); | |
588 | fprintf(stderr, "\t-F filter\t\t\t\tuser search filter pattern. %%s = login\n"); | |
589 | fprintf(stderr, "\t-u attribute\t\t\t\tattribute to use in combination with the basedn to create the user DN\n"); | |
590 | fprintf(stderr, "\t-s base|one|sub\t\t\t\tsearch scope\n"); | |
591 | fprintf(stderr, "\t-D binddn\t\t\t\tDN to bind as to perform searches\n"); | |
592 | fprintf(stderr, "\t-w bindpasswd\t\t\t\tpassword for binddn\n"); | |
593 | fprintf(stderr, "\t-W secretfile\t\t\t\tread password for binddn from file secretfile\n"); | |
7ed0602b | 594 | #if HAS_URI_SUPPORT |
26ac0430 | 595 | fprintf(stderr, "\t-H URI\t\t\t\t\tLDAPURI (defaults to ldap://localhost)\n"); |
7ed0602b | 596 | #endif |
26ac0430 AJ |
597 | fprintf(stderr, "\t-h server\t\t\t\tLDAP server (defaults to localhost)\n"); |
598 | fprintf(stderr, "\t-p port\t\t\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT); | |
599 | fprintf(stderr, "\t-P\t\t\t\t\tpersistent LDAP connection\n"); | |
7ed0602b | 600 | #if defined(NETSCAPE_SSL) |
26ac0430 | 601 | fprintf(stderr, "\t-E sslcertpath\t\t\t\tenable LDAP over SSL\n"); |
7ed0602b | 602 | #endif |
26ac0430 AJ |
603 | fprintf(stderr, "\t-c timeout\t\t\t\tconnect timeout\n"); |
604 | fprintf(stderr, "\t-t timelimit\t\t\t\tsearch time limit\n"); | |
605 | fprintf(stderr, "\t-R\t\t\t\t\tdo not follow referrals\n"); | |
606 | fprintf(stderr, "\t-a never|always|search|find\t\twhen to dereference aliases\n"); | |
7ed0602b | 607 | #ifdef LDAP_VERSION3 |
26ac0430 AJ |
608 | fprintf(stderr, "\t-v 2|3\t\t\t\t\tLDAP version\n"); |
609 | fprintf(stderr, "\t-Z\t\t\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n"); | |
7ed0602b | 610 | #endif |
26ac0430 AJ |
611 | fprintf(stderr, "\t-S\t\t\t\t\tStrip NT domain from usernames\n"); |
612 | fprintf(stderr, "\n"); | |
613 | fprintf(stderr, "\tIf you need to bind as a user to perform searches then use the\n\t-D binddn -w bindpasswd or -D binddn -W secretfile options\n\n"); | |
614 | return -1; | |
7ed0602b | 615 | } |
616 | return 0; | |
617 | } | |
618 | static int | |
e9505fad | 619 | readSecret(const char *filename) |
7ed0602b | 620 | { |
621 | char buf[BUFSIZ]; | |
622 | char *e = 0; | |
623 | FILE *f; | |
624 | ||
625 | if (!(f = fopen(filename, "r"))) { | |
26ac0430 AJ |
626 | fprintf(stderr, PROGRAM_NAME " ERROR: Can not read secret file %s\n", filename); |
627 | return 1; | |
7ed0602b | 628 | } |
629 | if (!fgets(buf, sizeof(buf) - 1, f)) { | |
26ac0430 AJ |
630 | fprintf(stderr, PROGRAM_NAME " ERROR: Secret file %s is empty\n", filename); |
631 | fclose(f); | |
632 | return 1; | |
7ed0602b | 633 | } |
634 | /* strip whitespaces on end */ | |
635 | if ((e = strrchr(buf, '\n'))) | |
26ac0430 | 636 | *e = 0; |
7ed0602b | 637 | if ((e = strrchr(buf, '\r'))) |
26ac0430 | 638 | *e = 0; |
7ed0602b | 639 | |
bb85e424 | 640 | bindpasswd = xstrdup(buf); |
e9505fad | 641 | if (!bindpasswd) { |
26ac0430 | 642 | fprintf(stderr, PROGRAM_NAME " ERROR: can not allocate memory\n"); |
7ed0602b | 643 | } |
7ed0602b | 644 | fclose(f); |
645 | ||
646 | return 0; | |
647 | } | |
648 | ||
649 | void | |
650 | LDAPHHA1(RequestData * requestData) | |
651 | { | |
46e791c6 | 652 | char *password = NULL; |
7ed0602b | 653 | ldapconnect(); |
46e791c6 EF |
654 | |
655 | // use the -l delimiter to find realm, or | |
656 | // only honor the -r specified realm | |
657 | const bool lookup = (!*frealm && *delimiter) || | |
859e7e25 | 658 | (*frealm && strcmp(requestData->realm, frealm) == 0); |
46e791c6 EF |
659 | |
660 | if (lookup) | |
661 | password = getpassword(requestData->user, requestData->realm); | |
662 | ||
7ed0602b | 663 | if (password != NULL) { |
26ac0430 AJ |
664 | if (encrpass) |
665 | xstrncpy(requestData->HHA1, password, sizeof(requestData->HHA1)); | |
666 | else { | |
667 | HASH HA1; | |
668 | DigestCalcHA1("md5", requestData->user, requestData->realm, password, NULL, NULL, HA1, requestData->HHA1); | |
669 | } | |
670 | free(password); | |
7ed0602b | 671 | } else { |
26ac0430 | 672 | requestData->error = -1; |
7ed0602b | 673 | } |
674 | ||
675 | } | |
f53969cc | 676 |