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