1 /* adbuf.c - dynamic buffers support
2 *
3 * Copyright(C) 2001-2003 Salvatore Sanfilippo <antirez@invece.org>
4 * All rights reserved.
5 *
6 * -----------------------------------------------------------------------------
7 * Design principles:
8 *
9 * - This library is little and probably not so flexible nor
10 * full-featured. The goal is to have something of useful
11 * enough to build stuff like mysql queries without to care
12 * about allocation, but with very simple code so that security
13 * auditing is quite simple.
14 * - security is more important than speed in this context, so there
15 * is some redundant and useless check to prevent that some unsane use
16 * become a security problem.
17 * - while the library is binary-safe the buffers are implicitly
18 * nul termined. Even an empty buffer just initialized points
19 * to an empty nul termined string. This prevents problems passing
20 * strings that the user never nul-termined to functions that
21 * expects nul-termined strings.
22 * - memory is more important than speed in this context, so we do often
23 * realloc to change the buffer size even if not required.
24 * This should protect about strange usage patterns that may result
25 * in a lot of memory allocated.
26 *
27 * -----------------------------------------------------------------------------
28 * Security auditing history:
29 * format is SECAUDIT(date)(time spent in seconds)(audited part)
30 *
31 * SECAUDIT(Dec 18 2001)(3600)(all)
32 * SECAUDIT(Aug 19 2003)(600)(adbuf_printf)
33 *
34 * After the last security auditing the code changed, so a new
35 * auditing is needed as fast as possible.
36 * Remember to audit adbuf.h too.
37 *
38 * -----------------------------------------------------------------------------
39 * CHANGES
40 *
41 * 18 Aug 2003 - Changes section just created.
42 * 19 Aug 2003 - Added adbuf_printf().
43 *
44 * -----------------------------------------------------------------------------
45 * HISTORY OF SECURITY VULNERABILITIES
46 *
47 * - Nothing discovered for now.
48 *
49 * -----------------------------------------------------------------------------
50 * TODO
51 *
52 * - adbuf_slice(), with Python-like semantics
53 * - adbuf_split(), similar to the TCL split command
54 * - minimal documentation
55 */
56
57 /* $Id: adbuf.c,v 1.1.1.1 2003/08/31 17:24:00 antirez Exp $ */
58
59 #include <stdio.h>
60 #include <sys/types.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <stdarg.h>
64
65 #include "adbuf.h"
66
67 /* initialize a new buffer. The new empty buffer will
68 * appear as an empty nul terminated string to functions
69 * that expects a string */
adbuf_init(struct adbuf * b)70 int adbuf_init(struct adbuf *b)
71 {
72 b->buf = malloc(1);
73 /* note that if the allocation fails b->buf is set to NULL
74 * so it's safe to call adbuf_free() after a failed initialization */
75 if (b->buf == NULL)
76 return 1;
77 b->buf[0] = '\0';
78 b->size = 1;
79 b->left = 1;
80 return 0;
81 }
82
83 /* free a buffer */
adbuf_free(struct adbuf * b)84 void adbuf_free(struct adbuf *b)
85 {
86 if (b->buf) { /* not really needed with sane libC */
87 free(b->buf);
88 b->buf = NULL;
89 }
90 }
91
92 /* reset the buffer */
adbuf_reset(struct adbuf * b)93 int adbuf_reset(struct adbuf *b)
94 {
95 adbuf_free(b);
96 return adbuf_init(b);
97 }
98
99 /* add data to the buffer 'b'. return 0 on success, 1 on out of memory.
100 * len = 0 and data = NULL is valid */
adbuf_add(struct adbuf * b,void * data,size_t len)101 int adbuf_add(struct adbuf *b, void *data, size_t len)
102 {
103 if (adbuf_ptr(b) == NULL)
104 return 1; /* bad buffer in input */
105 if (len == 0)
106 return 0; /* nothing to add */
107 if ((len+1) > b->left) { /* need one more byte to add a nul term */
108 size_t newsz = b->size + len + ADBUF_INCR;
109 void *t = realloc(b->buf, newsz);
110
111 if (t == NULL)
112 return 1; /* out of memory */
113 b->buf = t;
114 b->left += len + ADBUF_INCR;
115 b->size = newsz;
116 }
117 memcpy(b->buf + adbuf_used(b), data, len);
118 b->buf[adbuf_used(b)+len] = '\0'; /* always nul term */
119 b->left -= len;
120 return 0;
121 }
122
123 /* adbuf_addchar() is like adbuf_add() when {len} = 1, but sligthly
124 * optmized to add just one byte */
adbuf_addchar(struct adbuf * b,int c)125 int adbuf_addchar(struct adbuf *b, int c)
126 {
127 if (adbuf_ptr(b) == NULL)
128 return 1; /* bad buffer in input */
129 if (b->left >= 2) {
130 unsigned char *p = b->buf + adbuf_used(b);
131
132 *p = c;
133 *(p+1) = '\0';
134 b->left -= 1;
135 return 0;
136 } else {
137 unsigned char t[1];
138
139 t[0] = c;
140 return adbuf_add(b, &t, 1);
141 }
142 return 0; /* unreached */
143 }
144
145 /* add the given nul terminated string */
adbuf_strcat(struct adbuf * b,char * string)146 int adbuf_strcat(struct adbuf *b, char *string)
147 {
148 return adbuf_add(b, string, strlen(string));
149 }
150
151 /* concatenate the buffer b to the buffer a */
adbuf_cat(struct adbuf * a,struct adbuf * b)152 int adbuf_cat(struct adbuf *a, struct adbuf *b)
153 {
154 return adbuf_add(a, b->buf, adbuf_used(b));
155 }
156
157 /* cut the buffer to 'count' bytes on the right. If the used buffer is
158 * already smaller than 'count' no operation is performed.
159 * The function preserves the nul term.
160 * On success zero is returned. The function returns 1 on out of memory */
adbuf_cut(struct adbuf * b,size_t count)161 int adbuf_cut(struct adbuf *b, size_t count)
162 {
163 char *t;
164
165 if (adbuf_ptr(b) == NULL)
166 return 1; /* bad buffer in input */
167 if (count >= adbuf_used(b))
168 return 0;
169 count++; /* preserve space for the nul term */
170 t = realloc(b->buf, count);
171 if (t == NULL)
172 return 1; /* out of memory */
173 t[count-1] = '\0';
174 b->buf = t;
175 b->size = count;
176 b->left = 1; /* the nul term is conceptually free space */
177 return 0;
178 }
179
180 /* discard count characters on the left */
adbuf_ltrim(struct adbuf * b,size_t count)181 int adbuf_ltrim(struct adbuf *b, size_t count)
182 {
183 char *t;
184 size_t newlen;
185
186 if (adbuf_ptr(b) == NULL)
187 return 1; /* bad buffer in input */
188 if (count == 0) /* nothing to trim */
189 return 0;
190 /* to discard all the buffer on the left is just
191 * the same as to reset the buffer */
192 if (count >= adbuf_used(b))
193 return adbuf_reset(b);
194 newlen = adbuf_used(b)-count;
195 t = malloc(newlen+1); /* add one byte for the nul term */
196 if (t == NULL)
197 return 1; /* out of memory */
198 memcpy(t, adbuf_ptr(b)+count, newlen);
199 t[newlen] = '\0';
200 free(b->buf);
201 b->buf = t;
202 b->size = newlen+1;
203 b->left = 1;
204 return 0;
205 }
206
207 /* discard count caracters on the right */
adbuf_rtrim(struct adbuf * b,size_t count)208 int adbuf_rtrim(struct adbuf *b, size_t count)
209 {
210 return adbuf_cut(b, adbuf_used(b)-count);
211 }
212
213 #define ADBUF_ITOABUFSZ 32 /* ok for 64bit integers and more */
214
215 /* add the string rappresentation of the long integer l */
adbuf_add_long(struct adbuf * b,long l)216 int adbuf_add_long(struct adbuf *b, long l)
217 {
218 int n = 0;
219 char s[ADBUF_ITOABUFSZ];
220 char *p = s+ADBUF_ITOABUFSZ-1;
221
222 *p-- = '\0';
223 if (l < 0) {
224 n = 1;
225 l = -l;
226 }
227 while(p > s) {
228 *p-- = '0' + (l % 10);
229 l /= 10;
230 if (l == 0)
231 break;
232 }
233 if (n)
234 *p-- = '-';
235 p++;
236 return adbuf_strcat(b, p);
237 }
238
239 /* the same as adbuf_add_long() but with unsigned integers */
adbuf_add_ulong(struct adbuf * b,unsigned long l)240 int adbuf_add_ulong(struct adbuf *b, unsigned long l)
241 {
242 char s[ADBUF_ITOABUFSZ];
243 char *p = s+ADBUF_ITOABUFSZ-1;
244 *p-- = '\0';
245 while(p >= s) {
246 *p-- = '0' + (l % 10);
247 l /= 10;
248 if (l == 0)
249 break;
250 }
251 p++;
252 return adbuf_strcat(b, p);
253 }
254
255 /* clone the buffer src in the buffer dst.
256 * The buffers will be indipendent */
adbuf_clone(struct adbuf * src,struct adbuf * dst)257 int adbuf_clone(struct adbuf *src, struct adbuf *dst)
258 {
259 if (adbuf_ptr(src) == NULL)
260 return 1; /* bad buffer in input */
261 if (adbuf_init(dst))
262 return 1; /* out of memory */
263 return adbuf_add(dst, adbuf_ptr(src), adbuf_used(src));
264 }
265
266 /* Concat to the buffer using printf-like format.
267 * Note that while this function try to detect
268 * non-C99 vsnprintf() behaviour, it can be
269 * unsafe with some vsnprintf() implementation.
270 *
271 * On Linux with glibc >= 2.1, and recent *BSDs, and
272 * in any other system with a C99-wise vsprintf(), it is sane.
273 * On Linux with glibc < 2.1 it should be still secure,
274 * but the behaviour is different (unable to handle strings
275 * with more than ADBUF_PRINTF_BUFSZ chars).
276 * On other non-C99 systems be prepared to random results. */
277 #define ADBUF_PRINTF_BUFSZ 1024
adbuf_printf(struct adbuf * dst,const char * fmt,...)278 int adbuf_printf(struct adbuf *dst, const char *fmt, ...)
279 {
280 char buf[ADBUF_PRINTF_BUFSZ];
281 int retval;
282 va_list ap;
283
284 va_start(ap, fmt);
285 retval = vsnprintf(buf, ADBUF_PRINTF_BUFSZ, fmt, ap);
286 buf[ADBUF_PRINTF_BUFSZ-1] = '\0';
287 va_end(ap);
288
289 if (retval <= -1) { /* pre-C99 vsnprintf() behaviour */
290 /* We just append the output without to care
291 * about a too slow buffer. This isn't a security
292 * issue, but the semantics of adbuf_printf() changes
293 * on this systems. */
294 return adbuf_add(dst, buf, strlen(buf));
295 }
296 if (retval >= ADBUF_PRINTF_BUFSZ) { /* PRINTF_BUFSZ wasn't enough */
297 /* Use dynamic allocation */
298 char *dynbuf;
299 int newretval;
300
301 if ((dynbuf = malloc(retval+1)) == NULL)
302 return 1; /* Out of memory */
303 va_start(ap, fmt);
304 newretval = vsnprintf(dynbuf, retval+1, fmt, ap);
305 dynbuf[retval] = '\0';
306 va_end(ap);
307
308 /* If we can trust the return value, we can avoid
309 * strlen() */
310 if (newretval == retval) {
311 int rv;
312 rv = adbuf_add(dst, dynbuf, retval);
313 free(dynbuf);
314 return rv;
315 } else { /* On strange results we are more prudent */
316 int rv;
317 rv = adbuf_add(dst, dynbuf, strlen(dynbuf));
318 free(dynbuf);
319 return rv;
320 }
321 } else { /* The simple case */
322 return adbuf_add(dst, buf, retval);
323 }
324 }
325
326 #ifdef TEST_MAIN
327
328 #include <stdio.h>
329
main(void)330 int main(void)
331 {
332 struct adbuf b, bb;
333 int add = 0, i;
334
335 adbuf_init(&b);
336 for(i = 0; i < 6; i++)
337 adbuf_strcat(&b, ".,;-+*#*+-;,.");
338 while(adbuf_used(&b) > 0) {
339 for (i = 0; i < add; i++) printf(" ");
340 printf("%s\n", adbuf_ptr(&b));
341 adbuf_rtrim(&b, 1);
342 adbuf_ltrim(&b, 1);
343 add++;
344 }
345 adbuf_free(&b);
346 adbuf_init(&b);
347 for (i = 0; i < 6000; i++) {
348 char c;
349 for (c = 'A'; c <= 'Z'; c++)
350 adbuf_addchar(&b, c);
351 }
352 adbuf_rtrim(&b, adbuf_used(&b)-500);
353 printf("%s\n", adbuf_ptr(&b));
354 adbuf_free(&b);
355 adbuf_init(&b);
356 adbuf_strcat(&b, "adbuf_printf with small output: ");
357 adbuf_printf(&b, "%d %04x", 123456789, 123456789);
358 printf("%s\n", adbuf_ptr(&b));
359 adbuf_reset(&b);
360 for (i = 0; i < 1024; i++) {
361 adbuf_addchar(&b, 'X');
362 }
363 adbuf_init(&bb);
364 adbuf_printf(&bb, "%s---%s",
365 adbuf_ptr(&b), adbuf_ptr(&b));
366 adbuf_free(&b);
367 printf("bif printf test... ");
368 if (strlen(adbuf_ptr(&bb)) == (1024*2)+3)
369 printf("PASSED\n");
370 else
371 printf("FALIED!!!\n");
372 adbuf_free(&bb);
373 return 0;
374 }
375 #endif /* TEST_MAIN */
376