]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind/bin/named/db_ixfr.c
This commit was generated by cvs2svn to compensate for changes in r56639,
[FreeBSD/FreeBSD.git] / contrib / bind / bin / named / db_ixfr.c
1 #if !defined(lint) && !defined(SABER)
2 static char     rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $";
3 #endif                /* not lint */
4
5 /*
6  * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
7  * 
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies, and that
11  * the name of Check Point Software Technologies Incorporated not be used 
12  * in advertising or publicity pertaining to distribution of the document 
13  * or software without specific, written prior permission.
14  * 
15  * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES 
16  * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.   
18  * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
19  * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR 
20  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
22  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 /*
26  * Manage ixfr transaction log
27  */
28
29 #include "port_before.h"
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 #include <sys/socket.h>
35
36 #include <netinet/in.h>
37 #include <arpa/nameser.h>
38 #include <arpa/inet.h>
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #include <resolv.h>
44 #include <res_update.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <syslog.h>
50 #include <time.h>
51
52 #include <isc/eventlib.h>
53 #include <isc/logging.h>
54
55 #include "port_after.h"
56
57 #include "named.h"
58
59 #define DBIXFR_ERROR            -1
60 #define DBIXFR_FOUND_RR         2
61 #define DBIXFR_END              3
62
63 static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *,
64                       ns_updrec **, u_int32_t *, u_int32_t *);
65
66 ns_updrec *
67 ixfr_get_change_list(struct zoneinfo *zp,
68                      u_int32_t from_serial, u_int32_t to_serial)
69 {
70         FILE *          fp;
71         u_int32_t       old_serial, new_serial;
72         char            origin[MAXDNAME];
73         struct namebuf *np, *listnp, *finlistnp;
74         LIST(ns_updrec) listuprec;
75         int             ret, mode;
76         ns_updrec       *uprec;
77
78         if (SEQ_GT(from_serial, to_serial))
79                 return (NULL);
80         listnp = finlistnp = NULL;
81         INIT_LIST(listuprec);
82         if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
83                 ns_warning(ns_log_db, "%s: %s",
84                            zp->z_ixfr_base, strerror(errno));
85                 return (NULL);
86         }
87         strcpy(origin, zp->z_origin);
88         lineno = 1;
89         np = NULL;
90         mode = 0;
91         old_serial = new_serial = 0;
92         for (;;) {
93                 ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec,
94                                  &old_serial, &new_serial);
95                 switch (ret) {
96                 case DBIXFR_ERROR:
97                         (void) my_fclose(fp);
98                         ns_warning(ns_log_db, "Logical error in %s line %d", 
99                                    zp->z_ixfr_base, lineno);
100                         return (NULL);
101                 case DBIXFR_FOUND_RR:
102                         if (EMPTY(listuprec)) {
103                                 /* skip updates prior to the one we want */
104                                 if (uprec->r_zone != from_serial) {
105                                         while (uprec != NULL) {
106                                                 ns_updrec *prev;
107
108                                                 if (uprec->r_dp != NULL)
109                                                       db_freedata(uprec->r_dp);
110                                                 uprec->r_dp = NULL;
111                                                 prev = PREV(uprec, r_link);
112                                                 res_freeupdrec(uprec);
113                                                 uprec = prev;
114                                         }
115                                         break;
116                                 }
117                         }
118                         APPEND(listuprec, uprec, r_link);
119                         /* continue; */
120                         break;
121                 case DBIXFR_END:
122                         (void) my_fclose(fp);
123                         return (HEAD(listuprec));
124                 default:
125                         (void) my_fclose(fp);
126                         return (NULL);
127                 }
128         }
129 }
130
131 /*
132  * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial,
133  *                   u_int32_t to_serial)
134  * 
135  * verify that ixfr transaction log contains changes  
136  * from from_serial to to_serial
137  * 
138  * returns: 
139  *         0 = serial number is up to date
140  *         1 = transision is possible 
141  *        -1 = error while opening the ixfr transaction log
142  *        -2 = error in parameters
143  *        -3 = logical error in the history file 
144  */
145 int
146 ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial)
147 {
148         FILE           *fp;
149         u_int32_t       old_serial = 0, new_serial = 0;
150         char            buf[BUFSIZ];
151         char           *cp;
152         struct stat     st;
153         int             nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
154                         inside_next = 0;
155         int             err;
156         int             id, rcode = NOERROR;
157
158         if (SEQ_GT(from_serial, to_serial))
159                 return (-2);
160         if (from_serial == to_serial)
161                 return (0);
162         /* If there is no log file, just return. */
163         if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL)
164                 return (-1);
165         if (stat(zp->z_ixfr_base, &st) < 0) {
166                 if (errno != ENOENT)
167                         ns_error(ns_log_db,
168                                  "unexpected stat(%s) failure: %s",
169                                  zp->z_ixfr_base, strerror(errno));
170                 return (-1);
171         }
172         if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
173                 ns_warning(ns_log_db, "%s: %s",
174                            zp->z_ixfr_base, strerror(errno));
175                 return (-1);
176         }
177         if (fgets(buf, sizeof(buf), fp) == NULL) {
178                 ns_error(ns_log_update, "fgets() from %s failed: %s",
179                          zp->z_updatelog, strerror(errno));
180                 fclose(fp);
181                 return (-1);
182         }
183         if (strcmp(buf, LogSignature) != 0) {
184                 ns_error(ns_log_update, "invalid log file %s",
185                          zp->z_updatelog);
186                 fclose(fp);
187                 return (-3);
188         }
189         lineno = 1;
190         for (;;) {
191                 if (getword(buf, sizeof buf, fp, 0)) {
192                         nonempty_lineno = lineno;
193                 } else {
194                         if (lineno == (nonempty_lineno + 1))
195                                 continue;
196                         inside_next = 0;
197                         prev_pktdone = 1;
198                         cont = 1;
199                 }
200                 if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
201                     !strcasecmp(buf, "[IXFR_UPDATE]")) {
202                         err = 0;
203                         rcode = NOERROR;
204                         cp = fgets(buf, sizeof buf, fp);
205                         if (cp != NULL)
206                                 lineno++;
207                         if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
208                                 id = -1;
209                         inside_next = 1;
210                         prev_pktdone = 1;
211                         cont = 1;
212                 } else if (!strcasecmp(buf, "serial")) {
213                         cp = fgets(buf, sizeof buf, fp);
214                         if (cp != NULL)
215                                 lineno++;
216                         if (sscanf((char *) cp, "%u", &old_serial)) {
217                                 if (from_serial >= old_serial) {
218                                         fclose(fp);
219                                         return (1);
220                                 } else {
221                                         fclose(fp);
222                                         return (-1);
223                                 }
224                         }
225                         prev_pktdone = 1;
226                         cont = 1;
227                 } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
228                         /* XXXRTH not enough error checking here */
229                         cp = fgets(buf, sizeof buf, fp);
230                         if (cp != NULL)
231                                 lineno++;
232                         if (cp == NULL ||
233                             sscanf((char *) cp, "from %u to %u",
234                                     &old_serial, &new_serial) != 2) {
235                                 fclose(fp);
236                                 return (-3);
237                         } else if (from_serial >= old_serial) {
238                                 fclose(fp);
239                                 return (1);
240                         }
241                         fclose(fp);
242                         return (-1);
243                 }
244                 if (prev_pktdone) {
245                         prev_pktdone = 0;
246                         if (feof(fp))
247                                 break;
248                 }
249         }
250         fclose(fp);
251         return (0);
252 }
253
254 /* from db_load.c */
255
256 static struct map m_section[] = {
257         {"zone", S_ZONE},
258         {"prereq", S_PREREQ},
259         {"update", S_UPDATE},
260         {"reserved", S_ADDT},
261 };
262 #define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map))
263
264 /* from ns_req.c */
265
266 static struct map m_opcode[] = {
267         {"nxdomain", NXDOMAIN},
268         {"yxdomain", YXDOMAIN},
269         {"nxrrset", NXRRSET},
270         {"yxrrset", YXRRSET},
271         {"delete", DELETE},
272         {"add", ADD},
273 };
274 #define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map))
275
276 /* XXXRTH workaround map difficulties */
277 #define M_CLASS_CNT m_class_cnt
278 #define M_TYPE_CNT m_type_cnt
279
280 /*
281  * int
282  * ixfr_getrr(struct zoneinfo *zp, FILE *fp,
283  *            const char *filename, char *origin, struct namebuf **np,
284  *            u_int32_t *old_serial, u_int32_t *new_serial)
285  * 
286  * read a line from the historic of a zone.
287  * 
288  * returns:
289  * 
290  *         DBIXFR_ERROR = an error occured 
291  *         DBIXFR_FOUND_RR = a rr encountered 
292  *         DBIXFR_END = end of file
293  */
294 static int
295 ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin,
296            ns_updrec **uprec, u_int32_t *old_serial,
297            u_int32_t *new_serial)
298 {
299         static int      read_soa, read_ns, rrcount;
300
301         char            data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
302         const char     *errtype = "Database";
303         char           *dname, *cp, *cp1;
304         char            buf[MAXDATA];
305         u_int32_t       serial, ttl;
306         int             nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
307                         inside_next = 0;
308         int             id, rcode = NOERROR;
309         int             i, c, section, opcode, matches, zonenum, err, multiline;
310         int             type, class;
311         u_int32_t       n;
312         enum transport  transport;
313         struct map     *mp;
314         int             zonelist[MAXDNAME];
315         struct databuf *dp;
316         struct in_addr  ina;
317         struct sockaddr_in empty_from;
318         int             datasize;
319         ns_updque       listuprec;
320         ns_updrec *     rrecp;
321         u_long          l;
322
323 #define    ERRTO(msg)  if (1) { errtype = msg; goto err; } else (void)NULL
324
325         err = 0;
326         transport = primary_trans;
327         lineno = 1;
328         INIT_LIST(listuprec);
329         for (;;) {
330                 if (!getword(buf, sizeof buf, fp, 0)) {
331                         if (lineno == (nonempty_lineno + 1) && !(feof(fp))) {
332                                 /*
333                                  * End of a nonempty line inside an update
334                                  * packet or not inside an update packet.
335                                  */
336                                 continue;
337                         }
338                         /*
339                          * Empty line or EOF.
340                          * 
341                          * Marks completion of current update packet.
342                          */
343                         inside_next = 0;
344                         prev_pktdone = 1;
345                         cont = 1;
346                 } else {
347                         nonempty_lineno = lineno;
348                 }
349
350                 if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
351                     !strcasecmp(buf, "[IXFR_UPDATE]")) {
352                         err = 0;
353                         rcode = NOERROR;
354                         cp = fgets(buf, sizeof buf, fp);
355                         if (cp != NULL)
356                                 lineno++;
357                         if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
358                                 id = -1;
359                         inside_next = 1;
360                         prev_pktdone = 1;
361                         cont = 1;
362                 } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
363                         /* XXXRTH not enough error checking here */
364                         cp = fgets(buf, sizeof buf, fp);
365                         if (cp != NULL)
366                                 lineno++;
367                         if (cp == NULL ||
368                             sscanf((char *) cp, "from %u to %u",
369                                     old_serial, new_serial) != 2) {
370                                 ns_error(ns_log_update,
371                                          "incr_serial problem with %s",
372                                          zp->z_updatelog);
373                         } else {
374                                 serial = get_serial(zp);
375                         }
376                         cont = 1;
377                 } else if (!strcasecmp(buf, "[END_DELTA]")) {
378                         prev_pktdone = 1;
379                         cont = 1;
380                         lineno++;
381                 }
382                 if (prev_pktdone) {
383                         if (!EMPTY(listuprec)) {
384                                 n++;
385                                 *uprec = TAIL(listuprec);
386                                 return (DBIXFR_FOUND_RR);
387                         }
388                         prev_pktdone = 0;
389                         if (feof(fp))
390                                 break;
391                 }
392                 if (cont) {
393                         cont = 0;
394                         continue;
395                 }
396                 if (!inside_next)
397                         continue;
398                 /*
399                  * inside the same update packet, continue accumulating
400                  * records.
401                  */
402                 section = -1;
403                 n = strlen(buf);
404                 if (buf[n - 1] == ':')
405                         buf[--n] = '\0';
406                 for (mp = m_section; mp < m_section + M_SECTION_CNT; mp++)
407                         if (!strcasecmp(buf, mp->token)) {
408                                 section = mp->val;
409                                 break;
410                         }
411                 ttl = 0;
412                 type = -1;
413                 class = zp->z_class;
414                 n = 0;
415                 data[0] = '\0';
416                 switch (section) {
417                 case S_ZONE:
418                         cp = fgets(buf, sizeof buf, fp);
419                         if (!cp)
420                                 *buf = '\0';
421                         n = sscanf(cp, "origin %s class %s serial %ul",
422                                    origin, sclass, &serial);
423                         if (n != 3 || ns_samename(origin, zp->z_origin) != 1)
424                                 err++;
425                         if (cp)
426                                 lineno++;
427                         if (!err && inside_next) {
428                                 int             success;
429
430                                 dname = origin;
431                                 type = T_SOA;
432                                 class = sym_ston(__p_class_syms, sclass,
433                                                  &success);
434                                 if (!success) {
435                                         err++;
436                                         break;
437                                 }
438                                 matches = findzone(dname, class, 0,
439                                                    zonelist, MAXDNAME);
440                                 if (matches)
441                                         zonenum = zonelist[0];
442                                 else
443                                         err++;
444                         }
445                         break;
446                 case S_PREREQ:
447                 case S_UPDATE:
448                         /* Operation code. */
449                         if (!getword(buf, sizeof buf, fp, 0)) {
450                                 err++;
451                                 break;
452                         }
453                         opcode = -1;
454                         if (buf[0] == '{') {
455                                 n = strlen(buf);
456                                 for (i = 0; (u_int32_t) i < n; i++)
457                                         buf[i] = buf[i + 1];
458                                 if (buf[n - 2] == '}')
459                                         buf[n - 2] = '\0';
460                         }
461                         for (mp = m_opcode; mp < m_opcode + M_OPCODE_CNT; mp++)
462                                 if (!strcasecmp(buf, mp->token)) {
463                                         opcode = mp->val;
464                                         break;
465                                 }
466                         if (opcode == -1) {
467                                 err++;
468                                 break;
469                         }
470                         /* Owner's domain name. */
471                         if (!getword((char *) dnbuf, sizeof dnbuf, fp, 0)) {
472                                 err++;
473                                 break;
474                         }
475                         n = strlen((char *) dnbuf) - 1;
476                         if (dnbuf[n] == '.')
477                                 dnbuf[n] = '\0';
478                         dname = dnbuf;
479                         ttl = 0;
480                         type = -1;
481                         class = zp->z_class;
482                         n = 0;
483                         data[0] = '\0';
484                         (void) getword(buf, sizeof buf, fp, 1);
485                         if (isdigit(buf[0])) {    /* ttl */
486                                 if (ns_parse_ttl(buf, &l) < 0) {
487                                         err++;
488                                         break;
489                                 }
490                                 ttl = l;
491                                 (void) getword(buf, sizeof buf, fp, 1);
492                         }
493                         /* possibly class */
494                         if (buf[0] != '\0') {
495                                 int             success;
496                                 int             maybe_class;
497
498                                 maybe_class = sym_ston(__p_class_syms,
499                                                        buf, &success);
500                                 if (success) {
501                                         class = maybe_class;
502                                         (void) getword(buf, sizeof buf, fp, 1);
503                                 }
504                         }
505                         /* possibly type */
506                         if (buf[0] != '\0') {
507                                 int             success;
508                                 int             maybe_type;
509
510                                 maybe_type = sym_ston(__p_type_syms,
511                                                       buf, &success);
512
513                                 if (success) {
514                                         type = maybe_type;
515                                         (void) getword(buf, sizeof buf, fp, 1);
516                                 }
517                         }
518                         if (buf[0] != '\0')    /* possibly rdata */
519                         /*
520                          * Convert the ascii data 'buf' to the proper
521                          * format based on the type and pack into
522                          * 'data'.
523                          * 
524                          * XXX - same as in db_load(), consolidation
525                          * needed
526                          */
527                         switch (type) {
528                         case T_A:
529                                 if (!inet_aton(buf, &ina)) {
530                                         err++;
531                                         break;
532                                 }
533                                 n = ntohl(ina.s_addr);
534                                 cp = data;
535                                 PUTLONG(n, cp);
536                                 n = INT32SZ;
537                                 break;
538                         case T_HINFO:
539                         case T_ISDN:
540                                 n = strlen(buf);
541                                 data[0] = n;
542                                 memcpy(data + 1, buf, n);
543                                 n++;
544                                 if (!getword(buf, sizeof buf, fp, 0)) {
545                                         i = 0;
546                                 } else {
547                                         endline(fp);
548                                         i = strlen(buf);
549                                 }
550                                 data[n] = i;
551                                 n++;
552                                 memcpy(data + n + 1, buf, i);
553                                 n += i;
554                                 break;
555                         case T_SOA:
556                         case T_MINFO:
557                         case T_RP:
558                                 (void) strcpy(data, buf);
559                                 cp = data + strlen(data) + 1;
560                                 if (!getword((char *) cp,
561                                              sizeof data - (cp - data),
562                                              fp, 1)) {
563                                         err++;
564                                         break;
565                                 }
566                                 cp += strlen((char *) cp) + 1;
567                                 if (type != T_SOA) {
568                                         n = cp - data;
569                                         break;
570                                 }
571                                 if (class != zp->z_class ||
572                                     ns_samename(dname, zp->z_origin) != 1) {
573                                         err++;
574                                         break;
575                                 }
576                                 c = getnonblank(fp, zp->z_updatelog);
577                                 if (c == '(') {
578                                         multiline = 1;
579                                 } else {
580                                         multiline = 0;
581                                         ungetc(c, fp);
582                                 }
583                                 n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL);
584                                 if (getnum_error) {
585                                         err++;
586                                         break;
587                                 }
588                                 if (opcode == ADD && i == 0)
589                                         *new_serial = n;
590                                 PUTLONG(n, cp);
591                                 for (i = 0; i < 4; i++) {
592                                         if (!getword(buf, sizeof buf, fp, 1)) {
593                                                 err++;
594                                                 break;
595                                         }
596                                         if (ns_parse_ttl(buf, &l) < 0) {
597                                                 err++;
598                                                 break;
599                                         }
600                                         n = l;
601                                         PUTLONG(n, cp);
602                                 }
603                                 if (multiline &&
604                                     getnonblank(fp, zp->z_updatelog) != ')')
605                                 {
606                                         err++;
607                                         break;
608                                 }
609                                 endline(fp);
610                                 n = cp - data;
611                                 break;
612                         case T_WKS:
613                                 if (!inet_aton(buf, &ina)) {
614                                         err++;
615                                         break;
616                                 }
617                                 n = ntohl(ina.s_addr);
618                                 cp = data;
619                                 PUTLONG(n, cp);
620                                 *cp = (char) getprotocol(fp, zp->z_updatelog);
621                                 n = INT32SZ + sizeof(char);
622                                 n = getservices((int) n, data,
623                                                 fp, zp->z_updatelog);
624                                 break;
625                         case T_NS:
626                         case T_CNAME:
627                         case T_MB:
628                         case T_MG:
629                         case T_MR:
630                         case T_PTR:
631                                 (void) strcpy(data, buf);
632                                 if (makename(data, origin,
633                                              sizeof(data)) == -1) {
634                                         err++;
635                                         break;
636                                 }
637                                 n = strlen(data) + 1;
638                                 break;
639                         case T_MX:
640                         case T_AFSDB:
641                         case T_RT:
642                                 n = 0;
643                                 cp = buf;
644                                 while (isdigit(*cp))
645                                         n = n * 10 + (*cp++ - '0');
646                                 /* catch bad values */
647                                 cp = data;
648                                 PUTSHORT((u_int16_t) n, cp);
649                                 if (!getword(buf, sizeof(buf), fp, 1)) {
650                                         err++;
651                                         break;
652                                 }
653                                 (void) strcpy((char *) cp, buf);
654                                 if (makename((char *) cp, origin,
655                                              sizeof(data) - (cp - data)) == -1)
656                                 {
657                                         err++;
658                                         break;
659                                 }
660                                 /* advance pointer to end of data */
661                                 cp += strlen((char *) cp) + 1;
662                                 /* now save length */
663                                 n = (cp - data);
664                                 break;
665                         case T_PX:
666                                 n = 0;
667                                 data[0] = '\0';
668                                 cp = buf;
669                                 while (isdigit(*cp))
670                                         n = n * 10 + (*cp++ - '0');
671                                 cp = data;
672                                 PUTSHORT((u_int16_t) n, cp);
673                                 for (i = 0; i < 2; i++) {
674                                         if (!getword(buf, sizeof(buf), fp, 0))
675                                         {
676                                                 err++;
677                                                 break;
678                                         }
679                                         (void) strcpy((char *) cp, buf);
680                                         cp += strlen((char *) cp) + 1;
681                                 }
682                                 n = cp - data;
683                                 break;
684                         case T_TXT:
685                         case T_X25:
686                                 i = strlen(buf);
687                                 cp = data;
688                                 datasize = sizeof data;
689                                 cp1 = buf;
690                                 while (i > MAXCHARSTRING) {
691                                         if (datasize <= MAXCHARSTRING) {
692                                                 ns_error(ns_log_update,
693                                                          "record too big");
694                                                 return (-1);
695                                         }
696                                         datasize -= MAXCHARSTRING;
697                                         *cp++ = (char)MAXCHARSTRING;
698                                         memcpy(cp, cp1, MAXCHARSTRING);
699                                         cp += MAXCHARSTRING;
700                                         cp1 += MAXCHARSTRING;
701                                         i -= MAXCHARSTRING;
702                                 }
703                                 if (datasize < i + 1) {
704                                         ns_error(ns_log_update,
705                                                  "record too big");
706                                         return (-1);
707                                 }
708                                 *cp++ = i;
709                                 memcpy(cp, cp1, i);
710                                 cp += i;
711                                 n = cp - data;
712                                 endline(fp);
713                                 /* XXXVIX: segmented texts 4.9.5 */
714                                 break;
715                         case T_NSAP:
716                                 n = inet_nsap_addr(buf, (u_char *) data,
717                                                    sizeof data);
718                                 endline(fp);
719                                 break;
720                         case T_LOC:
721                                 cp = buf + (n = strlen(buf));
722                                 *cp = ' ';
723                                 cp++;
724                                 while ((i = getc(fp), *cp = i, i != EOF)
725                                        && *cp != '\n' && (n < MAXDATA))
726                                 {
727                                         cp++;
728                                         n++;
729                                 }
730                                 if (*cp == '\n')
731                                         ungetc(*cp, fp);
732                                 *cp = '\0';
733                                 n = loc_aton(buf, (u_char *) data);
734                                 if (n == 0) {
735                                         err++;
736                                         break;
737                                 }
738                                 endline(fp);
739                                 break;
740                         case ns_t_sig: 
741                         case ns_t_nxt:
742                         case ns_t_key:
743                         case ns_t_cert:{
744                                 char *errmsg = NULL;
745
746                                 n  = parse_sec_rdata(buf, sizeof(buf), 1,
747                                                      (u_char *) data,
748                                                      sizeof(data),
749                                                      fp, zp, dname, ttl,
750                                                      type, domain_ctx,
751                                                      transport, &errmsg);
752                                 if (errmsg) {
753                                         err++;
754                                         endline(fp);
755                                         n = 0;
756                                 }
757                                 break;
758                         }
759                         default:
760                                 err++;
761                         }
762                         if (section == S_PREREQ) {
763                                 ttl = 0;
764                                 if (opcode == NXDOMAIN) {
765                                         class = C_NONE;
766                                         type = T_ANY;
767                                         n = 0;
768                                 } else if (opcode == YXDOMAIN) {
769                                         class = C_ANY;
770                                         type = T_ANY;
771                                         n = 0;
772                                 } else if (opcode == NXRRSET) {
773                                         class = C_NONE;
774                                         n = 0;
775                                 } else if (opcode == YXRRSET) {
776                                         if (n == 0)
777                                         class = C_ANY;
778                                 }
779                         } else {/* section == S_UPDATE */
780                                 if (opcode == DELETE) {
781                                         if (n == 0) {
782                                                 class = C_ANY;
783                                                 if (type == -1)
784                                                 type = T_ANY;
785                                         } else {
786                                                 class = zp->z_class;
787                                         }
788                                 }
789                         }
790                         break;
791                 case S_ADDT:
792                 default:
793                         ns_debug(ns_log_update, 1,
794                                  "cannot interpret section: %d", section);
795                         inside_next = 0;
796                         err++;
797                 }
798                 if (err) {
799                         inside_next = 0;
800                         ns_debug(ns_log_update, 1,
801                         "merge of update id %d failed due to error at line %d",
802                                  id, lineno);
803                         memset(&empty_from, 0, sizeof empty_from);
804                         free_rrecp(&listuprec, rcode, empty_from);
805                         continue;
806                 }
807                 rrecp = res_mkupdrec(section, dname, class, type, ttl);
808                 if (section != S_ZONE) {
809                         dp = savedata(class, type, ttl, (u_char *) data, n);
810                         dp->d_zone = zonenum;
811                         dp->d_cred = DB_C_ZONE;
812                         dp->d_clev = nlabels(zp->z_origin);
813                         rrecp->r_dp = dp;
814                         rrecp->r_opcode = opcode;
815                 } else {
816                         rrecp->r_zone = zonenum;
817                         rrecp->r_opcode = opcode;
818                 }
819
820                 /* remove add/delete pairs */
821                 if (section == S_UPDATE) {
822                         ns_updrec *arp;
823                         int foundmatch;
824
825                         arp = TAIL(listuprec);
826                         foundmatch = 0;
827                         while (arp) {
828                                 if (arp->r_section == S_UPDATE &&
829                                     ((arp->r_opcode == DELETE &&
830                                       opcode == ADD) ||
831                                      (opcode == DELETE &&
832                                       arp->r_opcode == ADD)) &&
833                                      arp->r_dp->d_type == dp->d_type &&
834                                      arp->r_dp->d_class == dp->d_class &&
835                                      arp->r_dp->d_ttl == dp->d_ttl &&
836                                      ns_samename(arp->r_dname, dname) == 1 &&
837                                      db_cmp(arp->r_dp, dp) == 0) {
838                                         db_freedata(dp);
839                                         db_freedata(arp->r_dp);
840                                         UNLINK(listuprec, arp, r_link);
841                                         res_freeupdrec(arp);
842                                         res_freeupdrec(rrecp);
843                                         foundmatch = 1;
844                                         break;
845                                 }
846                                 arp = PREV(arp, r_link);
847                         }
848                         if (foundmatch)
849                                 continue;
850                 }
851
852                 APPEND(listuprec, rrecp, r_link);
853                 /* Override zone number with current zone serial number */
854                 rrecp->r_zone = serial;
855         }   
856
857         if (err)
858                 return (DBIXFR_ERROR);
859
860         return (DBIXFR_END);
861 }