The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
util.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 (at
5 * 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: 500e25662db2c71ce84cc885ba81aa5a854479f4 $
19 * @file lib/ldap/util.c
20 * @brief Utility functions to escape and parse DNs
21 *
22 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2017 The FreeRADIUS Server Project.
25 */
26RCSID("$Id: 500e25662db2c71ce84cc885ba81aa5a854479f4 $")
27
29
30#include <freeradius-devel/ldap/base.h>
31#include <freeradius-devel/util/base16.h>
32
33#include <freeradius-devel/util/value.h>
34
35#include <stdarg.h>
36
37/* RFC 4514 DN attribute value special characters */
38static const char dn_specials[] = ",+\"\\<>;*=()";
39static const char hextab[] = "0123456789abcdef";
40static const bool escapes[SBUFF_CHAR_CLASS] = {
41 [' '] = true,
42 ['#'] = true,
43 ['='] = true,
44 ['"'] = true,
45 ['+'] = true,
46 [','] = true,
47 [';'] = true,
48 ['<'] = true,
49 ['>'] = true,
50 ['\''] = true
51};
52
53
54/** Copy in to out, hex escaping every byte flagged in escape_chars
55 *
56 * @param[out] out Where to write the escaped value.
57 * @param[in] in Value to escape. Consumed on success.
58 * @param[in] escape_chars Bytes to escape, indexed by byte value.
59 * @return
60 * - >= 0 the number of bytes written to out.
61 * - < 0 the number of additional bytes out needed. Neither sbuff is advanced.
62 */
63static inline CC_HINT(always_inline) fr_slen_t ldap_escape(fr_sbuff_t *out, fr_sbuff_t *in, bool const *escape_chars)
64{
65 fr_sbuff_t our_out = FR_SBUFF(out);
66 fr_sbuff_t our_in = FR_SBUFF(in);
67
68 while (fr_sbuff_extend(&our_in)) {
69 uint8_t c = (uint8_t)*fr_sbuff_current(&our_in);
70
71 if (escape_chars[c]) {
72 FR_SBUFF_IN_CHAR_RETURN(&our_out, '\\');
74 } else {
75 FR_SBUFF_IN_CHAR_RETURN(&our_out, (char)c);
76 }
77 fr_sbuff_advance(&our_in, 1);
78 }
79
80 fr_sbuff_set(in, &our_in);
81 FR_SBUFF_SET_RETURN(out, &our_out);
82}
83
84/** Escape a value for use as an RFC 4514 DN attribute value
85 *
86 * Escapes the characters that have special meaning in a DN, and a leading
87 * space or '#', as @verbatim <hex><hex> @endverbatim sequences.
88 *
89 * @param[out] out Where to write the escaped value.
90 * @param[in] in Value to escape. Consumed on success.
91 * @return
92 * - >= 0 the number of bytes written to out.
93 * - < 0 the number of additional bytes out needed. Neither sbuff is advanced.
94 */
96{
97 static const bool dn_escape_chars[SBUFF_CHAR_CLASS] = {
98 ['\0'] = true,
99 [','] = true,
100 ['+'] = true,
101 ['"'] = true,
102 ['\\'] = true,
103 ['<'] = true,
104 ['>'] = true,
105 [';'] = true,
106 ['*'] = true,
107 ['='] = true,
108 ['('] = true,
109 [')'] = true
110 };
111
112 fr_sbuff_t our_out = FR_SBUFF(out);
113 fr_sbuff_t our_in = FR_SBUFF(in);
114
115 /*
116 * Space and '#' only need escaping at the start of the value.
117 */
118 if (fr_sbuff_is_char(&our_in, ' ') || fr_sbuff_is_char(&our_in, '#')) {
119 FR_SBUFF_IN_CHAR_RETURN(&our_out, '\\');
121 fr_sbuff_advance(&our_in, 1);
122 }
123
124 FR_SBUFF_RETURN(ldap_escape, &our_out, &our_in, dn_escape_chars);
125
126 fr_sbuff_set(in, &our_in);
127 FR_SBUFF_SET_RETURN(out, &our_out);
128}
129
130/** Escape a value for use as an RFC 4515 filter assertion value
131 *
132 * Escapes only the characters that MUST be escaped in filter assertion values
133 * per RFC 4515: '*', '(', ')', '\', and NUL. Other characters (including ',',
134 * '+', '=') must NOT be escaped. Some LDAP implementations do not decode
135 * non-required @verbatim <hex><hex> @endverbatim sequences in assertion
136 * values and will fail to match.
137 *
138 * @param[out] out Where to write the escaped value.
139 * @param[in] in Value to escape. Consumed on success.
140 * @return
141 * - >= 0 the number of bytes written to out.
142 * - < 0 the number of additional bytes out needed. Neither sbuff is advanced.
143 */
145{
146 static const bool filter_escape_chars[SBUFF_CHAR_CLASS] = {
147 ['\0'] = true,
148 ['*'] = true,
149 ['('] = true,
150 [')'] = true,
151 ['\\'] = true
152 };
153
154 return ldap_escape(out, in, filter_escape_chars);
155}
156
157/** Escape a value box for use as an RFC 4514 DN attribute value
158 *
159 * Suitable as a #fr_value_box_escape_func_t.
160 */
167
168/** Escape a value box for use as an RFC 4515 filter assertion value
169 *
170 * Suitable as a #fr_value_box_escape_func_t.
171 */
178
179/** Converts escaped DNs and filter strings into normal
180 *
181 * @note RFC 4515 says filter strings can only use the @verbatim <hex><hex> @endverbatim
182 * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
183 * with a backslash..
184 *
185 * Will unescape any special characters in strings, or @verbatim <hex><hex> @endverbatim
186 * sequences.
187 *
188 * @param request The current request.
189 * @param out Pointer to output buffer.
190 * @param outlen Size of the output buffer.
191 * @param in Escaped string string.
192 * @param arg Any additional arguments (unused).
193 */
194size_t fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
195{
196 char const *p;
197 char const *c1, *c2;
198 char c3;
199 size_t freespace = outlen;
200
201 if (outlen <= 1) return 0;
202
203 p = in;
204 while (*p && (--freespace > 0)) {
205 if (*p != '\\') {
206 next:
207 *out++ = *p++;
208 continue;
209 }
210
211 p++;
212
213 /* It's an escaped special, just remove the slash */
214 if (memchr(dn_specials, *p, sizeof(dn_specials) - 1)) {
215 *out++ = *p++;
216 continue;
217 }
218
219 /* Is a hex sequence */
220 if (!(c1 = memchr(hextab, tolower(p[0]), 16)) ||
221 !(c2 = memchr(hextab, tolower(p[1]), 16))) goto next;
222 c3 = ((c1 - hextab) << 4) + (c2 - hextab);
223
224 *out++ = c3;
225 p += 2;
226 }
227
228 *out = '\0';
229
230 return outlen - freespace;
231}
232
233
234/** Check whether a string looks like a DN
235 *
236 * @param[in] in Str to check.
237 * @param[in] inlen Length of string to check.
238 * @return
239 * - true if string looks like a DN.
240 * - false if string does not look like DN.
241 */
242bool fr_ldap_util_is_dn(char const *in, size_t inlen)
243{
244 char const *p;
245
246 char want = '=';
247 bool too_soon = true;
248 int comp = 1;
249
250 for (p = in; inlen > 0; p++, inlen--) {
251 if (p[0] == '\\') {
252 char c;
253
254 too_soon = false;
255
256 /*
257 * Invalid escape sequence, not a DN
258 */
259 if (inlen < 2) return false;
260
261 /*
262 * Double backslash, consume two chars
263 */
264 if (p[1] == '\\') {
265 inlen--;
266 p++;
267 continue;
268 }
269
270 /*
271 * Special, consume two chars
272 */
273 if (escapes[(uint8_t) p[1]]) {
274 inlen -= 1;
275 p += 1;
276 continue;
277 }
278
279 /*
280 * Invalid escape sequence, not a DN
281 */
282 if (inlen < 3) return false;
283
284 /*
285 * Hex encoding, consume three chars
286 */
287 if (fr_base16_decode(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1) {
288 inlen -= 2;
289 p += 2;
290 continue;
291 }
292
293 /*
294 * Invalid escape sequence, not a DN
295 */
296 return false;
297 }
298
299 switch (*p) {
300 case '=':
301 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
302 want = ',';
303 too_soon = true;
304 break;
305
306 case ',':
307 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
308 want = '=';
309 too_soon = true;
310 comp++;
311 break;
312
313 default:
314 too_soon = false;
315 break;
316 }
317 }
318
319 /*
320 * If the string ended with , or =, or the number
321 * of components was less than 2
322 *
323 * i.e. we don't have <attr>=<val>,<attr>=<val>
324 */
325 if (too_soon || (comp < 2)) return false;
326
327 return true;
328}
329
330/** Parse a subset (just server side sort and virtual list view for now) of LDAP URL extensions
331 *
332 * @param[out] sss Array of LDAPControl * pointers to add controls to.
333 * @param[in] sss_len How many elements remain in the sss array.
334 * @param[in] extensions A NULL terminated array of extensions.
335 * @return
336 * - >0 the number of controls added.
337 * - 0 if no controls added.
338 * - -1 on failure.
339 */
340int fr_ldap_parse_url_extensions(LDAPControl **sss, size_t sss_len, char *extensions[])
341{
342 LDAPControl **sss_p = sss, **sss_end = sss_p + sss_len;
343 int i;
344
345 if (!extensions) {
346 *sss_p = NULL;
347 return 0;
348 }
349
350 /*
351 * Parse extensions in the LDAP URL
352 */
353 for (i = 0; extensions[i]; i++) {
354 fr_sbuff_t sbuff = FR_SBUFF_IN(extensions[i], strlen(extensions[i]));
355 bool is_critical = false;
356
357 if (sss_p == sss_end) {
358 fr_strerror_printf("Too many extensions. Maximum is %ld", sss_len);
359 goto error;
360 }
361
362 if (fr_sbuff_next_if_char(&sbuff, '!')) is_critical = true;
363
364 /*
365 * Server side sort control
366 */
367 if (fr_sbuff_adv_past_str(&sbuff, "sss", 3)) {
368 LDAPSortKey **keys;
369 int ret;
370
371 if (!fr_sbuff_next_if_char(&sbuff, '=')) {
372 LDAPControl **s;
373 fr_strerror_const("Server side sort extension must be "
374 "in the format \"[!]sss=<key>[,key]\"");
375 error:
376 s = sss;
377 while (s < sss_p) {
378 if (*s) ldap_control_free(*s);
379 s++;
380 }
381 return -1;
382 }
383
384 ret = ldap_create_sort_keylist(&keys, fr_sbuff_current(&sbuff));
385 if (ret != LDAP_SUCCESS) {
386 fr_strerror_printf("Invalid server side sort value \"%s\": %s",
387 fr_sbuff_current(&sbuff), ldap_err2string(ret));
388 goto error;
389 }
390
391 if (*sss_p) ldap_control_free(*sss_p);
392
393 ret = ldap_create_sort_control(fr_ldap_handle_thread_local(), keys, is_critical ? 1 : 0, sss_p);
394 ldap_free_sort_keylist(keys);
395 if (ret != LDAP_SUCCESS) {
396 fr_strerror_printf("Failed creating server sort control: %s",
397 ldap_err2string(ret));
398 goto error;
399 }
400 sss_p++;
401 *sss_p = NULL; /* Terminate */
402 continue;
403 }
404
405 if (fr_sbuff_adv_past_str(&sbuff, "vlv", 3)) {
406 LDAPVLVInfo vlvinfo;
407 uint32_t ext_value;
408 struct berval attr_value;
409 int ret;
410
411 if (!fr_sbuff_next_if_char(&sbuff, '=')) {
412 vlv_error:
413 fr_strerror_const("Virtual list view extension must be "
414 "in the format \"[!]vlv=<before>/<after>(/<offset>/<count>|:<value>)");
415 goto error;
416 }
417
418 vlvinfo.ldvlv_context = NULL;
419
420 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
421 if (!fr_sbuff_next_if_char(&sbuff, '/')) goto vlv_error;
422 vlvinfo.ldvlv_before_count = ext_value;
423
424 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
425 vlvinfo.ldvlv_after_count = ext_value;
426
427 /* offset/count syntax */
428 if (fr_sbuff_next_if_char(&sbuff, '/')) {
429 /* Ensure attrvalue is null - this is how the type of vlv control is determined */
430 vlvinfo.ldvlv_attrvalue = NULL;
431
432 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
433 if (!fr_sbuff_next_if_char(&sbuff, '/')) goto error;
434 vlvinfo.ldvlv_offset = ext_value;
435
436 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
437 vlvinfo.ldvlv_count = ext_value;
438
439 /* greaterThanOrEqual attribute syntax*/
440 } else if (fr_sbuff_next_if_char(&sbuff, ':')) {
441 attr_value.bv_val = fr_sbuff_current(&sbuff);
442 attr_value.bv_len = fr_sbuff_remaining(&sbuff);
443 vlvinfo.ldvlv_attrvalue = &attr_value;
444
445 } else goto error;
446
447 ret = ldap_create_vlv_control(fr_ldap_handle_thread_local(), &vlvinfo, sss_p);
448
449 if (ret != LDAP_SUCCESS) {
450 fr_strerror_printf("Failed creating virtual list view control: %s",
451 ldap_err2string(ret));
452 goto error;
453 }
454
455 sss_p++;
456 *sss_p = NULL; /* Terminate */
457 continue;
458 }
459
460 fr_strerror_printf("URL extension \"%s\" not supported", extensions[i]);
461 return -1;
462 }
463
464 return (sss_end - sss_p);
465}
466
467/** Release value iteration state
468 *
469 * Must be called once for every fr_ldap_value_iter_init, whether
470 * iteration completed or not.
471 *
472 * @param[in] iter to release.
473 */
475{
476 ber_free(iter->ber, 0);
477 iter->ber = NULL;
478}
479
480/** Return the next value of the iterated attribute
481 *
482 * @param[out] err Set to -1 if the entry could not be parsed.
483 * Untouched otherwise. May be NULL.
484 * @param[in] iter to advance.
485 * @return
486 * - The next value.
487 * - NULL when the values are exhausted, or the entry could not be
488 * parsed.
489 */
491{
492 if (iter->end) return NULL;
493
494 if (ber_scanf(iter->ber, "m", &iter->value) == LBER_ERROR) {
495 fr_strerror_const("Malformed search result entry");
496 iter->end = true;
497 if (err) *err = -1;
498 return NULL;
499 }
500
501 if (ber_next_element(iter->ber, &iter->len, iter->last) == LBER_DEFAULT) iter->end = true;
502
503 return &iter->value;
504}
505
506/** Start an in place iteration over an attribute's values in an entry
507 *
508 * The returned values point into the result message the entry belongs
509 * to, nothing is copied, and the values remain valid until the result
510 * message is freed with ldap_msgfree.
511 *
512 * @param[out] err Set to -1 if the entry could not be parsed.
513 * Untouched otherwise. May be NULL.
514 * @param[out] iter to initialise. Release with fr_ldap_value_iter_done.
515 * @param[in] handle the entry was received on.
516 * @param[in] entry whose values to iterate.
517 * @param[in] attr to find.
518 * @return
519 * - The attribute's first value.
520 * - NULL if the entry does not contain the attribute, or could not
521 * be parsed.
522 */
523struct berval *fr_ldap_value_iter_init(int *err, fr_ldap_value_iter_t *iter, LDAP *handle, LDAPMessage *entry,
524 char const *attr)
525{
526 struct berval dn, name;
527 size_t attr_len = strlen(attr);
528 ber_len_t remaining;
529
530 *iter = (fr_ldap_value_iter_t){};
531
532 if (ldap_get_dn_ber(handle, entry, &iter->ber, &dn) != LDAP_SUCCESS) {
533 error:
534 fr_strerror_const("Malformed search result entry");
535 iter->end = true;
536 if (err) *err = -1;
537 return NULL;
538 }
539
540 for (;;) {
541 if (ber_get_option(iter->ber, LBER_OPT_BER_REMAINING_BYTES, &remaining) != LBER_OPT_SUCCESS) goto error;
542 if (remaining == 0) break;
543
544 if (ber_scanf(iter->ber, "{m" /*}*/, &name) == LBER_ERROR) goto error;
545
546 if ((name.bv_len != attr_len) || (strncasecmp(name.bv_val, attr, attr_len) != 0)) {
547 if (ber_scanf(iter->ber, "x") == LBER_ERROR) goto error;
548 continue;
549 }
550
551 if (ber_first_element(iter->ber, &iter->len, &iter->last) != LBER_DEFAULT) iter->found = true;
552 break;
553 }
554 if (!iter->found) {
555 iter->end = true;
556 return NULL;
557 }
558
559 return fr_ldap_value_iter_next(err, iter);
560}
561
562/** Free the ber held by an allocated value iterator
563 *
564 */
566{
568
569 return 0;
570}
571
572/** Allocate a value iterator, released when the iterator is freed
573 *
574 * Behaves as fr_ldap_value_iter_init, with the ber memory freed by a
575 * talloc destructor, so the iteration state is released when the
576 * iterator or any of its talloc ancestors are freed.
577 *
578 * @param[out] err Set to -1 if the entry could not be parsed.
579 * Untouched otherwise. May be NULL.
580 * @param[out] out The allocated iterator.
581 * @param[in] ctx to allocate the iterator in.
582 * @param[in] handle the entry was received on.
583 * @param[in] entry whose values to iterate.
584 * @param[in] attr to find.
585 * @return
586 * - The attribute's first value.
587 * - NULL if the entry does not contain the attribute, or could not
588 * be parsed.
589 */
590struct berval *fr_ldap_value_iter_alloc(int *err, fr_ldap_value_iter_t **out, TALLOC_CTX *ctx,
591 LDAP *handle, LDAPMessage *entry, char const *attr)
592{
594 struct berval *value;
595
596 MEM(iter = talloc(ctx, fr_ldap_value_iter_t));
597
598 value = fr_ldap_value_iter_init(err, iter, handle, entry, attr);
599 talloc_set_destructor(iter, _fr_ldap_value_iter_free);
600 *out = iter;
601
602 return value;
603}
604
605/** Sum the lengths of an attribute's values across every entry of a result
606 *
607 * The values are read in place from the result message, no arrays are
608 * allocated and no values are copied.
609 *
610 * @param[out] num Number of values found.
611 * @param[out] strings_len Total length of the values, including a NUL
612 * byte for each.
613 * @param[in] handle the result was received on.
614 * @param[in] result Head of the result message chain.
615 * @param[in] attr whose values to measure.
616 * @return
617 * - 0 on success.
618 * - -1 if an entry could not be parsed.
619 */
620int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LDAPMessage *result, char const *attr)
621{
622 LDAPMessage *entry;
623
624 *num = 0;
625 *strings_len = 0;
626
627 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
629 struct berval *value;
630 int err = 0;
631
632 for (value = fr_ldap_value_iter_init(&err, &iter, handle, entry, attr);
633 value;
634 value = fr_ldap_value_iter_next(&err, &iter)) {
635 *strings_len += value->bv_len + 1;
636 (*num)++;
637 }
639 if (unlikely(err < 0)) return -1;
640 }
641
642 return 0;
643}
644
645/** Copy an attribute's values from every entry of a result into a string list
646 *
647 * The list, its pointer array and every string come from a single talloc
648 * pool. The values are read in place from the result message, the only
649 * copies made are the strings in the list.
650 *
651 * @param[in] ctx to allocate the list in.
652 * @param[in] handle the result was received on.
653 * @param[in] result Head of the result message chain.
654 * @param[in] attr whose values to copy. May be NULL, in which case
655 * only the extra slots are allocated.
656 * @param[in] extra Leading pointer array slots to leave NULL, for the
657 * caller to fill with strings not copied into the pool.
658 * @return
659 * - List of the attribute's values. Empty if the result holds no
660 * values for the attribute.
661 * - NULL if an entry could not be parsed.
662 */
663talloc_str_list_t *fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result,
664 char const *attr, size_t extra)
665{
666 talloc_str_list_t *list = NULL;
667 LDAPMessage *entry;
668 size_t num = 0, strings_len = 0;
669
670 if (attr) {
671 if (unlikely(fr_ldap_result_values_len(&num, &strings_len, handle, result, attr) < 0)) return NULL;
672 }
673
674 MEM(list = talloc_str_list_alloc(ctx, num + extra, strings_len));
675 list->p += extra;
676
677 if (num == 0) return list;
678
679 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
681 struct berval *value;
682 int err = 0;
683
684 for (value = fr_ldap_value_iter_init(&err, &iter, handle, entry, attr);
685 value;
686 value = fr_ldap_value_iter_next(&err, &iter)) {
687 MEM(talloc_str_list_append(list, value->bv_val, value->bv_len));
688 }
690 if (unlikely(err < 0)) {
691 talloc_free(list);
692 return NULL;
693 }
694 }
695
696 return list;
697}
698
699/** Find an attribute in an entry, returning its first value referenced in place
700 *
701 * The value points into the result message the entry belongs to, nothing
702 * is allocated and nothing needs freeing. The value remains valid until
703 * the result message is freed with ldap_msgfree.
704 *
705 * @param[out] out First value of the attribute. Untouched when the
706 * attribute is not found.
707 * @param[in] handle the entry was received on.
708 * @param[in] entry to search.
709 * @param[in] attr to find.
710 * @return
711 * - The number of values the attribute has.
712 * - 0 if the entry does not contain the attribute.
713 * - -1 if the entry could not be parsed.
714 */
715int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr)
716{
718 struct berval *value;
719 int num = 0, err = 0;
720
721 for (value = fr_ldap_value_iter_init(&err, &iter, handle, entry, attr);
722 value;
723 value = fr_ldap_value_iter_next(&err, &iter)) {
724 if (num == 0) *out = *value;
725 num++;
726 }
728 if (unlikely(err < 0)) return -1;
729
730 return num;
731}
732
733/** Convert a berval to a talloced string
734 *
735 * The ldap_get_values function is deprecated, and ldap_get_values_len
736 * does not guarantee the berval buffers it returns are \0 terminated.
737 *
738 * For some cases this is fine, for others we require a \0 terminated
739 * buffer (feeding DNs back into libldap for example).
740 *
741 * @param ctx to allocate in.
742 * @param in Berval to copy.
743 * @return \0 terminated buffer containing in->bv_val.
744 */
745char *fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
746{
747 char *out;
748
749 out = talloc_array(ctx, char, in->bv_len + 1);
750 if (!out) return NULL;
751
752 memcpy(out, in->bv_val, in->bv_len);
753 out[in->bv_len] = '\0';
754
755 return out;
756}
757
758/** Convert a berval to a talloced buffer
759 *
760 * @param ctx to allocate in.
761 * @param in Berval to copy.
762 * @return buffer containing in->bv_val.
763 */
764uint8_t *fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
765{
766 uint8_t *out;
767
768 out = talloc_array(ctx, uint8_t, in->bv_len);
769 if (!out) return NULL;
770
771 memcpy(out, in->bv_val, in->bv_len);
772
773 return out;
774}
775
776/** Normalise escape sequences in a DN
777 *
778 * Characters in a DN can either be escaped as
779 * @verbatim <hex><hex> @endverbatim or @verbatim <special> @endverbatim
780 *
781 * The LDAP directory chooses how characters are escaped, which can make
782 * local comparisons of DNs difficult.
783 *
784 * Here we search for hex sequences that match special chars, and convert
785 * them to the @verbatim <special> @endverbatim form.
786 *
787 * @note the resulting output string will only ever be shorter than the
788 * input, so it's fine to use the same buffer for both out and in.
789 *
790 * @param out Where to write the normalised DN.
791 * @param in The input DN.
792 * @return The number of bytes written to out.
793 */
794size_t fr_ldap_util_normalise_dn(char *out, char const *in)
795{
796 char const *p;
797 char *o = out;
798
799 for (p = in; *p != '\0'; p++) {
800 if (p[0] == '\\') {
801 char c = '\0';
802
803 /*
804 * Double backslashes get passed through as-is.
805 * Copy both and let the for loop advance past the second.
806 */
807 if (p[1] == '\\') {
808 *o++ = p[0];
809 *o++ = p[1];
810 p++;
811 continue;
812 }
813
814 /*
815 * Hex encodings that have an alternative
816 * special encoding, get rewritten to the
817 * special encoding.
818 */
819 if (fr_base16_decode(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1 &&
820 escapes[(uint8_t) c]) {
821 *o++ = '\\';
822 *o++ = c;
823 p += 2;
824 continue;
825 }
826 }
827 *o++ = *p;
828 }
829 *o = '\0';
830
831 return o - out;
832}
833
834/** Find the place at which the two DN strings diverge
835 *
836 * Returns the length of the non matching string in full.
837 *
838 * @param full DN.
839 * @param part Partial DN as returned by ldap_parse_result.
840 * @return
841 * - Length of the portion of full which wasn't matched
842 * - -1 on failure.
843 */
844size_t fr_ldap_common_dn(char const *full, char const *part)
845{
846 size_t f_len, p_len, i;
847
848 if (!full) return -1;
849
850 f_len = strlen(full);
851
852 if (!part) return -1;
853
854 p_len = strlen(part);
855 if (!p_len) return f_len;
856
857 if ((f_len < p_len) || !f_len) return -1;
858
859 for (i = 0; i < p_len; i++) if (part[p_len - 1 - i] != full[f_len - 1 - i]) return -1;
860
861 return f_len - p_len;
862}
863
864/** Build a filter matching a set of objects by DN
865 *
866 * Produces `(|(<dn_attr>=<dn>)...)`, ANDed with filter if one is given.
867 * DN values are escaped.
868 *
869 * @param[in] ctx to allocate the filter string in.
870 * @param[in] dn_attr Attribute which matches an object's own DN,
871 * e.g. entryDN or distinguishedName.
872 * @param[in] filter Optional filter to AND with the DN set, may be NULL.
873 * @param[in] dn_list NULL terminated list of DNs to match, no empty strings.
874 * @return The filter string.
875 */
876char *fr_ldap_filter_afrom_dn_list(TALLOC_CTX *ctx, char const *dn_attr, char const *filter,
877 char const * const *dn_list)
878{
879 fr_sbuff_t sbuff;
880 fr_sbuff_uctx_talloc_t sbuff_ctx;
881 char const * const *dn_p;
882 bool has_filter = filter && *filter;
883
884 MEM(fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_ctx, 256, SIZE_MAX));
885
886 if (has_filter) MEM(fr_sbuff_in_sprintf(&sbuff, "(&%s", filter) >= 0);
887 MEM(fr_sbuff_in_strcpy_literal(&sbuff, "(|") >= 0);
888 for (dn_p = dn_list; *dn_p; dn_p++) {
889 MEM(fr_sbuff_in_sprintf(&sbuff, "(%s=", dn_attr) >= 0);
890 MEM(fr_ldap_filter_escape(&sbuff, &FR_SBUFF_IN_STR(*dn_p)) >= 0);
891 MEM(fr_sbuff_in_char(&sbuff, ')') >= 0);
892 }
893 MEM(fr_sbuff_in_char(&sbuff, ')') >= 0);
894 if (has_filter) MEM(fr_sbuff_in_char(&sbuff, ')') >= 0);
895
896 MEM(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) == 0);
897
898 return fr_sbuff_buff(&sbuff);
899}
900
901/** Combine filters and tokenize to a tmpl
902 *
903 * @param ctx To allocate combined filter in
904 * @param t_rules Rules for parsing combined filter.
905 * @param sub Array of subfilters (may contain NULLs).
906 * @param sublen Number of potential subfilters in array.
907 * @param out Where to write a pointer to the resulting tmpl.
908 * @return length of combined data.
909 */
910int fr_ldap_filter_to_tmpl(TALLOC_CTX *ctx, tmpl_rules_t const *t_rules, char const **sub, size_t sublen, tmpl_t **out)
911{
912 char *buffer = NULL;
913 char const *in = NULL;
914 fr_slen_t len = 0;
915 size_t i;
916 int cnt = 0;
917 tmpl_t *parsed;
918
919 *out = NULL;
920
921 /*
922 * Figure out how many filter elements we need to integrate
923 */
924 for (i = 0; i < sublen; i++) {
925 if (sub[i] && *sub[i]) {
926 in = sub[i];
927 cnt++;
928 len += strlen(sub[i]);
929 }
930 }
931
932 if (!cnt) return 0;
933
934 if (cnt > 1) {
935 /*
936 * Allocate a buffer large enough, allowing for (& ... ) plus trailing '\0'
937 */
938 buffer = talloc_array(ctx, char, len + 4);
939
940 strcpy(buffer, "(&");
941 for (i = 0; i < sublen; i++) {
942 if (sub[i] && (*sub[i] != '\0')) {
943 strcat(buffer, sub[i]);
944 }
945 }
946 strcat(buffer, ")");
947 in = buffer;
948 }
949
950 len = tmpl_afrom_substr(ctx, &parsed, &FR_SBUFF_IN_STR(in), T_DOUBLE_QUOTED_STRING, NULL, t_rules);
951
953
954 if (len < 0) {
955 EMARKER(in, -len, fr_strerror());
956 return -1;
957 }
958
959 *out = parsed;
960 return 0;
961}
962
963/** Check that a particular attribute is included in an attribute list
964 *
965 * @param[in] attrs list to check
966 * @param[in] attr to look for
967 * @return
968 * - 1 if attr is in list
969 * - 0 if attr is missing
970 * - -1 if checks not possible
971 */
972int fr_ldap_attrs_check(char const **attrs, char const *attr)
973{
974 size_t len, i;
975
976 if (!attr) return -1;
977
978 len = talloc_array_length(attrs);
979
980 for (i = 0; i < len; i++) {
981 if (!attrs[i]) continue;
982 if (strcasecmp(attrs[i], attr) == 0) return 1;
983 if (strcasecmp(attrs[i], "*") == 0) return 1;
984 }
985
986 return 0;
987}
988
989/** Check an LDAP server entry in URL format is valid
990 *
991 * @param[in,out] handle_config LDAP handle config being built
992 * @param[in] server string to parse
993 * @param[in] cs in which the server is defined
994 * @return
995 * - 0 for valid server definition
996 * - -1 for invalid server definition
997 */
998int fr_ldap_server_url_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION const *cs)
999{
1000 LDAPURLDesc *ldap_url;
1001 bool set_port_maybe = true;
1002 int default_port = LDAP_PORT;
1003 char const *p;
1004 char *url;
1005 CONF_ITEM *ci = (CONF_ITEM *)cf_pair_find(cs, "server");
1006
1007 if (ldap_url_parse(server, &ldap_url)) {
1008 cf_log_err(ci, "Parsing LDAP URL \"%s\" failed", server);
1009 ldap_url_error:
1010 ldap_free_urldesc(ldap_url);
1011 return -1;
1012 }
1013
1014 if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
1015 cf_log_err(ci, "Base DN cannot be specified via server URL");
1016 goto ldap_url_error;
1017 }
1018
1019 if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
1020 cf_log_err(ci, "Attribute list cannot be speciried via server URL");
1021 goto ldap_url_error;
1022 }
1023
1024 /*
1025 * ldap_url_parse sets this to base by default.
1026 */
1027 if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
1028 cf_log_err(ci, "Scope cannot be specified via server URL");
1029 goto ldap_url_error;
1030 }
1031 ldap_url->lud_scope = -1; /* Otherwise LDAP adds ?base */
1032
1033 /*
1034 * The public ldap_url_parse function sets the default
1035 * port, so we have to discover whether a port was
1036 * included ourselves.
1037 */
1038 if ((p = strchr(server, ']')) && (p[1] == ':')) { /* IPv6 */
1039 set_port_maybe = false;
1040 } else if ((p = strchr(server, ':')) && (strchr(p+1, ':') != NULL)) { /* IPv4 */
1041 set_port_maybe = false;
1042 }
1043
1044 /*
1045 * Figure out the default port from the URL
1046 */
1047 if (ldap_url->lud_scheme) {
1048 if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) {
1049 if (handle_config->start_tls == true) {
1050 cf_log_err(ci, "ldaps:// scheme is not compatible with 'start_tls'");
1051 goto ldap_url_error;
1052 }
1053 default_port = LDAPS_PORT;
1054 handle_config->tls_mode = LDAP_OPT_X_TLS_HARD;
1055 } else if (strcmp(ldap_url->lud_scheme, "ldapi") == 0) {
1056 set_port_maybe = false;
1057 }
1058 }
1059
1060 if (set_port_maybe) {
1061 /*
1062 * URL port overrides configured port.
1063 */
1064 ldap_url->lud_port = handle_config->port;
1065
1066 /*
1067 * If there's no URL port, then set it to the default
1068 * this is so debugging messages show explicitly
1069 * the port we're connecting to.
1070 */
1071 if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
1072 }
1073
1074 url = ldap_url_desc2str(ldap_url);
1075 if (!url) {
1076 cf_log_err(ci, "Failed recombining URL components");
1077 goto ldap_url_error;
1078 }
1079 handle_config->server = talloc_asprintf_append(handle_config->server, "%s ", url);
1080
1081 ldap_free_urldesc(ldap_url);
1082 ldap_memfree(url);
1083 return (0);
1084}
1085
1086/** Check an LDAP server config in server:port format is valid
1087 *
1088 * @param[in,out] handle_config LDAP handle config being built
1089 * @param[in] server string to parse
1090 * @param[in] cs in which the server is defined
1091 * @return
1092 * - 0 for valid server definition
1093 * - -1 for invalid server definition
1094 */
1095int fr_ldap_server_config_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION *cs)
1096{
1097 char const *p;
1098 char *q;
1099 int port = 0;
1100 size_t len;
1101
1102 port = handle_config->port;
1103
1104 /*
1105 * We don't support URLs if the library didn't provide
1106 * URL parsing functions.
1107 */
1108 if (strchr(server, '/')) {
1109 CONF_ITEM *ci;
1110 bad_server_fmt:
1111 ci = (CONF_ITEM *)cf_pair_find(cs, "server");
1112 cf_log_err(ci, "Invalid 'server' entry, must be in format <server>[:<port>] or "
1113 "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
1114 return -1;
1115 }
1116
1117 p = strrchr(server, ':');
1118 if (p) {
1119 port = (int)strtol((p + 1), &q, 10);
1120 if ((p == server) || ((p + 1) == q) || (*q != '\0')) goto bad_server_fmt;
1121 len = p - server;
1122 } else {
1123 len = strlen(server);
1124 }
1125 if (port == 0) port = LDAP_PORT;
1126
1127 handle_config->server = talloc_asprintf_append(handle_config->server, "ldap://%.*s:%i ",
1128 (int)len, server, port);
1129 return 0;
1130}
1131
1132/** Translate the error code emitted from ldap_url_parse and friends into something accessible with fr_strerror()
1133 *
1134 * @param[in] ldap_url_err The error code returned
1135 */
1136char const *fr_ldap_url_err_to_str(int ldap_url_err)
1137{
1138 switch (ldap_url_err) {
1139 case LDAP_URL_SUCCESS:
1140 return "success";
1141
1142 case LDAP_URL_ERR_MEM:
1143 return "no memory";
1144
1145 case LDAP_URL_ERR_PARAM:
1146 return "parameter is bad";
1147
1148 case LDAP_URL_ERR_BADSCHEME:
1149 return "URL doesn't begin with \"[c]ldap[si]://\"";
1150
1151 case LDAP_URL_ERR_BADENCLOSURE:
1152 return "URL is missing trailing \">\"";
1153
1154 case LDAP_URL_ERR_BADURL:
1155 return "URL is bad";
1156
1157 case LDAP_URL_ERR_BADHOST:
1158 return "host/port is bad";
1159
1160 case LDAP_URL_ERR_BADATTRS:
1161 return "bad (or missing) attributes";
1162
1163 case LDAP_URL_ERR_BADSCOPE:
1164 return "scope string is invalid (or missing)";
1165
1166 case LDAP_URL_ERR_BADFILTER:
1167 return "bad or missing filter";
1168
1169 case LDAP_URL_ERR_BADEXTS:
1170 return "bad or missing extensions";
1171
1172 default:
1173 return "unknown reason";
1174 }
1175}
1176
1177/** Dump out the contents of an LDAPMessage
1178 *
1179 * Intended to be called from a debugger.
1180 *
1181 * @param[in] entry LDAPMessage to dump.
1182 */
1183void fr_ldap_entry_dump(LDAPMessage *entry)
1184{
1185 char *dn;
1186 BerElement *ber = NULL;
1187 char *attr;
1188 struct berval **vals;
1189 int i;
1190 LDAP *ld = fr_ldap_handle_thread_local();
1191 int msgtype;
1192
1193 msgtype = ldap_msgtype(entry);
1194 switch (msgtype) {
1195 case LDAP_RES_SEARCH_ENTRY:
1196 dn = ldap_get_dn(ld, entry);
1197 if (dn) {
1198 DEBUG("dn: %s", dn);
1199 ldap_memfree(dn);
1200 }
1201
1202 for (attr = ldap_first_attribute(ld, entry, &ber);
1203 attr != NULL;
1204 attr = ldap_next_attribute(ld, entry, ber)) {
1205 vals = ldap_get_values_len(ld, entry, attr);
1206 if (!vals) {
1207 DEBUG("%s: no values", attr);
1208 ldap_memfree(attr);
1209 continue;
1210 }
1211
1212 for (i = 0; vals[i] != NULL; i++) {
1213 bool binary = false;
1214 ber_len_t j;
1215
1216 for (j = 0; j < vals[i]->bv_len; j++) {
1217 char c = vals[i]->bv_val[j];
1218 if ((c < 32) || (c > 126)) {
1219 binary = true;
1220 break;
1221 }
1222 }
1223
1224 if (binary) {
1225 DEBUG("%s[%u]: %pV", attr, i, fr_box_octets((uint8_t *)vals[i]->bv_val, vals[i]->bv_len));
1226 continue;
1227 }
1228
1229 DEBUG("%s[%u]: %pV", attr, i, fr_box_strvalue_len(vals[i]->bv_val, vals[i]->bv_len));
1230 }
1231
1232 ldap_value_free_len(vals);
1233 ldap_memfree(attr);
1234 }
1235 break;
1236
1237 case LDAP_RES_SEARCH_RESULT:
1238 case LDAP_RES_BIND:
1239 case LDAP_RES_MODIFY:
1240 case LDAP_RES_ADD:
1241 case LDAP_RES_DELETE:
1242 case LDAP_RES_COMPARE:
1243 case LDAP_RES_EXTENDED:
1244 {
1245 int rc;
1246 char *matched = NULL;
1247 char *errmsg = NULL;
1248 char **refs = NULL;
1249
1250 rc = ldap_parse_result(ld, entry, &msgtype, &matched, &errmsg, &refs, NULL, 0);
1251 if (rc != LDAP_SUCCESS) {
1252 DEBUG("failed to parse result: %s", ldap_err2string(rc));
1253 break;
1254 }
1255
1256 DEBUG("result code: %d (%s)", msgtype, ldap_err2string(msgtype));
1257
1258 if (matched && *matched) {
1259 DEBUG("matched DN: %s", matched);
1260 }
1261 if (errmsg && *errmsg) {
1262 DEBUG("error message: %s", errmsg);
1263 }
1264 if (refs) {
1265 for (i = 0; refs[i] != NULL; i++) {
1266 DEBUG("referral: %s", refs[i]);
1267 }
1268 }
1269
1270 if (matched) ldap_memfree(matched);
1271 if (errmsg) ldap_memfree(errmsg);
1272 if (refs) ldap_memvfree((void **)refs);
1273 }
1274 break;
1275
1276 default:
1277 DEBUG("unhandled LDAP message type: %d", msgtype);
1278 break;
1279 }
1280
1281 if (ber) ber_free(ber, 0);
1282}
static int const char char buffer[256]
Definition acutest.h:576
strcpy(log_entry->msg, buffer)
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:109
#define fr_base16_encode_byte(_out, _byte)
Definition base16.h:67
#define USES_APPLE_DEPRECATED_API
Definition build.h:547
#define RCSID(id)
Definition build.h:560
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1598
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:343
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define MEM(x)
Definition debug.h:38
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static fr_slen_t err
Definition dict.h:906
static fr_slen_t in
Definition dict.h:906
Test enumeration values.
Definition dict_test.h:92
Definition dwarf.c:424
talloc_free(hp)
static char const escape_chars[]
Definition jpath.c:92
ber_len_t len
Length of the current element.
Definition base.h:968
#define LDAP_DN_SAFE_FOR
Marks a value box as already escaped for use as a DN attribute value.
Definition base.h:1012
char * last
End marker of the value set.
Definition base.h:967
char * server
Initial server to bind to.
Definition base.h:233
#define LDAP_FILTER_SAFE_FOR
Marks a value box as already escaped for use as a filter assertion value.
Definition base.h:1016
bool end
All values have been returned.
Definition base.h:971
bool start_tls
Send the Start TLS message to the LDAP directory to start encrypted communications using the standard...
Definition base.h:267
bool found
The attribute was found in the entry.
Definition base.h:970
BerElement * ber
Cursor over the entry.
Definition base.h:966
uint16_t port
Port to use when binding to the server.
Definition base.h:236
struct berval value
Value the iterator is positioned on.
Definition base.h:969
Connection configuration.
Definition base.h:230
State of an in place iteration over an attribute's values.
Definition base.h:965
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
Definition base.c:1131
char const * fr_ldap_url_err_to_str(int ldap_url_err)
Translate the error code emitted from ldap_url_parse and friends into something accessible with fr_st...
Definition util.c:1136
struct berval * fr_ldap_value_iter_init(int *err, fr_ldap_value_iter_t *iter, LDAP *handle, LDAPMessage *entry, char const *attr)
Start an in place iteration over an attribute's values in an entry.
Definition util.c:523
static const char hextab[]
Definition util.c:39
static int _fr_ldap_value_iter_free(fr_ldap_value_iter_t *iter)
Free the ber held by an allocated value iterator.
Definition util.c:565
size_t fr_ldap_util_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Definition util.c:794
static const bool escapes[SBUFF_CHAR_CLASS]
Definition util.c:40
int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr)
Find an attribute in an entry, returning its first value referenced in place.
Definition util.c:715
int fr_ldap_filter_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box for use as an RFC 4515 filter assertion value.
Definition util.c:172
void fr_ldap_value_iter_done(fr_ldap_value_iter_t *iter)
Release value iteration state.
Definition util.c:474
bool fr_ldap_util_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
Definition util.c:242
fr_slen_t fr_ldap_dn_escape(fr_sbuff_t *out, fr_sbuff_t *in)
Escape a value for use as an RFC 4514 DN attribute value.
Definition util.c:95
size_t fr_ldap_common_dn(char const *full, char const *part)
Find the place at which the two DN strings diverge.
Definition util.c:844
struct berval * fr_ldap_value_iter_next(int *err, fr_ldap_value_iter_t *iter)
Return the next value of the iterated attribute.
Definition util.c:490
int fr_ldap_attrs_check(char const **attrs, char const *attr)
Check that a particular attribute is included in an attribute list.
Definition util.c:972
uint8_t * fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced buffer.
Definition util.c:764
int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LDAPMessage *result, char const *attr)
Sum the lengths of an attribute's values across every entry of a result.
Definition util.c:620
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:998
static USES_APPLE_DEPRECATED_API const char dn_specials[]
Definition util.c:38
fr_slen_t fr_ldap_filter_escape(fr_sbuff_t *out, fr_sbuff_t *in)
Escape a value for use as an RFC 4515 filter assertion value.
Definition util.c:144
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
Definition util.c:745
static fr_slen_t ldap_escape(fr_sbuff_t *out, fr_sbuff_t *in, bool const *escape_chars)
Copy in to out, hex escaping every byte flagged in escape_chars.
Definition util.c:63
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:1095
talloc_str_list_t * fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, char const *attr, size_t extra)
Copy an attribute's values from every entry of a result into a string list.
Definition util.c:663
int fr_ldap_dn_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box for use as an RFC 4514 DN attribute value.
Definition util.c:161
size_t fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts escaped DNs and filter strings into normal.
Definition util.c:194
void fr_ldap_entry_dump(LDAPMessage *entry)
Dump out the contents of an LDAPMessage.
Definition util.c:1183
int fr_ldap_parse_url_extensions(LDAPControl **sss, size_t sss_len, char *extensions[])
Parse a subset (just server side sort and virtual list view for now) of LDAP URL extensions.
Definition util.c:340
int fr_ldap_filter_to_tmpl(TALLOC_CTX *ctx, tmpl_rules_t const *t_rules, char const **sub, size_t sublen, tmpl_t **out)
Combine filters and tokenize to a tmpl.
Definition util.c:910
struct berval * fr_ldap_value_iter_alloc(int *err, fr_ldap_value_iter_t **out, TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *entry, char const *attr)
Allocate a value iterator, released when the iterator is freed.
Definition util.c:590
char * fr_ldap_filter_afrom_dn_list(TALLOC_CTX *ctx, char const *dn_attr, char const *filter, char const *const *dn_list)
Build a filter matching a set of objects by DN.
Definition util.c:876
#define EMARKER(_str, _marker_idx, _marker)
Definition log.h:237
unsigned int uint32_t
unsigned char uint8_t
ssize_t fr_slen_t
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:35
int strcasecmp(char *s1, char *s2)
Definition missing.c:65
static char const * url[FR_RADIUS_FAIL_MAX+1]
#define fr_assert(_expr)
Definition rad_assert.h:37
static fr_cmp_ret_t comp(void const *a, void const *b)
Definition rbmonkey.c:13
static char const * name
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
Definition sbuff.c:433
size_t fr_sbuff_adv_past_str(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
Definition sbuff.c:1818
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1627
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition sbuff.c:2194
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define SBUFF_CHAR_CLASS
Definition sbuff.h:203
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_STR(_start)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_in_strcpy_literal(_sbuff, _str)
#define fr_sbuff_in_char(_sbuff,...)
Talloc sbuff extension structure.
Definition sbuff.h:137
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
talloc_str_list_t * talloc_str_list_alloc(TALLOC_CTX *ctx, size_t num, size_t strings_len)
Allocate a list to hold num strings of strings_len total length.
Definition talloc.c:888
char const * talloc_str_list_append(talloc_str_list_t *list, char const *str, size_t len)
Append a copy of a string to a string list.
Definition talloc.c:954
char const ** p
Where the next appended string is written.
Definition talloc.h:255
A NULL terminated array of strings with an append cursor.
Definition talloc.h:253
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_value_box_escape_in_place_func(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_func_t escape)
Escape a value box in place using an sbuff escape function.
Definition value.c:7044
#define fr_value_box_is_safe_for_only(_box, _safe_for)
Definition value.h:1133
#define fr_box_strvalue_len(_val, _len)
Definition value.h:334
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1062
static size_t char ** out
Definition value.h:1062
#define fr_box_octets(_val, _len)
Definition value.h:336