]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/external_acl/ldap_group/squid_ldap_group.c
Bug 1298: Multiple OIDs in SNMP GETNEXT not processed
[thirdparty/squid.git] / helpers / external_acl / ldap_group / squid_ldap_group.c
CommitLineData
8f7b71f7 1/*
6708c52c 2 * squid_ldap_group: lookup group membership in LDAP
3 *
251c9916 4 * (C)2002,2003 MARA Systems AB
6708c52c 5 *
6 * License: squid_ldap_group is free software; you can redistribute it
7 * and/or modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2,
9 * or (at your option) any later version.
8f7b71f7 10 *
6708c52c 11 * Authors:
12 * Flavio Pescuma <flavio@marasystems.com>
251c9916 13 * Henrik Nordstrom <hno@marasystems.com>
6708c52c 14 * MARA Systems AB, Sweden <http://www.marasystems.com>
387b9f71 15 *
5eecb267 16 * With contributions from others mentioned in the ChangeLog file
8f7b71f7 17 *
6708c52c 18 * In part based on squid_ldap_auth by Glen Newton and Henrik Nordstrom.
19 *
20 * Latest version of this program can always be found from MARA Systems
21 * at http://marasystems.com/download/LDAP_Group/
8f7b71f7 22 *
23 * Dependencies: You need to get the OpenLDAP libraries
6708c52c 24 * from http://www.openldap.org or use another compatible
25 * LDAP C-API library.
387b9f71 26 *
27 * If you want to make a TLS enabled connection you will also need the
28 * OpenSSL libraries linked into openldap. See http://www.openssl.org/
8f7b71f7 29 *
6708c52c 30 * License: squid_ldap_group is free software; you can redistribute it
8f7b71f7 31 * and/or modify it under the terms of the GNU General Public License
32 * as published by the Free Software Foundation; either version 2,
33 * or (at your option) any later version.
8f7b71f7 34 */
35
e39ea462 36#include "util.h"
37
8f7b71f7 38#include <stdio.h>
39#include <string.h>
40#include <stdlib.h>
d440f560 41#include <ctype.h>
e39ea462 42
43#ifdef _SQUID_MSWIN_ /* Native Windows port and MinGW */
44
45#define snprintf _snprintf
46#include <windows.h>
47#include <winldap.h>
48#ifndef LDAPAPI
49#define LDAPAPI __cdecl
50#endif
51#ifdef LDAP_VERSION3
20e869bf 52#ifndef LDAP_OPT_X_TLS
53#define LDAP_OPT_X_TLS 0x6000
54#endif
e39ea462 55/* Some tricks to allow dynamic bind with ldap_start_tls_s entry point at
56 run time.
57 */
58#undef ldap_start_tls_s
59#if LDAP_UNICODE
60#define LDAP_START_TLS_S "ldap_start_tls_sW"
61typedef WINLDAPAPI ULONG (LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *);
62#else
63#define LDAP_START_TLS_S "ldap_start_tls_sA"
64typedef WINLDAPAPI ULONG (LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
65#endif /* LDAP_UNICODE */
66PFldap_start_tls_s Win32_ldap_start_tls_s;
67#define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l,NULL,NULL,s,c)
68#endif /* LDAP_VERSION3 */
69
70#else
71
8f7b71f7 72#include <lber.h>
8f7b71f7 73#include <ldap.h>
e39ea462 74
75#endif
76
b627c18a 77#if defined(LDAP_OPT_NETWORK_TIMEOUT)
78#include <sys/time.h>
79#endif
8f7b71f7 80
6708c52c 81#define PROGRAM_NAME "squid_ldap_group"
4a618699 82#define VERSION "2.17"
6708c52c 83
84/* Globals */
85
86static char *basedn = NULL;
8f7b71f7 87static char *searchfilter = NULL;
6708c52c 88static char *userbasedn = NULL;
89static char *userdnattr = NULL;
90static char *usersearchfilter = NULL;
8f7b71f7 91static char *binddn = NULL;
92static char *bindpasswd = NULL;
93static int searchscope = LDAP_SCOPE_SUBTREE;
94static int persistent = 0;
95static int noreferrals = 0;
96static int debug = 0;
97static int aliasderef = LDAP_DEREF_NEVER;
653b264e 98#if defined(NETSCAPE_SSL)
99static char *sslpath = NULL;
100static int sslinit = 0;
101#endif
102static int connect_timeout = 0;
103static int timelimit = LDAP_NO_LIMIT;
8f7b71f7 104
251c9916 105#ifdef LDAP_VERSION3
387b9f71 106/* Added for TLS support and version 3 */
107static int use_tls = 0;
108static int version = -1;
251c9916 109#endif
387b9f71 110
6708c52c 111static int searchLDAP(LDAP * ld, char *group, char *user, char *extension_dn);
8f7b71f7 112
954a8513 113static int readSecret(char *filename);
114
8f7b71f7 115/* Yuck.. we need to glue to different versions of the API */
116
b10eaeab 117#ifndef LDAP_NO_ATTRS
118#define LDAP_NO_ATTRS "1.1"
119#endif
120
8f7b71f7 121#if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
d440f560 122static int
123squid_ldap_errno(LDAP * ld)
8f7b71f7 124{
125 int err = 0;
126 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
127 return err;
128}
d440f560 129static void
130squid_ldap_set_aliasderef(LDAP * ld, int deref)
8f7b71f7 131{
132 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
133}
d440f560 134static void
135squid_ldap_set_referrals(LDAP * ld, int referrals)
8f7b71f7 136{
137 int *value = referrals ? LDAP_OPT_ON : LDAP_OPT_OFF;
138 ldap_set_option(ld, LDAP_OPT_REFERRALS, value);
139}
653b264e 140static void
141squid_ldap_set_timelimit(LDAP *ld, int timelimit)
142{
143 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
144}
145static void
146squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
147{
148#if defined(LDAP_OPT_NETWORK_TIMEOUT)
149 struct timeval tv;
150 tv.tv_sec = timelimit;
151 tv.tv_usec = 0;
152 ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
153#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
154 timelimit *= 1000;
155 ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timelimit);
156#endif
157}
d440f560 158static void
159squid_ldap_memfree(char *p)
387b9f71 160{
161 ldap_memfree(p);
162}
8f7b71f7 163#else
d440f560 164static int
165squid_ldap_errno(LDAP * ld)
8f7b71f7 166{
167 return ld->ld_errno;
168}
d440f560 169static void
170squid_ldap_set_aliasderef(LDAP * ld, int deref)
8f7b71f7 171{
172 ld->ld_deref = deref;
173}
d440f560 174static void
175squid_ldap_set_referrals(LDAP * ld, int referrals)
8f7b71f7 176{
177 if (referrals)
178 ld->ld_options |= ~LDAP_OPT_REFERRALS;
179 else
180 ld->ld_options &= ~LDAP_OPT_REFERRALS;
181}
653b264e 182static void
183squid_ldap_set_timelimit(LDAP *ld, int timelimit)
184{
185 ld->ld_timelimit = timelimit;
186}
187static void
188squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
189{
190 fprintf(stderr, "Connect timeouts not supported in your LDAP library\n");
191}
d440f560 192static void
193squid_ldap_memfree(char *p)
387b9f71 194{
195 free(p);
196}
8f7b71f7 197#endif
198
5eecb267 199#ifdef LDAP_API_FEATURE_X_OPENLDAP
200 #if LDAP_VENDOR_VERSION > 194
201 #define HAS_URI_SUPPORT 1
202 #endif
203#endif
204
8f7b71f7 205int
206main(int argc, char **argv)
207{
b627c18a 208 char buf[8192];
6708c52c 209 char *user, *group, *extension_dn = NULL;
387b9f71 210 char *ldapServer = NULL;
8f7b71f7 211 LDAP *ld = NULL;
6708c52c 212 int tryagain = 0, rc;
387b9f71 213 int port = LDAP_PORT;
6708c52c 214 int use_extension_dn = 0;
215 int strip_nt_domain = 0;
1958420a 216 int err = 0;
8f7b71f7 217
218 setbuf(stdout, NULL);
219
387b9f71 220 while (argc > 1 && argv[1][0] == '-') {
8f7b71f7 221 char *value = "";
222 char option = argv[1][1];
d440f560 223 switch (option) {
387b9f71 224 case 'P':
8f7b71f7 225 case 'R':
387b9f71 226 case 'z':
227 case 'Z':
307228f1 228 case 'd':
2d184c3e 229 case 'g':
6708c52c 230 case 'S':
8f7b71f7 231 break;
232 default:
233 if (strlen(argv[1]) > 2) {
d440f560 234 value = argv[1] + 2;
387b9f71 235 } else if (argc > 2) {
8f7b71f7 236 value = argv[2];
237 argv++;
238 argc--;
387b9f71 239 } else
240 value = "";
8f7b71f7 241 break;
242 }
243 argv++;
244 argc--;
d440f560 245 switch (option) {
5eecb267 246 case 'H':
247#if !HAS_URI_SUPPORT
248 fprintf(stderr, "ERROR: Your LDAP library does not have URI support\n");
249 exit(1);
250#endif
251 /* Fall thru to -h */
387b9f71 252 case 'h':
d440f560 253 if (ldapServer) {
254 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
255 char *newhost = malloc(len);
256 snprintf(newhost, len, "%s %s", ldapServer, value);
257 free(ldapServer);
258 ldapServer = newhost;
259 } else {
260 ldapServer = strdup(value);
261 }
262 break;
8f7b71f7 263 case 'b':
d440f560 264 basedn = value;
265 break;
8f7b71f7 266 case 'f':
d440f560 267 searchfilter = value;
268 break;
6708c52c 269 case 'B':
270 userbasedn = value;
271 break;
272 case 'F':
273 usersearchfilter = value;
274 break;
275 case 'u':
276 userdnattr = value;
277 break;
8f7b71f7 278 case 's':
d440f560 279 if (strcmp(value, "base") == 0)
280 searchscope = LDAP_SCOPE_BASE;
281 else if (strcmp(value, "one") == 0)
282 searchscope = LDAP_SCOPE_ONELEVEL;
283 else if (strcmp(value, "sub") == 0)
284 searchscope = LDAP_SCOPE_SUBTREE;
285 else {
6708c52c 286 fprintf(stderr, PROGRAM_NAME " ERROR: Unknown search scope '%s'\n", value);
d440f560 287 exit(1);
288 }
289 break;
0b9a90fd 290 case 'E':
653b264e 291#if defined(NETSCAPE_SSL)
292 sslpath = value;
293 if (port == LDAP_PORT)
294 port = LDAPS_PORT;
295#else
296 fprintf(stderr, PROGRAM_NAME " ERROR: -E unsupported with this LDAP library\n");
297 exit(1);
298#endif
299 break;
300 case 'c':
301 connect_timeout = atoi(value);
302 break;
303 case 't':
304 timelimit = atoi(value);
305 break;
8f7b71f7 306 case 'a':
d440f560 307 if (strcmp(value, "never") == 0)
308 aliasderef = LDAP_DEREF_NEVER;
309 else if (strcmp(value, "always") == 0)
310 aliasderef = LDAP_DEREF_ALWAYS;
311 else if (strcmp(value, "search") == 0)
312 aliasderef = LDAP_DEREF_SEARCHING;
313 else if (strcmp(value, "find") == 0)
314 aliasderef = LDAP_DEREF_FINDING;
315 else {
6708c52c 316 fprintf(stderr, PROGRAM_NAME " ERROR: Unknown alias dereference method '%s'\n", value);
d440f560 317 exit(1);
318 }
319 break;
8f7b71f7 320 case 'D':
d440f560 321 binddn = value;
322 break;
8f7b71f7 323 case 'w':
d440f560 324 bindpasswd = value;
325 break;
954a8513 326 case 'W':
327 readSecret (value);
328 break;
387b9f71 329 case 'P':
d440f560 330 persistent = !persistent;
331 break;
387b9f71 332 case 'p':
d440f560 333 port = atoi(value);
334 break;
8f7b71f7 335 case 'R':
d440f560 336 noreferrals = !noreferrals;
337 break;
251c9916 338#ifdef LDAP_VERSION3
387b9f71 339 case 'v':
d440f560 340 switch (atoi(value)) {
341 case 2:
342 version = LDAP_VERSION2;
387b9f71 343 break;
d440f560 344 case 3:
387b9f71 345 version = LDAP_VERSION3;
387b9f71 346 break;
d440f560 347 default:
348 fprintf(stderr, "Protocol version should be 2 or 3\n");
349 exit(1);
350 }
351 break;
352 case 'Z':
353 if (version == LDAP_VERSION2) {
354 fprintf(stderr, "TLS (-Z) is incompatible with version %d\n",
355 version);
356 exit(1);
357 }
358 version = LDAP_VERSION3;
359 use_tls = 1;
360 break;
251c9916 361#endif
8f7b71f7 362 case 'd':
d440f560 363 debug = 1;
364 break;
2d184c3e 365 case 'g':
6708c52c 366 use_extension_dn = 1;
367 break;
0b9a90fd 368 case 'S':
6708c52c 369 strip_nt_domain = 1;
2d184c3e 370 break;
8f7b71f7 371 default:
6708c52c 372 fprintf(stderr, PROGRAM_NAME " ERROR: Unknown command line option '%c'\n", option);
d440f560 373 exit(1);
8f7b71f7 374 }
375 }
376
387b9f71 377 while (argc > 1) {
378 char *value = argv[1];
379 if (ldapServer) {
380 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
381 char *newhost = malloc(len);
382 snprintf(newhost, len, "%s %s", ldapServer, value);
383 free(ldapServer);
384 ldapServer = newhost;
385 } else {
386 ldapServer = strdup(value);
387 }
388 argc--;
389 argv++;
390 }
391
392 if (!ldapServer)
393 ldapServer = "localhost";
394
395 if (!basedn || !searchfilter) {
4a618699 396 fprintf(stderr, "\n" PROGRAM_NAME " version " VERSION "\n\n");
6708c52c 397 fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n");
398 fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under where to search for groups\n");
399 fprintf(stderr, "\t-f filter (REQUIRED)\tgroup search filter pattern. %%v = user,\n\t\t\t\t%%a = group\n");
400 fprintf(stderr, "\t-B basedn (REQUIRED)\tbase dn under where to search for users\n");
401 fprintf(stderr, "\t-F filter (REQUIRED)\tuser search filter pattern. %%s = login\n");
8f7b71f7 402 fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n");
403 fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n");
404 fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n");
954a8513 405 fprintf(stderr, "\t-W secretfile\t\tread password for binddn from file secretfile\n");
5eecb267 406#if HAS_URI_SUPPORT
407 fprintf(stderr, "\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
408#endif
387b9f71 409 fprintf(stderr, "\t-h server\t\tLDAP server (defaults to localhost)\n");
410 fprintf(stderr, "\t-p port\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT);
411 fprintf(stderr, "\t-P\t\t\tpersistent LDAP connection\n");
653b264e 412#if defined(NETSCAPE_SSL)
413 fprintf(stderr, "\t-E sslcertpath\t\tenable LDAP over SSL\n");
414#endif
415 fprintf(stderr, "\t-c timeout\t\tconnect timeout\n");
416 fprintf(stderr, "\t-t timelimit\t\tsearch time limit\n");
8f7b71f7 417 fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n");
418 fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
5eecb267 419#ifdef LDAP_VERSION3
420 fprintf(stderr, "\t-v 2|3\t\t\tLDAP version\n");
6708c52c 421 fprintf(stderr, "\t-Z\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n");
5eecb267 422#endif
6708c52c 423 fprintf(stderr, "\t-g\t\t\tfirst query parameter is base DN extension\n\t\t\t\tfor this query\n");
424 fprintf(stderr, "\t-S\t\t\tStrip NT domain from usernames\n");
8f7b71f7 425 fprintf(stderr, "\n");
954a8513 426 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");
8f7b71f7 427 exit(1);
428 }
e39ea462 429
430/* On Windows ldap_start_tls_s is available starting from Windows XP,
431 so we need to bind at run-time with the function entry point
432 */
433#ifdef _SQUID_MSWIN_
434 if (use_tls) {
435
436 HMODULE WLDAP32Handle;
437
438 WLDAP32Handle = GetModuleHandle("wldap32");
439 if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
440 fprintf( stderr, PROGRAM_NAME ": ERROR: TLS (-Z) not supported on this platform.\n");
441 exit(1);
442 }
443 }
444#endif
445
8f7b71f7 446 while (fgets(buf, 256, stdin) != NULL) {
2d184c3e 447 int found = 0;
1958420a 448 if (!strchr(buf, '\n')) {
449 /* too large message received.. skip and deny */
450 fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
451 while (fgets(buf, sizeof(buf), stdin)) {
452 fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
453 if (strchr(buf, '\n') != NULL)
454 break;
455 }
456 goto error;
457 }
458 user = strtok(buf, " \n");
459 if (!user) {
460 fprintf(stderr, "%s: Invalid request\n", argv[0]);
461 goto error;
462 }
463 rfc1738_unescape(user);
464 if (strip_nt_domain) {
6708c52c 465 char *u = strchr(user, '\\');
466 if (!u)
467 u = strchr(user, '/');
468 if (u && u[1])
469 user = u + 1;
470 }
1958420a 471 if (use_extension_dn) {
472 extension_dn = strtok(NULL, " \n");
473 if (!extension_dn) {
474 fprintf(stderr, "%s: Invalid request\n", argv[0]);
475 goto error;
476 }
477 rfc1738_unescape(extension_dn);
478 }
8f7b71f7 479
1958420a 480 while (!found && user && (group = strtok(NULL, " \n")) != NULL) {
481 rfc1738_unescape(group);
2d184c3e 482
483 recover:
484 if (ld == NULL) {
5eecb267 485#if HAS_URI_SUPPORT
486 if (strstr(ldapServer, "://") != NULL) {
487 rc = ldap_initialize( &ld, ldapServer );
488 if( rc != LDAP_SUCCESS ) {
489 fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
490 break;
491 }
492 } else
653b264e 493#endif
494#if NETSCAPE_SSL
495 if (sslpath) {
496 if ( !sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
497 fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
498 sslpath);
499 exit(1);
500 } else {
501 sslinit++;
502 }
503 if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
504 fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
505 ldapServer, port);
506 exit(1);
507 }
508 } else
5eecb267 509#endif
2d184c3e 510 if ((ld = ldap_init(ldapServer, port)) == NULL) {
5eecb267 511 fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",ldapServer, port);
2d184c3e 512 break;
513 }
5eecb267 514
653b264e 515 if (connect_timeout)
516 squid_ldap_set_connect_timeout(ld, connect_timeout);
517
251c9916 518#ifdef LDAP_VERSION3
2d184c3e 519 if (version == -1) {
520 version = LDAP_VERSION2;
521 }
20e869bf 522 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
2d184c3e 523 fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
524 version);
525 ldap_unbind(ld);
526 ld = NULL;
527 break;
528 }
20e869bf 529 if (use_tls) {
530#ifdef LDAP_OPT_X_TLS
531 if (version == LDAP_VERSION3 && ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
532 fprintf(stderr, "Could not Activate TLS connection\n");
533 ldap_unbind(ld);
534 ld = NULL;
535 break;
536 } else {
537 fprintf(stderr, "TLS requires LDAP version 3\n");
538 exit(1);
539 }
540#else
541 fprintf(stderr, "TLS not supported with your LDAP library\n");
542 exit(1);
543#endif
2d184c3e 544 }
251c9916 545#endif
653b264e 546 squid_ldap_set_timelimit(ld, timelimit);
2d184c3e 547 squid_ldap_set_referrals(ld, !noreferrals);
548 squid_ldap_set_aliasderef(ld, aliasderef);
6708c52c 549 if (binddn && bindpasswd && *binddn && *bindpasswd) {
550 rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
551 if (rc != LDAP_SUCCESS) {
552 fprintf(stderr, PROGRAM_NAME " WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc));
553 ldap_unbind(ld);
554 ld = NULL;
555 break;
556 }
557 }
558 if (debug)
559 fprintf(stderr, "Connected OK\n");
387b9f71 560 }
6708c52c 561 if (searchLDAP(ld, group, user, extension_dn) == 0) {
2d184c3e 562 found = 1;
563 break;
564 } else {
565 if (tryagain) {
566 tryagain = 0;
567 ldap_unbind(ld);
568 ld = NULL;
569 goto recover;
570 }
387b9f71 571 }
8f7b71f7 572 }
2d184c3e 573 if (found)
574 printf("OK\n");
1958420a 575 else {
576error:
387b9f71 577 printf("ERR\n");
1958420a 578}
2d184c3e 579
580 if (ld != NULL) {
581 if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
8f7b71f7 582 ldap_unbind(ld);
583 ld = NULL;
6708c52c 584 } else {
585 tryagain = 1;
8f7b71f7 586 }
8f7b71f7 587 }
1958420a 588 err = 0;
8f7b71f7 589 }
590 if (ld)
591 ldap_unbind(ld);
592 return 0;
593}
594
595static int
251c9916 596ldap_escape_value(char *escaped, int size, const char *src)
6708c52c 597{
598 int n = 0;
251c9916 599 while (size > 4 && *src) {
6708c52c 600 switch(*src) {
601 case '*':
602 case '(':
603 case ')':
604 case '\\':
605 n += 3;
606 size -= 3;
607 if (size > 0) {
251c9916 608 *escaped++ = '\\';
307228f1 609 snprintf(escaped, 3, "%02x", (unsigned char)*src++);
251c9916 610 escaped+=2;
6708c52c 611 }
612 break;
613 default:
251c9916 614 *escaped++ = *src++;
6708c52c 615 n++;
616 size--;
617 }
618 }
251c9916 619 *escaped = '\0';
6708c52c 620 return n;
621}
622
623static int
624build_filter(char *filter, int size, const char *template, const char *user, const char *group)
625{
626 int n;
627 while(*template && size > 0) {
628 switch(*template) {
629 case '%':
630 template++;
631 switch (*template) {
632 case 'u':
633 case 'v':
634 template++;
635 n = ldap_escape_value(filter, size, user);
636 size -= n;
637 filter += n;
638 break;
639 case 'g':
640 case 'a':
641 template++;
642 n = ldap_escape_value(filter, size, group);
643 size -= n;
644 filter += n;
645 break;
646 default:
647 fprintf(stderr, "ERROR: Unknown filter template string %%%c\n", *template);
648 return 1;
649 break;
650 }
651 break;
652 case '\\':
653 template++;
654 if (*template) {
655 *filter++ = *template++;
656 size--;
657 }
658 break;
659 default:
660 *filter++ = *template++;
661 size--;
662 break;
663 }
664 }
665 if (size <= 0) {
666 fprintf(stderr, "ERROR: Filter too large\n");
667 return 1;
668 }
669 *filter = '\0';
670 return 0;
671}
672
673static int
674searchLDAPGroup(LDAP * ld, char *group, char *member, char *extension_dn)
8f7b71f7 675{
d440f560 676 char filter[256];
677 static char searchbase[256];
678 LDAPMessage *res = NULL;
679 LDAPMessage *entry;
6708c52c 680 int rc;
b10eaeab 681 char *searchattr[] = {LDAP_NO_ATTRS, NULL};
8f7b71f7 682
6708c52c 683 if (extension_dn && *extension_dn)
684 snprintf(searchbase, sizeof(searchbase), "%s,%s", extension_dn, basedn);
d440f560 685 else
686 snprintf(searchbase, sizeof(searchbase), "%s", basedn);
8f7b71f7 687
6708c52c 688 if (build_filter(filter, sizeof(filter), searchfilter, member, group) != 0) {
689 fprintf(stderr, PROGRAM_NAME " ERROR, Failed to construct LDAP search filter. filter=\"%s\", user=\"%s\", group=\"%s\"\n", filter, member, group);
690 return 1;
691 }
8f7b71f7 692
6708c52c 693 if (debug)
5eecb267 694 fprintf(stderr, "group filter '%s', searchbase '%s'\n", filter, searchbase);
8f7b71f7 695
b10eaeab 696 rc = ldap_search_s(ld, searchbase, searchscope, filter, searchattr, 1, &res);
6708c52c 697 if (rc != LDAP_SUCCESS) {
d440f560 698 if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
699 /* Everything is fine. This is expected when referrals
700 * are disabled.
701 */
702 } else {
6708c52c 703 fprintf(stderr, PROGRAM_NAME " WARNING, LDAP search error '%s'\n", ldap_err2string(rc));
653b264e 704#if defined(NETSCAPE_SSL)
705 if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
706 int sslerr = PORT_GetError();
707 fprintf(stderr, PROGRAM_NAME ": WARNING, SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
708 }
709#endif
6708c52c 710 ldap_msgfree(res);
711 return 1;
d440f560 712 }
d440f560 713 }
714 entry = ldap_first_entry(ld, res);
715 if (!entry) {
716 ldap_msgfree(res);
717 return 1;
718 }
719 ldap_msgfree(res);
720 return 0;
8f7b71f7 721}
6708c52c 722
723static int
724searchLDAP(LDAP *ld, char *group, char *login, char *extension_dn)
725{
726
727 if (usersearchfilter) {
728 char filter[8192];
729 char searchbase[8192];
730 char escaped_login[1024];
731 LDAPMessage *res = NULL;
732 LDAPMessage *entry;
733 int rc;
734 char *userdn;
b10eaeab 735 char *searchattr[] = {LDAP_NO_ATTRS, NULL};
42576a10 736 if (extension_dn && *extension_dn)
737 snprintf(searchbase, sizeof(searchbase), "%s,%s", extension_dn, userbasedn ? userbasedn : basedn);
5eecb267 738 else
739 snprintf(searchbase, sizeof(searchbase), "%s", userbasedn ? userbasedn : basedn);
6708c52c 740 ldap_escape_value(escaped_login, sizeof(escaped_login), login);
741 snprintf(filter, sizeof(filter), usersearchfilter, 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, escaped_login);
742 if (debug)
5eecb267 743 fprintf(stderr, "user filter '%s', searchbase '%s'\n", filter, searchbase);
b10eaeab 744 rc = ldap_search_s(ld, searchbase, searchscope, filter, searchattr, 1, &res);
6708c52c 745 if (rc != LDAP_SUCCESS) {
746 if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
747 /* Everything is fine. This is expected when referrals
748 * are disabled.
749 */
750 } else {
751 fprintf(stderr, PROGRAM_NAME " WARNING, LDAP search error '%s'\n", ldap_err2string(rc));
653b264e 752#if defined(NETSCAPE_SSL)
753 if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
754 int sslerr = PORT_GetError();
755 fprintf(stderr, PROGRAM_NAME ": WARNING, SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
756 }
757#endif
6708c52c 758 ldap_msgfree(res);
759 return 1;
760 }
761 }
762 entry = ldap_first_entry(ld, res);
763 if (!entry) {
5eecb267 764 fprintf(stderr, PROGRAM_NAME " WARNING, User '%s' not found in '%s'\n", login, searchbase);
6708c52c 765 ldap_msgfree(res);
766 return 1;
767 }
768 userdn = ldap_get_dn(ld, entry);
769 rc = searchLDAPGroup(ld, group, userdn, extension_dn);
770 squid_ldap_memfree(userdn);
771 ldap_msgfree(res);
772 return rc;
773 } else if (userdnattr) {
774 char dn[8192];
775 if (extension_dn && *extension_dn)
776 sprintf(dn, "%s=%s, %s, %s", userdnattr, login, extension_dn, userbasedn ? userbasedn : basedn);
777 else
778 sprintf(dn, "%s=%s, %s", userdnattr, login, userbasedn ? userbasedn : basedn);
779 return searchLDAPGroup(ld, group, dn, extension_dn);
780 } else {
781 return searchLDAPGroup(ld, group, login, extension_dn);
782 }
783}
954a8513 784
785
786int readSecret(char *filename)
787{
788 char buf[BUFSIZ];
789 char *e=0;
790 FILE *f;
791
792 if(!(f=fopen(filename, "r"))) {
793 fprintf(stderr, PROGRAM_NAME " ERROR: Can not read secret file %s\n", filename);
794 return 1;
795 }
796
797 if( !fgets(buf, sizeof(buf)-1, f)) {
798 fprintf(stderr, PROGRAM_NAME " ERROR: Secret file %s is empty\n", filename);
799 fclose(f);
800 return 1;
801 }
802
803 /* strip whitespaces on end */
804 if((e = strrchr(buf, '\n'))) *e = 0;
805 if((e = strrchr(buf, '\r'))) *e = 0;
806
807 bindpasswd = (char *) calloc(sizeof(char), strlen(buf)+1);
808 if (bindpasswd) {
809 strcpy(bindpasswd, buf);
810 } else {
811 fprintf(stderr, PROGRAM_NAME " ERROR: can not allocate memory\n");
812 }
813
814 fclose(f);
815
816 return 0;
817}