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