krb5 commit: Make k5buf more flexible for binary data

ghudson at mit.edu ghudson at mit.edu
Fri Mar 24 15:07:07 EDT 2023


https://github.com/krb5/krb5/commit/fc1ad91f68a06dfc9b082897120985d45438fa9f
commit fc1ad91f68a06dfc9b082897120985d45438fa9f
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Mar 13 17:42:50 2023 -0400

    Make k5buf more flexible for binary data
    
    Remove the invariant that buf.data is always zero-terminated, to allow
    marshalling of binary data into precisely allocated fixed regions.
    Add k5_buf_cstring() to zero-terminate the buffer and retrieve the
    data pointer.  Adjust all callers that build C strings appropriately.
    
    Add a k5_buf_add_byte() convenience wrapper alongside the integer
    marshalling wrappers.  Change k5_buf_init_fixed() to accept a void
    pointer so it can more conveniently be used with uint8_t arrays.

 src/clients/ksu/authorization.c                    |  4 ++--
 src/clients/kvno/kvno.c                            |  9 ++++++--
 src/include/k5-buf.h                               | 20 ++++++++++++----
 src/kadmin/dbutil/tdumputil.c                      |  2 +-
 src/kadmin/server/auth_acl.c                       |  2 +-
 src/kdc/kdc_util.c                                 |  4 ++--
 src/lib/gssapi/spnego/negoex_util.c                |  7 +++---
 src/lib/kadm5/logger.c                             |  7 +++---
 src/lib/krb5/krb/chpw.c                            | 11 +++++----
 src/lib/krb5/krb/kerrs.c                           |  2 +-
 src/lib/krb5/krb/preauth_otp.c                     |  7 +++---
 src/lib/krb5/os/dnsglue.c                          |  2 +-
 src/lib/krb5/os/dnssrv.c                           |  2 +-
 src/lib/krb5/os/expand_path.c                      | 13 +++++++----
 src/lib/krb5/os/localauth_rule.c                   | 11 ++++-----
 src/lib/krb5/os/trace.c                            |  2 +-
 src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c       | 10 ++++----
 src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c  |  8 ++-----
 src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c      |  2 +-
 src/plugins/preauth/pkinit/pkinit_crypto_openssl.c |  8 +------
 src/util/support/json.c                            |  6 ++---
 src/util/support/k5buf.c                           | 27 ++++++++++++----------
 src/util/support/libkrb5support-fixed.exports      |  1 +
 src/util/support/t_k5buf.c                         | 17 +++++++-------
 src/util/support/utf8_conv.c                       |  4 ++--
 25 files changed, 101 insertions(+), 87 deletions(-)

diff --git a/src/clients/ksu/authorization.c b/src/clients/ksu/authorization.c
index 6ea10844f..fb9d5d094 100644
--- a/src/clients/ksu/authorization.c
+++ b/src/clients/ksu/authorization.c
@@ -501,11 +501,11 @@ krb5_boolean find_first_cmd_that_exists(fcmd_arr, cmd_out, err_out)
         for(j= 0; j < i; j ++)
             k5_buf_add_fmt(&buf, " %s ", fcmd_arr[j]);
         k5_buf_add(&buf, "\n");
-        if (k5_buf_status(&buf) != 0) {
+        *err_out = k5_buf_cstring(&buf);
+        if (*err_out == NULL) {
             perror(prog_name);
             exit(1);
         }
-        *err_out = buf.data;
     }
 
 
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
index 7f8667ce4..03f72f596 100644
--- a/src/clients/kvno/kvno.c
+++ b/src/clients/kvno/kvno.c
@@ -222,7 +222,7 @@ read_pem_file(char *file_name, krb5_data *der_out)
     FILE *fp = NULL;
     const char *begin_line = "-----BEGIN CERTIFICATE-----";
     const char *end_line = "-----END ", *line;
-    char linebuf[256];
+    char linebuf[256], *b64;
     struct k5buf buf = EMPTY_K5BUF;
     uint8_t *der_cert;
     size_t dlen;
