The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
util.c
Go to the documentation of this file.
1/*
2 * This program is 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: 15a5ca2a3c6fe2049bff450343ce6bd7e49387ed $
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: 15a5ca2a3c6fe2049bff450343ce6bd7e49387ed $")
27
29
30#include <freeradius-devel/ldap/base.h>
31#include <freeradius-devel/util/base16.h>
32
33#include <stdarg.h>
34#include <ctype.h>
35
36static const char specials[] = ",+\"\\<>;*=()";
37static const char hextab[] = "0123456789abcdef";
38static const bool escapes[UINT8_MAX + 1] = {
39 [' '] = true,
40 ['#'] = true,
41 ['='] = true,
42 ['"'] = true,
43 ['+'] = true,
44 [','] = true,
45 [';'] = true,
46 ['<'] = true,
47 ['>'] = true,
48 ['\''] = true
49};
50
51/** Converts "bad" strings into ones which are safe for LDAP
52 *
53 * @note RFC 4515 says filter strings can only use the @verbatim <hex><hex> @endverbatim
54 * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
55 * with a backslash. For simplicity, we always use the hex escape sequences.
56 * In other areas where we're doing DN comparison, the DNs need to be normalised first
57 * so that they both use only hex escape sequences.
58 *
59 * @note This is a callback for xlat operations.
60 *
61 * Will escape any characters in input strings that would cause the string to be interpreted
62 * as part of a DN and or filter. Escape sequence is @verbatim <hex><hex> @endverbatim.
63 *
64 * @param request The current request.
65 * @param out Pointer to output buffer.
66 * @param outlen Size of the output buffer.
67 * @param in Raw unescaped string.
68 * @param arg Any additional arguments (unused).
69 */
70size_t fr_ldap_uri_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
71{
72 size_t left = outlen;
73
74 if ((*in == ' ') || (*in == '#')) goto encode;
75
76 while (*in) {
77 /*
78 * Encode unsafe characters.
79 */
80 if (memchr(specials, *in, sizeof(specials) - 1)) {
81 encode:
82 /*
83 * Only 3 or less bytes available.
84 */
85 if (left <= 3) break;
86
87 *out++ = '\\';
88 *out++ = hextab[(*in >> 4) & 0x0f];
89 *out++ = hextab[*in & 0x0f];
90 in++;
91 left -= 3;
92
93 continue;
94 }
95
96 if (left <= 1) break;
97
98 /*
99 * Doesn't need encoding
100 */
101 *out++ = *in++;
102 left--;
103 }
104
105 *out = '\0';
106
107 return outlen - left;
108}
109
111{
112 fr_sbuff_t sbuff;
113 fr_sbuff_uctx_talloc_t sbuff_ctx;
114 size_t len;
115 fr_value_box_entry_t entry;
116
118
119 if ((vb->type != FR_TYPE_STRING) && (fr_value_box_cast_in_place(vb, vb, FR_TYPE_STRING, NULL) < 0)) {
121 return -1;
122 }
123
124 if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, vb->vb_length * 3, vb->vb_length * 3)) {
125 fr_strerror_printf_push("Failed to allocate buffer for escaped filter");
126 return -1;
127 }
128
129 len = fr_ldap_uri_escape_func(NULL, fr_sbuff_buff(&sbuff), vb->vb_length * 3 + 1, vb->vb_strvalue, NULL);
130
131 /*
132 * If the returned length is unchanged, the value was already safe
133 */
134 if (len == vb->vb_length) {
135 talloc_free(fr_sbuff_buff(&sbuff));
136 } else {
137 entry = vb->entry;
138 fr_sbuff_trim_talloc(&sbuff, len);
140 fr_value_box_strdup_shallow(vb, NULL, fr_sbuff_buff(&sbuff), vb->tainted);
141 vb->entry = entry;
142 }
143
145
146 return 0;
147}
148
149/** Converts escaped DNs and filter strings into normal
150 *
151 * @note RFC 4515 says filter strings can only use the @verbatim <hex><hex> @endverbatim
152 * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
153 * with a backslash..
154 *
155 * Will unescape any special characters in strings, or @verbatim <hex><hex> @endverbatim
156 * sequences.
157 *
158 * @param request The current request.
159 * @param out Pointer to output buffer.
160 * @param outlen Size of the output buffer.
161 * @param in Escaped string string.
162 * @param arg Any additional arguments (unused).
163 */
164size_t fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
165{
166 char const *p;
167 char *c1, *c2, c3;
168 size_t freespace = outlen;
169
170 if (outlen <= 1) return 0;
171
172 p = in;
173 while (*p && (--freespace > 0)) {
174 if (*p != '\\') {
175 next:
176 *out++ = *p++;
177 continue;
178 }
179
180 p++;
181
182 /* It's an escaped special, just remove the slash */
183 if (memchr(specials, *p, sizeof(specials) - 1)) {
184 *out++ = *p++;
185 continue;
186 }
187
188 /* Is a hex sequence */
189 if (!(c1 = memchr(hextab, tolower(p[0]), 16)) ||
190 !(c2 = memchr(hextab, tolower(p[1]), 16))) goto next;
191 c3 = ((c1 - hextab) << 4) + (c2 - hextab);
192
193 *out++ = c3;
194 p += 2;
195 }
196
197 *out = '\0';
198
199 return outlen - freespace;
200}
201
202
203/** Check whether a string looks like a DN
204 *
205 * @param[in] in Str to check.
206 * @param[in] inlen Length of string to check.
207 * @return
208 * - true if string looks like a DN.
209 * - false if string does not look like DN.
210 */
211bool fr_ldap_util_is_dn(char const *in, size_t inlen)
212{
213 char const *p;
214
215 char want = '=';
216 bool too_soon = true;
217 int comp = 1;
218
219 for (p = in; inlen > 0; p++, inlen--) {
220 if (p[0] == '\\') {
221 char c;
222
223 too_soon = false;
224
225 /*
226 * Invalid escape sequence, not a DN
227 */
228 if (inlen < 2) return false;
229
230 /*
231 * Double backslash, consume two chars
232 */
233 if (p[1] == '\\') {
234 inlen--;
235 p++;
236 continue;
237 }
238
239 /*
240 * Special, consume two chars
241 */
242 if (escapes[(uint8_t) p[1]]) {
243 inlen -= 1;
244 p += 1;
245 continue;
246 }
247
248 /*
249 * Invalid escape sequence, not a DN
250 */
251 if (inlen < 3) return false;
252
253 /*
254 * Hex encoding, consume three chars
255 */
256 if (fr_base16_decode(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1) {
257 inlen -= 2;
258 p += 2;
259 continue;
260 }
261
262 /*
263 * Invalid escape sequence, not a DN
264 */
265 return false;
266 }
267
268 switch (*p) {
269 case '=':
270 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
271 want = ',';
272 too_soon = true;
273 break;
274
275 case ',':
276 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
277 want = '=';
278 too_soon = true;
279 comp++;
280 break;
281
282 default:
283 too_soon = false;
284 break;
285 }
286 }
287
288 /*
289 * If the string ended with , or =, or the number
290 * of components was less than 2
291 *
292 * i.e. we don't have <attr>=<val>,<attr>=<val>
293 */
294 if (too_soon || (comp < 2)) return false;
295
296 return true;
297}
298
299/** Parse a subset (just server side sort and virtual list view for now) of LDAP URL extensions
300 *
301 * @param[out] sss Array of LDAPControl * pointers to add controls to.
302 * @param[in] sss_len How many elements remain in the sss array.
303 * @param[in] extensions A NULL terminated array of extensions.
304 * @return
305 * - >0 the number of controls added.
306 * - 0 if no controls added.
307 * - -1 on failure.
308 */
309int fr_ldap_parse_url_extensions(LDAPControl **sss, size_t sss_len, char *extensions[])
310{
311 LDAPControl **sss_p = sss, **sss_end = sss_p + sss_len;
312 int i;
313
314 if (!extensions) {
315 *sss_p = NULL;
316 return 0;
317 }
318
319 /*
320 * Parse extensions in the LDAP URL
321 */
322 for (i = 0; extensions[i]; i++) {
323 fr_sbuff_t sbuff = FR_SBUFF_IN(extensions[i], strlen(extensions[i]));
324 bool is_critical = false;
325
326 if (sss_p == sss_end) {
327 fr_strerror_printf("Too many extensions. Maximum is %ld", sss_len);
328 goto error;
329 }
330
331 if (fr_sbuff_next_if_char(&sbuff, '!')) is_critical = true;
332
333 /*
334 * Server side sort control
335 */
336 if (fr_sbuff_adv_past_str(&sbuff, "sss", 3)) {
337 LDAPSortKey **keys;
338 int ret;
339
340 if (!fr_sbuff_next_if_char(&sbuff, '=')) {
341 LDAPControl **s;
342 fr_strerror_const("Server side sort extension must be "
343 "in the format \"[!]sss=<key>[,key]\"");
344 error:
345 s = sss;
346 while (s < sss_p) {
347 if (*s) ldap_control_free(*s);
348 s++;
349 }
350 return -1;
351 }
352
353 ret = ldap_create_sort_keylist(&keys, fr_sbuff_current(&sbuff));
354 if (ret != LDAP_SUCCESS) {
355 fr_strerror_printf("Invalid server side sort value \"%s\": %s",
356 fr_sbuff_current(&sbuff), ldap_err2string(ret));
357 goto error;
358 }
359
360 if (*sss_p) ldap_control_free(*sss_p);
361
362 ret = ldap_create_sort_control(fr_ldap_handle_thread_local(), keys, is_critical ? 1 : 0, sss_p);
363 ldap_free_sort_keylist(keys);
364 if (ret != LDAP_SUCCESS) {
365 fr_strerror_printf("Failed creating server sort control: %s",
366 ldap_err2string(ret));
367 goto error;
368 }
369 sss_p++;
370 *sss_p = NULL; /* Terminate */
371 continue;
372 }
373
374 if (fr_sbuff_adv_past_str(&sbuff, "vlv", 3)) {
375 LDAPVLVInfo vlvinfo;
376 uint32_t ext_value;
377 struct berval attr_value;
378 int ret;
379
380 if (!fr_sbuff_next_if_char(&sbuff, '=')) {
381 vlv_error:
382 fr_strerror_const("Virtual list view extension must be "
383 "in the format \"[!]vlv=<before>/<after>(/<offset>/<count>|:<value>)");
384 goto error;
385 }
386
387 vlvinfo.ldvlv_context = NULL;
388
389 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
390 if (!fr_sbuff_next_if_char(&sbuff, '/')) goto vlv_error;
391 vlvinfo.ldvlv_before_count = ext_value;
392
393 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
394 vlvinfo.ldvlv_after_count = ext_value;
395
396 /* offset/count syntax */
397 if (fr_sbuff_next_if_char(&sbuff, '/')) {
398 /* Ensure attrvalue is null - this is how the type of vlv control is determined */
399 vlvinfo.ldvlv_attrvalue = NULL;
400
401 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
402 if (!fr_sbuff_next_if_char(&sbuff, '/')) goto error;
403 vlvinfo.ldvlv_offset = ext_value;
404
405 if (fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) goto vlv_error;
406 vlvinfo.ldvlv_count = ext_value;
407
408 /* greaterThanOrEqual attribute syntax*/
409 } else if (fr_sbuff_next_if_char(&sbuff, ':')) {
410 attr_value.bv_val = fr_sbuff_current(&sbuff);
411 attr_value.bv_len = fr_sbuff_remaining(&sbuff);
412 vlvinfo.ldvlv_attrvalue = &attr_value;
413
414 } else goto error;
415
416 ret = ldap_create_vlv_control(fr_ldap_handle_thread_local(), &vlvinfo, sss_p);
417
418 if (ret != LDAP_SUCCESS) {
419 fr_strerror_printf("Failed creating virtual list view control: %s",
420 ldap_err2string(ret));
421 goto error;
422 }
423
424 sss_p++;
425 *sss_p = NULL; /* Terminate */
426 continue;
427 }
428
429 fr_strerror_printf("URL extension \"%s\" not supported", extensions[i]);
430 return -1;
431 }
432
433 return (sss_end - sss_p);
434}
435
436/** Convert a berval to a talloced string
437 *
438 * The ldap_get_values function is deprecated, and ldap_get_values_len
439 * does not guarantee the berval buffers it returns are \0 terminated.
440 *
441 * For some cases this is fine, for others we require a \0 terminated
442 * buffer (feeding DNs back into libldap for example).
443 *
444 * @param ctx to allocate in.
445 * @param in Berval to copy.
446 * @return \0 terminated buffer containing in->bv_val.
447 */
448char *fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
449{
450 char *out;
451
452 out = talloc_array(ctx, char, in->bv_len + 1);
453 if (!out) return NULL;
454
455 memcpy(out, in->bv_val, in->bv_len);
456 out[in->bv_len] = '\0';
457
458 return out;
459}
460
461/** Convert a berval to a talloced buffer
462 *
463 * @param ctx to allocate in.
464 * @param in Berval to copy.
465 * @return buffer containing in->bv_val.
466 */
467uint8_t *fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
468{
469 uint8_t *out;
470
471 out = talloc_array(ctx, uint8_t, in->bv_len);
472 if (!out) return NULL;
473
474 memcpy(out, in->bv_val, in->bv_len);
475
476 return out;
477}
478
479/** Normalise escape sequences in a DN
480 *
481 * Characters in a DN can either be escaped as
482 * @verbatim <hex><hex> @endverbatim or @verbatim <special> @endverbatim
483 *
484 * The LDAP directory chooses how characters are escaped, which can make
485 * local comparisons of DNs difficult.
486 *
487 * Here we search for hex sequences that match special chars, and convert
488 * them to the @verbatim <special> @endverbatim form.
489 *
490 * @note the resulting output string will only ever be shorter than the
491 * input, so it's fine to use the same buffer for both out and in.
492 *
493 * @param out Where to write the normalised DN.
494 * @param in The input DN.
495 * @return The number of bytes written to out.
496 */
497size_t fr_ldap_util_normalise_dn(char *out, char const *in)
498{
499 char const *p;
500 char *o = out;
501
502 for (p = in; *p != '\0'; p++) {
503 if (p[0] == '\\') {
504 char c = '\0';
505
506 /*
507 * Double backslashes get processed specially
508 */
509 if (p[1] == '\\') {
510 p += 1;
511 *o++ = p[0];
512 *o++ = p[1];
513 continue;
514 }
515
516 /*
517 * Hex encodings that have an alternative
518 * special encoding, get rewritten to the
519 * special encoding.
520 */
521 if (fr_base16_decode(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1 &&
522 escapes[(uint8_t) c]) {
523 *o++ = '\\';
524 *o++ = c;
525 p += 2;
526 continue;
527 }
528 }
529 *o++ = *p;
530 }
531 *o = '\0';
532
533 return o - out;
534}
535
536/** Find the place at which the two DN strings diverge
537 *
538 * Returns the length of the non matching string in full.
539 *
540 * @param full DN.
541 * @param part Partial DN as returned by ldap_parse_result.
542 * @return
543 * - Length of the portion of full which wasn't matched
544 * - -1 on failure.
545 */
546size_t fr_ldap_common_dn(char const *full, char const *part)
547{
548 size_t f_len, p_len, i;
549
550 if (!full) return -1;
551
552 f_len = strlen(full);
553
554 if (!part) return -1;
555
556 p_len = strlen(part);
557 if (!p_len) return f_len;
558
559 if ((f_len < p_len) || !f_len) return -1;
560
561 for (i = 0; i < p_len; i++) if (part[p_len - i] != full[f_len - i]) return -1;
562
563 return f_len - p_len;
564}
565
566/** Combine filters and tokenize to a tmpl
567 *
568 * @param ctx To allocate combined filter in
569 * @param t_rules Rules for parsing combined filter.
570 * @param sub Array of subfilters (may contain NULLs).
571 * @param sublen Number of potential subfilters in array.
572 * @param out Where to write a pointer to the resulting tmpl.
573 * @return length of combined data.
574 */
575int fr_ldap_filter_to_tmpl(TALLOC_CTX *ctx, tmpl_rules_t const *t_rules, char const **sub, size_t sublen, tmpl_t **out)
576{
577 char *buffer = NULL;
578 char const *in = NULL;
579 ssize_t len = 0;
580 size_t i;
581 int cnt = 0;
582 tmpl_t *parsed;
583
584 *out = NULL;
585
586 /*
587 * Figure out how many filter elements we need to integrate
588 */
589 for (i = 0; i < sublen; i++) {
590 if (sub[i] && *sub[i]) {
591 in = sub[i];
592 cnt++;
593 len += strlen(sub[i]);
594 }
595 }
596
597 if (!cnt) return 0;
598
599 if (cnt > 1) {
600 /*
601 * Allocate a buffer large enough, allowing for (& ... ) plus trailing '\0'
602 */
603 buffer = talloc_array(ctx, char, len + 4);
604
605 strcpy(buffer, "(&");
606 for (i = 0; i < sublen; i++) {
607 if (sub[i] && (*sub[i] != '\0')) {
608 strcat(buffer, sub[i]);
609 }
610 }
611 strcat(buffer, ")");
612 in = buffer;
613 }
614
615 len = tmpl_afrom_substr(ctx, &parsed, &FR_SBUFF_IN(in, strlen(in)), T_DOUBLE_QUOTED_STRING, NULL, t_rules);
616
618
619 if (len < 0) {
620 EMARKER(in, -len, fr_strerror());
621 return -1;
622 }
623
624 *out = parsed;
625 return 0;
626}
627
628/** Check that a particular attribute is included in an attribute list
629 *
630 * @param[in] attrs list to check
631 * @param[in] attr to look for
632 * @return
633 * - 1 if attr is in list
634 * - 0 if attr is missing
635 * - -1 if checks not possible
636 */
637int fr_ldap_attrs_check(char const **attrs, char const *attr)
638{
639 size_t len, i;
640
641 if (!attr) return -1;
642
643 len = talloc_array_length(attrs);
644
645 for (i = 0; i < len; i++) {
646 if (!attrs[i]) continue;
647 if (strcasecmp(attrs[i], attr) == 0) return 1;
648 if (strcasecmp(attrs[i], "*") == 0) return 1;
649 }
650
651 return 0;
652}
653
654/** Check an LDAP server entry in URL format is valid
655 *
656 * @param[in,out] handle_config LDAP handle config being built
657 * @param[in] server string to parse
658 * @param[in] cs in which the server is defined
659 * @return
660 * - 0 for valid server definition
661 * - -1 for invalid server definition
662 */
663int fr_ldap_server_url_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION const *cs)
664{
665 LDAPURLDesc *ldap_url;
666 bool set_port_maybe = true;
667 int default_port = LDAP_PORT;
668 char *p, *url;
669 CONF_ITEM *ci = (CONF_ITEM *)cf_pair_find(cs, "server");
670
671 if (ldap_url_parse(server, &ldap_url)) {
672 cf_log_err(ci, "Parsing LDAP URL \"%s\" failed", server);
673 ldap_url_error:
674 ldap_free_urldesc(ldap_url);
675 return -1;
676 }
677
678 if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
679 cf_log_err(ci, "Base DN cannot be specified via server URL");
680 goto ldap_url_error;
681 }
682
683 if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
684 cf_log_err(ci, "Attribute list cannot be speciried via server URL");
685 goto ldap_url_error;
686 }
687
688 /*
689 * ldap_url_parse sets this to base by default.
690 */
691 if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
692 cf_log_err(ci, "Scope cannot be specified via server URL");
693 goto ldap_url_error;
694 }
695 ldap_url->lud_scope = -1; /* Otherwise LDAP adds ?base */
696
697 /*
698 * The public ldap_url_parse function sets the default
699 * port, so we have to discover whether a port was
700 * included ourselves.
701 */
702 if ((p = strchr(server, ']')) && (p[1] == ':')) { /* IPv6 */
703 set_port_maybe = false;
704 } else if ((p = strchr(server, ':')) && (strchr(p+1, ':') != NULL)) { /* IPv4 */
705 set_port_maybe = false;
706 }
707
708 /*
709 * Figure out the default port from the URL
710 */
711 if (ldap_url->lud_scheme) {
712 if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) {
713 if (handle_config->start_tls == true) {
714 cf_log_err(ci, "ldaps:// scheme is not compatible with 'start_tls'");
715 goto ldap_url_error;
716 }
717 default_port = LDAPS_PORT;
718 handle_config->tls_mode = LDAP_OPT_X_TLS_HARD;
719 } else if (strcmp(ldap_url->lud_scheme, "ldapi") == 0) {
720 set_port_maybe = false;
721 }
722 }
723
724 if (set_port_maybe) {
725 /*
726 * URL port overrides configured port.
727 */
728 ldap_url->lud_port = handle_config->port;
729
730 /*
731 * If there's no URL port, then set it to the default
732 * this is so debugging messages show explicitly
733 * the port we're connecting to.
734 */
735 if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
736 }
737
738 url = ldap_url_desc2str(ldap_url);
739 if (!url) {
740 cf_log_err(ci, "Failed recombining URL components");
741 goto ldap_url_error;
742 }
743 handle_config->server = talloc_asprintf_append(handle_config->server, "%s ", url);
744
745 ldap_free_urldesc(ldap_url);
746 ldap_memfree(url);
747 return (0);
748}
749
750/** Check an LDAP server config in server:port format is valid
751 *
752 * @param[in,out] handle_config LDAP handle config being built
753 * @param[in] server string to parse
754 * @param[in] cs in which the server is defined
755 * @return
756 * - 0 for valid server definition
757 * - -1 for invalid server definition
758 */
759int fr_ldap_server_config_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION *cs)
760{
761 char const *p;
762 char *q;
763 int port = 0;
764 size_t len;
765
766 port = handle_config->port;
767
768 /*
769 * We don't support URLs if the library didn't provide
770 * URL parsing functions.
771 */
772 if (strchr(server, '/')) {
773 CONF_ITEM *ci;
774 bad_server_fmt:
775 ci = (CONF_ITEM *)cf_pair_find(cs, "server");
776 cf_log_err(ci, "Invalid 'server' entry, must be in format <server>[:<port>] or "
777 "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
778 return -1;
779 }
780
781 p = strrchr(server, ':');
782 if (p) {
783 port = (int)strtol((p + 1), &q, 10);
784 if ((p == server) || ((p + 1) == q) || (*q != '\0')) goto bad_server_fmt;
785 len = p - server;
786 } else {
787 len = strlen(server);
788 }
789 if (port == 0) port = LDAP_PORT;
790
791 handle_config->server = talloc_asprintf_append(handle_config->server, "ldap://%.*s:%i ",
792 (int)len, server, port);
793 return 0;
794}
795
796/** Translate the error code emitted from ldap_url_parse and friends into something accessible with fr_strerror()
797 *
798 * @param[in] ldap_url_err The error code returned
799 */
800char const *fr_ldap_url_err_to_str(int ldap_url_err)
801{
802 switch (ldap_url_err) {
803 case LDAP_URL_SUCCESS:
804 return "success";
805
806 case LDAP_URL_ERR_MEM:
807 return "no memory";
808
809 case LDAP_URL_ERR_PARAM:
810 return "parameter is bad";
811
812 case LDAP_URL_ERR_BADSCHEME:
813 return "URL doesn't begin with \"[c]ldap[si]://\"";
814
815 case LDAP_URL_ERR_BADENCLOSURE:
816 return "URL is missing trailing \">\"";
817
818 case LDAP_URL_ERR_BADURL:
819 return "URL is bad";
820
821 case LDAP_URL_ERR_BADHOST:
822 return "host/port is bad";
823
824 case LDAP_URL_ERR_BADATTRS:
825 return "bad (or missing) attributes";
826
827 case LDAP_URL_ERR_BADSCOPE:
828 return "scope string is invalid (or missing)";
829
830 case LDAP_URL_ERR_BADFILTER:
831 return "bad or missing filter";
832
833 case LDAP_URL_ERR_BADEXTS:
834 return "bad or missing extensions";
835
836 default:
837 return "unknown reason";
838 }
839}
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:95
#define USES_APPLE_DEPRECATED_API
Definition build.h:470
#define RCSID(id)
Definition build.h:483
#define UNUSED
Definition build.h:315
Common header for all CONF_* types.
Definition cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
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:1439
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
static fr_slen_t in
Definition dict.h:827
char * server
Initial server to bind to.
Definition base.h:224
bool start_tls
Send the Start TLS message to the LDAP directory to start encrypted communications using the standard...
Definition base.h:258
uint16_t port
Port to use when binding to the server.
Definition base.h:227
Connection configuration.
Definition base.h:221
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
Definition base.c:1106
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:800
static const char hextab[]
Definition util.c:37
size_t fr_ldap_util_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Definition util.c:497
size_t fr_ldap_uri_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts "bad" strings into ones which are safe for LDAP.
Definition util.c:70
bool fr_ldap_util_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
Definition util.c:211
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:546
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:637
static USES_APPLE_DEPRECATED_API const char specials[]
Definition util.c:36
uint8_t * fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced buffer.
Definition util.c:467
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:663
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
Definition util.c:448
int fr_ldap_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Definition util.c:110
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:759
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:164
static const bool escapes[UINT8_MAX+1]
Definition util.c:38
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:309
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:575
#define EMARKER(_str, _marker_idx, _marker)
Definition log.h:232
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define UINT8_MAX
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
Definition bio.c:1140
static int8_t comp(void const *a, void const *b)
Definition rbmonkey.c:13
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:419
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:1712
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:2088
#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_out(_err, _out, _in)
#define fr_sbuff_remaining(_sbuff_or_marker)
Talloc sbuff extension structure.
Definition sbuff.h:139
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:347
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
#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:3572
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3681
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4046
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1048
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1055
static size_t char fr_sbuff_t size_t inlen
Definition value.h:997
static size_t char ** out
Definition value.h:997