xref: /dragonfly/contrib/pam_passwdqc/concat.c (revision 7d3e9a5b)
1 /*
2  * concat() - allocate memory and safely concatenate strings in portable C
3  * (and C++ if you like).
4  *
5  * This code deals gracefully with potential integer overflows (perhaps when
6  * input strings are maliciously long), as well as with input strings changing
7  * from under it (perhaps because of misbehavior of another thread).  It does
8  * not depend on non-portable functions such as snprintf() and asprintf().
9  *
10  * Written by Solar Designer <solar at openwall.com> and placed in the
11  * public domain.
12  */
13 
14 #include <string.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <limits.h>
18 #include "concat.h"
19 
20 char *concat(const char *s1, ...)
21 {
22 	va_list args;
23 	const char *s;
24 	char *p, *result;
25 	size_t l, m, n;
26 
27 	m = n = strlen(s1);
28 	va_start(args, s1);
29 	while ((s = va_arg(args, char *))) {
30 		l = strlen(s);
31 		if ((m += l) < l)
32 			break;
33 	}
34 	va_end(args);
35 	if (s || m >= INT_MAX)
36 		return NULL;
37 
38 	result = (char *)malloc(m + 1);
39 	if (!result)
40 		return NULL;
41 
42 	memcpy(p = result, s1, n);
43 	p += n;
44 	va_start(args, s1);
45 	while ((s = va_arg(args, char *))) {
46 		l = strlen(s);
47 		if ((n += l) < l || n > m)
48 			break;
49 		memcpy(p, s, l);
50 		p += l;
51 	}
52 	va_end(args);
53 	if (s || m != n || p != result + n) {
54 		free(result);
55 		return NULL;
56 	}
57 
58 	*p = 0;
59 	return result;
60 }
61 
62 #ifdef TEST
63 #include <stdio.h>
64 
65 int main(int argc, char **argv)
66 {
67 	puts(concat(argv[0], argv[1], argv[2], argv[3], NULL));
68 	return 0;
69 }
70 #endif
71