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