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