@@ -267,7 +267,12 @@ read_pem_file(char *file_name, krb5_data *der_out)
         k5_buf_add(&buf, line);
     }
 
-    der_cert = k5_base64_decode(buf.data, &dlen);
+    b64 = k5_buf_cstring(&buf);
+    if (b64 == NULL) {
+        ret = ENOMEM;
+        goto cleanup;
+    }
+    der_cert = k5_base64_decode(b64, &dlen);
     if (der_cert == NULL) {
         ret = EINVAL;
         k5_setmsg(context, ret, _("Invalid base64"));
diff --git a/src/include/k5-buf.h b/src/include/k5-buf.h
index f2cdb0cbe..0db90ccff 100644
--- a/src/include/k5-buf.h
+++ b/src/include/k5-buf.h
@@ -35,8 +35,9 @@
  * fixed or dynamic buffer without the need to check for a failure at each step
  * (and without aborting on malloc failure).  If an allocation failure occurs
  * or the fixed buffer runs out of room, the buffer will be set to an error
- * state which can be detected with k5_buf_status.  Data in a buffer is
- * terminated with a zero byte so that it can be used as a C string.
+ * state which can be detected with k5_buf_status.  Data in a buffer is not
+ * automatically terminated with a zero byte; call k5_buf_cstring() to use the
+ * contents as a C string.
  *
  * k5buf structures are usually stack-allocated.  Do not put k5buf structure
  * pointers into public APIs.  It is okay to reference the data and len fields
@@ -58,7 +59,7 @@ struct k5buf {
 
 /* Initialize a k5buf using a fixed-sized, existing buffer.  SPACE must be
  * more than zero, or an assertion failure will result. */
-void k5_buf_init_fixed(struct k5buf *buf, char *data, size_t space);
+void k5_buf_init_fixed(struct k5buf *buf, void *data, size_t space);
 
 /* Initialize a k5buf using an internally allocated dynamic buffer. */
 void k5_buf_init_dynamic(struct k5buf *buf);
@@ -73,7 +74,8 @@ void k5_buf_add(struct k5buf *buf, const char *data);
 /* Add a counted series of bytes to BUF. */
 void k5_buf_add_len(struct k5buf *buf, const void *data, size_t len);
 
-/* Add sprintf-style formatted data to BUF. */
+/* Add sprintf-style formatted data to BUF.  For a fixed-length buffer this
+ * operation will fail if there isn't room for a zero terminator. */
 void k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
 #if !defined(__cplusplus) && (__GNUC__ > 2)
     __attribute__((__format__(__printf__, 2, 3)))
@@ -88,6 +90,10 @@ void k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
 #endif
     ;
 
+/* Without changing the length of buf, ensure that there is a zero byte after
+ * buf.data and return it.  Return NULL on error. */
+char *k5_buf_cstring(struct k5buf *buf);
+
 /* Extend the length of buf by len and return a pointer to the reserved space,
  * to be filled in by the caller.  Return NULL on error. */
 void *k5_buf_get_space(struct k5buf *buf, size_t len);
@@ -108,6 +114,12 @@ int k5_buf_status(struct k5buf *buf);
  */
 void k5_buf_free(struct k5buf *buf);
 
+static inline void
+k5_buf_add_byte(struct k5buf *buf, uint8_t val)
+{
+    k5_buf_add_len(buf, &val, 1);
+}
+
 static inline void
 k5_buf_add_uint16_be(struct k5buf *buf, uint16_t val)
 {
diff --git a/src/kadmin/dbutil/tdumputil.c b/src/kadmin/dbutil/tdumputil.c
index 2c14d5670..076cfa971 100644
--- a/src/kadmin/dbutil/tdumputil.c
+++ b/src/kadmin/dbutil/tdumputil.c
@@ -92,7 +92,7 @@ qquote(struct flavor *fl, const char *s)
         if (*sp == fl->quotechar)
             k5_buf_add_len(&buf, sp, 1);
     }
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 /*
diff --git a/src/kadmin/server/auth_acl.c b/src/kadmin/server/auth_acl.c
index efe9c6961..ce9ace36a 100644
--- a/src/kadmin/server/auth_acl.c
+++ b/src/kadmin/server/auth_acl.c
@@ -146,7 +146,7 @@ get_line(FILE *fp, const char *fname, int *lineno, int *incr)
                 *incr = 0;
                 k5_buf_truncate(&buf, 0);
             } else {
-                return buf.data;
+                return k5_buf_cstring(&buf);
             }
         }
     }
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 932eeb880..df0d35f60 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1135,7 +1135,7 @@ ktypes2str(krb5_enctype *ktype, int nktypes)
         k5_buf_add_fmt(&buf, "%s%s(%ld)", i ? ", " : "", name, (long)ktype[i]);
     }
     k5_buf_add(&buf, "}");
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 char *
@@ -1164,7 +1164,7 @@ rep_etypes2str(krb5_kdc_rep *rep)
     }
 
     k5_buf_add(&buf, "}");
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 static krb5_error_code
diff --git a/src/lib/gssapi/spnego/negoex_util.c b/src/lib/gssapi/spnego/negoex_util.c
index 99580fd79..edc5462e8 100644
--- a/src/lib/gssapi/spnego/negoex_util.c
+++ b/src/lib/gssapi/spnego/negoex_util.c
@@ -157,7 +157,7 @@ guid_to_string(const uint8_t guid[GUID_LENGTH])
 
     k5_buf_init_dynamic(&buf);
     add_guid(&buf, guid);
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 /* Check that the described vector lies within the message, and return a
@@ -188,7 +188,7 @@ trace_received_message(spnego_gss_ctx_id_t ctx,
             if (i + 1 < msg->u.n.nschemes)
                 k5_buf_add(&buf, " ");
         }
-        info = buf.data;
+        info = k5_buf_cstring(&buf);
     } else if (msg->type == INITIATOR_META_DATA ||
                msg->type == ACCEPTOR_META_DATA ||
                msg->type == CHALLENGE || msg->type == AP_REQUEST) {
@@ -613,7 +613,8 @@ negoex_add_nego_message(spnego_gss_ctx_id_t ctx, enum message_type type,
 
     if (buf.len > 0) {
         k5_buf_truncate(&buf, buf.len - 1);
-        TRACE_NEGOEX_OUTGOING(ctx->kctx, seqnum, typestr(type), buf.data);
+        TRACE_NEGOEX_OUTGOING(ctx->kctx, seqnum, typestr(type),
+                              k5_buf_cstring(&buf));
         k5_buf_free(&buf);
     }
 }
diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
index c6885edf2..e14da5379 100644
--- a/src/lib/kadm5/logger.c
+++ b/src/lib/kadm5/logger.c
@@ -182,7 +182,7 @@ static void
 klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap)
 {
     struct k5buf buf;
-    const char *emsg;
+    const char *emsg, *msg;
 
     if (format == NULL)
         return;
@@ -200,8 +200,9 @@ klog_com_err_proc(const char *whoami, long int code, const char *format, va_list
     /* Add the formatted message. */
     k5_buf_add_vfmt(&buf, format, ap);
 
-    if (k5_buf_status(&buf) == 0)
-        krb5_klog_syslog(code ? LOG_ERR : LOG_INFO, "%s", (char *)buf.data);
+    msg = k5_buf_cstring(&buf);
+    if (msg != NULL)
+        krb5_klog_syslog(code ? LOG_ERR : LOG_INFO, "%s", msg);
 
     k5_buf_free(&buf);
 }
diff --git a/src/lib/krb5/krb/chpw.c b/src/lib/krb5/krb/chpw.c
index 803c80feb..aca394592 100644
--- a/src/lib/krb5/krb/chpw.c
+++ b/src/lib/krb5/krb/chpw.c
@@ -393,6 +393,7 @@ decode_ad_policy_info(const krb5_data *data, char **msg_out)
     uint64_t password_days;
     const char *p;
     struct k5buf buf;
+    char *msg;
 
     *msg_out = NULL;
     if (data->length != AD_POLICY_INFO_LENGTH)
@@ -462,13 +463,13 @@ decode_ad_policy_info(const krb5_data *data, char **msg_out)
                        (int)password_days);
     }
 
