]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/starter/args.c
Moved debug.[ch] to utils folder
[thirdparty/strongswan.git] / src / starter / args.c
CommitLineData
997358a6
MW
1/* automatic handling of confread struct arguments
2 * Copyright (C) 2006 Andreas Steffen
3 * Hochschule fuer Technik Rapperswil, Switzerland
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
997358a6
MW
14 */
15
16#include <stddef.h>
17#include <stdlib.h>
18#include <string.h>
19
163b2273 20#include <library.h>
f05b4272 21#include <utils/debug.h>
997358a6 22
997358a6 23#include "keywords.h"
997358a6
MW
24#include "confread.h"
25#include "args.h"
26
27/* argument types */
28
29typedef enum {
3d7a244b
AS
30 ARG_NONE,
31 ARG_ENUM,
32 ARG_UINT,
33 ARG_TIME,
34 ARG_ULNG,
9c7faa86 35 ARG_ULLI,
3d7a244b
AS
36 ARG_PCNT,
37 ARG_STR,
38 ARG_LST,
39 ARG_MISC
997358a6
MW
40} arg_t;
41
42/* various keyword lists */
43
44static const char *LST_bool[] = {
3d7a244b
AS
45 "no",
46 "yes",
47 NULL
997358a6
MW
48};
49
50static const char *LST_sendcert[] = {
3d7a244b
AS
51 "always",
52 "ifasked",
53 "never",
54 "yes",
55 "no",
56 NULL
997358a6
MW
57};
58
0644ebd3 59static const char *LST_unique[] = {
3d7a244b
AS
60 "no",
61 "yes",
62 "replace",
63 "keep",
f4cc7ea1 64 "never",
3d7a244b 65 NULL
0644ebd3
MW
66};
67
4841189b 68static const char *LST_strict[] = {
3d7a244b
AS
69 "no",
70 "yes",
71 "ifuri",
72 NULL
4841189b 73};
997358a6 74static const char *LST_dpd_action[] = {
3d7a244b
AS
75 "none",
76 "clear",
77 "hold",
78 "restart",
79 NULL
997358a6
MW
80};
81
82static const char *LST_startup[] = {
3d7a244b
AS
83 "ignore",
84 "add",
85 "route",
86 "start",
87 NULL
997358a6
MW
88};
89
997358a6 90static const char *LST_keyexchange[] = {
3d7a244b
AS
91 "ike",
92 "ikev1",
93 "ikev2",
94 NULL
997358a6
MW
95};
96
e838c39b
TB
97static const char *LST_authby[] = {
98 "psk",
99 "secret",
100 "pubkey",
101 "rsa",
102 "rsasig",
103 "ecdsa",
104 "ecdsasig",
105 "xauthpsk",
106 "xauthrsasig",
107 "never",
108 NULL
109};
110
997358a6 111typedef struct {
3d7a244b
AS
112 arg_t type;
113 size_t offset;
114 const char **list;
997358a6
MW
115} token_info_t;
116
117static const token_info_t token_info[] =
118{
3d7a244b 119 /* config setup keywords */
3d7a244b 120 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
3d7a244b 121 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
3d7a244b
AS
122 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
123 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
25fb9d3f 124 { ARG_MISC, 0, NULL /* KW_PKCS11_DEPRECATED */ },
9707d9db 125 { ARG_MISC, 0, NULL /* KW_SETUP_DEPRECATED */ },
3d7a244b
AS
126
127 /* conn section keywords */
128 { ARG_STR, offsetof(starter_conn_t, name), NULL },
129 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
130 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
131 { ARG_MISC, 0, NULL /* KW_TYPE */ },
3d7a244b
AS
132 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
133 { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool },
e129168b 134 { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool },
3d7a244b 135 { ARG_MISC, 0, NULL /* KW_AUTH */ },
e838c39b 136 { ARG_STR, offsetof(starter_conn_t, authby), LST_authby },
3d7a244b 137 { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL },
64d7b073 138 { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL },
3d7a244b
AS
139 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
140 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
141 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
142 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
143 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
ca41aa06
TB
144 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL },
145 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL },
146 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL },
147 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL },
3d7a244b
AS
148 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
149 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
150 { ARG_MISC, 0, NULL /* KW_REKEY */ },
151 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
152 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
153 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
3d7a244b
AS
154 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
155 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
156 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
f34ebc84 157 { ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action },
8015c91c 158 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
3d7a244b
AS
159 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
160 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
8143f109 161 { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL },
3d7a244b
AS
162 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
163 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
164 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
2b26a9c3 165 { ARG_UINT, offsetof(starter_conn_t, reqid), NULL },
ee26c537 166 { ARG_MISC, 0, NULL /* KW_MARK */ },
26c4d010
AS
167 { ARG_MISC, 0, NULL /* KW_MARK_IN */ },
168 { ARG_MISC, 0, NULL /* KW_MARK_OUT */ },
6c302616 169 { ARG_MISC, 0, NULL /* KW_TFC */ },
25fb9d3f 170 { ARG_MISC, 0, NULL /* KW_PFS_DEPRECATED */ },
9707d9db 171 { ARG_MISC, 0, NULL /* KW_CONN_DEPRECATED */ },
3d7a244b
AS
172
173 /* ca section keywords */
174 { ARG_STR, offsetof(starter_ca_t, name), NULL },
175 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
176 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
3d7a244b
AS
177 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
178 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
179 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
180 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
181 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
9707d9db 182 { ARG_MISC, 0, NULL /* KW_CA_DEPRECATED */ },
3d7a244b
AS
183
184 /* end keywords */
e59a5000 185 { ARG_STR, offsetof(starter_end_t, host), NULL },
667b7372 186 { ARG_UINT, offsetof(starter_end_t, ikeport), NULL },
8dd094e1 187 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
3d7a244b 188 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
61e48488 189 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
17319aa2 190 { ARG_STR, offsetof(starter_end_t, dns), NULL },
3d7a244b
AS
191 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
192 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
193 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
194 { ARG_STR, offsetof(starter_end_t, updown), NULL },
195 { ARG_STR, offsetof(starter_end_t, auth), NULL },
196 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
197 { ARG_STR, offsetof(starter_end_t, id), NULL },
198 { ARG_STR, offsetof(starter_end_t, id2), NULL },
199 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
200 { ARG_STR, offsetof(starter_end_t, cert), NULL },
201 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
6367de28 202 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
3d7a244b
AS
203 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
204 { ARG_STR, offsetof(starter_end_t, ca), NULL },
205 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
206 { ARG_STR, offsetof(starter_end_t, groups), NULL },
46df61df 207 { ARG_STR, offsetof(starter_end_t, groups2), NULL },
9707d9db 208 { ARG_MISC, 0, NULL /* KW_END_DEPRECATED */ },
997358a6
MW
209};
210
10c13ed2 211static void free_list(char **list)
997358a6 212{
3d7a244b 213 char **s;
997358a6 214
3d7a244b
AS
215 for (s = list; *s; s++)
216 {
217 free(*s);
218 }
219 free(list);
997358a6
MW
220}
221
10c13ed2 222char** new_list(char *value)
997358a6 223{
3d7a244b
AS
224 char *val, *b, *e, *end, **ret;
225 int count;
226
7cce0e96 227 val = strdupnull(value);
3d7a244b 228 if (!val)
10c13ed2 229 {
3d7a244b 230 return NULL;
10c13ed2 231 }
3d7a244b
AS
232 end = val + strlen(val);
233 for (b = val, count = 0; b < end;)
234 {
235 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
236 *e = '\0';
237 if (e != b)
10c13ed2 238 {
3d7a244b 239 count++;
10c13ed2 240 }
3d7a244b
AS
241 b = e + 1;
242 }
243 if (count == 0)
244 {
245 free(val);
246 return NULL;
247 }
248 ret = (char **)malloc((count+1) * sizeof(char *));
249
250 for (b = val, count = 0; b < end; )
251 {
252 for (e = b; (*e != '\0'); e++);
253 if (e != b)
10c13ed2 254 {
7cce0e96 255 ret[count++] = strdupnull(b);
10c13ed2 256 }
3d7a244b
AS
257 b = e + 1;
258 }
259 ret[count] = NULL;
67411e66 260 free(val);
3d7a244b 261 return ret;
997358a6
MW
262}
263
264
265/*
266 * assigns an argument value to a struct field
267 */
10c13ed2
AS
268bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
269 bool *assigned)
997358a6 270{
3d7a244b
AS
271 char *p = base + token_info[token].offset;
272 const char **list = token_info[token].list;
997358a6 273
3d7a244b 274 int index = -1; /* used for enumeration arguments */
997358a6 275
f82365ad 276 seen_t *seen = (seen_t*)base; /* seen flags are at the top of the struct */
997358a6 277
3d7a244b 278 *assigned = FALSE;
997358a6 279
163b2273 280 DBG3(DBG_APP, " %s=%s", kw->entry->name, kw->value);
997358a6 281
f82365ad 282 if (*seen & SEEN_KW(token, first))
997358a6 283 {
163b2273 284 DBG1(DBG_APP, "# duplicate '%s' option", kw->entry->name);
997358a6 285 return FALSE;
997358a6 286 }
997358a6 287
3d7a244b 288 /* set flag that this argument has been seen */
f82365ad 289 *seen |= SEEN_KW(token, first);
997358a6 290
3d7a244b
AS
291 /* is there a keyword list? */
292 if (list != NULL && token_info[token].type != ARG_LST)
997358a6 293 {
3d7a244b 294 bool match = FALSE;
997358a6 295
3d7a244b 296 while (*list != NULL && !match)
997358a6 297 {
3d7a244b
AS
298 index++;
299 match = streq(kw->value, *list++);
997358a6 300 }
3d7a244b 301 if (!match)
997358a6 302 {
163b2273 303 DBG1(DBG_APP, "# bad value: %s=%s", kw->entry->name, kw->value);
3d7a244b 304 return FALSE;
997358a6 305 }
997358a6 306 }
997358a6 307
3d7a244b
AS
308 switch (token_info[token].type)
309 {
310 case ARG_NONE:
163b2273 311 DBG1(DBG_APP, "# option '%s' not supported yet", kw->entry->name);
3d7a244b
AS
312 return FALSE;
313 case ARG_ENUM:
314 {
3d7a244b
AS
315 if (index < 0)
316 {
163b2273
TB
317 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
318 kw->entry->name, kw->value, index);
3d7a244b
AS
319 return FALSE;
320 }
5533a889
TB
321
322 if (token_info[token].list == LST_bool)
323 {
324 bool *b = (bool *)p;
325 *b = (index > 0);
326 }
327 else
328 {
329 int *i = (int *)p;
330 *i = index;
331 }
3d7a244b 332 }
997358a6
MW
333 break;
334
3d7a244b 335 case ARG_UINT:
997358a6 336 {
3d7a244b 337 char *endptr;
7daf5226 338 u_int *u = (u_int *)p;
3d7a244b
AS
339
340 *u = strtoul(kw->value, &endptr, 10);
341
342 if (*endptr != '\0')
343 {
163b2273
TB
344 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
345 kw->value);
3d7a244b
AS
346 return FALSE;
347 }
997358a6 348 }
3d7a244b
AS
349 break;
350 case ARG_ULNG:
351 case ARG_PCNT:
997358a6 352 {
3d7a244b
AS
353 char *endptr;
354 unsigned long *l = (unsigned long *)p;
355
356 *l = strtoul(kw->value, &endptr, 10);
357
358 if (token_info[token].type == ARG_ULNG)
359 {
360 if (*endptr != '\0')
361 {
163b2273
TB
362 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
363 kw->value);
3d7a244b
AS
364 return FALSE;
365 }
366 }
367 else
368 {
369 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
370 {
163b2273
TB
371 DBG1(DBG_APP, "# bad percent value: %s=%s", kw->entry->name,
372 kw->value);
3d7a244b
AS
373 return FALSE;
374 }
375 }
376
997358a6 377 }
3d7a244b 378 break;
9c7faa86
TB
379 case ARG_ULLI:
380 {
381 char *endptr;
382 unsigned long long *ll = (unsigned long long *)p;
383
384 *ll = strtoull(kw->value, &endptr, 10);
385
386 if (*endptr != '\0')
387 {
163b2273
TB
388 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
389 kw->value);
9c7faa86
TB
390 return FALSE;
391 }
392 }
393 break;
3d7a244b 394 case ARG_TIME:
997358a6 395 {
3d7a244b
AS
396 char *endptr;
397 time_t *t = (time_t *)p;
398
399 *t = strtoul(kw->value, &endptr, 10);
400
401 /* time in seconds? */
402 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
10c13ed2 403 {
3d7a244b 404 break;
10c13ed2 405 }
3d7a244b
AS
406 if (endptr[1] == '\0')
407 {
408 if (*endptr == 'm') /* time in minutes? */
409 {
410 *t *= 60;
411 break;
412 }
413 if (*endptr == 'h') /* time in hours? */
414 {
415 *t *= 3600;
416 break;
417 }
418 if (*endptr == 'd') /* time in days? */
419 {
420 *t *= 3600*24;
421 break;
422 }
423 }
163b2273
TB
424 DBG1(DBG_APP, "# bad duration value: %s=%s", kw->entry->name,
425 kw->value);
3d7a244b 426 return FALSE;
997358a6 427 }
3d7a244b
AS
428 case ARG_STR:
429 {
430 char **cp = (char **)p;
997358a6 431
3d7a244b
AS
432 /* free any existing string */
433 free(*cp);
997358a6 434
3d7a244b 435 /* assign the new string */
7cce0e96 436 *cp = strdupnull(kw->value);
3d7a244b
AS
437 }
438 break;
439 case ARG_LST:
997358a6 440 {
3d7a244b
AS
441 char ***listp = (char ***)p;
442
443 /* free any existing list */
444 if (*listp != NULL)
10c13ed2 445 {
3d7a244b 446 free_list(*listp);
10c13ed2 447 }
3d7a244b
AS
448 /* create a new list and assign values */
449 *listp = new_list(kw->value);
450
451 /* is there a keyword list? */
452 if (list != NULL)
453 {
454 char ** lst;
455
7daf5226 456 for (lst = *listp; lst && *lst; lst++)
3d7a244b
AS
457 {
458 bool match = FALSE;
459
460 list = token_info[token].list;
7daf5226 461
3d7a244b
AS
462 while (*list != NULL && !match)
463 {
464 match = streq(*lst, *list++);
465 }
466 if (!match)
467 {
163b2273
TB
468 DBG1(DBG_APP, "# bad value: %s=%s",
469 kw->entry->name, *lst);
3d7a244b
AS
470 return FALSE;
471 }
472 }
473 }
997358a6 474 }
1c004beb 475 /* fall through */
3d7a244b
AS
476 default:
477 return TRUE;
997358a6 478 }
997358a6 479
3d7a244b
AS
480 *assigned = TRUE;
481 return TRUE;
997358a6
MW
482}
483
484/*
485 * frees all dynamically allocated arguments in a struct
486 */
10c13ed2 487void free_args(kw_token_t first, kw_token_t last, char *base)
997358a6 488{
3d7a244b 489 kw_token_t token;
997358a6 490
3d7a244b 491 for (token = first; token <= last; token++)
997358a6 492 {
3d7a244b 493 char *p = base + token_info[token].offset;
997358a6 494
3d7a244b 495 switch (token_info[token].type)
997358a6 496 {
3d7a244b
AS
497 case ARG_STR:
498 {
499 char **cp = (char **)p;
500
501 free(*cp);
502 *cp = NULL;
503 }
504 break;
505 case ARG_LST:
506 {
507 char ***listp = (char ***)p;
508
509 if (*listp != NULL)
510 {
511 free_list(*listp);
512 *listp = NULL;
513 }
514 }
515 break;
516 default:
517 break;
518 }
997358a6 519 }
997358a6
MW
520}
521
522/*
523 * clone all dynamically allocated arguments in a struct
524 */
10c13ed2 525void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
997358a6 526{
3d7a244b 527 kw_token_t token;
997358a6 528
3d7a244b 529 for (token = first; token <= last; token++)
997358a6 530 {
3d7a244b
AS
531 if (token_info[token].type == ARG_STR)
532 {
533 char **cp1 = (char **)(base1 + token_info[token].offset);
534 char **cp2 = (char **)(base2 + token_info[token].offset);
997358a6 535
7cce0e96 536 *cp1 = strdupnull(*cp2);
3d7a244b 537 }
997358a6 538 }
997358a6
MW
539}
540
10c13ed2 541static bool cmp_list(char **list1, char **list2)
997358a6 542{
3d7a244b 543 if ((list1 == NULL) && (list2 == NULL))
10c13ed2 544 {
3d7a244b 545 return TRUE;
10c13ed2 546 }
3d7a244b 547 if ((list1 == NULL) || (list2 == NULL))
10c13ed2 548 {
3d7a244b 549 return FALSE;
10c13ed2 550 }
997358a6 551
3d7a244b
AS
552 for ( ; *list1 && *list2; list1++, list2++)
553 {
554 if (strcmp(*list1,*list2) != 0)
10c13ed2 555 {
3d7a244b 556 return FALSE;
10c13ed2 557 }
3d7a244b 558 }
997358a6 559
3d7a244b 560 if ((*list1 != NULL) || (*list2 != NULL))
10c13ed2 561 {
3d7a244b 562 return FALSE;
10c13ed2 563 }
997358a6 564
3d7a244b 565 return TRUE;
997358a6
MW
566}
567
568/*
569 * compare all arguments in a struct
570 */
10c13ed2 571bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
997358a6 572{
3d7a244b 573 kw_token_t token;
997358a6 574
3d7a244b 575 for (token = first; token <= last; token++)
997358a6 576 {
3d7a244b
AS
577 char *p1 = base1 + token_info[token].offset;
578 char *p2 = base2 + token_info[token].offset;
579
580 switch (token_info[token].type)
581 {
582 case ARG_ENUM:
10c13ed2
AS
583 if (token_info[token].list == LST_bool)
584 {
585 bool *b1 = (bool *)p1;
586 bool *b2 = (bool *)p2;
587
588 if (*b1 != *b2)
589 {
590 return FALSE;
591 }
592 }
593 else
3d7a244b
AS
594 {
595 int *i1 = (int *)p1;
596 int *i2 = (int *)p2;
597
598 if (*i1 != *i2)
10c13ed2 599 {
3d7a244b 600 return FALSE;
10c13ed2 601 }
3d7a244b
AS
602 }
603 break;
604 case ARG_UINT:
605 {
606 u_int *u1 = (u_int *)p1;
607 u_int *u2 = (u_int *)p2;
608
609 if (*u1 != *u2)
10c13ed2 610 {
3d7a244b 611 return FALSE;
10c13ed2 612 }
3d7a244b
AS
613 }
614 break;
615 case ARG_ULNG:
616 case ARG_PCNT:
617 {
618 unsigned long *l1 = (unsigned long *)p1;
619 unsigned long *l2 = (unsigned long *)p2;
620
621 if (*l1 != *l2)
10c13ed2 622 {
3d7a244b 623 return FALSE;
10c13ed2 624 }
3d7a244b
AS
625 }
626 break;
9c7faa86
TB
627 case ARG_ULLI:
628 {
629 unsigned long long *ll1 = (unsigned long long *)p1;
630 unsigned long long *ll2 = (unsigned long long *)p2;
631
632 if (*ll1 != *ll2)
633 {
634 return FALSE;
635 }
636 }
637 break;
3d7a244b
AS
638 case ARG_TIME:
639 {
640 time_t *t1 = (time_t *)p1;
641 time_t *t2 = (time_t *)p2;
642
643 if (*t1 != *t2)
10c13ed2 644 {
3d7a244b 645 return FALSE;
10c13ed2 646 }
3d7a244b
AS
647 }
648 break;
649 case ARG_STR:
650 {
651 char **cp1 = (char **)p1;
652 char **cp2 = (char **)p2;
653
654 if (*cp1 == NULL && *cp2 == NULL)
10c13ed2 655 {
3d7a244b 656 break;
10c13ed2 657 }
3d7a244b 658 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
10c13ed2 659 {
3d7a244b 660 return FALSE;
10c13ed2 661 }
3d7a244b
AS
662 }
663 break;
664 case ARG_LST:
665 {
666 char ***listp1 = (char ***)p1;
667 char ***listp2 = (char ***)p2;
668
669 if (!cmp_list(*listp1, *listp2))
10c13ed2 670 {
3d7a244b 671 return FALSE;
10c13ed2 672 }
3d7a244b
AS
673 }
674 break;
675 default:
676 break;
677 }
997358a6 678 }
3d7a244b 679 return TRUE;
997358a6 680}