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