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