basic_ldap_auth.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  * squid_ldap_auth: authentication via ldap for squid proxy server
11  *
12  * Authors:
13  * Henrik Nordstrom
14  * hno@squid-cache.org
15  *
16  * Glen Newton
17  * glen.newton@nrc.ca
18  * Advanced Services
19  * CISTI
20  * National Research Council
21  *
22  * with contributions from others mentioned in the Changes section below
23  *
24  * Usage: squid_ldap_auth -b basedn [-s searchscope]
25  * [-f searchfilter] [-D binddn -w bindpasswd]
26  * [-u attr] [-h host] [-p port] [-P] [-R] [ldap_server_name[:port]] ...
27  *
28  * Dependencies: You need to get the OpenLDAP libraries
29  * from http://www.openldap.org or another compatible LDAP C-API
30  * implementation.
31  *
32  * If you want to make a TLS enabled connection you will also need the
33  * OpenSSL libraries linked into openldap. See http://www.openssl.org/
34  *
35  * License: squid_ldap_auth is free software; you can redistribute it
36  * and/or modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2,
38  * or (at your option) any later version.
39  *
40  * Changes:
41  * 2019-01-02: Amish
42  * - Use SEND_*() macro and support for BH error
43  * 2005-01-07: Henrik Nordstrom <hno@squid-cache.org>
44  * - Added some sanity checks on login names to avoid
45  * users bypassing equality checks by exploring the
46  * overly helpful match capabilities of LDAP
47  * 2004-07-17: Henrik Nordstrom <hno@squid-cache.org>
48  * - Corrected non-persistent mode to only issue one
49  * ldap_bind per connection.
50  * - -U option to compare the users password rather
51  * than binding.
52  * 2004-03-01: Henrik Nordstrom <hno@squid-cache.org>
53  * - corrected building of search filters to escape
54  * unsafe input
55  * - -d option for "debug" like squid_ldap_group
56  * 2004-01-05: Henrik Nordstrom <hno@squid-cache.org>
57  * - Corrected TLS mode
58  * 2003-03-01: David J N Begley
59  * - Support for Netscape API method of ldap over SSL
60  * connections
61  * - Timeout option for better recovery when using
62  * multiple LDAP servers
63  * 2003-03-01: Christoph Lechleitner <lech@ibcl.at>
64  * - Added -W option to read bindpasswd from file
65  * 2003-03-01: Juerg Michel
66  * - Added support for ldap URI via the -H option
67  * (requires OpenLDAP)
68  * 2001-12-12: Michael Cunningham <m.cunningham@xpedite.com>
69  * - Added TLS support and partial ldap version 3 support.
70  * 2001-10-04: Henrik Nordstrom <hno@squid-cache.org>
71  * - Be consistent with the other helpers in how
72  * spaces are managed. If there is space characters
73  * then these are assumed to be part of the password
74  * 2001-09-05: Henrik Nordstrom <hno@squid-cache.org>
75  * - Added ability to specify another default LDAP port to
76  * connect to. Persistent connections moved to -P
77  * 2001-05-02: Henrik Nordstrom <hno@squid-cache.org>
78  * - Support newer OpenLDAP 2.x libraries using the
79  * revised Internet Draft API which unfortunately
80  * is not backwards compatible with RFC1823..
81  * 2001-04-15: Henrik Nordstrom <hno@squid-cache.org>
82  * - Added command line option for basedn
83  * - Added the ability to search for the user DN
84  * 2001-04-16: Henrik Nordstrom <hno@squid-cache.org>
85  * - Added -D binddn -w bindpasswd.
86  * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org>
87  * - Added -R to disable referrals
88  * - Added -a to control alias dereferencing
89  * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org>
90  * - Added -u, DN username attribute name
91  * 2001-04-18: Henrik Nordstrom <hno@squid-cache.org>
92  * - Allow full filter specifications in -f
93  */
94 
95 #include "squid.h"
97 
98 #define LDAP_DEPRECATED 1
99 
100 #include "rfc1738.h"
101 #include "util.h"
102 
103 #include <cctype>
104 #include <cstring>
105 
106 #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
107 #define snprintf _snprintf
108 #include <windows.h>
109 #include <winldap.h>
110 #ifndef LDAPAPI
111 #define LDAPAPI __cdecl
112 #endif
113 #ifdef LDAP_VERSION3
114 #ifndef LDAP_OPT_X_TLS
115 #define LDAP_OPT_X_TLS 0x6000
116 #endif
117 /* Some tricks to allow dynamic bind with ldap_start_tls_s entry point at
118  * run time.
119  */
120 #undef ldap_start_tls_s
121 #if LDAP_UNICODE
122 #define LDAP_START_TLS_S "ldap_start_tls_sW"
123 typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *);
124 #else
125 #define LDAP_START_TLS_S "ldap_start_tls_sA"
126 typedef WINLDAPAPI ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
127 #endif /* LDAP_UNICODE */
128 PFldap_start_tls_s Win32_ldap_start_tls_s;
129 #define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l, nullptr, nullptr,s,c)
130 #endif /* LDAP_VERSION3 */
131 
132 #else
133 
134 #include <lber.h>
135 #include <ldap.h>
136 
137 #ifndef LDAP_SECURITY_ERROR
138 #define LDAP_SECURITY_ERROR(err) (0x2f <= (err) && (err) <= 0x32) // [47, 50]
139 #endif
140 
141 #endif
142 
143 #define PROGRAM_NAME "basic_ldap_auth"
144 
145 /* Global options */
146 static const char *basedn;
147 static const char *searchfilter = nullptr;
148 static const char *binddn = nullptr;
149 static const char *bindpasswd = nullptr;
150 static const char *userattr = "uid";
151 static const char *passwdattr = nullptr;
152 static int searchscope = LDAP_SCOPE_SUBTREE;
153 static int persistent = 0;
154 static int bind_once = 0;
155 static int noreferrals = 0;
156 static int aliasderef = LDAP_DEREF_NEVER;
157 #if defined(NETSCAPE_SSL)
158 static const char *sslpath = nullptr;
159 static int sslinit = 0;
160 #endif
161 static int connect_timeout = 0;
162 static int timelimit = LDAP_NO_LIMIT;
163 
164 /* Added for TLS support and version 3 */
165 static int use_tls = 0;
166 static int version = -1;
167 
168 static int checkLDAP(LDAP * ld, const char *userid, const char *password, const char *server, int port);
169 static int readSecret(const char *filename);
170 
171 /* Yuck.. we need to glue to different versions of the API */
172 
173 #ifndef LDAP_NO_ATTRS
174 #define LDAP_NO_ATTRS "1.1"
175 #endif
176 
177 #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
178 static int
179 squid_ldap_errno(LDAP * ld)
180 {
181  int err = 0;
182  ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
183  return err;
184 }
185 static void
186 squid_ldap_set_aliasderef(LDAP * ld, int deref)
187 {
188  ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
189 }
190 static void
191 squid_ldap_set_referrals(LDAP * ld, int referrals)
192 {
193  int *value = static_cast<int*>(referrals ? LDAP_OPT_ON :LDAP_OPT_OFF);
194  ldap_set_option(ld, LDAP_OPT_REFERRALS, value);
195 }
196 static void
197 squid_ldap_set_timelimit(LDAP * ld, int aTimeLimit)
198 {
199  ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &aTimeLimit);
200 }
201 static void
202 squid_ldap_set_connect_timeout(LDAP * ld, int aTimeLimit)
203 {
204 #if defined(LDAP_OPT_NETWORK_TIMEOUT)
205  struct timeval tv;
206  tv.tv_sec = aTimeLimit;
207  tv.tv_usec = 0;
208  ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
209 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
210  aTimeLimit *= 1000;
211  ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &aTimeLimit);
212 #endif
213 }
214 static void
215 squid_ldap_memfree(char *p)
216 {
217  ldap_memfree(p);
218 }
219 
220 #else
221 static int
223 {
224  return ld->ld_errno;
225 }
226 static void
227 squid_ldap_set_aliasderef(LDAP * ld, int deref)
228 {
229  ld->ld_deref = deref;
230 }
231 static void
232 squid_ldap_set_referrals(LDAP * ld, int referrals)
233 {
234  if (referrals)
235  ld->ld_options |= ~LDAP_OPT_REFERRALS;
236  else
237  ld->ld_options &= ~LDAP_OPT_REFERRALS;
238 }
239 static void
241 {
242  ld->ld_timelimit = timelimit;
243 }
244 static void
246 {
247  fprintf(stderr, "Connect timeouts not supported in your LDAP library\n");
248 }
249 static void
251 {
252  free(p);
253 }
254 
255 #endif
256 
257 #ifdef LDAP_API_FEATURE_X_OPENLDAP
258 #if LDAP_VENDOR_VERSION > 194
259 #define HAS_URI_SUPPORT 1
260 #endif
261 #endif
262 
263 static LDAP *
265 {
266  LDAP *ld = nullptr;
267 #if HAS_URI_SUPPORT
268  if (strstr(ldapServer, "://") != nullptr) {
269  int rc = ldap_initialize(&ld, ldapServer);
270  if (rc != LDAP_SUCCESS) {
271  fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
272  exit(EXIT_FAILURE);
273  }
274  } else
275 #endif
276 #if NETSCAPE_SSL
277  if (sslpath) {
278  if (!sslinit && (ldapssl_client_init(sslpath, nullptr) != LDAP_SUCCESS)) {
279  fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
280  sslpath);
281  exit(EXIT_FAILURE);
282  } else {
283  ++sslinit;
284  }
285  if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
286  fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
287  ldapServer, port);
288  exit(EXIT_FAILURE);
289  }
290  } else
291 #endif
292  if ((ld = ldap_init(ldapServer, port)) == nullptr) {
293  fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",
294  ldapServer, port);
295  exit(EXIT_FAILURE);
296  }
297  if (connect_timeout)
299 
300 #ifdef LDAP_VERSION3
301  if (version == -1) {
302  version = LDAP_VERSION3;
303  }
304  if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
305  fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
306  version);
307  exit(EXIT_FAILURE);
308  }
309  if (use_tls) {
310 #ifdef LDAP_OPT_X_TLS
311  if (version != LDAP_VERSION3) {
312  fprintf(stderr, "TLS requires LDAP version 3\n");
313  exit(EXIT_FAILURE);
314  } else if (ldap_start_tls_s(ld, nullptr, nullptr) != LDAP_SUCCESS) {
315  fprintf(stderr, "Could not Activate TLS connection\n");
316  exit(EXIT_FAILURE);
317  }
318 #else
319  fprintf(stderr, "TLS not supported with your LDAP library\n");
320  exit(EXIT_FAILURE);
321 #endif
322  }
323 #endif
327  return ld;
328 }
329 
330 /* Make a sanity check on the username to reject oddly typed names */
331 static int
332 validUsername(const char *user)
333 {
334  const unsigned char *p = (const unsigned char *) user;
335 
336  /* Leading whitespace? */
337  if (xisspace(p[0]))
338  return 0;
339  while (p[0] && p[1]) {
340  if (xisspace(p[0])) {
341  /* More than one consequitive space? */
342  if (xisspace(p[1]))
343  return 0;
344  /* or odd space type character used? */
345  if (p[0] != ' ')
346  return 0;
347  }
348  ++p;
349  }
350  /* Trailing whitespace? */
351  if (xisspace(p[0]))
352  return 0;
353  return 1;
354 }
355 
356 int
357 main(int argc, char **argv)
358 {
359  char buf[1024];
360  char *user, *passwd;
361  char *ldapServer = nullptr;
362  LDAP *ld = nullptr;
363  int tryagain;
364  int port = LDAP_PORT;
365 
366  setbuf(stdout, nullptr);
367 
368  while (argc > 1 && argv[1][0] == '-') {
369  const char *value = "";
370  char option = argv[1][1];
371  switch (option) {
372  case 'P':
373  case 'R':
374  case 'z':
375  case 'Z':
376  case 'd':
377  case 'O':
378  break;
379  default:
380  if (strlen(argv[1]) > 2) {
381  value = argv[1] + 2;
382  } else if (argc > 2) {
383  value = argv[2];
384  ++argv;
385  --argc;
386  } else
387  value = "";
388  break;
389  }
390  ++argv;
391  --argc;
392  switch (option) {
393  case 'H':
394 #if !HAS_URI_SUPPORT
395  fprintf(stderr, "ERROR: Your LDAP library does not have URI support\n");
396  exit(EXIT_FAILURE);
397 #endif
398  /* Fall thru to -h */
399  case 'h':
400  if (ldapServer) {
401  int len = strlen(ldapServer) + 1 + strlen(value) + 1;
402  char *newhost = static_cast<char*>(xmalloc(len));
403  snprintf(newhost, len, "%s %s", ldapServer, value);
404  free(ldapServer);
405  ldapServer = newhost;
406  } else {
407  ldapServer = xstrdup(value);
408  }
409  break;
410  case 'b':
411  basedn = value;
412  break;
413  case 'f':
414  searchfilter = value;
415  break;
416  case 'u':
417  userattr = value;
418  break;
419  case 'U':
420  passwdattr = value;
421  break;
422  case 's':
423  if (strcmp(value, "base") == 0)
424  searchscope = LDAP_SCOPE_BASE;
425  else if (strcmp(value, "one") == 0)
426  searchscope = LDAP_SCOPE_ONELEVEL;
427  else if (strcmp(value, "sub") == 0)
428  searchscope = LDAP_SCOPE_SUBTREE;
429  else {
430  fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown search scope '%s'\n", value);
431  exit(EXIT_FAILURE);
432  }
433  break;
434  case 'E':
435 #if defined(NETSCAPE_SSL)
436  sslpath = value;
437  if (port == LDAP_PORT)
438  port = LDAPS_PORT;
439 #else
440  fprintf(stderr, PROGRAM_NAME " ERROR: -E unsupported with this LDAP library\n");
441  exit(EXIT_FAILURE);
442 #endif
443  break;
444  case 'c':
445  connect_timeout = atoi(value);
446  break;
447  case 't':
448  timelimit = atoi(value);
449  break;
450  case 'a':
451  if (strcmp(value, "never") == 0)
452  aliasderef = LDAP_DEREF_NEVER;
453  else if (strcmp(value, "always") == 0)
454  aliasderef = LDAP_DEREF_ALWAYS;
455  else if (strcmp(value, "search") == 0)
456  aliasderef = LDAP_DEREF_SEARCHING;
457  else if (strcmp(value, "find") == 0)
458  aliasderef = LDAP_DEREF_FINDING;
459  else {
460  fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown alias dereference method '%s'\n", value);
461  exit(EXIT_FAILURE);
462  }
463  break;
464  case 'D':
465  binddn = value;
466  break;
467  case 'w':
468  bindpasswd = value;
469  break;
470  case 'W':
471  readSecret(value);
472  break;
473  case 'P':
475  break;
476  case 'O':
477  bind_once = !bind_once;
478  break;
479  case 'p':
480  port = atoi(value);
481  break;
482  case 'R':
484  break;
485 #ifdef LDAP_VERSION3
486  case 'v':
487  switch (atoi(value)) {
488  case 2:
489  version = LDAP_VERSION2;
490  break;
491  case 3:
492  version = LDAP_VERSION3;
493  break;
494  default:
495  fprintf(stderr, "Protocol version should be 2 or 3\n");
496  exit(EXIT_FAILURE);
497  }
498  break;
499  case 'Z':
500  if (version == LDAP_VERSION2) {
501  fprintf(stderr, "TLS (-Z) is incompatible with version %d\n",
502  version);
503  exit(EXIT_FAILURE);
504  }
505  version = LDAP_VERSION3;
506  use_tls = 1;
507  break;
508 #endif
509  case 'd':
510  debug_enabled = 1;
511  break;
512  default:
513  fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown command line option '%c'\n", option);
514  exit(EXIT_FAILURE);
515  }
516  }
517 
518  while (argc > 1) {
519  char *value = argv[1];
520  if (ldapServer) {
521  int len = strlen(ldapServer) + 1 + strlen(value) + 1;
522  char *newhost = static_cast<char*>(xmalloc(len));
523  snprintf(newhost, len, "%s %s", ldapServer, value);
524  free(ldapServer);
525  ldapServer = newhost;
526  } else {
527  ldapServer = xstrdup(value);
528  }
529  --argc;
530  ++argv;
531  }
532  if (!ldapServer)
533  ldapServer = xstrdup("localhost");
534 
535  if (!basedn) {
536  fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn [options] [ldap_server_name[:port]]...\n\n");
537  fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under which to search\n");
538  fprintf(stderr, "\t-f filter\t\tsearch filter to locate user DN\n");
539  fprintf(stderr, "\t-u userattr\t\tusername DN attribute\n");
540  fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n");
541  fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n");
542  fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n");
543  fprintf(stderr, "\t-W secretfile\t\tread password for binddn from file secretfile\n");
544 #if HAS_URI_SUPPORT
545  fprintf(stderr, "\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
546 #endif
547  fprintf(stderr, "\t-h server\t\tLDAP server (defaults to localhost)\n");
548  fprintf(stderr, "\t-p port\t\t\tLDAP server port\n");
549  fprintf(stderr, "\t-P\t\t\tpersistent LDAP connection\n");
550 #if defined(NETSCAPE_SSL)
551  fprintf(stderr, "\t-E sslcertpath\t\tenable LDAP over SSL\n");
552 #endif
553  fprintf(stderr, "\t-c timeout\t\tconnect timeout\n");
554  fprintf(stderr, "\t-t timelimit\t\tsearch time limit\n");
555  fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n");
556  fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
557 #ifdef LDAP_VERSION3
558  fprintf(stderr, "\t-v 2|3\t\t\tLDAP version\n");
559  fprintf(stderr, "\t-Z\t\t\tTLS encrypt the LDAP connection, requires LDAP version 3\n");
560 #endif
561  fprintf(stderr, "\t-d\t\t\tenable debug mode\n");
562  fprintf(stderr, "\n");
563  fprintf(stderr, "\tIf no search filter is specified, then the dn <userattr>=user,basedn\n\twill be used (same as specifying a search filter of '<userattr>=',\n\tbut quicker as as there is no need to search for the user DN)\n\n");
564  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");
565  exit(EXIT_FAILURE);
566  }
567  /* On Windows ldap_start_tls_s is available starting from Windows XP,
568  * so we need to bind at run-time with the function entry point
569  */
570 #if _SQUID_WINDOWS_
571  if (use_tls) {
572 
573  HMODULE WLDAP32Handle;
574 
575  WLDAP32Handle = GetModuleHandle("wldap32");
576  if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
577  fprintf(stderr, PROGRAM_NAME ": ERROR: TLS (-Z) not supported on this platform.\n");
578  exit(EXIT_FAILURE);
579  }
580  }
581 #endif
582 
583  while (fgets(buf, sizeof(buf), stdin) != nullptr) {
584  user = strtok(buf, " \r\n");
585  passwd = strtok(nullptr, "\r\n");
586 
587  if (!user) {
588  SEND_ERR(HLP_MSG("Missing username"));
589  continue;
590  }
591  if (!passwd || !passwd[0]) {
592  SEND_ERR(HLP_MSG("Missing password"));
593  continue;
594  }
595  rfc1738_unescape(user);
596  rfc1738_unescape(passwd);
597  if (!validUsername(user)) {
598  SEND_ERR(HLP_MSG("Invalid username"));
599  continue;
600  }
601  tryagain = (ld != nullptr);
602 recover:
603  if (ld == nullptr && persistent)
605  if (checkLDAP(ld, user, passwd, ldapServer, port) != 0) {
606  const auto e = squid_ldap_errno(ld);
607  if (tryagain && e != LDAP_INVALID_CREDENTIALS) {
608  tryagain = 0;
609  ldap_unbind(ld);
610  ld = nullptr;
611  goto recover;
612  }
613  if (LDAP_SECURITY_ERROR(e))
614  SEND_ERR(ldap_err2string(e));
615  else
616  SEND_BH(ldap_err2string(e));
617  } else {
618  SEND_OK("");
619  }
620  if (ld && (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
621  ldap_unbind(ld);
622  ld = nullptr;
623  }
624  }
625  if (ld)
626  ldap_unbind(ld);
627  return EXIT_SUCCESS;
628 }
629 
630 static int
631 ldap_escape_value(char *escaped, int size, const char *src)
632 {
633  int n = 0;
634  while (size > 4 && *src) {
635  switch (*src) {
636  case '*':
637  case '(':
638  case ')':
639  case '\\':
640  n += 3;
641  size -= 3;
642  if (size > 0) {
643  *escaped = '\\';
644  ++escaped;
645  snprintf(escaped, 3, "%02x", (unsigned char) *src);
646  ++src;
647  escaped += 2;
648  }
649  break;
650  default:
651  *escaped = *src;
652  ++escaped;
653  ++src;
654  ++n;
655  --size;
656  }
657  }
658  *escaped = '\0';
659  return n;
660 }
661 
662 /* Check the userid & password.
663  * Return 0 on success, 1 on failure
664  */
665 static int
666 checkLDAP(LDAP * persistent_ld, const char *userid, const char *password, const char *ldapServer, int port)
667 {
668  char dn[1024];
669  int ret = 0;
670  LDAP *bind_ld = nullptr;
671 
672  if (!*password) {
673  /* LDAP can't bind with a blank password. Seen as "anonymous"
674  * and always granted access
675  */
676  debug("Blank password given\n");
677  return 1;
678  }
679  if (searchfilter) {
680  char filter[16384];
681  char escaped_login[1024];
682  LDAPMessage *res = nullptr;
683  LDAPMessage *entry;
684  char *searchattr[] = {(char *)LDAP_NO_ATTRS, nullptr};
685  char *userdn;
686  int rc;
687  LDAP *search_ld = persistent_ld;
688 
689  if (!search_ld)
690  search_ld = open_ldap_connection(ldapServer, port);
691 
692  ldap_escape_value(escaped_login, sizeof(escaped_login), userid);
693  if (binddn) {
694  rc = ldap_simple_bind_s(search_ld, binddn, bindpasswd);
695  if (rc != LDAP_SUCCESS) {
696  fprintf(stderr, PROGRAM_NAME ": WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc));
697  ret = 1;
698  goto search_done;
699  }
700  }
701  snprintf(filter, sizeof(filter), searchfilter, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login, escaped_login);
702  debug("user filter '%s', searchbase '%s'\n", filter, basedn);
703  rc = ldap_search_s(search_ld, basedn, searchscope, filter, searchattr, 1, &res);
704  if (rc != LDAP_SUCCESS) {
705  if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
706  /* Everything is fine. This is expected when referrals
707  * are disabled.
708  */
709  debug("noreferrals && rc == LDAP_PARTIAL_RESULTS\n");
710  } else {
711  fprintf(stderr, PROGRAM_NAME ": WARNING, LDAP search error '%s'\n", ldap_err2string(rc));
712 #if defined(NETSCAPE_SSL)
713  if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
714  int sslerr = PORT_GetError();
715  fprintf(stderr, PROGRAM_NAME ": WARNING, SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
716  }
717 #endif
718  ret = 1;
719  goto search_done;
720  }
721  }
722  entry = ldap_first_entry(search_ld, res);
723  if (!entry) {
724  debug("Ldap search returned nothing\n");
725  ret = 1;
726  goto search_done;
727  }
728  userdn = ldap_get_dn(search_ld, entry);
729  if (!userdn) {
730  fprintf(stderr, PROGRAM_NAME ": ERROR, could not get user DN for '%s'\n", userid);
731  ret = 1;
732  goto search_done;
733  }
734  snprintf(dn, sizeof(dn), "%s", userdn);
735  squid_ldap_memfree(userdn);
736 
737  if (ret == 0 && (!binddn || !bind_once || passwdattr)) {
738  /* Reuse the search connection for comparing the user password attribute */
739  bind_ld = search_ld;
740  search_ld = nullptr;
741  }
742 search_done:
743  if (res) {
744  ldap_msgfree(res);
745  res = nullptr;
746  }
747  if (search_ld && search_ld != persistent_ld) {
748  ldap_unbind(search_ld);
749  search_ld = nullptr;
750  }
751  if (ret != 0)
752  return ret;
753  } else {
754  snprintf(dn, sizeof(dn), "%s=%s,%s", userattr, userid, basedn);
755  }
756 
757  debug("attempting to authenticate user '%s'\n", dn);
758  if (!bind_ld && !bind_once)
759  bind_ld = persistent_ld;
760  if (!bind_ld)
762  if (passwdattr) {
763  if (ldap_compare_s(bind_ld, dn, passwdattr, password) != LDAP_COMPARE_TRUE) {
764  ret = 1;
765  }
766  } else if (ldap_simple_bind_s(bind_ld, dn, password) != LDAP_SUCCESS)
767  ret = 1;
768  if (bind_ld != persistent_ld) {
769  ldap_unbind(bind_ld);
770  bind_ld = nullptr;
771  }
772  return ret;
773 }
774 
775 int
776 readSecret(const char *filename)
777 {
778  char buf[BUFSIZ];
779  char *e = nullptr;
780  FILE *f;
781  char *passwd = nullptr;
782 
783  if (!(f = fopen(filename, "r"))) {
784  fprintf(stderr, PROGRAM_NAME " ERROR: Can not read secret file %s\n", filename);
785  return 1;
786  }
787  if (!fgets(buf, sizeof(buf) - 1, f)) {
788  fprintf(stderr, PROGRAM_NAME " ERROR: Secret file %s is empty\n", filename);
789  fclose(f);
790  return 1;
791  }
792  /* strip whitespaces on end */
793  if ((e = strrchr(buf, '\n')))
794  *e = 0;
795  if ((e = strrchr(buf, '\r')))
796  *e = 0;
797 
798  passwd = static_cast<char *>(calloc(strlen(buf) + 1, sizeof(char)));
799  if (!passwd) {
800  fprintf(stderr, PROGRAM_NAME " ERROR: can not allocate memory\n");
801  exit(EXIT_FAILURE);
802  }
803  strcpy(passwd, buf);
804  bindpasswd = passwd;
805 
806  fclose(f);
807 
808  return 0;
809 }
810 
static void squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
static void squid_ldap_set_aliasderef(LDAP *ld, int deref)
#define BUFSIZ
Definition: defines.h:20
static void squid_ldap_set_timelimit(LDAP *ld, int timelimit)
#define xmalloc
static const char * bindpasswd
void debug(const char *format,...)
Definition: debug.cc:19
static void squid_ldap_set_referrals(LDAP *ld, int referrals)
static int persistent
#define xstrdup
static int use_tls
static int noreferrals
static int port
Definition: ldap_backend.cc:70
static int connect_timeout
static int checkLDAP(LDAP *ld, const char *userid, const char *password, const char *server, int port)
static int squid_ldap_errno(LDAP *ld)
static int readSecret(const char *filename)
static int timelimit
int size
Definition: ModDevPoll.cc:69
#define NULL
Definition: types.h:145
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define SEND_ERR(x)
#define LDAP_NO_ATTRS
int debug_enabled
Definition: debug.cc:13
static int validUsername(const char *user)
static int ldap_escape_value(char *escaped, int size, const char *src)
#define SEND_BH(x)
static char * ldapServer
Definition: ldap_backend.cc:59
static int version
static int bind_once
#define PROGRAM_NAME
static LDAP * open_ldap_connection(const char *ldapServer, int port)
int main(int argc, char **argv)
unsigned int ULONG
Definition: smblib-priv.h:147
static int aliasderef
#define LDAP_SECURITY_ERROR(err)
static char server[MAXLINE]
static int searchscope
static const char * userattr
static LDAP * ld
Definition: ldap_backend.cc:57
static const char * basedn
#define xisspace(x)
Definition: xis.h:15
static const char * binddn
static const char * passwdattr
static const char * searchfilter
#define HLP_MSG(text)
#define SEND_OK(x)
static void squid_ldap_memfree(char *p)

 

Introduction

Documentation

Support

Miscellaneous