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