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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors