]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/external/kerberos_ldap_group/support_ldap.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / acl / external / kerberos_ldap_group / support_ldap.cc
1 /*
2 * Copyright (C) 1996-2021 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
55 char *convert_domain_to_bind_path(char *domain);
56 char *escape_filter(char *filter);
57 int check_AD(struct main_args *margs, LDAP * ld);
58 int ldap_set_defaults(LDAP * ld);
59 int ldap_set_ssl_defaults(struct main_args *margs);
60 LDAP *tool_ldap_open(struct main_args *margs, char *host, int port, char *ssl);
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
77 size_t get_attributes(LDAP * ld, LDAPMessage * res,
78 const char *attribute /* IN */, char ***out_val /* OUT (caller frees) */ );
79 size_t get_bin_attributes(LDAP * ld, LDAPMessage * res,
80 const char *attribute /* IN */, char ***out_val,
81 int **out_len /* OUT (caller frees) */ );
82 int search_group_tree(struct main_args *margs, LDAP * ld, char *bindp,
83 char *ldap_group, char *group, int depth);
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 || HAVE_SASL_DARWIN
89 static LDAP_REBINDPROC_CALLBACK ldap_sasl_rebind;
90
91 static int LDAP_CALL LDAP_CALLBACK
92 ldap_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
104 static LDAP_REBINDPROC_CALLBACK ldap_simple_rebind;
105
106 static int LDAP_CALL LDAP_CALLBACK
107 ldap_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, NULL, NULL,
121 NULL);
122 }
123 #elif HAVE_LDAP_REBIND_PROC
124 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
125 static LDAP_REBIND_PROC ldap_sasl_rebind;
126
127 static int
128 ldap_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
135
136 static LDAP_REBIND_PROC ldap_simple_rebind;
137
138 static int
139 ldap_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, NULL, NULL,
149 NULL);
150 }
151
152 #elif HAVE_LDAP_REBIND_FUNCTION
153 #ifndef LDAP_REFERRALS
154 #define LDAP_REFERRALS
155 #endif
156 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
157 static LDAP_REBIND_FUNCTION ldap_sasl_rebind;
158
159 static int
160 ldap_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
172 static LDAP_REBIND_FUNCTION ldap_simple_rebind;
173
174 static int
175 ldap_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, NULL, NULL,
189 NULL);
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 || HAVE_SASL_DARWIN
196 static LDAP_REBIND_PROC ldap_sasl_rebind;
197
198 static int
199 ldap_sasl_rebind(LDAP * ld, LDAP_CONST char *, ber_tag_t request,
200 ber_int_t msgid, 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
207 static LDAP_REBIND_PROC ldap_simple_rebind;
208
209 static int
210 ldap_simple_rebind(LDAP * ld, LDAP_CONST char *, ber_tag_t request,
211 ber_int_t msgid, 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, NULL, NULL,
221 NULL);
222 }
223
224 #endif
225 char *
226 convert_domain_to_bind_path(char *domain)
227 {
228 char *dp, *bindp = NULL, *bp = NULL;
229 size_t i = 0;
230
231 if (!domain)
232 return NULL;
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
259 char *
260 escape_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
298 int
299 check_AD(struct main_args *margs, LDAP * ld)
300 {
301 LDAPMessage *res;
302 char **attr_value = NULL;
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, NULL, 0, NULL, NULL, &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 debug((char *)
326 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
327 LogTime(), PROGRAM, attr_value[0], FILTER_SAM);
328 rc = ldap_search_ext_s(ld, attr_value[0], LDAP_SCOPE_SUBTREE,
329 (char *) FILTER_SAM, NULL, 0, NULL, NULL, &searchtime, 0, &res);
330 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(),
331 PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld,
332 res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
333 if (ldap_count_entries(ld, res) > 0)
334 margs->AD = 1;
335 } else
336 debug((char *)
337 "%s| %s: DEBUG: Did not find ldap entry for subschemasubentry\n",
338 LogTime(), PROGRAM);
339 debug((char *)
340 "%s| %s: DEBUG: Determined ldap server %sas an Active Directory server\n",
341 LogTime(), PROGRAM, margs->AD ? "" : "not ");
342 /*
343 * Cleanup
344 */
345 if (attr_value) {
346 size_t j;
347 for (j = 0; j < max_attr; ++j) {
348 xfree(attr_value[j]);
349 }
350 safe_free(attr_value);
351 }
352 ldap_msgfree(res);
353 return rc;
354 }
355
356 int
357 search_group_tree(struct main_args *margs, LDAP * ld, char *bindp,
358 char *ldap_group, char *group, int depth)
359 {
360 LDAPMessage *res = NULL;
361 char **attr_value = NULL;
362 size_t max_attr = 0;
363 char *filter = NULL;
364 char *search_exp = NULL;
365 size_t se_len = 0;
366 int rc = 0, retval = 0;
367 int ldepth;
368 char *ldap_filter_esc = NULL;
369 struct timeval searchtime;
370
371 #define FILTER_GROUP_AD "(&(%s)(objectclass=group))"
372 #define FILTER_GROUP "(&(memberuid=%s)(objectclass=posixgroup))"
373
374 searchtime.tv_sec = SEARCH_TIMEOUT;
375 searchtime.tv_usec = 0;
376
377 if (margs->AD)
378 filter = (char *) FILTER_GROUP_AD;
379 else
380 filter = (char *) FILTER_GROUP;
381
382 ldap_filter_esc = escape_filter(ldap_group);
383
384 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
385 search_exp = (char *) xmalloc(se_len);
386 snprintf(search_exp, se_len, filter, ldap_filter_esc);
387
388 xfree(ldap_filter_esc);
389
390 if (depth > margs->mdepth) {
391 debug((char *) "%s| %s: DEBUG: Max search depth reached %d>%d\n",
392 LogTime(), PROGRAM, depth, margs->mdepth);
393 xfree(search_exp);
394 return 0;
395 }
396 debug((char *)
397 "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n",
398 LogTime(), PROGRAM, bindp, search_exp);
399 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE, search_exp, NULL, 0,
400 NULL, NULL, &searchtime, 0, &res);
401 xfree(search_exp);
402
403 if (rc != LDAP_SUCCESS) {
404 error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n",
405 LogTime(), PROGRAM, ldap_err2string(rc));
406 return 0;
407 }
408 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM,
409 ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1
410 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
411
412 if (margs->AD)
413 max_attr = get_attributes(ld, res, ATTRIBUTE_AD, &attr_value);
414 else
415 max_attr = get_attributes(ld, res, ATTRIBUTE, &attr_value);
416
417 /*
418 * Compare group names
419 */
420 retval = 0;
421 ldepth = depth + 1;
422 for (size_t j = 0; j < max_attr; ++j) {
423 char *av = NULL;
424
425 /* Compare first CN= value assuming it is the same as the group name itself */
426 av = attr_value[j];
427 if (!strncasecmp("CN=", av, 3)) {
428 char *avp = NULL;
429 av += 3;
430 if ((avp = strchr(av, ','))) {
431 *avp = '\0';
432 }
433 }
434 if (debug_enabled) {
435 int n;
436 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
437 " \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, j + 1, av);
438 for (n = 0; av[n] != '\0'; ++n)
439 fprintf(stderr, "%02x", (unsigned char) av[n]);
440 fprintf(stderr, "\n");
441 }
442 if (!strcasecmp(group, av)) {
443 retval = 1;
444 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
445 " \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM,
446 j + 1, av, group);
447 break;
448 } else
449 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
450 " \"%s\" does not match group name \"%s\"\n", LogTime(),
451 PROGRAM, j + 1, av, group);
452 /*
453 * Do recursive group search
454 */
455 debug((char *)
456 "%s| %s: DEBUG: Perform recursive group search for group \"%s\"\n",
457 LogTime(), PROGRAM, av);
458 av = attr_value[j];
459 if (search_group_tree(margs, ld, bindp, av, group, ldepth)) {
460 retval = 1;
461 if (!strncasecmp("CN=", av, 3)) {
462 char *avp = NULL;
463 av += 3;
464 if ((avp = strchr(av, ','))) {
465 *avp = '\0';
466 }
467 }
468 if (debug_enabled)
469 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
470 " \"%s\" is member of group named \"%s\"\n", LogTime(),
471 PROGRAM, j + 1, av, group);
472 else
473 break;
474
475 }
476 }
477
478 /*
479 * Cleanup
480 */
481 if (attr_value) {
482 for (size_t j = 0; j < max_attr; ++j) {
483 xfree(attr_value[j]);
484 }
485 safe_free(attr_value);
486 }
487 ldap_msgfree(res);
488
489 return retval;
490 }
491
492 int
493 ldap_set_defaults(LDAP * ld)
494 {
495 int val, rc = 0;
496 #if LDAP_OPT_NETWORK_TIMEOUT
497 struct timeval tv;
498 #endif
499 val = LDAP_VERSION3;
500 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &val);
501 if (rc != LDAP_SUCCESS) {
502 debug((char *)
503 "%s| %s: DEBUG: Error while setting protocol version: %s\n",
504 LogTime(), PROGRAM, ldap_err2string(rc));
505 return rc;
506 }
507 rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
508 if (rc != LDAP_SUCCESS) {
509 debug((char *) "%s| %s: DEBUG: Error while setting referrals off: %s\n",
510 LogTime(), PROGRAM, ldap_err2string(rc));
511 return rc;
512 }
513 #if LDAP_OPT_NETWORK_TIMEOUT
514 tv.tv_sec = CONNECT_TIMEOUT;
515 tv.tv_usec = 0;
516 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
517 if (rc != LDAP_SUCCESS) {
518 debug((char *)
519 "%s| %s: DEBUG: Error while setting network timeout: %s\n",
520 LogTime(), PROGRAM, ldap_err2string(rc));
521 return rc;
522 }
523 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
524 return LDAP_SUCCESS;
525 }
526
527 int
528 ldap_set_ssl_defaults(struct main_args *margs)
529 {
530 #if HAVE_OPENLDAP || HAVE_LDAPSSL_CLIENT_INIT
531 int rc = 0;
532 #endif
533 #if HAVE_OPENLDAP
534 int val;
535 #elif HAVE_LDAPSSL_CLIENT_INIT
536 char *ssl_certdbpath = NULL;
537 #endif
538
539 #if HAVE_OPENLDAP
540 if (!margs->rc_allow) {
541 char *ssl_cacertfile = NULL;
542 char *ssl_cacertdir = NULL;
543 debug((char *)
544 "%s| %s: DEBUG: Enable server certificate check for ldap server.\n",
545 LogTime(), PROGRAM);
546 val = LDAP_OPT_X_TLS_DEMAND;
547 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
548 if (rc != LDAP_SUCCESS) {
549 error((char *)
550 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT DEMAND for ldap server: %s\n",
551 LogTime(), PROGRAM, ldap_err2string(rc));
552 return rc;
553 }
554 ssl_cacertfile = xstrdup(getenv("TLS_CACERTFILE"));
555 if (!ssl_cacertfile) {
556 ssl_cacertfile = xstrdup("/etc/ssl/certs/cert.pem");
557 }
558 if (access(ssl_cacertfile, R_OK) == 0) {
559 debug((char *)
560 "%s| %s: DEBUG: Set certificate file for ldap server to %s. (Changeable through setting environment variable TLS_CACERTFILE)\n",
561 LogTime(), PROGRAM, ssl_cacertfile);
562 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
563 ssl_cacertfile);
564 xfree(ssl_cacertfile);
565 if (rc != LDAP_OPT_SUCCESS) {
566 error((char *)
567 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n",
568 LogTime(), PROGRAM, ldap_err2string(rc));
569 return rc;
570 }
571 } else {
572 debug((char *)
573 "%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",
574 LogTime(), PROGRAM, ssl_cacertfile, strerror(errno));
575 xfree(ssl_cacertfile);
576 ssl_cacertdir = xstrdup(getenv("TLS_CACERTDIR"));
577 if (!ssl_cacertdir) {
578 ssl_cacertdir = xstrdup("/etc/ssl/certs");
579 }
580 if (access(ssl_cacertdir, R_OK) == 0) {
581 debug((char *)
582 "%s| %s: DEBUG: Set certificate database path for ldap server to %s. (Changeable through setting environment variable TLS_CACERTDIR)\n",
583 LogTime(), PROGRAM, ssl_cacertdir);
584 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR,
585 ssl_cacertdir);
586 xfree(ssl_cacertdir);
587 if (rc != LDAP_OPT_SUCCESS) {
588 error((char *)
589 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTDIR for ldap server: %s\n",
590 LogTime(), PROGRAM, ldap_err2string(rc));
591 return rc;
592 }
593 } else {
594 debug((char *)
595 "%s| %s: DEBUG: Set certificate database path for ldap server to %s failed (%s). (Changeable through setting environment variable TLS_CACERTDIR)\n",
596 LogTime(), PROGRAM, ssl_cacertdir, strerror(errno));
597 xfree(ssl_cacertdir);
598 return errno;
599 }
600 }
601 } else {
602 debug((char *)
603 "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
604 LogTime(), PROGRAM);
605 val = LDAP_OPT_X_TLS_ALLOW;
606 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
607 if (rc != LDAP_SUCCESS) {
608 error((char *)
609 "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT ALLOW for ldap server: %s\n",
610 LogTime(), PROGRAM, ldap_err2string(rc));
611 return rc;
612 }
613 }
614 #elif HAVE_LDAPSSL_CLIENT_INIT
615 /*
616 * Solaris SSL ldap calls require path to certificate database
617 */
618 /*
619 * rc = ldapssl_client_init( ssl_certdbpath, NULL );
620 * rc = ldapssl_advclientauth_init( ssl_certdbpath, NULL , 0 , NULL, NULL, 0, NULL, 2);
621 */
622 ssl_certdbpath = getenv("SSL_CERTDBPATH");
623 if (!ssl_certdbpath) {
624 ssl_certdbpath = xstrdup("/etc/certs");
625 }
626 debug((char *)
627 "%s| %s: DEBUG: Set certificate database path for ldap server to %s. (Changeable through setting environment variable SSL_CERTDBPATH)\n",
628 LogTime(), PROGRAM, ssl_certdbpath);
629 if (!margs->rc_allow) {
630 rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0,
631 NULL, 2);
632 } else {
633 rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0,
634 NULL, 0);
635 debug((char *)
636 "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
637 LogTime(), PROGRAM);
638 }
639 xfree(ssl_certdbpath);
640 if (rc != LDAP_SUCCESS) {
641 error((char *)
642 "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
643 LogTime(), PROGRAM, ldapssl_err2string(rc));
644 return rc;
645 }
646 #else
647 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
648 LogTime(), PROGRAM);
649 #endif
650 return LDAP_SUCCESS;
651 }
652
653 size_t
654 get_attributes(LDAP * ld, LDAPMessage * res, const char *attribute,
655 char ***ret_value)
656 {
657
658 char **attr_value = *ret_value;
659 size_t max_attr = 0;
660
661 /*
662 * loop over attributes
663 */
664 debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n",
665 LogTime(), PROGRAM, attribute);
666 for (LDAPMessage * msg = ldap_first_entry(ld, res); msg;
667 msg = ldap_next_entry(ld, msg)) {
668
669 switch (ldap_msgtype(msg)) {
670
671 case LDAP_RES_SEARCH_ENTRY: {
672 BerElement *b = NULL;
673 for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
674 attr = ldap_next_attribute(ld, msg, b)) {
675 if (strcasecmp(attr, attribute) == 0) {
676 struct berval **values;
677
678 if ((values =
679 ldap_get_values_len(ld, msg, attr)) != NULL) {
680 for (int il = 0; values[il] != NULL; ++il) {
681
682 attr_value =
683 (char **) xrealloc(attr_value,
684 (max_attr + 1) * sizeof(char *));
685 if (!attr_value)
686 break;
687
688 attr_value[max_attr] =
689 (char *) xmalloc(values[il]->bv_len + 1);
690 memcpy(attr_value[max_attr], values[il]->bv_val,
691 values[il]->bv_len);
692 attr_value[max_attr][values[il]->bv_len] = 0;
693 max_attr++;
694 }
695 }
696 ber_bvecfree(values);
697 }
698 ldap_memfree(attr);
699 }
700 ber_free(b, 0);
701 }
702 break;
703 case LDAP_RES_SEARCH_REFERENCE:
704 debug((char *)
705 "%s| %s: DEBUG: Received a search reference message\n",
706 LogTime(), PROGRAM);
707 break;
708 case LDAP_RES_SEARCH_RESULT:
709 debug((char *) "%s| %s: DEBUG: Received a search result message\n",
710 LogTime(), PROGRAM);
711 break;
712 default:
713 break;
714 }
715 }
716
717 debug((char *) "%s| %s: DEBUG: %" PRIuSIZE
718 " ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM,
719 max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
720
721 *ret_value = attr_value;
722 return max_attr;
723 }
724
725 size_t
726 get_bin_attributes(LDAP * ld, LDAPMessage * res, const char *attribute,
727 char ***ret_value, int **ret_len)
728 {
729
730 char **attr_value = *ret_value;
731 int *attr_len = *ret_len;
732 size_t max_attr = 0;
733
734 /*
735 * loop over attributes
736 */
737 debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n",
738 LogTime(), PROGRAM, attribute);
739 for (LDAPMessage * msg = ldap_first_entry(ld, res); msg;
740 msg = ldap_next_entry(ld, msg)) {
741
742 switch (ldap_msgtype(msg)) {
743
744 case LDAP_RES_SEARCH_ENTRY: {
745 BerElement *b = NULL;
746 for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
747 attr = ldap_next_attribute(ld, msg, b)) {
748 if (strcasecmp(attr, attribute) == 0) {
749 struct berval **values;
750
751 if ((values =
752 ldap_get_values_len(ld, msg, attr)) != NULL) {
753 for (int il = 0; values[il] != NULL; ++il) {
754
755 attr_value =
756 (char **) xrealloc(attr_value,
757 (max_attr + 1) * sizeof(char *));
758 if (!attr_value)
759 break;
760
761 attr_len =
762 (int *) xrealloc(attr_len,
763 (max_attr + 1) * sizeof(int));
764 if (!attr_len)
765 break;
766
767 attr_value[max_attr] =
768 (char *) xmalloc(values[il]->bv_len + 1);
769 memcpy(attr_value[max_attr], values[il]->bv_val,
770 values[il]->bv_len);
771 attr_value[max_attr][values[il]->bv_len] = 0;
772 attr_len[max_attr] = values[il]->bv_len;
773 max_attr++;
774 }
775 }
776 ber_bvecfree(values);
777 }
778 ldap_memfree(attr);
779 }
780 ber_free(b, 0);
781 }
782 break;
783 case LDAP_RES_SEARCH_REFERENCE:
784 debug((char *)
785 "%s| %s: DEBUG: Received a search reference message\n",
786 LogTime(), PROGRAM);
787 break;
788 case LDAP_RES_SEARCH_RESULT:
789 debug((char *) "%s| %s: DEBUG: Received a search result message\n",
790 LogTime(), PROGRAM);
791 break;
792 default:
793 break;
794 }
795 }
796
797 debug((char *) "%s| %s: DEBUG: %" PRIuSIZE
798 " ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM,
799 max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
800
801 *ret_value = attr_value;
802 *ret_len = attr_len;
803 return max_attr;
804 }
805
806 /*
807 * call to open ldap server with or without SSL
808 */
809 LDAP *
810 tool_ldap_open(struct main_args * margs, char *host, int port, char *ssl)
811 {
812 LDAP *ld;
813 #if HAVE_OPENLDAP
814 LDAPURLDesc *url = NULL;
815 char *ldapuri = NULL;
816 #endif
817 int rc = 0;
818
819 /*
820 * Use ldap open here to check if TCP connection is possible. If possible use it.
821 * (Not sure if this is the best way)
822 */
823 #if HAVE_OPENLDAP
824 url = (LDAPURLDesc *) xmalloc(sizeof(*url));
825 memset(url, 0, sizeof(*url));
826 #if HAVE_LDAP_URL_LUD_SCHEME
827 if (ssl)
828 url->lud_scheme = xstrdup("ldaps");
829 else
830 url->lud_scheme = xstrdup("ldap");
831 #endif
832 url->lud_host = xstrdup(host);
833 url->lud_port = port;
834 #if HAVE_LDAP_SCOPE_DEFAULT
835 url->lud_scope = LDAP_SCOPE_DEFAULT;
836 #else
837 url->lud_scope = LDAP_SCOPE_SUBTREE;
838 #endif
839 #if HAVE_LDAP_URL_DESC2STR
840 ldapuri = ldap_url_desc2str(url);
841 #elif HAVE_LDAP_URL_PARSE
842 rc = ldap_url_parse(ldapuri, &url);
843 if (rc != LDAP_SUCCESS) {
844 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
845 LogTime(), PROGRAM, ldap_err2string(rc));
846 xfree(ldapuri);
847 ldap_free_urldesc(url);
848 return NULL;
849 }
850 #else
851 #error "No URL parsing function"
852 #endif
853 ldap_free_urldesc(url);
854 rc = ldap_initialize(&ld, ldapuri);
855 xfree(ldapuri);
856 if (rc != LDAP_SUCCESS) {
857 error((char *)
858 "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
859 LogTime(), PROGRAM, ldap_err2string(rc));
860 ldap_unbind_ext(ld, NULL, NULL);
861 ld = NULL;
862 return NULL;
863 }
864 #else
865 ld = ldap_init(host, port);
866 #endif
867 rc = ldap_set_defaults(ld);
868 if (rc != LDAP_SUCCESS) {
869 error((char *)
870 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
871 LogTime(), PROGRAM, ldap_err2string(rc));
872 ldap_unbind_ext(ld, NULL, NULL);
873 ld = NULL;
874 return NULL;
875 }
876 if (ssl) {
877 /*
878 * Try Start TLS first
879 */
880 debug((char *) "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM);
881 rc = ldap_set_ssl_defaults(margs);
882 if (rc != LDAP_SUCCESS) {
883 error((char *)
884 "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n",
885 LogTime(), PROGRAM, ldap_err2string(rc));
886 ldap_unbind_ext(ld, NULL, NULL);
887 ld = NULL;
888 return NULL;
889 }
890 #if HAVE_OPENLDAP
891 /*
892 * Use tls if possible
893 */
894 rc = ldap_start_tls_s(ld, NULL, NULL);
895 if (rc != LDAP_SUCCESS) {
896 debug((char *)
897 "%s| %s: WARNING: Error while setting start_tls for ldap server: %s\n",
898 LogTime(), PROGRAM, ldap_err2string(rc));
899 ldap_unbind_ext(ld, NULL, NULL);
900 ld = NULL;
901 url = (LDAPURLDesc *) xmalloc(sizeof(*url));
902 memset(url, 0, sizeof(*url));
903 #if HAVE_LDAP_URL_LUD_SCHEME
904 url->lud_scheme = xstrdup("ldaps");
905 #endif
906 url->lud_host = xstrdup(host);
907 url->lud_port = port;
908 #if HAVE_LDAP_SCOPE_DEFAULT
909 url->lud_scope = LDAP_SCOPE_DEFAULT;
910 #else
911 url->lud_scope = LDAP_SCOPE_SUBTREE;
912 #endif
913 #if HAVE_LDAP_URL_DESC2STR
914 ldapuri = ldap_url_desc2str(url);
915 #elif HAVE_LDAP_URL_PARSE
916 rc = ldap_url_parse(ldapuri, &url);
917 if (rc != LDAP_SUCCESS) {
918 error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
919 LogTime(), PROGRAM, ldap_err2string(rc));
920 xfree(ldapuri);
921 ldap_free_urldesc(url);
922 return NULL;
923 }
924 #else
925 #error "No URL parsing function"
926 #endif
927 ldap_free_urldesc(url);
928 rc = ldap_initialize(&ld, ldapuri);
929 xfree(ldapuri);
930 if (rc != LDAP_SUCCESS) {
931 error((char *)
932 "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
933 LogTime(), PROGRAM, ldap_err2string(rc));
934 ldap_unbind_ext(ld, NULL, NULL);
935 ld = NULL;
936 return NULL;
937 }
938 rc = ldap_set_defaults(ld);
939 if (rc != LDAP_SUCCESS) {
940 error((char *)
941 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
942 LogTime(), PROGRAM, ldap_err2string(rc));
943 ldap_unbind_ext(ld, NULL, NULL);
944 ld = NULL;
945 return NULL;
946 }
947 }
948 #elif HAVE_LDAPSSL_CLIENT_INIT
949 ld = ldapssl_init(host, port, 1);
950 if (!ld) {
951 error((char *)
952 "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
953 LogTime(), PROGRAM, ldapssl_err2string(rc));
954 ldap_unbind_ext(ld, NULL, NULL);
955 ld = NULL;
956 return NULL;
957 }
958 rc = ldap_set_defaults(ld);
959 if (rc != LDAP_SUCCESS) {
960 error((char *)
961 "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
962 LogTime(), PROGRAM, ldap_err2string(rc));
963 ldap_unbind_ext(ld, NULL, NULL);
964 ld = NULL;
965 return NULL;
966 }
967 #else
968 error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
969 LogTime(), PROGRAM);
970 #endif
971 }
972 return ld;
973 }
974
975 /*
976 * ldap calls to get attribute from Ldap Directory Server
977 */
978 int
979 get_memberof(struct main_args *margs, char *user, char *domain, char *group)
980 {
981 LDAP *ld = NULL;
982 LDAPMessage *res;
983 #if !HAVE_SUN_LDAP_SDK
984 int ldap_debug = 0;
985 #endif
986 struct ldap_creds *lcreds = NULL;
987 char *bindp = NULL;
988 char *filter = NULL;
989 char *search_exp;
990 size_t se_len = 0;
991 struct timeval searchtime;
992 int rc = 0, kc = 1;
993 int retval;
994 char **attr_value = NULL;
995 size_t max_attr = 0;
996 struct hstruct *hlist = NULL;
997 size_t nhosts = 0;
998 char *ldap_filter_esc = NULL;
999
1000 searchtime.tv_sec = SEARCH_TIMEOUT;
1001 searchtime.tv_usec = 0;
1002 /*
1003 * Fill Kerberos memory cache with credential from keytab for SASL/GSSAPI
1004 */
1005 if (domain) {
1006 debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n",
1007 LogTime(), PROGRAM);
1008
1009 #if HAVE_KRB5
1010 if (margs->nokerberos) {
1011 kc = 1;
1012 debug((char *)
1013 "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n",
1014 LogTime(), PROGRAM);
1015 } else {
1016 kc = krb5_create_cache(domain, margs->principal);
1017 if (kc) {
1018 error((char *)
1019 "%s| %s: ERROR: Error during setup of Kerberos credential cache\n",
1020 LogTime(), PROGRAM);
1021 }
1022 }
1023 #else
1024 kc = 1;
1025 debug((char *)
1026 "%s| %s: DEBUG: Kerberos is not supported. Use username/password with ldap url instead\n",
1027 LogTime(), PROGRAM);
1028 #endif
1029 }
1030
1031 if (kc && (!margs->lurl || !margs->luser || !margs->lpass)) {
1032 /*
1033 * If Kerberos fails and no url given exit here
1034 */
1035 retval = 0;
1036 goto cleanup;
1037 }
1038 #if !HAVE_SUN_LDAP_SDK
1039 /*
1040 * Initialise ldap
1041 */
1042 // ldap_debug = 127 /* LDAP_DEBUG_TRACE */ ;
1043 // ldap_debug = -1 /* LDAP_DEBUG_ANY */ ;
1044 ldap_debug = 0;
1045 (void) ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug);
1046 #endif
1047 debug((char *) "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(),
1048 PROGRAM);
1049
1050 if (domain && !kc) {
1051 if (margs->ssl) {
1052 debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n",
1053 LogTime(), PROGRAM);
1054 }
1055 debug((char *)
1056 "%s| %s: DEBUG: Canonicalise ldap server name for domain %s\n",
1057 LogTime(), PROGRAM, domain);
1058 /*
1059 * Loop over list of ldap servers of users domain
1060 */
1061 nhosts = get_ldap_hostname_list(margs, &hlist, 0, domain);
1062 for (size_t i = 0; i < nhosts; ++i) {
1063 int port = 389;
1064 if (hlist[i].port != -1)
1065 port = hlist[i].port;
1066 debug((char *)
1067 "%s| %s: DEBUG: Setting up connection to ldap server %s:%d\n",
1068 LogTime(), PROGRAM, hlist[i].host, port);
1069
1070 ld = tool_ldap_open(margs, hlist[i].host, port, margs->ssl);
1071 if (!ld)
1072 continue;
1073
1074 /*
1075 * ldap bind with SASL/GSSAPI authentication (only possible if a domain was part of the username)
1076 */
1077
1078 #if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
1079 debug((char *)
1080 "%s| %s: DEBUG: Bind to ldap server with SASL/GSSAPI\n",
1081 LogTime(), PROGRAM);
1082
1083 rc = tool_sasl_bind(ld, bindp, margs->ssl);
1084 if (rc != LDAP_SUCCESS) {
1085 error((char *)
1086 "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n",
1087 LogTime(), PROGRAM, ldap_err2string(rc));
1088 ldap_unbind_ext(ld, NULL, NULL);
1089 ld = NULL;
1090 continue;
1091 }
1092 lcreds = (struct ldap_creds *) xmalloc(sizeof(struct ldap_creds));
1093 lcreds->dn = NULL;
1094 lcreds->pw = margs->ssl ? xstrdup(margs->ssl) : NULL;
1095 ldap_set_rebind_proc(ld, ldap_sasl_rebind, (char *) lcreds);
1096 if (ld != NULL) {
1097 debug((char *)
1098 "%s| %s: DEBUG: %s initialised %sconnection to ldap server %s:%d\n",
1099 LogTime(), PROGRAM, ld ? "Successfully" : "Failed to",
1100 margs->ssl ? "SSL protected " : "", hlist[i].host, port);
1101 break;
1102 }
1103 #else
1104 ldap_unbind_ext(ld, NULL, NULL);
1105 ld = NULL;
1106 error((char *) "%s| %s: ERROR: SASL not supported on system\n",
1107 LogTime(), PROGRAM);
1108 continue;
1109 #endif
1110 }
1111 nhosts = free_hostname_list(&hlist, nhosts);
1112 if (ld == NULL) {
1113 debug((char *)
1114 "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n",
1115 LogTime(), PROGRAM, strerror(errno));
1116 }
1117 bindp = convert_domain_to_bind_path(domain);
1118 }
1119 if ((!domain || !ld) && margs->lurl && strstr(margs->lurl, "://")) {
1120 char *hostname;
1121 char *host;
1122 int port;
1123 char *ssl = NULL;
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 NULL, NULL, NULL);
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, NULL, NULL);
1171 ld = NULL;
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 == NULL) {
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, NULL, NULL);
1213 ld = NULL;
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, NULL, 0,
1234 NULL, NULL, &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, NULL, NULL);
1241 ld = NULL;
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 = NULL;
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 = NULL;
1268 av += 3;
1269 if ((avp = strchr(av, ','))) {
1270 *avp = '\0';
1271 }
1272 }
1273 if (debug_enabled) {
1274 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
1275 " \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, k + 1, av);
1276 for (unsigned int n = 0; av[n] != '\0'; ++n)
1277 fprintf(stderr, "%02x", (unsigned char) av[n]);
1278 fprintf(stderr, "\n");
1279 }
1280 if (!strcasecmp(group, av)) {
1281 retval = 1;
1282 if (debug_enabled)
1283 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
1284 " \"%s\" matches group name \"%s\"\n", LogTime(),
1285 PROGRAM, k + 1, av, group);
1286 else
1287 break;
1288 } else
1289 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
1290 " \"%s\" does not match group name \"%s\"\n", LogTime(),
1291 PROGRAM, k + 1, av, group);
1292 }
1293 /*
1294 * Do recursive group search for AD only since posixgroups can not contain other groups
1295 */
1296 if (!retval && margs->AD) {
1297 if (debug_enabled && max_attr > 0) {
1298 debug((char *)
1299 "%s| %s: DEBUG: Perform recursive group search\n",
1300 LogTime(), PROGRAM);
1301 }
1302 for (size_t j = 0; j < max_attr; ++j) {
1303 char *av = NULL;
1304
1305 av = attr_value[j];
1306 if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1307 retval = 1;
1308 if (!strncasecmp("CN=", av, 3)) {
1309 char *avp = NULL;
1310 av += 3;
1311 if ((avp = strchr(av, ','))) {
1312 *avp = '\0';
1313 }
1314 }
1315 if (debug_enabled)
1316 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
1317 " group \"%s\" is (in)direct member of group \"%s\"\n",
1318 LogTime(), PROGRAM, j + 1, av, group);
1319 else
1320 break;
1321 }
1322 }
1323 }
1324 /*
1325 * Cleanup
1326 */
1327 if (attr_value) {
1328 for (size_t j = 0; j < max_attr; ++j) {
1329 xfree(attr_value[j]);
1330 }
1331 safe_free(attr_value);
1332 }
1333 ldap_msgfree(res);
1334 } else if (ldap_count_entries(ld, res) == 0 && margs->AD) {
1335 ldap_msgfree(res);
1336 ldap_unbind_ext(ld, NULL, NULL);
1337 ld = NULL;
1338 retval = 0;
1339 goto cleanup;
1340 } else {
1341 ldap_msgfree(res);
1342 retval = 0;
1343 }
1344
1345 if (retval == 0) {
1346 /*
1347 * Check for primary Group membership
1348 */
1349 debug((char *)
1350 "%s| %s: DEBUG: Search for primary group membership: \"%s\"\n",
1351 LogTime(), PROGRAM, group);
1352 if (margs->AD)
1353 filter = (char *) FILTER_AD;
1354 else
1355 filter = (char *) FILTER_UID;
1356
1357 ldap_filter_esc = escape_filter(user);
1358
1359 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1360 search_exp = (char *) xmalloc(se_len);
1361 snprintf(search_exp, se_len, filter, ldap_filter_esc);
1362
1363 xfree(ldap_filter_esc);
1364
1365 debug((char *)
1366 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1367 LogTime(), PROGRAM, bindp, search_exp);
1368 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE, search_exp, NULL,
1369 0, NULL, NULL, &searchtime, 0, &res);
1370 xfree(search_exp);
1371
1372 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(),
1373 PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld,
1374 res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1375
1376 max_attr = 0;
1377 if (!rc) {
1378 if (margs->AD)
1379 max_attr =
1380 get_attributes(ld, res, ATTRIBUTE_GID_AD, &attr_value);
1381 else
1382 max_attr = get_attributes(ld, res, ATTRIBUTE_GID, &attr_value);
1383 }
1384
1385 if (max_attr == 1) {
1386 char **attr_value_2 = NULL;
1387 size_t max_attr_2 = 0;
1388
1389 if (margs->AD) {
1390 char **attr_value_3 = NULL;
1391 int *attr_len_3 = NULL;
1392 size_t max_attr_3 = 0;
1393 uint32_t gid = atoi(attr_value[0]);
1394
1395 /* Get objectsid and search for group
1396 * with objectsid = domain(objectsid) + primarygroupid */
1397 debug((char *) "%s| %s: DEBUG: Got primaryGroupID %u\n",
1398 LogTime(), PROGRAM, gid);
1399 max_attr_3 =
1400 get_bin_attributes(ld, res, ATTRIBUTE_SID, &attr_value_3,
1401 &attr_len_3);
1402 ldap_msgfree(res);
1403 if (max_attr_3 == 1) {
1404 int len = attr_len_3[0];
1405 if (len < 4) {
1406 debug((char *)
1407 "%s| %s: ERROR: Length %d is too short for objectSID\n",
1408 LogTime(), PROGRAM, len);
1409 rc = 1;
1410 } else {
1411 char *se = NULL;
1412 attr_value_3[0][len - 1] = ((gid >> 24) & 0xff);
1413 attr_value_3[0][len - 2] = ((gid >> 16) & 0xff);
1414 attr_value_3[0][len - 3] = ((gid >> 8) & 0xff);
1415 attr_value_3[0][len - 4] = ((gid >> 0) & 0xff);
1416
1417 #define FILTER_SID_1 "(objectSID="
1418 #define FILTER_SID_2 ")"
1419
1420 se_len =
1421 strlen(FILTER_SID_1) + len * 3 +
1422 strlen(FILTER_SID_2) + 1;
1423 search_exp = (char *) xmalloc(se_len);
1424 snprintf(search_exp, se_len, "%s", FILTER_SID_1);
1425
1426 for (int j = 0; j < len; j++) {
1427 se = xstrdup(search_exp);
1428 snprintf(search_exp, se_len, "%s\\%02x", se,
1429 attr_value_3[0][j] & 0xFF);
1430 xfree(se);
1431 }
1432 se = xstrdup(search_exp);
1433 snprintf(search_exp, se_len, "%s%s", se, FILTER_SID_2);
1434 xfree(se);
1435
1436 debug((char *)
1437 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1438 LogTime(), PROGRAM, bindp, search_exp);
1439 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1440 search_exp, NULL, 0, NULL, NULL, &searchtime, 0,
1441 &res);
1442 xfree(search_exp);
1443
1444 debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n",
1445 LogTime(), PROGRAM, ldap_count_entries(ld, res),
1446 ldap_count_entries(ld, res) > 1
1447 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1448
1449 }
1450 } else {
1451 rc = 1;
1452 }
1453 if (attr_value_3) {
1454 size_t j;
1455 for (j = 0; j < max_attr_3; ++j) {
1456 xfree(attr_value_3[j]);
1457 }
1458 safe_free(attr_value_3);
1459 }
1460 if (attr_len_3) {
1461 xfree(attr_len_3);
1462 }
1463 } else {
1464 ldap_msgfree(res);
1465 filter = (char *) FILTER_GID;
1466
1467 ldap_filter_esc = escape_filter(attr_value[0]);
1468
1469 se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1470 search_exp = (char *) xmalloc(se_len);
1471 snprintf(search_exp, se_len, filter, ldap_filter_esc);
1472
1473 xfree(ldap_filter_esc);
1474
1475 debug((char *)
1476 "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1477 LogTime(), PROGRAM, bindp, search_exp);
1478 rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1479 search_exp, NULL, 0, NULL, NULL, &searchtime, 0, &res);
1480 xfree(search_exp);
1481 }
1482
1483 if (!rc) {
1484 if (margs->AD)
1485 max_attr_2 =
1486 get_attributes(ld, res, ATTRIBUTE_DN, &attr_value_2);
1487 else
1488 max_attr_2 =
1489 get_attributes(ld, res, ATTRIBUTE, &attr_value_2);
1490 ldap_msgfree(res);
1491 } else {
1492 ldap_msgfree(res);
1493 }
1494 /*
1495 * Compare group names
1496 */
1497 retval = 0;
1498 if (max_attr_2 == 1) {
1499 /* Compare first CN= value assuming it is the same as the group name itself */
1500 char *av = attr_value_2[0];
1501 if (!strncasecmp("CN=", av, 3)) {
1502 char *avp = NULL;
1503 av += 3;
1504 if ((avp = strchr(av, ','))) {
1505 *avp = '\0';
1506 }
1507 }
1508 if (!strcasecmp(group, av)) {
1509 retval = 1;
1510 debug((char *)
1511 "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n",
1512 LogTime(), PROGRAM, av, group);
1513 } else
1514 debug((char *)
1515 "%s| %s: DEBUG: \"%s\" does not match group name \"%s\"\n",
1516 LogTime(), PROGRAM, av, group);
1517
1518 }
1519 /*
1520 * Do recursive group search for AD only since posixgroups can not contain other groups
1521 */
1522 if (!retval && margs->AD) {
1523 if (debug_enabled && max_attr_2 > 0) {
1524 debug((char *)
1525 "%s| %s: DEBUG: Perform recursive group search\n",
1526 LogTime(), PROGRAM);
1527 }
1528 for (size_t j = 0; j < max_attr_2; ++j) {
1529 char *av = NULL;
1530
1531 av = attr_value_2[j];
1532 if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1533 retval = 1;
1534 if (!strncasecmp("CN=", av, 3)) {
1535 char *avp = NULL;
1536 av += 3;
1537 if ((avp = strchr(av, ','))) {
1538 *avp = '\0';
1539 }
1540 }
1541 if (debug_enabled) {
1542 debug((char *) "%s| %s: DEBUG: Entry %" PRIuSIZE
1543 " group \"%s\" is (in)direct member of group \"%s\"\n",
1544 LogTime(), PROGRAM, j + 1, av, group);
1545 } else {
1546 break;
1547 }
1548 }
1549 }
1550 }
1551 /*
1552 * Cleanup
1553 */
1554 if (attr_value_2) {
1555 size_t j;
1556 for (j = 0; j < max_attr_2; ++j) {
1557 xfree(attr_value_2[j]);
1558 }
1559 safe_free(attr_value_2);
1560 }
1561
1562 debug((char *) "%s| %s: DEBUG: Users primary group %s %s\n",
1563 LogTime(), PROGRAM, retval ? "matches" : "does not match",
1564 group);
1565
1566 } else {
1567 ldap_msgfree(res);
1568 debug((char *)
1569 "%s| %s: DEBUG: Did not find ldap entry for group %s\n",
1570 LogTime(), PROGRAM, group);
1571 }
1572 /*
1573 * Cleanup
1574 */
1575 if (attr_value) {
1576 for (size_t j = 0; j < max_attr; ++j) {
1577 xfree(attr_value[j]);
1578 }
1579 safe_free(attr_value);
1580 }
1581 }
1582 rc = ldap_unbind_ext(ld, NULL, NULL);
1583 ld = NULL;
1584 if (rc != LDAP_SUCCESS) {
1585 error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n",
1586 LogTime(), PROGRAM, ldap_err2string(rc));
1587 }
1588 debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM);
1589 cleanup:
1590 if (lcreds) {
1591 xfree(lcreds->dn);
1592 xfree(lcreds->pw);
1593 xfree(lcreds);
1594 }
1595 xfree(bindp);
1596 return (retval);
1597 }
1598 #endif
1599