1 /*************************************************************************
2 **  Copyright (c) 2012, 2014, 2016, The Trusted Domain Project.
3 ** 	All rights reserved.
4 **************************************************************************/
5 #include "opendmarc_internal.h"
6 
7 /* libbsd if found */
8 #ifdef USE_BSD_H
9 # include <bsd/string.h>
10 #endif /* USE_BSD_H */
11 
12 /* libstrl if needed */
13 #ifdef USE_STRL_H
14 # include <strl.h>
15 #endif /* USE_STRL_H */
16 
17 /* opendmarc_strl if needed */
18 #ifdef USE_DMARCSTRL_H
19 # include <opendmarc_strl.h>
20 #endif /* USE_DMARCSTRL_H */
21 
22 /*****************************************************
23 **  OPENDMARC_UTIL_CLEARARGV -- Free the argv array
24 **
25 **	Parameters:
26 **		ary	-- Pointer to array to free
27 **	Returns:
28 **		NULL always
29 **	Side Effects:
30 **		Allocates and reallocates memory.
31 */
32 u_char **
opendmarc_util_clearargv(u_char ** ary)33 opendmarc_util_clearargv(u_char **ary)
34 {
35 	if (ary != NULL)
36 	{
37 		u_char **arp;
38 
39 		for (arp = ary; *arp != NULL; ++arp)
40 		{
41 			(void) free(*arp);
42 			*arp = NULL;
43 		}
44 		(void) free(ary);
45 		ary = NULL;
46 	}
47 	return ary;
48 }
49 
50 /*****************************************************
51 **  OPENDMARC_UTIL_PUSHARGV -- Add to and array of strings.
52 **
53 **	Parameters:
54 **		str	-- The string to add.
55 **		ary	-- The array to extend.
56 **		cnt	-- Points to number of elements.
57 **	Returns:
58 **		ary on success.
59 **		NULL on error and sets errno.
60 **	Side Effects:
61 **		Allocates and reallocates memory.
62 */
63 u_char **
opendmarc_util_pushargv(u_char * str,u_char ** ary,int * cnt)64 opendmarc_util_pushargv(u_char *str, u_char **ary, int *cnt)
65 {
66 	int   	 i;
67 	u_char **tmp;
68 
69 	if (str == NULL)
70 		return ary;
71 
72 	if (ary == NULL)
73 	{
74 		ary = malloc(sizeof(char **) * 2);
75 		if (ary == NULL)
76 		{
77 			return NULL;
78 		}
79 		ary[0] = strdup(str);
80 		ary[1] = NULL;
81 		if (ary[0] == NULL)
82 		{
83 			(void) free(ary);
84 			return NULL;
85 		}
86 		if (cnt != NULL)
87 			*cnt = 1;
88 		return ary;
89 	}
90 	if (cnt == NULL)
91 	{
92 		for (i = 0; ;i++)
93 		{
94 			if (ary[i] == NULL)
95 				break;
96 		}
97 	}
98 	else
99 		i = *cnt;
100 	tmp = realloc((void *)ary, sizeof(char **) * (i+2));
101 	if (tmp == NULL)
102 	{
103 		ary = opendmarc_util_clearargv(ary);
104 		return NULL;
105 	}
106 	ary = tmp;
107 	ary[i] = strdup(str);
108 	if (ary[i] == NULL)
109 	{
110 		ary = opendmarc_util_clearargv(ary);
111 		return NULL;
112 	}
113 	ary[i+1] = NULL;
114 	if (cnt != NULL)
115 		*cnt = i + 1;
116 	return ary;
117 }
118 
119 /*****************************************************
120 **  OPENDMARC_UTIL_DUPE_ARGV -- Duplicate an argv
121 **
122 **	Parameters:
123 **		ary	-- Pointer to array to dupe
124 **	Returns:
125 **		u_char **	-- On success
126 **		NULL		-- on error
127 **	Side Effects:
128 **		Allocates and reallocates memory.
129 */
130 u_char **
opendmarc_util_dupe_argv(u_char ** ary)131 opendmarc_util_dupe_argv(u_char **ary)
132 {
133 	u_char **new = NULL;
134 	int      new_cnt = 0;
135 
136 	if (ary != NULL)
137 	{
138 		u_char **arp;
139 
140 		for (arp = ary; *arp != NULL; ++arp)
141 			new = opendmarc_util_pushargv(*arp, new, &new_cnt);
142 	}
143 	return new;
144 }
145 
146 /*****************************************************
147 **  OPENDMARC_UTIL_CLEANUP -- Remove whitespace
148 **
149 **	Parameters:
150 **		str	-- The string cleanup
151 **		buf	-- Where to place result
152 **		buflen	-- Length of buf
153 **	Returns:
154 **		buf on success.
155 **		NULL on error and sets errno.
156 **	Side Effects:
157 */
158 u_char *
opendmarc_util_cleanup(u_char * str,u_char * buf,size_t buflen)159 opendmarc_util_cleanup(u_char *str, u_char *buf, size_t buflen)
160 {
161 	char *sp, *ep;
162 
163 	if (str == NULL || buf == NULL || strlen((char *)str) > buflen)
164 	{
165 		errno = EINVAL;
166 		return NULL;
167 	}
168 
169 	(void) memset(buf, '\0', buflen);
170 
171 	for (sp = str, ep = buf; *sp != '\0'; sp++)
172 	{
173 		if (!isascii(*sp) || !isspace(*sp))
174 			*ep++ = *sp;
175 	}
176 
177 	return buf;
178 }
179 
180 /************************************************************
181 ** OPENDMARC_UTIL_FINDDOMAIN --Focus on the domain
182 **
183 **	Parameters:
184 **		raw	-- The address containing domain
185 **		buf	-- Where to place result
186 **		buflen	-- Length of buf
187 **	Returns:
188 **		buf on success.
189 **		NULL on error and sets errno.
190 **	Side Effects:
191 ** 	   e.g. (foo) a@a.com (bar) --->  a.com
192 **	        "foo" <a@a.com> "foo" --> a.com
193 **		a@a.com, b@b.com, c@c.com --> a.com
194 */
195 u_char *
opendmarc_util_finddomain(u_char * raw,u_char * buf,size_t buflen)196 opendmarc_util_finddomain(u_char *raw, u_char *buf, size_t buflen)
197 {
198 	u_char *a     	= NULL;
199 	u_char *b     	= NULL;
200 	u_char *ep    	= NULL;
201 	u_char  copy[BUFSIZ];
202 	u_char *cp	= NULL;
203 	int 	inparen	= 0;
204 #define OPENDMARC_MAX_QUOTES (256)
205 	int	quotes[OPENDMARC_MAX_QUOTES + 1];
206 	int	numquotes = 0;
207 	size_t  len;
208 
209 	if (raw == NULL)
210 		return NULL;
211 
212 	(void) memset(copy, '\0', sizeof copy);
213 	len = strlen((char *)raw);
214 	if (len > BUFSIZ)
215 		len = BUFSIZ - 1;
216 	(void) strncpy(copy, raw, len);
217 
218 	/*
219 	 * Quoted commas do not delimit addresses.
220 	 * Un-quoted ones do.
221 	 */
222 	for (cp = copy; *cp != '\0'; ++cp)
223 	{
224 		/*
225 		 * <> has a higher precedence than quotes.
226 		 * Prevents "From: Davide D'Marco <user@blah.com>" from breaking.
227 		 */
228 		if (*cp == '<')
229 			break;
230 
231 		if (numquotes == 0 && *cp == ',')
232 		{
233 			*cp = '\0';
234 			break;
235 		}
236 		if (numquotes > 0 && *cp == ')')
237 		{
238 			if (quotes[numquotes-1]  == ')')
239 			{
240 				--numquotes;
241 				*cp = ' ';
242 				continue;
243 			}
244 		}
245 		if (*cp == '"' || *cp == '\'' || *cp == '(')
246 		{
247 			if (*cp == '(')
248 				*cp = ')';
249 			if (numquotes == 0)
250 			{
251 				quotes[numquotes] = *cp;
252 				++numquotes;
253 				*cp = ' ';
254 				continue;
255 			}
256 			if (*cp == quotes[numquotes -1])
257 			{
258 				--numquotes;
259 				*cp = ' ';
260 				continue;
261 			}
262 			quotes[numquotes] = *cp;
263 			if (numquotes >= OPENDMARC_MAX_QUOTES)
264 				break;
265 			++numquotes;
266 			*cp = ' ';
267 			continue;
268 		}
269 		if (numquotes > 0)
270 			*cp = ' ';
271 	}
272 	ep = copy + strlen((char *)copy);
273 	for (b = ep-1; b > copy; --b)
274 	{
275 		if (*b == '<')
276 			break;
277 	}
278 	if (*b == '<')
279 	{
280 		for (a = b; a < ep; ++a)
281 		{
282 			if (*a == '>')
283 				break;
284 		}
285 		if (*a == '>')
286 		{
287 			*a = '\0';
288 			cp = ++b;
289 			goto strip_local_part;
290 		}
291 	}
292 	for (a = copy; a < ep; a++)
293 	{
294 		if (isspace((int)*a))
295 			continue;
296 		if (*a == '(')
297 		{
298 			inparen = 1;
299 			continue;
300 		}
301 		if (inparen == 1 && *a != ')')
302 			continue;
303 		if (inparen == 1 && *a == ')')
304 		{
305 			inparen = 0;
306 			continue;
307 		}
308 		break;
309 	}
310 	for (b = ep -1; b > a; --b)
311 	{
312 		if (isspace((int)*b))
313 			continue;
314 		if (*b == ')')
315 		{
316 			inparen = 1;
317 			continue;
318 		}
319 		if (inparen == 1 && *b != '(')
320 			continue;
321 		if (inparen == 1 && *b == '(')
322 		{
323 			inparen = 0;
324 			continue;
325 		}
326 		break;
327 	}
328 	*(b+1) ='\0';
329 	cp = a;
330 strip_local_part:
331 	if (cp == NULL)
332 		cp = copy;
333 	ep = strchr(cp, '@');
334 	if (ep != NULL)
335 		cp = ep + 1;
336 	len = strlen((char *)cp);
337 	if (len > buflen)
338 		cp[buflen -1] = '\0';
339 	len = strlen((char *)cp);
340 	if (len > 0)
341 	{
342 		/*
343 		 * If the domain name ends in a dot, drop that dot.
344 		 */
345 		ep = cp + len -1;
346 		if (*ep == '.')
347 			*ep = '\0';
348 	}
349 	(void) strlcpy(buf, cp, buflen);
350 	return buf;
351 }
352 
353 char **
opendmarc_util_freenargv(char ** ary,int * num)354 opendmarc_util_freenargv(char **ary, int *num)
355 {
356 	if (ary != NULL)
357 	{
358 		char **ccp;
359 
360 		for (ccp = ary; *ccp != NULL; ++ccp)
361 		{
362 			(void) free(*ccp);
363 			*ccp = NULL;
364 		}
365 		(void) free(ary);
366 		ary = NULL;
367 	}
368 	if (num != NULL)
369 		*num = 0;
370 	return NULL;
371 }
372 
373 char **
opendmarc_util_pushnargv(char * str,char ** ary,int * num)374 opendmarc_util_pushnargv(char *str, char **ary, int *num)
375 {
376 	int    i;
377 	char **tmp;
378 
379 	if (str != NULL)
380 	{
381 		if (ary == NULL)
382 		{
383 			ary = calloc(sizeof(char **), 2);
384 			if (ary == NULL)
385 			{
386 				if (num != NULL)
387 					*num = 0;
388 				return NULL;
389 			}
390 			*ary = strdup(str);
391 			*(ary+1) = NULL;
392 			if (*ary == NULL)
393 			{
394 				(void) free(ary);
395 				ary = NULL;
396 				if (num != NULL)
397 					*num = 0;
398 				return NULL;
399 			}
400 			if (num != NULL)
401 				*num = 1;
402 			return ary;
403 		}
404 		i = 0;
405 		if (num == NULL)
406 		{
407 			for (i = 0; ;i++)
408 			{
409 				if (ary[i] == NULL)
410 					break;
411 			}
412 		}
413 		else
414 			i = *num;
415 		tmp = realloc((void *)ary, sizeof(char **) * (i+2));
416 		if (tmp == NULL)
417 		{
418 			ary = opendmarc_util_freenargv(ary, num);
419 			return NULL;
420 		}
421 		ary = tmp;
422 		ary[i] = strdup(str);
423 		if (ary[i] == NULL)
424 		{
425 			ary = opendmarc_util_freenargv(ary, num);
426 			return NULL;
427 		}
428 		++i;
429 		ary[i] = NULL;
430 		if (num != NULL)
431 			*num = i;
432 	}
433 	return ary;
434 }
435 
436 /*
437 ** Convert a decimal unsigned long interger into a string.
438 ** Returns a pointer to the passed buffer.
439 */
440 char *
opendmarc_util_ultoa(unsigned long val,char * buffer,size_t bufferlen)441 opendmarc_util_ultoa(unsigned long val, char *buffer, size_t bufferlen)
442 {
443 	register char  *b = buffer;
444 	register size_t l = bufferlen;
445 	register unsigned long    v = val;
446 	register long  mod, d, digit;
447 #define MAXDIGITS (32)
448 	int digits[MAXDIGITS];
449 
450 	if (b == NULL || l < 2)
451 		return NULL;
452 
453 	if (v == 0)
454 	{
455 		*b++ = '0';
456 		*b = '\0';
457 		return buffer;
458 	}
459 	digit = 0;
460 	do
461 	{
462 		mod = v % 10;
463 		v = v / 10;
464 		digits[digit] = mod;
465 		++digit;
466 		if (digit >= MAXDIGITS)
467 			break;
468 	} while(v != 0);
469 	for (d = digit-1; d >= 0; --d)
470 	{
471 		 switch (digits[d])
472 		 {
473 			case 0: *b++ = '0'; --l; break;
474 			case 1: *b++ = '1'; --l; break;
475 			case 2: *b++ = '2'; --l; break;
476 			case 3: *b++ = '3'; --l; break;
477 			case 4: *b++ = '4'; --l; break;
478 			case 5: *b++ = '5'; --l; break;
479 			case 6: *b++ = '6'; --l; break;
480 			case 7: *b++ = '7'; --l; break;
481 			case 8: *b++ = '8'; --l; break;
482 			case 9: *b++ = '9'; --l; break;
483 		 }
484 		 if (l == 1)
485 			break;
486 	}
487 	*b = '\0';
488 	return buffer;
489 }
490