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