-    if (k5_buf_status(&buf) != 0)
+    msg = k5_buf_cstring(&buf);
+    if (msg == NULL)
         return ENOMEM;
-
-    if (buf.len > 0)
-        *msg_out = buf.data;
+    if (*msg != '\0')
+        *msg_out = msg;
     else
-        k5_buf_free(&buf);
+        free(msg);
     return 0;
 }
 
diff --git a/src/lib/krb5/krb/kerrs.c b/src/lib/krb5/krb/kerrs.c
index 0146d9a41..0e8167929 100644
--- a/src/lib/krb5/krb/kerrs.c
+++ b/src/lib/krb5/krb/kerrs.c
@@ -165,7 +165,7 @@ err_fmt_fmt(const char *err_fmt, long code, const char *msg)
         s += 2;
     }
     k5_buf_add(&buf, s);        /* Remainder after last token */
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 const char * KRB5_CALLCONV
diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c
index 5305d9a29..38eaf426c 100644
--- a/src/lib/krb5/krb/preauth_otp.c
+++ b/src/lib/krb5/krb/preauth_otp.c
@@ -504,7 +504,7 @@ prompt_for_tokeninfo(krb5_context context, krb5_prompter_fct prompter,
                      void *prompter_data, krb5_otp_tokeninfo **tis,
                      krb5_otp_tokeninfo **out_ti)
 {
-    char response[1024];
+    char response[1024], *prompt;
     krb5_otp_tokeninfo *ti = NULL;
     krb5_error_code retval = 0;
     struct k5buf buf;
@@ -517,11 +517,12 @@ prompt_for_tokeninfo(krb5_context context, krb5_prompter_fct prompter,
         k5_buf_add_len(&buf, tis[i]->vendor.data, tis[i]->vendor.length);
         k5_buf_add(&buf, "\n");
     }
-    if (k5_buf_status(&buf) != 0)
+    prompt = k5_buf_cstring(&buf);
+    if (prompt == NULL)
         return ENOMEM;
 
     do {
-        retval = doprompt(context, prompter, prompter_data, buf.data,
+        retval = doprompt(context, prompter, prompter_data, prompt,
                           _("Enter #"), response, sizeof(response));
         if (retval != 0)
             goto cleanup;
diff --git a/src/lib/krb5/os/dnsglue.c b/src/lib/krb5/os/dnsglue.c
index 0cd213fdd..668a7a69a 100644
--- a/src/lib/krb5/os/dnsglue.c
+++ b/src/lib/krb5/os/dnsglue.c
@@ -392,7 +392,7 @@ txt_lookup_name(const char *prefix, const char *name)
             k5_buf_add(&buf, ".");
     }
 
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 /*
diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c
index 5992a9bdf..62d6d1371 100644
--- a/src/lib/krb5/os/dnssrv.c
+++ b/src/lib/krb5/os/dnssrv.c
@@ -72,7 +72,7 @@ make_lookup_name(const krb5_data *realm, const char *service,
     if (buf.len > 0 && ((char *)buf.data)[buf.len - 1] != '.')
         k5_buf_add(&buf, ".");
 
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 /* Insert new into the list *head, ordering by priority.  Weight is not
diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c
index 4ce466c19..5cbccf08c 100644
--- a/src/lib/krb5/os/expand_path.c
+++ b/src/lib/krb5/os/expand_path.c
@@ -454,7 +454,7 @@ k5_expand_path_tokens_extra(krb5_context context, const char *path_in,
 {
     krb5_error_code ret;
     struct k5buf buf;
-    char *tok_begin, *tok_end, *tok_val, **extra_tokens = NULL;
+    char *tok_begin, *tok_end, *tok_val, **extra_tokens = NULL, *path;
     const char *path_left;
     size_t nargs = 0, i;
     va_list ap;
@@ -517,22 +517,25 @@ k5_expand_path_tokens_extra(krb5_context context, const char *path_in,
         path_left = tok_end + 1;
     }
 
-    ret = k5_buf_status(&buf);
-    if (ret)
+    path = k5_buf_cstring(&buf);
+    if (path == NULL) {
+        ret = ENOMEM;
         goto cleanup;
+    }
 
 #ifdef _WIN32
     /* Also deal with slashes. */
     {
         char *p;
-        for (p = buf.data; *p != '\0'; p++) {
+        for (p = path; *p != '\0'; p++) {
             if (*p == '/')
                 *p = '\\';
         }
     }
 #endif
-    *path_out = buf.data;
+    *path_out = path;
     memset(&buf, 0, sizeof(buf));
+    ret = 0;
 
 cleanup:
     k5_buf_free(&buf);
diff --git a/src/lib/krb5/os/localauth_rule.c b/src/lib/krb5/os/localauth_rule.c
index 8be29c415..056857633 100644
--- a/src/lib/krb5/os/localauth_rule.c
+++ b/src/lib/krb5/os/localauth_rule.c
@@ -130,10 +130,8 @@ do_replacement(const char *regstr, const char *repl, krb5_boolean doall,
     }
     regfree(&re);
     k5_buf_add(&buf, instr);
-    if (k5_buf_status(&buf) != 0)
-        return ENOMEM;
-    *outstr = buf.data;
-    return 0;
+    *outstr = k5_buf_cstring(&buf);
+    return (*outstr == NULL) ? ENOMEM : 0;
 }
 
 /*
@@ -265,11 +263,10 @@ aname_get_selstring(krb5_context context, krb5_const_principal aname,
         return KRB5_CONFIG_BADFORMAT;
     }
 
-    if (k5_buf_status(&selstring) != 0)
+    *selstring_out = k5_buf_cstring(&selstring);
+    if (*selstring_out == NULL)
         return ENOMEM;
-
     *contextp = current + 1;
-    *selstring_out = selstring.data;
     return 0;
 }
 
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 3369fc4ba..5f64ca8d6 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -366,7 +366,7 @@ trace_format(krb5_context context, const char *fmt, va_list ap)
                    creds->client, creds->server);
         }
     }
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 /* Allows trace_format formatters to be represented in terms of other
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
index 6bc20593f..b3bf1ba6d 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
@@ -1370,7 +1370,7 @@ get_ldap_auth_ind(krb5_context context, LDAP *ld, LDAPMessage *ldap_ent,
 {
     krb5_error_code ret;
     int i;
-    char **auth_inds = NULL;
+    char **auth_inds = NULL, *indstr;
     struct k5buf buf = EMPTY_K5BUF;
 
     auth_inds = ldap_get_values(ld, ldap_ent, "krbPrincipalAuthInd");
@@ -1386,12 +1386,14 @@ get_ldap_auth_ind(krb5_context context, LDAP *ld, LDAPMessage *ldap_ent,
             k5_buf_add(&buf, " ");
     }
 
-    ret = k5_buf_status(&buf);
-    if (ret)
+    indstr = k5_buf_cstring(&buf);
+    if (indstr == NULL) {
+        ret = ENOMEM;
         goto cleanup;
+    }
 
     ret = krb5_dbe_set_string(context, entry, KRB5_KDB_SK_REQUIRE_AUTH,
-                              buf.data);
+                              indstr);
     if (!ret)
         *mask |= KDB_AUTH_IND_ATTR;
 
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
index b5a4e5f76..6328fbe2b 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
@@ -614,8 +614,6 @@ krb5_ldap_parse_principal_name(char *i_princ_name, char **o_princ_name)
     at_rlm_name = strrchr(i_princ_name, '@');
     if (!at_rlm_name) {
         *o_princ_name = strdup(i_princ_name);
-        if (!*o_princ_name)
-            return ENOMEM;
     } else {
         k5_buf_init_dynamic(&buf);
         for (p = i_princ_name; p < at_rlm_name; p++) {
@@ -624,9 +622,7 @@ krb5_ldap_parse_principal_name(char *i_princ_name, char **o_princ_name)
             k5_buf_add_len(&buf, p, 1);
         }
         k5_buf_add(&buf, at_rlm_name);
-        if (k5_buf_status(&buf) != 0)
-            return ENOMEM;
-        *o_princ_name = buf.data;
+        *o_princ_name = k5_buf_cstring(&buf);
     }
-    return 0;
+    return (*o_princ_name == NULL) ? ENOMEM : 0;
 }
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
index 3daf52493..753929b06 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
@@ -87,7 +87,7 @@ ldap_filter_correct (char *in)
             break;
         k5_buf_add_fmt(&buf, "\\%2x", (unsigned char)*in++);
     }
-    return buf.data;
+    return k5_buf_cstring(&buf);
 }
 
 static int
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 6ae6425d8..f41328763 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -4406,7 +4406,6 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
 {
     struct k5buf buf;
     int n = 0;
-    char *ret;
 
     k5_buf_init_dynamic(&buf);
     k5_buf_add(&buf, "PKCS11:");
@@ -4431,12 +4430,7 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
         k5_buf_add_fmt(&buf, "%sslotid=%ld", n++ ? ":" : "",
                        (long)idopts->slotid);
     }
-    if (k5_buf_status(&buf) == 0)
-        ret = strdup(buf.data);
-    else
-        ret = NULL;
-    k5_buf_free(&buf);
-    return ret;
+    return k5_buf_cstring(&buf);
 }
 
 static krb5_error_code
diff --git a/src/util/support/json.c b/src/util/support/json.c
index ae2feae97..ac2e5be0b 100644
--- a/src/util/support/json.c
+++ b/src/util/support/json.c
@@ -696,10 +696,8 @@ k5_json_encode(k5_json_value val, char **json_out)
         k5_buf_free(&buf);
         return ret;
     }
-    if (k5_buf_status(&buf) != 0)
-        return ENOMEM;
-    *json_out = buf.data;
-    return 0;
+    *json_out = k5_buf_cstring(&buf);
+    return (*json_out == NULL) ? ENOMEM : 0;
 }
 
 /*** JSON decoding ***/
diff --git a/src/util/support/k5buf.c b/src/util/support/k5buf.c
index b2b5e5b67..a17d2310f 100644
--- a/src/util/support/k5buf.c
+++ b/src/util/support/k5buf.c
@@ -73,13 +73,13 @@ ensure_space(struct k5buf *buf, size_t len)
 
     if (buf->buftype == K5BUF_ERROR)
         return 0;
-    if (buf->space - 1 - buf->len >= len) /* Enough room already. */
+    if (buf->space - buf->len >= len) /* Enough room already. */
         return 1;
     if (buf->buftype == K5BUF_FIXED) /* Can't resize a fixed buffer. */
         goto error_exit;
     assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
     new_space = buf->space * 2;
-    while (new_space - buf->len - 1 < len) {
+    while (new_space - buf->len < len) {
         if (new_space > SIZE_MAX / 2)
             goto error_exit;
         new_space *= 2;
@@ -90,7 +90,6 @@ ensure_space(struct k5buf *buf, size_t len)
         if (new_data == NULL)
             goto error_exit;
         memcpy(new_data, buf->data, buf->len);
-        new_data[buf->len] = '\0';
         zap(buf->data, buf->len);
         free(buf->data);
     } else {
@@ -112,14 +111,13 @@ error_exit:
 }
 
 void
-k5_buf_init_fixed(struct k5buf *buf, char *data, size_t space)
+k5_buf_init_fixed(struct k5buf *buf, void *data, size_t space)
 {
     assert(space > 0);
     buf->buftype = K5BUF_FIXED;
     buf->data = data;
     buf->space = space;
     buf->len = 0;
-    *endptr(buf) = '\0';
 }
 
 void
@@ -133,7 +131,6 @@ k5_buf_init_dynamic(struct k5buf *buf)
         return;
     }
     buf->len = 0;
-    *endptr(buf) = '\0';
 }
 
 void
@@ -158,7 +155,6 @@ k5_buf_add_len(struct k5buf *buf, const void *data, size_t len)
     if (len > 0)
         memcpy(endptr(buf), data, len);
     buf->len += len;
-    *endptr(buf) = '\0';
 }
 
 void
