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