]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/external_acl/kerberos_ldap_group/support_ldap.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / external_acl / kerberos_ldap_group / support_ldap.cc
CommitLineData
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
55char *convert_domain_to_bind_path(char *domain);
56char *escape_filter(char *filter);
57int check_AD(struct main_args *margs, LDAP * ld);
4ebcf1ce 58int ldap_set_defaults(LDAP * ld);
b1218840
AJ
59int ldap_set_ssl_defaults(struct main_args *margs);
60LDAP *tool_ldap_open(struct main_args *margs, char *host, int port, char *ssl);
61
62#define CONNECT_TIMEOUT 2
63#define SEARCH_TIMEOUT 30
64
65#define FILTER "(memberuid=%s)"
66#define ATTRIBUTE "cn"
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 77size_t get_attributes(LDAP * ld, LDAPMessage * res, const char *attribute /* IN */ , char ***out_val /* OUT (caller frees) */ );
1a22a39e 78size_t get_bin_attributes(LDAP * ld, LDAPMessage * res, const char *attribute /* IN */ , char ***out_val , int **out_len /* OUT (caller frees) */ );
b1218840
AJ
79int 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
85static LDAP_REBINDPROC_CALLBACK ldap_sasl_rebind;
86
87static int LDAP_CALL LDAP_CALLBACK
88ldap_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
105static LDAP_REBINDPROC_CALLBACK ldap_simple_rebind;
106
107static int LDAP_CALL LDAP_CALLBACK
108ldap_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
125static LDAP_REBIND_PROC ldap_sasl_rebind;
126
127static int
128ldap_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
140static LDAP_REBIND_PROC ldap_simple_rebind;
141
142static int
143ldap_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
159static LDAP_REBIND_FUNCTION ldap_sasl_rebind;
160
161static int
162ldap_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
179static LDAP_REBIND_FUNCTION ldap_simple_rebind;
180
181static int
182ldap_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
202static LDAP_REBIND_PROC ldap_sasl_rebind;
203
204static int
ced8def3 205ldap_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
212static LDAP_REBIND_PROC ldap_simple_rebind;
213
214static int
ced8def3 215ldap_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
223char *
224convert_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
257char *
258escape_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
297int
298check_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}
344int
345search_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
465int
4ebcf1ce 466ldap_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
495int
496ldap_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
572size_t
573get_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
631size_t
632get_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 */
700LDAP *
701tool_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 */
850int
851get_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 1372cleanup:
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