]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/LDAP_group/ext_ldap_group_acl.cc
Merged from trunk
[thirdparty/squid.git] / helpers / external_acl / LDAP_group / ext_ldap_group_acl.cc
1 /*
2 * ext_ldap_group_acl: lookup group membership in LDAP
3 *
4 * Version 2.17
5 *
6 * (C)2002,2003 MARA Systems AB
7 *
8 * License: squid_ldap_group is free software; you can redistribute it
9 * and/or modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * Authors:
14 * Flavio Pescuma <flavio@marasystems.com>
15 * Henrik Nordstrom <hno@marasystems.com>
16 * MARA Systems AB, Sweden <http://www.marasystems.com>
17 *
18 * With contributions from others mentioned in the ChangeLog file
19 *
20 * In part based on squid_ldap_auth by Glen Newton and Henrik Nordstrom.
21 *
22 * Latest version of this program can always be found from MARA Systems
23 * at http://marasystems.com/download/LDAP_Group/
24 *
25 * Dependencies: You need to get the OpenLDAP libraries
26 * from http://www.openldap.org or use another compatible
27 * LDAP C-API library.
28 *
29 * If you want to make a TLS enabled connection you will also need the
30 * OpenSSL libraries linked into openldap. See http://www.openssl.org/
31 *
32 * License: squid_ldap_group is free software; you can redistribute it
33 * and/or modify it under the terms of the GNU General Public License
34 * as published by the Free Software Foundation; either version 2,
35 * or (at your option) any later version.
36 */
37 #include "squid.h"
38 #include "helpers/defines.h"
39 #include "rfc1738.h"
40 #include "util.h"
41
42 #define LDAP_DEPRECATED 1
43
44 #include <cctype>
45 #include <cstring>
46
47 #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
48
49 #define snprintf _snprintf
50 #include <windows.h>
51 #include <winldap.h>
52 #ifndef LDAPAPI
53 #define LDAPAPI __cdecl
54 #endif
55 #ifdef LDAP_VERSION3
56 #ifndef LDAP_OPT_X_TLS
57 #define LDAP_OPT_X_TLS 0x6000
58 #endif
59 /* Some tricks to allow dynamic bind with ldap_start_tls_s entry point at
60 * run time.
61 */
62 #undef ldap_start_tls_s
63 #if LDAP_UNICODE
64 #define LDAP_START_TLS_S "ldap_start_tls_sW"
65 typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *);
66 #else
67 #define LDAP_START_TLS_S "ldap_start_tls_sA"
68 typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
69 #endif /* LDAP_UNICODE */
70 PFldap_start_tls_s Win32_ldap_start_tls_s;
71 #define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l,NULL,NULL,s,c)
72 #endif /* LDAP_VERSION3 */
73
74 #else
75
76 #if HAVE_LBER_H
77 #include <lber.h>
78 #endif
79 #if HAVE_LDAP_H
80 #include <ldap.h>
81 #endif
82
83 #endif
84
85 #define PROGRAM_NAME "ext_ldap_group_acl"
86 #define PROGRAM_VERSION "2.17"
87
88 /* Globals */
89
90 static const char *basedn = NULL;
91 static const char *searchfilter = NULL;
92 static const char *userbasedn = NULL;
93 static const char *userdnattr = NULL;
94 static const char *usersearchfilter = NULL;
95 static const char *binddn = NULL;
96 static const char *bindpasswd = NULL;
97 static int searchscope = LDAP_SCOPE_SUBTREE;
98 static int persistent = 0;
99 static int noreferrals = 0;
100 static int aliasderef = LDAP_DEREF_NEVER;
101 #if defined(NETSCAPE_SSL)
102 static char *sslpath = NULL;
103 static int sslinit = 0;
104 #endif
105 static int connect_timeout = 0;
106 static int timelimit = LDAP_NO_LIMIT;
107
108 #ifdef LDAP_VERSION3
109 /* Added for TLS support and version 3 */
110 static int use_tls = 0;
111 static int version = -1;
112 #endif
113
114 static int searchLDAP(LDAP * ld, char *group, char *user, char *extension_dn);
115
116 static int readSecret(const char *filename);
117
118 /* Yuck.. we need to glue to different versions of the API */
119
120 #ifndef LDAP_NO_ATTRS
121 #define LDAP_NO_ATTRS "1.1"
122 #endif
123
124 #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
125 static int
126 squid_ldap_errno(LDAP * ld)
127 {
128 int err = 0;
129 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
130 return err;
131 }
132 static void
133 squid_ldap_set_aliasderef(LDAP * ld, int deref)
134 {
135 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
136 }
137 static void
138 squid_ldap_set_referrals(LDAP * ld, int referrals)
139 {
140 int *value = static_cast<int*>(referrals ? LDAP_OPT_ON :LDAP_OPT_OFF);
141 ldap_set_option(ld, LDAP_OPT_REFERRALS, value);
142 }
143 static void
144 squid_ldap_set_timelimit(LDAP * ld, int aTimeLimit)
145 {
146 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &aTimeLimit);
147 }
148 static void
149 squid_ldap_set_connect_timeout(LDAP * ld, int aTimeLimit)
150 {
151 #if defined(LDAP_OPT_NETWORK_TIMEOUT)
152 struct timeval tv;
153 tv.tv_sec = aTimeLimit;
154 tv.tv_usec = 0;
155 ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
156 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
157 aTimeLimit *= 1000;
158 ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &aTimeLimit);
159 #endif
160 }
161 static void
162 squid_ldap_memfree(char *p)
163 {
164 ldap_memfree(p);
165 }
166
167 #else
168 static int
169 squid_ldap_errno(LDAP * ld)
170 {
171 return ld->ld_errno;
172 }
173 static void
174 squid_ldap_set_aliasderef(LDAP * ld, int deref)
175 {
176 ld->ld_deref = deref;
177 }
178 static void
179 squid_ldap_set_referrals(LDAP * ld, int referrals)
180 {
181 if (referrals)
182 ld->ld_options |= ~LDAP_OPT_REFERRALS;
183 else
184 ld->ld_options &= ~LDAP_OPT_REFERRALS;
185 }
186 static void
187 squid_ldap_set_timelimit(LDAP * ld, int timelimit)
188 {
189 ld->ld_timelimit = timelimit;
190 }
191 static void
192 squid_ldap_set_connect_timeout(LDAP * ld, int timelimit)
193 {
194 fprintf(stderr, "WARNING: Connect timeouts not supported in your LDAP library\n");
195 }
196 static void
197 squid_ldap_memfree(char *p)
198 {
199 free(p);
200 }
201
202 #endif
203
204 #ifdef LDAP_API_FEATURE_X_OPENLDAP
205 #if LDAP_VENDOR_VERSION > 194
206 #define HAS_URI_SUPPORT 1
207 #endif
208 #endif
209
210 int
211 main(int argc, char **argv)
212 {
213 char buf[HELPER_INPUT_BUFFER];
214 char *user, *group, *extension_dn = NULL;
215 char *ldapServer = NULL;
216 LDAP *ld = NULL;
217 int tryagain = 0, rc;
218 int port = LDAP_PORT;
219 int use_extension_dn = 0;
220 int strip_nt_domain = 0;
221 int strip_kerberos_realm = 0;
222
223 setbuf(stdout, NULL);
224
225 while (argc > 1 && argv[1][0] == '-') {
226 const char *value = "";
227 char option = argv[1][1];
228 switch (option) {
229 case 'P':
230 case 'R':
231 case 'z':
232 case 'Z':
233 case 'd':
234 case 'g':
235 case 'S':
236 case 'K':
237 break;
238 default:
239 if (strlen(argv[1]) > 2) {
240 value = argv[1] + 2;
241 } else if (argc > 2) {
242 value = argv[2];
243 ++argv;
244 --argc;
245 } else
246 value = "";
247 break;
248 }
249 ++argv;
250 --argc;
251 switch (option) {
252 case 'H':
253 #if !HAS_URI_SUPPORT
254 fprintf(stderr, "FATAL: Your LDAP library does not have URI support\n");
255 exit(1);
256 #endif
257 /* Fall thru to -h */
258 case 'h':
259 if (ldapServer) {
260 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
261 char *newhost = (char*)malloc(len);
262 snprintf(newhost, len, "%s %s", ldapServer, value);
263 free(ldapServer);
264 ldapServer = newhost;
265 } else {
266 ldapServer = xstrdup(value);
267 }
268 break;
269 case 'b':
270 basedn = value;
271 break;
272 case 'f':
273 searchfilter = value;
274 break;
275 case 'B':
276 userbasedn = value;
277 break;
278 case 'F':
279 usersearchfilter = value;
280 break;
281 case 'u':
282 userdnattr = value;
283 break;
284 case 's':
285 if (strcmp(value, "base") == 0)
286 searchscope = LDAP_SCOPE_BASE;
287 else if (strcmp(value, "one") == 0)
288 searchscope = LDAP_SCOPE_ONELEVEL;
289 else if (strcmp(value, "sub") == 0)
290 searchscope = LDAP_SCOPE_SUBTREE;
291 else {
292 fprintf(stderr, PROGRAM_NAME ": FATAL: Unknown search scope '%s'\n", value);
293 exit(1);
294 }
295 break;
296 case 'E':
297 #if defined(NETSCAPE_SSL)
298 sslpath = value;
299 if (port == LDAP_PORT)
300 port = LDAPS_PORT;
301 #else
302 fprintf(stderr, PROGRAM_NAME ": FATAL: -E unsupported with this LDAP library\n");
303 exit(1);
304 #endif
305 break;
306 case 'c':
307 connect_timeout = atoi(value);
308 break;
309 case 't':
310 timelimit = atoi(value);
311 break;
312 case 'a':
313 if (strcmp(value, "never") == 0)
314 aliasderef = LDAP_DEREF_NEVER;
315 else if (strcmp(value, "always") == 0)
316 aliasderef = LDAP_DEREF_ALWAYS;
317 else if (strcmp(value, "search") == 0)
318 aliasderef = LDAP_DEREF_SEARCHING;
319 else if (strcmp(value, "find") == 0)
320 aliasderef = LDAP_DEREF_FINDING;
321 else {
322 fprintf(stderr, PROGRAM_NAME ": FATAL: Unknown alias dereference method '%s'\n", value);
323 exit(1);
324 }
325 break;
326 case 'D':
327 binddn = value;
328 break;
329 case 'w':
330 bindpasswd = value;
331 break;
332 case 'W':
333 readSecret(value);
334 break;
335 case 'P':
336 persistent = !persistent;
337 break;
338 case 'p':
339 port = atoi(value);
340 break;
341 case 'R':
342 noreferrals = !noreferrals;
343 break;
344 #ifdef LDAP_VERSION3
345 case 'v':
346 switch (atoi(value)) {
347 case 2:
348 version = LDAP_VERSION2;
349 break;
350 case 3:
351 version = LDAP_VERSION3;
352 break;
353 default:
354 fprintf(stderr, "FATAL: Protocol version should be 2 or 3\n");
355 exit(1);
356 }
357 break;
358 case 'Z':
359 if (version == LDAP_VERSION2) {
360 fprintf(stderr, "FATAL: TLS (-Z) is incompatible with version %d\n",
361 version);
362 exit(1);
363 }
364 version = LDAP_VERSION3;
365 use_tls = 1;
366 break;
367 #endif
368 case 'd':
369 debug_enabled = 1;
370 break;
371 case 'g':
372 use_extension_dn = 1;
373 break;
374 case 'S':
375 strip_nt_domain = 1;
376 break;
377 case 'K':
378 strip_kerberos_realm = 1;
379 break;
380 default:
381 fprintf(stderr, PROGRAM_NAME ": FATAL: Unknown command line option '%c'\n", option);
382 exit(1);
383 }
384 }
385
386 while (argc > 1) {
387 char *value = argv[1];
388 if (ldapServer) {
389 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
390 char *newhost = (char*)malloc(len);
391 snprintf(newhost, len, "%s %s", ldapServer, value);
392 free(ldapServer);
393 ldapServer = newhost;
394 } else {
395 ldapServer = xstrdup(value);
396 }
397 --argc;
398 ++argv;
399 }
400
401 if (!ldapServer)
402 ldapServer = (char *) "localhost";
403
404 if (!basedn || !searchfilter) {
405 fprintf(stderr, "\n" PROGRAM_NAME " version " PROGRAM_VERSION "\n\n");
406 fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n");
407 fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under where to search for groups\n");
408 fprintf(stderr, "\t-f filter (REQUIRED)\tgroup search filter pattern. %%u = user,\n\t\t\t\t%%v = group\n");
409 fprintf(stderr, "\t-B basedn (REQUIRED)\tbase dn under where to search for users\n");
410 fprintf(stderr, "\t-F filter (REQUIRED)\tuser search filter pattern. %%s = login\n");
411 fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n");
412 fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n");
413 fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n");
414 fprintf(stderr, "\t-W secretfile\t\tread password for binddn from file secretfile\n");
415 #if HAS_URI_SUPPORT
416 fprintf(stderr, "\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
417 #endif
418 fprintf(stderr, "\t-h server\t\tLDAP server (defaults to localhost)\n");
419 fprintf(stderr, "\t-p port\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT);
420 fprintf(stderr, "\t-P\t\t\tpersistent LDAP connection\n");
421 #if defined(NETSCAPE_SSL)
422 fprintf(stderr, "\t-E sslcertpath\t\tenable LDAP over SSL\n");
423 #endif
424 fprintf(stderr, "\t-c timeout\t\tconnect timeout\n");
425 fprintf(stderr, "\t-t timelimit\t\tsearch time limit\n");
426 fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n");
427 fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
428 #ifdef LDAP_VERSION3
429 fprintf(stderr, "\t-v 2|3\t\t\tLDAP version\n");
430 fprintf(stderr, "\t-Z\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n");
431 #endif
432 fprintf(stderr, "\t-g\t\t\tfirst query parameter is base DN extension\n\t\t\t\tfor this query\n");
433 fprintf(stderr, "\t-S\t\t\tStrip NT domain from usernames\n");
434 fprintf(stderr, "\t-K\t\t\tStrip Kerberos realm from usernames\n");
435 fprintf(stderr, "\t-d\t\t\tenable debug mode\n");
436 fprintf(stderr, "\n");
437 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");
438 exit(1);
439 }
440 /* On Windows ldap_start_tls_s is available starting from Windows XP,
441 * so we need to bind at run-time with the function entry point
442 */
443 #if _SQUID_WINDOWS_
444 if (use_tls) {
445
446 HMODULE WLDAP32Handle;
447
448 WLDAP32Handle = GetModuleHandle("wldap32");
449 if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
450 fprintf(stderr, PROGRAM_NAME ": FATAL: TLS (-Z) not supported on this platform.\n");
451 exit(1);
452 }
453 }
454 #endif
455
456 while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) {
457 int found = 0;
458 if (!strchr(buf, '\n')) {
459 /* too large message received.. skip and deny */
460 fprintf(stderr, "%s: ERROR: Input Too large: %s\n", argv[0], buf);
461 while (fgets(buf, sizeof(buf), stdin)) {
462 fprintf(stderr, "%s: ERROR: Input Too large..: %s\n", argv[0], buf);
463 if (strchr(buf, '\n') != NULL)
464 break;
465 }
466 SEND_ERR("");
467 continue;
468 }
469 user = strtok(buf, " \n");
470 if (!user) {
471 debug("%s: Invalid request: No Username given\n", argv[0]);
472 SEND_ERR("Invalid request. No Username");
473 continue;
474 }
475 rfc1738_unescape(user);
476 if (strip_nt_domain) {
477 char *u = strrchr(user, '\\');
478 if (!u)
479 u = strrchr(user, '/');
480 if (!u)
481 u = strrchr(user, '+');
482 if (u && u[1])
483 user = u + 1;
484 }
485 if (strip_kerberos_realm) {
486 char *u = strchr(user, '@');
487 if (u != NULL) {
488 *u = '\0';
489 }
490 }
491 if (use_extension_dn) {
492 extension_dn = strtok(NULL, " \n");
493 if (!extension_dn) {
494 debug("%s: Invalid request: Extension DN configured, but none sent.\n", argv[0]);
495 SEND_ERR("Invalid Request. Extension DN required.");
496 continue;
497 }
498 rfc1738_unescape(extension_dn);
499 }
500 while (!found && user && (group = strtok(NULL, " \n")) != NULL) {
501 rfc1738_unescape(group);
502
503 recover:
504 if (ld == NULL) {
505 #if HAS_URI_SUPPORT
506 if (strstr(ldapServer, "://") != NULL) {
507 rc = ldap_initialize(&ld, ldapServer);
508 if (rc != LDAP_SUCCESS) {
509 fprintf(stderr, "%s: ERROR: Unable to connect to LDAPURI:%s\n", argv[0], ldapServer);
510 break;
511 }
512 } else
513 #endif
514 #if NETSCAPE_SSL
515 if (sslpath) {
516 if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
517 fprintf(stderr, "FATAL: Unable to initialise SSL with cert path %s\n", sslpath);
518 exit(1);
519 } else {
520 ++sslinit;
521 }
522 if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
523 fprintf(stderr, "FATAL: Unable to connect to SSL LDAP server: %s port:%d\n",
524 ldapServer, port);
525 exit(1);
526 }
527 } else
528 #endif
529 if ((ld = ldap_init(ldapServer, port)) == NULL) {
530 fprintf(stderr, "ERROR: Unable to connect to LDAP server:%s port:%d\n", ldapServer, port);
531 break;
532 }
533 if (connect_timeout)
534 squid_ldap_set_connect_timeout(ld, connect_timeout);
535
536 #ifdef LDAP_VERSION3
537 if (version == -1) {
538 version = LDAP_VERSION3;
539 }
540 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
541 fprintf(stderr, "ERROR: Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
542 version);
543 ldap_unbind(ld);
544 ld = NULL;
545 break;
546 }
547 if (use_tls) {
548 #ifdef LDAP_OPT_X_TLS
549 if (version != LDAP_VERSION3) {
550 fprintf(stderr, "FATAL: TLS requires LDAP version 3\n");
551 exit(1);
552 } else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
553 fprintf(stderr, "ERROR: Could not Activate TLS connection\n");
554 ldap_unbind(ld);
555 ld = NULL;
556 break;
557 }
558 #else
559 fprintf(stderr, "FATAL: TLS not supported with your LDAP library\n");
560 exit(1);
561 #endif
562 }
563 #endif
564 squid_ldap_set_timelimit(ld, timelimit);
565 squid_ldap_set_referrals(ld, !noreferrals);
566 squid_ldap_set_aliasderef(ld, aliasderef);
567 if (binddn && bindpasswd && *binddn && *bindpasswd) {
568 rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
569 if (rc != LDAP_SUCCESS) {
570 fprintf(stderr, PROGRAM_NAME ": WARNING: could not bind to binddn '%s'\n", ldap_err2string(rc));
571 ldap_unbind(ld);
572 ld = NULL;
573 break;
574 }
575 }
576 debug("Connected OK\n");
577 }
578 if (searchLDAP(ld, group, user, extension_dn) == 0) {
579 found = 1;
580 break;
581 } else {
582 if (tryagain) {
583 tryagain = 0;
584 ldap_unbind(ld);
585 ld = NULL;
586 goto recover;
587 }
588 }
589 }
590 if (found)
591 SEND_OK("");
592 else {
593 SEND_ERR("");
594 }
595
596 if (ld != NULL) {
597 if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
598 ldap_unbind(ld);
599 ld = NULL;
600 } else {
601 tryagain = 1;
602 }
603 }
604 }
605 if (ld)
606 ldap_unbind(ld);
607 return 0;
608 }
609
610 static int
611 ldap_escape_value(char *escaped, int size, const char *src)
612 {
613 int n = 0;
614 while (size > 4 && *src) {
615 switch (*src) {
616 case '*':
617 case '(':
618 case ')':
619 case '\\':
620 n += 3;
621 size -= 3;
622 if (size > 0) {
623 *escaped = '\\';
624 ++escaped;
625 snprintf(escaped, 3, "%02x", (unsigned char) *src);
626 ++src;
627 escaped += 2;
628 }
629 break;
630 default:
631 *escaped = *src;
632 ++escaped;
633 ++src;
634 ++n;
635 --size;
636 }
637 }
638 *escaped = '\0';
639 return n;
640 }
641
642 static int
643 build_filter(char *filter, int size, const char *templ, const char *user, const char *group)
644 {
645 int n;
646 while (*templ && size > 0) {
647 switch (*templ) {
648 case '%':
649 ++templ;
650 switch (*templ) {
651 case 'u':
652 case 'v':
653 ++templ;
654 n = ldap_escape_value(filter, size, user);
655 size -= n;
656 filter += n;
657 break;
658 case 'g':
659 case 'a':
660 ++templ;
661 n = ldap_escape_value(filter, size, group);
662 size -= n;
663 filter += n;
664 break;
665 default:
666 fprintf(stderr, "ERROR: Unknown filter template string %%%c\n", *templ);
667 return 1;
668 break;
669 }
670 break;
671 case '\\':
672 ++templ;
673 if (*templ) {
674 *filter = *templ;
675 ++filter;
676 ++templ;
677 --size;
678 }
679 break;
680 default:
681 *filter = *templ;
682 ++filter;
683 ++templ;
684 --size;
685 break;
686 }
687 }
688 if (size <= 0) {
689 fprintf(stderr, "ERROR: Filter too large\n");
690 return 1;
691 }
692 *filter = '\0';
693 return 0;
694 }
695
696 static int
697 searchLDAPGroup(LDAP * ld, char *group, char *member, char *extension_dn)
698 {
699 char filter[256];
700 static char searchbase[256];
701 LDAPMessage *res = NULL;
702 LDAPMessage *entry;
703 int rc;
704 char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
705
706 if (extension_dn && *extension_dn)
707 snprintf(searchbase, sizeof(searchbase), "%s,%s", extension_dn, basedn);
708 else
709 snprintf(searchbase, sizeof(searchbase), "%s", basedn);
710
711 if (build_filter(filter, sizeof(filter), searchfilter, member, group) != 0) {
712 fprintf(stderr, PROGRAM_NAME ": ERROR: Failed to construct LDAP search filter. filter=\"%s\", user=\"%s\", group=\"%s\"\n", filter, member, group);
713 return 1;
714 }
715 debug("group filter '%s', searchbase '%s'\n", filter, searchbase);
716
717 rc = ldap_search_s(ld, searchbase, searchscope, filter, searchattr, 1, &res);
718 if (rc != LDAP_SUCCESS) {
719 if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
720 /* Everything is fine. This is expected when referrals
721 * are disabled.
722 */
723 } else {
724 fprintf(stderr, PROGRAM_NAME ": WARNING: LDAP search error '%s'\n", ldap_err2string(rc));
725 #if defined(NETSCAPE_SSL)
726 if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
727 int sslerr = PORT_GetError();
728 fprintf(stderr, PROGRAM_NAME ": WARNING: SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
729 }
730 #endif
731 ldap_msgfree(res);
732 return 1;
733 }
734 }
735 entry = ldap_first_entry(ld, res);
736 if (!entry) {
737 ldap_msgfree(res);
738 return 1;
739 }
740 ldap_msgfree(res);
741 return 0;
742 }
743
744 static int
745 searchLDAP(LDAP * ld, char *group, char *login, char *extension_dn)
746 {
747
748 if (usersearchfilter) {
749 char filter[8192];
750 char searchbase[8192];
751 char escaped_login[1024];
752 LDAPMessage *res = NULL;
753 LDAPMessage *entry;
754 int rc;
755 char *userdn;
756 char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
757 if (extension_dn && *extension_dn)
758 snprintf(searchbase, sizeof(searchbase), "%s,%s", extension_dn, userbasedn ? userbasedn : basedn);
759 else
760 snprintf(searchbase, sizeof(searchbase), "%s", userbasedn ? userbasedn : basedn);
761 ldap_escape_value(escaped_login, sizeof(escaped_login), login);
762 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);
763 debug("user filter '%s', searchbase '%s'\n", filter, searchbase);
764 rc = ldap_search_s(ld, searchbase, searchscope, filter, searchattr, 1, &res);
765 if (rc != LDAP_SUCCESS) {
766 if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
767 /* Everything is fine. This is expected when referrals
768 * are disabled.
769 */
770 } else {
771 fprintf(stderr, PROGRAM_NAME ": WARNING: LDAP search error '%s'\n", ldap_err2string(rc));
772 #if defined(NETSCAPE_SSL)
773 if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
774 int sslerr = PORT_GetError();
775 fprintf(stderr, PROGRAM_NAME ": WARNING: SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
776 }
777 #endif
778 ldap_msgfree(res);
779 return 1;
780 }
781 }
782 entry = ldap_first_entry(ld, res);
783 if (!entry) {
784 fprintf(stderr, PROGRAM_NAME ": WARNING: User '%s' not found in '%s'\n", login, searchbase);
785 ldap_msgfree(res);
786 return 1;
787 }
788 userdn = ldap_get_dn(ld, entry);
789 rc = searchLDAPGroup(ld, group, userdn, extension_dn);
790 squid_ldap_memfree(userdn);
791 ldap_msgfree(res);
792 return rc;
793 } else if (userdnattr) {
794 char dn[8192];
795 if (extension_dn && *extension_dn)
796 snprintf(dn, 8192, "%s=%s, %s, %s", userdnattr, login, extension_dn, userbasedn ? userbasedn : basedn);
797 else
798 snprintf(dn, 8192, "%s=%s, %s", userdnattr, login, userbasedn ? userbasedn : basedn);
799 return searchLDAPGroup(ld, group, dn, extension_dn);
800 } else {
801 return searchLDAPGroup(ld, group, login, extension_dn);
802 }
803 }
804
805 int
806 readSecret(const char *filename)
807 {
808 char buf[BUFSIZ];
809 char *e = 0;
810 FILE *f;
811
812 if (!(f = fopen(filename, "r"))) {
813 fprintf(stderr, PROGRAM_NAME ": ERROR: Can not read secret file %s\n", filename);
814 return 1;
815 }
816 if (!fgets(buf, sizeof(buf) - 1, f)) {
817 fprintf(stderr, PROGRAM_NAME ": ERROR: Secret file %s is empty\n", filename);
818 fclose(f);
819 return 1;
820 }
821 /* strip whitespaces on end */
822 if ((e = strrchr(buf, '\n')))
823 *e = 0;
824 if ((e = strrchr(buf, '\r')))
825 *e = 0;
826
827 bindpasswd = xstrdup(buf);
828 if (!bindpasswd) {
829 fprintf(stderr, PROGRAM_NAME ": ERROR: can not allocate memory\n");
830 }
831 fclose(f);
832
833 return 0;
834 }