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