support_ldap.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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
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, nullptr, nullptr,
121  nullptr);
122 }
123 #elif HAVE_LDAP_REBIND_PROC
124 #if HAVE_SASL_H || HAVE_SASL_SASL_H
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 /* HAVE_SASL_H || HAVE_SASL_SASL_H */
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, 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
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, 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
196 static LDAP_REBIND_PROC ldap_sasl_rebind;
197 
198 static int
199 ldap_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 
207 static LDAP_REBIND_PROC ldap_simple_rebind;
208 
209 static int
210 ldap_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
225 char *
226 convert_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 
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 = 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  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, nullptr, 0, nullptr, nullptr, &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 = nullptr;
361  char **attr_value = nullptr;
362  size_t max_attr = 0;
363  char *filter = nullptr;
364  char *search_exp = nullptr;
365  size_t se_len = 0;
366  int rc = 0, retval = 0;
367  int ldepth;
368  char *ldap_filter_esc = nullptr;
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, nullptr, 0,
400  nullptr, nullptr, &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 = nullptr;
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 = nullptr;
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 %zu \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, j + 1, av);
437  for (n = 0; av[n] != '\0'; ++n)
438  fprintf(stderr, "%02x", (unsigned char) av[n]);
439  fprintf(stderr, "\n");
440  }
441  if (!strcasecmp(group, av)) {
442  retval = 1;
443  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM,
444  j + 1, av, group);
445  break;
446  } else
447  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" does not match group name \"%s\"\n", LogTime(),
448  PROGRAM, j + 1, av, group);
449  /*
450  * Do recursive group search
451  */
452  debug((char *)
453  "%s| %s: DEBUG: Perform recursive group search for group \"%s\"\n",
454  LogTime(), PROGRAM, av);
455  av = attr_value[j];
456  if (search_group_tree(margs, ld, bindp, av, group, ldepth)) {
457  retval = 1;
458  if (!strncasecmp("CN=", av, 3)) {
459  char *avp = nullptr;
460  av += 3;
461  if ((avp = strchr(av, ','))) {
462  *avp = '\0';
463  }
464  }
465  if (debug_enabled)
466  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" is member of group named \"%s\"\n", LogTime(),
467  PROGRAM, j + 1, av, group);
468  else
469  break;
470 
471  }
472  }
473 
474  /*
475  * Cleanup
476  */
477  if (attr_value) {
478  for (size_t j = 0; j < max_attr; ++j) {
479  xfree(attr_value[j]);
480  }
481  safe_free(attr_value);
482  }
483  ldap_msgfree(res);
484 
485  return retval;
486 }
487 
488 int
489 ldap_set_defaults(LDAP * ld)
490 {
491  int val, rc = 0;
492 #if LDAP_OPT_NETWORK_TIMEOUT
493  struct timeval tv;
494 #endif
495  val = LDAP_VERSION3;
496  rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &val);
497  if (rc != LDAP_SUCCESS) {
498  debug((char *)
499  "%s| %s: DEBUG: Error while setting protocol version: %s\n",
500  LogTime(), PROGRAM, ldap_err2string(rc));
501  return rc;
502  }
503  rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
504  if (rc != LDAP_SUCCESS) {
505  debug((char *) "%s| %s: DEBUG: Error while setting referrals off: %s\n",
506  LogTime(), PROGRAM, ldap_err2string(rc));
507  return rc;
508  }
509 #if LDAP_OPT_NETWORK_TIMEOUT
510  tv.tv_sec = CONNECT_TIMEOUT;
511  tv.tv_usec = 0;
512  rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
513  if (rc != LDAP_SUCCESS) {
514  debug((char *)
515  "%s| %s: DEBUG: Error while setting network timeout: %s\n",
516  LogTime(), PROGRAM, ldap_err2string(rc));
517  return rc;
518  }
519 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
520  return LDAP_SUCCESS;
521 }
522 
523 int
524 ldap_set_ssl_defaults(struct main_args *margs)
525 {
526 #if HAVE_OPENLDAP || HAVE_LDAPSSL_CLIENT_INIT
527  int rc = 0;
528 #endif
529 #if HAVE_OPENLDAP
530  int val;
531 #elif HAVE_LDAPSSL_CLIENT_INIT
532  char *ssl_certdbpath = nullptr;
533 #endif
534 
535 #if HAVE_OPENLDAP
536  if (!margs->rc_allow) {
537  char *ssl_cacertfile = nullptr;
538  char *ssl_cacertdir = nullptr;
539  debug((char *)
540  "%s| %s: DEBUG: Enable server certificate check for ldap server.\n",
541  LogTime(), PROGRAM);
542  val = LDAP_OPT_X_TLS_DEMAND;
543  rc = ldap_set_option(nullptr, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
544  if (rc != LDAP_SUCCESS) {
545  error((char *)
546  "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT DEMAND for ldap server: %s\n",
547  LogTime(), PROGRAM, ldap_err2string(rc));
548  return rc;
549  }
550  ssl_cacertfile = xstrdup(getenv("TLS_CACERTFILE"));
551  if (!ssl_cacertfile) {
552  ssl_cacertfile = xstrdup("/etc/ssl/certs/cert.pem");
553  }
554  if (access(ssl_cacertfile, R_OK) == 0) {
555  debug((char *)
556  "%s| %s: DEBUG: Set certificate file for ldap server to %s. (Changeable through setting environment variable TLS_CACERTFILE)\n",
557  LogTime(), PROGRAM, ssl_cacertfile);
558  rc = ldap_set_option(nullptr, LDAP_OPT_X_TLS_CACERTFILE,
559  ssl_cacertfile);
560  xfree(ssl_cacertfile);
561  if (rc != LDAP_OPT_SUCCESS) {
562  error((char *)
563  "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n",
564  LogTime(), PROGRAM, ldap_err2string(rc));
565  return rc;
566  }
567  } else {
568  debug((char *)
569  "%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",
570  LogTime(), PROGRAM, ssl_cacertfile, strerror(errno));
571  xfree(ssl_cacertfile);
572  ssl_cacertdir = xstrdup(getenv("TLS_CACERTDIR"));
573  if (!ssl_cacertdir) {
574  ssl_cacertdir = xstrdup("/etc/ssl/certs");
575  }
576  if (access(ssl_cacertdir, R_OK) == 0) {
577  debug((char *)
578  "%s| %s: DEBUG: Set certificate database path for ldap server to %s. (Changeable through setting environment variable TLS_CACERTDIR)\n",
579  LogTime(), PROGRAM, ssl_cacertdir);
580  rc = ldap_set_option(nullptr, LDAP_OPT_X_TLS_CACERTDIR,
581  ssl_cacertdir);
582  xfree(ssl_cacertdir);
583  if (rc != LDAP_OPT_SUCCESS) {
584  error((char *)
585  "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTDIR for ldap server: %s\n",
586  LogTime(), PROGRAM, ldap_err2string(rc));
587  return rc;
588  }
589  } else {
590  debug((char *)
591  "%s| %s: DEBUG: Set certificate database path for ldap server to %s failed (%s). (Changeable through setting environment variable TLS_CACERTDIR)\n",
592  LogTime(), PROGRAM, ssl_cacertdir, strerror(errno));
593  xfree(ssl_cacertdir);
594  return errno;
595  }
596  }
597  } else {
598  debug((char *)
599  "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
600  LogTime(), PROGRAM);
601  val = LDAP_OPT_X_TLS_ALLOW;
602  rc = ldap_set_option(nullptr, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
603  if (rc != LDAP_SUCCESS) {
604  error((char *)
605  "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT ALLOW for ldap server: %s\n",
606  LogTime(), PROGRAM, ldap_err2string(rc));
607  return rc;
608  }
609  }
610 #elif HAVE_LDAPSSL_CLIENT_INIT
611  /*
612  * Solaris SSL ldap calls require path to certificate database
613  */
614  /*
615  * rc = ldapssl_client_init( ssl_certdbpath, nullptr);
616  * rc = ldapssl_advclientauth_init( ssl_certdbpath, nullptr, 0 , nullptr, nullptr, 0, nullptr, 2);
617  */
618  ssl_certdbpath = getenv("SSL_CERTDBPATH");
619  if (!ssl_certdbpath) {
620  ssl_certdbpath = xstrdup("/etc/certs");
621  }
622  debug((char *)
623  "%s| %s: DEBUG: Set certificate database path for ldap server to %s. (Changeable through setting environment variable SSL_CERTDBPATH)\n",
624  LogTime(), PROGRAM, ssl_certdbpath);
625  if (!margs->rc_allow) {
626  rc = ldapssl_advclientauth_init(ssl_certdbpath, nullptr, 0, nullptr, nullptr, 0,
627  nullptr, 2);
628  } else {
629  rc = ldapssl_advclientauth_init(ssl_certdbpath, nullptr, 0, nullptr, nullptr, 0,
630  nullptr, 0);
631  debug((char *)
632  "%s| %s: DEBUG: Disable server certificate check for ldap server.\n",
633  LogTime(), PROGRAM);
634  }
635  xfree(ssl_certdbpath);
636  if (rc != LDAP_SUCCESS) {
637  error((char *)
638  "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
639  LogTime(), PROGRAM, ldapssl_err2string(rc));
640  return rc;
641  }
642 #else
643  (void)margs;
644  error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
645  LogTime(), PROGRAM);
646 #endif
647  return LDAP_SUCCESS;
648 }
649 
650 size_t
651 get_attributes(LDAP * ld, LDAPMessage * res, const char *attribute,
652  char ***ret_value)
653 {
654 
655  char **attr_value = *ret_value;
656  size_t max_attr = 0;
657 
658  /*
659  * loop over attributes
660  */
661  debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n",
662  LogTime(), PROGRAM, attribute);
663  for (LDAPMessage * msg = ldap_first_entry(ld, res); msg;
664  msg = ldap_next_entry(ld, msg)) {
665 
666  switch (ldap_msgtype(msg)) {
667 
668  case LDAP_RES_SEARCH_ENTRY: {
669  BerElement *b = nullptr;
670  for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
671  attr = ldap_next_attribute(ld, msg, b)) {
672  if (strcasecmp(attr, attribute) == 0) {
673  struct berval **values;
674 
675  if ((values =
676  ldap_get_values_len(ld, msg, attr)) != nullptr) {
677  for (int il = 0; values[il] != nullptr; ++il) {
678 
679  attr_value =
680  (char **) xrealloc(attr_value,
681  (max_attr + 1) * sizeof(char *));
682  if (!attr_value)
683  break;
684 
685  attr_value[max_attr] =
686  (char *) xmalloc(values[il]->bv_len + 1);
687  memcpy(attr_value[max_attr], values[il]->bv_val,
688  values[il]->bv_len);
689  attr_value[max_attr][values[il]->bv_len] = 0;
690  max_attr++;
691  }
692  }
693  ber_bvecfree(values);
694  }
695  ldap_memfree(attr);
696  }
697  ber_free(b, 0);
698  }
699  break;
700  case LDAP_RES_SEARCH_REFERENCE:
701  debug((char *)
702  "%s| %s: DEBUG: Received a search reference message\n",
703  LogTime(), PROGRAM);
704  break;
705  case LDAP_RES_SEARCH_RESULT:
706  debug((char *) "%s| %s: DEBUG: Received a search result message\n",
707  LogTime(), PROGRAM);
708  break;
709  default:
710  break;
711  }
712  }
713 
714  debug((char *) "%s| %s: DEBUG: %zu ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM,
715  max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
716 
717  *ret_value = attr_value;
718  return max_attr;
719 }
720 
721 size_t
722 get_bin_attributes(LDAP * ld, LDAPMessage * res, const char *attribute,
723  char ***ret_value, int **ret_len)
724 {
725 
726  char **attr_value = *ret_value;
727  int *attr_len = *ret_len;
728  size_t max_attr = 0;
729 
730  /*
731  * loop over attributes
732  */
733  debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n",
734  LogTime(), PROGRAM, attribute);
735  for (LDAPMessage * msg = ldap_first_entry(ld, res); msg;
736  msg = ldap_next_entry(ld, msg)) {
737 
738  switch (ldap_msgtype(msg)) {
739 
740  case LDAP_RES_SEARCH_ENTRY: {
741  BerElement *b = nullptr;
742  for (char *attr = ldap_first_attribute(ld, msg, &b); attr;
743  attr = ldap_next_attribute(ld, msg, b)) {
744  if (strcasecmp(attr, attribute) == 0) {
745  struct berval **values;
746 
747  if ((values =
748  ldap_get_values_len(ld, msg, attr)) != nullptr) {
749  for (int il = 0; values[il] != nullptr; ++il) {
750 
751  attr_value =
752  (char **) xrealloc(attr_value,
753  (max_attr + 1) * sizeof(char *));
754  if (!attr_value)
755  break;
756 
757  attr_len =
758  (int *) xrealloc(attr_len,
759  (max_attr + 1) * sizeof(int));
760  if (!attr_len)
761  break;
762 
763  attr_value[max_attr] =
764  (char *) xmalloc(values[il]->bv_len + 1);
765  memcpy(attr_value[max_attr], values[il]->bv_val,
766  values[il]->bv_len);
767  attr_value[max_attr][values[il]->bv_len] = 0;
768  attr_len[max_attr] = values[il]->bv_len;
769  max_attr++;
770  }
771  }
772  ber_bvecfree(values);
773  }
774  ldap_memfree(attr);
775  }
776  ber_free(b, 0);
777  }
778  break;
779  case LDAP_RES_SEARCH_REFERENCE:
780  debug((char *)
781  "%s| %s: DEBUG: Received a search reference message\n",
782  LogTime(), PROGRAM);
783  break;
784  case LDAP_RES_SEARCH_RESULT:
785  debug((char *) "%s| %s: DEBUG: Received a search result message\n",
786  LogTime(), PROGRAM);
787  break;
788  default:
789  break;
790  }
791  }
792 
793  debug((char *) "%s| %s: DEBUG: %zu ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM,
794  max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
795 
796  *ret_value = attr_value;
797  *ret_len = attr_len;
798  return max_attr;
799 }
800 
801 /*
802  * call to open ldap server with or without SSL
803  */
804 LDAP *
805 tool_ldap_open(struct main_args * margs, char *host, int port, char *ssl)
806 {
807  LDAP *ld;
808 #if HAVE_OPENLDAP
809  LDAPURLDesc *url = nullptr;
810  char *ldapuri = nullptr;
811 #endif
812  int rc = 0;
813 
814  /*
815  * Use ldap open here to check if TCP connection is possible. If possible use it.
816  * (Not sure if this is the best way)
817  */
818 #if HAVE_OPENLDAP
819  url = (LDAPURLDesc *) xmalloc(sizeof(*url));
820  memset(url, 0, sizeof(*url));
821 #if HAVE_LDAP_URL_LUD_SCHEME
822  if (ssl)
823  url->lud_scheme = xstrdup("ldaps");
824  else
825  url->lud_scheme = xstrdup("ldap");
826 #endif
827  url->lud_host = xstrdup(host);
828  url->lud_port = port;
829 #if HAVE_LDAP_SCOPE_DEFAULT
830  url->lud_scope = LDAP_SCOPE_DEFAULT;
831 #else
832  url->lud_scope = LDAP_SCOPE_SUBTREE;
833 #endif
834 #if HAVE_LDAP_URL_DESC2STR
835  ldapuri = ldap_url_desc2str(url);
836 #elif HAVE_LDAP_URL_PARSE
837  rc = ldap_url_parse(ldapuri, &url);
838  if (rc != LDAP_SUCCESS) {
839  error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
840  LogTime(), PROGRAM, ldap_err2string(rc));
841  xfree(ldapuri);
842  ldap_free_urldesc(url);
843  return nullptr;
844  }
845 #else
846 #error "No URL parsing function"
847 #endif
848  ldap_free_urldesc(url);
849  rc = ldap_initialize(&ld, ldapuri);
850  xfree(ldapuri);
851  if (rc != LDAP_SUCCESS) {
852  error((char *)
853  "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
854  LogTime(), PROGRAM, ldap_err2string(rc));
855  ldap_unbind_ext(ld, nullptr, nullptr);
856  ld = nullptr;
857  return nullptr;
858  }
859 #else
860  ld = ldap_init(host, port);
861 #endif
862  rc = ldap_set_defaults(ld);
863  if (rc != LDAP_SUCCESS) {
864  error((char *)
865  "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
866  LogTime(), PROGRAM, ldap_err2string(rc));
867  ldap_unbind_ext(ld, nullptr, nullptr);
868  ld = nullptr;
869  return nullptr;
870  }
871  if (ssl) {
872  /*
873  * Try Start TLS first
874  */
875  debug((char *) "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM);
876  rc = ldap_set_ssl_defaults(margs);
877  if (rc != LDAP_SUCCESS) {
878  error((char *)
879  "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n",
880  LogTime(), PROGRAM, ldap_err2string(rc));
881  ldap_unbind_ext(ld, nullptr, nullptr);
882  ld = nullptr;
883  return nullptr;
884  }
885 #if HAVE_OPENLDAP
886  /*
887  * Use tls if possible
888  */
889  rc = ldap_start_tls_s(ld, nullptr, nullptr);
890  if (rc != LDAP_SUCCESS) {
891  debug((char *)
892  "%s| %s: WARNING: Error while setting start_tls for ldap server: %s\n",
893  LogTime(), PROGRAM, ldap_err2string(rc));
894  ldap_unbind_ext(ld, nullptr, nullptr);
895  ld = nullptr;
896  url = (LDAPURLDesc *) xmalloc(sizeof(*url));
897  memset(url, 0, sizeof(*url));
898 #if HAVE_LDAP_URL_LUD_SCHEME
899  url->lud_scheme = xstrdup("ldaps");
900 #endif
901  url->lud_host = xstrdup(host);
902  url->lud_port = port;
903 #if HAVE_LDAP_SCOPE_DEFAULT
904  url->lud_scope = LDAP_SCOPE_DEFAULT;
905 #else
906  url->lud_scope = LDAP_SCOPE_SUBTREE;
907 #endif
908 #if HAVE_LDAP_URL_DESC2STR
909  ldapuri = ldap_url_desc2str(url);
910 #elif HAVE_LDAP_URL_PARSE
911  rc = ldap_url_parse(ldapuri, &url);
912  if (rc != LDAP_SUCCESS) {
913  error((char *) "%s| %s: ERROR: Error while parsing url: %s\n",
914  LogTime(), PROGRAM, ldap_err2string(rc));
915  xfree(ldapuri);
916  ldap_free_urldesc(url);
917  return nullptr;
918  }
919 #else
920 #error "No URL parsing function"
921 #endif
922  ldap_free_urldesc(url);
923  rc = ldap_initialize(&ld, ldapuri);
924  xfree(ldapuri);
925  if (rc != LDAP_SUCCESS) {
926  error((char *)
927  "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n",
928  LogTime(), PROGRAM, ldap_err2string(rc));
929  ldap_unbind_ext(ld, nullptr, nullptr);
930  ld = nullptr;
931  return nullptr;
932  }
933  rc = ldap_set_defaults(ld);
934  if (rc != LDAP_SUCCESS) {
935  error((char *)
936  "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
937  LogTime(), PROGRAM, ldap_err2string(rc));
938  ldap_unbind_ext(ld, nullptr, nullptr);
939  ld = nullptr;
940  return nullptr;
941  }
942  }
943 #elif HAVE_LDAPSSL_CLIENT_INIT
944  ld = ldapssl_init(host, port, 1);
945  if (!ld) {
946  error((char *)
947  "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n",
948  LogTime(), PROGRAM, ldapssl_err2string(rc));
949  ldap_unbind_ext(ld, nullptr, nullptr);
950  ld = nullptr;
951  return nullptr;
952  }
953  rc = ldap_set_defaults(ld);
954  if (rc != LDAP_SUCCESS) {
955  error((char *)
956  "%s| %s: ERROR: Error while setting default options for ldap server: %s\n",
957  LogTime(), PROGRAM, ldap_err2string(rc));
958  ldap_unbind_ext(ld, nullptr, nullptr);
959  ld = nullptr;
960  return nullptr;
961  }
962 #else
963  error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n",
964  LogTime(), PROGRAM);
965 #endif
966  }
967  return ld;
968 }
969 
970 /*
971  * ldap calls to get attribute from Ldap Directory Server
972  */
973 int
974 get_memberof(struct main_args *margs, char *user, char *domain, char *group)
975 {
976  LDAP *ld = nullptr;
977  LDAPMessage *res;
978 #if !HAVE_SUN_LDAP_SDK
979  int ldap_debug = 0;
980 #endif
981  struct ldap_creds *lcreds = nullptr;
982  char *bindp = nullptr;
983  char *filter = nullptr;
984  char *search_exp;
985  size_t se_len = 0;
986  struct timeval searchtime;
987  int rc = 0, kc = 1;
988  int retval;
989  char **attr_value = nullptr;
990  size_t max_attr = 0;
991  struct hstruct *hlist = nullptr;
992  size_t nhosts = 0;
993  char *ldap_filter_esc = nullptr;
994 
995  searchtime.tv_sec = SEARCH_TIMEOUT;
996  searchtime.tv_usec = 0;
997  /*
998  * Fill Kerberos memory cache with credential from keytab for SASL/GSSAPI
999  */
1000  if (domain) {
1001  debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n",
1002  LogTime(), PROGRAM);
1003 
1004 #if HAVE_KRB5
1005  if (margs->nokerberos) {
1006  kc = 1;
1007  debug((char *)
1008  "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n",
1009  LogTime(), PROGRAM);
1010  } else {
1011  kc = krb5_create_cache(domain, margs->principal);
1012  if (kc) {
1013  error((char *)
1014  "%s| %s: ERROR: Error during setup of Kerberos credential cache\n",
1015  LogTime(), PROGRAM);
1016  }
1017  }
1018 #else
1019  kc = 1;
1020  debug((char *)
1021  "%s| %s: DEBUG: Kerberos is not supported. Use username/password with ldap url instead\n",
1022  LogTime(), PROGRAM);
1023 #endif
1024  }
1025 
1026  if (kc && (!margs->lurl || !margs->luser || !margs->lpass)) {
1027  /*
1028  * If Kerberos fails and no url given exit here
1029  */
1030  retval = 0;
1031  goto cleanup;
1032  }
1033 #if !HAVE_SUN_LDAP_SDK
1034  /*
1035  * Initialise ldap
1036  */
1037 // ldap_debug = 127 /* LDAP_DEBUG_TRACE */ ;
1038 // ldap_debug = -1 /* LDAP_DEBUG_ANY */ ;
1039  ldap_debug = 0;
1040  (void) ldap_set_option(nullptr, LDAP_OPT_DEBUG_LEVEL, &ldap_debug);
1041 #endif
1042  debug((char *) "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(),
1043  PROGRAM);
1044 
1045  if (domain && !kc) {
1046  if (margs->ssl) {
1047  debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n",
1048  LogTime(), PROGRAM);
1049  }
1050  debug((char *)
1051  "%s| %s: DEBUG: Canonicalise ldap server name for domain %s\n",
1052  LogTime(), PROGRAM, domain);
1053  /*
1054  * Loop over list of ldap servers of users domain
1055  */
1056  nhosts = get_ldap_hostname_list(margs, &hlist, 0, domain);
1057  for (size_t i = 0; i < nhosts; ++i) {
1058  int port = 389;
1059  if (hlist[i].port != -1)
1060  port = hlist[i].port;
1061  debug((char *)
1062  "%s| %s: DEBUG: Setting up connection to ldap server %s:%d\n",
1063  LogTime(), PROGRAM, hlist[i].host, port);
1064 
1065  ld = tool_ldap_open(margs, hlist[i].host, port, margs->ssl);
1066  if (!ld)
1067  continue;
1068 
1069  /*
1070  * ldap bind with SASL/GSSAPI authentication (only possible if a domain was part of the username)
1071  */
1072 
1073 #if HAVE_SASL_H || HAVE_SASL_SASL_H
1074  debug((char *)
1075  "%s| %s: DEBUG: Bind to ldap server with SASL/GSSAPI\n",
1076  LogTime(), PROGRAM);
1077 
1078  rc = tool_sasl_bind(ld, bindp, margs->ssl);
1079  if (rc != LDAP_SUCCESS) {
1080  error((char *)
1081  "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n",
1082  LogTime(), PROGRAM, ldap_err2string(rc));
1083  ldap_unbind_ext(ld, nullptr, nullptr);
1084  ld = nullptr;
1085  continue;
1086  }
1087  lcreds = (struct ldap_creds *) xmalloc(sizeof(struct ldap_creds));
1088  lcreds->dn = nullptr;
1089  lcreds->pw = margs->ssl ? xstrdup(margs->ssl) : nullptr;
1090  ldap_set_rebind_proc(ld, ldap_sasl_rebind, (char *) lcreds);
1091  if (ld != nullptr) {
1092  debug((char *)
1093  "%s| %s: DEBUG: %s initialised %sconnection to ldap server %s:%d\n",
1094  LogTime(), PROGRAM, ld ? "Successfully" : "Failed to",
1095  margs->ssl ? "SSL protected " : "", hlist[i].host, port);
1096  break;
1097  }
1098 #else
1099  ldap_unbind_ext(ld, nullptr, nullptr);
1100  ld = nullptr;
1101  error((char *) "%s| %s: ERROR: SASL not supported on system\n",
1102  LogTime(), PROGRAM);
1103  continue;
1104 #endif
1105  }
1106  nhosts = free_hostname_list(&hlist, nhosts);
1107  if (ld == nullptr) {
1108  debug((char *)
1109  "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n",
1110  LogTime(), PROGRAM, strerror(errno));
1111  }
1112  if (margs->lbind) {
1113  bindp = xstrdup(margs->lbind);
1114  } else {
1115  bindp = convert_domain_to_bind_path(domain);
1116  }
1117  }
1118  if ((!domain || !ld) && margs->lurl && strstr(margs->lurl, "://")) {
1119  char *hostname;
1120  char *host;
1121  int port;
1122  char *ssl = nullptr;
1123  char *p;
1124  /*
1125  * If username does not contain a domain and a url was given then try it
1126  */
1127  hostname = strstr(margs->lurl, "://") + 3;
1128  ssl = strstr(margs->lurl, "ldaps://");
1129  if (ssl) {
1130  debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n",
1131  LogTime(), PROGRAM);
1132  }
1133  debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name %s\n",
1134  LogTime(), PROGRAM, hostname);
1135  /*
1136  * Loop over list of ldap servers
1137  */
1138  host = xstrdup(hostname);
1139  port = 389;
1140  if ((p = strchr(host, ':'))) {
1141  *p = '\0';
1142  ++p;
1143  port = atoi(p);
1144  }
1145  nhosts = get_hostname_list(&hlist, 0, host);
1146  xfree(host);
1147  for (size_t i = 0; i < nhosts; ++i) {
1148  struct berval cred;
1149  if (margs->lpass) {
1150  cred.bv_val = margs->lpass;
1151  cred.bv_len = strlen(margs->lpass);
1152  }
1153  ld = tool_ldap_open(margs, hlist[i].host, port, ssl);
1154  if (!ld)
1155  continue;
1156  /*
1157  * ldap bind with username/password authentication
1158  */
1159 
1160  debug((char *)
1161  "%s| %s: DEBUG: Bind to ldap server with Username/Password\n",
1162  LogTime(), PROGRAM);
1163  rc = ldap_sasl_bind_s(ld, margs->luser, LDAP_SASL_SIMPLE, &cred,
1164  nullptr, nullptr, nullptr);
1165  if (rc != LDAP_SUCCESS) {
1166  error((char *)
1167  "%s| %s: ERROR: Error while binding to ldap server with Username/Password: %s\n",
1168  LogTime(), PROGRAM, ldap_err2string(rc));
1169  ldap_unbind_ext(ld, nullptr, nullptr);
1170  ld = nullptr;
1171  continue;
1172  }
1173  lcreds = (struct ldap_creds *) xmalloc(sizeof(struct ldap_creds));
1174  lcreds->dn = xstrdup(margs->luser);
1175  lcreds->pw = xstrdup(margs->lpass);
1176  ldap_set_rebind_proc(ld, ldap_simple_rebind, (char *) lcreds);
1177  debug((char *)
1178  "%s| %s: DEBUG: %s set up %sconnection to ldap server %s:%d\n",
1179  LogTime(), PROGRAM, ld ? "Successfully" : "Failed to",
1180  ssl ? "SSL protected " : "", hlist[i].host, port);
1181  break;
1182 
1183  }
1184  nhosts = free_hostname_list(&hlist, nhosts);
1185  xfree(bindp);
1186  if (margs->lbind) {
1187  bindp = xstrdup(margs->lbind);
1188  } else {
1189  bindp = convert_domain_to_bind_path(domain);
1190  }
1191  }
1192  if (ld == nullptr) {
1193  debug((char *)
1194  "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n",
1195  LogTime(), PROGRAM, strerror(errno));
1196  retval = 0;
1197  goto cleanup;
1198  }
1199  /*
1200  * ldap search for user
1201  */
1202  /*
1203  * Check if server is AD by querying for attribute samaccountname
1204  */
1205  margs->AD = 0;
1206  rc = check_AD(margs, ld);
1207  if (rc != LDAP_SUCCESS) {
1208  error((char *)
1209  "%s| %s: ERROR: Error determining ldap server type: %s\n",
1210  LogTime(), PROGRAM, ldap_err2string(rc));
1211  ldap_unbind_ext(ld, nullptr, nullptr);
1212  ld = nullptr;
1213  retval = 0;
1214  goto cleanup;
1215  }
1216  if (margs->AD)
1217  filter = (char *) FILTER_AD;
1218  else
1219  filter = (char *) FILTER;
1220 
1221  ldap_filter_esc = escape_filter(user);
1222 
1223  se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1224  search_exp = (char *) xmalloc(se_len);
1225  snprintf(search_exp, se_len, filter, ldap_filter_esc);
1226 
1227  xfree(ldap_filter_esc);
1228 
1229  debug((char *)
1230  "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n",
1231  LogTime(), PROGRAM, bindp, search_exp);
1232  rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE, search_exp, nullptr, 0,
1233  nullptr, nullptr, &searchtime, 0, &res);
1234  xfree(search_exp);
1235 
1236  if (rc != LDAP_SUCCESS) {
1237  error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n",
1238  LogTime(), PROGRAM, ldap_err2string(rc));
1239  ldap_unbind_ext(ld, nullptr, nullptr);
1240  ld = nullptr;
1241  retval = 0;
1242  goto cleanup;
1243  }
1244  debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM,
1245  ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1
1246  || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1247 
1248  if (ldap_count_entries(ld, res) != 0) {
1249 
1250  if (margs->AD)
1251  max_attr = get_attributes(ld, res, ATTRIBUTE_AD, &attr_value);
1252  else {
1253  max_attr = get_attributes(ld, res, ATTRIBUTE, &attr_value);
1254  }
1255 
1256  /*
1257  * Compare group names
1258  */
1259  retval = 0;
1260  for (size_t k = 0; k < max_attr; ++k) {
1261  char *av = nullptr;
1262 
1263  /* Compare first CN= value assuming it is the same as the group name itself */
1264  av = attr_value[k];
1265  if (!strncasecmp("CN=", av, 3)) {
1266  char *avp = nullptr;
1267  av += 3;
1268  if ((avp = strchr(av, ','))) {
1269  *avp = '\0';
1270  }
1271  }
1272  if (debug_enabled) {
1273  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, k + 1, av);
1274  for (unsigned int n = 0; av[n] != '\0'; ++n)
1275  fprintf(stderr, "%02x", (unsigned char) av[n]);
1276  fprintf(stderr, "\n");
1277  }
1278  if (!strcasecmp(group, av)) {
1279  retval = 1;
1280  if (debug_enabled)
1281  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" matches group name \"%s\"\n", LogTime(),
1282  PROGRAM, k + 1, av, group);
1283  else
1284  break;
1285  } else
1286  debug((char *) "%s| %s: DEBUG: Entry %zu \"%s\" does not match group name \"%s\"\n", LogTime(),
1287  PROGRAM, k + 1, av, group);
1288  }
1289  /*
1290  * Do recursive group search for AD only since posixgroups can not contain other groups
1291  */
1292  if (!retval && margs->AD) {
1293  if (debug_enabled && max_attr > 0) {
1294  debug((char *)
1295  "%s| %s: DEBUG: Perform recursive group search\n",
1296  LogTime(), PROGRAM);
1297  }
1298  for (size_t j = 0; j < max_attr; ++j) {
1299  char *av = nullptr;
1300 
1301  av = attr_value[j];
1302  if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1303  retval = 1;
1304  if (!strncasecmp("CN=", av, 3)) {
1305  char *avp = nullptr;
1306  av += 3;
1307  if ((avp = strchr(av, ','))) {
1308  *avp = '\0';
1309  }
1310  }
1311  if (debug_enabled)
1312  debug((char *) "%s| %s: DEBUG: Entry %zu group \"%s\" is (in)direct member of group \"%s\"\n",
1313  LogTime(), PROGRAM, j + 1, av, group);
1314  else
1315  break;
1316  }
1317  }
1318  }
1319  /*
1320  * Cleanup
1321  */
1322  if (attr_value) {
1323  for (size_t j = 0; j < max_attr; ++j) {
1324  xfree(attr_value[j]);
1325  }
1326  safe_free(attr_value);
1327  }
1328  ldap_msgfree(res);
1329  } else if (ldap_count_entries(ld, res) == 0 && margs->AD) {
1330  ldap_msgfree(res);
1331  ldap_unbind_ext(ld, nullptr, nullptr);
1332  ld = nullptr;
1333  retval = 0;
1334  goto cleanup;
1335  } else {
1336  ldap_msgfree(res);
1337  retval = 0;
1338  }
1339 
1340  if (retval == 0) {
1341  /*
1342  * Check for primary Group membership
1343  */
1344  debug((char *)
1345  "%s| %s: DEBUG: Search for primary group membership: \"%s\"\n",
1346  LogTime(), PROGRAM, group);
1347  if (margs->AD)
1348  filter = (char *) FILTER_AD;
1349  else
1350  filter = (char *) FILTER_UID;
1351 
1352  ldap_filter_esc = escape_filter(user);
1353 
1354  se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1355  search_exp = (char *) xmalloc(se_len);
1356  snprintf(search_exp, se_len, filter, ldap_filter_esc);
1357 
1358  xfree(ldap_filter_esc);
1359 
1360  debug((char *)
1361  "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1362  LogTime(), PROGRAM, bindp, search_exp);
1363  rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE, search_exp, nullptr,
1364  0, nullptr, nullptr, &searchtime, 0, &res);
1365  xfree(search_exp);
1366 
1367  debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(),
1368  PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld,
1369  res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1370 
1371  max_attr = 0;
1372  if (!rc) {
1373  if (margs->AD)
1374  max_attr =
1375  get_attributes(ld, res, ATTRIBUTE_GID_AD, &attr_value);
1376  else
1377  max_attr = get_attributes(ld, res, ATTRIBUTE_GID, &attr_value);
1378  }
1379 
1380  if (max_attr == 1) {
1381  char **attr_value_2 = nullptr;
1382  size_t max_attr_2 = 0;
1383 
1384  if (margs->AD) {
1385  char **attr_value_3 = nullptr;
1386  int *attr_len_3 = nullptr;
1387  size_t max_attr_3 = 0;
1388  uint32_t gid = atoi(attr_value[0]);
1389 
1390  /* Get objectsid and search for group
1391  * with objectsid = domain(objectsid) + primarygroupid */
1392  debug((char *) "%s| %s: DEBUG: Got primaryGroupID %u\n",
1393  LogTime(), PROGRAM, gid);
1394  max_attr_3 =
1395  get_bin_attributes(ld, res, ATTRIBUTE_SID, &attr_value_3,
1396  &attr_len_3);
1397  ldap_msgfree(res);
1398  if (max_attr_3 == 1) {
1399  int len = attr_len_3[0];
1400  if (len < 4) {
1401  debug((char *)
1402  "%s| %s: ERROR: Length %d is too short for objectSID\n",
1403  LogTime(), PROGRAM, len);
1404  rc = 1;
1405  } else {
1406  char *se = nullptr;
1407  attr_value_3[0][len - 1] = ((gid >> 24) & 0xff);
1408  attr_value_3[0][len - 2] = ((gid >> 16) & 0xff);
1409  attr_value_3[0][len - 3] = ((gid >> 8) & 0xff);
1410  attr_value_3[0][len - 4] = ((gid >> 0) & 0xff);
1411 
1412 #define FILTER_SID_1 "(objectSID="
1413 #define FILTER_SID_2 ")"
1414 
1415  se_len =
1416  strlen(FILTER_SID_1) + len * 3 +
1417  strlen(FILTER_SID_2) + 1;
1418  search_exp = (char *) xmalloc(se_len);
1419  snprintf(search_exp, se_len, "%s", FILTER_SID_1);
1420 
1421  for (int j = 0; j < len; j++) {
1422  se = xstrdup(search_exp);
1423  snprintf(search_exp, se_len, "%s\\%02x", se,
1424  attr_value_3[0][j] & 0xFF);
1425  xfree(se);
1426  }
1427  se = xstrdup(search_exp);
1428  snprintf(search_exp, se_len, "%s%s", se, FILTER_SID_2);
1429  xfree(se);
1430 
1431  debug((char *)
1432  "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1433  LogTime(), PROGRAM, bindp, search_exp);
1434  rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1435  search_exp, nullptr, 0, nullptr, nullptr, &searchtime, 0,
1436  &res);
1437  xfree(search_exp);
1438 
1439  debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n",
1440  LogTime(), PROGRAM, ldap_count_entries(ld, res),
1441  ldap_count_entries(ld, res) > 1
1442  || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
1443 
1444  }
1445  } else {
1446  rc = 1;
1447  }
1448  if (attr_value_3) {
1449  size_t j;
1450  for (j = 0; j < max_attr_3; ++j) {
1451  xfree(attr_value_3[j]);
1452  }
1453  safe_free(attr_value_3);
1454  }
1455  if (attr_len_3) {
1456  xfree(attr_len_3);
1457  }
1458  } else {
1459  ldap_msgfree(res);
1460  filter = (char *) FILTER_GID;
1461 
1462  ldap_filter_esc = escape_filter(attr_value[0]);
1463 
1464  se_len = strlen(filter) + strlen(ldap_filter_esc) + 1;
1465  search_exp = (char *) xmalloc(se_len);
1466  snprintf(search_exp, se_len, filter, ldap_filter_esc);
1467 
1468  xfree(ldap_filter_esc);
1469 
1470  debug((char *)
1471  "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n",
1472  LogTime(), PROGRAM, bindp, search_exp);
1473  rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
1474  search_exp, nullptr, 0, nullptr, nullptr, &searchtime, 0, &res);
1475  xfree(search_exp);
1476  }
1477 
1478  if (!rc) {
1479  if (margs->AD)
1480  max_attr_2 =
1481  get_attributes(ld, res, ATTRIBUTE_DN, &attr_value_2);
1482  else
1483  max_attr_2 =
1484  get_attributes(ld, res, ATTRIBUTE, &attr_value_2);
1485  ldap_msgfree(res);
1486  } else {
1487  ldap_msgfree(res);
1488  }
1489  /*
1490  * Compare group names
1491  */
1492  retval = 0;
1493  if (max_attr_2 == 1) {
1494  /* Compare first CN= value assuming it is the same as the group name itself */
1495  char *av = attr_value_2[0];
1496  if (!strncasecmp("CN=", av, 3)) {
1497  char *avp = nullptr;
1498  av += 3;
1499  if ((avp = strchr(av, ','))) {
1500  *avp = '\0';
1501  }
1502  }
1503  if (!strcasecmp(group, av)) {
1504  retval = 1;
1505  debug((char *)
1506  "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n",
1507  LogTime(), PROGRAM, av, group);
1508  } else
1509  debug((char *)
1510  "%s| %s: DEBUG: \"%s\" does not match group name \"%s\"\n",
1511  LogTime(), PROGRAM, av, group);
1512 
1513  }
1514  /*
1515  * Do recursive group search for AD only since posixgroups can not contain other groups
1516  */
1517  if (!retval && margs->AD) {
1518  if (debug_enabled && max_attr_2 > 0) {
1519  debug((char *)
1520  "%s| %s: DEBUG: Perform recursive group search\n",
1521  LogTime(), PROGRAM);
1522  }
1523  for (size_t j = 0; j < max_attr_2; ++j) {
1524  char *av = nullptr;
1525 
1526  av = attr_value_2[j];
1527  if (search_group_tree(margs, ld, bindp, av, group, 1)) {
1528  retval = 1;
1529  if (!strncasecmp("CN=", av, 3)) {
1530  char *avp = nullptr;
1531  av += 3;
1532  if ((avp = strchr(av, ','))) {
1533  *avp = '\0';
1534  }
1535  }
1536  if (debug_enabled) {
1537  debug((char *) "%s| %s: DEBUG: Entry %zu group \"%s\" is (in)direct member of group \"%s\"\n",
1538  LogTime(), PROGRAM, j + 1, av, group);
1539  } else {
1540  break;
1541  }
1542  }
1543  }
1544  }
1545  /*
1546  * Cleanup
1547  */
1548  if (attr_value_2) {
1549  size_t j;
1550  for (j = 0; j < max_attr_2; ++j) {
1551  xfree(attr_value_2[j]);
1552  }
1553  safe_free(attr_value_2);
1554  }
1555 
1556  debug((char *) "%s| %s: DEBUG: Users primary group %s %s\n",
1557  LogTime(), PROGRAM, retval ? "matches" : "does not match",
1558  group);
1559 
1560  } else {
1561  ldap_msgfree(res);
1562  debug((char *)
1563  "%s| %s: DEBUG: Did not find ldap entry for group %s\n",
1564  LogTime(), PROGRAM, group);
1565  }
1566  /*
1567  * Cleanup
1568  */
1569  if (attr_value) {
1570  for (size_t j = 0; j < max_attr; ++j) {
1571  xfree(attr_value[j]);
1572  }
1573  safe_free(attr_value);
1574  }
1575  }
1576  rc = ldap_unbind_ext(ld, nullptr, nullptr);
1577  ld = nullptr;
1578  if (rc != LDAP_SUCCESS) {
1579  error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n",
1580  LogTime(), PROGRAM, ldap_err2string(rc));
1581  }
1582  debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM);
1583 cleanup:
1584  if (lcreds) {
1585  xfree(lcreds->dn);
1586  xfree(lcreds->pw);
1587  xfree(lcreds);
1588  }
1589  xfree(bindp);
1590  return (retval);
1591 }
1592 #endif
1593 
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
char * principal
Definition: support.h:93
#define xmalloc
#define PROGRAM
Definition: support.h:169
int mdepth
Definition: support.h:87
void debug(const char *format,...)
Definition: debug.cc:19
void error(char *format,...)
#define xstrdup
char * host
Definition: support.h:124
char * luser
Definition: support.h:80
size_t free_hostname_list(struct hstruct **hlist, size_t nhosts)
static int port
Definition: ldap_backend.cc:70
char * strerror(int ern)
Definition: strerror.c:22
int AD
Definition: support.h:86
size_t get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, size_t nhosts, char *domain)
int port
Definition: support.h:125
int debug_enabled
Definition: debug.cc:13
#define safe_free(x)
Definition: xalloc.h:73
int get_memberof(struct main_args *margs, char *user, char *domain, char *group)
size_t get_hostname_list(struct hstruct **hlist, size_t nhosts, char *name)
char * lpass
Definition: support.h:81
const char * LogTime(void)
#define xfree
char * pw
Definition: support.h:132
int rc_allow
Definition: support.h:85
char * lbind
Definition: support.h:82
int nokerberos
Definition: support.h:88
char * dn
Definition: support.h:131
static LDAP * ld
Definition: ldap_backend.cc:57
char * ssl
Definition: support.h:84
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126
char * lurl
Definition: support.h:83
int unsigned int
Definition: stub_fd.cc:19

 

Introduction

Documentation

Support

Miscellaneous