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