@@ -195,7 +191,7 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
 
     if (r >= 0) {
         /* snprintf correctly told us how much space is required. */
-        if (!ensure_space(buf, r))
+        if (!ensure_space(buf, r + 1))
             return;
         remaining = buf->space - buf->len;
         r = vsnprintf(endptr(buf), remaining, fmt, ap);
@@ -214,8 +210,8 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
         return;
     }
     if (ensure_space(buf, r)) {
-        /* Copy the temporary string into buf, including terminator. */
-        memcpy(endptr(buf), tmp, r + 1);
+        /* Copy the temporary string into buf. */
+        memcpy(endptr(buf), tmp, r);
         buf->len += r;
     }
     if (buf->buftype == K5BUF_DYNAMIC_ZAP)
@@ -233,13 +229,21 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
     va_end(ap);
 }
 
+char *
+k5_buf_cstring(struct k5buf *buf)
+{
+    if (!ensure_space(buf, 1))
+        return NULL;
+    *endptr(buf) = '\0';
+    return buf->data;
+}
+
 void *
 k5_buf_get_space(struct k5buf *buf, size_t len)
 {
     if (!ensure_space(buf, len))
         return NULL;
     buf->len += len;
-    *endptr(buf) = '\0';
     return endptr(buf) - len;
 }
 
