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: 8c0d0e0866b5c80b14aabab813f319048c0e8ea7 $
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 connection_state_t state, void *uctx);
526 
528  UNUSED 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  */
575  connection_signal_init(thread->conn);
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  PERROR("Sync error");
722  ret = -1;
723  goto free_msg;
724  }
725 
726  DEBUG3("Got %s message for sync (msgid %i)",
727  fr_table_str_by_value(sync_ldap_msg_table, type, "<invalid>"), sync->msgid);
728 
729  switch (type) {
730  case LDAP_RES_SEARCH_REFERENCE:
731  case LDAP_RES_SEARCH_ENTRY:
732  callback = sync->config->entry;
733  break;
734 
735  case LDAP_RES_INTERMEDIATE:
736  callback = sync->config->intermediate;
737  break;
738 
739  default:
740  WARN("Ignoring unexpected message type (%i)", type);
741  ret = 0;
742  goto free_msg;
743  }
744 
745  if (callback) {
746  ret = callback(sync, msg, ctrls);
747  if (ret < 0) PERROR("Sync callback error");
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 
756  ldap_controls_free(ctrls);
757 
758  return ret;
759 }
760 
761 /** Send a fake packet to run the "load Cookie" section
762  *
763  * @param ctx Context to allocate temporary pairs in.
764  * @param inst LDAP sync configuration.
765  * @param sync_no Id of the sync whose.
766  * @param thread Thread specific LDAP sync data.
767  * @return
768  * - 0 on success
769  * - -1 on failure
770  */
771 static int proto_ldap_cookie_load_send(TALLOC_CTX *ctx, proto_ldap_sync_ldap_t const *inst, size_t sync_no,
773  size_t j, len;
774  sync_config_t *config = inst->parent->sync_config[sync_no];
775  fr_pair_list_t pairs;
776  fr_pair_t *vp;
777  fr_dbuff_t *dbuff;
778  fr_ldap_connection_t *ldap_conn = thread->conn->h;
779 
780  fr_pair_list_init(&pairs);
781  if (unlikely(fr_pair_list_copy(ctx, &pairs, &config->sync_pairs) < 0)) return -1;
782 
783  /*
784  * Ensure we have access to the thread instance
785  * in for the demux callbacks
786  */
787  inst->parent->sync_config[sync_no]->user_ctx = thread;
788 
789  /*
790  * Assess the namingContext which applies to this sync
791  */
792  for (j = 0; j < talloc_array_length(ldap_conn->directory->naming_contexts); j++) {
793  len = strlen(ldap_conn->directory->naming_contexts[j]);
794  if (strlen(config->base_dn) < len) continue;
795 
796  if (strncasecmp(&config->base_dn[strlen(config->base_dn)-len],
797  ldap_conn->directory->naming_contexts[j],
798  strlen(ldap_conn->directory->naming_contexts[j])) == 0) {
799  config->root_dn = ldap_conn->directory->naming_contexts[j];
800  break;
801  }
802  }
803 
804  /*
805  * Set up callbacks based on directory type.
806  */
807  switch (ldap_conn->directory->sync_type) {
809  config->init = rfc4533_sync_init;
811  config->intermediate = rfc4533_sync_intermediate;
813  break;
814 
818  break;
819 
823  break;
824 
825  default:
826  fr_assert(0);
827  }
828 
831  if (!vp) return -1;
832  fr_pair_list_append_by_da(ctx, vp, &pairs, attr_ldap_sync_packet_id, (uint32_t)sync_no, false);
833  if (!vp) return -1;
834 
835  if (config->root_dn) {
837  config->root_dn, strlen(config->root_dn), false);
838  if (!vp) return -1;
839  }
840 
841  FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096);
842 
843  if (fr_internal_encode_list(dbuff, &pairs, &encode_ctx) < 0) return -1;
844 
845  if (fr_network_listen_send_packet(thread->nr, thread->li, thread->li,
846  fr_dbuff_buff(dbuff), fr_dbuff_used(dbuff),
847  fr_time(), NULL) < 0) return -1;
848  fr_pair_list_free(&pairs);
849  return 0;
850 }
851 
852 /** Timer event to retry running "load Cookie" on failures
853  *
854  */
856  proto_ldap_cookie_load_retry_ctx *retry_ctx = talloc_get_type_abort(uctx, proto_ldap_cookie_load_retry_ctx);
857 
858  DEBUG2("Retrying \"load Cookie\" for sync no %ld", retry_ctx->sync_no);
859  if (proto_ldap_cookie_load_send(retry_ctx, retry_ctx->inst, retry_ctx->sync_no,
860  retry_ctx->thread) < 0) {
861  ERROR("Failed retrying \"load Cookie\". Will try again in %pV seconds",
863  (void) fr_event_timer_in(retry_ctx->thread->conn->h, el,
864  &retry_ctx->inst->parent->sync_config[retry_ctx->sync_no]->ev,
866  proto_ldap_cookie_load_retry, retry_ctx);
867  return;
868  }
869  talloc_free(retry_ctx);
870 }
871 
872 /** LDAP sync mod_write for child listener
873  *
874  * Handle any returned data after the worker has processed the packet and,
875  * for packets where tracking structures were used, ensure they are freed.
876  */
877 static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t request_time,
878  uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
879 {
882  fr_dbuff_t dbuff;
884  uint32_t packet_id;
885  fr_pair_list_t tmp;
886  fr_pair_t *vp = NULL;
887  ssize_t ret;
888  TALLOC_CTX *local;
889  sync_packet_ctx_t *sync_packet_ctx = NULL;
890 
891  local = talloc_new(NULL);
892  fr_dbuff_init(&dbuff, buffer, buffer_len);
893 
894  if (packet_ctx) sync_packet_ctx = talloc_get_type_abort(packet_ctx, sync_packet_ctx_t);
895 
896  /*
897  * Extract returned attributes into a temporary list
898  */
899  fr_pair_list_init(&tmp);
900 
901  ret = fr_internal_decode_list_dbuff(local, &tmp, fr_dict_root(dict_ldap_sync), &dbuff, NULL);
902  if (ret < 0) goto finish;
903 
904  /*
905  * There should always be a packet ID and code
906  */
908  fr_assert(vp);
909  packet_id = vp->vp_uint32;
910 
911  vp = fr_pair_find_by_da(&tmp, NULL, attr_packet_type);
912  fr_assert(vp);
913  pcode = vp->vp_uint32;
914 
915  switch (pcode) {
917  {
918  uint8_t *cookie = NULL;
919 
920  /*
921  * If the received packet ID is greater than the number of syncs
922  * we have then something very bad has happened
923  */
924  fr_assert (packet_id <= talloc_array_length(inst->parent->sync_config));
925 
926  /*
927  * Look for the returned cookie.
928  */
930  if (vp) cookie = talloc_memdup(inst, vp->vp_octets, vp->vp_length);
931 
932  if (inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent, cookie) < 0) {
933  ret = -1;
934  goto finish;
935  }
936  }
937  break;
938 
940  break;
941 
943  {
944  sync_config_t const *sync_config;
945 
946  if (!sync_packet_ctx || !sync_packet_ctx->refresh) break;
947 
948  /*
949  * Abandon the old sync and start a new one with the relevant cookie.
950  */
951  sync_config = sync_packet_ctx->sync->config;
952  DEBUG3("Restarting sync with base %s", sync_config->base_dn);
953  talloc_free(sync_packet_ctx->sync);
954  if (inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent,
955  sync_packet_ctx->cookie) < 0) {
956  ret = -1;
957  goto finish;
958  }
959  }
960  break;
961 
963  {
965 
966  ERROR("Load Cookie failed for sync %d, retrying in %pV seconds", packet_id,
967  fr_box_time_delta(inst->handle_config.reconnection_delay));
968 
969  MEM(retry_ctx = talloc(thread, proto_ldap_cookie_load_retry_ctx));
970  *retry_ctx = (proto_ldap_cookie_load_retry_ctx){
971  .thread = thread,
972  .inst = inst,
973  .sync_no = packet_id,
974  };
975 
976  (void) fr_event_timer_in(thread->conn->h, thread->el, &inst->parent->sync_config[packet_id]->ev,
977  inst->handle_config.reconnection_delay,
978  proto_ldap_cookie_load_retry, retry_ctx);
979  }
980  break;
981 
982  default:
983  ERROR("Invalid packet type returned %d", pcode);
984  break;
985  }
986 
987  if (sync_packet_ctx) {
988  sync_state_t *sync = sync_packet_ctx->sync;
989  sync_packet_ctx_t *pc;
990  proto_ldap_sync_t *ldap_sync = inst->parent;
991 
992  sync_packet_ctx->status = SYNC_PACKET_COMPLETE;
993 
994  /*
995  * A cookie has been stored, reset the counter of changes
996  */
997  if (sync_packet_ctx->type == SYNC_PACKET_TYPE_COOKIE) sync->changes_since_cookie = 0;
998 
999  /*
1000  * Pop any processed updates from the head of the list
1001  */
1002  while ((pc = fr_dlist_head(&sync->pending))) {
1003  /*
1004  * If the head entry in the list is a pending cookie but we have
1005  * not processed enough entries and there are more pending
1006  * cookies, mark this one as processed.
1007  */
1008  if ((pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) &&
1009  (sync->changes_since_cookie < ldap_sync->cookie_changes) &&
1010  (sync->pending_cookies > 1)) pc->status = SYNC_PACKET_COMPLETE;
1011 
1012  if (pc->status != SYNC_PACKET_COMPLETE) break;
1013 
1014  /*
1015  * Update counters depending on entry type
1016  */
1017  if (pc->type == SYNC_PACKET_TYPE_COOKIE) {
1018  sync->pending_cookies--;
1019  } else {
1020  sync->changes_since_cookie++;
1021  }
1022  pc = fr_dlist_pop_head(&sync->pending);
1023  talloc_free(pc);
1024  }
1025 
1026  /*
1027  * If the head of the list is a cookie which has not yet
1028  * been processed and sufficient changes have been recorded
1029  * send the cookie.
1030  */
1031  if (pc && (pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) &&
1032  (sync->changes_since_cookie >= ldap_sync->cookie_changes)) ldap_sync_cookie_send(pc);
1033  }
1034 
1035 finish:
1036  fr_pair_list_free(&tmp);
1037  talloc_free(local);
1038 
1039  return ret;
1040 }
1041 
1042 /** Callback for socket errors when running initial root query
1043  */
1045  UNUSED int fd_errno, void *uctx)
1046 {
1047  proto_ldap_dir_ctx *dir_ctx = talloc_get_type_abort(uctx, proto_ldap_dir_ctx);
1048  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(dir_ctx->conn->h, fr_ldap_connection_t);
1049 
1050  talloc_free(dir_ctx);
1051  fr_ldap_state_error(ldap_conn);
1052 }
1053 
1054 /** Callback to process results of initial root query, identifying directory type
1055  */
1056 static void _proto_ldap_socket_open_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1057 {
1058  proto_ldap_dir_ctx *dir_ctx = talloc_get_type_abort(uctx, proto_ldap_dir_ctx);
1059  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(dir_ctx->conn->h, fr_ldap_connection_t);
1062  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(dir_ctx->main_listen->thread_instance,
1064  fr_ldap_rcode_t status;
1065  LDAPMessage *result;
1066 
1067  size_t i;
1068  TALLOC_CTX *local = NULL;
1069 
1070  /*
1071  * Fetch the result. Setting the timeout to 0 here means use
1072  * res_timeout from the configuration.
1073  */
1074  status = fr_ldap_result(&result, NULL, ldap_conn, dir_ctx->msgid, LDAP_MSG_ALL, NULL, fr_time_delta_from_msec(0));
1075  if (status != LDAP_PROC_SUCCESS) {
1076  PERROR("Failed querying for directory type");
1077  if (result) ldap_msgfree(result);
1078  error:
1079  talloc_free(dir_ctx);
1080  if (local) talloc_free(local);
1082  return;
1083  }
1084 
1085  fr_ldap_directory_result_parse(ldap_conn->directory, ldap_conn->handle, result, ldap_conn->config->name);
1086  ldap_msgfree(result);
1087 
1088  /*
1089  * If the server does not support any of the relevant controls, we just
1090  * tidy up - no point in signalling to reconnect.
1091  */
1092  if (ldap_conn->directory->sync_type == FR_LDAP_SYNC_NONE) {
1093  ERROR("LDAP sync configured for directory which does not support any suitable control");
1094  talloc_free(dir_ctx);
1095  connection_signal_halt(ldap_conn->conn);
1096  return;
1097  }
1098 
1099  /*
1100  * We've done all the preparation work on the LDAP connection, now
1101  * use normal network event listeners.
1102  */
1104  fr_network_listen_add(thread->nr, thread->li);
1105 
1106  DEBUG2("Starting sync(s)");
1107 
1108  local = talloc_new(NULL);
1109 
1110  /*
1111  * Sync operations start by sending a fake packet to run
1112  * the load Cookie section in order to retrieve the cookie
1113  */
1114  for (i = 0; i < talloc_array_length(inst->parent->sync_config); i++) {
1115  if (proto_ldap_cookie_load_send(local, inst, i, thread) < 0) goto error;
1116  }
1117 
1118  talloc_free(dir_ctx);
1119  talloc_free(local);
1120 }
1121 
1122 /** Allocate a child listener
1123  *
1124  * Called as a watch function when the LDAP connection enters the INIT state
1125  */
1127  UNUSED connection_state_t state, void *uctx)
1128 {
1129  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(uctx, proto_ldap_sync_ldap_thread_t);
1130  fr_listen_t *li;
1131 
1132  MEM(li = talloc_zero(conn, fr_listen_t));
1133 
1134  thread->li = li;
1135  li->thread_instance = thread;
1136 
1138  li->name = li->app_io->common.name;
1140 
1141  /*
1142  * Use the app from the parent listener to access
1143  * the encoder / decoder functions
1144  */
1145  li->app = thread->parent->app;
1146  li->app_instance = thread->parent->app_instance;
1147  li->server_cs = thread->inst->parent->server_cs;
1148 }
1149 
1150 /** Callback for closure of LDAP connection
1151  *
1152  * Schedules re-start of the connection if appropriate
1153  */
1155  UNUSED connection_state_t state, void *uctx)
1156 {
1157  fr_listen_t *listen = talloc_get_type_abort(uctx, fr_listen_t);
1158  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(listen->thread_instance, proto_ldap_sync_ldap_thread_t);
1159  proto_ldap_sync_ldap_t const *inst = thread->inst;
1160 
1161  if (fr_event_loop_exiting(thread->el)) return;
1162 
1163  if (prev == CONNECTION_STATE_CONNECTED) {
1164  ERROR("LDAP connection closed. Scheduling restart in %pVs",
1165  fr_box_time_delta(inst->handle_config.reconnection_delay));
1166  if (fr_event_timer_in(thread, thread->el, &thread->conn_retry_ev,
1167  inst->handle_config.reconnection_delay,
1168  proto_ldap_connection_init, listen) < 0) {
1169  FATAL("Failed inserting event: %s", fr_strerror());
1170  }
1171  }
1172 }
1173 
1174 /** Query an LDAP server to establish its type
1175  *
1176  * Called as a watch function once the LDAP connection enters the CONNECTED state
1177  *
1178  * There are three different forms of LDAP sync/persistent search - so we need
1179  * to know what we're dealing with, and whether the relevant options have been enabled.
1180  */
1182  UNUSED connection_state_t state, void *uctx)
1183 {
1184  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(uctx, proto_ldap_sync_ldap_thread_t);
1185  fr_listen_t *listen = talloc_get_type_abort(thread->parent, fr_listen_t);
1188  fr_ldap_connection_t *ldap_conn = talloc_get_type_abort(conn->h, fr_ldap_connection_t);
1189 
1190  proto_ldap_dir_ctx *dir_ctx;
1191 
1192  if (ldap_conn->fd < 0) {
1193  connection_failed:
1194  if (fr_event_timer_in(thread, thread->el, &thread->conn_retry_ev,
1195  inst->handle_config.reconnection_delay,
1196  proto_ldap_connection_init, listen) < 0) {
1197  FATAL("Failed inserting event: %s", fr_strerror());
1198  }
1199  return;
1200  }
1201 
1202  thread->li->fd = ldap_conn->fd;
1203 
1204  MEM(dir_ctx = talloc_zero(inst, proto_ldap_dir_ctx));
1205  if (!dir_ctx) goto connection_failed;
1206 
1207  dir_ctx->main_listen = listen;
1208  dir_ctx->conn = conn;
1209  dir_ctx->child_listen = thread->li;
1210 
1211 #ifdef SO_RCVBUF
1212  if (inst->recv_buff_is_set) {
1213  int opt;
1214 
1215  opt = inst->recv_buff;
1216  if (setsockopt(ldap_conn->fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(int)) < 0) {
1217  WARN("Failed setting 'recv_buff': %s", fr_syserror(errno));
1218  }
1219  }
1220 #endif
1221 
1222  /*
1223  * Set the callback which will handle the results of this query
1224  */
1225  if (fr_event_fd_insert(conn, NULL, conn->el, ldap_conn->fd,
1227  NULL,
1229  dir_ctx) < 0) {
1230  goto connection_failed;
1231  }
1232 
1233  /*
1234  * Allocate the directory structure and send the query
1235  */
1236  dir_ctx->msgid = fr_ldap_conn_directory_alloc_async(ldap_conn);
1237 
1238  if (dir_ctx->msgid < 0) {
1239  talloc_free(dir_ctx);
1240  goto connection_failed;
1241  }
1242 
1243  /*
1244  * Add a watch to catch closed LDAP connections
1245  */
1247  _proto_ldap_socket_closed, true, listen);
1248 }
1249 
1250 /** Callback triggered when parent listener app_io has its event list set
1251  *
1252  * Initiates the actual outbound LDAP connection
1253  *
1254  * @param[in] li The parent listener.
1255  * @param[in] el Event list for this listener.
1256  * @param[in] nr Network handler.
1257  */
1258 static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
1259 {
1261  proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_ldap_sync_ldap_thread_t);
1262 
1263  /*
1264  * Set up thread data
1265  */
1266  thread->name = inst->handle_config.name;
1267  thread->parent = li;
1268  thread->el = el;
1269  thread->nr = nr;
1270  thread->inst = inst;
1271 
1272  /*
1273  * Initialise the connection
1274  */
1276 }
1277 
1278 static int mod_instantiate(module_inst_ctx_t const *mctx)
1279 {
1280  proto_ldap_sync_ldap_t *inst = talloc_get_type_abort(mctx->mi->data, proto_ldap_sync_ldap_t);
1281  CONF_SECTION *conf = mctx->mi->conf;
1282  char const *server;
1283 
1284  /*
1285  * Verify that the LDAP server configuration is valid, either
1286  * distinct server and port or an LDAP url.
1287  */
1288  fr_assert(inst->server);
1289 
1290  inst->parent = talloc_get_type_abort(mctx->mi->parent->data, proto_ldap_sync_t);
1291  inst->cs = conf;
1292 
1293  if (inst->recv_buff_is_set) {
1294  FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, >=, 32);
1295  FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, <=, INT_MAX);
1296  }
1297 
1298  server = inst->server;
1299  inst->handle_config.server = talloc_strdup(inst, "");
1300 
1301  if (ldap_is_ldap_url(server)) {
1302  if (fr_ldap_server_url_check(&inst->handle_config, server, conf) < 0) return -1;
1303  } else {
1304  if (fr_ldap_server_config_check(&inst->handle_config, server, conf) < 0) return -1;
1305  }
1306 
1307  inst->handle_config.server[talloc_array_length(inst->handle_config.server) - 1] = '\0';
1308 
1309  inst->handle_config.name = talloc_typed_asprintf(inst, "proto_ldap_conn (%s)",
1311 
1312  return 0;
1313 }
1314 
1316  .common = {
1317  .magic = MODULE_MAGIC_INIT,
1318  .name = "ldap_sync_child"
1319  },
1320  .read = proto_ldap_child_mod_read,
1321  .write = proto_ldap_child_mod_write,
1322  .close = proto_ldap_child_mod_close,
1323 
1324  .default_message_size = 4096,
1325  .track_duplicates = false,
1326 };
1327 
1329  .common = {
1330  .magic = MODULE_MAGIC_INIT,
1331  .name = "ldap_sync_ldap",
1332  .config = proto_ldap_sync_ldap_config,
1333  .inst_size = sizeof(proto_ldap_sync_ldap_t),
1334  .thread_inst_size = sizeof(proto_ldap_sync_ldap_thread_t),
1335  .instantiate = mod_instantiate
1336  },
1337 
1338  .default_message_size = 4096,
1339  .track_duplicates = false,
1340 
1341  .event_list_set = mod_event_list_set,
1342 };
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:468
#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:379
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition: cf_parse.h:487
#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:405
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:684
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
Definition: cf_util.c:1197
#define cf_parent(_cf)
Definition: cf_util.h:101
static int max_outstanding
Definition: channel_test.c:51
connection_state_t
Definition: connection.h:45
@ CONNECTION_STATE_CLOSED
Connection has been closed.
Definition: connection.h:55
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition: connection.h:52
@ CONNECTION_STATE_INIT
Init state, sets up connection.
Definition: connection.h:49
@ 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:767
#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:882
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition: dbuff.h:556
next
Definition: dcursor.h:178
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#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:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:2400
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
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:805
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:763
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
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:386
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:287
fr_ldap_sync_type_t sync_type
What kind of LDAP sync this directory supports.
Definition: base.h:211
LDAP * handle
libldap handle.
Definition: base.h:333
fr_ldap_directory_t * directory
The type of directory we're connected to.
Definition: base.h:342
int fd
File descriptor for this connection.
Definition: base.h:349
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:344
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:701
char const * name
Name of the module that created this connection.
Definition: base.h:222
fr_time_delta_t reconnection_delay
How long to wait before attempting to reconnect.
Definition: base.h:311
int fr_ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle, LDAPMessage *result, char const *name)
Definition: directory.c:52
void * uctx
User data associated with the handle.
Definition: base.h:354
@ FR_LDAP_SYNC_NONE
No support for LDAP sync.
Definition: base.h:158
@ FR_LDAP_SYNC_ACTIVE_DIRECTORY
Directory supports AD style persistent search.
Definition: base.h:160
@ FR_LDAP_SYNC_PERSISTENT_SEARCH
Directory supports persistent search.
Definition: base.h:161
@ FR_LDAP_SYNC_RFC4533
Directory supports RFC 4533.
Definition: base.h:159
connection_t * conn
Connection state handle.
Definition: base.h:345
char const ** naming_contexts
Databases served by this directory.
Definition: base.h:213
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
Definition: base.h:582
@ LDAP_PROC_SUCCESS
Operation was successful.
Definition: base.h:585
@ LDAP_PROC_BAD_CONN
Transitory error, caller should retry the operation with a new connection.
Definition: base.h:589
@ LDAP_PROC_REFRESH_REQUIRED
Don't continue with the current refresh phase, exit, and retry the operation with a NULL cookie.
Definition: base.h:604
Tracks the state of a libldap connection handle.
Definition: base.h:332
#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:1105
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:643
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:2755
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:1260
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
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
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:693
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:2319
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:770
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:183
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 void _proto_ldap_socket_closed(UNUSED connection_t *conn, connection_state_t prev, UNUSED connection_state_t state, void *uctx)
Callback for closure of LDAP connection.
static fr_dict_attr_t const * attr_packet_type
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 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 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
static void _proto_ldap_socket_init(connection_t *conn, UNUSED connection_state_t prev, UNUSED connection_state_t state, void *uctx)
Allocate a child listener.
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 void _proto_ldap_socket_open_connected(connection_t *conn, UNUSED connection_state_t prev, UNUSED connection_state_t state, void *uctx)
Query an LDAP server to establish its 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.
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.
connection_t * conn
Our connection to the LDAP directory.
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)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
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:717
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:260
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:452
void connection_signal_shutdown(connection_t *conn)
Shuts down a connection gracefully.
Definition: connection.c:1228
void connection_signal_halt(connection_t *conn)
Shuts down a connection ungracefully.
Definition: connection.c:1291
void connection_signal_reconnect(connection_t *conn, connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
Definition: connection.c:1167
void connection_signal_init(connection_t *conn)
Asynchronously signal a halted connection to start.
Definition: connection.c:1107
connection_watch_entry_t * connection_add_watch_post(connection_t *conn, connection_state_t state, 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:532
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
module_instance_t const * parent
Parent module's instance (if any).
Definition: module.h:337
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:974
return count
Definition: module.c:163
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:772
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:49
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:492
#define talloc_get_type_abort_const
Definition: talloc.h:282
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
Definition: time.h:575
"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:233
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:309
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:286
#define fr_pair_list_append_by_da_parent_len(_ctx, _vp, _list, _attr, _val, _len, _tainted)
Definition: pair.h:331
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:5315
#define fr_box_time_delta(_val)
Definition: value.h:343