ext_ldap_group_acl.cc
Go to the documentation of this file.
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"
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
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
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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_BH(HLP_MSG("Input too large"));
475  continue;
476  }
477  user = strtok(buf, " \n");
478  if (!user) {
479  debug("%s: Invalid request: No Username given\n", argv[0]);
480  SEND_BH(HLP_MSG("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_BH(HLP_MSG("Invalid Request. Extension DN required"));
504  continue;
505  }
506  rfc1738_unescape(extension_dn);
507  }
508  const char *broken = nullptr;
509  while (!found && user && (group = strtok(NULL, " \n")) != NULL) {
510  rfc1738_unescape(group);
511 
512 recover:
513  if (ld == NULL) {
514 #if HAS_URI_SUPPORT
515  if (strstr(ldapServer, "://") != NULL) {
516  rc = ldap_initialize(&ld, ldapServer);
517  if (rc != LDAP_SUCCESS) {
518  broken = HLP_MSG("Unable to connect to LDAP server");
519  fprintf(stderr, "%s: ERROR: Unable to connect to LDAPURI:%s\n", argv[0], ldapServer);
520  break;
521  }
522  } else
523 #endif
524 #if NETSCAPE_SSL
525  if (sslpath) {
526  if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
527  fprintf(stderr, "FATAL: Unable to initialise SSL with cert path %s\n", sslpath);
528  exit(EXIT_FAILURE);
529  } else {
530  ++sslinit;
531  }
532  if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
533  fprintf(stderr, "FATAL: Unable to connect to SSL LDAP server: %s port:%d\n",
534  ldapServer, port);
535  exit(EXIT_FAILURE);
536  }
537  } else
538 #endif
539  if ((ld = ldap_init(ldapServer, port)) == NULL) {
540  broken = HLP_MSG("Unable to connect to LDAP server");
541  fprintf(stderr, "ERROR: %s:%s port:%d\n", broken, ldapServer, port);
542  break;
543  }
544  if (connect_timeout)
545  squid_ldap_set_connect_timeout(ld, connect_timeout);
546 
547 #ifdef LDAP_VERSION3
548  if (version == -1) {
549  version = LDAP_VERSION3;
550  }
551  if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
552  broken = HLP_MSG("Could not set LDAP_OPT_PROTOCOL_VERSION");
553  fprintf(stderr, "ERROR: %s %d\n", broken, version);
554  ldap_unbind(ld);
555  ld = NULL;
556  break;
557  }
558  if (use_tls) {
559 #ifdef LDAP_OPT_X_TLS
560  if (version != LDAP_VERSION3) {
561  fprintf(stderr, "FATAL: TLS requires LDAP version 3\n");
562  exit(EXIT_FAILURE);
563  } else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
564  broken = HLP_MSG("Could not Activate TLS connection");
565  fprintf(stderr, "ERROR: %s\n", broken);
566  ldap_unbind(ld);
567  ld = NULL;
568  break;
569  }
570 #else
571  fprintf(stderr, "FATAL: TLS not supported with your LDAP library\n");
572  exit(EXIT_FAILURE);
573 #endif
574  }
575 #endif
576  squid_ldap_set_timelimit(ld, timelimit);
577  squid_ldap_set_referrals(ld, !noreferrals);
578  squid_ldap_set_aliasderef(ld, aliasderef);
579  if (binddn && bindpasswd && *binddn && *bindpasswd) {
580  rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
581  if (rc != LDAP_SUCCESS) {
582  broken = HLP_MSG("could not bind");
583  fprintf(stderr, PROGRAM_NAME ": WARNING: %s to binddn '%s'\n", broken, ldap_err2string(rc));
584  ldap_unbind(ld);
585  ld = NULL;
586  break;
587  }
588  }
589  debug("Connected OK\n");
590  }
591  int searchResult = searchLDAP(ld, group, user, extension_dn);
592  if (searchResult == 0) {
593  found = 1;
594  break;
595  } else if (searchResult < 0) {
596  if (tryagain) {
597  tryagain = 0;
598  ldap_unbind(ld);
599  ld = NULL;
600  goto recover;
601  }
602  broken = HLP_MSG("LDAP search error");
603  }
604  }
605  if (found)
606  SEND_OK("");
607  else if (broken)
608  SEND_BH(broken);
609  else {
610  SEND_ERR("");
611  }
612 
613  if (ld != NULL) {
614  if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
615  ldap_unbind(ld);
616  ld = NULL;
617  } else {
618  tryagain = 1;
619  }
620  }
621  }
622  if (ld)
623  ldap_unbind(ld);
624  return EXIT_SUCCESS;
625 }
626 
627 static std::string
628 ldap_escape_value(const std::string &src)
629 {
630  std::stringstream str;
631  for (const auto &c : src) {
632  switch (c) {
633  case '*':
634  case '(':
635  case ')':
636  case '\\':
637  str << '\\' << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(c);
638  break;
639  default:
640  str << c;
641  }
642  }
643  return str.str();
644 }
645 
646 static bool
647 build_filter(std::string &filter, const char *templ, const char *user, const char *group)
648 {
649  std::stringstream str;
650  while (*templ) {
651  switch (*templ) {
652  case '%':
653  ++templ;
654  switch (*templ) {
655  case 'u':
656  case 'v':
657  ++templ;
658  str << ldap_escape_value(user);
659  break;
660  case 'g':
661  case 'a':
662  ++templ;
663  str << ldap_escape_value(group);
664  break;
665  default:
666  fprintf(stderr, "ERROR: Unknown filter template string %%%c\n", *templ);
667  filter = str.str();
668  return false;
669  }
670  break;
671  case '\\':
672  ++templ;
673  if (*templ) {
674  str << *templ;
675  ++templ;
676  }
677  break;
678  default:
679  str << *templ;
680  ++templ;
681  break;
682  }
683  }
684  filter = str.str();
685  return true;
686 }
687 
688 static std::string
689 build_searchbase(const char *extension_dn, const char *base_dn)
690 {
691  std::stringstream searchBaseStream;
692  if (extension_dn && *extension_dn)
693  searchBaseStream << extension_dn << ",";
694  searchBaseStream << base_dn;
695  return searchBaseStream.str();
696 }
697 
698 static bool ldap_search_ok(const int result)
699 {
700  if (result == LDAP_SUCCESS)
701  return true;
702  if (noreferrals && result == LDAP_PARTIAL_RESULTS) {
703  /* Everything is fine. This is expected when referrals
704  * are disabled.
705  */
706  return true;
707  }
708  std::cerr << PROGRAM_NAME << ": WARNING: LDAP search error '" <<
709  ldap_err2string(result) << "'" << std::endl;
710 #if defined(NETSCAPE_SSL)
711  if (sslpath && ((result == LDAP_SERVER_DOWN) || (result == LDAP_CONNECT_ERROR))) {
712  int sslerr = PORT_GetError();
713  std::cerr << PROGRAM_NAME << ": WARNING: SSL error " << sslerr << " (" <<
714  ldapssl_err2string(sslerr) << ")" << std::endl;
715  }
716 #endif
717  return false;
718 }
719 
720 typedef const std::unique_ptr<LDAPMessage, decltype(&ldap_msgfree)> LdapResult;
721 
722 static int
723 searchLDAPGroup(LDAP * ld, const char *group, const char *member, const char *extension_dn)
724 {
725  std::string filter;
726  LDAPMessage *res = NULL;
727  int rc;
728  char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
729 
730  const std::string searchbase = build_searchbase(extension_dn, basedn);
731  if (!build_filter(filter, searchfilter, member, group)) {
732  std::cerr << PROGRAM_NAME << ": ERROR: Failed to construct LDAP search filter. filter=\"" <<
733  filter.c_str() << "\", user=\"" << member << "\", group=\"" << group << "\"" << std::endl;
734  return -1;
735  }
736  debug("group filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
737 
738  rc = ldap_search_s(ld, searchbase.c_str(), searchscope, filter.c_str(), searchattr, 1, &res);
739  LdapResult ldapRes(res, ldap_msgfree);
740  if (!ldap_search_ok(rc))
741  return -1;
742 
743  return ldap_first_entry(ld, ldapRes.get()) ? 0 : 1;
744 }
745 
746 static void
747 formatWithString(std::string &formatted, const std::string &value)
748 {
749  size_t start_pos = 0;
750  while ((start_pos = formatted.find("%s", start_pos)) != std::string::npos) {
751  formatted.replace(start_pos, 2, value);
752  start_pos += 2;
753  }
754 }
755 
756 static int
757 searchLDAP(LDAP * ld, char *group, char *login, char *extension_dn)
758 {
759 
760  const char *current_userdn = userbasedn ? userbasedn : basedn;
761  if (usersearchfilter) {
762  LDAPMessage *res = NULL;
763  LDAPMessage *entry;
764  int rc;
765  char *userdn;
766  char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
767  const std::string searchbase = build_searchbase(extension_dn, current_userdn);
768  std::string filter(usersearchfilter);
769  const std::string escaped_login = ldap_escape_value(login);
770  formatWithString(filter, escaped_login);
771 
772  debug("user filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
773  rc = ldap_search_s(ld, searchbase.c_str(), searchscope, filter.c_str(), searchattr, 1, &res);
774  LdapResult ldapRes(res, ldap_msgfree);
775  if (!ldap_search_ok(rc))
776  return -1;
777  entry = ldap_first_entry(ld, ldapRes.get());
778  if (!entry) {
779  std::cerr << PROGRAM_NAME << ": WARNING: User '" << login <<
780  " not found in '" << searchbase.c_str() << "'" << std::endl;
781  return 1;
782  }
783  userdn = ldap_get_dn(ld, entry);
784  rc = searchLDAPGroup(ld, group, userdn, extension_dn);
785  squid_ldap_memfree(userdn);
786  return rc;
787  } else if (userdnattr) {
788  std::stringstream str;
789  str << userdnattr << "=" << login << ", ";
790  if (extension_dn && *extension_dn)
791  str << extension_dn << ", ";
792  str << current_userdn;
793  return searchLDAPGroup(ld, group, str.str().c_str(), extension_dn);
794  } else {
795  return searchLDAPGroup(ld, group, login, extension_dn);
796  }
797 }
798 
799 int
800 readSecret(const char *filename)
801 {
802  char buf[BUFSIZ];
803  char *e = 0;
804  FILE *f;
805 
806  if (!(f = fopen(filename, "r"))) {
807  fprintf(stderr, PROGRAM_NAME ": ERROR: Can not read secret file %s\n", filename);
808  return 1;
809  }
810  if (!fgets(buf, sizeof(buf) - 1, f)) {
811  fprintf(stderr, PROGRAM_NAME ": ERROR: Secret file %s is empty\n", filename);
812  fclose(f);
813  return 1;
814  }
815  /* strip whitespaces on end */
816  if ((e = strrchr(buf, '\n')))
817  *e = 0;
818  if ((e = strrchr(buf, '\r')))
819  *e = 0;
820 
821  bindpasswd = xstrdup(buf);
822  if (!bindpasswd) {
823  fprintf(stderr, PROGRAM_NAME ": ERROR: can not allocate memory\n");
824  }
825  fclose(f);
826 
827  return 0;
828 }
829 
static void squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
static const char * usersearchfilter
static const char * bindpasswd
int debug_enabled
Definition: debug.cc:13
static int searchLDAPGroup(LDAP *ld, const char *group, const char *member, const char *extension_dn)
static void squid_ldap_set_referrals(LDAP *ld, int referrals)
#define xstrdup
static int version
static int use_tls
static int connect_timeout
static int persistent
int main(int argc, char **argv)
static const char * userdnattr
char * p
Definition: membanger.c:43
static const char * basedn
static bool build_filter(std::string &filter, const char *templ, const char *user, const char *group)
static int readSecret(const char *filename)
#define SEND_OK(x)
static int squid_ldap_errno(LDAP *ld)
static int searchscope
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:26
#define HLP_MSG(text)
static int searchLDAP(LDAP *ld, char *group, char *user, char *extension_dn)
static const char * binddn
static std::string build_searchbase(const char *extension_dn, const char *base_dn)
static int debug
Definition: tcp-banger3.c:105
static void formatWithString(std::string &formatted, const std::string &value)
static std::string ldap_escape_value(const std::string &src)
#define PROGRAM_VERSION
static int port
Definition: ldap_backend.cc:69
static void squid_ldap_set_aliasderef(LDAP *ld, int deref)
#define BUFSIZ
Definition: defines.h:20
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void const char * buf
Definition: stub_helper.cc:16
static bool ldap_search_ok(const int result)
static int noreferrals
static void squid_ldap_set_timelimit(LDAP *ld, int timelimit)
#define xmalloc
#define SEND_BH(x)
static void squid_ldap_memfree(char *p)
static int strip_nt_domain
Definition: ldap_backend.cc:70
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
static int timelimit
static char * ldapServer
Definition: ldap_backend.cc:58
unsigned int ULONG
Definition: smblib-priv.h:147
#define PROGRAM_NAME
#define LDAP_NO_ATTRS
static int aliasderef
#define SEND_ERR(x)
const std::unique_ptr< LDAPMessage, decltype(&ldap_msgfree)> LdapResult
static const char * userbasedn
#define NULL
Definition: types.h:166
static const char * searchfilter
#define free(a)
Definition: hash.c:31

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors