Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_ldap_internal.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Internal LDAP Adaptive Framework Adaptor functions
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
16 #include "afw.h"
17 #include "afw_ldap_internal.h"
18 #include "afw_ldap_metadata.h"
19 
20 char * afw_ldap_internal_allattrs[] = { "+", "*", NULL };
21 
22 static const int impl_zero = 0;
23 
24 
25 LDAPMessage *
26 afw_ldap_internal_search_s(
28  int ldap_scope, const afw_utf8_z_t *filter, afw_xctx_t *xctx)
29 {
30  int rv;
31  LDAPMessage *result;
32 
33  rv = ldap_search_s(session->ld, (char *)dn, ldap_scope, (char *)filter,
34  afw_ldap_internal_allattrs, 0, &result);
35  if (result) {
36  afw_pool_register_cleanup_before(session->pub.p, result, NULL,
37  afw_ldap_internal_cleanup_ldap_msgfree, xctx);
38  }
39  if (rv != LDAP_SUCCESS) {
40  AFW_THROW_ERROR_RV_Z(general, ldap, rv, "ldap_search_s() failed.",
41  xctx);
42  }
43 
44  return result;
45 }
46 
47 
48 void
49 afw_ldap_internal_cleanup_ldap_msgfree(
50  void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
51 {
52  ldap_msgfree((LDAPMessage *)data);
53 }
54 
55 void
56 afw_ldap_internal_cleanup_ldap_value_free_len(
57  void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
58 {
59  ldap_value_free_len((struct berval **)data);
60 }
61 
62 void
63 afw_ldap_internal_cleanup_ldap_memfree(
64  void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
65 {
66  ldap_memfree(data);
67 }
68 
69 
70 const afw_utf8_t *
71 afw_ldap_internal_get_object_id(
73  LDAPMessage *e, afw_boolean_t check_base, afw_xctx_t *xctx)
74 {
75  afw_utf8_z_t *dn_z;
76  int errno;
77 
78  dn_z = ldap_get_dn(self->ld, e);
79  if (dn_z) {
80  afw_pool_register_cleanup_before(self->pub.p, dn_z, NULL,
81  afw_ldap_internal_cleanup_ldap_memfree,
82  xctx);
83  }
84  else {
85  ldap_get_option(self->ld, LDAP_OPT_ERROR_NUMBER, &errno);
86  AFW_THROW_ERROR_RV_Z(general, ldap, errno, "ldap_get_dn() error.",
87  xctx);
88  }
89 
90  return afw_utf8_create(dn_z, AFW_UTF8_Z_LEN, xctx->p, xctx);
91 }
92 
93 
94 /* Used on windows to support preventVerifyCert. */
95 #if defined(_WIN32) || defined(WIN32)
96 BOOLEAN impl_prevent_verify_server_cert(
97  PLDAP Connection,
98  PCCERT_CONTEXT *pServerCert
99 )
100 {
101  return TRUE;
102 }
103 #endif
104 
105 void
106 afw_ldap_internal_session_begin(
108  afw_xctx_t *xctx)
109 {
110  afw_ldap_internal_adaptor_t *adaptor =
111  (afw_ldap_internal_adaptor_t *)self->pub.adaptor;
112  const afw_pool_t *p = self->pub.p;
113  const afw_value_t *bind_parameters_value;
114  const afw_object_t *bind_parameters;
115  int rv = 0;
116  apr_ldap_err_t *err = NULL;
117  int version = LDAP_VERSION3;
118  int secure;
119 
120  /* check to see if we're already initialized
121  if (obj->ldap_initialized) {
122  return rc;
123  }*/
124 
125  /* Create an LDAP handle */
126  if (self->adaptor->lud->lud_scheme &&
127  strcmp(self->adaptor->lud->lud_scheme, "ldaps") == 0)
128  {
129  secure = APR_LDAP_SSL;
130  } else
131  secure = APR_LDAP_NONE;
132 
133  rv = apr_ldap_init(afw_pool_get_apr_pool(p), &(self->ld),
134  self->adaptor->lud->lud_host, self->adaptor->lud->lud_port,
135  secure, &err);
136  if (rv != LDAP_SUCCESS) {
137  AFW_THROW_ERROR_RV_Z(general, ldap, rv,
138  (err && err->msg)?err->msg:"Unknown error.", xctx);
139  }
140 
141  /* Set version to 3 as required by OpenLDAP and supported by others. */
142  rv = apr_ldap_set_option(afw_pool_get_apr_pool(p), self->ld,
143  LDAP_OPT_PROTOCOL_VERSION,
144  (void*)&version,
145  &err);
146  if (rv != LDAP_SUCCESS) {
147  AFW_THROW_ERROR_RV_Z(general, ldap, rv, err->msg, xctx);
148  }
149 
150  /* Set prevent verify cert if requested.*/
151  if (adaptor->prevent_verify_cert) {
152  /*
153  * apr_ldap_set_option() doesn't support APR_LDAP_OPT_VERIFY_CERT for
154  * windows.
155  */
156 #if defined(_WIN32) || defined(WIN32)
157  rv = ldap_set_option(self->ld, LDAP_OPT_SERVER_CERTIFICATE,
158  impl_prevent_verify_server_cert);
159 #else
160  rv = apr_ldap_set_option(afw_pool_get_apr_pool(p), self->ld,
161  APR_LDAP_OPT_VERIFY_CERT,
162  &impl_zero,
163  &err);
164 #endif
165  }
166 
167  if (rv != LDAP_SUCCESS) {
168  AFW_THROW_ERROR_RV_Z(general, ldap, rv, err->msg, xctx);
169  }
170 
171  /* Set to use referral.
172  rv = apr_ldap_set_option(xctx->p, self->ld,
173  APR_LDAP_OPT_REFERRALS,
174  (void*)&one,
175  &err);
176  if (rv != LDAP_SUCCESS) {
177  AFW_THROW_ERROR_RV_Z(general, ldap, rv, err->msg, xctx);
178  }
179  */
180 
181  /* Get bind dn and password */
182  bind_parameters_value = afw_value_evaluate(
183  self->adaptor->bind_parameters, p, xctx);
184  if (!afw_value_is_object(bind_parameters_value)) {
185  AFW_THROW_ERROR_FZ(general, xctx,
186  "Invalid bindParameters for adaptorId %" AFW_UTF8_FMT,
187  &adaptor->pub.adaptor_id);
188  }
189  bind_parameters = ((const afw_value_object_t *)bind_parameters_value)
190  ->internal;
191  self->bind_dn_z = afw_object_old_get_property_as_utf8_z(bind_parameters,
192  &afw_ldap_s_dn, p, xctx);
193  self->bind_password_z = afw_object_old_get_property_as_utf8_z(bind_parameters,
194  &afw_ldap_s_password, p, xctx);
195  if (!self->bind_dn_z || !self->bind_password_z) {
196  AFW_THROW_ERROR_FZ(general, xctx,
197  "Invalid bindParameters for adaptorId %" AFW_UTF8_FMT,
198  &adaptor->pub.adaptor_id);
199  }
200 
201 
202  /*
203  * Bind
204  *
205  * Cast const away on bind_dn and bind password since ldap doesn't specify
206  * const on them but also doesn't modify them.
207  */
208  rv = ldap_simple_bind_s(self->ld,
209  (char *)self->bind_dn_z,
210  (char *)self->bind_password_z);
211  if (rv != LDAP_SUCCESS) {
212  AFW_THROW_ERROR_RV_Z(general, ldap, rv,
213  "Error binding with user and password.", xctx);
214  }
215 
216 }
217 
218 void
219 afw_ldap_internal_session_end(afw_ldap_internal_adaptor_session_t *self)
220 {
221  /* Free stuff .... */
222 
223  /* unbind */
224  if (self->ld) {
225  ldap_unbind(self->ld);
226  }
227 }
228 
229 
230 /* Internal create an adaptive object from an LDAPMessage. */
231 const afw_object_t *
232 afw_ldap_internal_create_object_from_entry(
234  const afw_utf8_t *object_type_id,
235  const afw_utf8_t *object_id,
236  LDAPMessage *e,
237  const afw_pool_t *p,
238  afw_xctx_t *xctx)
239 {
240  const afw_object_t *o;
241  char *a;
242  const afw_utf8_t *property_name;
243  BerElement *be;
244  struct berval **bv;
245  const afw_value_t *value;
246  afw_ldap_object_type_attribute_t *first_attribute;
248 
249  if (!object_id || !object_id->s) {
250  object_id = afw_ldap_internal_get_object_id(self, e, FALSE, xctx);
251  }
252 
253  /*
254  * Get first attribute for this object type. There might not be one
255  * early on.
256  */
257  first_attribute = NULL;
258  if (self->adaptor->metadata &&
259  self->adaptor->metadata->object_type_attributes)
260  {
261  first_attribute = apr_hash_get
262  (self->adaptor->metadata->object_type_attributes,
263  object_type_id->s, object_type_id->len);
264  }
265 
266  o = afw_object_create_managed(p, xctx);
267  bv = NULL;
268  a = NULL;
269  be = NULL;
270  AFW_TRY {
271  for (a = ldap_first_attribute(self->ld, e, &be); a;
272  a = ldap_next_attribute(self->ld, e, be))
273  {
274  bv = ldap_get_values_len(self->ld, e, a);
275  property_name = afw_utf8_create_copy(a, AFW_UTF8_Z_LEN,
276  o->p, xctx);
277 
278  /* Get attribute for this property name if there is one. */
280  first_attribute, property_name);
281 
282  /* Change bv to value. */
283  value = afw_ldap_metadata_bv_to_value(self, attribute,
284  property_name, bv, o->p, xctx);
285 
286  /* If there is a value, set its property. */
287  if (value) {
288  afw_object_set_property(o, property_name, value, xctx);
289  }
290 
291  /* Free bv and a. */
292  ldap_value_free_len(bv);
293  bv = NULL;
294  ldap_memfree(a);
295  a = NULL;
296  }
297  }
298  AFW_FINALLY{
299 
300  /* Free bv if needed. */
301  if (bv) {
302  ldap_value_free_len(bv);
303  }
304 
305  /* Free a if needed. */
306  if (a) {
307  ldap_memfree(a);
308  }
309 
310  /* Free be if needed. */
311  if (be) {
312  ber_free(be, 0);
313  }
314  }
315  AFW_ENDTRY;
316 
317  afw_object_meta_set_ids(o, &self->adaptor->pub.adaptor_id,
318  object_type_id, object_id, xctx);
319 
320  return o;
321 }
322 
323 /* useful macro for determining if node, x, is a non-leaf node */
324 #define AFW_QUERY_CRITERIA_CONTINUE(x) \
325  (x != AFW_QUERY_CRITERIA_FALSE && x != AFW_QUERY_CRITERIA_TRUE)
326 
327 /*
328  * afw_ldap_internal_expression_from_filter_entry()
329  *
330  * This routine takes an individual query criteria filter entry
331  * and generates the appropriate LDAP search filter.
332  *
333  */
334 const afw_utf8_t *
335 afw_ldap_internal_expression_from_filter_entry(
337  const afw_query_criteria_filter_entry_t * entry,
338  afw_xctx_t *xctx)
339 {
340  const afw_utf8_t *filter_expression = NULL;
341  const afw_utf8_t *property_name, *property_value;
342  struct berval **bv;
343 
344 
345  if (entry == AFW_QUERY_CRITERIA_FALSE ||
346  entry == AFW_QUERY_CRITERIA_TRUE)
347  {
348  return NULL;
349  }
350 
351  property_name = entry->property_name;
352 
353  /* convert the filter value to a string for LDAP comparison to use */
354  bv = afw_ldap_metadata_value_to_bv(session, property_name, entry->value, xctx);
355  if (bv == NULL) {
356  AFW_THROW_ERROR_Z(general,
357  "Query criteria could not be converted into an LDAP filter string.", xctx);
358  }
359 
360  /* turn it into an afw string for easy use by the format routines */
361  property_value = afw_utf8_create((*bv)->bv_val, (*bv)->bv_len, xctx->p, xctx);
362 
363  switch (entry->op_id) {
364  case afw_query_criteria_filter_op_id_eq:
365  filter_expression = afw_utf8_printf(xctx->p, xctx,
366  "%" AFW_UTF8_FMT "=%" AFW_UTF8_FMT,
367  AFW_UTF8_FMT_ARG(property_name),
368  AFW_UTF8_FMT_ARG(property_value));
369  break;
370  case afw_query_criteria_filter_op_id_ne:
371  filter_expression = afw_utf8_printf(xctx->p, xctx,
372  "!(%" AFW_UTF8_FMT "=%" AFW_UTF8_FMT ")",
373  AFW_UTF8_FMT_ARG(property_name),
374  AFW_UTF8_FMT_ARG(property_value));
375  break;
376  case afw_query_criteria_filter_op_id_lt:
377  filter_expression = afw_utf8_printf(xctx->p, xctx,
378  "%" AFW_UTF8_FMT "<%" AFW_UTF8_FMT,
379  AFW_UTF8_FMT_ARG(property_name),
380  AFW_UTF8_FMT_ARG(property_value));
381  break;
382  case afw_query_criteria_filter_op_id_le:
383  filter_expression = afw_utf8_printf(xctx->p, xctx,
384  "%" AFW_UTF8_FMT "<=%" AFW_UTF8_FMT,
385  AFW_UTF8_FMT_ARG(property_name),
386  AFW_UTF8_FMT_ARG(property_value));
387  break;
388  case afw_query_criteria_filter_op_id_gt:
389  filter_expression = afw_utf8_printf(xctx->p, xctx,
390  "%" AFW_UTF8_FMT ">%" AFW_UTF8_FMT,
391  AFW_UTF8_FMT_ARG(property_name),
392  AFW_UTF8_FMT_ARG(property_value));
393  break;
394  case afw_query_criteria_filter_op_id_ge:
395  filter_expression = afw_utf8_printf(xctx->p, xctx,
396  "%" AFW_UTF8_FMT ">=%" AFW_UTF8_FMT,
397  AFW_UTF8_FMT_ARG(property_name),
398  AFW_UTF8_FMT_ARG(property_value));
399  break;
400  default:
401  AFW_THROW_ERROR_Z(general,
402  "query operator not supported by LDAP", xctx);
403  break;
404  }
405 
406  return filter_expression;
407 }
408 
409 /*
410  *
411  */
412 const afw_utf8_t *
413 afw_ldap_internal_expression_from_query_criteria(
415  const afw_query_criteria_filter_entry_t * entry,
416  afw_xctx_t *xctx)
417 {
418  const afw_utf8_t *filter_expression = NULL;
419  const afw_utf8_t *on_true;
420  const afw_utf8_t *on_false;
421 
422  filter_expression = afw_ldap_internal_expression_from_filter_entry(
423  session, entry, xctx);
424 
425  /* A bottom leaf of our decision tree, so return our expression */
426  if (entry->on_true == AFW_QUERY_CRITERIA_TRUE &&
427  entry->on_false == AFW_QUERY_CRITERIA_FALSE)
428  {
429  return filter_expression;
430  }
431 
432  /* (entry AND on_true) OR (on_false) */
433  else if (AFW_QUERY_CRITERIA_CONTINUE(entry->on_true) &&
434  AFW_QUERY_CRITERIA_CONTINUE(entry->on_false))
435  {
436  on_true = afw_ldap_internal_expression_from_query_criteria(
437  session, entry->on_true, xctx);
438  on_false = afw_ldap_internal_expression_from_query_criteria(
439  session, entry->on_false, xctx);
440 
441  /* (|(&(filter_expression)(on_true))(on_false)) */
442  filter_expression = afw_utf8_printf(xctx->p, xctx,
443  "|(&(%" AFW_UTF8_FMT ")(%" AFW_UTF8_FMT "))(%" AFW_UTF8_FMT ")",
444  AFW_UTF8_FMT_ARG(filter_expression),
445  AFW_UTF8_FMT_ARG(on_true), AFW_UTF8_FMT_ARG(on_false));
446  }
447 
448  /* (entry AND on_true) */
449  else if (AFW_QUERY_CRITERIA_CONTINUE(entry->on_true))
450  {
451  on_true = afw_ldap_internal_expression_from_query_criteria(
452  session, entry->on_true, xctx);
453 
454  /* (&(filter_expression)(on_true)) */
455  filter_expression = afw_utf8_printf(xctx->p, xctx, "&(%" AFW_UTF8_FMT ")(%" AFW_UTF8_FMT ")",
456  filter_expression->len, filter_expression->s,
457  on_true->len, on_true->s);
458  }
459 
460  /* (entry OR on_false) */
461  else if (AFW_QUERY_CRITERIA_CONTINUE(entry->on_false))
462  {
463  on_false = afw_ldap_internal_expression_from_query_criteria(
464  session, entry->on_false, xctx);
465 
466  /* (|(filter_expression)(on_false)) */
467  filter_expression = afw_utf8_printf(xctx->p, xctx,
468  "|(%" AFW_UTF8_FMT ")(%" AFW_UTF8_FMT ")",
469  AFW_UTF8_FMT_ARG(filter_expression),
470  AFW_UTF8_FMT_ARG(on_false));
471  }
472 
473  return filter_expression;
474 
475 }
Adaptive Framework Core API.
Adaptive Framework LDAP Internal Header
afw_ldap_object_type_attribute_t * afw_ldap_metadata_get_object_type_attribute(afw_ldap_object_type_attribute_t *first, const afw_utf8_t *name)
Return afw_ldap_object_type_attribute_t * for name.
Adaptive Framework LDAP Metadata Header.
#define afw_value_is_object(A_VALUE)
Macro to determine if value is evaluated object.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
#define AFW_UTF8_Z_LEN
String is NUL (0) terminate.
Definition: afw_common.h:266
_Bool afw_boolean_t
Definition: afw_common.h:373
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
#define AFW_FINALLY
Always executed regardless of error.
Definition: afw_error.h:702
#define AFW_THROW_ERROR_RV_Z(code, rv_source_id, rv, message_z, xctx)
Macro used to set error and rv in xctx and throw it.
Definition: afw_error.h:301
#define AFW_ENDTRY
Ends an AFW try block.
Definition: afw_error.h:727
#define AFW_TRY
Begin an AFW TRY block.
Definition: afw_error.h:634
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
afw_object_meta_set_ids(const afw_object_t *instance, const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, afw_xctx_t *xctx)
Set object's ids.
afw_object_old_get_property_as_utf8_z(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_pool_t *p, afw_xctx_t *xctx)
Get an object's property value including ancestors as utf8_z in specified pool.
Definition: afw_object.c:555
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_register_cleanup_before(instance, data, data2, cleanup, xctx)
Call method register_cleanup_before of interface afw_pool.
#define AFW_QUERY_CRITERIA_FALSE
#define AFW_QUERY_CRITERIA_TRUE
#define afw_utf8_create_copy(s, len, p, xctx)
Make a utf-8 sting from chars in pool specified.
Definition: afw_utf8.h:369
afw_utf8_printf(const afw_pool_t *p, afw_xctx_t *xctx, const afw_utf8_z_t *format,...)
Create a utf-8 string using a c format string in specified pool.
Definition: afw_utf8.c:459
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
#define afw_value_evaluate(value, p, xctx)
Evaluate value if needed using specific pool.
Definition: afw_value.h:841
Interface afw_object public struct.
Interface afw_pool public struct.
Parsed filter entry from query string.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
struct for data type object values.
Interface afw_value public struct.
Interface afw_xctx public struct.