1 /*
2 * Copyright (c) 2012, 2013, 2014, 2020, 2021
3 * Inferno Nettverk A/S, Norway. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. The above copyright notice, this list of conditions and the following
9 * disclaimer must appear in all copies of the software, derivative works
10 * or modified versions, and any portions thereof, aswell as in all
11 * supporting documentation.
12 * 2. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by
15 * Inferno Nettverk A/S, Norway.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Inferno Nettverk A/S requests users of this software to return to
31 *
32 * Software Distribution Coordinator or sdc@inet.no
33 * Inferno Nettverk A/S
34 * Oslo Research Park
35 * Gaustadall�en 21
36 * NO-0349 Oslo
37 * Norway
38 *
39 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40 * the rights to redistribute these changes.
41 *
42 */
43
44 #include "common.h"
45
46 static const char rcsid[] =
47 "$Id: shmemconfig.c,v 1.49.4.5.6.6 2021/02/02 19:34:14 karls Exp $";
48
49 static size_t
50 linkedsize(const linkedname_t *head);
51 /*
52 * Returns size used for contents of "head" (if not NULL), and all following.
53 */
54
55 static void
56 poolinit(void *pool, const size_t size);
57 /*
58 * inits a memorypool of size "size" using the memoryblock "pool", including
59 * initing global alignment variables.
60 *
61 * Subsequent calls to getmem() will return maximally aligned memory
62 * from that pool.
63 */
64
65 void *
66 getmem(const size_t size);
67 /*
68 * Returns "size" bytes of memory from the current memorypool,
69 * or NULL if there is not enough memory available.
70 */
71
72 # if 0
73 static size_t
74 memleft(void);
75 /*
76 * Returns the number of bytes left in the memorypool.
77 */
78 #endif
79
80 static size_t
81 memleft_no_alignment_luck(void);
82 /*
83 *
84 */
85
86 typedef enum { COPY = 1, SIZE } configop_t;
87 static ssize_t
88 pointer_copyorsize(const configop_t op, struct config *src,
89 const ptrdiff_t srcoffset, struct config *dst,
90 void *mem, const size_t memsize);
91 /*
92 * copies or sizes up all pointers in src based on whether "op" indicates
93 * the operation is copy or size.
94 *
95 * If the op is COPY, "mem" points to a memory area of size "memsize", which
96 * must be big enough to hold the contents of all pointers.
97 * If "mem" is NULL if the function should allocate the memory via malloc(3)
98 * itself.
99 *
100 * Returns:
101 * If op is COPY or FREE: 0 on success, -1 on failure.
102 * If op is SIZE: size required to hold the contents of all pointers.
103 */
104
105
106 /*
107 * variable for local memorypool inited by poolinit() and used by getmem().
108 */
109 static void *_nextstart;
110 static uintptr_t _alignment, _mask;
111
112 static size_t _left, _left_no_alignment_luck, _extra_due_alignment;
113
114 #define ADDLEN(_len, total) \
115 do { \
116 const size_t len = (_len); \
117 \
118 if ((len) != 0) { \
119 slog(LOG_DEBUG, "%s: adding %lu bytes at line %d", \
120 function, (unsigned long)((len) + _alignment), __LINE__); \
121 \
122 *(total) += ((len) + _alignment); \
123 } \
124 } while (/* CONSTCOND */ 0)
125
126
127 #define DOOFFSET(object, offset) \
128 do { \
129 if (object != NULL) \
130 (object) = (void *)((uintptr_t)(object) + (offset)); \
131 } while (/* CONSTCOND */ 0)
132
133 #define DOCOPY(src, srcoffset, dst, attr, attrsize, memfunc) \
134 do { \
135 const size_t tocopy = (attrsize); \
136 \
137 if (tocopy == 0) { \
138 SASSERTX((src)->attr == NULL); \
139 SASSERTX((dst)->attr == NULL); \
140 } \
141 else { \
142 SASSERTX((src)->attr != NULL); \
143 \
144 if (((dst)->attr = memfunc(tocopy)) == NULL) { \
145 swarn("%s: failed to allocate %lu byte%s of memory at line %d. " \
146 "Memory left: %lu", \
147 function, \
148 (unsigned long)tocopy, \
149 tocopy == 1 ? "" : "s", \
150 __LINE__, \
151 (unsigned long)memleft_no_alignment_luck()); \
152 return -1; \
153 } \
154 \
155 DOOFFSET(((src)->attr), srcoffset); \
156 memcpy((dst)->attr, (src)->attr, tocopy); \
157 } \
158 } while (/* CONSTCOND */ 0)
159
160 #define DOLINKCOPY(lsrc, srcoffset, ldst, lattr, memfunc) \
161 do { \
162 linkedname_t *srclink, *dstlink; \
163 \
164 SASSERTX(lsrc != NULL); \
165 \
166 if ((srclink = (lsrc)->lattr) == NULL) \
167 break; \
168 \
169 DOOFFSET(srclink, srcoffset); \
170 (lsrc)->lattr = srclink; /* update src also. */ \
171 \
172 if (((ldst)->lattr = memfunc(sizeof(*(ldst)->lattr))) == NULL) { \
173 swarnx("%s: failed to allocate %lu byte%s of memory at line %d", \
174 function, \
175 (unsigned long)sizeof(*(ldst)->lattr), \
176 (unsigned long)sizeof(*(ldst)->lattr) == 1 ? "" : "s", \
177 __LINE__); \
178 return -1; \
179 } \
180 dstlink = (ldst)->lattr; \
181 \
182 do { \
183 char *name; \
184 \
185 SASSERTX(srclink->name != NULL); \
186 name = srclink->name; \
187 \
188 DOOFFSET(name, srcoffset); /* just for strlen(). */ \
189 DOCOPY(srclink, srcoffset, dstlink, name, strlen(name) + 1, memfunc); \
190 \
191 DOOFFSET(srclink->next, srcoffset); \
192 if (srclink->next == NULL) \
193 dstlink->next = NULL; \
194 else { \
195 if ((dstlink->next = memfunc(sizeof(*dstlink->next))) == NULL) { \
196 swarnx("%s: failed to allocate %lu byte%s of memory at line %d", \
197 function, \
198 (unsigned long)sizeof(*dstlink->next), \
199 (unsigned long)sizeof(*dstlink->next) == 1 ? "" : "s", \
200 __LINE__); \
201 return -1; \
202 } \
203 } \
204 \
205 dstlink = dstlink->next; \
206 srclink = srclink->next; \
207 } while (srclink != NULL); \
208 } while (/* CONSTCOND */ 0)
209
210 #define DOLOGCOPY(src, srcoffset, dst, attr, memfunc) \
211 do { \
212 if ((src)->attr.filenoc > 0) { \
213 size_t i; \
214 \
215 DOCOPY(src, \
216 srcoffset, \
217 dst, \
218 attr.fnamev, \
219 sizeof(*src->attr.fnamev) * src->attr.filenoc, \
220 memfunc); \
221 \
222 for (i = 0; i < src->attr.filenoc; ++i) \
223 DOCOPY(src, \
224 srcoffset, \
225 dst, \
226 attr.fnamev[i], \
227 strlen((char *)((uintptr_t)src->attr.fnamev[i] + srcoffset)) + 1, \
228 memfunc); \
229 \
230 DOCOPY(src, \
231 srcoffset, \
232 dst, \
233 attr.filenov, \
234 sizeof(*src->attr.filenov) * src->attr.filenoc, \
235 memfunc); \
236 \
237 DOCOPY(src, \
238 srcoffset, \
239 dst, \
240 attr.createdv, \
241 sizeof(*src->attr.createdv) * src->attr.filenoc, \
242 memfunc); \
243 } \
244 } while (/* CONSTCOND */ 0)
245
246
247 size_t
pointer_size(config)248 pointer_size(config)
249 struct config *config;
250 {
251
252 return pointer_copyorsize(SIZE, config, 0, NULL, NULL, 0);
253 }
254
255 int
pointer_copy(src,srcoffset,dst,mem,memsize)256 pointer_copy(src, srcoffset, dst, mem, memsize)
257 struct config *src;
258 const ptrdiff_t srcoffset;
259 struct config *dst;
260 void *mem;
261 const size_t memsize;
262 {
263 /* const char *function = "pointer_copy()"; */
264
265 SASSERTX(dst != NULL);
266
267 return pointer_copyorsize(COPY,
268 src,
269 srcoffset,
270 dst,
271 mem,
272 memsize);
273 }
274
275 static ssize_t
pointer_copyorsize(op,src,srcoffset,dst,mem,memsize)276 pointer_copyorsize(op, src, srcoffset, dst, mem, memsize)
277 const configop_t op;
278 struct config *src;
279 const ptrdiff_t srcoffset;
280 struct config *dst;
281 void *mem;
282 const size_t memsize;
283 {
284 const char *function = "pointer_copyorsize()";
285 void *(*memfunc)(size_t size) = (memsize == 0 ? malloc : getmem);
286 rule_t *srcrulev[] = { src->crule, src->hrule, src->srule };
287 ssize_t size;
288 size_t i;
289 int docopy = 0, dofree = 0, dosize = 0;
290
291 switch (op) {
292 case COPY:
293 docopy = 1;
294 break;
295
296 case SIZE:
297 dosize = 1;
298 break;
299
300 default:
301 SERRX(op);
302 }
303
304 slog(LOG_DEBUG,
305 "%s: docopy = %d, dofree = %d, dosize = %d, "
306 "mem = %p, memsize = %lu, offset = %ld",
307 function,
308 docopy,
309 dofree,
310 dosize,
311 mem,
312 (unsigned long)memsize,
313 (long)srcoffset);
314
315 /*
316 * regardless of whether it's copy or size as we need poolinit() to
317 * calculate required alignment/padbytes, or the calculated size will
318 * be to low.
319 */
320 poolinit(mem, memsize);
321
322 /*
323 * Then go through all the individual attributes and copy/free/size the
324 * pointed to memory. Better keep our tongue straight in our mouth here,
325 * as the local saying goes.
326 */
327
328 size = 0;
329
330 if (src->internal.addrc > 0) {
331 switch (op) {
332 case COPY:
333 DOCOPY(src,
334 srcoffset,
335 dst,
336 internal.addrv,
337 sizeof(*src->internal.addrv) * src->internal.addrc,
338 memfunc);
339 break;
340
341 case SIZE:
342 ADDLEN(sizeof(*src->internal.addrv) * src->internal.addrc, &size);
343 break;
344 }
345 }
346
347 if (src->external.addrc > 0) {
348 switch (op) {
349 case COPY:
350 DOCOPY(src,
351 srcoffset,
352 dst,
353 external.addrv,
354 sizeof(*src->external.addrv) * src->external.addrc,
355 memfunc);
356 break;
357
358 case SIZE:
359 ADDLEN(sizeof(*src->external.addrv) * src->external.addrc, &size);
360 break;
361
362 }
363 }
364
365 for (i = 0; i < ELEMENTS(srcrulev); ++i) {
366 struct rule_t *dstrule; /* false gcc warning: may be used uninitialized */
367 struct rule_t *srcrule = srcrulev[i];
368
369 if (srcrule == NULL)
370 continue;
371
372 switch (op) {
373 case COPY:
374 /*
375 * Init stepwise so that the head of the next rule type starts
376 * after all rules of previous type. This is just to ease
377 * debugging.
378 */
379 DOOFFSET(srcrule, srcoffset);
380
381 switch (srcrule->type) {
382 case object_crule:
383 DOCOPY(src,
384 srcoffset,
385 dst,
386 crule,
387 sizeof(*src->crule),
388 memfunc);
389 dstrule = dst->crule;
390 break;
391
392 #if HAVE_SOCKS_HOSTID
393 case object_hrule:
394 DOCOPY(src,
395 srcoffset,
396 dst,
397 hrule,
398 sizeof(*src->hrule),
399 memfunc);
400 dstrule = dst->hrule;
401 break;
402 #endif /* HAVE_SOCKS_HOSTID */
403
404 case object_srule:
405 DOCOPY(src,
406 srcoffset,
407 dst,
408 srule,
409 sizeof(*src->srule),
410 memfunc);
411 dstrule = dst->srule;
412 break;
413
414 default:
415 SERRX(srcrule->type);
416 }
417
418 break;
419
420 case SIZE:
421 ADDLEN(sizeof(*srcrule), &size);
422 break;
423 }
424
425 do {
426 if (srcrule->socketoptionc > 0) {
427 switch (op) {
428 case COPY:
429 DOCOPY(srcrule,
430 srcoffset,
431 dstrule,
432 socketoptionv,
433 sizeof(*srcrule->socketoptionv) * srcrule->socketoptionc,
434 memfunc);
435 break;
436
437 case SIZE:
438 ADDLEN(sizeof(*srcrule->socketoptionv)
439 * srcrule->socketoptionc,
440 &size);
441 break;
442 }
443 }
444
445 #if HAVE_LDAP
446 switch (op) {
447 case COPY:
448 DOLINKCOPY(srcrule,
449 srcoffset,
450 dstrule,
451 state.ldapauthorisation.ldapurl,
452 memfunc);
453
454 DOLINKCOPY(srcrule,
455 srcoffset,
456 dstrule,
457 state.ldapauthorisation.ldapbasedn,
458 memfunc);
459 break;
460
461 case SIZE:
462 ADDLEN(linkedsize(srcrule->state.ldapauthorisation.ldapurl), &size);
463 ADDLEN(linkedsize(srcrule->state.ldapauthorisation.ldapbasedn), &size);
464 break;
465 }
466
467 #endif /* HAVE_LDAP */
468
469 switch (op) {
470 case COPY:
471 DOLINKCOPY(srcrule, srcoffset, dstrule, user, memfunc);
472 DOLINKCOPY(srcrule, srcoffset, dstrule, group, memfunc);
473 break;
474
475 case SIZE:
476 ADDLEN(linkedsize(srcrule->user), &size);
477 ADDLEN(linkedsize(srcrule->group), &size);
478 break;
479 }
480
481 #if HAVE_LDAP
482 switch (op) {
483 case COPY:
484 DOLINKCOPY(srcrule, srcoffset, dstrule, ldapgroup, memfunc);
485 break;
486
487 case SIZE:
488 ADDLEN(linkedsize(srcrule->ldapgroup), &size);
489 break;
490 }
491 #endif /* HAVE_LDAP */
492
493 switch (op) {
494 case COPY:
495 if (srcrule->next == NULL)
496 dstrule->next = NULL;
497 else
498 DOCOPY(srcrule,
499 srcoffset,
500 dstrule,
501 next,
502 sizeof(*srcrule->next),
503 memfunc);
504
505 srcrule = srcrule->next;
506 dstrule = dstrule->next;
507 break;
508
509 case SIZE:
510 if (srcrule->next != NULL)
511 ADDLEN(sizeof(*srcrule), &size);
512
513 srcrule = srcrule->next;
514 break;
515
516 }
517 } while (srcrule != NULL);
518 }
519
520 if (src->route != NULL) {
521 route_t *dstroute; /* false gcc warning: may be used uninitialized */
522 route_t *srcroute;
523
524 switch (op) {
525 case COPY:
526 DOCOPY(src, srcoffset, dst, route, sizeof(*src->route), memfunc);
527 dstroute = dst->route;
528 break;
529
530 case SIZE:
531 ADDLEN(sizeof(*srcroute), &size);
532 break;
533 }
534
535 srcroute = src->route;
536
537 do {
538 switch (op) {
539 case COPY:
540 DOCOPY(srcroute,
541 srcoffset,
542 dstroute,
543 socketoptionv,
544 sizeof(*srcroute->socketoptionv) * srcroute->socketoptionc,
545 memfunc);
546
547 if (srcroute->next == NULL)
548 dstroute->next = NULL;
549 else
550 DOCOPY(srcroute,
551 srcoffset,
552 dstroute,
553 next,
554 sizeof(*srcroute->next),
555 memfunc);
556
557 dstroute = dstroute->next;
558 srcroute = srcroute->next;
559 break;
560
561 case SIZE:
562 ADDLEN(sizeof(*srcroute->socketoptionv)
563 * srcroute->socketoptionc,
564 &size);
565
566 if (srcroute->next != NULL)
567 ADDLEN(sizeof(*srcroute), &size);
568
569 srcroute = srcroute->next;
570 break;
571 }
572 } while (srcroute != NULL);
573 }
574
575 if (src->monitor != NULL) {
576 monitor_t *dstmonitor; /* false gcc warning: may be used uninitialized */
577 monitor_t *srcmonitor;
578
579 switch (op) {
580 case COPY:
581 DOCOPY(src,
582 srcoffset,
583 dst,
584 monitor,
585 sizeof(*src->monitor),
586 memfunc);
587
588 dstmonitor = dst->monitor;
589 break;
590
591 case SIZE:
592 ADDLEN(sizeof(*srcmonitor), &size);
593 break;
594 }
595
596 srcmonitor = src->monitor;
597 do {
598 switch (op) {
599 case COPY:
600 if (srcmonitor->next == NULL)
601 dstmonitor->next = NULL;
602 else
603 DOCOPY(srcmonitor,
604 srcoffset,
605 dstmonitor,
606 next,
607 sizeof(*dstmonitor->next),
608 memfunc);
609
610 dstmonitor = dstmonitor->next;
611 srcmonitor = srcmonitor->next;
612 break;
613
614 case SIZE:
615 if (srcmonitor->next != NULL)
616 ADDLEN(sizeof(*srcmonitor), &size);
617
618 srcmonitor = srcmonitor->next;
619 break;
620 }
621 } while (srcmonitor != NULL);
622 }
623
624 if (src->socketoptionc > 0) {
625 switch (op) {
626 case COPY:
627 DOCOPY(src,
628 srcoffset,
629 dst,
630 socketoptionv,
631 sizeof(*src->socketoptionv) * src->socketoptionc,
632 memfunc);
633 break;
634
635 case SIZE:
636 ADDLEN(sizeof(*src->socketoptionv) * src->socketoptionc,
637 &size);
638 break;
639 }
640 }
641
642 if (docopy) {
643 dst->oldshmemv = sockscf.oldshmemv; /* process-local. */
644 dst->stat = sockscf.stat; /* process-local. */
645 dst->state = sockscf.state; /* process-local. */
646 dst->child = sockscf.child; /* process-local. */
647 }
648
649 switch (op) {
650 case COPY:
651 DOLOGCOPY(src, srcoffset, dst, errlog, memfunc);
652 DOLOGCOPY(src, srcoffset, dst, log, memfunc);
653 break;
654
655 case SIZE: {
656 logtype_t *logv[] = { &src->errlog, &src->log };
657
658 for (i = 0; i < ELEMENTS(logv); ++i) {
659 if (logv[i]->filenoc > 0) {
660 size_t ii;
661
662 ADDLEN(sizeof((*logv[i]->fnamev)) * logv[i]->filenoc, &size);
663 ADDLEN(sizeof(*(logv[i]->createdv)) * logv[i]->filenoc, &size);
664 ADDLEN(sizeof(*(logv[i]->filenov)) * logv[i]->filenoc, &size);
665
666 for (ii = 0; ii < logv[i]->filenoc; ++ii)
667 ADDLEN(strlen(logv[i]->fnamev[ii]) + 1, &size);
668 }
669 }
670 break;
671 }
672 }
673
674 slog(LOG_DEBUG, "%s: extra bytes used due to alignment issues: %lu",
675 function, (unsigned long)_extra_due_alignment);
676
677 if (op == COPY) {
678 if (memleft_no_alignment_luck() == 0)
679 slog(LOG_DEBUG,
680 "%s: all allocated bytes used, as expected", function);
681 else
682 swarnx("%s: %lu byte%s of memory left in pool after copying to dst",
683 function,
684 (unsigned long)memleft_no_alignment_luck(),
685 memleft_no_alignment_luck() == 1 ? "" : "s");
686 }
687
688 if (dosize)
689 return size;
690 else
691 return 0;
692 }
693
694 size_t
compareconfigs(a,b)695 compareconfigs(a, b)
696 const struct config *a;
697 const struct config *b;
698 {
699 #define CHECKRESULT(rc, attr, size) \
700 do { \
701 if ((rc) != 0) { \
702 swarnx("%s: %lu byte%s compare on line %d says attribute \"%s\" is not " \
703 "identical in both config objects", \
704 function, \
705 (unsigned long)(size), \
706 size == 1 ? "" : "s", \
707 __LINE__, \
708 #attr); \
709 \
710 return 0; \
711 } \
712 \
713 compared += size; \
714 } while (/* CONSTCOND */ 0)
715
716 #define PTRCHECK(a, b, attr) \
717 do { \
718 if ((a->attr == NULL && b->attr != NULL) \
719 || (a->attr != NULL && b->attr == NULL)) { \
720 swarnx("%s: \"%s\"-attribute in objects are not the same. " \
721 "In \"%s\" \"%s\" is %s NULL pointer, while in \"%s\" it %s", \
722 function, \
723 #attr, \
724 #a, \
725 #attr, \
726 a->attr == NULL ? "a" : "is not a", \
727 #b, \
728 b->attr == NULL ? "is" : "is not"); \
729 \
730 return 0; \
731 } \
732 } while (/* CONSTCOND */ 0)
733
734 #define EQCHECK_PTR(a, b, attr, size) \
735 do { \
736 int rc; \
737 \
738 PTRCHECK((a), (b), attr); \
739 if ((a)->attr != NULL) { \
740 rc = memcmp((a)->attr, (b)->attr, (size)); \
741 CHECKRESULT(rc, attr, size); \
742 } \
743 } while (/* CONSTCOND */ 0)
744
745 #define EQCHECK(a, b, attr) \
746 do { \
747 size_t size; \
748 int rc; \
749 \
750 size = sizeof(a->attr); \
751 rc = memcmp(&a->attr, &b->attr, size); \
752 \
753 CHECKRESULT(rc, attr, size); \
754 \
755 } while (/* CONSTCOND */ 0)
756
757 #define LINKCHECK(lsrc, ldst, lattr) \
758 do { \
759 PTRCHECK(lsrc, ldst, lattr); \
760 if (lsrc->lattr != NULL) { \
761 linkedname_t *srclink = lsrc->lattr; \
762 linkedname_t *dstlink = ldst->lattr; \
763 \
764 do { \
765 EQCHECK_PTR(srclink, \
766 dstlink, \
767 name, \
768 strlen(srclink->name) + 1); \
769 PTRCHECK(srclink, dstlink, next); \
770 \
771 srclink = srclink->next; \
772 dstlink = dstlink->next; \
773 } while (srclink != NULL); \
774 } \
775 } while (/* CONSTCOND */ 0)
776
777 const char *function = "compareconfigs()";
778 const rule_t *arulev[] = { a->crule, a->hrule, a->srule },
779 *brulev[] = { b->crule, b->hrule, b->srule };
780 const logtype_t *alogv[] = { &a->errlog, &a->log },
781 *blogv[] = { &b->errlog, &b->log };
782 size_t i, compared = 0;
783
784 /*
785 * Check all pointers and structs, as that's where an error is likely
786 * to occur. Also check non-pointers where easy to do, though it should
787 * be almost impossible for an error to exists there due to the initial
788 * struct assignment between 'a' and 'b'.
789 */
790
791 EQCHECK(a, b, initial);
792
793 EQCHECK_PTR(a,
794 b,
795 internal.addrv,
796 sizeof(*a->internal.addrv) * a->internal.addrc);
797
798 EQCHECK_PTR(a,
799 b,
800 external.addrv,
801 sizeof(*a->external.addrv) * a->external.addrc);
802 EQCHECK(a, b, cpu);
803
804 PTRCHECK(a, b, crule);
805 PTRCHECK(a, b, hrule);
806 PTRCHECK(a, b, srule);
807 for (i = 0; i < ELEMENTS(arulev); ++i) {
808 const rule_t *arule = arulev[i], *brule = brulev[i];
809 rule_t tmprulea, tmpruleb;
810
811 if (arulev[i] == NULL)
812 continue;
813
814 SASSERTX(arule != NULL);
815 SASSERTX(brule != NULL);
816
817 do {
818 EQCHECK_PTR(arule,
819 brule,
820 socketoptionv,
821 sizeof(*arule->socketoptionv) * arule->socketoptionc);
822
823 EQCHECK(arule, brule, src);
824 EQCHECK(arule, brule, dst);
825 EQCHECK(arule, brule, rdr_from);
826 EQCHECK(arule, brule, rdr_to);
827 EQCHECK(arule, brule, hostidoption_isset);
828 #if HAVE_SOCKS_HOSTID
829 EQCHECK(arule, brule, hostid);
830 EQCHECK(arule, brule, hostindex);
831 #endif /* HAVE_SOCKS_HOSTID */
832
833 EQCHECK(arule, brule, log);
834 EQCHECK(arule, brule, number);
835 EQCHECK(arule, brule, linenumber);
836
837 /*
838 * mostly memory, but a few pointers too; just copy their address.
839 */
840
841 tmprulea = *arule;
842 tmpruleb = *brule;
843
844 #if HAVE_LDAP
845
846 tmprulea.state.ldapauthorisation.ldapurl
847 = tmpruleb.state.ldapauthorisation.ldapurl;
848
849 tmprulea.state.ldapauthorisation.ldapbasedn
850 = tmpruleb.state.ldapauthorisation.ldapbasedn;
851
852 tmprulea.state.ldapauthentication.ldapurl
853 = tmpruleb.state.ldapauthentication.ldapurl;
854
855 #endif /* HAVE_LDAP */
856
857 EQCHECK((&tmprulea), (&tmpruleb), state);
858
859 #if HAVE_LDAP
860
861 LINKCHECK(arule, brule, state.ldapauthorisation.ldapurl);
862 LINKCHECK(arule, brule, state.ldapauthorisation.ldapbasedn);
863
864 #endif /* HAVE_LDAP */
865
866 EQCHECK(arule, brule, timeout);
867 LINKCHECK(arule, brule, user);
868 LINKCHECK(arule, brule, group);
869
870 #if HAVE_LDAP
871
872 LINKCHECK(arule, brule, ldapgroup);
873 EQCHECK(arule, brule, ldapsettingsfromuser);
874
875 #endif /* HAVE_LDAP */
876
877 #if HAVE_LIBWRAP
878
879 EQCHECK(arule, brule, libwrap);
880
881 #endif /* HAVE_LIBWRAP */
882
883 EQCHECK(arule, brule, bw_shmid);
884 EQCHECK(arule, brule, mstats_shmid);
885 EQCHECK(arule, brule, ss_shmid);
886
887 PTRCHECK(arule, brule, next);
888 arule = arule->next;
889 brule = brule->next;
890 } while (arule != NULL);
891 }
892
893 EQCHECK(a, b, routeoptions);
894 PTRCHECK(a, b, route);
895 if (a->route != NULL) {
896 route_t *aroute = a->route,
897 *broute = b->route;
898
899 do {
900 EQCHECK(aroute, broute, number);
901 EQCHECK(aroute, broute, state);
902
903 EQCHECK(aroute, broute, socketoptionc);
904 EQCHECK_PTR(aroute,
905 broute,
906 socketoptionv,
907 sizeof(*aroute->socketoptionv) * aroute->socketoptionc);
908
909 EQCHECK(aroute, broute, src);
910 EQCHECK(aroute, broute, dst);
911 EQCHECK(aroute, broute, gw);
912 EQCHECK(aroute, broute, rdr_from);
913
914 PTRCHECK(aroute, broute, next);
915 aroute = aroute->next;
916 broute = broute->next;
917 } while (aroute != NULL);
918 }
919
920 if (a->monitor != NULL) {
921 monitor_t *amon = a->monitor, *bmon = b->monitor;
922
923 do {
924 EQCHECK(amon, bmon, number);
925 EQCHECK(amon, bmon, mstats_shmid);
926 EQCHECK(amon, bmon, src);
927 EQCHECK(amon, bmon, dst);
928
929 #if HAVE_SOCKS_HOSTID
930 EQCHECK(amon, bmon, hostid);
931 EQCHECK(amon, bmon, hostindex);
932 #endif /* HAVE_SOCKS_HOSTID */
933
934 PTRCHECK(amon, bmon, next);
935 amon = amon->next;
936 bmon = bmon->next;
937 } while (amon != NULL);
938 }
939
940
941 EQCHECK(a, b, socketoptionc);
942 EQCHECK_PTR(a,
943 b,
944 socketoptionv,
945 sizeof(*a->socketoptionv) * a->socketoptionc);
946
947 EQCHECK(a, b, compat);
948 EQCHECK(a, b, extension);
949
950 for (i = 0; i < ELEMENTS(alogv); ++i) {
951 const logtype_t *alog = alogv[i], *blog = blogv[i];
952
953 EQCHECK(alog, blog, type);
954
955 PTRCHECK(alog, blog, filenov);
956 PTRCHECK(alog, blog, createdv);
957
958 if (alog->fnamev != NULL) {
959 size_t ii;
960
961 for (ii = 0; ii < alog->filenoc; ++ii)
962 EQCHECK_PTR(alog,
963 blog,
964 fnamev[ii],
965 strlen(alog->fnamev[ii]) + 1);
966
967 SASSERTX(alog->filenov != NULL);
968 EQCHECK_PTR(alog,
969 blog,
970 filenov,
971 sizeof(*alog->filenov) * alog->filenoc);
972
973 SASSERTX(alog->createdv != NULL);
974 EQCHECK_PTR(alog,
975 blog,
976 createdv,
977 sizeof(*alog->createdv) * alog->filenoc);
978 }
979
980 PTRCHECK(alog, blog, fnamev);
981
982 EQCHECK(alog, blog, filenoc);
983 EQCHECK(alog, blog, facility);
984 EQCHECK(alog, blog, facilityname);
985 }
986
987 EQCHECK(a, b, srchost);
988
989 #if !HAVE_PRIVILEGES
990 EQCHECK(a, b, uid);
991 #endif /* !HAVE_PRIVILEGES */
992
993 EQCHECK(a, b, cmethodv);
994 EQCHECK(a, b, cmethodc);
995
996 EQCHECK(a, b, smethodv);
997 EQCHECK(a, b, smethodc);
998
999 EQCHECK(a, b, udpconnectdst);
1000
1001 /* hosts_{allow,deny}_old; set at startup only. */
1002
1003 return compared;
1004 }
1005
1006 static size_t
linkedsize(list)1007 linkedsize(list)
1008 const linkedname_t *list;
1009 {
1010 const char *function = "linkedsize()";
1011 size_t size = 0;
1012
1013 if (list == NULL)
1014 return 0;
1015
1016 size += sizeof(*list); /* first link it's up to caller to align. */
1017 ADDLEN(strlen(list->name) + 1 /* NUL */, &size);
1018 list = list->next;
1019
1020 while (list != NULL) {
1021 ADDLEN(sizeof(*list), &size);
1022 ADDLEN(strlen(list->name) + 1 /* NUL */, &size);
1023 list = list->next;
1024 }
1025
1026 return size;
1027 }
1028
1029 static void
poolinit(pool,size)1030 poolinit(pool, size)
1031 void *pool;
1032 const size_t size;
1033 {
1034 const char *function = "poolinit()";
1035
1036 /*
1037 * try to figure out what the strictest *pointer* alignment is so that
1038 * getmem() can return properly aligned data.
1039 */
1040 const void *_voidv[2];
1041 _mask = ~(((uintptr_t)&_voidv[1] - (uintptr_t)&_voidv[0]) - 1);
1042 _alignment = ((uintptr_t)&_voidv[1] - (uintptr_t)&_voidv[0]),
1043
1044 _nextstart = pool;
1045 _left = _left_no_alignment_luck = size;
1046
1047 slog(LOG_DEBUG,
1048 "%s: memorypoolsize is %lu, starting at address %p. "
1049 "Alignment is on %lu-byte boundary",
1050 function, (unsigned long)size, pool, (unsigned long)_alignment);
1051 }
1052
1053 void *
getmem(size)1054 getmem(size)
1055 const size_t size;
1056 {
1057 const char *function = "getmem()";
1058 void *start;
1059 size_t size_with_padding;
1060
1061
1062 /*
1063 * technically we could do with adding (_alignment - 1 bytes) and instead
1064 * a check for testing what the non-aligned address happens to be, since
1065 * it could happen to be aligned. That would prevent us from easily
1066 * checking that the amount of memory allocated and the memory we calculated
1067 * as the required amount is the same however, so ignore that minor
1068 * optimization.
1069 */
1070 start = (void *)(((uintptr_t)(_nextstart) + _alignment) & _mask);
1071 size_with_padding = ((uintptr_t)start - (uintptr_t)_nextstart) + size;
1072
1073 slog(LOG_DEBUG, "%s: size %lu (with padding: %lu)",
1074 function, (unsigned long)size, (unsigned long)size_with_padding);
1075
1076 if (_left < size_with_padding)
1077 return NULL;
1078
1079 _extra_due_alignment += size_with_padding - size;
1080 _left_no_alignment_luck -= size + _alignment;
1081
1082 _left -= size_with_padding;
1083 _nextstart = (void *)((uintptr_t)_nextstart + size_with_padding);
1084
1085 SASSERTX(((uintptr_t)start % _alignment) == 0);
1086 return start;
1087 }
1088
1089 void
doconfigtest(void)1090 doconfigtest(void)
1091 {
1092 const char *function = "doconfigtest()";
1093 static struct config *shmem;
1094 size_t size, pointedto, mempointedto;
1095 struct config *mem;
1096
1097 slog(LOG_DEBUG,
1098 "%s: doing test with memory preallocated for pointercontents",
1099 function);
1100
1101 pointedto = pointer_size(&sockscf);
1102 slog(LOG_DEBUG, "%s: size of config: %lu, pointed to size: %lu",
1103 function, (unsigned long)sizeof(sockscf), (unsigned long)pointedto);
1104
1105 size = sizeof(sockscf) + pointedto;
1106 if ((shmem = malloc(size)) == NULL)
1107 serrx("%s: could not malloc(3) %lu bytes", function, (unsigned long)size);
1108
1109
1110 /*
1111 * Shallow copy what we can.
1112 */
1113 *shmem = sockscf;
1114
1115 /*
1116 * Then do a deep copy of the rest.
1117 */
1118 if (pointer_copy(&sockscf,
1119 0x0,
1120 shmem,
1121 (char *)shmem + sizeof(sockscf),
1122 size - sizeof(sockscf)) == 0)
1123 slog(LOG_DEBUG, "%s: pointer_copy() successful", function);
1124 else
1125 serr("%s: pointer_copy() failed", function);
1126
1127 if ((size = compareconfigs(&sockscf, shmem)) == 0)
1128 swarnx("%s: created config not identical to original config", function);
1129 else
1130 slog(LOG_DEBUG,
1131 "%s: created config identical to original, %lu bytes compared",
1132 function, (unsigned long)size);
1133
1134 /*
1135 * Try to copy again, this time from memory we copied to.
1136 */
1137
1138 slog(LOG_DEBUG, "%s: doing test #2 with memory preallocated for pointers",
1139 function);
1140
1141 mempointedto = pointer_size(shmem);
1142
1143 if (mempointedto != pointedto) {
1144 swarnx("%s: memory pointed to by shmem is %lu, but expected %lu",
1145 function, (unsigned long)mempointedto, (unsigned long)pointedto);
1146
1147 free(shmem);
1148 return;
1149 }
1150
1151 size = sizeof(sockscf) + mempointedto;
1152 if ((mem = malloc(size)) == NULL)
1153 serrx("%s: could not malloc(3) %lu bytes", function, (unsigned long)size);
1154
1155
1156 /*
1157 * Shallow copy what we can.
1158 */
1159 *mem = *shmem;
1160
1161 /*
1162 * Then do a deep copy of the rest.
1163 */
1164 if (pointer_copy(shmem,
1165 0x0,
1166 mem,
1167 (char *)mem + sizeof(sockscf),
1168 size - sizeof(sockscf)) == 0)
1169 slog(LOG_DEBUG, "%s: pointer_copy() successful", function);
1170 else
1171 serr("%s: pointer_copy() failed", function);
1172
1173 if ((size = compareconfigs(shmem, mem)) == 0)
1174 swarnx("%s: created config not identical to original config", function);
1175 else
1176 slog(LOG_DEBUG,
1177 "%s: created config is identical to original. %lu bytes compared",
1178 function, (unsigned long)size);
1179
1180 free(shmem);
1181 free(mem);
1182
1183 /*
1184 * test without preallocating memory for pointercontents.
1185 */
1186
1187 slog(LOG_DEBUG,
1188 "%s: doing test *without* memory preallocated for pointercontents",
1189 function);
1190
1191 size = sizeof(sockscf);
1192 if ((shmem = malloc(size)) == NULL)
1193 serrx("%s: could not malloc(3) %lu bytes", function, (unsigned long)size);
1194
1195
1196 /*
1197 * Shallow copy what we can.
1198 */
1199 *shmem = sockscf;
1200
1201 /*
1202 * Then do a deep copy of the rest.
1203 */
1204 if (pointer_copy(&sockscf,
1205 0x0,
1206 shmem,
1207 NULL,
1208 0) == 0)
1209 slog(LOG_DEBUG, "%s: pointer_copy() successful", function);
1210 else
1211 serr("%s: pointer_copy() failed", function);
1212
1213 if ((size = compareconfigs(&sockscf, shmem)) == 0)
1214 swarnx("%s: created config not identical to original config", function);
1215 else
1216 slog(LOG_DEBUG,
1217 "%s: created config is identical to original. %lu bytes compared",
1218 function, (unsigned long)size);
1219
1220 /* needs to be handled specially. */
1221 sockd_freelogobject(&shmem->log, 0 /* just test. */);
1222 sockd_freelogobject(&shmem->errlog, 0 /* just test. */);
1223
1224 /* free(shmem). Should free shmem->pointers too, but can not. */
1225 }
1226
1227 #if 0
1228 static size_t
1229 memleft(void)
1230 {
1231 return _left;
1232 }
1233 #endif
1234
1235 static size_t
memleft_no_alignment_luck(void)1236 memleft_no_alignment_luck(void)
1237 {
1238 return _left_no_alignment_luck;
1239 }
1240