@@ -250,7 +254,6 @@ k5_buf_truncate(struct k5buf *buf, size_t len)
         return;
     assert(len <= buf->len);
     buf->len = len;
-    *endptr(buf) = '\0';
 }
 
 int
diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
index 0bafe1c84..015802496 100644
--- a/src/util/support/libkrb5support-fixed.exports
+++ b/src/util/support/libkrb5support-fixed.exports
@@ -8,6 +8,7 @@ k5_buf_add
 k5_buf_add_len
 k5_buf_add_fmt
 k5_buf_add_vfmt
+k5_buf_cstring
 k5_buf_get_space
 k5_buf_truncate
 k5_buf_status
diff --git a/src/util/support/t_k5buf.c b/src/util/support/t_k5buf.c
index ba86851dc..734b2720c 100644
--- a/src/util/support/t_k5buf.c
+++ b/src/util/support/t_k5buf.c
@@ -50,7 +50,6 @@ check_buf(struct k5buf *buf, const char *name)
     } else {
         fail_if(buf->space == 0, name);
         fail_if(buf->len >= buf->space, name);
-        fail_if(((char *)buf->data)[buf->len] != 0, name);
     }
 }
 
@@ -65,14 +64,14 @@ test_basic()
     k5_buf_add_len(&buf, "world", 5);
     check_buf(&buf, "basic fixed");
     fail_if(buf.data == NULL || buf.len != 11, "basic fixed");
