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