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