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