home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / named / ns_req.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-30  |  32.0 KB  |  1,353 lines

  1. /*
  2.  * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
  3.  * 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. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)ns_req.c    4.47 (Berkeley) 7/1/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/uio.h>
  40. #include <sys/time.h>
  41. #include <sys/file.h>
  42. #include <sys/socket.h>
  43. #include <netinet/in.h>
  44. #include <syslog.h>
  45. #include <arpa/nameser.h>
  46. #include <resolv.h>
  47. #include <stdio.h>
  48. #include "ns.h"
  49. #include "db.h"
  50.  
  51. #define NADDRECS    20
  52.  
  53. extern    int    debug;
  54. extern    FILE    *ddt;
  55.  
  56. struct addinfo {
  57.     char    *a_dname;        /* domain name */
  58.     u_short    a_class;        /* class for address */
  59. };
  60.  
  61. struct    addinfo addinfo[NADDRECS];    /* additional info records */
  62. int    addcount;            /* number of names in addinfo */
  63. int    xfr_disabled = 0;        /* set to disable zone xfrs */
  64. int    needs_prime_cache = 0;        /* set if we need a priming */
  65.  
  66. u_char    *dnptrs[20];        /* ptrs to dnames in message for dn_comp */
  67.  
  68. extern time_t retrytime();
  69. extern struct qinfo *sysquery();
  70. extern char *localdomain;    /* XXX */
  71. extern int errno;
  72. /*
  73.  * Process request using database; assemble and send response.
  74.  */
  75. ns_req(msg, msglen, buflen, qsp, from, dfd)
  76.     u_char *msg;
  77.     int msglen, buflen;
  78.     struct qstream *qsp;
  79.     struct sockaddr_in *from;
  80.     int dfd;
  81. {
  82.     register HEADER *hp;
  83.     register u_char *cp;
  84.     struct namebuf *np;
  85.     register struct databuf *dp;
  86.     struct hashbuf *htp;
  87.     struct netinfo *lp;
  88.     char *fname, *answers;
  89.     u_char *eom, *omsg;
  90.     char dnbuf[MAXDNAME], *dname;
  91.     u_char **dpp;
  92.     int n, class, type, count, foundname, founddata, omsglen, cname = 0;
  93.     u_short id;
  94.     struct databuf *nsp[NSMAX];
  95.     struct qinfo *qp;
  96.     extern struct qinfo *qhead;
  97.     extern struct netinfo *local();
  98.     extern int nsid;
  99.  
  100. #ifdef DEBUG
  101.     if (debug > 3) {
  102.         fprintf(ddt,"ns_req()\n");
  103.         fp_query((char *)msg, ddt);
  104.     }
  105. #endif
  106.  
  107.     hp = (HEADER *) msg;
  108.     if (hp->qr) {
  109.         ns_resp(msg, msglen);
  110.  
  111.         /* Now is a safe time for housekeeping */
  112.         if (needs_prime_cache)
  113.             prime_cache();
  114.         return;
  115.     }
  116.  
  117.     hp->rcode = NOERROR;
  118.     cp = msg + sizeof(HEADER);
  119.     eom = msg + msglen;
  120.     dpp = dnptrs;
  121.     *dpp++ = msg;
  122.     addcount = 0;
  123.  
  124.     switch (hp->opcode) {
  125.     case QUERY:
  126. #ifdef STATS
  127.         stats[S_QUERIES].cnt++;
  128. #endif
  129.         if (ntohs(hp->qdcount) != 1 ||
  130.             hp->ancount || hp->nscount || hp->arcount) {
  131. #ifdef DEBUG
  132.             if (debug)
  133.                 fprintf(ddt,"FORMERR Query header counts wrong\n");
  134. #endif
  135.             hp->qdcount = 0;
  136.             hp->ancount = 0;
  137.             hp->nscount = 0;
  138.             hp->arcount = 0;
  139.             hp->rcode = FORMERR;
  140.             goto finish;
  141.         }
  142.         /*
  143.          * Get domain name, class, and type.
  144.          */
  145.         if ((*cp & INDIR_MASK) == 0)
  146.             *dpp++ = cp;    /* remember name for compression */
  147.         *dpp = NULL;
  148.         if ((n = dn_expand(msg, eom, cp, (u_char *)dnbuf,
  149.             sizeof(dnbuf))) < 0) {
  150. #ifdef DEBUG
  151.             if (debug)
  152.                 fprintf(ddt,"FORMERR Query expand name failed\n");
  153. #endif
  154.             hp->rcode = FORMERR;
  155.             goto finish;
  156.         }
  157.         cp += n;
  158.         GETSHORT(type, cp);
  159.         GETSHORT(class, cp);
  160.         if (cp > eom) {
  161. #ifdef DEBUG
  162.             if (debug)
  163.                 fprintf(ddt,"FORMERR Query message length short\n");
  164. #endif
  165.             hp->rcode = FORMERR;
  166.             goto finish;
  167.         }
  168. #ifdef DEBUG
  169.         if (cp < eom)
  170.             if (debug > 5)
  171.                 fprintf(ddt,"message length > received message\n");
  172. #endif
  173.  
  174. #ifdef STATS
  175.         if ((type > T_ANY) || (type < 0))
  176.             typestats[0]++;    /* Bad type */
  177.         else
  178.             typestats[type]++;
  179. #endif
  180.         /*
  181.          * Process query.
  182.          */
  183.         if (type == T_AXFR) {
  184.             /* refuse request if not a TCP connection */
  185.             if (qsp == QSTREAM_NULL || xfr_disabled) {
  186. #ifdef DEBUG
  187.                 if (debug)
  188.                     fprintf(ddt,"T_AXFR via UDP refused\n");
  189. #endif
  190.                 hp->rcode = REFUSED;
  191.                 goto finish;
  192.             }
  193.             dnptrs[0] = NULL;    /* don't compress names */
  194.             hp->rd = 0;        /* recursion not possible */
  195.         }
  196.         buflen -= msglen;
  197.         count = 0;
  198.         foundname = 0;
  199.         founddata = 0;
  200.         dname = dnbuf;
  201. try_again:
  202. #ifdef DEBUG
  203.         if (debug)
  204.             fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",
  205.                 dname, hp->id, type);
  206. #endif
  207.         htp = hashtab;        /* lookup relative to root */
  208.         if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
  209.             fname = "";
  210. #ifdef DEBUG
  211.         if (debug)
  212.             fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n",
  213.                 np == NULL ? "missed" : "found",
  214.                 dname, fname, cname);
  215. #endif
  216.         /* START XXX */
  217.         /*
  218.          * if nlookup failed to find address then
  219.          *  see if there are any '.''s in the name
  220.          * if not then add local domain name to the
  221.          * name and try again.
  222.          */
  223.         if (np == NULL && localdomain && index(dname, '.') == NULL) {
  224.             (void) strcat(dname,".");
  225.             (void) strcat(dname, localdomain);
  226. #ifdef DEBUG
  227.             if (debug)
  228.                 fprintf(ddt,"req: nlookup(%s) type=%d\n",
  229.                     dname, type);
  230. #endif
  231.             htp = hashtab;
  232.             np = nlookup(dname, &htp, &fname, 0);
  233.             }
  234.         /* END XXX */
  235.         if (np == NULL || fname != dname)
  236.             goto fetchns;
  237.  
  238.         foundname++;
  239.         answers = (char *)cp;
  240.         count = cp - msg;
  241.         n = finddata(np, class, type, hp, &dname, &buflen, &count);
  242.         if (n == 0)
  243.             goto fetchns;        /* NO data available */
  244.         cp += n;
  245.         buflen -= n;
  246.         msglen += n;
  247.         hp->ancount += count;
  248.         if (fname != dname && type != T_CNAME && type != T_ANY) {
  249.             if (cname++ >= MAXCNAMES) {
  250. #ifdef DEBUG
  251.                 if (debug >= 3)
  252.                     fprintf(ddt,
  253.                     "resp: leaving, MAXCNAMES exceeded\n");
  254. #endif
  255.                 hp->rcode = SERVFAIL;
  256.                 goto finish;
  257.             }
  258.             goto try_again;
  259.         }
  260.         founddata = 1;
  261. #ifdef DEBUG
  262.         if (debug >= 3) {
  263.             fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);
  264.             fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);
  265.         }
  266. #endif
  267.         if ((lp = local(from)) != NULL) 
  268.             sort_response(answers, count, lp, cp);
  269.         if (type == T_AXFR) {
  270.             if (founddata) {
  271.                 hp->ancount = htons(hp->ancount);
  272.                 startxfr(qsp, np, msg, cp - msg);
  273.                 return;
  274.             }
  275.             hp->rcode = REFUSED;    /* No go if unauthoritative */
  276.             goto finish;
  277.         }
  278. #ifdef notdef
  279.         /*
  280.          * If we found an authoritative answer,
  281.          * we're done.
  282.          */
  283.         if (hp->aa)
  284.             goto finish;
  285. #endif
  286.  
  287. fetchns:
  288.         /*
  289.           * Look for name servers to refer to and fill in the authority
  290.           * section or record the address for forwarding the query
  291.           * (recursion desired).
  292.           */
  293.         nsp[0] = NULL;
  294.         switch (findns(&np, class, nsp, &count)) {
  295.         case NXDOMAIN:
  296.             if (!foundname)
  297.                 hp->rcode = NXDOMAIN;
  298. #ifdef DEBUG
  299.             if (debug >= 3)
  300.                 fprintf(ddt,"req: leaving (%s, rcode %d)\n",
  301.                     dname, hp->rcode);
  302. #endif
  303.             if (class != C_ANY) {
  304.                 hp->aa = 1;
  305.                 /* XXX
  306.                  * should return SOA if founddata == 0,
  307.                  * but old named's are confused by an SOA
  308.                  * in the auth. section if there's no error.
  309.                  */
  310.                 if (foundname == 0 && np) {
  311.                     n = doaddauth(hp, cp, buflen, np, nsp[0]);
  312.                     cp += n;
  313.                     buflen -= n;
  314.                 }
  315.             }
  316.             goto finish;
  317.  
  318.         case SERVFAIL:
  319.             if (!founddata) {
  320.                 hp->rcode = SERVFAIL;
  321.                 goto finish;
  322.             }
  323.         }
  324.  
  325.         /*
  326.          *  If we successfully found the answer in the cache
  327.          *  or this is not a recursive query, then add the
  328.          *  nameserver references here and return.
  329.          */
  330.         if (founddata || (!hp->rd)) {
  331.             n = add_data(np, nsp, cp, buflen);
  332.             if (n < 0) {
  333.                 hp->tc = 1;
  334.                 n = (-n);
  335.             }
  336.             cp += n;
  337.             buflen -= n;
  338.             hp->nscount = htons((u_short)count);
  339.             goto finish;
  340.         }
  341.  
  342.         /*
  343.          *  At this point, we don't have the answer, but we do
  344.          *  have some NS's to try.  If the user would like us
  345.          *  to recurse, create the initial query.  If a cname
  346.          *  is involved, we need to build a new query and save
  347.          *  the old one in cmsg/cmsglen.
  348.          */
  349.         if (cname) {
  350.             omsg = (u_char *)malloc((unsigned)msglen);
  351.             if (omsg == (u_char *)NULL) {
  352. #ifdef DEBUG
  353.                 if (debug)
  354.                         fprintf(ddt,"ns_req: malloc fail\n");
  355. #endif
  356.                 syslog(LOG_ERR, "ns_req: Out Of Memory");
  357.                 hp->rcode = SERVFAIL;
  358.                 break;
  359.             }
  360.             id = hp->id;
  361.             hp->ancount = htons(hp->ancount);
  362.             bcopy(msg, omsg, omsglen = msglen);
  363.             msglen = res_mkquery(QUERY, dname, class, type,
  364.                 (char *)NULL, 0, NULL, (char *)msg,
  365.                 msglen+buflen);
  366.         }
  367.         n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp);
  368.         if (n != FW_OK && cname)
  369.             free(omsg);
  370.         switch (n) {
  371.         case FW_OK:
  372.             if (cname) {
  373.                 qp->q_cname = cname;
  374.                 qp->q_cmsg = (char *)omsg;
  375.                 qp->q_cmsglen = omsglen;
  376.                 qp->q_id = id;
  377.             }
  378.             break;
  379.         case FW_DUP:
  380.             break;        /* Duplicate request dropped */
  381.         case FW_NOSERVER:
  382.             if(np)
  383.                 np = np->n_parent;
  384.             goto fetchns;    /* Try again. */
  385.         case FW_SERVFAIL:
  386.             hp->rcode = SERVFAIL;
  387.             goto finish;
  388.         }
  389.         /* Now is a safe time for housekeeping */
  390.         if (needs_prime_cache)
  391.             prime_cache();
  392.         return;
  393.  
  394.     case IQUERY: {
  395.         register struct invbuf *ip;
  396.         register int i;
  397.         int dlen, alen;
  398.         char anbuf[PACKETSZ], *data;
  399.  
  400. #ifdef STATS
  401.         stats[S_IQUERIES].cnt++;
  402. #endif
  403.         hp->ancount = htons(hp->ancount);
  404.         if (hp->ancount != 1 ||
  405.             hp->qdcount || hp->nscount || hp->arcount) {
  406. #ifdef DEBUG
  407.             if (debug)
  408.                 fprintf(ddt,"FORMERR IQuery header counts wrong\n");
  409. #endif
  410.             hp->qdcount = 0;
  411.             hp->ancount = 0;
  412.             hp->nscount = 0;
  413.             hp->arcount = 0;
  414.             hp->rcode = FORMERR;
  415.             goto finish;
  416.         }
  417.         /*
  418.          * Skip domain name, get class, and type.
  419.          */
  420.         if ((n = dn_skipname(cp, eom)) < 0) {
  421. #ifdef DEBUG
  422.             if (debug)
  423.                 fprintf(ddt,"FORMERR IQuery packet name problem\n");
  424. #endif
  425.             hp->rcode = FORMERR;
  426.             goto finish;
  427.         }
  428.         cp += n;
  429.         GETSHORT(type, cp);
  430.         GETSHORT(class, cp);
  431.         cp += sizeof(u_long);
  432.         GETSHORT(dlen, cp);
  433.         cp += dlen;
  434.         if (cp != eom) {
  435. #ifdef DEBUG
  436.             if (debug)
  437.                 fprintf(ddt,"FORMERR IQuery message length off\n");
  438. #endif
  439.             hp->rcode = FORMERR;
  440.             goto finish;
  441.         }
  442.         /* not all inverse queries are handled. */
  443.         switch (type) {
  444.         case T_A:
  445.         case T_UID:
  446.         case T_GID:
  447.             break;
  448.  
  449.         default:
  450.             hp->rcode = REFUSED;
  451.             goto finish;
  452.         }
  453. #ifdef DEBUG
  454.         if (debug)
  455.             fprintf(ddt,"req: IQuery class %d type %d\n",
  456.                 class, type);
  457. #endif
  458.         fname = (char *)msg + sizeof(HEADER);
  459.         bcopy(fname, anbuf, alen = (char *)cp - fname);
  460.         data = anbuf + alen - dlen;
  461.         cp = (u_char *)fname;
  462.         buflen -= sizeof(HEADER);
  463.         count = 0;
  464.         for (ip = invtab[dhash(data, dlen)]; ip != NULL;
  465.             ip = ip->i_next) {
  466.             for (i = 0; i < INVBLKSZ; i++) {
  467.             if ((np = ip->i_dname[i]) == NULL)
  468.                 break;
  469. #ifdef DEBUG
  470.             if (debug >= 5)
  471.                 fprintf(ddt,"dname = %d\n", np->n_dname);
  472. #endif
  473.             for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  474.                 if (!match(dp, class, type))
  475.                     continue;
  476.                 if (dp->d_size != dlen ||
  477.                     bcmp(dp->d_data, data, dlen))
  478.                     continue;
  479.                 getname(np, dnbuf, sizeof(dnbuf));
  480. #ifdef DEBUG
  481.                 if (debug > 2)
  482.                     fprintf(ddt,"req: IQuery found %s\n",
  483.                         dnbuf);
  484. #endif
  485.                 buflen -= QFIXEDSZ;
  486.                 if ((n = dn_comp((u_char *)dnbuf, cp, buflen,
  487.                     (u_char **)NULL, (u_char **)NULL)) < 0)
  488.                 {
  489.                     hp->tc = 1;
  490.                     goto finish;
  491.                 }
  492.                 cp += n;
  493.                 PUTSHORT((u_short)dp->d_type, cp);
  494.                 PUTSHORT((u_short)dp->d_class, cp);
  495.                 buflen -= n;
  496.                 count++;
  497.             }
  498.             }
  499.         }
  500. #ifdef DEBUG
  501.         if (debug)
  502.             fprintf(ddt,"req: IQuery %d records\n", count);
  503. #endif
  504.         hp->qdcount = htons((u_short)count);
  505.         if (alen > buflen) {
  506.             hp->tc = 1;
  507.             break;
  508.         }
  509.         bcopy(anbuf, cp, alen);
  510.         cp += alen;
  511.         break;
  512.         }
  513.  
  514. #ifdef ALLOW_UPDATES
  515. /*
  516.  * In a sense the following constant should be defined in <arpa/nameser.h>,
  517.  * since it is returned here in place of a response code if the update was
  518.  * forwarded, and the response codes are defined in nameser.h.  On the other
  519.  * hand, though, this constant is only seen in this file.  The assumption
  520.  * here is that none of the other return codes equals this one (a good
  521.  * assumption, since they only occupy 4 bits over-the-wire)
  522.  */
  523. #define FORWARDED 1000
  524.         /* Call InitDynUpdate for all dynamic update requests */
  525.         case UPDATEM:
  526.         case UPDATEMA:
  527.         case UPDATED:
  528.         case UPDATEDA:
  529.         case UPDATEA:
  530.                 n = InitDynUpdate(hp, nsp, msg, msglen, cp, from, qsp, dfd);
  531.                 if (n == FORWARDED)
  532.                         return; /* Return directly because InitDynUpdate
  533.                                  * forwarded the query to the primary, so we
  534.                                  * will send response later
  535.                                  */
  536.                 else
  537.                         break;  /* Either sucessful primary update or failure;
  538.                                  * return response code to client
  539.                                  */
  540. #endif ALLOW_UPDATES
  541.  
  542.     case ZONEREF:
  543. #ifdef DEBUG
  544.         if (debug)
  545.             fprintf(ddt,"Refresh Zone\n");
  546. #endif
  547.  
  548.     default:
  549. #ifdef DEBUG
  550.         if (debug >= 2)
  551.             fprintf(ddt,"Opcode %d not implemented\n", hp->opcode);
  552. #endif
  553.         hp->qdcount = 0;
  554.         hp->ancount = 0;
  555.         hp->nscount = 0;
  556.         hp->arcount = 0;
  557.         hp->rcode = NOTIMP;
  558.     }
  559. finish:
  560. #ifdef STATS
  561.     switch(hp->rcode) {
  562.     case NOERROR:
  563.         stats[S_RESPOK].cnt++;
  564.         break;
  565.     case FORMERR:
  566.         stats[S_RESPFORMERR].cnt++;
  567.         break;
  568.     default:
  569.         stats[S_RESPFAIL].cnt++;
  570.         break;
  571.     }
  572. #endif
  573.     hp->qr = 1;        /* set Response flag */
  574.     hp->ra = 1;        /* Recursion is Available */
  575.     hp->ancount = htons(hp->ancount);
  576.     if (addcount) {
  577.         n = doaddinfo(hp, cp, buflen);
  578.         cp += n;
  579.         buflen -= n;
  580.     }
  581.  
  582. #ifdef DEBUG
  583.     if (debug) {
  584.         fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n",
  585.             inet_ntoa(from->sin_addr), 
  586.         qsp == QSTREAM_NULL ? dfd : qsp->s_rfd, 
  587.         ntohs(from->sin_port),
  588.         ntohs(hp->id), local(from) == NULL ? "Remote" : "Local");
  589.     }
  590.     if (debug >= 10)
  591.         fp_query((char *)msg, ddt);
  592. #endif DEBUG
  593.     if (qsp == QSTREAM_NULL) {
  594.         if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from,
  595.             sizeof(*from))< 0){
  596. #ifdef DEBUG
  597.             if (debug)
  598.                 fprintf(ddt,"error returning msg errno=%d\n",errno);
  599. #endif DEBUG
  600.         }
  601. #ifdef STATS
  602.         stats[S_OUTPKTS].cnt++;
  603. #endif
  604.     } else {
  605.         (void) writemsg(qsp->s_rfd, msg, cp - msg);
  606.         sq_done(qsp);
  607.     }
  608.     if (needs_prime_cache)
  609.         prime_cache();    /* Now is a safe time */
  610. }
  611.  
  612. fwritemsg(rfp, msg, msglen)
  613.     FILE *rfp;
  614.     char *msg;
  615.     int msglen;
  616. {
  617.     u_short len = htons((u_short)msglen);
  618.  
  619.     if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 ||
  620.         fwrite(msg, msglen, 1, rfp) != 1) {
  621. #ifdef DEBUG
  622.         if (debug)
  623.             fprintf(ddt,"fwrite failed %d\n", errno);
  624. #endif
  625.     }
  626.     return;
  627. }
  628.  
  629. writemsg(rfd, msg, msglen)
  630.     int rfd;
  631.     char *msg;
  632.     int msglen;
  633. {
  634.     struct iovec iov[2];
  635.     u_short len = htons((u_short)msglen);
  636.  
  637.     iov[0].iov_base = (caddr_t)&len;
  638.     iov[0].iov_len = sizeof(len);
  639.     iov[1].iov_base = msg;
  640.     iov[1].iov_len = msglen;
  641.     if (writev(rfd, iov, 2) != sizeof(len) + msglen) {
  642. #ifdef DEBUG
  643.         if (debug)
  644.             fprintf(ddt,"write failed %d\n", errno);
  645. #endif
  646.         return (-1);
  647.     }
  648.     return (0);
  649. }
  650.  
  651. /*
  652.  *  Test a datum for validity and return non-zero if it is out of date.
  653.  */
  654. stale(dp)
  655. register struct databuf *dp;
  656. {
  657.     register struct zoneinfo *zp = &zones[dp->d_zone];
  658.  
  659.     switch (zp->z_type) {
  660.  
  661.     case Z_PRIMARY:
  662.         return (0);
  663.  
  664.     case Z_SECONDARY:
  665.         /*
  666.          * Check to see whether a secondary zone
  667.          * has expired; if so clear authority flag
  668.          * for zone and return true.  If lastupdate
  669.          * is in the future, assume zone is up-to-date.
  670.          */
  671.         if ((long)(tt.tv_sec - zp->z_lastupdate) > (long)zp->z_expire) {
  672. #ifdef DEBUG
  673.             if (debug)
  674.                 fprintf(ddt,
  675.                     "stale: secondary zone %s expired\n",
  676.                     zp->z_origin);
  677. #endif
  678.             syslog(LOG_ERR, "secondary zone \"%s\" expired\n",
  679.                 zp->z_origin);
  680.             zp->z_auth = 0;
  681.             return (1);
  682.         }
  683.         return (0);
  684.  
  685.     case Z_CACHE:
  686. #ifdef DEBUG
  687.         if (debug >= 3)
  688.             fprintf(ddt,"stale: ttl %d %d (x%x)\n",
  689.                 dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags);
  690. #endif
  691.         if (dp->d_flags & DB_F_HINT)
  692.             return(0);
  693.         return(dp->d_ttl < tt.tv_sec);
  694.  
  695.     }
  696.     /* NOTREACHED */
  697. }
  698.  
  699. /*
  700.  * Copy databuf into a resource record for replies.
  701.  * Return size of RR if OK, -1 if buffer is full.
  702.  */
  703. make_rr(name, dp, buf, buflen, doadd)
  704.     char *name;
  705.     register struct databuf *dp;
  706.     char *buf;
  707.     int buflen, doadd;
  708. {
  709.     register char *cp;
  710.     char *cp1, *sp;
  711.     struct zoneinfo *zp;
  712.     register long n;
  713.     register long ttl;
  714.     u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
  715.  
  716. #ifdef DEBUG
  717.     if (debug >= 5)
  718.         fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n",
  719.             name, dp, buf,
  720.             buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl);
  721. #endif
  722.  
  723.     zp = &zones[dp->d_zone];
  724.     /* check for outdated RR before updating dnptrs by dn_comp() (???) */
  725.     if (zp->z_type == Z_CACHE) {
  726.         ttl = dp->d_ttl - (u_long) tt.tv_sec;
  727.         if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
  728. #ifdef DEBUG
  729. /*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %d=>0, x%x\n", ttl, dp->d_flags);
  730. #endif
  731.             ttl = 0;
  732.         }
  733.     } else {
  734.         if (dp->d_ttl)
  735.             ttl = dp->d_ttl;
  736.         else
  737.             ttl = zp->z_minimum;        /* really default */
  738. #ifdef notdef /* don't decrease ttl based on time since verification */
  739.         if (zp->z_type == Z_SECONDARY) {
  740.             /*
  741.              * Set ttl to value received from primary,
  742.              * less time since we verified it (but never
  743.              * less than a small positive value).
  744.              */
  745.             ttl -= tt.tv_sec - zp->z_lastupdate;
  746.             if (ttl <= 0)
  747.                 ttl = 120;
  748.         }
  749. #endif
  750.     }
  751.  
  752.     buflen -= RRFIXEDSZ;
  753.     if ((n = dn_comp((u_char *)name, (u_char *)buf, buflen,
  754.         (u_char **)dnptrs, (u_char **)edp)) < 0)
  755.         return (-1);
  756.     cp = buf + n;
  757.     buflen -= n;
  758.     PUTSHORT((u_short)dp->d_type, cp);
  759.     PUTSHORT((u_short)dp->d_class, cp);
  760.     PUTLONG(ttl, cp);
  761.     sp = cp;
  762.     cp += sizeof(u_short);
  763.     switch (dp->d_type) {
  764.     case T_CNAME:
  765.     case T_MG:
  766.     case T_MR:
  767.     case T_PTR:
  768.         if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen,
  769.             (u_char **)dnptrs, (u_char **)edp)) < 0)
  770.             return (-1);
  771.         PUTSHORT((u_short)n, sp);
  772.         cp += n;
  773.         break;
  774.  
  775.     case T_MB:
  776.     case T_NS:
  777.         /* Store domain name in answer */
  778.         if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen,
  779.             (u_char **)dnptrs, (u_char **)edp)) < 0)
  780.             return (-1);
  781.         PUTSHORT((u_short)n, sp);
  782.         cp += n;
  783.         if (doadd)
  784.             addname(dp->d_data, dp->d_class);
  785.         break;
  786.  
  787.     case T_SOA:
  788.     case T_MINFO:
  789.         cp1 = dp->d_data;
  790.         if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
  791.             (u_char **)dnptrs, (u_char **)edp)) < 0)
  792.             return (-1);
  793.         cp += n;
  794.         buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long);
  795.         cp1 += strlen(cp1) + 1;
  796.         if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
  797.             (u_char **)dnptrs, (u_char **)edp)) < 0)
  798.             return (-1);
  799.         cp += n;
  800.         if (dp->d_type == T_SOA) {
  801.             cp1 += strlen(cp1) + 1;
  802.             bcopy(cp1, cp,
  803.                (int)(n = dp->d_size - (cp1 - dp->d_data)));
  804.             cp += n;
  805.         }
  806.         n = (u_short)(cp - sp) - sizeof(u_short);
  807.         PUTSHORT((u_short)n, sp);
  808.         break;
  809.  
  810.     case T_MX:
  811.         /* cp1 == our data/ cp == data of RR */
  812.         cp1 = dp->d_data;
  813.  
  814.          /* copy preference */
  815.          bcopy(cp1,cp,sizeof(u_short));
  816.          cp += sizeof(u_short);
  817.          cp1 += sizeof(u_short);
  818.          buflen -= sizeof(u_short);
  819.  
  820.           if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
  821.             (u_char **)dnptrs, (u_char **)edp)) < 0)
  822.               return(-1);
  823.           cp += n;
  824.  
  825.           /* save data length */
  826.           n = (u_short)(cp - sp) - sizeof(u_short);
  827.           PUTSHORT((u_short)n, sp);
  828.         if (doadd)
  829.             addname(cp1, dp->d_class);
  830.         break;
  831.  
  832.     default:
  833.         if (dp->d_size > buflen)
  834.             return (-1);
  835.         bcopy(dp->d_data, cp, dp->d_size);
  836.         PUTSHORT((u_short)dp->d_size, sp);
  837.         cp += dp->d_size;
  838.     }
  839.     return (cp - buf);
  840. }
  841.  
  842. addname(name, class)
  843. register char    *name;
  844. short    class;
  845. {
  846.     register struct addinfo *ap;
  847.     register int n;
  848.  
  849.     for (ap = addinfo, n = addcount; --n >= 0; ap++)
  850.         if (strcasecmp(ap->a_dname, name) == 0)
  851.             return;
  852.     /* add domain name to additional section */
  853.     if (addcount < NADDRECS) {
  854.         addcount++;
  855.         ap->a_dname = name;
  856.         ap->a_class = class;
  857.     }
  858. }
  859.  
  860. /*
  861.  * Lookup addresses for names in addinfo and put into the message's
  862.  * additional section.
  863.  */
  864. doaddinfo(hp, msg, msglen)
  865.     HEADER *hp;
  866.     char *msg;
  867.     int msglen;
  868. {
  869.     register struct namebuf *np;
  870.     register struct databuf *dp;
  871.     register struct addinfo *ap;
  872.     register char *cp;
  873.     struct hashbuf *htp;
  874.     char *fname;
  875.     int n, count, foundstale;
  876.  
  877. #ifdef DEBUG
  878.     if (debug >= 3)
  879.         fprintf(ddt,"doaddinfo() addcount = %d\n", addcount);
  880. #endif
  881.  
  882.     count = 0;
  883.     cp = msg;
  884.     for (ap = addinfo; --addcount >= 0; ap++) {
  885. #ifdef DEBUG
  886.         if (debug >= 3)
  887.             fprintf(ddt,"do additional '%s'\n", ap->a_dname);
  888. #endif
  889.         htp = hashtab;    /* because "nlookup" stomps on arg. */
  890.         np = nlookup(ap->a_dname, &htp, &fname, 0);
  891.         if (np == NULL || fname != ap->a_dname)
  892.             continue;
  893. #ifdef DEBUG
  894.         if (debug >= 3)
  895.             fprintf(ddt,"found it\n");
  896. #endif
  897.         foundstale = 0;
  898.         /* look for the data */
  899.         for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  900.             if (!match(dp, (int)ap->a_class, T_A))
  901.                 continue;
  902.             if (stale(dp)) {
  903.                 foundstale++;
  904. #ifdef DEBUG
  905.                 if (debug)
  906.                     fprintf(ddt,"doaddinfo: stale entry '%s'%s\n",
  907.                         np->n_dname,
  908.                         (dp->d_flags&DB_F_HINT) ? " hint":"" );
  909. #endif
  910.                 continue;
  911.             }
  912.             /*
  913.              *  Should be smart and eliminate duplicate
  914.              *  data here.    XXX
  915.              */
  916.             if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0)
  917.                 break;
  918. #ifdef DEBUG
  919.             if (debug >= 5)
  920.                 fprintf(ddt,"addinfo: adding address data n = %d\n",
  921.                    n);
  922. #endif
  923.             cp += n;
  924.             msglen -= n;
  925.             count++;
  926.         }
  927.         if (foundstale) {
  928.             /* Cache invalidate the address RR's */
  929.             delete_all(np, (int)ap->a_class, T_A);
  930.             (void) sysquery(ap->a_dname, (int)ap->a_class, T_A);
  931.         }
  932.     }
  933.     hp->arcount = htons((u_short)count);
  934.     return (cp - msg);
  935. }
  936.  
  937. doaddauth(hp, cp, buflen, np, dp)
  938.     register HEADER *hp;
  939.     char *cp;
  940.     int buflen;
  941.     struct namebuf *np;
  942.     struct databuf *dp;
  943. {
  944.     char dnbuf[MAXDNAME];
  945.     int n;
  946.  
  947.     getname(np, dnbuf, sizeof(dnbuf));
  948.     if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) {
  949. #ifdef DEBUG
  950.         if (debug)
  951.             fprintf(ddt,"doaddauth: can't add '%s' (%d)\n",
  952.                 dnbuf, buflen);
  953. #endif
  954.         return(0);
  955.     } else {
  956.         hp->nscount = htons(1);
  957.         return(n);
  958.     }
  959. }
  960.  
  961.  
  962. /*
  963.  * Get the domain name of 'np' and put in 'buf'.  Bounds checking is done.
  964.  */
  965. getname(np, buf, buflen)
  966.     struct namebuf *np;
  967.     char *buf;
  968.     int buflen;
  969. {
  970.     register char *cp;
  971.     register int i;
  972.  
  973.     cp = buf;
  974.     while (np != NULL) {
  975.         if ((i = strlen(np->n_dname))+1 >= buflen) {
  976.             *cp = '\0';
  977.             syslog(LOG_ERR, "domain name too long: %s...\n", buf);
  978.             strcpy(buf, "Name_Too_Long");
  979.             return;
  980.         }
  981.         if (cp != buf)
  982.             *cp++ = '.';
  983.         (void) strcpy(cp, np->n_dname);
  984.         cp += i;
  985.         buflen -= (i+1);
  986.         np = np->n_parent;
  987.     }
  988.     *cp = '\0';
  989. }
  990.  
  991. /*
  992.  * Do a zone transfer. SOA record already sent.
  993.  */
  994. doaxfr(np, rfp, isroot)
  995.     register struct namebuf *np;
  996.     FILE *rfp;
  997.     int isroot;
  998. {
  999.     register struct databuf *dp;
  1000.     register int n;
  1001.     struct hashbuf *htp;
  1002.     struct databuf *gdp;    /* glue databuf */
  1003.     struct namebuf *gnp;    /* glue namebuf */
  1004.     struct namebuf **npp, **nppend;
  1005.     char msg[PACKETSZ];
  1006.     char *cp;
  1007.     char *fname;
  1008.     char dname[MAXDNAME];
  1009.     HEADER *hp = (HEADER *) msg;
  1010.     int fndns;
  1011.  
  1012. #ifdef DEBUG
  1013.     if (debug && isroot)
  1014.         fprintf(ddt,"doaxfr()\n");
  1015. #endif
  1016.     fndns = 0;
  1017.     hp->id = 0;
  1018.     hp->opcode = QUERY;
  1019.     hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
  1020.     hp->qr = 1;
  1021.     hp->rcode = NOERROR;
  1022.     hp->qdcount = 0;
  1023.     hp->ancount = htons(1);
  1024.     hp->nscount = 0;
  1025.     hp->arcount = 0;
  1026.     cp = msg + sizeof(HEADER);
  1027.     getname(np, dname, sizeof(dname));
  1028.  
  1029.     /* first do data records */
  1030.     for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  1031.         /*
  1032.          * Skip the root SOA record (marks end of data);
  1033.          * don't send SOA for subdomains, as we're not sending them.
  1034.          */
  1035.         if (dp->d_type == T_SOA)
  1036.             continue;
  1037.         if (dp->d_type == T_NS)
  1038.             fndns = 1;
  1039.         if (dp->d_zone == 0 || stale(dp))
  1040.             continue;
  1041.         if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
  1042.             continue;
  1043.         fwritemsg(rfp, msg, n + sizeof(HEADER));
  1044.  
  1045.         if (dp->d_type == T_NS) {
  1046.             /*  Glue the sub domains together by sending 
  1047.              *  the address records for the sub domain
  1048.              *  name servers along.
  1049.              */
  1050.              htp = hashtab;
  1051.             cp = msg + sizeof(HEADER);
  1052.              gnp = nlookup(dp->d_data, &htp, &fname, 0);
  1053.              if (gnp == NULL || fname != dp->d_data)
  1054.                  continue;
  1055.              for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
  1056.                  if (gdp->d_type != T_A || stale(gdp))
  1057.                  continue;
  1058.                  if ((n = make_rr(fname, gdp, cp,
  1059.                      sizeof(msg)-sizeof(HEADER), 0)) < 0)
  1060.                  continue;
  1061.                  fwritemsg(rfp, msg, n + sizeof(HEADER));
  1062.              }
  1063.          }
  1064.     }
  1065.  
  1066.     /* next do subdomains, unless delegated */
  1067.     if ((isroot == 0 && fndns) || np->n_hash == NULL)
  1068.         return;
  1069.     npp = np->n_hash->h_tab;
  1070.     nppend = npp + np->n_hash->h_size;
  1071.     while (npp < nppend) {
  1072.         for (np = *npp++; np != NULL; np = np->n_next) {
  1073.             doaxfr(np, rfp, 0);
  1074.         }
  1075.     }
  1076. #ifdef DEBUG
  1077.     if (debug && isroot)
  1078.         fprintf(ddt,"exit doaxfr()\n");
  1079. #endif
  1080. }
  1081.  
  1082. #ifdef ALLOW_UPDATES
  1083. /*
  1084.  * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update.  If this is the
  1085.  * primary server for the zone being updated, we update the zone's serial
  1086.  * number and then call doupdate directly. If this is a secondary, we just
  1087.  * forward the update; this way, if the primary update fails (e.g., if the
  1088.  * primary is unavailable), we don't update the secondary; if the primary
  1089.  * update suceeds, ns_resp will get called with the response (when it comes
  1090.  * in), and then update the secondary's copy.
  1091.  */
  1092. InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd)
  1093.     register HEADER *hp;
  1094.     struct databuf *nsp[];
  1095.     char *msg;
  1096.     int msglen;
  1097.     u_char *startcp;
  1098.     struct sockaddr_in *from;
  1099.     struct qstream *qsp;
  1100.     int dfd;
  1101. {
  1102.     struct zoneinfo *zp;
  1103.     char dnbuf[MAXDNAME];
  1104.     struct hashbuf *htp = hashtab;    /* lookup relative to root */
  1105.     struct namebuf *np;
  1106.     struct databuf *olddp, *newdp, *dp;
  1107.     struct databuf **nspp;
  1108.     char *fname;
  1109.     register u_char *cp = startcp;
  1110.     short class, type;
  1111.     int n, size, zonenum;
  1112.     char ZoneName[MAXDNAME], *znp;
  1113.  
  1114.     if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
  1115. #ifdef DEBUG
  1116.         if (debug)
  1117.             fprintf(ddt,"FORMERR InitDynUpdate expand name failed\n");
  1118. #endif
  1119.         hp->rcode = FORMERR;
  1120.         return(FORMERR);
  1121.     }
  1122.     cp += n;
  1123.     GETSHORT(type, cp);
  1124.     if (type == T_SOA) {    /* T_SOA updates not allowed */
  1125.         hp->rcode = REFUSED;
  1126. #ifdef DEBUG
  1127.         if (debug)
  1128.             fprintf(ddt, "InitDynUpdate: REFUSED - SOA update\n");
  1129. #endif
  1130.         return(REFUSED);
  1131.     }
  1132.     GETSHORT(class, cp);
  1133.     cp += sizeof(u_long);
  1134.     GETSHORT(size, cp);
  1135. /****XXX - need bounds checking here ****/
  1136.     cp += size;
  1137.  
  1138.     if ((zonenum = findzone(dnbuf, class)) == 0) {  /* zone not found */
  1139.         hp->rcode = NXDOMAIN;
  1140.         return(NXDOMAIN);
  1141.     }
  1142.     zp = &zones[zonenum];
  1143.  
  1144.     /* Disallow updates for which we aren't authoratative.  Note: the
  1145.        following test doesn't work right:  If it's for a non-local zone,
  1146.        we will think it's a primary but be unable to lookup the namebuf,
  1147.        thus returning 'NXDOMAIN' */
  1148.     if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) {
  1149.         hp->rcode = REFUSED;
  1150. #ifdef DEBUG
  1151.         if (debug)
  1152.             fprintf(ddt, "InitDynUpdate: REFUSED - non-primary, non-sedondary update\n");
  1153. #endif
  1154.         return(REFUSED);
  1155.     }
  1156.     if (!(zp->z_state & Z_DYNAMIC)) {
  1157.         hp->rcode = REFUSED;
  1158. #ifdef DEBUG
  1159.         if (debug)
  1160.             fprintf(ddt, "InitDynUpdate: REFUSED - dynamic flag not set for zone\n");
  1161. #endif
  1162.         return(REFUSED);
  1163.     }
  1164.  
  1165.     /*
  1166.      * Lookup the zone namebuf.  Lookup "xyz" not "xyz.", since
  1167.      * otherwise the lookup fails, because '.' may have a nil n_hash
  1168.      * associated with it.
  1169.      */
  1170.     strcpy(ZoneName, zp->z_origin);
  1171.     znp = &ZoneName[strlen(ZoneName) - 1];
  1172.     if (*znp == '.')
  1173.         *znp = NULL;
  1174.     np = nlookup(ZoneName, &htp, &fname, 0);
  1175.     if ((np == NULL) || (fname != ZoneName)) {
  1176. #ifdef DEBUG
  1177.         if (debug)
  1178.             fprintf(ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
  1179.                 ZoneName);
  1180. #endif DEBUG
  1181.             syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n",
  1182.                ZoneName);
  1183.         hp->rcode = NXDOMAIN;
  1184.         return(NXDOMAIN);
  1185.     }
  1186.  
  1187.     /*
  1188.      * If this is the primary copy increment the serial number.  Don't
  1189.      * increment the serial number if this is a secondary; this way, if 2
  1190.      * different secondaries both update the primary, they will both have
  1191.      * lower serial numbers than the primary has, and hence eventually
  1192.      * refresh and get all updates and become consistent.
  1193.      *
  1194.      * Note that the serial number must be incremented in both the zone
  1195.      * data structure and the zone's namebuf.
  1196.      */
  1197.     switch (zp->z_type) {
  1198.     case Z_SECONDARY:        /* forward update to primary */
  1199.         nspp = nsp;
  1200.         dp = np->n_data;
  1201.         while (dp != NULL) {
  1202.             if (match(dp, class, T_NS)) {
  1203.                 if (nspp < &nsp[NSMAX-1])
  1204.                     *nspp++ = dp;
  1205.                 else
  1206.                     break;
  1207.             }
  1208.             dp = dp->d_next;
  1209.         }
  1210.         *nspp = NULL; /* Delimiter */
  1211.         if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL) < 0) {
  1212.             hp->rcode = SERVFAIL;
  1213.             return(SERVFAIL);
  1214.         }
  1215.         return(FORWARDED);
  1216.  
  1217.     case Z_PRIMARY:
  1218.         zp->z_serial++;
  1219.         olddp = np->n_data; /* old databuf */
  1220.         /* Find the SOA record */
  1221.         for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next)
  1222.             if (match(olddp, class, T_SOA))
  1223.                 break;
  1224.         if (olddp == NULL) {
  1225. #ifdef DEBUG
  1226.             if (debug)
  1227.                 fprintf(ddt,"InitDynUpdate: Couldn't find SOA record for '%s'\n",
  1228.                         ZoneName);
  1229. #endif DEBUG
  1230.             syslog(LOG_ERR,
  1231.                "InitDynUpdate: Couldn't find SOA record for '%s'\n"
  1232. ,
  1233.                ZoneName);
  1234.             hp->rcode = NXDOMAIN;
  1235.             return(NXDOMAIN);
  1236.         }
  1237.         newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl,
  1238.                  olddp->d_data, olddp->d_size);
  1239.         newdp->d_zone = olddp->d_zone;
  1240.         cp = (u_char *)newdp->d_data;
  1241.         cp += strlen(cp) + 1; /* skip origin string */
  1242.         cp += strlen(cp) + 1; /* skip in-charge string */
  1243.         putlong((u_long)(zp->z_serial), cp);
  1244. #ifdef DEBUG
  1245.         if (debug >= 4) {
  1246.             fprintf(ddt, "after stuffing data into newdp:\n");
  1247.             printSOAdata(newdp);
  1248.         }
  1249. #endif DEBUG
  1250.  
  1251.         if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
  1252.                    hashtab)) != NOERROR) {
  1253. #ifdef DEBUG
  1254.             if (debug)
  1255.                 fprintf(ddt,"InitDynUpdate: SOA update failed\n");
  1256. #endif DEBUG
  1257.             hp->rcode = NOCHANGE;
  1258.             return(NOCHANGE);
  1259.         }
  1260.  
  1261.         /* Now update the RR itself */
  1262.         if (doupdate(msg, msglen, msg + sizeof(HEADER),
  1263.                  zonenum, (struct databuf *)0, DB_NODATA) < 0) {
  1264. #ifdef DEBUG
  1265.             if (debug)
  1266.                 fprintf(ddt,"InitDynUpdate: doupdate failed\n");
  1267. #endif DEBUG
  1268.             /* doupdate fills in rcode */
  1269.             return(hp->rcode);
  1270.         }
  1271.         zp->hasChanged++;
  1272.         return(NOERROR);
  1273.     }
  1274. }
  1275.  
  1276. #ifdef DEBUG
  1277. /*
  1278.  * Print the contents of the data in databuf pointed to by dp for an SOA record
  1279.  */
  1280. printSOAdata(dp)
  1281.     struct databuf *dp;
  1282. {
  1283.     register u_char *cp;
  1284.  
  1285.     if (!debug)
  1286.         return;  /* Otherwise fprintf to ddt will bomb */
  1287.     cp = (u_char *)dp->d_data;
  1288.     fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp);
  1289.     cp += strlen(cp) + 1; /* skip origin string */
  1290.     fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
  1291.     cp += strlen(cp) + 1; /* skip in-charge string */
  1292.     fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));
  1293. }
  1294. #endif DEBUG
  1295. #endif ALLOW_UPDATES
  1296.  
  1297. struct databuf *
  1298. rm_datum(dp, np, pdp)
  1299. register struct databuf *pdp, *dp;
  1300. register struct namebuf *np;
  1301. {
  1302.     register struct databuf *ndp = dp->d_next;
  1303.  
  1304. #ifdef DEBUG
  1305.     if (debug > 2)
  1306.         fprintf(ddt, "rm_datum(%x, %x, %x) -> %x\n",
  1307.             dp, np->n_data, pdp, ndp);
  1308. #endif DEBUG
  1309.     if (pdp == NULL)
  1310.         np->n_data = ndp;
  1311.     else
  1312.         pdp->d_next = ndp;
  1313.     rminv(dp);
  1314.     (void) free((char *)dp);
  1315.     return(ndp);
  1316. }
  1317.  
  1318. startxfr(qsp, np, msg, msglen)
  1319.     struct qstream *qsp;
  1320.     struct namebuf *np;
  1321.     char    *msg;
  1322.     int    msglen;
  1323. {
  1324.     register FILE *rfp;
  1325.     int fdstat;
  1326.  
  1327. #ifdef DEBUG
  1328.     if (debug >= 5)
  1329.         fprintf(ddt,"startxfr()\n");
  1330. #endif
  1331.     /*
  1332.      * child does the work while
  1333.      * the parent continues
  1334.      */
  1335.     if (fork() == 0) {
  1336. #ifdef DEBUG
  1337.         if (debug >= 5)
  1338.             fprintf(ddt,"startxfr: child pid %d\n", getpid());
  1339. #endif
  1340.         rfp = fdopen(qsp->s_rfd, "w");
  1341.         setproctitle("zone XFR to", qsp->s_rfd);
  1342.         fdstat = fcntl(qsp->s_rfd, F_GETFL, 0);
  1343.         if (fdstat != -1)
  1344.             (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~O_NONBLOCK);
  1345.         fwritemsg(rfp, msg, msglen);
  1346.         doaxfr(np, rfp, 1);
  1347.         fwritemsg(rfp, msg, msglen);
  1348.         (void) fflush(rfp);
  1349.         exit(0);
  1350.     }
  1351.     sqrm(qsp);
  1352. }
  1353.