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;
}
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;
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"));
* 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
/* 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);
/* 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)))
#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);
*/
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)
{
if (*sp == fl->quotechar)
k5_buf_add_len(&buf, sp, 1);
}
- return buf.data;
+ return k5_buf_cstring(&buf);
}
/*
*incr = 0;
k5_buf_truncate(&buf, 0);
} else {
- return buf.data;
+ return k5_buf_cstring(&buf);
}
}
}
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 *
}
k5_buf_add(&buf, "}");
- return buf.data;
+ return k5_buf_cstring(&buf);
}
static krb5_error_code
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
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) {
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);
}
}
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;
/* 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);
}
uint64_t password_days;
const char *p;
struct k5buf buf;
+ char *msg;
*msg_out = NULL;
if (data->length != AD_POLICY_INFO_LENGTH)
(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;
}
s += 2;
}
k5_buf_add(&buf, s); /* Remainder after last token */
- return buf.data;
+ return k5_buf_cstring(&buf);
}
const char * KRB5_CALLCONV
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;
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;
k5_buf_add(&buf, ".");
}
- return buf.data;
+ return k5_buf_cstring(&buf);
}
/*
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
{
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;
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);
}
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;
}
/*
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;
}
creds->client, creds->server);
}
}
- return buf.data;
+ return k5_buf_cstring(&buf);
}
/* Allows trace_format formatters to be represented in terms of other
{
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");
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;
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++) {
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;
}
break;
k5_buf_add_fmt(&buf, "\\%2x", (unsigned char)*in++);
}
- return buf.data;
+ return k5_buf_cstring(&buf);
}
static int
{
struct k5buf buf;
int n = 0;
- char *ret;
k5_buf_init_dynamic(&buf);
k5_buf_add(&buf, "PKCS11:");
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
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 ***/
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;
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 {
}
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
return;
}
buf->len = 0;
- *endptr(buf) = '\0';
}
void
if (len > 0)
memcpy(endptr(buf), data, len);
buf->len += len;
- *endptr(buf) = '\0';
}
void
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);
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)
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;
}
return;
assert(len <= buf->len);
buf->len = len;
- *endptr(buf) = '\0';
}
int
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
} else {
fail_if(buf->space == 0, name);
fail_if(buf->len >= buf->space, name);
- fail_if(((char *)buf->data)[buf->len] != 0, name);
}
}
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);
}
/* 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");
/* 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");
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);
}
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);
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);
}
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);