]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add and use fr_pair_print_secure()
authorAlan T. DeKok <aland@freeradius.org>
Sat, 22 Jul 2023 12:39:47 +0000 (08:39 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 22 Jul 2023 12:39:47 +0000 (08:39 -0400)
to omit secrets when printing pairs

src/lib/util/pair.h
src/lib/util/pair_print.c
src/lib/util/print.c

index 2c4609f8c878116be90303d181fe6b4585b463c2..82cb64c5c233e5743ba2f40e472028ce76536a74 100644 (file)
@@ -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__);
index 48f872f16b1e89b2b126eb3a64e7c41a897f9af6..22bcd8d49880ed9d8f28371c995bedae913889e3 100644 (file)
@@ -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 = "<INVALID-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
index 2680d1e3ec5a3369c9e051528dba6d1c6b0275c0..22571db2b4342dd8b747227819857cc59c686823 100644 (file)
@@ -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;