]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/external_acl/kerberos_ldap_group/support_ldap.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / external_acl / kerberos_ldap_group / support_ldap.cc
CommitLineData
ca02e0ec 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 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
b1218840
AJ
9/*
10 * -----------------------------------------------------------------------------
11 *
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
13 *
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
29 *
30 * -----------------------------------------------------------------------------
31 */
32
0d0698bb
AJ
33/* get_attributes is partly from OpenLDAP Software <http://www.openldap.org/>.
34 *
35 * Copyright 1998-2009 The OpenLDAP Foundation.
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted only as authorized by the OpenLDAP
40 * Public License.
41 *
42 * A copy of this license is available in the file LICENSE in the
43 * top-level directory of the distribution or, alternatively, at
44 * <http://www.OpenLDAP.org/license.html>.
45 */
46
f7f3304a 47#include "squid.h"
b1218840
AJ
48#include "util.h"
49
7451e5ad 50#if HAVE_LDAP
b1218840
AJ
51
52#include "support.h"
1a30fdf5 53#include <cerrno>
b1218840
AJ
54
55char *convert_domain_to_bind_path(char *domain);
56char *escape_filter(char *filter);
57int check_AD(struct main_args *margs, LDAP * ld);
4ebcf1ce 58int ldap_set_defaults(LDAP * ld);
b1218840
AJ
59int ldap_set_ssl_defaults(struct main_args *margs);
60LDAP *tool_ldap_open(struct main_args *margs, char *host, int port, char *ssl);
61
62#define CONNECT_TIMEOUT 2
63#define SEARCH_TIMEOUT 30
64
65#define FILTER "(memberuid=%s)"
66#define ATTRIBUTE "cn"
1a22a39e 67#define ATTRIBUTE_DN "distinguishedName"
b1218840
AJ
68#define FILTER_UID "(uid=%s)"
69#define FILTER_GID "(&(gidNumber=%s)(objectclass=posixgroup))"
70#define ATTRIBUTE_GID "gidNumber"
1a22a39e
MM
71#define ATTRIBUTE_GID_AD "primaryGroupID"
72#define ATTRIBUTE_SID "objectSID"
b1218840
AJ
73
74#define FILTER_AD "(samaccountname=%s)"
75#define ATTRIBUTE_AD "memberof"
76
4ebcf1ce 77size_t get_attributes(LDAP * ld, LDAPMessage * res, const char *attribute /* IN */ , char ***out_val /* OUT (caller frees) */ );
1a22a39e 78size_t get_bin_attributes(LDAP * ld, LDAPMessage * res, const char *attribute /* IN */ , char ***out_val , int **out_len /* OUT (caller frees) */ );
b1218840
AJ
79int search_group_tree(struct main_args *margs, LDAP * ld, char *bindp, char *ldap_group, char *group, int depth);
80
1a22a39e
MM
81#if HAVE_SUN_LDAP_SDK || HAVE_MOZILLA_LDAP_SDK
82#if HAVE_LDAP_REBINDPROC_CALLBACK
b1218840 83
1a22a39e 84#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
b1218840
AJ
85static LDAP_REBINDPROC_CALLBACK ldap_sasl_rebind;
86
87static int LDAP_CALL LDAP_CALLBACK
88ldap_sasl_rebind(
89 LDAP * ld,
90 char **whop,
91 char **credp,
92 int *methodp,
93 int freeit,
94 void *params)
95{
96 struct ldap_creds *cp = (struct ldap_creds *) params;
97 whop = whop;
98 credp = credp;
99 methodp = methodp;
100 freeit = freeit;
101 return tool_sasl_bind(ld, cp->dn, cp->pw);
102}
103#endif
104
105static LDAP_REBINDPROC_CALLBACK ldap_simple_rebind;
106
107static int LDAP_CALL LDAP_CALLBACK
108ldap_simple_rebind(
109 LDAP * ld,
110 char **whop,
111 char **credp,
112 int *methodp,
113 int freeit,
114 void *params)
115{
116 struct ldap_creds *cp = (struct ldap_creds *) params;
75f3c557
MM
117 struct berval cred;
118 if (cp->pw) {
119 cred.bv_val=cp->pw;
5f4daa47 120 cred.bv_len=strlen(cp->pw);
75f3c557 121 }
b1218840
AJ
122 whop = whop;
123 credp = credp;
124 methodp = methodp;
125 freeit = freeit;
75f3c557 126 return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
b1218840 127}
1a22a39e
MM
128#elif HAVE_LDAP_REBIND_PROC
129#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
b1218840
AJ
130static LDAP_REBIND_PROC ldap_sasl_rebind;
131
132static int
133ldap_sasl_rebind(
134 LDAP * ld,
135 LDAP_CONST char *url,
136 ber_tag_t request,
137 ber_int_t msgid,
138 void *params)
139{
140 struct ldap_creds *cp = (struct ldap_creds *) params;
b1218840
AJ
141 return tool_sasl_bind(ld, cp->dn, cp->pw);
142}
143#endif
144
145static LDAP_REBIND_PROC ldap_simple_rebind;
146
147static int
148ldap_simple_rebind(
149 LDAP * ld,
150 LDAP_CONST char *url,
151 ber_tag_t request,
152 ber_int_t msgid,
153 void *params)
154{
155 struct ldap_creds *cp = (struct ldap_creds *) params;
75f3c557
MM
156 struct berval cred;
157 if (cp->pw) {
158 cred.bv_val=cp->pw;
5f4daa47 159 cred.bv_len=strlen(cp->pw);
75f3c557
MM
160 }
161 return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
b1218840
AJ
162}
163
1a22a39e 164#elif HAVE_LDAP_REBIND_FUNCTION
b1218840
AJ
165#ifndef LDAP_REFERRALS
166#define LDAP_REFERRALS
167#endif
1a22a39e 168#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
b1218840
AJ
169static LDAP_REBIND_FUNCTION ldap_sasl_rebind;
170
171static int
172ldap_sasl_rebind(
173 LDAP * ld,
174 char **whop,
175 char **credp,
176 int *methodp,
177 int freeit,
178 void *params)
179{
180 struct ldap_creds *cp = (struct ldap_creds *) params;
181 whop = whop;
182 credp = credp;
183 methodp = methodp;
184 freeit = freeit;
185 return tool_sasl_bind(ld, cp->dn, cp->pw);
186}
187#endif
188
189static LDAP_REBIND_FUNCTION ldap_simple_rebind;
190
191static int
192ldap_simple_rebind(
193 LDAP * ld,
194 char **whop,
195 char **credp,
196 int *methodp,
197 int freeit,
198 void *params)
199{
200 struct ldap_creds *cp = (struct ldap_creds *) params;
75f3c557
MM
201 struct berval cred;
202 if (cp->pw) {
203 cred.bv_val=cp->pw;
5f4daa47 204 cred.bv_len=strlen(cp->pw);
75f3c557 205 }
b1218840
AJ
206 whop = whop;
207 credp = credp;
208 methodp = methodp;
209 freeit = freeit;
75f3c557 210 return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
b1218840
AJ
211}
212#else
213#error "No rebind functione defined"
214#endif
215#else /* HAVE_SUN_LDAP_SDK */
1a22a39e 216#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
b1218840
AJ
217static LDAP_REBIND_PROC ldap_sasl_rebind;
218
219static int
75f3c557 220ldap_sasl_rebind(LDAP *ld, LDAP_CONST char *, ber_tag_t request, ber_int_t msgid, void *params)
b1218840
AJ
221{
222 struct ldap_creds *cp = (struct ldap_creds *) params;
b1218840
AJ
223 return tool_sasl_bind(ld, cp->dn, cp->pw);
224}
225#endif
226
227static LDAP_REBIND_PROC ldap_simple_rebind;
228
229static int
75f3c557 230ldap_simple_rebind(LDAP *ld, LDAP_CONST char *, ber_tag_t request, ber_int_t msgid, void *params)
b1218840
AJ
231{
232
233 struct ldap_creds *cp = (struct ldap_creds *) params;
75f3c557
MM
234 struct berval cred;
235 if (cp->pw) {
236 cred.bv_val=cp->pw;
5f4daa47 237 cred.bv_len=strlen(cp->pw);
75f3c557
MM
238 }
239 return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
b1218840
AJ
240}
241
242#endif
243char *
244convert_domain_to_bind_path(char *domain)
245{
246 char *dp, *bindp = NULL, *bp = NULL;
4ebcf1ce 247 size_t i = 0;
b1218840
AJ
248
249 if (!domain)
2e881a6f 250 return NULL;
b1218840 251
a2f5277a 252 for (dp = domain; *dp; ++dp) {
2e881a6f 253 if (*dp == '.')
755494da 254 ++i;
b1218840 255 }
2e881a6f
A
256 /*
257 * add dc= and
258 * replace . with ,dc= => new length = old length + #dots * 3 + 3
b1218840
AJ
259 */
260 bindp = (char *) xmalloc(strlen(domain) + 3 + i * 3 + 1);
261 bp = bindp;
262 strcpy(bp, "dc=");
263 bp += 3;
a2f5277a 264 for (dp = domain; *dp; ++dp) {
2e881a6f
A
265 if (*dp == '.') {
266 strcpy(bp, ",dc=");
267 bp += 4;
f207fe64
FC
268 } else {
269 *bp = *dp;
270 ++bp;
271 }
b1218840
AJ
272 }
273 *bp = '\0';
274 return bindp;
275}
276
277char *
278escape_filter(char *filter)
279{
b1218840 280 char *ldap_filter_esc, *ldf;
4ebcf1ce 281 size_t i;
b1218840
AJ
282
283 i = 0;
a2f5277a 284 for (ldap_filter_esc = filter; *ldap_filter_esc; ++ldap_filter_esc) {
2e881a6f
A
285 if ((*ldap_filter_esc == '*') ||
286 (*ldap_filter_esc == '(') ||
287 (*ldap_filter_esc == ')') ||
288 (*ldap_filter_esc == '\\'))
289 i = i + 3;
b1218840
AJ
290 }
291
292 ldap_filter_esc = (char *) xcalloc(strlen(filter) + i + 1, sizeof(char));
293 ldf = ldap_filter_esc;
a2f5277a 294 for (; *filter; ++filter) {
2e881a6f
A
295 if (*filter == '*') {
296 strcpy(ldf, "\\2a");
297 ldf = ldf + 3;
298 } else if (*filter == '(') {
299 strcpy(ldf, "\\28");
300 ldf = ldf + 3;
301 } else if (*filter == ')') {
302 strcpy(ldf, "\\29");
303 ldf = ldf + 3;
304 } else if (*filter == '\\') {
305 strcpy(ldf, "\\5c");
306 ldf = ldf + 3;
307 } else {
308 *ldf = *filter;
755494da 309 ++ldf;
2e881a6f 310 }
b1218840
AJ
311 }
312 *ldf = '\0';
313
314 return ldap_filter_esc;
4ebcf1ce 315}
b1218840
AJ
316
317int
318check_AD(struct main_args *margs, LDAP * ld)
319{
320 LDAPMessage *res;
321 char **attr_value = NULL;
322 struct timeval searchtime;
4ebcf1ce
MM
323 size_t max_attr = 0;
324 int rc = 0;
b1218840
AJ
325
326#define FILTER_SCHEMA "(objectclass=*)"
327#define ATTRIBUTE_SCHEMA "schemaNamingContext"
328#define FILTER_SAM "(ldapdisplayname=samaccountname)"
329
330 searchtime.tv_sec = SEARCH_TIMEOUT;
331 searchtime.tv_usec = 0;
332
333 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path \"\" and filter: %s\n", LogTime(), PROGRAM, FILTER_SCHEMA);
334 rc = ldap_search_ext_s(ld, (char *) "", LDAP_SCOPE_BASE, (char *) FILTER_SCHEMA, NULL, 0,
2e881a6f 335 NULL, NULL, &searchtime, 0, &res);
b1218840
AJ
336
337 if (rc == LDAP_SUCCESS)
4ebcf1ce 338 max_attr = get_attributes(ld, res, ATTRIBUTE_SCHEMA, &attr_value);
b1218840
AJ
339
340 if (max_attr == 1) {
2e881a6f
A
341 ldap_msgfree(res);
342 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, attr_value[0], FILTER_SAM);
343 rc = ldap_search_ext_s(ld, attr_value[0], LDAP_SCOPE_SUBTREE, (char *) FILTER_SAM, NULL, 0,
344 NULL, NULL, &searchtime, 0, &res);
345 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
346 if (ldap_count_entries(ld, res) > 0)
347 margs->AD = 1;
b1218840 348 } else
2e881a6f 349 debug((char *) "%s| %s: DEBUG: Did not find ldap entry for subschemasubentry\n", LogTime(), PROGRAM);
b1218840
AJ
350 debug((char *) "%s| %s: DEBUG: Determined ldap server %sas an Active Directory server\n", LogTime(), PROGRAM, margs->AD ? "" : "not ");
351 /*
352 * Cleanup
353 */
354 if (attr_value) {
4ebcf1ce 355 size_t j;
a2f5277a 356 for (j = 0; j < max_attr; ++j) {
2e881a6f
A
357 xfree(attr_value[j]);
358 }
4ebcf1ce 359 safe_free(attr_value);
b1218840
AJ
360 }
361 ldap_msgfree(res);
362 return rc;
363}
364int
365search_group_tree(struct main_args *margs, LDAP * ld, char *bindp, char *ldap_group, char *group, int depth)
366{
367 LDAPMessage *res = NULL;
368 char **attr_value = NULL;
4ebcf1ce 369 size_t max_attr = 0;
b1218840
AJ
370 char *filter = NULL;
371 char *search_exp = NULL;
1a22a39e 372 size_t se_len = 0;
4ebcf1ce 373 int rc = 0, retval = 0;
b1218840
AJ
374 int ldepth;
375 char *ldap_filter_esc = NULL;
376 struct timeval searchtime;
377
378#define FILTER_GROUP_AD "(&(%s)(objectclass=group))"
379#define FILTER_GROUP "(&(memberuid=%s)(objectclass=posixgroup))"
380
381 searchtime.tv_sec = SEARCH_TIMEOUT;
382 searchtime.tv_usec = 0;
383
384 if (margs->AD)
2e881a6f 385 filter = (char *) FILTER_GROUP_AD;
b1218840 386 else
2e881a6f 387 filter = (char *) FILTER_GROUP;
b1218840
AJ
388
389 ldap_filter_esc = escape_filter(ldap_group);
390
1a22a39e
MM
391 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
392 search_exp = (char *) xmalloc(se_len);
393 snprintf(search_exp, se_len, filter, ldap_filter_esc);
b1218840 394
4ad7aabf 395 xfree(ldap_filter_esc);
b1218840
AJ
396
397 if (depth > margs->mdepth) {
2e881a6f 398 debug((char *) "%s| %s: DEBUG: Max search depth reached %d>%d\n", LogTime(), PROGRAM, depth, margs->mdepth);
4ad7aabf 399 xfree(search_exp);
2e881a6f 400 return 0;
b1218840
AJ
401 }
402 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n", LogTime(), PROGRAM, bindp, search_exp);
403 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
2e881a6f
A
404 search_exp, NULL, 0,
405 NULL, NULL, &searchtime, 0, &res);
4ad7aabf 406 xfree(search_exp);
b1218840
AJ
407
408 if (rc != LDAP_SUCCESS) {
2e881a6f 409 error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
2e881a6f 410 return 0;
b1218840
AJ
411 }
412 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
413
414 if (margs->AD)
4ebcf1ce 415 max_attr = get_attributes(ld, res, ATTRIBUTE_AD, &attr_value);
b1218840 416 else
4ebcf1ce 417 max_attr = get_attributes(ld, res, ATTRIBUTE, &attr_value);
b1218840
AJ
418
419 /*
420 * Compare group names
421 */
422 retval = 0;
423 ldepth = depth + 1;
365642d3 424 for (size_t j = 0; j < max_attr; ++j) {
4ebcf1ce 425 char *av = NULL;
b1218840 426
2e881a6f
A
427 /* Compare first CN= value assuming it is the same as the group name itself */
428 av = attr_value[j];
429 if (!strncasecmp("CN=", av, 3)) {
4ebcf1ce 430 char *avp = NULL;
2e881a6f
A
431 av += 3;
432 if ((avp = strchr(av, ','))) {
433 *avp = '\0';
434 }
435 }
436 if (debug_enabled) {
437 int n;
365642d3 438 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, j + 1, av);
a2f5277a 439 for (n = 0; av[n] != '\0'; ++n)
2e881a6f
A
440 fprintf(stderr, "%02x", (unsigned char) av[n]);
441 fprintf(stderr, "\n");
442 }
443 if (!strcasecmp(group, av)) {
444 retval = 1;
365642d3 445 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
2e881a6f
A
446 break;
447 } else
365642d3 448 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
2e881a6f
A
449 /*
450 * Do recursive group search
451 */
452 debug((char *) "%s| %s: DEBUG: Perform recursive group search for group \"%s\"\n", LogTime(), PROGRAM, av);
453 av = attr_value[j];
454 if (search_group_tree(margs, ld, bindp, av, group, ldepth)) {
455 retval = 1;
456 if (!strncasecmp("CN=", av, 3)) {
4ebcf1ce 457 char *avp = NULL;
2e881a6f
A
458 av += 3;
459 if ((avp = strchr(av, ','))) {
460 *avp = '\0';
461 }
462 }
463 if (debug_enabled)
365642d3 464 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" is member of group named \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
2e881a6f
A
465 else
466 break;
467
468 }
b1218840
AJ
469 }
470
471 /*
472 * Cleanup
473 */
474 if (attr_value) {
365642d3 475 for (size_t j = 0; j < max_attr; ++j) {
2e881a6f
A
476 xfree(attr_value[j]);
477 }
4ebcf1ce 478 safe_free(attr_value);
b1218840
AJ
479 }
480 ldap_msgfree(res);
481
482 return retval;
483}
484
485int
4ebcf1ce 486ldap_set_defaults(LDAP * ld)
b1218840
AJ
487{
488 int val, rc = 0;
1a22a39e 489#if LDAP_OPT_NETWORK_TIMEOUT
b1218840
AJ
490 struct timeval tv;
491#endif
492 val = LDAP_VERSION3;
493 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &val);
494 if (rc != LDAP_SUCCESS) {
2e881a6f
A
495 debug((char *) "%s| %s: DEBUG: Error while setting protocol version: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
496 return rc;
b1218840
AJ
497 }
498 rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
499 if (rc != LDAP_SUCCESS) {
2e881a6f
A
500 debug((char *) "%s| %s: DEBUG: Error while setting referrals off: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
501 return rc;
b1218840 502 }
1a22a39e 503#if LDAP_OPT_NETWORK_TIMEOUT
b1218840
AJ
504 tv.tv_sec = CONNECT_TIMEOUT;
505 tv.tv_usec = 0;
506 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
507 if (rc != LDAP_SUCCESS) {
2e881a6f
A
508 debug((char *) "%s| %s: DEBUG: Error while setting network timeout: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
509 return rc;
b1218840
AJ
510 }
511#endif /* LDAP_OPT_NETWORK_TIMEOUT */
512 return LDAP_SUCCESS;
513}
514
515int
516ldap_set_ssl_defaults(struct main_args *margs)
517{
1a22a39e 518#if HAVE_OPENLDAP || HAVE_LDAPSSL_CLIENT_INIT
b1218840
AJ
519 int rc = 0;
520#endif
1a22a39e 521#if HAVE_OPENLDAP
b1218840 522 int val;
1a22a39e 523#elif HAVE_LDAPSSL_CLIENT_INIT
b1218840
AJ
524 char *ssl_certdbpath = NULL;
525#endif
526
1a22a39e 527#if HAVE_OPENLDAP
b1218840 528 if (!margs->rc_allow) {
4ebcf1ce
MM
529 char *ssl_cacertfile = NULL;
530 int free_path;
2e881a6f
A
531 debug((char *) "%s| %s: DEBUG: Enable server certificate check for ldap server.\n", LogTime(), PROGRAM);
532 val = LDAP_OPT_X_TLS_DEMAND;
533 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
534 if (rc != LDAP_SUCCESS) {
535 error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT DEMAND for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
536 return rc;
537 }
538 ssl_cacertfile = getenv("TLS_CACERTFILE");
539 free_path = 0;
540 if (!ssl_cacertfile) {
541 ssl_cacertfile = xstrdup("/etc/ssl/certs/cert.pem");
542 free_path = 1;
543 }
544 debug((char *) "%s| %s: DEBUG: Set certificate file for ldap server to %s.(Changeable through setting environment variable TLS_CACERTFILE)\n", LogTime(), PROGRAM, ssl_cacertfile);
545 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ssl_cacertfile);
546 if (ssl_cacertfile && free_path) {
547 xfree(ssl_cacertfile);
2e881a6f
A
548 }
549 if (rc != LDAP_OPT_SUCCESS) {
550 error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
551 return rc;
552 }
b1218840 553 } else {
2e881a6f
A
554 debug((char *) "%s| %s: DEBUG: Disable server certificate check for ldap server.\n", LogTime(), PROGRAM);
555 val = LDAP_OPT_X_TLS_ALLOW;
556 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
557 if (rc != LDAP_SUCCESS) {
558 error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT ALLOW for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
559 return rc;
560 }
b1218840 561 }
1a22a39e 562#elif HAVE_LDAPSSL_CLIENT_INIT
2e881a6f 563 /*
b1218840
AJ
564 * Solaris SSL ldap calls require path to certificate database
565 */
2e881a6f
A
566 /*
567 * rc = ldapssl_client_init( ssl_certdbpath, NULL );
568 * rc = ldapssl_advclientauth_init( ssl_certdbpath, NULL , 0 , NULL, NULL, 0, NULL, 2);
569 */
b1218840
AJ
570 ssl_certdbpath = getenv("SSL_CERTDBPATH");
571 if (!ssl_certdbpath) {
2e881a6f 572 ssl_certdbpath = xstrdup("/etc/certs");
b1218840
AJ
573 }
574 debug((char *) "%s| %s: DEBUG: Set certificate database path for ldap server to %s.(Changeable through setting environment variable SSL_CERTDBPATH)\n", LogTime(), PROGRAM, ssl_certdbpath);
575 if (!margs->rc_allow) {
2e881a6f 576 rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0, NULL, 2);
b1218840 577 } else {
2e881a6f
A
578 rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0, NULL, 0);
579 debug((char *) "%s| %s: DEBUG: Disable server certificate check for ldap server.\n", LogTime(), PROGRAM);
b1218840 580 }
4ebcf1ce 581 xfree(ssl_certdbpath);
b1218840 582 if (rc != LDAP_SUCCESS) {
2e881a6f
A
583 error((char *) "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
584 return rc;
b1218840
AJ
585 }
586#else
587 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n", LogTime(), PROGRAM);
588#endif
589 return LDAP_SUCCESS;
590}
591
4ebcf1ce
MM
592size_t
593get_attributes(LDAP * ld, LDAPMessage * res, const char *attribute, char ***ret_value)
b1218840
AJ
594{
595
1a22a39e 596 char **attr_value = *ret_value;
4ebcf1ce 597 size_t max_attr = 0;
b1218840 598
b1218840
AJ
599 /*
600 * loop over attributes
601 */
602 debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n", LogTime(), PROGRAM, attribute);
1a22a39e 603 for (LDAPMessage *msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) {
2e881a6f
A
604
605 switch (ldap_msgtype(msg)) {
606
1a22a39e
MM
607 case LDAP_RES_SEARCH_ENTRY: {
608 BerElement *b = NULL;
609 for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
2e881a6f
A
610 attr = ldap_next_attribute(ld, msg, b)) {
611 if (strcasecmp(attr, attribute) == 0) {
612 struct berval **values;
2e881a6f
A
613
614 if ((values = ldap_get_values_len(ld, msg, attr)) != NULL) {
1a22a39e 615 for (int il = 0; values[il] != NULL; ++il) {
2e881a6f 616
4ebcf1ce 617 attr_value = (char **) xrealloc(attr_value, (max_attr + 1) * sizeof(char *));
2e881a6f
A
618 if (!attr_value)
619 break;
620
4ebcf1ce
MM
621 attr_value[max_attr] = (char *) xmalloc(values[il]->bv_len + 1);
622 memcpy(attr_value[max_attr], values[il]->bv_val, values[il]->bv_len);
623 attr_value[max_attr][values[il]->bv_len] = 0;
624 max_attr++;
2e881a6f 625 }
2e881a6f
A
626 }
627 ber_bvecfree(values);
628 }
629 ldap_memfree(attr);
630 }
631 ber_free(b, 0);
1a22a39e
MM
632 }
633 break;
634 case LDAP_RES_SEARCH_REFERENCE:
635 debug((char *) "%s| %s: DEBUG: Received a search reference message\n", LogTime(), PROGRAM);
636 break;
637 case LDAP_RES_SEARCH_RESULT:
638 debug((char *) "%s| %s: DEBUG: Received a search result message\n", LogTime(), PROGRAM);
639 break;
640 default:
2e881a6f 641 break;
1a22a39e
MM
642 }
643 }
644
645 debug((char *) "%s| %s: DEBUG: %" PRIuSIZE " ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM, max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
646
647 *ret_value = attr_value;
648 return max_attr;
649}
650
651size_t
652get_bin_attributes(LDAP * ld, LDAPMessage * res, const char *attribute, char ***ret_value, int **ret_len)
653{
654
655 char **attr_value = *ret_value;
656 int *attr_len = *ret_len;
657 size_t max_attr = 0;
658
659 /*
660 * loop over attributes
661 */
662 debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n", LogTime(), PROGRAM, attribute);
663 for ( LDAPMessage *msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) {
664
665 switch (ldap_msgtype(msg)) {
666
667 case LDAP_RES_SEARCH_ENTRY: {
668 BerElement *b = NULL;
669 for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
670 attr = ldap_next_attribute(ld, msg, b)) {
671 if (strcasecmp(attr, attribute) == 0) {
672 struct berval **values;
673
674 if ((values = ldap_get_values_len(ld, msg, attr)) != NULL) {
675 for (int il = 0; values[il] != NULL; ++il) {
676
677 attr_value = (char **) xrealloc(attr_value, (max_attr + 1) * sizeof(char *));
678 if (!attr_value)
679 break;
680
681 attr_len = (int *) xrealloc(attr_len, (max_attr + 1) * sizeof(int));
682 if (!attr_len)
683 break;
684
685 attr_value[max_attr] = (char *) xmalloc(values[il]->bv_len + 1);
686 memcpy(attr_value[max_attr], values[il]->bv_val, values[il]->bv_len);
687 attr_value[max_attr][values[il]->bv_len] = 0;
688 attr_len[max_attr]=values[il]->bv_len;
689 max_attr++;
690 }
691 }
692 ber_bvecfree(values);
693 }
694 ldap_memfree(attr);
695 }
696 ber_free(b, 0);
697 }
698 break;
2e881a6f
A
699 case LDAP_RES_SEARCH_REFERENCE:
700 debug((char *) "%s| %s: DEBUG: Received a search reference message\n", LogTime(), PROGRAM);
701 break;
702 case LDAP_RES_SEARCH_RESULT:
703 debug((char *) "%s| %s: DEBUG: Received a search result message\n", LogTime(), PROGRAM);
704 break;
705 default:
706 break;
707 }
b1218840
AJ
708 }
709
365642d3 710 debug((char *) "%s| %s: DEBUG: %" PRIuSIZE " ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM, max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
b1218840
AJ
711
712 *ret_value = attr_value;
1a22a39e 713 *ret_len = attr_len;
b1218840
AJ
714 return max_attr;
715}
716
717/*
718 * call to open ldap server with or without SSL
719 */
720LDAP *
721tool_ldap_open(struct main_args * margs, char *host, int port, char *ssl)
722{
723 LDAP *ld;
1a22a39e 724#if HAVE_OPENLDAP
b1218840
AJ
725 LDAPURLDesc *url = NULL;
726 char *ldapuri = NULL;
727#endif
728 int rc = 0;
729
2e881a6f
A
730 /*
731 * Use ldap open here to check if TCP connection is possible. If possible use it.
b1218840
AJ
732 * (Not sure if this is the best way)
733 */
1a22a39e 734#if HAVE_OPENLDAP
b1218840
AJ
735 url = (LDAPURLDesc *) xmalloc(sizeof(*url));
736 memset(url, 0, sizeof(*url));
1a22a39e 737#if HAVE_LDAP_URL_LUD_SCHEME
b1218840 738 if (ssl)
a667f09e 739 url->lud_scheme = xstrdup("ldaps");
b1218840 740 else
a667f09e 741 url->lud_scheme = xstrdup("ldap");
b1218840 742#endif
a667f09e 743 url->lud_host = xstrdup(host);
b1218840 744 url->lud_port = port;
1a22a39e 745#if HAVE_LDAP_SCOPE_DEFAULT
b1218840
AJ
746 url->lud_scope = LDAP_SCOPE_DEFAULT;
747#else
748 url->lud_scope = LDAP_SCOPE_SUBTREE;
749#endif
1a22a39e 750#if HAVE_LDAP_URL_DESC2STR
b1218840 751 ldapuri = ldap_url_desc2str(url);
1a22a39e 752#elif HAVE_LDAP_URL_PARSE
b1218840
AJ
753 rc = ldap_url_parse(ldapuri, &url);
754 if (rc != LDAP_SUCCESS) {
2e881a6f 755 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
b656d212 756 xfree(ldapuri);
4ebcf1ce 757 ldap_free_urldesc(url);
2e881a6f 758 return NULL;
b1218840
AJ
759 }
760#else
761#error "No URL parsing function"
762#endif
4ebcf1ce 763 ldap_free_urldesc(url);
b1218840 764 rc = ldap_initialize(&ld, ldapuri);
b656d212 765 xfree(ldapuri);
b1218840 766 if (rc != LDAP_SUCCESS) {
2e881a6f 767 error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 768 ldap_unbind_ext(ld,NULL,NULL);
2e881a6f
A
769 ld = NULL;
770 return NULL;
b1218840
AJ
771 }
772#else
773 ld = ldap_init(host, port);
774#endif
4ebcf1ce 775 rc = ldap_set_defaults(ld);
b1218840 776 if (rc != LDAP_SUCCESS) {
2e881a6f 777 error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 778 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
779 ld = NULL;
780 return NULL;
b1218840
AJ
781 }
782 if (ssl) {
2e881a6f
A
783 /*
784 * Try Start TLS first
785 */
786 debug((char *) "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM);
787 rc = ldap_set_ssl_defaults(margs);
788 if (rc != LDAP_SUCCESS) {
789 error((char *) "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 790 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
791 ld = NULL;
792 return NULL;
793 }
1a22a39e 794#if HAVE_OPENLDAP
2e881a6f
A
795 /*
796 * Use tls if possible
797 */
798 rc = ldap_start_tls_s(ld, NULL, NULL);
799 if (rc != LDAP_SUCCESS) {
800 error((char *) "%s| %s: ERROR: Error while setting start_tls for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 801 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
802 ld = NULL;
803 url = (LDAPURLDesc *) xmalloc(sizeof(*url));
804 memset(url, 0, sizeof(*url));
1a22a39e 805#if HAVE_LDAP_URL_LUD_SCHEME
a667f09e 806 url->lud_scheme = xstrdup("ldaps");
b1218840 807#endif
a667f09e 808 url->lud_host = xstrdup(host);
2e881a6f 809 url->lud_port = port;
1a22a39e 810#if HAVE_LDAP_SCOPE_DEFAULT
2e881a6f 811 url->lud_scope = LDAP_SCOPE_DEFAULT;
b1218840 812#else
2e881a6f 813 url->lud_scope = LDAP_SCOPE_SUBTREE;
b1218840 814#endif
1a22a39e 815#if HAVE_LDAP_URL_DESC2STR
2e881a6f 816 ldapuri = ldap_url_desc2str(url);
1a22a39e 817#elif HAVE_LDAP_URL_PARSE
2e881a6f
A
818 rc = ldap_url_parse(ldapuri, &url);
819 if (rc != LDAP_SUCCESS) {
820 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
4ad7aabf 821 xfree(ldapuri);
4ebcf1ce 822 ldap_free_urldesc(url);
2e881a6f
A
823 return NULL;
824 }
b1218840
AJ
825#else
826#error "No URL parsing function"
827#endif
4ebcf1ce 828 ldap_free_urldesc(url);
2e881a6f 829 rc = ldap_initialize(&ld, ldapuri);
4ad7aabf 830 xfree(ldapuri);
2e881a6f
A
831 if (rc != LDAP_SUCCESS) {
832 error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 833 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
834 ld = NULL;
835 return NULL;
836 }
4ebcf1ce 837 rc = ldap_set_defaults(ld);
2e881a6f
A
838 if (rc != LDAP_SUCCESS) {
839 error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 840 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
841 ld = NULL;
842 return NULL;
843 }
844 }
1a22a39e 845#elif HAVE_LDAPSSL_CLIENT_INIT
2e881a6f
A
846 ld = ldapssl_init(host, port, 1);
847 if (!ld) {
848 error((char *) "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
75f3c557 849 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
850 ld = NULL;
851 return NULL;
852 }
4ebcf1ce 853 rc = ldap_set_defaults(ld);
2e881a6f
A
854 if (rc != LDAP_SUCCESS) {
855 error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 856 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
857 ld = NULL;
858 return NULL;
859 }
b1218840 860#else
2e881a6f 861 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n", LogTime(), PROGRAM);
b1218840
AJ
862#endif
863 }
864 return ld;
865}
866
867/*
868 * ldap calls to get attribute from Ldap Directory Server
869 */
870int
871get_memberof(struct main_args *margs, char *user, char *domain, char *group)
872{
873 LDAP *ld = NULL;
874 LDAPMessage *res;
1a22a39e 875#if !HAVE_SUN_LDAP_SDK
b1218840
AJ
876 int ldap_debug = 0;
877#endif
878 struct ldap_creds *lcreds = NULL;
879 char *bindp = NULL;
880 char *filter = NULL;
881 char *search_exp;
1a22a39e 882 size_t se_len = 0;
b1218840 883 struct timeval searchtime;
4ebcf1ce 884 int rc = 0, kc = 1;
b1218840
AJ
885 int retval;
886 char **attr_value = NULL;
4ebcf1ce 887 size_t max_attr = 0;
b1218840 888 struct hstruct *hlist = NULL;
4ebcf1ce 889 size_t nhosts = 0;
b1218840
AJ
890 char *ldap_filter_esc = NULL;
891
b1218840
AJ
892 searchtime.tv_sec = SEARCH_TIMEOUT;
893 searchtime.tv_usec = 0;
894 /*
895 * Fill Kerberos memory cache with credential from keytab for SASL/GSSAPI
896 */
897 if (domain) {
2e881a6f 898 debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n", LogTime(), PROGRAM);
b1218840 899
1a22a39e 900#if HAVE_KRB5
7451e5ad
MM
901 if (margs->nokerberos) {
902 kc = 1;
903 debug((char *) "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n", LogTime(), PROGRAM);
904 } else {
905 kc = krb5_create_cache(domain);
906 if (kc) {
907 error((char *) "%s| %s: ERROR: Error during setup of Kerberos credential cache\n", LogTime(), PROGRAM);
908 }
2e881a6f 909 }
bec91ba0
MM
910#else
911 kc = 1;
b2bdde72 912 debug((char *) "%s| %s: DEBUG: Kerberos is not supported. Use username/password with ldap url instead\n", LogTime(), PROGRAM);
bec91ba0 913#endif
b1218840 914 }
bec91ba0 915
1a22a39e 916 if (kc && (!margs->lurl || !margs->luser || !margs->lpass)) {
2e881a6f
A
917 /*
918 * If Kerberos fails and no url given exit here
919 */
920 retval = 0;
921 goto cleanup;
b1218840 922 }
1a22a39e 923#if !HAVE_SUN_LDAP_SDK
b1218840
AJ
924 /*
925 * Initialise ldap
926 */
927 ldap_debug = 127 /* LDAP_DEBUG_TRACE */ ;
928 ldap_debug = -1 /* LDAP_DEBUG_ANY */ ;
929 ldap_debug = 0;
930 (void) ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug);
931#endif
932 debug((char *) "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(), PROGRAM);
933
934 if (domain && !kc) {
2e881a6f
A
935 if (margs->ssl) {
936 debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
937 }
938 debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name for domain %s\n", LogTime(), PROGRAM, domain);
939 /*
940 * Loop over list of ldap servers of users domain
941 */
942 nhosts = get_ldap_hostname_list(margs, &hlist, 0, domain);
365642d3 943 for (size_t i = 0; i < nhosts; ++i) {
4ebcf1ce 944 int port = 389;
2e881a6f
A
945 if (hlist[i].port != -1)
946 port = hlist[i].port;
947 debug((char *) "%s| %s: DEBUG: Setting up connection to ldap server %s:%d\n", LogTime(), PROGRAM, hlist[i].host, port);
948
949 ld = tool_ldap_open(margs, hlist[i].host, port, margs->ssl);
950 if (!ld)
951 continue;
952
953 /*
954 * ldap bind with SASL/GSSAPI authentication (only possible if a domain was part of the username)
955 */
b1218840 956
1a22a39e 957#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
2e881a6f
A
958 debug((char *) "%s| %s: DEBUG: Bind to ldap server with SASL/GSSAPI\n", LogTime(), PROGRAM);
959
960 rc = tool_sasl_bind(ld, bindp, margs->ssl);
961 if (rc != LDAP_SUCCESS) {
962 error((char *) "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 963 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
964 ld = NULL;
965 continue;
966 }
1a22a39e 967 lcreds = (struct ldap_creds *) xmalloc(sizeof(struct ldap_creds));
4ad7aabf 968 lcreds->dn = NULL;
2e881a6f
A
969 lcreds->pw = margs->ssl ? xstrdup(margs->ssl) : NULL;
970 ldap_set_rebind_proc(ld, ldap_sasl_rebind, (char *) lcreds);
971 if (ld != NULL) {
972 debug((char *) "%s| %s: DEBUG: %s initialised %sconnection to ldap server %s:%d\n", LogTime(), PROGRAM, ld ? "Successfully" : "Failed to", margs->ssl ? "SSL protected " : "", hlist[i].host, port);
973 break;
974 }
b1218840 975#else
75f3c557 976 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
977 ld = NULL;
978 error((char *) "%s| %s: ERROR: SASL not supported on system\n", LogTime(), PROGRAM);
979 continue;
b1218840 980#endif
2e881a6f
A
981 }
982 nhosts = free_hostname_list(&hlist, nhosts);
983 if (ld == NULL) {
984 debug((char *) "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n", LogTime(), PROGRAM, strerror(errno));
985 }
986 bindp = convert_domain_to_bind_path(domain);
b1218840
AJ
987 }
988 if ((!domain || !ld) && margs->lurl && strstr(margs->lurl, "://")) {
4ebcf1ce
MM
989 char *hostname;
990 char *host;
991 int port;
992 char *ssl = NULL;
993 char *p;
2e881a6f
A
994 /*
995 * If username does not contain a domain and a url was given then try it
996 */
997 hostname = strstr(margs->lurl, "://") + 3;
998 ssl = strstr(margs->lurl, "ldaps://");
999 if (ssl) {
1000 debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
1001 }
1002 debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name %s\n", LogTime(), PROGRAM, hostname);
1003 /*
1004 * Loop over list of ldap servers
1005 */
1006 host = xstrdup(hostname);
1007 port = 389;
1008 if ((p = strchr(host, ':'))) {
1009 *p = '\0';
755494da 1010 ++p;
2e881a6f
A
1011 port = atoi(p);
1012 }
4ebcf1ce
MM
1013 nhosts = get_hostname_list(&hlist, 0, host);
1014 xfree(host);
365642d3 1015 for (size_t i = 0; i < nhosts; ++i) {
5f4daa47
SM
1016 struct berval cred;
1017 if (margs->lpass) {
75f3c557
MM
1018 cred.bv_val=margs->lpass;
1019 cred.bv_len=strlen(margs->lpass);
5f4daa47 1020 }
2e881a6f
A
1021 ld = tool_ldap_open(margs, hlist[i].host, port, ssl);
1022 if (!ld)
1023 continue;
1024 /*
1025 * ldap bind with username/password authentication
1026 */
1027
1028 debug((char *) "%s| %s: DEBUG: Bind to ldap server with Username/Password\n", LogTime(), PROGRAM);
5f4daa47 1029 rc = ldap_sasl_bind_s(ld, margs->luser, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
2e881a6f
A
1030 if (rc != LDAP_SUCCESS) {
1031 error((char *) "%s| %s: ERROR: Error while binding to ldap server with Username/Password: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 1032 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
1033 ld = NULL;
1034 continue;
1035 }
1a22a39e 1036 lcreds = (struct ldap_creds *) xmalloc(sizeof(struct ldap_creds));
2e881a6f
A
1037 lcreds->dn = xstrdup(margs->luser);
1038 lcreds->pw = xstrdup(margs->lpass);
1039 ldap_set_rebind_proc(ld, ldap_simple_rebind, (char *) lcreds);
1040 debug((char *) "%s| %s: DEBUG: %s set up %sconnection to ldap server %s:%d\n", LogTime(), PROGRAM, ld ? "Successfully" : "Failed to", ssl ? "SSL protected " : "", hlist[i].host, port);
1041 break;
1042
1043 }
1044 nhosts = free_hostname_list(&hlist, nhosts);
4ad7aabf 1045 xfree(bindp);
2e881a6f
A
1046 if (margs->lbind) {
1047 bindp = xstrdup(margs->lbind);
1048 } else {
1049 bindp = convert_domain_to_bind_path(domain);
1050 }
b1218840
AJ
1051 }
1052 if (ld == NULL) {
2e881a6f
A
1053 debug((char *) "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n", LogTime(), PROGRAM, strerror(errno));
1054 retval = 0;
1055 goto cleanup;
b1218840
AJ
1056 }
1057 /*
1058 * ldap search for user
1059 */
2e881a6f 1060 /*
b1218840
AJ
1061 * Check if server is AD by querying for attribute samaccountname
1062 */
1063 margs->AD = 0;
1064 rc = check_AD(margs, ld);
1065 if (rc != LDAP_SUCCESS) {
2e881a6f 1066 error((char *) "%s| %s: ERROR: Error determining ldap server type: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 1067 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
1068 ld = NULL;
1069 retval = 0;
1070 goto cleanup;
b1218840
AJ
1071 }
1072 if (margs->AD)
2e881a6f 1073 filter = (char *) FILTER_AD;
b1218840 1074 else
2e881a6f 1075 filter = (char *) FILTER;
b1218840
AJ
1076
1077 ldap_filter_esc = escape_filter(user);
1078
1a22a39e
MM
1079 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1080 search_exp = (char *) xmalloc(se_len);
1081 snprintf(search_exp, se_len, filter, ldap_filter_esc);
b1218840 1082
4ad7aabf 1083 xfree(ldap_filter_esc);
b1218840
AJ
1084
1085 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n", LogTime(), PROGRAM, bindp, search_exp);
1086 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
2e881a6f
A
1087 search_exp, NULL, 0,
1088 NULL, NULL, &searchtime, 0, &res);
4ad7aabf 1089 xfree(search_exp);
b1218840
AJ
1090
1091 if (rc != LDAP_SUCCESS) {
2e881a6f 1092 error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
75f3c557 1093 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
1094 ld = NULL;
1095 retval = 0;
1096 goto cleanup;
b1218840
AJ
1097 }
1098 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1099
1100 if (ldap_count_entries(ld, res) != 0) {
1101
2e881a6f 1102 if (margs->AD)
4ebcf1ce 1103 max_attr = get_attributes(ld, res, ATTRIBUTE_AD, &attr_value);
2e881a6f 1104 else {
4ebcf1ce 1105 max_attr = get_attributes(ld, res, ATTRIBUTE, &attr_value);
2e881a6f
A
1106 }
1107
1108 /*
1109 * Compare group names
1110 */
1111 retval = 0;
365642d3 1112 for (size_t k = 0; k < max_attr; ++k) {
4ebcf1ce 1113 char *av = NULL;
2e881a6f
A
1114
1115 /* Compare first CN= value assuming it is the same as the group name itself */
4ebcf1ce 1116 av = attr_value[k];
2e881a6f 1117 if (!strncasecmp("CN=", av, 3)) {
4ebcf1ce 1118 char *avp = NULL;
2e881a6f
A
1119 av += 3;
1120 if ((avp = strchr(av, ','))) {
1121 *avp = '\0';
1122 }
1123 }
1124 if (debug_enabled) {
365642d3
AJ
1125 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, k + 1, av);
1126 for (unsigned int n = 0; av[n] != '\0'; ++n)
2e881a6f
A
1127 fprintf(stderr, "%02x", (unsigned char) av[n]);
1128 fprintf(stderr, "\n");
1129 }
1130 if (!strcasecmp(group, av)) {
1131 retval = 1;
1132 if (debug_enabled)
365642d3 1133 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, k + 1, av, group);
2e881a6f
A
1134 else
1135 break;
1136 } else
365642d3 1137 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, k + 1, av, group);
2e881a6f
A
1138 }
1139 /*
1140 * Do recursive group search for AD only since posixgroups can not contain other groups
1141 */
1142 if (!retval && margs->AD) {
1143 if (debug_enabled && max_attr > 0) {
1144 debug((char *) "%s| %s: DEBUG: Perform recursive group search\n", LogTime(), PROGRAM);
1145 }
365642d3 1146 for (size_t j = 0; j < max_attr; ++j) {
4ebcf1ce 1147 char *av = NULL;
2e881a6f
A
1148
1149 av = attr_value[j];
1150 if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1151 retval = 1;
1152 if (!strncasecmp("CN=", av, 3)) {
4ebcf1ce 1153 char *avp = NULL;
2e881a6f
A
1154 av += 3;
1155 if ((avp = strchr(av, ','))) {
1156 *avp = '\0';
1157 }
1158 }
1159 if (debug_enabled)
365642d3 1160 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " group \"%s\" is (in)direct member of group \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
2e881a6f
A
1161 else
1162 break;
1163 }
1164 }
1165 }
1166 /*
1167 * Cleanup
1168 */
1169 if (attr_value) {
365642d3 1170 for (size_t j = 0; j < max_attr; ++j) {
2e881a6f
A
1171 xfree(attr_value[j]);
1172 }
4ebcf1ce 1173 safe_free(attr_value);
2e881a6f
A
1174 }
1175 ldap_msgfree(res);
b1218840 1176 } else if (ldap_count_entries(ld, res) == 0 && margs->AD) {
2e881a6f 1177 ldap_msgfree(res);
75f3c557 1178 ldap_unbind_ext(ld, NULL, NULL);
2e881a6f
A
1179 ld = NULL;
1180 retval = 0;
1181 goto cleanup;
b1218840 1182 } else {
2e881a6f
A
1183 ldap_msgfree(res);
1184 retval = 0;
b1218840
AJ
1185 }
1186
1a22a39e 1187 if (retval == 0) {
2e881a6f
A
1188 /*
1189 * Check for primary Group membership
1190 */
1191 debug((char *) "%s| %s: DEBUG: Search for primary group membership: \"%s\"\n", LogTime(), PROGRAM, group);
1a22a39e
MM
1192 if (margs->AD)
1193 filter = (char *) FILTER_AD;
1194 else
1195 filter = (char *) FILTER_UID;
2e881a6f
A
1196
1197 ldap_filter_esc = escape_filter(user);
1198
1a22a39e
MM
1199 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1200 search_exp = (char *) xmalloc(se_len);
1201 snprintf(search_exp, se_len, filter, ldap_filter_esc);
2e881a6f 1202
4ad7aabf 1203 xfree(ldap_filter_esc);
2e881a6f
A
1204
1205 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, bindp, search_exp);
1206 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1207 search_exp, NULL, 0,
1208 NULL, NULL, &searchtime, 0, &res);
4ad7aabf 1209 xfree(search_exp);
2e881a6f
A
1210
1211 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1212
1a22a39e
MM
1213 max_attr = 0;
1214 if (!rc) {
1215 if (margs->AD)
1216 max_attr = get_attributes(ld, res, ATTRIBUTE_GID_AD, &attr_value);
1217 else
1218 max_attr = get_attributes(ld, res, ATTRIBUTE_GID, &attr_value);
1219 }
2e881a6f
A
1220
1221 if (max_attr == 1) {
1222 char **attr_value_2 = NULL;
4ebcf1ce 1223 size_t max_attr_2 = 0;
2e881a6f 1224
1a22a39e
MM
1225 if (margs->AD) {
1226 char **attr_value_3 = NULL;
1227 int *attr_len_3 = NULL;
1228 size_t max_attr_3 = 0;
1229 uint32_t gid=atoi(attr_value[0]);
1230
1231 /* Get objectsid and search for group
1232 * with objectsid = domain(objectsid) + primarygroupid */
1233 debug((char *) "%s| %s: DEBUG: Got primaryGroupID %u\n", LogTime(), PROGRAM, gid);
1234 max_attr_3 = get_bin_attributes(ld, res, ATTRIBUTE_SID, &attr_value_3, &attr_len_3);
1235 ldap_msgfree(res);
1236 if (max_attr_3 == 1) {
1237 int len=attr_len_3[0];
1238 if (len < 4) {
1239 debug((char *) "%s| %s: ERROR: Length %d is too short for objectSID\n", LogTime(), PROGRAM, len);
1240 rc = 1;
1241 } else {
1242 char *se=NULL;
1243 attr_value_3[0][len-1]=((gid>>24) & 0xff);
1244 attr_value_3[0][len-2]=((gid>>16) & 0xff);
1245 attr_value_3[0][len-3]=((gid>>8) & 0xff);
1246 attr_value_3[0][len-4]=((gid>>0) & 0xff);
1247
1248#define FILTER_SID_1 "(objectSID="
1249#define FILTER_SID_2 ")"
1250
1251 se_len = strlen(FILTER_SID_1) + len*3 + strlen(FILTER_SID_2) + 1;
1252 search_exp = (char *) xmalloc(se_len);
1253 snprintf(search_exp, se_len, "%s", FILTER_SID_1 );
1254
1255 for (int j=0; j<len; j++) {
581d42c4 1256 se=xstrdup(search_exp);
1a22a39e
MM
1257 snprintf(search_exp, se_len, "%s\\%02x", se, attr_value_3[0][j] & 0xFF);
1258 xfree(se);
1259 }
581d42c4 1260 se=xstrdup(search_exp);
1a22a39e
MM
1261 snprintf(search_exp, se_len, "%s%s", se, FILTER_SID_2 );
1262 xfree(se);
2e881a6f 1263
1a22a39e
MM
1264 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, bindp, search_exp);
1265 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1266 search_exp, NULL, 0,
1267 NULL, NULL, &searchtime, 0, &res);
1268 xfree(search_exp);
2e881a6f 1269
1a22a39e 1270 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
2e881a6f 1271
1a22a39e
MM
1272 }
1273 } else {
1274 rc = 1;
1275 }
1276 if (attr_value_3) {
1277 size_t j;
1278 for (j = 0; j < max_attr_3; ++j) {
1279 xfree(attr_value_3[j]);
1280 }
1281 safe_free(attr_value_3);
1282 }
1283 if (attr_len_3) {
1284 xfree(attr_len_3);
1285 }
1286 } else {
1287 ldap_msgfree(res);
1288 filter = (char *) FILTER_GID;
1289
1290 ldap_filter_esc = escape_filter(attr_value[0]);
1291
1292 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1293 search_exp = (char *) xmalloc(se_len);
1294 snprintf(search_exp, se_len, filter, ldap_filter_esc);
2e881a6f 1295
1a22a39e 1296 xfree(ldap_filter_esc);
2e881a6f 1297
1a22a39e
MM
1298 debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, bindp, search_exp);
1299 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1300 search_exp, NULL, 0,
1301 NULL, NULL, &searchtime, 0, &res);
1302 xfree(search_exp);
1303 }
1304
1305 if (!rc) {
1306 if (margs->AD)
1307 max_attr_2 = get_attributes(ld, res, ATTRIBUTE_DN, &attr_value_2);
1308 else
1309 max_attr_2 = get_attributes(ld, res, ATTRIBUTE, &attr_value_2);
1310 ldap_msgfree(res);
1311 } else {
1312 ldap_msgfree(res);
1313 }
2e881a6f
A
1314 /*
1315 * Compare group names
1316 */
1317 retval = 0;
1318 if (max_attr_2 == 1) {
2e881a6f 1319 /* Compare first CN= value assuming it is the same as the group name itself */
4ebcf1ce 1320 char *av = attr_value_2[0];
1a22a39e
MM
1321 if (!strncasecmp("CN=", av, 3)) {
1322 char *avp = NULL;
1323 av += 3;
1324 if ((avp = strchr(av, ','))) {
1325 *avp = '\0';
1326 }
1327 }
2e881a6f
A
1328 if (!strcasecmp(group, av)) {
1329 retval = 1;
1330 debug((char *) "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, av, group);
1331 } else
1332 debug((char *) "%s| %s: DEBUG: \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, av, group);
1333
1334 }
1a22a39e
MM
1335 /*
1336 * Do recursive group search for AD only since posixgroups can not contain other groups
1337 */
1338 if (!retval && margs->AD) {
1339 if (debug_enabled && max_attr_2 > 0) {
1340 debug((char *) "%s| %s: DEBUG: Perform recursive group search\n", LogTime(), PROGRAM);
1341 }
1342 for (size_t j = 0; j < max_attr_2; ++j) {
1343 char *av = NULL;
1344
1345 av = attr_value_2[j];
1346 if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1347 retval = 1;
1348 if (!strncasecmp("CN=", av, 3)) {
1349 char *avp = NULL;
1350 av += 3;
1351 if ((avp = strchr(av, ','))) {
1352 *avp = '\0';
1353 }
1354 }
1355 if (debug_enabled) {
1356 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE " group \"%s\" is (in)direct member of group \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
1357 } else {
1358 break;
1359 }
1360 }
1361 }
1362 }
2e881a6f
A
1363 /*
1364 * Cleanup
1365 */
1366 if (attr_value_2) {
4ebcf1ce 1367 size_t j;
a2f5277a 1368 for (j = 0; j < max_attr_2; ++j) {
2e881a6f
A
1369 xfree(attr_value_2[j]);
1370 }
4ebcf1ce 1371 safe_free(attr_value_2);
2e881a6f 1372 }
2e881a6f
A
1373
1374 debug((char *) "%s| %s: DEBUG: Users primary group %s %s\n", LogTime(), PROGRAM, retval ? "matches" : "does not match", group);
1375
96072b37 1376 } else {
4f10fd9b 1377 ldap_msgfree(res);
96072b37
AJ
1378 debug((char *) "%s| %s: DEBUG: Did not find ldap entry for group %s\n", LogTime(), PROGRAM, group);
1379 }
2e881a6f
A
1380 /*
1381 * Cleanup
1382 */
1383 if (attr_value) {
365642d3 1384 for (size_t j = 0; j < max_attr; ++j) {
2e881a6f
A
1385 xfree(attr_value[j]);
1386 }
4ebcf1ce 1387 safe_free(attr_value);
2e881a6f 1388 }
b1218840 1389 }
75f3c557 1390 rc = ldap_unbind_ext(ld, NULL, NULL);
b1218840
AJ
1391 ld = NULL;
1392 if (rc != LDAP_SUCCESS) {
2e881a6f 1393 error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
b1218840
AJ
1394 }
1395 debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM);
2e881a6f 1396cleanup:
b1218840 1397 if (lcreds) {
4ad7aabf
AJ
1398 xfree(lcreds->dn);
1399 xfree(lcreds->pw);
2e881a6f 1400 xfree(lcreds);
b1218840 1401 }
4ad7aabf 1402 xfree(bindp);
b1218840 1403 return (retval);
b1218840
AJ
1404}
1405#endif
f53969cc 1406