-    fail_if(strcmp(buf.data, "Hello world") != 0, "basic fixed");
+    fail_if(memcmp(buf.data, "Hello world", 11) != 0, "basic fixed");
 
     k5_buf_init_dynamic(&buf);
     k5_buf_add_len(&buf, "Hello", 5);
     k5_buf_add(&buf, " world");
     check_buf(&buf, "basic dynamic");
     fail_if(buf.data == NULL || buf.len != 11, "basic dynamic");
-    fail_if(strcmp(buf.data, "Hello world") != 0, "basic dynamic");
+    fail_if(memcmp(buf.data, "Hello world", 11) != 0, "basic dynamic");
     k5_buf_free(&buf);
 }
 
@@ -141,7 +140,7 @@ test_overflow()
     /* Cause a fixed-sized buffer overflow. */
     k5_buf_init_fixed(&buf, storage, sizeof(storage));
     k5_buf_add(&buf, "12345");
-    k5_buf_add(&buf, "12345");
+    k5_buf_add(&buf, "123456");
     check_buf(&buf, "overflow 1");
     fail_if(buf.buftype != K5BUF_ERROR, "overflow 1");
 
@@ -161,7 +160,7 @@ test_error()
 
     /* Cause an overflow and then perform actions afterwards. */
     k5_buf_init_fixed(&buf, storage, sizeof(storage));
