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