From: Alan T. DeKok Date: Sat, 22 Jul 2023 12:39:47 +0000 (-0400) Subject: add and use fr_pair_print_secure() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eaae58f458a098fc02017818291a48b2171f4f48;p=thirdparty%2Ffreeradius-server.git add and use fr_pair_print_secure() to omit secrets when printing pairs --- diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index 2c4609f8c87..82cb64c5c23 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -772,10 +772,17 @@ static inline fr_slen_t CC_HINT(nonnull(2,3)) ssize_t fr_pair_print(fr_sbuff_t *out, fr_pair_t const *parent, fr_pair_t const *vp) CC_HINT(nonnull(1,3)); +ssize_t fr_pair_print_secure(fr_sbuff_t *out, fr_pair_t const *parent, + fr_pair_t const *vp) CC_HINT(nonnull(1,3)); + static inline fr_slen_t CC_HINT(nonnull(2,4)) fr_pair_aprint(TALLOC_CTX *ctx, char **out, fr_pair_t const *parent, fr_pair_t const *vp) SBUFF_OUT_TALLOC_FUNC_NO_LEN_DEF(fr_pair_print, parent, vp) +static inline fr_slen_t CC_HINT(nonnull(2,4)) + fr_pair_aprint_secure(TALLOC_CTX *ctx, char **out, fr_pair_t const *parent, fr_pair_t const *vp) + SBUFF_OUT_TALLOC_FUNC_NO_LEN_DEF(fr_pair_print_secure, parent, vp) + void fr_pair_fprint(FILE *, fr_pair_t const *vp) CC_HINT(nonnull); #define fr_pair_list_log(_log, _lvl, _list) _fr_pair_list_log(_log, _lvl, NULL, _list, __FILE__, __LINE__); diff --git a/src/lib/util/pair_print.c b/src/lib/util/pair_print.c index 48f872f16b1..22bcd8d4988 100644 --- a/src/lib/util/pair_print.c +++ b/src/lib/util/pair_print.c @@ -114,6 +114,91 @@ ssize_t fr_pair_print(fr_sbuff_t *out, fr_pair_t const *parent, fr_pair_t const FR_SBUFF_SET_RETURN(out, &our_out); } +/** Print one attribute and value to a string with escape rules + * + * Similar to fr_pair_print(), but secrets are omitted. This function duplicates parts of the functionality + * of fr_pair_print(). fr_pair_print_value_quoted(), and fr_value_box_print_quoted(), but for the special + * case of secure strings. + * + * Note that only secrets of type "string" and "octets" are omitted. Other "secret" data types are still + * printed as-is. + * + * "octets" are still printed as "<<< secret >>>". Which won't parse correctly, but that's fine. Because + * omitted data is not meant to be parsed into real data. + * + * @param[in] out Where to write the string. + * @param[in] parent If not NULL, only print OID components from + * this parent to the VP. + * @param[in] vp to print. + + * @return + * - < 0 on error + * - Length of data written to out. + * - value >= outlen on truncation. + */ +ssize_t fr_pair_print_secure(fr_sbuff_t *out, fr_pair_t const *parent, fr_pair_t const *vp) +{ + char const *token = NULL; + fr_sbuff_t our_out = FR_SBUFF(out); + fr_dict_attr_t const *parent_da = NULL; + + PAIR_VERIFY(vp); + + if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) { + token = fr_tokens[vp->op]; + } else { + token = ""; + } + + if (parent && (parent->vp_type != FR_TYPE_GROUP)) parent_da = parent->da; + + if (vp->da->flags.is_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw."); + FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent_da, vp->da, false); + FR_SBUFF_IN_CHAR_RETURN(&our_out, ' '); + FR_SBUFF_IN_STRCPY_RETURN(&our_out, token); + FR_SBUFF_IN_CHAR_RETURN(&our_out, ' '); + + if (fr_type_is_leaf(vp->vp_type)) { + switch (vp->vp_type) { + case FR_TYPE_STRING: + if (vp->data.secret) goto secret; + FALL_THROUGH; + + case FR_TYPE_DATE: + FR_SBUFF_IN_CHAR_RETURN(&our_out, '"'); + FR_SBUFF_RETURN(fr_value_box_print, &our_out, &vp->data, &fr_value_escape_double); + FR_SBUFF_IN_CHAR_RETURN(&our_out, '"'); + break; + + case FR_TYPE_OCTETS: + if (vp->data.secret) { + secret: + FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "<<< secret >>>"); + break; + } + FALL_THROUGH; + + default: + if (fr_value_box_print(&our_out, &vp->data, NULL) < 0) return -1; + break; + } + } else { + fr_pair_t *child; + fr_dcursor_t cursor; + + FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' '); + for (child = fr_pair_dcursor_init(&cursor, &vp->vp_group); + child != NULL; + child = fr_dcursor_next(&cursor)) { + FR_SBUFF_RETURN(fr_pair_print_secure, &our_out, vp, child); + if (fr_dcursor_next_peek(&cursor)) FR_SBUFF_IN_CHAR_RETURN(&our_out, ',', ' '); + } + FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ', '}'); + } + + FR_SBUFF_SET_RETURN(out, &our_out); +} + /** Print one attribute and value to FP * * Complete string with '\\t' and '\\n' is written to buffer before printing to diff --git a/src/lib/util/print.c b/src/lib/util/print.c index 2680d1e3ec5..22571db2b43 100644 --- a/src/lib/util/print.c +++ b/src/lib/util/print.c @@ -680,7 +680,7 @@ static char *fr_vasprintf_internal(TALLOC_CTX *ctx, char const *fmt, va_list ap, * string need to occur in the NULL ctx so we don't fragment * any pool associated with it. */ - if (in->secret && suppress_secrets) { + if (unlikely(in->secret && suppress_secrets)) { subst = talloc_typed_strdup(NULL, "<<< secret >>>"); } else if (in) { @@ -804,7 +804,12 @@ static char *fr_vasprintf_internal(TALLOC_CTX *ctx, char const *fmt, va_list ap, } PAIR_VERIFY(in); - fr_pair_aprint(NULL, &subst, NULL, in); + + if (unlikely(in->data.secret && suppress_secrets)) { + fr_pair_aprint_secure(NULL, &subst, NULL, in); + } else { + fr_pair_aprint(NULL, &subst, NULL, in); + } } goto do_splice;