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