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