Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/support/k5buf.c
34889 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* util/support/k5buf.c - string buffer functions */
3
4
/*
5
* Copyright 2008 Massachusetts Institute of Technology.
6
* All Rights Reserved.
7
*
8
* Export of this software from the United States of America may
9
* require a specific license from the United States Government.
10
* It is the responsibility of any person or organization contemplating
11
* export to obtain such a license before exporting.
12
*
13
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14
* distribute this software and its documentation for any purpose and
15
* without fee is hereby granted, provided that the above copyright
16
* notice appear in all copies and that both that copyright notice and
17
* this permission notice appear in supporting documentation, and that
18
* the name of M.I.T. not be used in advertising or publicity pertaining
19
* to distribution of the software without specific, written prior
20
* permission. Furthermore if you modify this software you must label
21
* your software as modified software and not distribute it in such a
22
* fashion that it might be confused with the original M.I.T. software.
23
* M.I.T. makes no representations about the suitability of
24
* this software for any purpose. It is provided "as is" without express
25
* or implied warranty.
26
*/
27
28
/*
29
* Can't include krb5.h here, or k5-int.h which includes it, because krb5.h
30
* needs to be generated with error tables, after util/et, which builds after
31
* this directory.
32
*/
33
#include "k5-platform.h"
34
#include "k5-buf.h"
35
#include <assert.h>
36
37
/*
38
* Structure invariants:
39
*
40
* buftype is K5BUF_FIXED, K5BUF_DYNAMIC, K5BUF_DYNAMIC_ZAP, or K5BUF_ERROR
41
* if buftype is K5BUF_ERROR, the other fields are NULL or 0
42
* if buftype is not K5BUF_ERROR:
43
* space > 0
44
* len < space
45
* data[len] = '\0'
46
*/
47
48
/* Return a character pointer to the current end of buf. */
49
static inline char *
50
endptr(struct k5buf *buf)
51
{
52
return (char *)buf->data + buf->len;
53
}
54
55
static inline void
56
set_error(struct k5buf *buf)
57
{
58
buf->buftype = K5BUF_ERROR;
59
buf->data = NULL;
60
buf->space = buf->len = 0;
61
}
62
63
/*
64
* Make sure there is room for LEN more characters in BUF, in addition to the
65
* null terminator and what's already in there. Return true on success. On
66
* failure, set the error flag and return false.
67
*/
68
static int
69
ensure_space(struct k5buf *buf, size_t len)
70
{
71
size_t new_space;
72
char *new_data;
73
74
if (buf->buftype == K5BUF_ERROR)
75
return 0;
76
if (buf->space - buf->len >= len) /* Enough room already. */
77
return 1;
78
if (buf->buftype == K5BUF_FIXED) /* Can't resize a fixed buffer. */
79
goto error_exit;
80
assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
81
new_space = buf->space * 2;
82
while (new_space - buf->len < len) {
83
if (new_space > SIZE_MAX / 2)
84
goto error_exit;
85
new_space *= 2;
86
}
87
if (buf->buftype == K5BUF_DYNAMIC_ZAP) {
88
/* realloc() could leave behind a partial copy of sensitive data. */
89
new_data = malloc(new_space);
90
if (new_data == NULL)
91
goto error_exit;
92
memcpy(new_data, buf->data, buf->len);
93
zap(buf->data, buf->len);
94
free(buf->data);
95
} else {
96
new_data = realloc(buf->data, new_space);
97
if (new_data == NULL)
98
goto error_exit;
99
}
100
buf->data = new_data;
101
buf->space = new_space;
102
return 1;
103
104
error_exit:
105
if (buf->buftype == K5BUF_DYNAMIC_ZAP)
106
zap(buf->data, buf->len);
107
if (buf->buftype == K5BUF_DYNAMIC_ZAP || buf->buftype == K5BUF_DYNAMIC)
108
free(buf->data);
109
set_error(buf);
110
return 0;
111
}
112
113
void
114
k5_buf_init_fixed(struct k5buf *buf, void *data, size_t space)
115
{
116
assert(space > 0);
117
buf->buftype = K5BUF_FIXED;
118
buf->data = data;
119
buf->space = space;
120
buf->len = 0;
121
}
122
123
void
124
k5_buf_init_dynamic(struct k5buf *buf)
125
{
126
buf->buftype = K5BUF_DYNAMIC;
127
buf->space = 128;
128
buf->data = malloc(buf->space);
129
if (buf->data == NULL) {
130
set_error(buf);
131
return;
132
}
133
buf->len = 0;
134
}
135
136
void
137
k5_buf_init_dynamic_zap(struct k5buf *buf)
138
{
139
k5_buf_init_dynamic(buf);
140
if (buf->buftype == K5BUF_DYNAMIC)
141
buf->buftype = K5BUF_DYNAMIC_ZAP;
142
}
143
144
void
145
k5_buf_add(struct k5buf *buf, const char *data)
146
{
147
k5_buf_add_len(buf, data, strlen(data));
148
}
149
150
void
151
k5_buf_add_len(struct k5buf *buf, const void *data, size_t len)
152
{
153
if (!ensure_space(buf, len))
154
return;
155
if (len > 0)
156
memcpy(endptr(buf), data, len);
157
buf->len += len;
158
}
159
160
void
161
k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
162
{
163
va_list apcopy;
164
int r;
165
size_t remaining;
166
char *tmp;
167
168
if (buf->buftype == K5BUF_ERROR)
169
return;
170
remaining = buf->space - buf->len;
171
172
if (buf->buftype == K5BUF_FIXED) {
173
/* Format the data directly into the fixed buffer. */
174
r = vsnprintf(endptr(buf), remaining, fmt, ap);
175
if (SNPRINTF_OVERFLOW(r, remaining))
176
set_error(buf);
177
else
178
buf->len += (unsigned int) r;
179
return;
180
}
181
182
/* Optimistically format the data directly into the dynamic buffer. */
183
assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
184
va_copy(apcopy, ap);
185
r = vsnprintf(endptr(buf), remaining, fmt, apcopy);
186
va_end(apcopy);
187
if (!SNPRINTF_OVERFLOW(r, remaining)) {
188
buf->len += (unsigned int) r;
189
return;
190
}
191
192
if (r >= 0) {
193
/* snprintf correctly told us how much space is required. */
194
if (!ensure_space(buf, r + 1))
195
return;
196
remaining = buf->space - buf->len;
197
r = vsnprintf(endptr(buf), remaining, fmt, ap);
198
if (SNPRINTF_OVERFLOW(r, remaining)) /* Shouldn't ever happen. */
199
k5_buf_free(buf);
200
else
201
buf->len += (unsigned int) r;
202
return;
203
}
204
205
/* It's a pre-C99 snprintf implementation, or something else went wrong.
206
* Fall back to asprintf. */
207
r = vasprintf(&tmp, fmt, ap);
208
if (r < 0) {
209
k5_buf_free(buf);
210
return;
211
}
212
if (ensure_space(buf, r)) {
213
/* Copy the temporary string into buf. */
214
memcpy(endptr(buf), tmp, r);
215
buf->len += r;
216
}
217
if (buf->buftype == K5BUF_DYNAMIC_ZAP)
218
zap(tmp, strlen(tmp));
219
free(tmp);
220
}
221
222
void
223
k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
224
{
225
va_list ap;
226
227
va_start(ap, fmt);
228
k5_buf_add_vfmt(buf, fmt, ap);
229
va_end(ap);
230
}
231
232
char *
233
k5_buf_cstring(struct k5buf *buf)
234
{
235
if (!ensure_space(buf, 1))
236
return NULL;
237
*endptr(buf) = '\0';
238
return buf->data;
239
}
240
241
void *
242
k5_buf_get_space(struct k5buf *buf, size_t len)
243
{
244
if (!ensure_space(buf, len))
245
return NULL;
246
buf->len += len;
247
return endptr(buf) - len;
248
}
249
250
void
251
k5_buf_truncate(struct k5buf *buf, size_t len)
252
{
253
if (buf->buftype == K5BUF_ERROR)
254
return;
255
assert(len <= buf->len);
256
buf->len = len;
257
}
258
259
int
260
k5_buf_status(struct k5buf *buf)
261
{
262
return (buf->buftype == K5BUF_ERROR) ? ENOMEM : 0;
263
}
264
265
void
266
k5_buf_free(struct k5buf *buf)
267
{
268
if (buf->buftype == K5BUF_ERROR)
269
return;
270
assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
271
if (buf->buftype == K5BUF_DYNAMIC_ZAP)
272
zap(buf->data, buf->len);
273
free(buf->data);
274
set_error(buf);
275
}
276
277