-    k5_buf_add(&buf, "1");
+    k5_buf_add(&buf, "12");
     fail_if(buf.buftype != K5BUF_ERROR, "error");
     check_buf(&buf, "error");
     k5_buf_add(&buf, "test");
@@ -184,7 +183,7 @@ test_truncate()
     k5_buf_truncate(&buf, 7);
     check_buf(&buf, "truncate");
     fail_if(buf.data == NULL || buf.len != 7, "truncate");
-    fail_if(strcmp(buf.data, "abcdefg") != 0, "truncate");
+    fail_if(memcmp(buf.data, "abcdefg", 7) != 0, "truncate");
     k5_buf_free(&buf);
 }
 
@@ -222,7 +221,7 @@ test_fmt()
     k5_buf_add_fmt(&buf, " %d ", 3);
     check_buf(&buf, "fmt 1");
     fail_if(buf.data == NULL || buf.len != 6, "fmt 1");
-    fail_if(strcmp(buf.data, "foo 3 ") != 0, "fmt 1");
+    fail_if(memcmp(buf.data, "foo 3 ", 6) != 0, "fmt 1");
 
     /* Overflow the same buffer with formatted text. */
     k5_buf_add_fmt(&buf, "%d%d%d%d", 1, 2, 3, 4);
@@ -235,14 +234,14 @@ test_fmt()
     k5_buf_add_fmt(&buf, " %d ", 3);
     check_buf(&buf, "fmt 3");
     fail_if(buf.data == NULL || buf.len != 6, "fmt 3");
