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

 

Introduction

Documentation

Support

Miscellaneous