support_ldap.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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);
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 
const char * LogTime(void)
char * strerror(int ern)
Definition: strerror.c:22
static LDAP * ld
Definition: ldap_backend.cc:56
int mdepth
Definition: support.h:107
#define xcalloc
Definition: membanger.c:57
int debug_enabled
Definition: debug.cc:13
void error(char *format,...)
int i
Definition: membanger.c:49
#define xstrdup
#define safe_free(x)
Definition: xalloc.h:73
int get_memberof(struct main_args *margs, char *user, char *domain, char *group)
char * p
Definition: membanger.c:43
size_t get_hostname_list(struct hstruct **hlist, size_t nhosts, char *name)
char * lbind
Definition: support.h:102
char * luser
Definition: support.h:100
size_t get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, size_t nhosts, char *domain)
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:137
char * ssl
Definition: support.h:104
static int debug
Definition: tcp-banger3.c:105
char * host
Definition: support.h:143
int rc_allow
Definition: support.h:105
static int port
Definition: ldap_backend.cc:69
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
int AD
Definition: support.h:106
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
#define xmalloc
int nokerberos
Definition: support.h:108
char * lpass
Definition: support.h:101
#define PROGRAM
Definition: support.h:188
int port
Definition: support.h:144
char * lurl
Definition: support.h:103
#define xfree
char * dn
Definition: support.h:150
#define NULL
Definition: types.h:166
char * pw
Definition: support.h:151
size_t free_hostname_list(struct hstruct **hlist, size_t nhosts)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors