2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 * -----------------------------------------------------------------------------
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
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.
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.
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.
30 * -----------------------------------------------------------------------------
33 /* get_attributes is partly from OpenLDAP Software <http://www.openldap.org/>.
35 * Copyright 1998-2009 The OpenLDAP Foundation.
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted only as authorized by the OpenLDAP
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>.
55 char *convert_domain_to_bind_path(char *domain
);
56 char *escape_filter(char *filter
);
57 int check_AD(struct main_args
*margs
, LDAP
* ld
);
58 int ldap_set_defaults(LDAP
* ld
);
59 int ldap_set_ssl_defaults(struct main_args
*margs
);
60 LDAP
*tool_ldap_open(struct main_args
*margs
, char *host
, int port
, char *ssl
);
62 #define CONNECT_TIMEOUT 2
63 #define SEARCH_TIMEOUT 30
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"
74 #define FILTER_AD "(samaccountname=%s)"
75 #define ATTRIBUTE_AD "memberof"
77 size_t get_attributes(LDAP
* ld
, LDAPMessage
* res
,
78 const char *attribute
/* IN */, char ***out_val
/* OUT (caller frees) */ );
79 size_t get_bin_attributes(LDAP
* ld
, LDAPMessage
* res
,
80 const char *attribute
/* IN */, char ***out_val
,
81 int **out_len
/* OUT (caller frees) */ );
82 int search_group_tree(struct main_args
*margs
, LDAP
* ld
, char *bindp
,
83 char *ldap_group
, char *group
, int depth
);
85 #if HAVE_SUN_LDAP_SDK || HAVE_MOZILLA_LDAP_SDK
86 #if HAVE_LDAP_REBINDPROC_CALLBACK
88 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
89 static LDAP_REBINDPROC_CALLBACK ldap_sasl_rebind
;
91 static int LDAP_CALL LDAP_CALLBACK
92 ldap_sasl_rebind(LDAP
* ld
,
93 char **whop
, char **credp
, int *methodp
, int freeit
, void *params
)
95 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
100 return tool_sasl_bind(ld
, cp
->dn
, cp
->pw
);
104 static LDAP_REBINDPROC_CALLBACK ldap_simple_rebind
;
106 static int LDAP_CALL LDAP_CALLBACK
107 ldap_simple_rebind(LDAP
* ld
,
108 char **whop
, char **credp
, int *methodp
, int freeit
, void *params
)
110 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
113 cred
.bv_val
= cp
->pw
;
114 cred
.bv_len
= strlen(cp
->pw
);
120 return ldap_sasl_bind_s(ld
, cp
->dn
, LDAP_SASL_SIMPLE
, &cred
, nullptr, nullptr,
123 #elif HAVE_LDAP_REBIND_PROC
124 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
125 static LDAP_REBIND_PROC ldap_sasl_rebind
;
128 ldap_sasl_rebind(LDAP
* ld
,
129 LDAP_CONST
char *url
, ber_tag_t request
, ber_int_t msgid
, void *params
)
131 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
132 return tool_sasl_bind(ld
, cp
->dn
, cp
->pw
);
134 #endif /* HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN */
136 static LDAP_REBIND_PROC ldap_simple_rebind
;
139 ldap_simple_rebind(LDAP
* ld
,
140 LDAP_CONST
char *url
, ber_tag_t request
, ber_int_t msgid
, void *params
)
142 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
145 cred
.bv_val
= cp
->pw
;
146 cred
.bv_len
= strlen(cp
->pw
);
148 return ldap_sasl_bind_s(ld
, cp
->dn
, LDAP_SASL_SIMPLE
, &cred
, nullptr, nullptr,
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
157 static LDAP_REBIND_FUNCTION ldap_sasl_rebind
;
160 ldap_sasl_rebind(LDAP
* ld
,
161 char **whop
, char **credp
, int *methodp
, int freeit
, void *params
)
163 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
168 return tool_sasl_bind(ld
, cp
->dn
, cp
->pw
);
172 static LDAP_REBIND_FUNCTION ldap_simple_rebind
;
175 ldap_simple_rebind(LDAP
* ld
,
176 char **whop
, char **credp
, int *methodp
, int freeit
, void *params
)
178 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
181 cred
.bv_val
= cp
->pw
;
182 cred
.bv_len
= strlen(cp
->pw
);
188 return ldap_sasl_bind_s(ld
, cp
->dn
, LDAP_SASL_SIMPLE
, &cred
, nullptr, nullptr,
192 #error "No rebind functione defined"
194 #else /* HAVE_SUN_LDAP_SDK */
195 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
196 static LDAP_REBIND_PROC ldap_sasl_rebind
;
199 ldap_sasl_rebind(LDAP
* ld
, LDAP_CONST
char *, ber_tag_t
,
200 ber_int_t
, void *params
)
202 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
203 return tool_sasl_bind(ld
, cp
->dn
, cp
->pw
);
207 static LDAP_REBIND_PROC ldap_simple_rebind
;
210 ldap_simple_rebind(LDAP
* ld
, LDAP_CONST
char *, ber_tag_t
,
211 ber_int_t
, void *params
)
214 struct ldap_creds
*cp
= (struct ldap_creds
*) params
;
217 cred
.bv_val
= cp
->pw
;
218 cred
.bv_len
= strlen(cp
->pw
);
220 return ldap_sasl_bind_s(ld
, cp
->dn
, LDAP_SASL_SIMPLE
, &cred
, nullptr, nullptr,
226 convert_domain_to_bind_path(char *domain
)
228 char *dp
, *bindp
= nullptr, *bp
= nullptr;
234 for (dp
= domain
; *dp
; ++dp
) {
240 * replace . with ,dc= => new length = old length + #dots * 3 + 3
242 bindp
= (char *) xmalloc(strlen(domain
) + 3 + i
* 3 + 1);
246 for (dp
= domain
; *dp
; ++dp
) {
260 escape_filter(char *filter
)
262 char *ldap_filter_esc
, *ldf
;
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
== '\\'))
273 ldap_filter_esc
= (char *) xcalloc(strlen(filter
) + i
+ 1, sizeof(char));
274 ldf
= ldap_filter_esc
;
275 for (; *filter
; ++filter
) {
276 if (*filter
== '*') {
279 } else if (*filter
== '(') {
282 } else if (*filter
== ')') {
285 } else if (*filter
== '\\') {
295 return ldap_filter_esc
;
299 check_AD(struct main_args
*margs
, LDAP
* ld
)
302 char **attr_value
= nullptr;
303 struct timeval searchtime
;
307 #define FILTER_SCHEMA "(objectclass=*)"
308 #define ATTRIBUTE_SCHEMA "schemaNamingContext"
309 #define FILTER_SAM "(ldapdisplayname=samaccountname)"
311 searchtime
.tv_sec
= SEARCH_TIMEOUT
;
312 searchtime
.tv_usec
= 0;
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
);
320 if (rc
== LDAP_SUCCESS
)
321 max_attr
= get_attributes(ld
, res
, ATTRIBUTE_SCHEMA
, &attr_value
);
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)
337 "%s| %s: DEBUG: Did not find ldap entry for subschemasubentry\n",
340 "%s| %s: DEBUG: Determined ldap server %sas an Active Directory server\n",
341 LogTime(), PROGRAM
, margs
->AD
? "" : "not ");
347 for (j
= 0; j
< max_attr
; ++j
) {
348 xfree(attr_value
[j
]);
350 safe_free(attr_value
);
357 search_group_tree(struct main_args
*margs
, LDAP
* ld
, char *bindp
,
358 char *ldap_group
, char *group
, int depth
)
360 LDAPMessage
*res
= nullptr;
361 char **attr_value
= nullptr;
363 char *filter
= nullptr;
364 char *search_exp
= nullptr;
366 int rc
= 0, retval
= 0;
368 char *ldap_filter_esc
= nullptr;
369 struct timeval searchtime
;
371 #define FILTER_GROUP_AD "(&(%s)(objectclass=group))"
372 #define FILTER_GROUP "(&(memberuid=%s)(objectclass=posixgroup))"
374 searchtime
.tv_sec
= SEARCH_TIMEOUT
;
375 searchtime
.tv_usec
= 0;
378 filter
= (char *) FILTER_GROUP_AD
;
380 filter
= (char *) FILTER_GROUP
;
382 ldap_filter_esc
= escape_filter(ldap_group
);
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
);
388 xfree(ldap_filter_esc
);
390 if (depth
> margs
->mdepth
) {
391 debug((char *) "%s| %s: DEBUG: Max search depth reached %d>%d\n",
392 LogTime(), PROGRAM
, depth
, margs
->mdepth
);
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
);
403 if (rc
!= LDAP_SUCCESS
) {
404 error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n",
405 LogTime(), PROGRAM
, ldap_err2string(rc
));
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");
413 max_attr
= get_attributes(ld
, res
, ATTRIBUTE_AD
, &attr_value
);
415 max_attr
= get_attributes(ld
, res
, ATTRIBUTE
, &attr_value
);
418 * Compare group names
422 for (size_t j
= 0; j
< max_attr
; ++j
) {
425 /* Compare first CN= value assuming it is the same as the group name itself */
427 if (!strncasecmp("CN=", av
, 3)) {
430 if ((avp
= strchr(av
, ','))) {
436 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM
, j
+ 1, av
);
437 for (n
= 0; av
[n
] != '\0'; ++n
)
438 fprintf(stderr
, "%02x", (unsigned char) av
[n
]);
439 fprintf(stderr
, "\n");
441 if (!strcasecmp(group
, av
)) {
443 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM
,
447 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" does not match group name \"%s\"\n", LogTime(),
448 PROGRAM
, j
+ 1, av
, group
);
450 * Do recursive group search
453 "%s| %s: DEBUG: Perform recursive group search for group \"%s\"\n",
454 LogTime(), PROGRAM
, av
);
456 if (search_group_tree(margs
, ld
, bindp
, av
, group
, ldepth
)) {
458 if (!strncasecmp("CN=", av
, 3)) {
461 if ((avp
= strchr(av
, ','))) {
466 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" is member of group named \"%s\"\n", LogTime(),
467 PROGRAM
, j
+ 1, av
, group
);
478 for (size_t j
= 0; j
< max_attr
; ++j
) {
479 xfree(attr_value
[j
]);
481 safe_free(attr_value
);
489 ldap_set_defaults(LDAP
* ld
)
492 #if LDAP_OPT_NETWORK_TIMEOUT
496 rc
= ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
, &val
);
497 if (rc
!= LDAP_SUCCESS
) {
499 "%s| %s: DEBUG: Error while setting protocol version: %s\n",
500 LogTime(), PROGRAM
, ldap_err2string(rc
));
503 rc
= ldap_set_option(ld
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
);
504 if (rc
!= LDAP_SUCCESS
) {
505 debug((char *) "%s| %s: DEBUG: Error while setting referrals off: %s\n",
506 LogTime(), PROGRAM
, ldap_err2string(rc
));
509 #if LDAP_OPT_NETWORK_TIMEOUT
510 tv
.tv_sec
= CONNECT_TIMEOUT
;
512 rc
= ldap_set_option(ld
, LDAP_OPT_NETWORK_TIMEOUT
, &tv
);
513 if (rc
!= LDAP_SUCCESS
) {
515 "%s| %s: DEBUG: Error while setting network timeout: %s\n",
516 LogTime(), PROGRAM
, ldap_err2string(rc
));
519 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
524 ldap_set_ssl_defaults(struct main_args
*margs
)
526 #if HAVE_OPENLDAP || HAVE_LDAPSSL_CLIENT_INIT
531 #elif HAVE_LDAPSSL_CLIENT_INIT
532 char *ssl_certdbpath
= nullptr;
536 if (!margs
->rc_allow
) {
537 char *ssl_cacertfile
= nullptr;
538 char *ssl_cacertdir
= nullptr;
540 "%s| %s: DEBUG: Enable server certificate check for ldap server.\n",
542 val
= LDAP_OPT_X_TLS_DEMAND
;
543 rc
= ldap_set_option(nullptr, LDAP_OPT_X_TLS_REQUIRE_CERT
, &val
);
544 if (rc
!= LDAP_SUCCESS
) {
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
));
550 ssl_cacertfile
= xstrdup(getenv("TLS_CACERTFILE"));
551 if (!ssl_cacertfile
) {
552 ssl_cacertfile
= xstrdup("/etc/ssl/certs/cert.pem");
554 if (access(ssl_cacertfile
, R_OK
) == 0) {
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
);
558 rc
= ldap_set_option(nullptr, LDAP_OPT_X_TLS_CACERTFILE
,
560 xfree(ssl_cacertfile
);
561 if (rc
!= LDAP_OPT_SUCCESS
) {
563 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n",
564 LogTime(), PROGRAM
, ldap_err2string(rc
));
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");
576 if (access(ssl_cacertdir
, R_OK
) == 0) {
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
);
580 rc
= ldap_set_option(nullptr, LDAP_OPT_X_TLS_CACERTDIR
,
582 xfree(ssl_cacertdir
);
583 if (rc
!= LDAP_OPT_SUCCESS
) {
585 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTDIR for ldap server: %s\n",
586 LogTime(), PROGRAM
, ldap_err2string(rc
));
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
);
599 "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
601 val
= LDAP_OPT_X_TLS_ALLOW
;
602 rc
= ldap_set_option(nullptr, LDAP_OPT_X_TLS_REQUIRE_CERT
, &val
);
603 if (rc
!= LDAP_SUCCESS
) {
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
));
610 #elif HAVE_LDAPSSL_CLIENT_INIT
612 * Solaris SSL ldap calls require path to certificate database
615 * rc = ldapssl_client_init( ssl_certdbpath, nullptr);
616 * rc = ldapssl_advclientauth_init( ssl_certdbpath, nullptr, 0 , nullptr, nullptr, 0, nullptr, 2);
618 ssl_certdbpath
= getenv("SSL_CERTDBPATH");
619 if (!ssl_certdbpath
) {
620 ssl_certdbpath
= xstrdup("/etc/certs");
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
);
625 if (!margs
->rc_allow
) {
626 rc
= ldapssl_advclientauth_init(ssl_certdbpath
, nullptr, 0, nullptr, nullptr, 0,
629 rc
= ldapssl_advclientauth_init(ssl_certdbpath
, nullptr, 0, nullptr, nullptr, 0,
632 "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
635 xfree(ssl_certdbpath
);
636 if (rc
!= LDAP_SUCCESS
) {
638 "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
639 LogTime(), PROGRAM
, ldapssl_err2string(rc
));
644 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
651 get_attributes(LDAP
* ld
, LDAPMessage
* res
, const char *attribute
,
655 char **attr_value
= *ret_value
;
659 * loop over attributes
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
)) {
666 switch (ldap_msgtype(msg
)) {
668 case LDAP_RES_SEARCH_ENTRY
: {
669 BerElement
*b
= nullptr;
670 for (char *attr
= ldap_first_attribute(ld
, msg
, &b
); attr
;
671 attr
= ldap_next_attribute(ld
, msg
, b
)) {
672 if (strcasecmp(attr
, attribute
) == 0) {
673 struct berval
**values
;
676 ldap_get_values_len(ld
, msg
, attr
)) != nullptr) {
677 for (int il
= 0; values
[il
] != nullptr; ++il
) {
680 (char **) xrealloc(attr_value
,
681 (max_attr
+ 1) * sizeof(char *));
685 attr_value
[max_attr
] =
686 (char *) xmalloc(values
[il
]->bv_len
+ 1);
687 memcpy(attr_value
[max_attr
], values
[il
]->bv_val
,
689 attr_value
[max_attr
][values
[il
]->bv_len
] = 0;
693 ber_bvecfree(values
);
700 case LDAP_RES_SEARCH_REFERENCE
:
702 "%s| %s: DEBUG: Received a search reference message\n",
705 case LDAP_RES_SEARCH_RESULT
:
706 debug((char *) "%s| %s: DEBUG: Received a search result message\n",
714 debug((char *) "%s| %s: DEBUG: %zu ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM
,
715 max_attr
, max_attr
> 1 || max_attr
== 0 ? "ies" : "y", attribute
);
717 *ret_value
= attr_value
;
722 get_bin_attributes(LDAP
* ld
, LDAPMessage
* res
, const char *attribute
,
723 char ***ret_value
, int **ret_len
)
726 char **attr_value
= *ret_value
;
727 int *attr_len
= *ret_len
;
731 * loop over attributes
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
)) {
738 switch (ldap_msgtype(msg
)) {
740 case LDAP_RES_SEARCH_ENTRY
: {
741 BerElement
*b
= nullptr;
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
;
748 ldap_get_values_len(ld
, msg
, attr
)) != nullptr) {
749 for (int il
= 0; values
[il
] != nullptr; ++il
) {
752 (char **) xrealloc(attr_value
,
753 (max_attr
+ 1) * sizeof(char *));
758 (int *) xrealloc(attr_len
,
759 (max_attr
+ 1) * sizeof(int));
763 attr_value
[max_attr
] =
764 (char *) xmalloc(values
[il
]->bv_len
+ 1);
765 memcpy(attr_value
[max_attr
], values
[il
]->bv_val
,
767 attr_value
[max_attr
][values
[il
]->bv_len
] = 0;
768 attr_len
[max_attr
] = values
[il
]->bv_len
;
772 ber_bvecfree(values
);
779 case LDAP_RES_SEARCH_REFERENCE
:
781 "%s| %s: DEBUG: Received a search reference message\n",
784 case LDAP_RES_SEARCH_RESULT
:
785 debug((char *) "%s| %s: DEBUG: Received a search result message\n",
793 debug((char *) "%s| %s: DEBUG: %zu ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM
,
794 max_attr
, max_attr
> 1 || max_attr
== 0 ? "ies" : "y", attribute
);
796 *ret_value
= attr_value
;
802 * call to open ldap server with or without SSL
805 tool_ldap_open(struct main_args
* margs
, char *host
, int port
, char *ssl
)
809 LDAPURLDesc
*url
= nullptr;
810 char *ldapuri
= nullptr;
815 * Use ldap open here to check if TCP connection is possible. If possible use it.
816 * (Not sure if this is the best way)
819 url
= (LDAPURLDesc
*) xmalloc(sizeof(*url
));
820 memset(url
, 0, sizeof(*url
));
821 #if HAVE_LDAP_URL_LUD_SCHEME
823 url
->lud_scheme
= xstrdup("ldaps");
825 url
->lud_scheme
= xstrdup("ldap");
827 url
->lud_host
= xstrdup(host
);
828 url
->lud_port
= port
;
829 #if HAVE_LDAP_SCOPE_DEFAULT
830 url
->lud_scope
= LDAP_SCOPE_DEFAULT
;
832 url
->lud_scope
= LDAP_SCOPE_SUBTREE
;
834 #if HAVE_LDAP_URL_DESC2STR
835 ldapuri
= ldap_url_desc2str(url
);
836 #elif HAVE_LDAP_URL_PARSE
837 rc
= ldap_url_parse(ldapuri
, &url
);
838 if (rc
!= LDAP_SUCCESS
) {
839 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
840 LogTime(), PROGRAM
, ldap_err2string(rc
));
842 ldap_free_urldesc(url
);
846 #error "No URL parsing function"
848 ldap_free_urldesc(url
);
849 rc
= ldap_initialize(&ld
, ldapuri
);
851 if (rc
!= LDAP_SUCCESS
) {
853 "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
854 LogTime(), PROGRAM
, ldap_err2string(rc
));
855 ldap_unbind_ext(ld
, nullptr, nullptr);
860 ld
= ldap_init(host
, port
);
862 rc
= ldap_set_defaults(ld
);
863 if (rc
!= LDAP_SUCCESS
) {
865 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
866 LogTime(), PROGRAM
, ldap_err2string(rc
));
867 ldap_unbind_ext(ld
, nullptr, nullptr);
873 * Try Start TLS first
875 debug((char *) "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM
);
876 rc
= ldap_set_ssl_defaults(margs
);
877 if (rc
!= LDAP_SUCCESS
) {
879 "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n",
880 LogTime(), PROGRAM
, ldap_err2string(rc
));
881 ldap_unbind_ext(ld
, nullptr, nullptr);
887 * Use tls if possible
889 rc
= ldap_start_tls_s(ld
, nullptr, nullptr);
890 if (rc
!= LDAP_SUCCESS
) {
892 "%s| %s: WARNING: Error while setting start_tls for ldap server: %s\n",
893 LogTime(), PROGRAM
, ldap_err2string(rc
));
894 ldap_unbind_ext(ld
, nullptr, nullptr);
896 url
= (LDAPURLDesc
*) xmalloc(sizeof(*url
));
897 memset(url
, 0, sizeof(*url
));
898 #if HAVE_LDAP_URL_LUD_SCHEME
899 url
->lud_scheme
= xstrdup("ldaps");
901 url
->lud_host
= xstrdup(host
);
902 url
->lud_port
= port
;
903 #if HAVE_LDAP_SCOPE_DEFAULT
904 url
->lud_scope
= LDAP_SCOPE_DEFAULT
;
906 url
->lud_scope
= LDAP_SCOPE_SUBTREE
;
908 #if HAVE_LDAP_URL_DESC2STR
909 ldapuri
= ldap_url_desc2str(url
);
910 #elif HAVE_LDAP_URL_PARSE
911 rc
= ldap_url_parse(ldapuri
, &url
);
912 if (rc
!= LDAP_SUCCESS
) {
913 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
914 LogTime(), PROGRAM
, ldap_err2string(rc
));
916 ldap_free_urldesc(url
);
920 #error "No URL parsing function"
922 ldap_free_urldesc(url
);
923 rc
= ldap_initialize(&ld
, ldapuri
);
925 if (rc
!= LDAP_SUCCESS
) {
927 "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
928 LogTime(), PROGRAM
, ldap_err2string(rc
));
929 ldap_unbind_ext(ld
, nullptr, nullptr);
933 rc
= ldap_set_defaults(ld
);
934 if (rc
!= LDAP_SUCCESS
) {
936 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
937 LogTime(), PROGRAM
, ldap_err2string(rc
));
938 ldap_unbind_ext(ld
, nullptr, nullptr);
943 #elif HAVE_LDAPSSL_CLIENT_INIT
944 ld
= ldapssl_init(host
, port
, 1);
947 "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
948 LogTime(), PROGRAM
, ldapssl_err2string(rc
));
949 ldap_unbind_ext(ld
, nullptr, nullptr);
953 rc
= ldap_set_defaults(ld
);
954 if (rc
!= LDAP_SUCCESS
) {
956 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
957 LogTime(), PROGRAM
, ldap_err2string(rc
));
958 ldap_unbind_ext(ld
, nullptr, nullptr);
963 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
971 * ldap calls to get attribute from Ldap Directory Server
974 get_memberof(struct main_args
*margs
, char *user
, char *domain
, char *group
)
978 #if !HAVE_SUN_LDAP_SDK
981 struct ldap_creds
*lcreds
= nullptr;
982 char *bindp
= nullptr;
983 char *filter
= nullptr;
986 struct timeval searchtime
;
989 char **attr_value
= nullptr;
991 struct hstruct
*hlist
= nullptr;
993 char *ldap_filter_esc
= nullptr;
995 searchtime
.tv_sec
= SEARCH_TIMEOUT
;
996 searchtime
.tv_usec
= 0;
998 * Fill Kerberos memory cache with credential from keytab for SASL/GSSAPI
1001 debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n",
1002 LogTime(), PROGRAM
);
1005 if (margs
->nokerberos
) {
1008 "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n",
1009 LogTime(), PROGRAM
);
1011 kc
= krb5_create_cache(domain
, margs
->principal
);
1014 "%s| %s: ERROR: Error during setup of Kerberos credential cache\n",
1015 LogTime(), PROGRAM
);
1021 "%s| %s: DEBUG: Kerberos is not supported. Use username/password with ldap url instead\n",
1022 LogTime(), PROGRAM
);
1026 if (kc
&& (!margs
->lurl
|| !margs
->luser
|| !margs
->lpass
)) {
1028 * If Kerberos fails and no url given exit here
1033 #if !HAVE_SUN_LDAP_SDK
1037 // ldap_debug = 127 /* LDAP_DEBUG_TRACE */ ;
1038 // ldap_debug = -1 /* LDAP_DEBUG_ANY */ ;
1040 (void) ldap_set_option(nullptr, LDAP_OPT_DEBUG_LEVEL
, &ldap_debug
);
1042 debug((char *) "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(),
1045 if (domain
&& !kc
) {
1047 debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n",
1048 LogTime(), PROGRAM
);
1051 "%s| %s: DEBUG: Canonicalise ldap server name for domain %s\n",
1052 LogTime(), PROGRAM
, domain
);
1054 * Loop over list of ldap servers of users domain
1056 nhosts
= get_ldap_hostname_list(margs
, &hlist
, 0, domain
);
1057 for (size_t i
= 0; i
< nhosts
; ++i
) {
1059 if (hlist
[i
].port
!= -1)
1060 port
= hlist
[i
].port
;
1062 "%s| %s: DEBUG: Setting up connection to ldap server %s:%d\n",
1063 LogTime(), PROGRAM
, hlist
[i
].host
, port
);
1065 ld
= tool_ldap_open(margs
, hlist
[i
].host
, port
, margs
->ssl
);
1070 * ldap bind with SASL/GSSAPI authentication (only possible if a domain was part of the username)
1073 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
1075 "%s| %s: DEBUG: Bind to ldap server with SASL/GSSAPI\n",
1076 LogTime(), PROGRAM
);
1078 rc
= tool_sasl_bind(ld
, bindp
, margs
->ssl
);
1079 if (rc
!= LDAP_SUCCESS
) {
1081 "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n",
1082 LogTime(), PROGRAM
, ldap_err2string(rc
));
1083 ldap_unbind_ext(ld
, nullptr, nullptr);
1087 lcreds
= (struct ldap_creds
*) xmalloc(sizeof(struct ldap_creds
));
1088 lcreds
->dn
= nullptr;
1089 lcreds
->pw
= margs
->ssl
? xstrdup(margs
->ssl
) : nullptr;
1090 ldap_set_rebind_proc(ld
, ldap_sasl_rebind
, (char *) lcreds
);
1091 if (ld
!= nullptr) {
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
);
1099 ldap_unbind_ext(ld
, nullptr, nullptr);
1101 error((char *) "%s| %s: ERROR: SASL not supported on system\n",
1102 LogTime(), PROGRAM
);
1106 nhosts
= free_hostname_list(&hlist
, nhosts
);
1107 if (ld
== nullptr) {
1109 "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n",
1110 LogTime(), PROGRAM
, strerror(errno
));
1113 bindp
= xstrdup(margs
->lbind
);
1115 bindp
= convert_domain_to_bind_path(domain
);
1118 if ((!domain
|| !ld
) && margs
->lurl
&& strstr(margs
->lurl
, "://")) {
1122 char *ssl
= nullptr;
1125 * If username does not contain a domain and a url was given then try it
1127 hostname
= strstr(margs
->lurl
, "://") + 3;
1128 ssl
= strstr(margs
->lurl
, "ldaps://");
1130 debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n",
1131 LogTime(), PROGRAM
);
1133 debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name %s\n",
1134 LogTime(), PROGRAM
, hostname
);
1136 * Loop over list of ldap servers
1138 host
= xstrdup(hostname
);
1140 if ((p
= strchr(host
, ':'))) {
1145 nhosts
= get_hostname_list(&hlist
, 0, host
);
1147 for (size_t i
= 0; i
< nhosts
; ++i
) {
1150 cred
.bv_val
= margs
->lpass
;
1151 cred
.bv_len
= strlen(margs
->lpass
);
1153 ld
= tool_ldap_open(margs
, hlist
[i
].host
, port
, ssl
);
1157 * ldap bind with username/password authentication
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
,
1164 nullptr, nullptr, nullptr);
1165 if (rc
!= LDAP_SUCCESS
) {
1167 "%s| %s: ERROR: Error while binding to ldap server with Username/Password: %s\n",
1168 LogTime(), PROGRAM
, ldap_err2string(rc
));
1169 ldap_unbind_ext(ld
, nullptr, nullptr);
1173 lcreds
= (struct ldap_creds
*) xmalloc(sizeof(struct ldap_creds
));
1174 lcreds
->dn
= xstrdup(margs
->luser
);
1175 lcreds
->pw
= xstrdup(margs
->lpass
);
1176 ldap_set_rebind_proc(ld
, ldap_simple_rebind
, (char *) lcreds
);
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
);
1184 nhosts
= free_hostname_list(&hlist
, nhosts
);
1187 bindp
= xstrdup(margs
->lbind
);
1189 bindp
= convert_domain_to_bind_path(domain
);
1192 if (ld
== nullptr) {
1194 "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n",
1195 LogTime(), PROGRAM
, strerror(errno
));
1200 * ldap search for user
1203 * Check if server is AD by querying for attribute samaccountname
1206 rc
= check_AD(margs
, ld
);
1207 if (rc
!= LDAP_SUCCESS
) {
1209 "%s| %s: ERROR: Error determining ldap server type: %s\n",
1210 LogTime(), PROGRAM
, ldap_err2string(rc
));
1211 ldap_unbind_ext(ld
, nullptr, nullptr);
1217 filter
= (char *) FILTER_AD
;
1219 filter
= (char *) FILTER
;
1221 ldap_filter_esc
= escape_filter(user
);
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
);
1227 xfree(ldap_filter_esc
);
1230 "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n",
1231 LogTime(), PROGRAM
, bindp
, search_exp
);
1232 rc
= ldap_search_ext_s(ld
, bindp
, LDAP_SCOPE_SUBTREE
, search_exp
, nullptr, 0,
1233 nullptr, nullptr, &searchtime
, 0, &res
);
1236 if (rc
!= LDAP_SUCCESS
) {
1237 error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n",
1238 LogTime(), PROGRAM
, ldap_err2string(rc
));
1239 ldap_unbind_ext(ld
, nullptr, nullptr);
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");
1248 if (ldap_count_entries(ld
, res
) != 0) {
1251 max_attr
= get_attributes(ld
, res
, ATTRIBUTE_AD
, &attr_value
);
1253 max_attr
= get_attributes(ld
, res
, ATTRIBUTE
, &attr_value
);
1257 * Compare group names
1260 for (size_t k
= 0; k
< max_attr
; ++k
) {
1263 /* Compare first CN= value assuming it is the same as the group name itself */
1265 if (!strncasecmp("CN=", av
, 3)) {
1266 char *avp
= nullptr;
1268 if ((avp
= strchr(av
, ','))) {
1272 if (debug_enabled
) {
1273 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM
, k
+ 1, av
);
1274 for (unsigned int n
= 0; av
[n
] != '\0'; ++n
)
1275 fprintf(stderr
, "%02x", (unsigned char) av
[n
]);
1276 fprintf(stderr
, "\n");
1278 if (!strcasecmp(group
, av
)) {
1281 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" matches group name \"%s\"\n", LogTime(),
1282 PROGRAM
, k
+ 1, av
, group
);
1286 debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" does not match group name \"%s\"\n", LogTime(),
1287 PROGRAM
, k
+ 1, av
, group
);
1290 * Do recursive group search for AD only since posixgroups can not contain other groups
1292 if (!retval
&& margs
->AD
) {
1293 if (debug_enabled
&& max_attr
> 0) {
1295 "%s| %s: DEBUG: Perform recursive group search\n",
1296 LogTime(), PROGRAM
);
1298 for (size_t j
= 0; j
< max_attr
; ++j
) {
1302 if (search_group_tree(margs
, ld
, bindp
, av
, group
, 1)) {
1304 if (!strncasecmp("CN=", av
, 3)) {
1305 char *avp
= nullptr;
1307 if ((avp
= strchr(av
, ','))) {
1312 debug((char *) "%s| %s: DEBUG: Entry %zu group \"%s\" is (in)direct member of group \"%s\"\n",
1313 LogTime(), PROGRAM
, j
+ 1, av
, group
);
1323 for (size_t j
= 0; j
< max_attr
; ++j
) {
1324 xfree(attr_value
[j
]);
1326 safe_free(attr_value
);
1329 } else if (ldap_count_entries(ld
, res
) == 0 && margs
->AD
) {
1331 ldap_unbind_ext(ld
, nullptr, nullptr);
1342 * Check for primary Group membership
1345 "%s| %s: DEBUG: Search for primary group membership: \"%s\"\n",
1346 LogTime(), PROGRAM
, group
);
1348 filter
= (char *) FILTER_AD
;
1350 filter
= (char *) FILTER_UID
;
1352 ldap_filter_esc
= escape_filter(user
);
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
);
1358 xfree(ldap_filter_esc
);
1361 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1362 LogTime(), PROGRAM
, bindp
, search_exp
);
1363 rc
= ldap_search_ext_s(ld
, bindp
, LDAP_SCOPE_SUBTREE
, search_exp
, nullptr,
1364 0, nullptr, nullptr, &searchtime
, 0, &res
);
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");
1375 get_attributes(ld
, res
, ATTRIBUTE_GID_AD
, &attr_value
);
1377 max_attr
= get_attributes(ld
, res
, ATTRIBUTE_GID
, &attr_value
);
1380 if (max_attr
== 1) {
1381 char **attr_value_2
= nullptr;
1382 size_t max_attr_2
= 0;
1385 char **attr_value_3
= nullptr;
1386 int *attr_len_3
= nullptr;
1387 size_t max_attr_3
= 0;
1388 uint32_t gid
= atoi(attr_value
[0]);
1390 /* Get objectsid and search for group
1391 * with objectsid = domain(objectsid) + primarygroupid */
1392 debug((char *) "%s| %s: DEBUG: Got primaryGroupID %u\n",
1393 LogTime(), PROGRAM
, gid
);
1395 get_bin_attributes(ld
, res
, ATTRIBUTE_SID
, &attr_value_3
,
1398 if (max_attr_3
== 1) {
1399 int len
= attr_len_3
[0];
1402 "%s| %s: ERROR: Length %d is too short for objectSID\n",
1403 LogTime(), PROGRAM
, len
);
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);
1412 #define FILTER_SID_1 "(objectSID="
1413 #define FILTER_SID_2 ")"
1416 strlen(FILTER_SID_1
) + len
* 3 +
1417 strlen(FILTER_SID_2
) + 1;
1418 search_exp
= (char *) xmalloc(se_len
);
1419 snprintf(search_exp
, se_len
, "%s", FILTER_SID_1
);
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);
1427 se
= xstrdup(search_exp
);
1428 snprintf(search_exp
, se_len
, "%s%s", se
, FILTER_SID_2
);
1432 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1433 LogTime(), PROGRAM
, bindp
, search_exp
);
1434 rc
= ldap_search_ext_s(ld
, bindp
, LDAP_SCOPE_SUBTREE
,
1435 search_exp
, nullptr, 0, nullptr, nullptr, &searchtime
, 0,
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");
1450 for (j
= 0; j
< max_attr_3
; ++j
) {
1451 xfree(attr_value_3
[j
]);
1453 safe_free(attr_value_3
);
1460 filter
= (char *) FILTER_GID
;
1462 ldap_filter_esc
= escape_filter(attr_value
[0]);
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
);
1468 xfree(ldap_filter_esc
);
1471 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1472 LogTime(), PROGRAM
, bindp
, search_exp
);
1473 rc
= ldap_search_ext_s(ld
, bindp
, LDAP_SCOPE_SUBTREE
,
1474 search_exp
, nullptr, 0, nullptr, nullptr, &searchtime
, 0, &res
);
1481 get_attributes(ld
, res
, ATTRIBUTE_DN
, &attr_value_2
);
1484 get_attributes(ld
, res
, ATTRIBUTE
, &attr_value_2
);
1490 * Compare group names
1493 if (max_attr_2
== 1) {
1494 /* Compare first CN= value assuming it is the same as the group name itself */
1495 char *av
= attr_value_2
[0];
1496 if (!strncasecmp("CN=", av
, 3)) {
1497 char *avp
= nullptr;
1499 if ((avp
= strchr(av
, ','))) {
1503 if (!strcasecmp(group
, av
)) {
1506 "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n",
1507 LogTime(), PROGRAM
, av
, group
);
1510 "%s| %s: DEBUG: \"%s\" does not match group name \"%s\"\n",
1511 LogTime(), PROGRAM
, av
, group
);
1515 * Do recursive group search for AD only since posixgroups can not contain other groups
1517 if (!retval
&& margs
->AD
) {
1518 if (debug_enabled
&& max_attr_2
> 0) {
1520 "%s| %s: DEBUG: Perform recursive group search\n",
1521 LogTime(), PROGRAM
);
1523 for (size_t j
= 0; j
< max_attr_2
; ++j
) {
1526 av
= attr_value_2
[j
];
1527 if (search_group_tree(margs
, ld
, bindp
, av
, group
, 1)) {
1529 if (!strncasecmp("CN=", av
, 3)) {
1530 char *avp
= nullptr;
1532 if ((avp
= strchr(av
, ','))) {
1536 if (debug_enabled
) {
1537 debug((char *) "%s| %s: DEBUG: Entry %zu group \"%s\" is (in)direct member of group \"%s\"\n",
1538 LogTime(), PROGRAM
, j
+ 1, av
, group
);
1550 for (j
= 0; j
< max_attr_2
; ++j
) {
1551 xfree(attr_value_2
[j
]);
1553 safe_free(attr_value_2
);
1556 debug((char *) "%s| %s: DEBUG: Users primary group %s %s\n",
1557 LogTime(), PROGRAM
, retval
? "matches" : "does not match",
1563 "%s| %s: DEBUG: Did not find ldap entry for group %s\n",
1564 LogTime(), PROGRAM
, group
);
1570 for (size_t j
= 0; j
< max_attr
; ++j
) {
1571 xfree(attr_value
[j
]);
1573 safe_free(attr_value
);
1576 rc
= ldap_unbind_ext(ld
, nullptr, nullptr);
1578 if (rc
!= LDAP_SUCCESS
) {
1579 error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n",
1580 LogTime(), PROGRAM
, ldap_err2string(rc
));
1582 debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM
);