-    fail_if(strcmp(buf.data, "foo 3 ") != 0, "fmt 3");
+    fail_if(memcmp(buf.data, "foo 3 ", 6) != 0, "fmt 3");
 
     /* Format more text into the same buffer, causing a big resize. */
     k5_buf_add_fmt(&buf, "%s", data);
     check_buf(&buf, "fmt 4");
     fail_if(buf.space != 2048, "fmt 4");
     fail_if(buf.data == NULL || buf.len != 1029, "fmt 4");
-    fail_if(strcmp((char *)buf.data + 6, data) != 0, "fmt 4");
+    fail_if(memcmp((char *)buf.data + 6, data, 1023) != 0, "fmt 4");
     k5_buf_free(&buf);
 }
 
diff --git a/src/util/support/utf8_conv.c b/src/util/support/utf8_conv.c
index 5ddaa2d93..926a3c8a5 100644
--- a/src/util/support/utf8_conv.c
+++ b/src/util/support/utf8_conv.c
@@ -191,8 +191,8 @@ k5_utf16le_to_utf8(const uint8_t *utf16bytes, size_t nbytes, char **utf8_out)
     if (in.status)
         goto invalid;
 
-    *utf8_out = buf.data;
-    return 0;
+    *utf8_out = k5_buf_cstring(&buf);
+    return (*utf8_out == NULL) ? ENOMEM : 0;
 
 invalid:
     k5_buf_free(&buf);


More information about the cvs-krb5 mailing list