The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
proto_ldap_sync_ldap.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 38f2d8280a2713a5b8ba7e043afd2dfac8f18be9 $
19  * @file proto_ldap_sync_ldap.c
20  * @brief LDAP sync handler.
21  *
22  * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
23  */
25 
26 #define LOG_PREFIX "proto_ldap_sync_ldap"
27 
28 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
29 #include <freeradius-devel/internal/internal.h>
30 #include <freeradius-devel/server/protocol.h>
31 #include <freeradius-devel/server/request.h>
32 #include <freeradius-devel/io/listen.h>
33 #include <freeradius-devel/io/application.h>
34 #include <freeradius-devel/unlang/call.h>
35 #include <freeradius-devel/util/dbuff.h>
36 #include <freeradius-devel/ldap/base.h>
37 #include <freeradius-devel/ldap/conf.h>
38 
39 #include "proto_ldap_sync_ldap.h"
40 #include "rfc4533.h"
41 #include "persistent_search.h"
42 #include "active_directory.h"
43 
45 
48 
50  /*
51  * LDAP server definition
52  */
54 
55  /*
56  * Common LDAP conf parsers
57  */
59 
60  /*
61  * Network tunable parameters
62  */
63  { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, proto_ldap_sync_ldap_t, recv_buff) },
64  { FR_CONF_OFFSET("max_outstanding", proto_ldap_sync_ldap_t, max_outstanding), .dflt = "65536" },
65 
67 };
68 
69 static fr_dict_t const *dict_ldap_sync;
70 static fr_dict_t const *dict_freeradius;
71 
74  { .out = &dict_ldap_sync, .proto = "ldap" },
75  { .out = &dict_freeradius, .proto = "freeradius" },
76  { NULL }
77 };
78 
87 
90  { .out = &attr_ldap_sync_packet_id, .name = "Sync-Packet-ID", .type = FR_TYPE_UINT32, .dict = &dict_ldap_sync },
91  { .out = &attr_ldap_sync_cookie, .name = "LDAP-Sync.Cookie", .type = FR_TYPE_OCTETS, .dict = &dict_ldap_sync },
92  { .out = &attr_ldap_sync_entry_dn, .name = "LDAP-Sync.Entry-DN", .type = FR_TYPE_STRING, .dict = &dict_ldap_sync },
93  { .out = &attr_ldap_sync_entry_uuid, .name = "LDAP-Sync.Entry-UUID", .type = FR_TYPE_OCTETS, .dict = &dict_ldap_sync },
94  { .out = &attr_ldap_sync_orig_dn, .name = "LDAP-Sync.Original-DN", .type = FR_TYPE_STRING, .dict = &dict_ldap_sync },
95  { .out = &attr_ldap_sync_root_dn, .name = "LDAP-Sync.Directory-Root-DN", .type = FR_TYPE_STRING, .dict = &dict_ldap_sync },
96  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_ldap_sync },
97  { .out = &attr_ldap_sync_base_dn, .name = "LDAP-Sync-Base-DN", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
98  { NULL }
99 };
100 
105 };
106 
107 /** Operations performed on entries
108  */
110  { L("add"), SYNC_OP_ADD },
111  { L("delete"), SYNC_OP_DELETE },
112  { L("modify"), SYNC_OP_MODIFY },
113  { L("present"), SYNC_OP_PRESENT },
114 };
116 
117 /** Context used when looking up Directory types
118  */
119 typedef struct {
123  int msgid;
125 
126 /** Context for "load Cookie" retry timed event
127  */
128 typedef struct {
131  size_t sync_no;
133 
134 /** Compare two sync state structures on msgid
135  *
136  * @param[in] one first sync to compare.
137  * @param[in] two second sync to compare.
138  * @return CMP(one, two)
139  */
140 int8_t sync_state_cmp(void const *one, void const *two)
141 {
142  sync_state_t const *a = one, *b = two;
143 
144  return CMP(a->msgid, b->msgid);
145 }
146 
147 /** Tell the remote server to stop the sync
148  *
149  * Terminates the search informing the remote server that we no longer want to receive results
150  * for this sync. A RFC 4511 abandon request is used to inform the server.
151  *
152  * This allows individual syncs to be stopped without destroying the underlying connection.
153  *
154  * Removes the sync's msgid from the tree of msgids associated with the connection.
155  *
156  * @param[in] sync to abandon.
157  * @return 0
158  */
159 static int sync_state_free(sync_state_t *sync)
160 {
161  fr_ldap_connection_t *conn = talloc_get_type_abort(sync->conn, fr_ldap_connection_t);
162  fr_rb_tree_t *tree = talloc_get_type_abort(conn->uctx, fr_rb_tree_t);
163 
164  DEBUG3("Abandoning sync base dn \"%s\", filter \"%s\"", sync->config->base_dn, sync->config->filter);
165 
166  trigger_exec(NULL, sync->config->cs, "ldap_sync.stop", true, &sync->trigger_args);
167 
168  if (!sync->conn->handle) return 0; /* Handled already closed? */
169 
170  /*
171  * Tell the remote server to stop sending results
172  */
173  if (sync->msgid >= 0) ldap_abandon_ext(sync->conn->handle, sync->msgid, NULL, NULL);
174  fr_rb_delete(tree, &(sync_state_t){.msgid = sync->msgid});
175 
176  return 0;
177 }
178 
179 /** Allocate a sync state
180  *
181  * @param[in] ctx to allocate the sync state in.
182  * @param[in] conn which the sync will run on.
183  * @param[in] inst module instance for the sync.
184  * @param[in] sync_no number of the sync in the array of configs.
185  * @param[in] config for the sync.
186  * @return new sync state.
187  */
189  size_t sync_no, sync_config_t const *config)
190 {
191  sync_state_t *sync;
192  fr_pair_t *vp;
193 
194  MEM(sync = talloc_zero(ctx, sync_state_t));
195  sync->conn = conn;
196  sync->inst = inst;
197  sync->config = config;
198  sync->sync_no = sync_no;
199  sync->phase = SYNC_PHASE_INIT;
200 
202 
203  /*
204  * Create arguments to pass to triggers
205  */
208  talloc_array_length(config->base_dn) - 1, false);
209 
210  /*
211  * If the connection is freed, all the sync state is also freed
212  */
213  talloc_set_destructor(sync, sync_state_free);
214 
215  return sync;
216 }
217 
218 /** Add a new cookie packet ctx to the pending list
219  *
220  * Does not actually send the packet.
221  *
222  * @param[in] sync the cookie was received for.
223  * @param[in] refresh the sync after storing this cookie.
224  * @return
225  * - 0 on success.
226  * - -1 on failure
227  */
228 int ldap_sync_cookie_store(sync_state_t *sync, bool refresh)
229 {
230  sync_packet_ctx_t *sync_packet_ctx = NULL;
231  uint8_t *cookie = sync->cookie;
232 
233  MEM(sync_packet_ctx = talloc_zero(sync, sync_packet_ctx_t));
234  sync_packet_ctx->sync = sync;
235 
236  sync_packet_ctx->type = SYNC_PACKET_TYPE_COOKIE;
237  if (cookie) sync_packet_ctx->cookie = talloc_memdup(sync_packet_ctx, cookie, talloc_array_length(cookie));
238  sync_packet_ctx->refresh = refresh;
239 
240  if (fr_dlist_insert_tail(&sync->pending, sync_packet_ctx) < 0) {
241  talloc_free(sync_packet_ctx);
242  return -1;
243  }
244  sync->pending_cookies++;
245 
246  return 0;
247 }
248 
249 /** Event to handle storing of cookies on a timed basis
250  *
251  * Looks at the head of the list of pending sync packets for a cookie.
252  * A cookie at the head says that all the previous changes have been
253  * completed, so the cookie can be sent.
254  */
256 {
257  sync_state_t *sync = talloc_get_type_abort(uctx, sync_state_t);
258  sync_packet_ctx_t *sync_packet_ctx;
259 
260  if (sync->pending_cookies == 0) goto finish;
261 
262  /*
263  * Check the head entry in the list - is it a pending cookie
264  */
265  sync_packet_ctx = fr_dlist_head(&sync->pending);
266  if ((sync_packet_ctx->type != SYNC_PACKET_TYPE_COOKIE) ||
267  (sync_packet_ctx->status != SYNC_PACKET_PENDING)) goto finish;
268 
269  ldap_sync_cookie_send(sync_packet_ctx);
270 
271 finish:
272  (void) fr_event_timer_in(sync, el, &sync->cookie_ev, sync->inst->cookie_interval, ldap_sync_cookie_event, sync);
273 }
274 
275 /** Enqueue a new cookie store packet
276  *
277  * Create a new internal packet containing the cookie we received from the LDAP server.
278  * This allows the administrator to store the cookie and provide it on a future call to
279  * load Cookie.
280  *
281  * @param[in] sync_packet_ctx packet context containing the cookie to store.
282  * @return
283  * - 0 on success.
284  * - -1 on failure.
285 */
287 {
288  sync_state_t *sync = sync_packet_ctx->sync;
289  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(sync->config->user_ctx, proto_ldap_sync_ldap_thread_t);
290  fr_dbuff_t *dbuff;
291  fr_pair_list_t pairs;
292  fr_pair_t *vp;
293  TALLOC_CTX *local = NULL;
294  uint8_t *cookie = sync_packet_ctx->cookie;
295 
296  if (sync_packet_ctx->status != SYNC_PACKET_PENDING) return 0;
297  sync_packet_ctx->status = SYNC_PACKET_PREPARING;
298 
299  FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096);
300 
301  local = talloc_new(NULL);
302  fr_pair_list_init(&pairs);
303  if (fr_pair_list_copy(local, &pairs, &sync->config->sync_pairs) < 0) {
304  error:
305  talloc_free(local);
306  return -1;
307  }
308 
310  if (!vp) goto error;
311 
313  if (!vp) goto error;
314 
315  /*
316  * Add the cookie to the packet, if set.
317  * If the server has indicated a refresh is required it can do so
318  * with no cookie set - so we store a blank cookie to clear anything
319  * which was previously stored.
320  */
321  if (cookie) {
323  cookie, talloc_array_length(cookie), true);
324  if (!vp) goto error;
325  }
326 
327  if (fr_internal_encode_list(dbuff, &pairs, &encode_ctx) < 0) goto error;
328  talloc_free(local);
329 
330  if (fr_network_listen_send_packet(thread->nr, thread->li, thread->li, fr_dbuff_buff(dbuff),
331  fr_dbuff_used(dbuff), fr_time(), sync_packet_ctx) < 0) {
332  sync_packet_ctx->status = SYNC_PACKET_PENDING;
333  return -1;
334  }
335 
336  sync_packet_ctx->status = SYNC_PACKET_PROCESSING;
337 
338  return 0;
339 }
340 
341 /** Send a change packet to the workers
342  *
343  * Called each time a change packet is received and also from a
344  * timer event retrying packets which previously failed to send.
345  *
346  * @param sync_packet_ctx Packet to send
347  * @return
348  * - 0 on success.
349  * - -1 on failure.
350  */
352 {
353  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(sync_packet_ctx->sync->config->user_ctx,
355  fr_dbuff_t *dbuff;
356 
357  FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096);
358 
359  if (fr_internal_encode_list(dbuff, &sync_packet_ctx->pairs, &encode_ctx) < 0) return -1;
360  if (fr_network_listen_send_packet(thread->nr, thread->li, thread->li, fr_dbuff_buff(dbuff),
361  fr_dbuff_used(dbuff), fr_time(), sync_packet_ctx) < 0) return -1;
362 
363  sync_packet_ctx->status = SYNC_PACKET_PROCESSING;
364  fr_pair_list_free(&sync_packet_ctx->pairs);
365 
366  return 0;
367 }
368 
369 /** Event to handle sending of any change packets which failed to send.
370  *
371  * Looks at the head of the list of pending sync packets for unsent
372  * change packets and sends any up to the first cookie.
373  */
375 {
376  sync_state_t *sync = talloc_get_type_abort(uctx, sync_state_t);
377  sync_packet_ctx_t *sync_packet_ctx = NULL;
378 
379  while ((sync_packet_ctx = fr_dlist_next(&sync->pending, sync_packet_ctx))) {
380  if (sync_packet_ctx->type != SYNC_PACKET_TYPE_CHANGE) break;
381  if (sync_packet_ctx->status != SYNC_PACKET_PENDING) continue;
382 
383  /*
384  * Retry sending packet. Don't try any more if it fails.
385  */
386  if (ldap_sync_entry_send_network(sync_packet_ctx) < 0) break;
387  }
388 
389  /*
390  * We didn't run through the whole list, so there may be other pending
391  * packets - reschedule a retry event.
392  */
393  if (sync_packet_ctx) {
394  (void) fr_event_timer_in(sync, el, &sync->retry_ev, sync->inst->retry_interval,
395  ldap_sync_retry_event, sync);
396  }
397 }
398 
404 };
405 
406 /** Enqueue a new entry change packet.
407  *
408  * @param[in] sync notification has arrived for.
409  * @param[in] uuid of the entry (RFC 4533 only).
410  * @param[in] orig_dn original DN of the entry - provided by those directories
411  * implementing persistent search, when an entry is renamed.
412  * @param[in] msg containing the entry.
413  * @param[in] op The type of modification we need to perform to our
414  * representation of the entry.
415  * @return
416  * - 0 on success.
417  * - -1 on failure.
418  */
419 int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH], struct berval *orig_dn,
420  LDAPMessage *msg, sync_op_t op)
421 {
423  fr_pair_list_t *pairs;
424  fr_pair_t *vp;
425  sync_packet_ctx_t *sync_packet_ctx = NULL;
426 
427  MEM(sync_packet_ctx = talloc_zero(sync, sync_packet_ctx_t));
428  sync_packet_ctx->sync = sync;
429 
430  fr_pair_list_init(&sync_packet_ctx->pairs);
431  pairs = &sync_packet_ctx->pairs;
432 
433  if (fr_pair_list_copy(sync_packet_ctx, pairs, &sync->config->sync_pairs) < 0) {
434  error:
435  if (msg) ldap_msgfree(msg);
436  talloc_free(sync_packet_ctx);
437  return -1;
438  }
439 
440  pcode = sync_packet_code_table[op];
441 
442  fr_pair_list_append_by_da(sync_packet_ctx, vp, pairs, attr_packet_type, (uint32_t)pcode, false);
443  if (!vp) goto error;
444 
445  fr_pair_list_append_by_da(sync_packet_ctx, vp, pairs, attr_ldap_sync_packet_id, (uint32_t)sync->sync_no, false);
446  if (!vp) goto error;
447 
448  /*
449  * Add the UUID if provided
450  */
451  if (uuid) {
453  uuid, SYNC_UUID_LENGTH, true);
454  if (!vp) goto error;
455  }
456 
457  /*
458  * Add the original DN if provided
459  */
460  if (orig_dn && (orig_dn->bv_len > 0)) {
462  orig_dn->bv_val, orig_dn->bv_len, true);
463  if (!vp) goto error;
464  }
465 
466  /*
467  * Add the entry DN if there is an LDAP message to read
468  */
469  if (msg) {
470  char *entry_dn = ldap_get_dn(sync->conn->handle, msg);
471  map_t const *map = NULL;
472  struct berval **values;
473  int count, i;
474 
476  entry_dn, strlen(entry_dn), true);
477  if (!vp) goto error;
478 
479  ldap_memfree(entry_dn);
480 
481  /*
482  * Map LDAP returned attributes to pairs as per update map
483  */
484  while ((map = map_list_next(&sync->config->entry_map, map))) {
485  values = ldap_get_values_len(fr_ldap_handle_thread_local(), msg, map->rhs->name);
486  if (!values) goto next;
487 
488  count = ldap_count_values_len(values);
489 
490  for (i = 0; i < count; i++) {
491  if (values[i]->bv_len == 0) continue;
492 
493  if (pair_append_by_tmpl_parent(sync_packet_ctx, &vp, pairs, map->lhs, true) < 0) break;
494  if (fr_value_box_from_str(vp, &vp->data, vp->vp_type, NULL, values[i]->bv_val,
495  values[i]->bv_len, NULL, true) < 0) {
496  fr_pair_remove(pairs, vp);
497  talloc_free(vp);
498  }
499 
500  /* Only += operator adds multiple values */
501  if (map->op != T_OP_ADD_EQ) break;
502  }
503  next:
504  ldap_value_free_len(values);
505  }
506  }
507 
508  if (fr_dlist_insert_tail(&sync->pending, sync_packet_ctx) < 0) goto error;
509 
510  ldap_msgfree(msg);
511 
512  /*
513  * Send the packet and if it fails to send add a retry event
514  */
515  if ((ldap_sync_entry_send_network(sync_packet_ctx) < 0) &&
516  (fr_event_timer_in(sync, sync->conn->conn->el, &sync->retry_ev,
517  sync->inst->retry_interval, ldap_sync_retry_event, sync) < 0)) {
518  PERROR("Inserting LDAP sync retry timer failed");
519  }
520 
521  return 0;
522 }
523 
525  UNUSED fr_connection_state_t state, void *uctx);
526 
528  UNUSED fr_connection_state_t state, void *uctx);
529 
530 /** Attempt to (re)initialise a connection
531  *
532  * Performs complete re-initialization of a connection. Called during socket_open
533  * to create the initial connection and again any time we need to reopen the connection.
534  *
535  * @param[in] el the event list managing listen event.
536  * @param[in] now current time.
537  * @param[in] user_ctx Listener.
538  */
540 {
541  fr_listen_t *listen = talloc_get_type_abort(user_ctx, fr_listen_t);
542  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(listen->thread_instance, proto_ldap_sync_ldap_thread_t);
544 
545  if (thread->conn) talloc_free(thread->conn);
546 
547  /*
548  * Allocate an outbound LDAP connection
549  */
550  thread->conn = fr_ldap_connection_state_alloc(thread, thread->el, &inst->handle_config, "ldap_sync");
551 
552  if (!thread->conn) {
553  PERROR("Failed (re)initialising connection, will retry in %pV seconds",
554  fr_box_time_delta(inst->handle_config.reconnection_delay));
555 
556  if (fr_event_timer_in(thread, thread->el, &thread->conn_retry_ev,
557  inst->handle_config.reconnection_delay,
558  proto_ldap_connection_init, listen) < 0) {
559  FATAL("Failed inserting event: %s", fr_strerror());
560  }
561  }
562 
563  /*
564  * Add watch functions on the LDAP connection
565  */
567  _proto_ldap_socket_init, true, thread);
568 
570  _proto_ldap_socket_open_connected, true, thread);
571 
572  /*
573  * Signal the connection to start
574  */
576 
577  return;
578 }
579 
580 /** Child listener mod_close
581  *
582  * Ensures the LDAP connection is signalled to close gracefully when
583  * the listener is closed.
584  */
586 {
588 
590  return 0;
591 }
592 
593 /** LDAP sync mod_read for child listener
594  *
595  * Called when there is data to read on the LDAP connection
596  *
597  * Actual packets are created by the various callbacks since a single LDAP
598  * message can result in multiple packets to process e.g.:
599  *
600  * - Sync Info Message with syncInfoValue of syncIdSet can reference
601  * multiple directory entries.
602  * - Various sync related messages can include a new cookie in
603  * addition to their other data.
604  */
606  UNUSED size_t buffer_len, UNUSED size_t *leftover)
607 {
609  fr_ldap_connection_t *conn = talloc_get_type_abort(thread->conn->h, fr_ldap_connection_t);
610  struct timeval poll = { 1, 0 };
611  LDAPMessage *msg = NULL;
612  int ret = 0;
613  fr_ldap_rcode_t rcode;
614  sync_state_t *sync = NULL;
615  fr_rb_tree_t *tree;
616  int type, msgid;
617  LDAPControl **ctrls = NULL;
618  sync_msg_t callback = NULL;
619 
620  fr_assert(conn);
621 
622  /*
623  * If there are already too many outstanding requests just return.
624  * This will (potentially) cause the TCP buffer to fill and push the
625  * backpressure back to the LDAP server.
626  */
627  if (fr_network_listen_outstanding(thread->nr, li) >= thread->inst->max_outstanding) return 0;
628 
629  tree = talloc_get_type_abort(conn->uctx, fr_rb_tree_t);
630 
631  /*
632  * Pull the next outstanding message from this connection.
633  * We process one message at a time so that the message can be
634  * passed to the worker, and freed once the request has been
635  * handled.
636  */
637  ret = ldap_result(conn->handle, LDAP_RES_ANY, LDAP_MSG_ONE, &poll, &msg);
638 
639  switch (ret) {
640  case 0: /*
641  * Timeout - this has been observed if changes are being
642  * processed slowly, the TCP receive buffer fills and
643  * the LDAP directory pauses sending data for a period.
644  * Then all pending changes are processed and the receive buffer
645  * is emptied.
646  * The situation resolves when the directory starts sending
647  * data again.
648  */
649  return 0;
650 
651  case -1:
652  rcode = fr_ldap_error_check(NULL, conn, NULL, NULL);
653  if (rcode == LDAP_PROC_BAD_CONN) return -2;
654  return -1;
655 
656  default:
657  break;
658  }
659 
660  /*
661  * De-multiplex based on msgid
662  */
663  if (!msg) return 0;
664 
665  msgid = ldap_msgid(msg);
666  type = ldap_msgtype(msg);
667 
668  ret = 0;
669  if (msgid == 0) {
670  WARN("Ignoring unsolicited %s message",
672  free_msg:
673  if (ctrls) ldap_controls_free(ctrls);
674  ldap_msgfree(msg);
675  return ret;
676  }
677 
678  sync = fr_rb_find(tree, &(sync_state_t){.msgid = msgid});
679  if (!sync) {
680  WARN("Ignoring msgid %i, doesn't match any outstanding syncs", msgid);
681  goto free_msg;
682  }
683 
684  /*
685  * Check for errors contained within the message.
686  * This has to be per message, as multiple syncs
687  * are multiplexed together on one connection.
688  */
689  switch (fr_ldap_error_check(&ctrls, conn, msg, sync->config->base_dn)) {
690  case LDAP_PROC_SUCCESS:
691  break;
692 
693  /*
694  * The e-syncRefresRequired result code is the server informing us that
695  * the query needs to be restarted for a new refresh phase to run.
696  * It is sent as the result code for a SearchResultsDone message.
697  */
699  if (type != LDAP_RES_SEARCH_RESULT) {
700  PERROR("e-syncRefreshRequired result code received on wrong message type");
701  ret = -1;
702  goto free_msg;
703  }
704 
705  DEBUG2("LDAP Server returned e-syncRefreshRequired");
706  if (sync->config->refresh) {
707  return sync->config->refresh(sync, msg, ctrls);
708  }
709  goto free_msg;
710 
711  /*
712  * Don't think this should happen... but libldap
713  * is wonky sometimes...
714  */
715  case LDAP_PROC_BAD_CONN:
716  PERROR("Connection unusable");
717  ret = -2;
718  goto free_msg;
719 
720  default:
721  sync_error:
722  PERROR("Sync error");
723  ret = -1;
724  goto free_msg;
725  }
726 
727  DEBUG3("Got %s message for sync (msgid %i)",
728  fr_table_str_by_value(sync_ldap_msg_table, type, "<invalid>"), sync->msgid);
729 
730  switch (type) {
731  case LDAP_RES_SEARCH_REFERENCE:
732  case LDAP_RES_SEARCH_ENTRY:
733  callback = sync->config->entry;
734  break;
735 
736  case LDAP_RES_INTERMEDIATE:
737  callback = sync->config->intermediate;
738  break;
739 
740  default:
741  WARN("Ignoring unexpected message type (%i)", type);
742  ret = 0;
743  goto free_msg;
744  }
745 
746  if (callback) {
747  ret = callback(sync, msg, ctrls);
748  } else {
749  /*
750  * Callbacks are responsible for freeing the msg
751  * so if there is no callback, free it.
752  */
753  ldap_msgfree(msg);
754  }
755  if (ret < 0) goto sync_error;
756 
757  ldap_controls_free(ctrls);
758 
759  return 0;
760 }
761 
762 /** Send a fake packet to run the "load Cookie" section
763  *
764  * @param ctx Context to allocate temporary pairs in.
765  * @param inst LDAP sync configuration.
766  * @param sync_no Id of the sync whose.
767  * @param thread Thread specific LDAP sync data.
768  * @return
769  * - 0 on success
770  * - -1 on failure
771  */
772 static int proto_ldap_cookie_load_send(TALLOC_CTX *ctx, proto_ldap_sync_ldap_t const *inst, size_t sync_no,
774  size_t j, len;
775  sync_config_t *config = inst->parent->sync_config[sync_no];
776  fr_pair_list_t pairs;
777  fr_pair_t *vp;
778  fr_dbuff_t *dbuff;
779  fr_ldap_connection_t *ldap_conn = thread->conn->h;
780 
781  fr_pair_list_init(&pairs);
782  if (unlikely(fr_pair_list_copy(ctx, &pairs, &config->sync_pairs) < 0)) return -1;
783 
784  /*
785  * Ensure we have access to the thread instance
786  * in for the demux callbacks
787  */
788  inst->parent->sync_config[sync_no]->user_ctx = thread;
789 
790  /*
791  * Assess the namingContext which applies to this sync
792  */
793  for (j = 0; j < talloc_array_length(ldap_conn->directory->naming_contexts); j++) {
794  len = strlen(ldap_conn->directory->naming_contexts[j]);
795  if (strlen(config->base_dn) < len) continue;
796 
797  if (strncasecmp(&config->base_dn[strlen(config->base_dn)-len],
798  ldap_conn->directory->naming_contexts[j],
799  strlen(ldap_conn->directory->naming_contexts[j])) == 0) {
800  config->root_dn = ldap_conn->directory->naming_contexts[j];
801  break;
802  }
803  }
804 
805  /*
806  * Set up callbacks based on directory type.
807  */
808  switch (ldap_conn->directory->sync_type) {
810  config->init = rfc4533_sync_init;
812  config->intermediate = rfc4533_sync_intermediate;
814  break;
815 
819  break;
820 
824  break;
825 
826  default:
827  fr_assert(0);
828  }
829 
832  if (!vp) return -1;
833  fr_pair_list_append_by_da(ctx, vp, &pairs, attr_ldap_sync_packet_id, (uint32_t)sync_no, false);
834  if (!vp) return -1;
835 
836  if (config->root_dn) {
838  config->root_dn, strlen(config->root_dn), false);
839  if (!vp) return -1;
840  }
841 
842  FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096);
843 
844  if (fr_internal_encode_list(dbuff, &pairs, &encode_ctx) < 0) return -1;
845 
846  if (fr_network_listen_send_packet(thread->nr, thread->li, thread->li,
847  fr_dbuff_buff(dbuff), fr_dbuff_used(dbuff),
848  fr_time(), NULL) < 0) return -1;
849  fr_pair_list_free(&pairs);
850  return 0;
851 }
852 
853 /** Timer event to retry running "load Cookie" on failures
854  *
855  */
857  proto_ldap_cookie_load_retry_ctx *retry_ctx = talloc_get_type_abort(uctx, proto_ldap_cookie_load_retry_ctx);
858 
859  DEBUG2("Retrying \"load Cookie\" for sync no %ld", retry_ctx->sync_no);
860  if (proto_ldap_cookie_load_send(retry_ctx, retry_ctx->inst, retry_ctx->sync_no,
861  retry_ctx->thread) < 0) {
862  ERROR("Failed retrying \"load Cookie\". Will try again in %pV seconds",
864  (void) fr_event_timer_in(retry_ctx->thread->conn->h, el,
865  &retry_ctx->inst->parent->sync_config[retry_ctx->sync_no]->ev,
867  proto_ldap_cookie_load_retry, retry_ctx);
868  return;
869  }
870  talloc_free(retry_ctx);
871 }
872 
873 /** LDAP sync mod_write for child listener
874  *
875  * Handle any returned data after the worker has processed the packet and,
876  * for packets where tracking structures were used, ensure they are freed.
877  */
878 static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t request_time,
879  uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
880 {
883  fr_dbuff_t dbuff;
885  uint32_t packet_id;
886  fr_pair_list_t tmp;
887  fr_pair_t *vp = NULL;
888  ssize_t ret;
889  TALLOC_CTX *local;
890  sync_packet_ctx_t *sync_packet_ctx = NULL;
891 
892  local = talloc_new(NULL);
893  fr_dbuff_init(&dbuff, buffer, buffer_len);
894 
895  if (packet_ctx) sync_packet_ctx = talloc_get_type_abort(packet_ctx, sync_packet_ctx_t);
896 
897  /*
898  * Extract returned attributes into a temporary list
899  */
900  fr_pair_list_init(&tmp);
901 
902  ret = fr_internal_decode_list_dbuff(local, &tmp, fr_dict_root(dict_ldap_sync), &dbuff, NULL);
903  if (ret < 0) goto finish;
904 
905  /*
906  * There should always be a packet ID and code
907  */
909  fr_assert(vp);
910  packet_id = vp->vp_uint32;
911 
912  vp = fr_pair_find_by_da(&tmp, NULL, attr_packet_type);
913  fr_assert(vp);
914  pcode = vp->vp_uint32;
915 
916  switch (pcode) {
918  {
919  uint8_t *cookie = NULL;
920 
921  /*
922  * If the received packet ID is greater than the number of syncs
923  * we have then something very bad has happened
924  */
925  fr_assert (packet_id <= talloc_array_length(inst->parent->sync_config));
926 
927  /*
928  * Look for the returned cookie.
929  */
931  if (vp) cookie = talloc_memdup(inst, vp->vp_octets, vp->vp_length);
932 
933  if (inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent, cookie) < 0) {
934  ret = -1;
935  goto finish;
936  }
937  }
938  break;
939 
941  break;
942 
944  {
945  sync_config_t const *sync_config;
946 
947  if (!sync_packet_ctx || !sync_packet_ctx->refresh) break;
948 
949  /*
950  * Abandon the old sync and start a new one with the relevant cookie.
951  */
952  sync_config = sync_packet_ctx->sync->config;
953  DEBUG3("Restarting sync with base %s", sync_config->base_dn);
954  talloc_free(sync_packet_ctx->sync);
955  if (inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent,
956  sync_packet_ctx->cookie) < 0) {
957  ret = -1;
958  goto finish;
959  }
960  }
961  break;
962 
964  {
966 
967  ERROR("Load Cookie failed for sync %d, retrying in %pV seconds", packet_id,
968  fr_box_time_delta(inst->handle_config.reconnection_delay));
969 
970  MEM(retry_ctx = talloc(thread, proto_ldap_cookie_load_retry_ctx));
971  *retry_ctx = (proto_ldap_cookie_load_retry_ctx){
972  .thread = thread,
973  .inst = inst,
974  .sync_no = packet_id,
975  };
976 
977  (void) fr_event_timer_in(thread->conn->h, thread->el, &inst->parent->sync_config[packet_id]->ev,
978  inst->handle_config.reconnection_delay,
979  proto_ldap_cookie_load_retry, retry_ctx);
980  }
981  break;
982 
983  default:
984  ERROR("Invalid packet type returned %d", pcode);
985  break;
986  }
987 
988  if (sync_packet_ctx) {
989  sync_state_t *sync = sync_packet_ctx->sync;
990  sync_packet_ctx_t *pc;
991  proto_ldap_sync_t *ldap_sync = inst->parent;
992 
993  sync_packet_ctx->status = SYNC_PACKET_COMPLETE;
994 
995  /*
996  * A cookie has been stored, reset the counter of changes
997  */
998  if (sync_packet_ctx->type == SYNC_PACKET_TYPE_COOKIE) sync->changes_since_cookie = 0;
999 
1000  /*
1001  * Pop any processed updates from the head of the list
1002  */
1003  while ((pc = fr_dlist_head(&sync->pending))) {
1004  /*
1005  * If the head entry in the list is a pending cookie but we have
1006  * not processed enough entries and there are more pending
1007  * cookies, mark this one as processed.
1008  */
1009  if ((pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) &&
1010  (sync->changes_since_cookie < ldap_sync->cookie_changes) &&
1011  (sync->pending_cookies > 1)) pc->status = SYNC_PACKET_COMPLETE;
1012 
1013  if (pc->status != SYNC_PACKET_COMPLETE) break;
1014 
1015  /*
1016  * Update counters depending on entry type
1017  */
1018  if (pc->type == SYNC_PACKET_TYPE_COOKIE) {
1019  sync->pending_cookies--;
1020  } else {
1021  sync->changes_since_cookie++;
1022  }
1023  pc = fr_dlist_pop_head(&sync->pending);
1024  talloc_free(pc);
1025  }
1026 
1027  /*
1028  * If the head of the list is a cookie which has not yet
1029  * been processed and sufficient changes have been recorded
1030  * send the cookie.
1031  */
1032  if (pc && (pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) &&
1033  (sync->changes_since_cookie >= ldap_sync->cookie_changes)) ldap_sync_cookie_send(pc);
1034  }
1035 
1036 finish:
1037  fr_pair_list_free(&tmp);
1038  talloc_free(local);
1039 
1040  return ret;
1041 }
1042 
1043 /** Callback for socket errors when running initial root query
1044  */
1046  UNUSED int fd_errno, void *uctx)
1047 {
1048  proto_ldap_dir_ctx *dir_ctx = talloc_get_type_abort(uctx, proto_ldap_dir_ctx);
1049  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(dir_ctx->conn->h, fr_ldap_connection_t);
1050 
1051  talloc_free(dir_ctx);
1052  fr_ldap_state_error(ldap_conn);
1053 }
1054 
1055 /** Callback to process results of initial root query, identifying directory type
1056  */
1057 static void _proto_ldap_socket_open_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1058 {
1059  proto_ldap_dir_ctx *dir_ctx = talloc_get_type_abort(uctx, proto_ldap_dir_ctx);
1060  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(dir_ctx->conn->h, fr_ldap_connection_t);
1063  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(dir_ctx->main_listen->thread_instance,
1065  fr_ldap_rcode_t status;
1066  LDAPMessage *result;
1067 
1068  size_t i;
1069  TALLOC_CTX *local = NULL;
1070 
1071  /*
1072  * Fetch the result. Setting the timeout to 0 here means use
1073  * res_timeout from the configuration.
1074  */
1075  status = fr_ldap_result(&result, NULL, ldap_conn, dir_ctx->msgid, LDAP_MSG_ALL, NULL, fr_time_delta_from_msec(0));
1076  if (status != LDAP_PROC_SUCCESS) {
1077  PERROR("Failed querying for directory type");
1078  if (result) ldap_msgfree(result);
1079  error:
1080  talloc_free(dir_ctx);
1081  if (local) talloc_free(local);
1083  return;
1084  }
1085 
1086  fr_ldap_directory_result_parse(ldap_conn->directory, ldap_conn->handle, result, ldap_conn->config->name);
1087  ldap_msgfree(result);
1088 
1089  /*
1090  * If the server does not support any of the relevant controls, we just
1091  * tidy up - no point in signalling to reconnect.
1092  */
1093  if (ldap_conn->directory->sync_type == FR_LDAP_SYNC_NONE) {
1094  ERROR("LDAP sync configured for directory which does not support any suitable control");
1095  talloc_free(dir_ctx);
1096  fr_connection_signal_halt(ldap_conn->conn);
1097  return;
1098  }
1099 
1100  /*
1101  * We've done all the preparation work on the LDAP connection, now
1102  * use normal network event listeners.
1103  */
1105  fr_network_listen_add(thread->nr, thread->li);
1106 
1107  DEBUG2("Starting sync(s)");
1108 
1109  local = talloc_new(NULL);
1110 
1111  /*
1112  * Sync operations start by sending a fake packet to run
1113  * the load Cookie section in order to retrieve the cookie
1114  */
1115  for (i = 0; i < talloc_array_length(inst->parent->sync_config); i++) {
1116  if (proto_ldap_cookie_load_send(local, inst, i, thread) < 0) goto error;
1117  }
1118 
1119  talloc_free(dir_ctx);
1120  talloc_free(local);
1121 }
1122 
1123 /** Allocate a child listener
1124  *
1125  * Called as a watch function when the LDAP connection enters the INIT state
1126  */
1128  UNUSED fr_connection_state_t state, void *uctx)
1129 {
1130  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(uctx, proto_ldap_sync_ldap_thread_t);
1131  fr_listen_t *li;
1132 
1133  MEM(li = talloc_zero(conn, fr_listen_t));
1134 
1135  thread->li = li;
1136  li->thread_instance = thread;
1137 
1139  li->name = li->app_io->common.name;
1141 
1142  /*
1143  * Use the app from the parent listener to access
1144  * the encoder / decoder functions
1145  */
1146  li->app = thread->parent->app;
1147  li->app_instance = thread->parent->app_instance;
1148  li->server_cs = thread->inst->parent->server_cs;
1149 }
1150 
1151 /** Callback for closure of LDAP connection
1152  *
1153  * Schedules re-start of the connection if appropriate
1154  */
1156  UNUSED fr_connection_state_t state, void *uctx)
1157 {
1158  fr_listen_t *listen = talloc_get_type_abort(uctx, fr_listen_t);
1159  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(listen->thread_instance, proto_ldap_sync_ldap_thread_t);
1160  proto_ldap_sync_ldap_t const *inst = thread->inst;
1161 
1162  if (fr_event_loop_exiting(thread->el)) return;
1163 
1164  if (prev == FR_CONNECTION_STATE_CONNECTED) {
1165  ERROR("LDAP connection closed. Scheduling restart in %pVs",
1166  fr_box_time_delta(inst->handle_config.reconnection_delay));
1167  if (fr_event_timer_in(thread, thread->el, &thread->conn_retry_ev,
1168  inst->handle_config.reconnection_delay,
1169  proto_ldap_connection_init, listen) < 0) {
1170  FATAL("Failed inserting event: %s", fr_strerror());
1171  }
1172  }
1173 }
1174 
1175 /** Query an LDAP server to establish its type
1176  *
1177  * Called as a watch function once the LDAP connection enters the CONNECTED state
1178  *
1179  * There are three different forms of LDAP sync/persistent search - so we need
1180  * to know what we're dealing with, and whether the relevant options have been enabled.
1181  */
1183  UNUSED fr_connection_state_t state, void *uctx)
1184 {
1185  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(uctx, proto_ldap_sync_ldap_thread_t);
1186  fr_listen_t *listen = talloc_get_type_abort(thread->parent, fr_listen_t);
1189  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(conn->h, fr_ldap_connection_t);
1190 
1191  proto_ldap_dir_ctx *dir_ctx;
1192 
1193  if (ldap_conn->fd < 0) {
1194  connection_failed:
1195  if (fr_event_timer_in(thread, thread->el, &thread->conn_retry_ev,
1196  inst->handle_config.reconnection_delay,
1197  proto_ldap_connection_init, listen) < 0) {
1198  FATAL("Failed inserting event: %s", fr_strerror());
1199  }
1200  return;
1201  }
1202 
1203  thread->li->fd = ldap_conn->fd;
1204 
1205  MEM(dir_ctx = talloc_zero(inst, proto_ldap_dir_ctx));
1206  if (!dir_ctx) goto connection_failed;
1207 
1208  dir_ctx->main_listen = listen;
1209  dir_ctx->conn = conn;
1210  dir_ctx->child_listen = thread->li;
1211 
1212 #ifdef SO_RCVBUF
1213  if (inst->recv_buff_is_set) {
1214  int opt;
1215 
1216  opt = inst->recv_buff;
1217  if (setsockopt(ldap_conn->fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(int)) < 0) {
1218  WARN("Failed setting 'recv_buff': %s", fr_syserror(errno));
1219  }
1220  }
1221 #endif
1222 
1223  /*
1224  * Set the callback which will handle the results of this query
1225  */
1226  if (fr_event_fd_insert(conn, NULL, conn->el, ldap_conn->fd,
1228  NULL,
1230  dir_ctx) < 0) {
1231  goto connection_failed;
1232  }
1233 
1234  /*
1235  * Allocate the directory structure and send the query
1236  */
1237  dir_ctx->msgid = fr_ldap_conn_directory_alloc_async(ldap_conn);
1238 
1239  if (dir_ctx->msgid < 0) {
1240  talloc_free(dir_ctx);
1241  goto connection_failed;
1242  }
1243 
1244  /*
1245  * Add a watch to catch closed LDAP connections
1246  */
1248  _proto_ldap_socket_closed, true, listen);
1249 }
1250 
1251 /** Callback triggered when parent listener app_io has its event list set
1252  *
1253  * Initiates the actual outbound LDAP connection
1254  *
1255  * @param[in] li The parent listener.
1256  * @param[in] el Event list for this listener.
1257  * @param[in] nr Network handler.
1258  */
1259 static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
1260 {
1262  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_ldap_sync_ldap_thread_t);
1263 
1264  /*
1265  * Set up thread data
1266  */
1267  thread->name = inst->handle_config.name;
1268  thread->parent = li;
1269  thread->el = el;
1270  thread->nr = nr;
1271  thread->inst = inst;
1272 
1273  /*
1274  * Initialise the connection
1275  */
1277 }
1278 
1279 static int mod_instantiate(module_inst_ctx_t const *mctx)
1280 {
1281  proto_ldap_sync_ldap_t *inst = talloc_get_type_abort(mctx->inst->data, proto_ldap_sync_ldap_t);
1282  CONF_SECTION *conf = mctx->inst->conf;
1283  char const *server;
1284 
1285  /*
1286  * Verify that the LDAP server configuration is valid, either
1287  * distinct server and port or an LDAP url.
1288  */
1289  fr_assert(inst->server);
1290 
1291  server = inst->server;
1292  inst->handle_config.server = talloc_strdup(inst, "");
1293 
1294  if (ldap_is_ldap_url(server)) {
1295  if (fr_ldap_server_url_check(&inst->handle_config, server, conf) < 0) return -1;
1296  } else {
1297  if (fr_ldap_server_config_check(&inst->handle_config, server, conf) < 0) return -1;
1298  }
1299 
1300  inst->handle_config.server[talloc_array_length(inst->handle_config.server) - 1] = '\0';
1301 
1302  inst->handle_config.name = talloc_typed_asprintf(inst, "proto_ldap_conn (%s)",
1304 
1305  return 0;
1306 }
1307 
1308 static int mod_bootstrap(module_inst_ctx_t const *mctx)
1309 {
1310  proto_ldap_sync_ldap_t *inst = talloc_get_type_abort(mctx->inst->data, proto_ldap_sync_ldap_t);
1311  CONF_SECTION *conf = mctx->inst->conf;
1312  dl_module_inst_t const *dl_inst;
1313 
1314  dl_inst = dl_module_instance_by_data(inst);
1315  fr_assert(dl_inst);
1316 
1317  inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_ldap_sync_t);
1318  inst->cs = conf;
1319 
1320  if (inst->recv_buff_is_set) {
1321  FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, >=, 32);
1322  FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, <=, INT_MAX);
1323  }
1324 
1325  return 0;
1326 }
1327 
1329  .common = {
1330  .magic = MODULE_MAGIC_INIT,
1331  .name = "ldap_sync_child"
1332  },
1333  .read = proto_ldap_child_mod_read,
1334  .write = proto_ldap_child_mod_write,
1335  .close = proto_ldap_child_mod_close,
1336 
1337  .default_message_size = 4096,
1338  .track_duplicates = false,
1339 };
1340 
1342  .common = {
1343  .magic = MODULE_MAGIC_INIT,
1344  .name = "ldap_sync_ldap",
1345  .config = proto_ldap_sync_ldap_config,
1346  .inst_size = sizeof(proto_ldap_sync_ldap_t),
1347  .thread_inst_size = sizeof(proto_ldap_sync_ldap_thread_t),
1348 
1349  .bootstrap = mod_bootstrap,
1350  .instantiate = mod_instantiate
1351  },
1352 
1353  .default_message_size = 4096,
1354  .track_duplicates = false,
1355 
1356  .event_list_set = mod_event_list_set,
1357 };
int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie)
Allocate a sync state structure and issue the search.
int active_directory_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, UNUSED LDAPControl **ctrls)
Handle a LDAP_RES_SEARCH_ENTRY (SearchResultEntry) response.
static int const char char buffer[256]
Definition: acutest.h:574
log_entry msg
Definition: acutest.h:794
module_t common
Common fields to all loadable modules.
Definition: app_io.h:34
size_t default_message_size
Usually maximum message size.
Definition: app_io.h:39
Public structure describing an I/O path for a protocol.
Definition: app_io.h:33
#define USES_APPLE_DEPRECATED_API
Definition: build.h:431
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition: cf_parse.h:486
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition: cf_parse.h:282
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:406
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
Definition: cf_util.c:1138
#define cf_parent(_cf)
Definition: cf_util.h:98
static int max_outstanding
Definition: channel_test.c:51
fr_connection_state_t
Definition: connection.h:45
@ FR_CONNECTION_STATE_CLOSED
Connection has been closed.
Definition: connection.h:55
@ FR_CONNECTION_STATE_INIT
Init state, sets up connection.
Definition: connection.h:49
@ FR_CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition: connection.h:52
@ FR_CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition: connection.h:84
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:762
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition: dbuff.h:354
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition: dbuff.h:877
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition: dbuff.h:551
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
dl_module_inst_t const * dl_module_instance_by_data(void const *data)
Lookup a dl_module_inst_t via instance data.
Definition: dl_module.c:215
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
dl_module_inst_t const *_CONST parent
Parent module's instance (if any).
Definition: dl_module.h:167
A module/inst tuple.
Definition: dl_module.h:162
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a list.
Definition: dlist.h:672
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition: dlist.h:486
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition: dlist.h:275
#define fr_event_fd_insert(...)
Definition: event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition: event.h:62
#define fr_event_timer_in(...)
Definition: event.h:255
#define GLOBAL_LIB_TERMINATOR
Definition: global_lib.h:51
Structure to define how to initialise libraries with global configuration.
Definition: global_lib.h:38
bool allow_name_only
Allow name only pairs.
Definition: internal.h:36
char const * name
printable name for this socket - set by open
Definition: listen.h:29
void const * app_instance
Definition: listen.h:38
size_t default_message_size
copied from app_io, but may be changed
Definition: listen.h:51
fr_app_t const * app
Definition: listen.h:37
void const * app_io_instance
I/O path configuration context.
Definition: listen.h:32
CONF_SECTION * server_cs
CONF_SECTION of the server.
Definition: listen.h:40
void * thread_instance
thread / socket context
Definition: listen.h:33
int fd
file descriptor for this socket - set by open
Definition: listen.h:28
fr_app_io_t const * app_io
I/O path functions.
Definition: listen.h:31
size_t fr_network_listen_outstanding(fr_network_t *nr, fr_listen_t *li)
Get the number of outstanding packets.
Definition: network.c:792
int fr_network_listen_send_packet(fr_network_t *nr, fr_listen_t *parent, fr_listen_t *li, const uint8_t *buffer, size_t buflen, fr_time_t recv_time, void *packet_ctx)
Send a packet to the worker.
Definition: network.c:750
int fr_network_listen_add(fr_network_t *nr, fr_listen_t *li)
Add a fr_listen_t to a network.
Definition: network.c:236
int fr_ldap_conn_directory_alloc_async(fr_ldap_connection_t *ldap_conn)
Async extract useful information from the rootDSE of the LDAP server.
Definition: directory.c:283
fr_ldap_sync_type_t sync_type
What kind of LDAP sync this directory supports.
Definition: base.h:209
LDAP * handle
libldap handle.
Definition: base.h:331
fr_connection_t * conn
Connection state handle.
Definition: base.h:343
fr_ldap_directory_t * directory
The type of directory we're connected to.
Definition: base.h:340
int fd
File descriptor for this connection.
Definition: base.h:347
void fr_ldap_state_error(fr_ldap_connection_t *c)
Signal that there's been an error on the connection.
Definition: state.c:134
int fr_ldap_server_url_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION const *cs)
Check an LDAP server entry in URL format is valid.
Definition: util.c:605
fr_ldap_config_t const * config
rlm_ldap connection configuration.
Definition: base.h:342
int fr_ldap_server_config_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION *cs)
Check an LDAP server config in server:port format is valid.
Definition: util.c:699
char const * name
Name of the module that created this connection.
Definition: base.h:220
fr_time_delta_t reconnection_delay
How long to wait before attempting to reconnect.
Definition: base.h:309
int fr_ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle, LDAPMessage *result, char const *name)
Definition: directory.c:51
void * uctx
User data associated with the handle.
Definition: base.h:352
@ FR_LDAP_SYNC_NONE
No support for LDAP sync.
Definition: base.h:157
@ FR_LDAP_SYNC_ACTIVE_DIRECTORY
Directory supports AD style persistent search.
Definition: base.h:159
@ FR_LDAP_SYNC_PERSISTENT_SEARCH
Directory supports persistent search.
Definition: base.h:160
@ FR_LDAP_SYNC_RFC4533
Directory supports RFC 4533.
Definition: base.h:158
fr_connection_t * fr_ldap_connection_state_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, fr_ldap_config_t const *config, char const *log_prefix)
Alloc a self re-establishing connection to an LDAP server.
Definition: connection.c:380
char const ** naming_contexts
Databases served by this directory.
Definition: base.h:211
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
Definition: base.h:577
@ LDAP_PROC_SUCCESS
Operation was successful.
Definition: base.h:580
@ LDAP_PROC_BAD_CONN
Transitory error, caller should retry the operation with a new connection.
Definition: base.h:584
@ LDAP_PROC_REFRESH_REQUIRED
Don't continue with the current refresh phase, exit, and retry the operation with a NULL cookie.
Definition: base.h:599
Tracks the state of a libldap connection handle.
Definition: base.h:330
#define FR_LDAP_COMMON_CONF(_conf)
Definition: conf.h:19
fr_ldap_rcode_t fr_ldap_error_check(LDAPControl ***ctrls, fr_ldap_connection_t const *conn, LDAPMessage *msg, char const *dn)
Perform basic parsing of multiple types of messages, checking for error conditions.
Definition: base.c:232
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
Definition: base.c:1051
global_lib_autoinst_t fr_libldap_global_config
Definition: base.c:134
fr_ldap_rcode_t fr_ldap_result(LDAPMessage **result, LDAPControl ***ctrls, fr_ldap_connection_t const *conn, int msgid, int all, char const *dn, fr_time_delta_t timeout)
Parse response from LDAP server dealing with any errors.
Definition: base.c:449
#define PERROR(_fmt,...)
Definition: log.h:228
#define FATAL(_fmt,...)
Definition: log.h:224
#define DEBUG3(_fmt,...)
Definition: log.h:266
fr_time_t fr_event_list_time(fr_event_list_t *el)
Get the current server time according to the event list.
Definition: event.c:636
talloc_free(reap)
bool fr_event_loop_exiting(fr_event_list_t *el)
Check to see whether the event loop is in the process of exiting.
Definition: event.c:2748
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition: event.c:1253
Stores all information relating to an event list.
Definition: event.c:411
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:36
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition: pair.c:765
int persistent_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Handle a SearchResultEntry response from Persistent Search LDAP servers.
int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie)
Allocate and initialise sync queries for persistent searches.
static const conf_parser_t config[]
Definition: base.c:188
char const * filter
Filter to retrieve only user objects.
CONF_SECTION * server_cs
server CS for this listener.
sync_config_t ** sync_config
DNs and filters to monitor.
int(* sync_msg_t)(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Received an LDAP message related to a sync.
sync_op_t
Operations to perform on entries.
@ SYNC_OP_ADD
Entry should be added to our copy.
@ SYNC_OP_MODIFY
Entry should be updated in our copy.
@ SYNC_OP_DELETE
Entry should be deleted from our copy.
@ SYNC_OP_PRESENT
Entry is present and unchanged on the server.
fr_event_timer_t const * ev
Event for retrying cookie load.
char const * base_dn
DN to search for users under.
sync_msg_t entry
Called when we receive a searchEntry message.
sync_msg_t refresh
Called when we receive a eSyncRefreshRequired code.
CONF_SECTION * cs
Config section where this sync was defined.
sync_msg_t intermediate
Called when we receive a syncIntermediate message.
map_list_t entry_map
How to convert attributes in entries to FreeRADIUS attributes.
fr_pair_list_t sync_pairs
Pairs representing the sync config sent to the worker with each request.
fr_time_delta_t cookie_interval
Interval between storing cookies.
uint32_t cookie_changes
Number of LDAP changes to process between each cookie store operation.
fr_time_delta_t retry_interval
Interval between retrying failed change packets.
void * user_ctx
User ctx to pass to the callbacks.
An instance of a proto_ldap_sync listen section.
Areas of the directory to receive notifications for.
static void proto_ldap_connection_init(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *user_ctx)
Attempt to (re)initialise a connection.
int ldap_sync_cookie_send(sync_packet_ctx_t *sync_packet_ctx)
Enqueue a new cookie store packet.
fr_app_io_t proto_ldap_sync_ldap
static fr_dict_attr_t const * attr_packet_type
static void _proto_ldap_socket_init(fr_connection_t *conn, UNUSED fr_connection_state_t prev, UNUSED fr_connection_state_t state, void *uctx)
Allocate a child listener.
static fr_ldap_sync_packet_code_t const sync_packet_code_table[4]
static int proto_ldap_child_mod_close(fr_listen_t *li)
Child listener mod_close.
static int proto_ldap_cookie_load_send(TALLOC_CTX *ctx, proto_ldap_sync_ldap_t const *inst, size_t sync_no, proto_ldap_sync_ldap_thread_t *thread)
Send a fake packet to run the "load Cookie" section.
global_lib_autoinst_t const * proto_ldap_sync_ldap_lib[]
static void ldap_sync_retry_event(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Event to handle sending of any change packets which failed to send.
static fr_dict_attr_t const * attr_ldap_sync_packet_id
static fr_dict_t const * dict_ldap_sync
proto_ldap_sync_ldap_t const * inst
static fr_dict_attr_t const * attr_ldap_sync_entry_dn
int ldap_sync_cookie_store(sync_state_t *sync, bool refresh)
Add a new cookie packet ctx to the pending list.
static int sync_state_free(sync_state_t *sync)
Tell the remote server to stop the sync.
static void _proto_ldap_socket_open_connected(fr_connection_t *conn, UNUSED fr_connection_state_t prev, UNUSED fr_connection_state_t state, void *uctx)
Query an LDAP server to establish its type.
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_ldap_sync_base_dn
static fr_dict_attr_t const * attr_ldap_sync_orig_dn
static void _proto_ldap_socket_closed(UNUSED fr_connection_t *conn, fr_connection_state_t prev, UNUSED fr_connection_state_t state, void *uctx)
Callback for closure of LDAP connection.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
fr_connection_t * conn
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Callback triggered when parent listener app_io has its event list set.
fr_app_io_t proto_ldap_sync_child
static conf_parser_t const proto_ldap_sync_ldap_config[]
static void _proto_ldap_socket_open_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, UNUSED int fd_errno, void *uctx)
Callback for socket errors when running initial root query.
int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH], struct berval *orig_dn, LDAPMessage *msg, sync_op_t op)
Enqueue a new entry change packet.
static ssize_t proto_ldap_child_mod_read(fr_listen_t *li, UNUSED void **packet_ctx, UNUSED fr_time_t *recv_time_p, UNUSED uint8_t *buffer, UNUSED size_t buffer_len, UNUSED size_t *leftover)
LDAP sync mod_read for child listener.
size_t sync_op_table_len
fr_table_num_sorted_t const sync_op_table[]
Operations performed on entries.
static fr_dict_attr_t const * attr_ldap_sync_root_dn
sync_state_t * sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, proto_ldap_sync_t const *inst, size_t sync_no, sync_config_t const *config)
Allocate a sync state.
void ldap_sync_cookie_event(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Event to handle storing of cookies on a timed basis.
static fr_internal_encode_ctx_t encode_ctx
static int ldap_sync_entry_send_network(sync_packet_ctx_t *sync_packet_ctx)
Send a change packet to the workers.
int8_t sync_state_cmp(void const *one, void const *two)
Compare two sync state structures on msgid.
static fr_dict_attr_t const * attr_ldap_sync_entry_uuid
fr_dict_attr_autoload_t proto_ldap_sync_ldap_dict_attr[]
static fr_dict_attr_t const * attr_ldap_sync_cookie
proto_ldap_sync_ldap_thread_t * thread
fr_dict_autoload_t proto_ldap_sync_ldap_dict[]
static void proto_ldap_cookie_load_retry(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Timer event to retry running "load Cookie" on failures.
static int mod_instantiate(module_inst_ctx_t const *mctx)
static void _proto_ldap_socket_open_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Callback to process results of initial root query, identifying directory type.
static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t request_time, uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
LDAP sync mod_write for child listener.
Context used when looking up Directory types.
uint32_t pending_cookies
How many cookies are in the pending heap.
uint8_t * cookie
Opaque cookie, used to resume synchronisation.
size_t sync_no
Array position of config for this sync.
@ SYNC_PACKET_TYPE_CHANGE
Packet is an entry change.
@ SYNC_PACKET_TYPE_COOKIE
sync_phases_t phase
Phase this sync is in.
uint32_t max_outstanding
Maximum number of outstanding packets.
int msgid
The unique identifier for this sync session.
fr_connection_t * conn
Our connection to the LDAP directory.
uint8_t * cookie
Cookie to store - can be NULL.
fr_pair_list_t pairs
Pairs to send with change packets.
fr_dlist_head_t pending
List of pending changes in progress.
sync_config_t const * config
Configuration for this sync.
static fr_table_num_sorted_t const sync_ldap_msg_table[]
Types of LDAP messages relevant to LDAP sync.
sync_state_t * sync
Sync packet relates to.
sync_packet_status_t status
Status of this packet.
fr_event_timer_t const * conn_retry_ev
When to retry re-establishing the conn.
@ SYNC_PACKET_PREPARING
Packet being prepared.
@ SYNC_PACKET_PENDING
Packet not yet sent.
@ SYNC_PACKET_PROCESSING
Packet sent to worker.
@ SYNC_PACKET_COMPLETE
Packet response received from worker.
fr_listen_t * li
Our listener.
proto_ldap_sync_t const * inst
Module instance for this sync.
fr_ldap_config_t handle_config
Connection configuration instance.
fr_network_t * nr
Network handler.
fr_listen_t * parent
master IO handler.
#define SYNC_UUID_LENGTH
proto_ldap_sync_t * parent
The module that spawned us.
bool refresh
Does the sync require a refresh.
@ SYNC_PHASE_INIT
We haven't entered any of the refresh phases.
sync_packet_type_t type
Type of packet.
uint32_t changes_since_cookie
How many changes have been added since the last cookie was stored.
fr_event_timer_t const * cookie_ev
Timer event for sending cookies.
fr_ldap_connection_t * conn
Connection the sync is running on.
fr_pair_list_t trigger_args
Arguments to make available in triggers.
fr_event_timer_t const * retry_ev
Timer event for retrying failed changes.
fr_event_list_t * el
Network side event list.
proto_ldap_sync_ldap_t const * inst
instance data
Tracking structure for ldap sync packets.
State of an individual sync.
ssize_t fr_internal_decode_list_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *dbuff, void *decode_ctx)
Retrieve all pairs from the dbuff.
Definition: decode.c:310
ssize_t fr_internal_encode_list(fr_dbuff_t *dbuff, fr_pair_list_t const *list, void *encode_ctx)
Encode a list of pairs using the internal encoder.
Definition: encode.c:303
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
static rs_t * conf
Definition: radsniff.c:53
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition: rb.c:736
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition: rb.c:576
The main red black tree structure.
Definition: rb.h:73
int rfc4533_sync_refresh_required(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Handle result code of e-syncRefreshRequired.
Definition: rfc4533.c:716
int rfc4533_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Handle a SearchResultEntry or SearchResultReference response from an RFC 4533 server.
Definition: rfc4533.c:259
int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, uint8_t const *cookie)
Allocate and initialise RFC 4533 sync queries.
Definition: rfc4533.c:74
int rfc4533_sync_intermediate(sync_state_t *sync, LDAPMessage *msg, UNUSED LDAPControl **ctrls)
Handle a LDAP_RES_INTERMEDIATE (SyncInfo) response.
Definition: rfc4533.c:451
fr_connection_watch_entry_t * fr_connection_add_watch_post(fr_connection_t *conn, fr_connection_state_t state, fr_connection_watch_t watch, bool oneshot, void const *uctx)
Add a callback to be executed after a state function has been called.
Definition: connection.c:531
void fr_connection_signal_halt(fr_connection_t *conn)
Shuts down a connection ungracefully.
Definition: connection.c:1290
void fr_connection_signal_init(fr_connection_t *conn)
Asynchronously signal a halted connection to start.
Definition: connection.c:1106
void fr_connection_signal_shutdown(fr_connection_t *conn)
Shuts down a connection gracefully.
Definition: connection.c:1227
void fr_connection_signal_reconnect(fr_connection_t *conn, fr_connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
Definition: connection.c:1166
int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list))
Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
Definition: tmpl_eval.c:972
return count
Definition: module.c:175
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
Value pair map.
Definition: map.h:77
fr_token_t op
The operator that controls insertion of the dst attribute.
Definition: map.h:82
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:79
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_ldap_sync_packet_code_t
Types of the internal packets for processing LDAP sync messages.
Definition: sync.h:31
@ FR_LDAP_SYNC_CODE_PRESENT
LDAP server indicates a particular object is present and unchanged.
Definition: sync.h:33
@ FR_LDAP_SYNC_CODE_COOKIE_STORE_RESPONSE
Response to storing the new cookie.
Definition: sync.h:52
@ FR_LDAP_SYNC_CODE_ENTRY_RESPONSE
Response packet to present / add / modify / delete.
Definition: sync.h:42
@ FR_LDAP_SYNC_CODE_COOKIE_LOAD_FAIL
Response when coolie load fails.
Definition: sync.h:48
@ FR_LDAP_SYNC_CODE_ADD
Object has been added to the LDAP directory.
Definition: sync.h:36
@ FR_LDAP_SYNC_CODE_COOKIE_STORE
The server has sent a new cookie.
Definition: sync.h:50
@ FR_LDAP_SYNC_CODE_COOKIE_LOAD_RESPONSE
Response with the returned cookie.
Definition: sync.h:46
@ FR_LDAP_SYNC_CODE_DELETE
Object has been deleted.
Definition: sync.h:40
@ FR_LDAP_SYNC_CODE_COOKIE_LOAD
Before the sync starts, request any previously stored cookie.
Definition: sync.h:44
@ FR_LDAP_SYNC_CODE_MODIFY
Object has been modified.
Definition: sync.h:38
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
#define talloc_get_type_abort_const
Definition: talloc.h:270
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
Definition: time.h:573
"server local" time.
Definition: time.h:69
@ T_OP_ADD_EQ
Definition: token.h:69
int trigger_exec(unlang_interpret_t *intp, CONF_SECTION const *cs, char const *name, bool rate_limit, fr_pair_list_t *args)
Execute a trigger - call an executable to process an event.
Definition: trigger.c:280
static fr_event_list_t * el
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition: pair_inline.c:94
#define fr_pair_list_append_by_da_len(_ctx, _vp, _list, _attr, _val, _len, _tainted)
Append a pair to a list, assigning its value.
Definition: pair.h:308
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
#define fr_pair_list_append_by_da(_ctx, _vp, _list, _attr, _val, _tainted)
Append a pair to a list, assigning its value.
Definition: pair.h:285
#define fr_pair_list_append_by_da_parent_len(_ctx, _vp, _list, _attr, _val, _len, _tainted)
Definition: pair.h:330
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition: value.c:5264
#define fr_box_time_delta(_val)
Definition: value.h:336