]>
Commit | Line | Data |
---|---|---|
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" | |
61 | typedef 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" | |
64 | typedef WINLDAPAPI ULONG (LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *); | |
65 | #endif /* LDAP_UNICODE */ | |
66 | PFldap_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 | ||
86 | static char *basedn = NULL; | |
8f7b71f7 | 87 | static char *searchfilter = NULL; |
6708c52c | 88 | static char *userbasedn = NULL; |
89 | static char *userdnattr = NULL; | |
90 | static char *usersearchfilter = NULL; | |
8f7b71f7 | 91 | static char *binddn = NULL; |
92 | static char *bindpasswd = NULL; | |
93 | static int searchscope = LDAP_SCOPE_SUBTREE; | |
94 | static int persistent = 0; | |
95 | static int noreferrals = 0; | |
96 | static int debug = 0; | |
97 | static int aliasderef = LDAP_DEREF_NEVER; | |
653b264e | 98 | #if defined(NETSCAPE_SSL) |
99 | static char *sslpath = NULL; | |
100 | static int sslinit = 0; | |
101 | #endif | |
102 | static int connect_timeout = 0; | |
103 | static int timelimit = LDAP_NO_LIMIT; | |
8f7b71f7 | 104 | |
251c9916 | 105 | #ifdef LDAP_VERSION3 |
387b9f71 | 106 | /* Added for TLS support and version 3 */ |
107 | static int use_tls = 0; | |
108 | static int version = -1; | |
251c9916 | 109 | #endif |
387b9f71 | 110 | |
6708c52c | 111 | static int searchLDAP(LDAP * ld, char *group, char *user, char *extension_dn); |
8f7b71f7 | 112 | |
954a8513 | 113 | static 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 | 122 | static int |
123 | squid_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 | 129 | static void |
130 | squid_ldap_set_aliasderef(LDAP * ld, int deref) | |
8f7b71f7 | 131 | { |
132 | ldap_set_option(ld, LDAP_OPT_DEREF, &deref); | |
133 | } | |
d440f560 | 134 | static void |
135 | squid_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 | 140 | static void |
141 | squid_ldap_set_timelimit(LDAP *ld, int timelimit) | |
142 | { | |
143 | ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit); | |
144 | } | |
145 | static void | |
146 | squid_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 | 158 | static void |
159 | squid_ldap_memfree(char *p) | |
387b9f71 | 160 | { |
161 | ldap_memfree(p); | |
162 | } | |
8f7b71f7 | 163 | #else |
d440f560 | 164 | static int |
165 | squid_ldap_errno(LDAP * ld) | |
8f7b71f7 | 166 | { |
167 | return ld->ld_errno; | |
168 | } | |
d440f560 | 169 | static void |
170 | squid_ldap_set_aliasderef(LDAP * ld, int deref) | |
8f7b71f7 | 171 | { |
172 | ld->ld_deref = deref; | |
173 | } | |
d440f560 | 174 | static void |
175 | squid_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 | 182 | static void |
183 | squid_ldap_set_timelimit(LDAP *ld, int timelimit) | |
184 | { | |
185 | ld->ld_timelimit = timelimit; | |
186 | } | |
187 | static void | |
188 | squid_ldap_set_connect_timeout(LDAP *ld, int timelimit) | |
189 | { | |
190 | fprintf(stderr, "Connect timeouts not supported in your LDAP library\n"); | |
191 | } | |
d440f560 | 192 | static void |
193 | squid_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 | 205 | int |
206 | main(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 { |
576 | error: | |
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 | ||
595 | static int | |
251c9916 | 596 | ldap_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 | ||
623 | static int | |
624 | build_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 | ||
673 | static int | |
674 | searchLDAPGroup(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 | |
723 | static int | |
724 | searchLDAP(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 | ||
786 | int 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 | } |