]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/LDAP_group/ext_ldap_group_acl.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / external_acl / LDAP_group / ext_ldap_group_acl.cc
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"
68 typedef 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"
71 typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
72 #endif /* LDAP_UNICODE */
73 PFldap_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.18"
90
91 /* Globals */
92
93 static const char *basedn = NULL;
94 static const char *searchfilter = NULL;
95 static const char *userbasedn = NULL;
96 static const char *userdnattr = NULL;
97 static const char *usersearchfilter = NULL;
98 static const char *binddn = NULL;
99 static const char *bindpasswd = NULL;
100 static int searchscope = LDAP_SCOPE_SUBTREE;
101 static int persistent = 0;
102 static int noreferrals = 0;
103 static int aliasderef = LDAP_DEREF_NEVER;
104 #if defined(NETSCAPE_SSL)
105 static char *sslpath = NULL;
106 static int sslinit = 0;
107 #endif
108 static int connect_timeout = 0;
109 static int timelimit = LDAP_NO_LIMIT;
110
111 #ifdef LDAP_VERSION3
112 /* Added for TLS support and version 3 */
113 static int use_tls = 0;
114 static int version = -1;
115 #endif
116
117 static int searchLDAP(LDAP * ld, char *group, char *user, char *extension_dn);
118
119 static 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
128 static int
129 squid_ldap_errno(LDAP * ld)
130 {
131 int err = 0;
132 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
133 return err;
134 }
135 static void
136 squid_ldap_set_aliasderef(LDAP * ld, int deref)
137 {
138 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
139 }
140 static void
141 squid_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 }
146 static void
147 squid_ldap_set_timelimit(LDAP * ld, int aTimeLimit)
148 {
149 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &aTimeLimit);
150 }
151 static void
152 squid_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 }
164 static void
165 squid_ldap_memfree(char *p)
166 {
167 ldap_memfree(p);
168 }
169
170 #else
171 static int
172 squid_ldap_errno(LDAP * ld)
173 {
174 return ld->ld_errno;
175 }
176 static void
177 squid_ldap_set_aliasderef(LDAP * ld, int deref)
178 {
179 ld->ld_deref = deref;
180 }
181 static void
182 squid_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 }
189 static void
190 squid_ldap_set_timelimit(LDAP * ld, int timelimit)
191 {
192 ld->ld_timelimit = timelimit;
193 }
194 static void
195 squid_ldap_set_connect_timeout(LDAP * ld, int timelimit)
196 {
197 fprintf(stderr, "WARNING: Connect timeouts not supported in your LDAP library\n");
198 }
199 static void
200 squid_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
213 int
214 main(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
506 recover:
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
613 static int
614 ldap_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
645 static int
646 build_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
699 static int
700 searchLDAPGroup(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
747 static int
748 searchLDAP(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
808 int
809 readSecret(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 }
838