master.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/event.h>
00025 #include <isc/lex.h>
00026 #include <isc/magic.h>
00027 #include <isc/mem.h>
00028 #include <isc/print.h>
00029 #include <isc/serial.h>
00030 #include <isc/stdio.h>
00031 #include <isc/stdtime.h>
00032 #include <isc/string.h>
00033 #include <isc/task.h>
00034 #include <isc/util.h>
00035 
00036 #include <dns/callbacks.h>
00037 #include <dns/events.h>
00038 #include <dns/fixedname.h>
00039 #include <dns/master.h>
00040 #include <dns/name.h>
00041 #include <dns/rdata.h>
00042 #include <dns/rdataclass.h>
00043 #include <dns/rdatalist.h>
00044 #include <dns/rdataset.h>
00045 #include <dns/rdatastruct.h>
00046 #include <dns/rdatatype.h>
00047 #include <dns/result.h>
00048 #include <dns/soa.h>
00049 #include <dns/time.h>
00050 #include <dns/ttl.h>
00051 
00052 /*!
00053  * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ) structures
00054  * by these sizes when we need to.
00055  *
00056  */
00057 /*% RDLSZ reflects the number of different types with the same name expected. */
00058 #define RDLSZ 32
00059 /*%
00060  * RDSZ reflects the number of rdata expected at a give name that can fit into
00061  * 64k.
00062  */
00063 #define RDSZ 512
00064 
00065 #define NBUFS 4
00066 #define MAXWIRESZ 255
00067 
00068 /*%
00069  * Target buffer size and minimum target size.
00070  * MINTSIZ must be big enough to hold the largest rdata record.
00071  * \brief
00072  * TSIZ >= MINTSIZ
00073  */
00074 #define TSIZ (128*1024)
00075 /*%
00076  * max message size - header - root - type - class - ttl - rdlen
00077  */
00078 #define MINTSIZ DNS_RDATA_MAXLENGTH
00079 /*%
00080  * Size for tokens in the presentation format,
00081  * The largest tokens are the base64 blocks in KEY and CERT records,
00082  * Largest key allowed is about 1372 bytes but
00083  * there is no fixed upper bound on CERT records.
00084  * 2K is too small for some X.509s, 8K is overkill.
00085  */
00086 #define TOKENSIZ (8*1024)
00087 
00088 /*%
00089  * Buffers sizes for $GENERATE.
00090  */
00091 #define DNS_MASTER_LHS 2048
00092 #define DNS_MASTER_RHS MINTSIZ
00093 
00094 #define CHECKNAMESFAIL(x) (((x) & DNS_MASTER_CHECKNAMESFAIL) != 0)
00095 
00096 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
00097 
00098 typedef struct dns_incctx dns_incctx_t;
00099 
00100 /*%
00101  * Master file load state.
00102  */
00103 
00104 struct dns_loadctx {
00105         unsigned int            magic;
00106         isc_mem_t               *mctx;
00107         dns_masterformat_t      format;
00108 
00109         dns_rdatacallbacks_t    *callbacks;
00110         isc_task_t              *task;
00111         dns_loaddonefunc_t      done;
00112         void                    *done_arg;
00113 
00114         /* Common methods */
00115         isc_result_t            (*openfile)(dns_loadctx_t *lctx,
00116                                             const char *filename);
00117         isc_result_t            (*load)(dns_loadctx_t *lctx);
00118 
00119         /* Members used by all formats */
00120         isc_uint32_t            maxttl;
00121 
00122         /* Members specific to the text format: */
00123         isc_lex_t               *lex;
00124         isc_boolean_t           keep_lex;
00125         unsigned int            options;
00126         isc_boolean_t           ttl_known;
00127         isc_boolean_t           default_ttl_known;
00128         isc_boolean_t           warn_1035;
00129         isc_boolean_t           warn_tcr;
00130         isc_boolean_t           warn_sigexpired;
00131         isc_boolean_t           seen_include;
00132         isc_uint32_t            ttl;
00133         isc_uint32_t            default_ttl;
00134         dns_rdataclass_t        zclass;
00135         dns_fixedname_t         fixed_top;
00136         dns_name_t              *top;                   /*%< top of zone */
00137 
00138         /* Members specific to the raw format: */
00139         FILE                    *f;
00140         isc_boolean_t           first;
00141         dns_masterrawheader_t   header;
00142 
00143         /* Which fixed buffers we are using? */
00144         unsigned int            loop_cnt;               /*% records per quantum,
00145                                                          * 0 => all. */
00146         isc_boolean_t           canceled;
00147         isc_mutex_t             lock;
00148         isc_result_t            result;
00149         /* locked by lock */
00150         isc_uint32_t            references;
00151         dns_incctx_t            *inc;
00152         isc_uint32_t            resign;
00153 
00154         dns_masterincludecb_t   include_cb;
00155         void                    *include_arg;
00156 };
00157 
00158 struct dns_incctx {
00159         dns_incctx_t            *parent;
00160         dns_name_t              *origin;
00161         dns_name_t              *current;
00162         dns_name_t              *glue;
00163         dns_fixedname_t         fixed[NBUFS];           /* working buffers */
00164         unsigned int            in_use[NBUFS];          /* covert to bitmap? */
00165         int                     glue_in_use;
00166         int                     current_in_use;
00167         int                     origin_in_use;
00168         isc_boolean_t           origin_changed;
00169         isc_boolean_t           drop;
00170         unsigned int            glue_line;
00171         unsigned int            current_line;
00172 };
00173 
00174 #define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
00175 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
00176 
00177 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
00178 
00179 static isc_result_t
00180 openfile_text(dns_loadctx_t *lctx, const char *master_file);
00181 
00182 static isc_result_t
00183 load_text(dns_loadctx_t *lctx);
00184 
00185 static isc_result_t
00186 openfile_raw(dns_loadctx_t *lctx, const char *master_file);
00187 
00188 static isc_result_t
00189 load_raw(dns_loadctx_t *lctx);
00190 
00191 static isc_result_t
00192 openfile_map(dns_loadctx_t *lctx, const char *master_file);
00193 
00194 static isc_result_t
00195 load_map(dns_loadctx_t *lctx);
00196 
00197 static isc_result_t
00198 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
00199 
00200 static isc_result_t
00201 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
00202        dns_name_t *, const char *, unsigned int);
00203 
00204 static isc_boolean_t
00205 is_glue(rdatalist_head_t *, dns_name_t *);
00206 
00207 static dns_rdatalist_t *
00208 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
00209                 rdatalist_head_t *, isc_mem_t *mctx);
00210 
00211 static dns_rdata_t *
00212 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
00213            isc_mem_t *);
00214 
00215 static void
00216 load_quantum(isc_task_t *task, isc_event_t *event);
00217 
00218 static isc_result_t
00219 task_send(dns_loadctx_t *lctx);
00220 
00221 static void
00222 loadctx_destroy(dns_loadctx_t *lctx);
00223 
00224 #define GETTOKENERR(lexer, options, token, eol, err) \
00225         do { \
00226                 result = gettoken(lexer, options, token, eol, callbacks); \
00227                 switch (result) { \
00228                 case ISC_R_SUCCESS: \
00229                         break; \
00230                 case ISC_R_UNEXPECTED: \
00231                         goto insist_and_cleanup; \
00232                 default: \
00233                         if (MANYERRS(lctx, result)) { \
00234                                 SETRESULT(lctx, result); \
00235                                 LOGIT(result); \
00236                                 read_till_eol = ISC_TRUE; \
00237                                 err \
00238                                 goto next_line; \
00239                         } else \
00240                                 goto log_and_cleanup; \
00241                 } \
00242                 if ((token)->type == isc_tokentype_special) { \
00243                         result = DNS_R_SYNTAX; \
00244                         if (MANYERRS(lctx, result)) { \
00245                                 SETRESULT(lctx, result); \
00246                                 LOGIT(result); \
00247                                 read_till_eol = ISC_TRUE; \
00248                                 goto next_line; \
00249                         } else \
00250                                 goto log_and_cleanup; \
00251                 } \
00252         } while (0)
00253 #define GETTOKEN(lexer, options, token, eol) \
00254         GETTOKENERR(lexer, options, token, eol, {} )
00255 
00256 #define COMMITALL \
00257         do { \
00258                 result = commit(callbacks, lctx, &current_list, \
00259                                 ictx->current, source, ictx->current_line); \
00260                 if (MANYERRS(lctx, result)) { \
00261                         SETRESULT(lctx, result); \
00262                 } else if (result != ISC_R_SUCCESS) \
00263                         goto insist_and_cleanup; \
00264                 result = commit(callbacks, lctx, &glue_list, \
00265                                 ictx->glue, source, ictx->glue_line); \
00266                 if (MANYERRS(lctx, result)) { \
00267                         SETRESULT(lctx, result); \
00268                 } else if (result != ISC_R_SUCCESS) \
00269                         goto insist_and_cleanup; \
00270                 rdcount = 0; \
00271                 rdlcount = 0; \
00272                 isc_buffer_init(&target, target_mem, target_size); \
00273                 rdcount_save = rdcount; \
00274                 rdlcount_save = rdlcount; \
00275         } while (0)
00276 
00277 #define WARNUNEXPECTEDEOF(lexer) \
00278         do { \
00279                 if (isc_lex_isfile(lexer)) \
00280                         (*callbacks->warn)(callbacks, \
00281                                 "%s: file does not end with newline", \
00282                                 source); \
00283         } while (0)
00284 
00285 #define EXPECTEOL \
00286         do { \
00287                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
00288                 if (token.type != isc_tokentype_eol) { \
00289                         isc_lex_ungettoken(lctx->lex, &token); \
00290                         result = DNS_R_EXTRATOKEN; \
00291                         if (MANYERRS(lctx, result)) { \
00292                                 SETRESULT(lctx, result); \
00293                                 LOGIT(result); \
00294                                 read_till_eol = ISC_TRUE; \
00295                                 continue; \
00296                         } else if (result != ISC_R_SUCCESS) \
00297                                 goto log_and_cleanup; \
00298                 } \
00299         } while (0)
00300 
00301 #define MANYERRS(lctx, result) \
00302                 ((result != ISC_R_SUCCESS) && \
00303                  (result != ISC_R_IOERROR) && \
00304                  ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
00305 
00306 #define SETRESULT(lctx, r) \
00307                 do { \
00308                         if ((lctx)->result == ISC_R_SUCCESS) \
00309                                 (lctx)->result = r; \
00310                 } while (0)
00311 
00312 #define LOGITFILE(result, filename) \
00313         if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
00314             result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
00315             result == ISC_R_NOPERM) \
00316                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
00317                                     "dns_master_load", source, line, \
00318                                     filename, dns_result_totext(result)); \
00319         else LOGIT(result)
00320 
00321 #define LOGIT(result) \
00322         if (result == ISC_R_NOMEMORY) \
00323                 (*callbacks->error)(callbacks, "dns_master_load: %s", \
00324                                     dns_result_totext(result)); \
00325         else \
00326                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
00327                                     "dns_master_load", \
00328                                     source, line, dns_result_totext(result))
00329 
00330 
00331 static unsigned char in_addr_arpa_data[]  = "\007IN-ADDR\004ARPA";
00332 static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
00333 static const dns_name_t in_addr_arpa =
00334 {
00335         DNS_NAME_MAGIC,
00336         in_addr_arpa_data, 14, 3,
00337         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
00338         in_addr_arpa_offsets, NULL,
00339         {(void *)-1, (void *)-1},
00340         {NULL, NULL}
00341 };
00342 
00343 static unsigned char ip6_int_data[]  = "\003IP6\003INT";
00344 static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
00345 static const dns_name_t ip6_int =
00346 {
00347         DNS_NAME_MAGIC,
00348         ip6_int_data, 9, 3,
00349         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
00350         ip6_int_offsets, NULL,
00351         {(void *)-1, (void *)-1},
00352         {NULL, NULL}
00353 };
00354 
00355 static unsigned char ip6_arpa_data[]  = "\003IP6\004ARPA";
00356 static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
00357 static const dns_name_t ip6_arpa =
00358 {
00359         DNS_NAME_MAGIC,
00360         ip6_arpa_data, 10, 3,
00361         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
00362         ip6_arpa_offsets, NULL,
00363         {(void *)-1, (void *)-1},
00364         {NULL, NULL}
00365 };
00366 
00367 
00368 static inline isc_result_t
00369 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
00370          isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
00371 {
00372         isc_result_t result;
00373 
00374         options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
00375                 ISC_LEXOPT_ESCAPE;
00376         result = isc_lex_gettoken(lex, options, token);
00377         if (result != ISC_R_SUCCESS) {
00378                 switch (result) {
00379                 case ISC_R_NOMEMORY:
00380                         return (ISC_R_NOMEMORY);
00381                 default:
00382                         (*callbacks->error)(callbacks,
00383                                             "dns_master_load: %s:%lu:"
00384                                             " isc_lex_gettoken() failed: %s",
00385                                             isc_lex_getsourcename(lex),
00386                                             isc_lex_getsourceline(lex),
00387                                             isc_result_totext(result));
00388                         return (result);
00389                 }
00390                 /*NOTREACHED*/
00391         }
00392         if (eol != ISC_TRUE)
00393                 if (token->type == isc_tokentype_eol ||
00394                     token->type == isc_tokentype_eof) {
00395                         unsigned long int line;
00396                         const char *what;
00397                         const char *file;
00398                         file = isc_lex_getsourcename(lex);
00399                         line = isc_lex_getsourceline(lex);
00400                         if (token->type == isc_tokentype_eol) {
00401                                 line--;
00402                                 what = "line";
00403                         } else
00404                                 what = "file";
00405                         (*callbacks->error)(callbacks,
00406                             "dns_master_load: %s:%lu: unexpected end of %s",
00407                                             file, line, what);
00408                         return (ISC_R_UNEXPECTEDEND);
00409                 }
00410         return (ISC_R_SUCCESS);
00411 }
00412 
00413 
00414 void
00415 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
00416 
00417         REQUIRE(target != NULL && *target == NULL);
00418         REQUIRE(DNS_LCTX_VALID(source));
00419 
00420         LOCK(&source->lock);
00421         INSIST(source->references > 0);
00422         source->references++;
00423         INSIST(source->references != 0);        /* Overflow? */
00424         UNLOCK(&source->lock);
00425 
00426         *target = source;
00427 }
00428 
00429 void
00430 dns_loadctx_detach(dns_loadctx_t **lctxp) {
00431         dns_loadctx_t *lctx;
00432         isc_boolean_t need_destroy = ISC_FALSE;
00433 
00434         REQUIRE(lctxp != NULL);
00435         lctx = *lctxp;
00436         REQUIRE(DNS_LCTX_VALID(lctx));
00437 
00438         LOCK(&lctx->lock);
00439         INSIST(lctx->references > 0);
00440         lctx->references--;
00441         if (lctx->references == 0)
00442                 need_destroy = ISC_TRUE;
00443         UNLOCK(&lctx->lock);
00444 
00445         if (need_destroy)
00446                 loadctx_destroy(lctx);
00447         *lctxp = NULL;
00448 }
00449 
00450 static void
00451 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
00452         dns_incctx_t *parent;
00453 
00454  again:
00455         parent = ictx->parent;
00456         ictx->parent = NULL;
00457 
00458         isc_mem_put(mctx, ictx, sizeof(*ictx));
00459 
00460         if (parent != NULL) {
00461                 ictx = parent;
00462                 goto again;
00463         }
00464 }
00465 
00466 static void
00467 loadctx_destroy(dns_loadctx_t *lctx) {
00468         isc_mem_t *mctx;
00469         isc_result_t result;
00470 
00471         REQUIRE(DNS_LCTX_VALID(lctx));
00472 
00473         lctx->magic = 0;
00474         if (lctx->inc != NULL)
00475                 incctx_destroy(lctx->mctx, lctx->inc);
00476 
00477         if (lctx->f != NULL) {
00478                 result = isc_stdio_close(lctx->f);
00479                 if (result != ISC_R_SUCCESS) {
00480                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00481                                          "isc_stdio_close() failed: %s",
00482                                          isc_result_totext(result));
00483                 }
00484         }
00485 
00486         /* isc_lex_destroy() will close all open streams */
00487         if (lctx->lex != NULL && !lctx->keep_lex)
00488                 isc_lex_destroy(&lctx->lex);
00489 
00490         if (lctx->task != NULL)
00491                 isc_task_detach(&lctx->task);
00492         DESTROYLOCK(&lctx->lock);
00493         mctx = NULL;
00494         isc_mem_attach(lctx->mctx, &mctx);
00495         isc_mem_detach(&lctx->mctx);
00496         isc_mem_put(mctx, lctx, sizeof(*lctx));
00497         isc_mem_detach(&mctx);
00498 }
00499 
00500 static isc_result_t
00501 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
00502         dns_incctx_t *ictx;
00503         isc_region_t r;
00504         int i;
00505 
00506         ictx = isc_mem_get(mctx, sizeof(*ictx));
00507         if (ictx == NULL)
00508                 return (ISC_R_NOMEMORY);
00509 
00510         for (i = 0; i < NBUFS; i++) {
00511                 dns_fixedname_init(&ictx->fixed[i]);
00512                 ictx->in_use[i] = ISC_FALSE;
00513         }
00514 
00515         ictx->origin_in_use = 0;
00516         ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
00517         ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
00518         dns_name_toregion(origin, &r);
00519         dns_name_fromregion(ictx->origin, &r);
00520 
00521         ictx->glue = NULL;
00522         ictx->current = NULL;
00523         ictx->glue_in_use = -1;
00524         ictx->current_in_use = -1;
00525         ictx->parent = NULL;
00526         ictx->drop = ISC_FALSE;
00527         ictx->glue_line = 0;
00528         ictx->current_line = 0;
00529         ictx->origin_changed = ISC_TRUE;
00530 
00531         *ictxp = ictx;
00532         return (ISC_R_SUCCESS);
00533 }
00534 
00535 static isc_result_t
00536 loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
00537                unsigned int options, isc_uint32_t resign, dns_name_t *top,
00538                dns_rdataclass_t zclass, dns_name_t *origin,
00539                dns_rdatacallbacks_t *callbacks, isc_task_t *task,
00540                dns_loaddonefunc_t done, void *done_arg,
00541                dns_masterincludecb_t include_cb, void *include_arg,
00542                isc_lex_t *lex, dns_loadctx_t **lctxp)
00543 {
00544         dns_loadctx_t *lctx;
00545         isc_result_t result;
00546         isc_region_t r;
00547         isc_lexspecials_t specials;
00548 
00549         REQUIRE(lctxp != NULL && *lctxp == NULL);
00550         REQUIRE(callbacks != NULL);
00551         REQUIRE(callbacks->add != NULL);
00552         REQUIRE(callbacks->error != NULL);
00553         REQUIRE(callbacks->warn != NULL);
00554         REQUIRE(mctx != NULL);
00555         REQUIRE(dns_name_isabsolute(top));
00556         REQUIRE(dns_name_isabsolute(origin));
00557         REQUIRE((task == NULL && done == NULL) ||
00558                 (task != NULL && done != NULL));
00559 
00560         lctx = isc_mem_get(mctx, sizeof(*lctx));
00561         if (lctx == NULL)
00562                 return (ISC_R_NOMEMORY);
00563         result = isc_mutex_init(&lctx->lock);
00564         if (result != ISC_R_SUCCESS) {
00565                 isc_mem_put(mctx, lctx, sizeof(*lctx));
00566                 return (result);
00567         }
00568 
00569         lctx->inc = NULL;
00570         result = incctx_create(mctx, origin, &lctx->inc);
00571         if (result != ISC_R_SUCCESS)
00572                 goto cleanup_ctx;
00573 
00574         lctx->maxttl = 0;
00575 
00576         lctx->format = format;
00577         switch (format) {
00578         default:
00579                 INSIST(0);
00580         case dns_masterformat_text:
00581                 lctx->openfile = openfile_text;
00582                 lctx->load = load_text;
00583                 break;
00584         case dns_masterformat_raw:
00585                 lctx->openfile = openfile_raw;
00586                 lctx->load = load_raw;
00587                 break;
00588         case dns_masterformat_map:
00589                 lctx->openfile = openfile_map;
00590                 lctx->load = load_map;
00591                 break;
00592         }
00593 
00594         if (lex != NULL) {
00595                 lctx->lex = lex;
00596                 lctx->keep_lex = ISC_TRUE;
00597         } else {
00598                 lctx->lex = NULL;
00599                 result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
00600                 if (result != ISC_R_SUCCESS)
00601                         goto cleanup_inc;
00602                 lctx->keep_lex = ISC_FALSE;
00603                 memset(specials, 0, sizeof(specials));
00604                 specials[0] = 1;
00605                 specials['('] = 1;
00606                 specials[')'] = 1;
00607                 specials['"'] = 1;
00608                 isc_lex_setspecials(lctx->lex, specials);
00609                 isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
00610         }
00611 
00612         lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0);
00613         lctx->ttl = 0;
00614         lctx->default_ttl_known = lctx->ttl_known;
00615         lctx->default_ttl = 0;
00616         lctx->warn_1035 = ISC_TRUE;     /* XXX Argument? */
00617         lctx->warn_tcr = ISC_TRUE;      /* XXX Argument? */
00618         lctx->warn_sigexpired = ISC_TRUE;       /* XXX Argument? */
00619         lctx->options = options;
00620         lctx->seen_include = ISC_FALSE;
00621         lctx->zclass = zclass;
00622         lctx->resign = resign;
00623         lctx->result = ISC_R_SUCCESS;
00624         lctx->include_cb = include_cb;
00625         lctx->include_arg = include_arg;
00626 
00627         dns_fixedname_init(&lctx->fixed_top);
00628         lctx->top = dns_fixedname_name(&lctx->fixed_top);
00629         dns_name_toregion(top, &r);
00630         dns_name_fromregion(lctx->top, &r);
00631 
00632         lctx->f = NULL;
00633         lctx->first = ISC_TRUE;
00634         dns_master_initrawheader(&lctx->header);
00635 
00636         lctx->loop_cnt = (done != NULL) ? 100 : 0;
00637         lctx->callbacks = callbacks;
00638         lctx->task = NULL;
00639         if (task != NULL)
00640                 isc_task_attach(task, &lctx->task);
00641         lctx->done = done;
00642         lctx->done_arg = done_arg;
00643         lctx->canceled = ISC_FALSE;
00644         lctx->mctx = NULL;
00645         isc_mem_attach(mctx, &lctx->mctx);
00646         lctx->references = 1;                   /* Implicit attach. */
00647         lctx->magic = DNS_LCTX_MAGIC;
00648         *lctxp = lctx;
00649         return (ISC_R_SUCCESS);
00650 
00651  cleanup_inc:
00652         incctx_destroy(mctx, lctx->inc);
00653  cleanup_ctx:
00654         isc_mem_put(mctx, lctx, sizeof(*lctx));
00655         return (result);
00656 }
00657 
00658 static const char *hex = "0123456789abcdef0123456789ABCDEF";
00659 
00660 /*%
00661  * Convert value into a nibble sequence from least significant to most
00662  * significant nibble.  Zero fill upper most significant nibbles if
00663  * required to make the width.
00664  *
00665  * Returns the number of characters that should have been written without
00666  * counting the terminating NUL.
00667  */
00668 static unsigned int
00669 nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) {
00670         unsigned int count = 0;
00671 
00672         /*
00673          * This reserve space for the NUL string terminator.
00674          */
00675         if (length > 0U) {
00676                 *numbuf = '\0';
00677                 length--;
00678         }
00679         do {
00680                 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)];
00681                 value >>= 4;
00682                 if (length > 0U) {
00683                         *numbuf++ = val;
00684                         *numbuf = '\0';
00685                         length--;
00686                 }
00687                 if (width > 0)
00688                         width--;
00689                 count++;
00690                 /*
00691                  * If width is non zero then we need to add a label seperator.
00692                  * If value is non zero then we need to add another label and
00693                  * that requires a label seperator.
00694                  */
00695                 if (width > 0 || value != 0) {
00696                         if (length > 0U) {
00697                                 *numbuf++ = '.';
00698                                 *numbuf = '\0';
00699                                 length--;
00700                         }
00701                         if (width > 0)
00702                                 width--;
00703                         count++;
00704                 }
00705         } while (value != 0 || width > 0);
00706         return (count);
00707 }
00708 
00709 static isc_result_t
00710 genname(char *name, int it, char *buffer, size_t length) {
00711         char fmt[sizeof("%04000000000d")];
00712         char numbuf[128];
00713         char *cp;
00714         char mode[2];
00715         int delta = 0;
00716         isc_textregion_t r;
00717         unsigned int n;
00718         unsigned int width;
00719         isc_boolean_t nibblemode;
00720 
00721         r.base = buffer;
00722         r.length = (unsigned int)length;
00723 
00724         while (*name != '\0') {
00725                 if (*name == '$') {
00726                         name++;
00727                         if (*name == '$') {
00728                                 if (r.length == 0)
00729                                         return (ISC_R_NOSPACE);
00730                                 r.base[0] = *name++;
00731                                 isc_textregion_consume(&r, 1);
00732                                 continue;
00733                         }
00734                         nibblemode = ISC_FALSE;
00735                         strcpy(fmt, "%d");
00736                         /* Get format specifier. */
00737                         if (*name == '{' ) {
00738                                 n = sscanf(name, "{%d,%u,%1[doxXnN]}",
00739                                            &delta, &width, mode);
00740                                 switch (n) {
00741                                 case 1:
00742                                         break;
00743                                 case 2:
00744                                         n = snprintf(fmt, sizeof(fmt),
00745                                                      "%%0%ud", width);
00746                                         break;
00747                                 case 3:
00748                                         if (mode[0] == 'n' || mode[0] == 'N')
00749                                                 nibblemode = ISC_TRUE;
00750                                         n = snprintf(fmt, sizeof(fmt),
00751                                                      "%%0%u%c", width, mode[0]);
00752                                         break;
00753                                 default:
00754                                         return (DNS_R_SYNTAX);
00755                                 }
00756                                 if (n >= sizeof(fmt))
00757                                         return (ISC_R_NOSPACE);
00758                                 /* Skip past closing brace. */
00759                                 while (*name != '\0' && *name++ != '}')
00760                                         continue;
00761                         }
00762                         if (nibblemode)
00763                                 n = nibbles(numbuf, sizeof(numbuf), width,
00764                                             mode[0], it + delta);
00765                         else
00766                                 n = snprintf(numbuf, sizeof(numbuf), fmt,
00767                                              it + delta);
00768                         if (n >= sizeof(numbuf))
00769                                 return (ISC_R_NOSPACE);
00770                         cp = numbuf;
00771                         while (*cp != '\0') {
00772                                 if (r.length == 0)
00773                                         return (ISC_R_NOSPACE);
00774                                 r.base[0] = *cp++;
00775                                 isc_textregion_consume(&r, 1);
00776                         }
00777                 } else if (*name == '\\') {
00778                         if (r.length == 0)
00779                                 return (ISC_R_NOSPACE);
00780                         r.base[0] = *name++;
00781                         isc_textregion_consume(&r, 1);
00782                         if (*name == '\0')
00783                                 continue;
00784                         if (r.length == 0)
00785                                 return (ISC_R_NOSPACE);
00786                         r.base[0] = *name++;
00787                         isc_textregion_consume(&r, 1);
00788                 } else {
00789                         if (r.length == 0)
00790                                 return (ISC_R_NOSPACE);
00791                         r.base[0] = *name++;
00792                         isc_textregion_consume(&r, 1);
00793                 }
00794         }
00795         if (r.length == 0)
00796                 return (ISC_R_NOSPACE);
00797         r.base[0] = '\0';
00798         return (ISC_R_SUCCESS);
00799 }
00800 
00801 static isc_result_t
00802 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
00803          const char *source, unsigned int line)
00804 {
00805         char *target_mem = NULL;
00806         char *lhsbuf = NULL;
00807         char *rhsbuf = NULL;
00808         dns_fixedname_t ownerfixed;
00809         dns_name_t *owner;
00810         dns_rdata_t rdata = DNS_RDATA_INIT;
00811         dns_rdatacallbacks_t *callbacks;
00812         dns_rdatalist_t rdatalist;
00813         dns_rdatatype_t type;
00814         rdatalist_head_t head;
00815         int target_size = MINTSIZ;      /* only one rdata at a time */
00816         isc_buffer_t buffer;
00817         isc_buffer_t target;
00818         isc_result_t result;
00819         isc_textregion_t r;
00820         int i, n, start, stop, step = 0;
00821         dns_incctx_t *ictx;
00822         char dummy;
00823 
00824         ictx = lctx->inc;
00825         callbacks = lctx->callbacks;
00826         dns_fixedname_init(&ownerfixed);
00827         owner = dns_fixedname_name(&ownerfixed);
00828         ISC_LIST_INIT(head);
00829 
00830         target_mem = isc_mem_get(lctx->mctx, target_size);
00831         rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS);
00832         lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS);
00833         if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
00834                 result = ISC_R_NOMEMORY;
00835                 goto error_cleanup;
00836         }
00837         isc_buffer_init(&target, target_mem, target_size);
00838 
00839         n = sscanf(range, "%d-%d%[/]%d", &start, &stop, &dummy, &step);
00840         if ((n != 2 && n != 4) || (start < 0) || (stop < 0) ||
00841              (n == 4 && step < 1) || (stop < start))
00842         {
00843                (*callbacks->error)(callbacks,
00844                                   "%s: %s:%lu: invalid range '%s'",
00845                                   "$GENERATE", source, line, range);
00846                 result = DNS_R_SYNTAX;
00847                 goto insist_cleanup;
00848         }
00849         if (n == 2)
00850                 step = 1;
00851 
00852         /*
00853          * Get type.
00854          */
00855         r.base = gtype;
00856         r.length = strlen(gtype);
00857         result = dns_rdatatype_fromtext(&type, &r);
00858         if (result != ISC_R_SUCCESS) {
00859                 (*callbacks->error)(callbacks,
00860                                    "%s: %s:%lu: unknown RR type '%s'",
00861                                    "$GENERATE", source, line, gtype);
00862                 goto insist_cleanup;
00863         }
00864 
00865         for (i = start; i <= stop; i += step) {
00866                 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS);
00867                 if (result != ISC_R_SUCCESS)
00868                         goto error_cleanup;
00869                 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS);
00870                 if (result != ISC_R_SUCCESS)
00871                         goto error_cleanup;
00872 
00873                 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
00874                 isc_buffer_add(&buffer, strlen(lhsbuf));
00875                 isc_buffer_setactive(&buffer, strlen(lhsbuf));
00876                 result = dns_name_fromtext(owner, &buffer, ictx->origin,
00877                                            0, NULL);
00878                 if (result != ISC_R_SUCCESS)
00879                         goto error_cleanup;
00880 
00881                 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
00882                     (lctx->options & DNS_MASTER_SLAVE) == 0 &&
00883                     (lctx->options & DNS_MASTER_KEY) == 0 &&
00884                     !dns_name_issubdomain(owner, lctx->top))
00885                 {
00886                         char namebuf[DNS_NAME_FORMATSIZE];
00887                         dns_name_format(owner, namebuf, sizeof(namebuf));
00888                         /*
00889                          * Ignore out-of-zone data.
00890                          */
00891                         (*callbacks->warn)(callbacks,
00892                                            "%s:%lu: "
00893                                            "ignoring out-of-zone data (%s)",
00894                                            source, line, namebuf);
00895                         continue;
00896                 }
00897 
00898                 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
00899                 isc_buffer_add(&buffer, strlen(rhsbuf));
00900                 isc_buffer_setactive(&buffer, strlen(rhsbuf));
00901 
00902                 result = isc_lex_openbuffer(lctx->lex, &buffer);
00903                 if (result != ISC_R_SUCCESS)
00904                         goto error_cleanup;
00905 
00906                 isc_buffer_init(&target, target_mem, target_size);
00907                 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
00908                                             lctx->lex, ictx->origin, 0,
00909                                             lctx->mctx, &target, callbacks);
00910                 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
00911                 if (result != ISC_R_SUCCESS)
00912                         goto error_cleanup;
00913 
00914                 dns_rdatalist_init(&rdatalist);
00915                 rdatalist.type = type;
00916                 rdatalist.rdclass = lctx->zclass;
00917                 rdatalist.ttl = lctx->ttl;
00918                 ISC_LIST_PREPEND(head, &rdatalist, link);
00919                 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
00920                 result = commit(callbacks, lctx, &head, owner, source, line);
00921                 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
00922                 if (result != ISC_R_SUCCESS)
00923                         goto error_cleanup;
00924                 dns_rdata_reset(&rdata);
00925         }
00926         result = ISC_R_SUCCESS;
00927         goto cleanup;
00928 
00929  error_cleanup:
00930         if (result == ISC_R_NOMEMORY)
00931                 (*callbacks->error)(callbacks, "$GENERATE: %s",
00932                                     dns_result_totext(result));
00933         else
00934                 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
00935                                     source, line, dns_result_totext(result));
00936 
00937  insist_cleanup:
00938         INSIST(result != ISC_R_SUCCESS);
00939 
00940  cleanup:
00941         if (target_mem != NULL)
00942                 isc_mem_put(lctx->mctx, target_mem, target_size);
00943         if (lhsbuf != NULL)
00944                 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS);
00945         if (rhsbuf != NULL)
00946                 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS);
00947         return (result);
00948 }
00949 
00950 static void
00951 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source,
00952           unsigned int line, isc_uint32_t *ttlp)
00953 {
00954         if (*ttlp > 0x7fffffffUL) {
00955                 (callbacks->warn)(callbacks,
00956                                   "%s: %s:%lu: "
00957                                   "$TTL %lu > MAXTTL, "
00958                                   "setting $TTL to 0",
00959                                   "dns_master_load",
00960                                   source, line,
00961                                   *ttlp);
00962                 *ttlp = 0;
00963         }
00964 }
00965 
00966 static isc_result_t
00967 check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
00968          unsigned long line)
00969 {
00970         char *tmp = NULL;
00971         isc_result_t result = ISC_R_SUCCESS;
00972         void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
00973 
00974         if ((lctx->options & DNS_MASTER_FATALNS) != 0)
00975                 callback = lctx->callbacks->error;
00976         else
00977                 callback = lctx->callbacks->warn;
00978 
00979         if (token->type == isc_tokentype_string) {
00980                 struct in_addr addr;
00981                 struct in6_addr addr6;
00982 
00983                 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
00984                 if (tmp == NULL)
00985                         return (ISC_R_NOMEMORY);
00986                 /*
00987                  * Catch both "1.2.3.4" and "1.2.3.4."
00988                  */
00989                 if (tmp[strlen(tmp) - 1] == '.')
00990                         tmp[strlen(tmp) - 1] = '\0';
00991                 if (inet_aton(tmp, &addr) == 1 ||
00992                     inet_pton(AF_INET6, tmp, &addr6) == 1)
00993                         result = DNS_R_NSISADDRESS;
00994         }
00995         if (result != ISC_R_SUCCESS)
00996                 (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' "
00997                             "appears to be an address",
00998                             source, line, DNS_AS_STR(*token));
00999         if (tmp != NULL)
01000                 isc_mem_free(lctx->mctx, tmp);
01001         return (result);
01002 }
01003 
01004 static void
01005 check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
01006                dns_rdatacallbacks_t *callbacks)
01007 {
01008         dns_name_t *name;
01009 
01010         name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
01011         if (dns_name_internalwildcard(name)) {
01012                 char namebuf[DNS_NAME_FORMATSIZE];
01013 
01014                 dns_name_format(name, namebuf, sizeof(namebuf));
01015                 (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername "
01016                                    "'%s' contains an non-terminal wildcard",
01017                                    source, line, namebuf);
01018         }
01019 }
01020 
01021 static isc_result_t
01022 openfile_text(dns_loadctx_t *lctx, const char *master_file) {
01023         return (isc_lex_openfile(lctx->lex, master_file));
01024 }
01025 
01026 static isc_result_t
01027 load_text(dns_loadctx_t *lctx) {
01028         dns_rdataclass_t rdclass;
01029         dns_rdatatype_t type, covers;
01030         isc_uint32_t ttl_offset = 0;
01031         dns_name_t *new_name;
01032         isc_boolean_t current_has_delegation = ISC_FALSE;
01033         isc_boolean_t done = ISC_FALSE;
01034         isc_boolean_t finish_origin = ISC_FALSE;
01035         isc_boolean_t finish_include = ISC_FALSE;
01036         isc_boolean_t read_till_eol = ISC_FALSE;
01037         isc_boolean_t initialws;
01038         char *include_file = NULL;
01039         isc_token_t token;
01040         isc_result_t result = ISC_R_UNEXPECTED;
01041         rdatalist_head_t glue_list;
01042         rdatalist_head_t current_list;
01043         dns_rdatalist_t *this;
01044         dns_rdatalist_t *rdatalist = NULL;
01045         dns_rdatalist_t *new_rdatalist;
01046         int rdlcount = 0;
01047         int rdlcount_save = 0;
01048         int rdatalist_size = 0;
01049         isc_buffer_t buffer;
01050         isc_buffer_t target;
01051         isc_buffer_t target_ft;
01052         isc_buffer_t target_save;
01053         dns_rdata_t *rdata = NULL;
01054         dns_rdata_t *new_rdata;
01055         int rdcount = 0;
01056         int rdcount_save = 0;
01057         int rdata_size = 0;
01058         unsigned char *target_mem = NULL;
01059         int target_size = TSIZ;
01060         int new_in_use;
01061         unsigned int loop_cnt = 0;
01062         isc_mem_t *mctx;
01063         dns_rdatacallbacks_t *callbacks;
01064         dns_incctx_t *ictx;
01065         char *range = NULL;
01066         char *lhs = NULL;
01067         char *gtype = NULL;
01068         char *rhs = NULL;
01069         const char *source = "";
01070         unsigned long line = 0;
01071         isc_boolean_t explicit_ttl;
01072         isc_stdtime_t now;
01073         char classname1[DNS_RDATACLASS_FORMATSIZE];
01074         char classname2[DNS_RDATACLASS_FORMATSIZE];
01075         unsigned int options = 0;
01076 
01077         REQUIRE(DNS_LCTX_VALID(lctx));
01078         callbacks = lctx->callbacks;
01079         mctx = lctx->mctx;
01080         ictx = lctx->inc;
01081 
01082         ISC_LIST_INIT(glue_list);
01083         ISC_LIST_INIT(current_list);
01084 
01085         isc_stdtime_get(&now);
01086 
01087         /*
01088          * Allocate target_size of buffer space.  This is greater than twice
01089          * the maximum individual RR data size.
01090          */
01091         target_mem = isc_mem_get(mctx, target_size);
01092         if (target_mem == NULL) {
01093                 result = ISC_R_NOMEMORY;
01094                 goto log_and_cleanup;
01095         }
01096         isc_buffer_init(&target, target_mem, target_size);
01097         target_save = target;
01098 
01099         if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0)
01100                 options |= DNS_RDATA_CHECKNAMES;
01101         if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
01102                 options |= DNS_RDATA_CHECKNAMESFAIL;
01103         if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
01104                 options |= DNS_RDATA_CHECKMX;
01105         if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
01106                 options |= DNS_RDATA_CHECKMXFAIL;
01107         source = isc_lex_getsourcename(lctx->lex);
01108         do {
01109                 initialws = ISC_FALSE;
01110                 line = isc_lex_getsourceline(lctx->lex);
01111                 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
01112                          &token, ISC_TRUE);
01113                 line = isc_lex_getsourceline(lctx->lex);
01114 
01115                 if (token.type == isc_tokentype_eof) {
01116                         if (read_till_eol)
01117                                 WARNUNEXPECTEDEOF(lctx->lex);
01118                         /* Pop the include stack? */
01119                         if (ictx->parent != NULL) {
01120                                 COMMITALL;
01121                                 lctx->inc = ictx->parent;
01122                                 ictx->parent = NULL;
01123                                 incctx_destroy(lctx->mctx, ictx);
01124                                 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
01125                                 line = isc_lex_getsourceline(lctx->lex);
01126                                 source = isc_lex_getsourcename(lctx->lex);
01127                                 ictx = lctx->inc;
01128                                 continue;
01129                         }
01130                         done = ISC_TRUE;
01131                         continue;
01132                 }
01133 
01134                 if (token.type == isc_tokentype_eol) {
01135                         read_till_eol = ISC_FALSE;
01136                         continue;               /* blank line */
01137                 }
01138 
01139                 if (read_till_eol)
01140                         continue;
01141 
01142                 if (token.type == isc_tokentype_initialws) {
01143                         /*
01144                          * Still working on the same name.
01145                          */
01146                         initialws = ISC_TRUE;
01147                 } else if (token.type == isc_tokentype_string ||
01148                            token.type == isc_tokentype_qstring) {
01149 
01150                         /*
01151                          * "$" Support.
01152                          *
01153                          * "$ORIGIN" and "$INCLUDE" can both take domain names.
01154                          * The processing of "$ORIGIN" and "$INCLUDE" extends
01155                          * across the normal domain name processing.
01156                          */
01157 
01158                         if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
01159                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01160                                 finish_origin = ISC_TRUE;
01161                         } else if (strcasecmp(DNS_AS_STR(token),
01162                                               "$TTL") == 0) {
01163                                 GETTOKENERR(lctx->lex, 0, &token, ISC_FALSE,
01164                                             lctx->ttl = 0;
01165                                             lctx->default_ttl_known = ISC_TRUE;);
01166                                 result =
01167                                    dns_ttl_fromtext(&token.value.as_textregion,
01168                                                     &lctx->ttl);
01169                                 if (MANYERRS(lctx, result)) {
01170                                         SETRESULT(lctx, result);
01171                                         lctx->ttl = 0;
01172                                 } else if (result != ISC_R_SUCCESS)
01173                                         goto insist_and_cleanup;
01174                                 limit_ttl(callbacks, source, line, &lctx->ttl);
01175                                 lctx->default_ttl = lctx->ttl;
01176                                 lctx->default_ttl_known = ISC_TRUE;
01177                                 EXPECTEOL;
01178                                 continue;
01179                         } else if (strcasecmp(DNS_AS_STR(token),
01180                                               "$INCLUDE") == 0) {
01181                                 COMMITALL;
01182                                 if ((lctx->options & DNS_MASTER_NOINCLUDE)
01183                                     != 0)
01184                                 {
01185                                         (callbacks->error)(callbacks,
01186                                            "%s: %s:%lu: $INCLUDE not allowed",
01187                                            "dns_master_load",
01188                                            source, line);
01189                                         result = DNS_R_REFUSED;
01190                                         goto insist_and_cleanup;
01191                                 }
01192                                 if (ttl_offset != 0) {
01193                                         (callbacks->error)(callbacks,
01194                                            "%s: %s:%lu: $INCLUDE "
01195                                            "may not be used with $DATE",
01196                                            "dns_master_load",
01197                                            source, line);
01198                                         result = DNS_R_SYNTAX;
01199                                         goto insist_and_cleanup;
01200                                 }
01201                                 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
01202                                          ISC_FALSE);
01203                                 if (include_file != NULL)
01204                                         isc_mem_free(mctx, include_file);
01205                                 include_file = isc_mem_strdup(mctx,
01206                                                            DNS_AS_STR(token));
01207                                 if (include_file == NULL) {
01208                                         result = ISC_R_NOMEMORY;
01209                                         goto log_and_cleanup;
01210                                 }
01211                                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
01212 
01213                                 if (token.type == isc_tokentype_eol ||
01214                                     token.type == isc_tokentype_eof) {
01215                                         if (token.type == isc_tokentype_eof)
01216                                                 WARNUNEXPECTEDEOF(lctx->lex);
01217                                         /*
01218                                          * No origin field.
01219                                          */
01220                                         result = pushfile(include_file,
01221                                                           ictx->origin, lctx);
01222                                         if (MANYERRS(lctx, result)) {
01223                                                 SETRESULT(lctx, result);
01224                                                 LOGITFILE(result, include_file);
01225                                                 continue;
01226                                         } else if (result != ISC_R_SUCCESS) {
01227                                                 LOGITFILE(result, include_file);
01228                                                 goto insist_and_cleanup;
01229                                         }
01230                                         ictx = lctx->inc;
01231                                         source =
01232                                                isc_lex_getsourcename(lctx->lex);
01233                                         line = isc_lex_getsourceline(lctx->lex);
01234                                         POST(line);
01235                                         continue;
01236                                 }
01237                                 /*
01238                                  * There is an origin field.  Fall through
01239                                  * to domain name processing code and do
01240                                  * the actual inclusion later.
01241                                  */
01242                                 finish_include = ISC_TRUE;
01243                         } else if (strcasecmp(DNS_AS_STR(token),
01244                                               "$DATE") == 0) {
01245                                 isc_int64_t dump_time64;
01246                                 isc_stdtime_t dump_time, current_time;
01247                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01248                                 isc_stdtime_get(&current_time);
01249                                 result = dns_time64_fromtext(DNS_AS_STR(token),
01250                                                              &dump_time64);
01251                                 if (MANYERRS(lctx, result)) {
01252                                         SETRESULT(lctx, result);
01253                                         LOGIT(result);
01254                                         dump_time64 = 0;
01255                                 } else if (result != ISC_R_SUCCESS)
01256                                         goto log_and_cleanup;
01257                                 dump_time = (isc_stdtime_t)dump_time64;
01258                                 if (dump_time != dump_time64) {
01259                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
01260                                          "%s: %s:%lu: $DATE outside epoch",
01261                                          "dns_master_load", source, line);
01262                                         result = ISC_R_UNEXPECTED;
01263                                         goto insist_and_cleanup;
01264                                 }
01265                                 if (dump_time > current_time) {
01266                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
01267                                         "%s: %s:%lu: "
01268                                         "$DATE in future, using current date",
01269                                         "dns_master_load", source, line);
01270                                         dump_time = current_time;
01271                                 }
01272                                 ttl_offset = current_time - dump_time;
01273                                 EXPECTEOL;
01274                                 continue;
01275                         } else if (strcasecmp(DNS_AS_STR(token),
01276                                               "$GENERATE") == 0) {
01277                                 /*
01278                                  * Lazy cleanup.
01279                                  */
01280                                 if (range != NULL)
01281                                         isc_mem_free(mctx, range);
01282                                 if (lhs != NULL)
01283                                         isc_mem_free(mctx, lhs);
01284                                 if (gtype != NULL)
01285                                         isc_mem_free(mctx, gtype);
01286                                 if (rhs != NULL)
01287                                         isc_mem_free(mctx, rhs);
01288                                 range = lhs = gtype = rhs = NULL;
01289                                 /* RANGE */
01290                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01291                                 range = isc_mem_strdup(mctx,
01292                                                      DNS_AS_STR(token));
01293                                 if (range == NULL) {
01294                                         result = ISC_R_NOMEMORY;
01295                                         goto log_and_cleanup;
01296                                 }
01297                                 /* LHS */
01298                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01299                                 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
01300                                 if (lhs == NULL) {
01301                                         result = ISC_R_NOMEMORY;
01302                                         goto log_and_cleanup;
01303                                 }
01304                                 rdclass = 0;
01305                                 explicit_ttl = ISC_FALSE;
01306                                 /* CLASS? */
01307                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01308                                 if (dns_rdataclass_fromtext(&rdclass,
01309                                             &token.value.as_textregion)
01310                                                 == ISC_R_SUCCESS) {
01311                                         GETTOKEN(lctx->lex, 0, &token,
01312                                                  ISC_FALSE);
01313                                 }
01314                                 /* TTL? */
01315                                 if (dns_ttl_fromtext(&token.value.as_textregion,
01316                                                      &lctx->ttl)
01317                                                 == ISC_R_SUCCESS) {
01318                                         limit_ttl(callbacks, source, line,
01319                                                   &lctx->ttl);
01320                                         lctx->ttl_known = ISC_TRUE;
01321                                         explicit_ttl = ISC_TRUE;
01322                                         GETTOKEN(lctx->lex, 0, &token,
01323                                                  ISC_FALSE);
01324                                 }
01325                                 /* CLASS? */
01326                                 if (rdclass == 0 &&
01327                                     dns_rdataclass_fromtext(&rdclass,
01328                                                     &token.value.as_textregion)
01329                                                 == ISC_R_SUCCESS)
01330                                         GETTOKEN(lctx->lex, 0, &token,
01331                                                  ISC_FALSE);
01332                                 /* TYPE */
01333                                 gtype = isc_mem_strdup(mctx,
01334                                                        DNS_AS_STR(token));
01335                                 if (gtype == NULL) {
01336                                         result = ISC_R_NOMEMORY;
01337                                         goto log_and_cleanup;
01338                                 }
01339                                 /* RHS */
01340                                 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING,
01341                                          &token, ISC_FALSE);
01342                                 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
01343                                 if (rhs == NULL) {
01344                                         result = ISC_R_NOMEMORY;
01345                                         goto log_and_cleanup;
01346                                 }
01347                                 if (!lctx->ttl_known &&
01348                                     !lctx->default_ttl_known) {
01349                                         (*callbacks->error)(callbacks,
01350                                             "%s: %s:%lu: no TTL specified",
01351                                             "dns_master_load", source, line);
01352                                         result = DNS_R_NOTTL;
01353                                         if (MANYERRS(lctx, result)) {
01354                                                 SETRESULT(lctx, result);
01355                                                 lctx->ttl = 0;
01356                                         } else if (result != ISC_R_SUCCESS)
01357                                                 goto insist_and_cleanup;
01358                                 } else if (!explicit_ttl &&
01359                                            lctx->default_ttl_known) {
01360                                         lctx->ttl = lctx->default_ttl;
01361                                 }
01362                                 /*
01363                                  * If the class specified does not match the
01364                                  * zone's class print out a error message and
01365                                  * exit.
01366                                  */
01367                                 if (rdclass != 0 && rdclass != lctx->zclass) {
01368                                         goto bad_class;
01369                                 }
01370                                 result = generate(lctx, range, lhs, gtype, rhs,
01371                                                   source, line);
01372                                 if (MANYERRS(lctx, result)) {
01373                                         SETRESULT(lctx, result);
01374                                 } else if (result != ISC_R_SUCCESS)
01375                                         goto insist_and_cleanup;
01376                                 EXPECTEOL;
01377                                 continue;
01378                         } else if (strncasecmp(DNS_AS_STR(token),
01379                                                "$", 1) == 0) {
01380                                 (callbacks->error)(callbacks,
01381                                            "%s: %s:%lu: "
01382                                            "unknown $ directive '%s'",
01383                                            "dns_master_load", source, line,
01384                                            DNS_AS_STR(token));
01385                                 result = DNS_R_SYNTAX;
01386                                 if (MANYERRS(lctx, result)) {
01387                                         SETRESULT(lctx, result);
01388                                 } else if (result != ISC_R_SUCCESS)
01389                                         goto insist_and_cleanup;
01390                         }
01391 
01392                         /*
01393                          * Normal processing resumes.
01394                          *
01395                          * Find a free name buffer.
01396                          */
01397                         for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
01398                                 if (!ictx->in_use[new_in_use])
01399                                         break;
01400                         INSIST(new_in_use < NBUFS);
01401                         dns_fixedname_init(&ictx->fixed[new_in_use]);
01402                         new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
01403                         isc_buffer_init(&buffer, token.value.as_region.base,
01404                                         token.value.as_region.length);
01405                         isc_buffer_add(&buffer, token.value.as_region.length);
01406                         isc_buffer_setactive(&buffer,
01407                                              token.value.as_region.length);
01408                         result = dns_name_fromtext(new_name, &buffer,
01409                                           ictx->origin, 0, NULL);
01410                         if (MANYERRS(lctx, result)) {
01411                                 SETRESULT(lctx, result);
01412                                 LOGIT(result);
01413                                 read_till_eol = ISC_TRUE;
01414                                 continue;
01415                         } else if (result != ISC_R_SUCCESS)
01416                                 goto log_and_cleanup;
01417 
01418                         /*
01419                          * Finish $ORIGIN / $INCLUDE processing if required.
01420                          */
01421                         if (finish_origin) {
01422                                 if (ictx->origin_in_use != -1)
01423                                         ictx->in_use[ictx->origin_in_use] =
01424                                                 ISC_FALSE;
01425                                 ictx->origin_in_use = new_in_use;
01426                                 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
01427                                 ictx->origin = new_name;
01428                                 ictx->origin_changed = ISC_TRUE;
01429                                 finish_origin = ISC_FALSE;
01430                                 EXPECTEOL;
01431                                 continue;
01432                         }
01433                         if (finish_include) {
01434                                 finish_include = ISC_FALSE;
01435                                 EXPECTEOL;
01436                                 result = pushfile(include_file, new_name, lctx);
01437                                 if (MANYERRS(lctx, result)) {
01438                                         SETRESULT(lctx, result);
01439                                         LOGITFILE(result, include_file);
01440                                         continue;
01441                                 } else if (result != ISC_R_SUCCESS) {
01442                                         LOGITFILE(result, include_file);
01443                                         goto insist_and_cleanup;
01444                                 }
01445                                 ictx = lctx->inc;
01446                                 ictx->origin_changed = ISC_TRUE;
01447                                 source = isc_lex_getsourcename(lctx->lex);
01448                                 line = isc_lex_getsourceline(lctx->lex);
01449                                 POST(line);
01450                                 continue;
01451                         }
01452 
01453                         /*
01454                          * "$" Processing Finished
01455                          */
01456 
01457                         /*
01458                          * If we are processing glue and the new name does
01459                          * not match the current glue name, commit the glue
01460                          * and pop stacks leaving us in 'normal' processing
01461                          * state.  Linked lists are undone by commit().
01462                          */
01463                         if (ictx->glue != NULL &&
01464                             dns_name_compare(ictx->glue, new_name) != 0) {
01465                                 result = commit(callbacks, lctx, &glue_list,
01466                                                 ictx->glue, source,
01467                                                 ictx->glue_line);
01468                                 if (MANYERRS(lctx, result)) {
01469                                         SETRESULT(lctx, result);
01470                                 } else if (result != ISC_R_SUCCESS)
01471                                         goto insist_and_cleanup;
01472                                 if (ictx->glue_in_use != -1)
01473                                         ictx->in_use[ictx->glue_in_use] =
01474                                                 ISC_FALSE;
01475                                 ictx->glue_in_use = -1;
01476                                 ictx->glue = NULL;
01477                                 rdcount = rdcount_save;
01478                                 rdlcount = rdlcount_save;
01479                                 target = target_save;
01480                         }
01481 
01482                         /*
01483                          * If we are in 'normal' processing state and the new
01484                          * name does not match the current name, see if the
01485                          * new name is for glue and treat it as such,
01486                          * otherwise we have a new name so commit what we
01487                          * have.
01488                          */
01489                         if ((ictx->glue == NULL) && (ictx->current == NULL ||
01490                             dns_name_compare(ictx->current, new_name) != 0)) {
01491                                 if (current_has_delegation &&
01492                                         is_glue(&current_list, new_name)) {
01493                                         rdcount_save = rdcount;
01494                                         rdlcount_save = rdlcount;
01495                                         target_save = target;
01496                                         ictx->glue = new_name;
01497                                         ictx->glue_in_use = new_in_use;
01498                                         ictx->in_use[ictx->glue_in_use] =
01499                                                 ISC_TRUE;
01500                                 } else {
01501                                         result = commit(callbacks, lctx,
01502                                                         &current_list,
01503                                                         ictx->current,
01504                                                         source,
01505                                                         ictx->current_line);
01506                                         if (MANYERRS(lctx, result)) {
01507                                                 SETRESULT(lctx, result);
01508                                         } else if (result != ISC_R_SUCCESS)
01509                                                 goto insist_and_cleanup;
01510                                         rdcount = 0;
01511                                         rdlcount = 0;
01512                                         if (ictx->current_in_use != -1)
01513                                             ictx->in_use[ictx->current_in_use] =
01514                                                 ISC_FALSE;
01515                                         ictx->current_in_use = new_in_use;
01516                                         ictx->in_use[ictx->current_in_use] =
01517                                                 ISC_TRUE;
01518                                         ictx->current = new_name;
01519                                         current_has_delegation = ISC_FALSE;
01520                                         isc_buffer_init(&target, target_mem,
01521                                                         target_size);
01522                                 }
01523                                 /*
01524                                  * Check for internal wildcards.
01525                                  */
01526                                 if ((lctx->options & DNS_MASTER_CHECKWILDCARD)
01527                                                  != 0)
01528                                         check_wildcard(ictx, source, line,
01529                                                        callbacks);
01530 
01531                         }
01532                         if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
01533                             (lctx->options & DNS_MASTER_SLAVE) == 0 &&
01534                             (lctx->options & DNS_MASTER_KEY) == 0 &&
01535                             !dns_name_issubdomain(new_name, lctx->top))
01536                         {
01537                                 char namebuf[DNS_NAME_FORMATSIZE];
01538                                 dns_name_format(new_name, namebuf,
01539                                                 sizeof(namebuf));
01540                                 /*
01541                                  * Ignore out-of-zone data.
01542                                  */
01543                                 (*callbacks->warn)(callbacks,
01544                                        "%s:%lu: "
01545                                        "ignoring out-of-zone data (%s)",
01546                                        source, line, namebuf);
01547                                 ictx->drop = ISC_TRUE;
01548                         } else
01549                                 ictx->drop = ISC_FALSE;
01550                 } else {
01551                         UNEXPECTED_ERROR(__FILE__, __LINE__,
01552                                          "%s:%lu: isc_lex_gettoken() returned "
01553                                          "unexpected token type (%d)",
01554                                          source, line, token.type);
01555                         result = ISC_R_UNEXPECTED;
01556                         if (MANYERRS(lctx, result)) {
01557                                 SETRESULT(lctx, result);
01558                                 LOGIT(result);
01559                                 continue;
01560                         } else if (result != ISC_R_SUCCESS)
01561                                 goto insist_and_cleanup;
01562                 }
01563 
01564                 /*
01565                  * Find TTL, class and type.  Both TTL and class are optional
01566                  * and may occur in any order if they exist. TTL and class
01567                  * come before type which must exist.
01568                  *
01569                  * [<TTL>] [<class>] <type> <RDATA>
01570                  * [<class>] [<TTL>] <type> <RDATA>
01571                  */
01572 
01573                 type = 0;
01574                 rdclass = 0;
01575 
01576                 GETTOKEN(lctx->lex, 0, &token, initialws);
01577 
01578                 if (initialws) {
01579                         if (token.type == isc_tokentype_eol) {
01580                                 read_till_eol = ISC_FALSE;
01581                                 continue;               /* blank line */
01582                         }
01583 
01584                         if (token.type == isc_tokentype_eof) {
01585                                 WARNUNEXPECTEDEOF(lctx->lex);
01586                                 read_till_eol = ISC_FALSE;
01587                                 isc_lex_ungettoken(lctx->lex, &token);
01588                                 continue;
01589                         }
01590 
01591                         if (ictx->current == NULL) {
01592                                 (*callbacks->error)(callbacks,
01593                                         "%s:%lu: no current owner name",
01594                                         source, line);
01595                                 result = DNS_R_NOOWNER;
01596                                 if (MANYERRS(lctx, result)) {
01597                                         SETRESULT(lctx, result);
01598                                         read_till_eol = ISC_TRUE;
01599                                         continue;
01600                                 } else if (result != ISC_R_SUCCESS)
01601                                         goto insist_and_cleanup;
01602                         }
01603 
01604                         if (ictx->origin_changed) {
01605                                 char cbuf[DNS_NAME_FORMATSIZE];
01606                                 char obuf[DNS_NAME_FORMATSIZE];
01607                                 dns_name_format(ictx->current, cbuf,
01608                                                 sizeof(cbuf));
01609                                 dns_name_format(ictx->origin, obuf,
01610                                                 sizeof(obuf));
01611                                 (*callbacks->warn)(callbacks,
01612                                         "%s:%lu: record with inherited "
01613                                         "owner (%s) immediately after "
01614                                         "$ORIGIN (%s)", source, line,
01615                                         cbuf, obuf);
01616                         }
01617                 }
01618 
01619                 ictx->origin_changed = ISC_FALSE;
01620 
01621                 if (dns_rdataclass_fromtext(&rdclass,
01622                                             &token.value.as_textregion)
01623                                 == ISC_R_SUCCESS)
01624                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01625 
01626                 explicit_ttl = ISC_FALSE;
01627                 result = dns_ttl_fromtext(&token.value.as_textregion,
01628                                           &lctx->ttl);
01629                 if (result == ISC_R_SUCCESS) {
01630                         limit_ttl(callbacks, source, line, &lctx->ttl);
01631                         explicit_ttl = ISC_TRUE;
01632                         lctx->ttl_known = ISC_TRUE;
01633                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01634                 }
01635 
01636                 if (token.type != isc_tokentype_string) {
01637                         UNEXPECTED_ERROR(__FILE__, __LINE__,
01638                         "isc_lex_gettoken() returned unexpected token type");
01639                         result = ISC_R_UNEXPECTED;
01640                         if (MANYERRS(lctx, result)) {
01641                                 SETRESULT(lctx, result);
01642                                 read_till_eol = ISC_TRUE;
01643                                 continue;
01644                         } else if (result != ISC_R_SUCCESS)
01645                                 goto insist_and_cleanup;
01646                 }
01647 
01648                 if (rdclass == 0 &&
01649                     dns_rdataclass_fromtext(&rdclass,
01650                                             &token.value.as_textregion)
01651                                 == ISC_R_SUCCESS)
01652                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01653 
01654                 if (token.type != isc_tokentype_string) {
01655                         UNEXPECTED_ERROR(__FILE__, __LINE__,
01656                         "isc_lex_gettoken() returned unexpected token type");
01657                         result = ISC_R_UNEXPECTED;
01658                         if (MANYERRS(lctx, result)) {
01659                                 SETRESULT(lctx, result);
01660                                 read_till_eol = ISC_TRUE;
01661                                 continue;
01662                         } else if (result != ISC_R_SUCCESS)
01663                                 goto insist_and_cleanup;
01664                 }
01665 
01666                 result = dns_rdatatype_fromtext(&type,
01667                                                 &token.value.as_textregion);
01668                 if (result != ISC_R_SUCCESS) {
01669                         (*callbacks->warn)(callbacks,
01670                                    "%s:%lu: unknown RR type '%.*s'",
01671                                    source, line,
01672                                    token.value.as_textregion.length,
01673                                    token.value.as_textregion.base);
01674                         if (MANYERRS(lctx, result)) {
01675                                 SETRESULT(lctx, result);
01676                                 read_till_eol = ISC_TRUE;
01677                                 continue;
01678                         } else if (result != ISC_R_SUCCESS)
01679                                 goto insist_and_cleanup;
01680                 }
01681 
01682                 /*
01683                  * If the class specified does not match the zone's class
01684                  * print out a error message and exit.
01685                  */
01686                 if (rdclass != 0 && rdclass != lctx->zclass) {
01687   bad_class:
01688 
01689                         dns_rdataclass_format(rdclass, classname1,
01690                                               sizeof(classname1));
01691                         dns_rdataclass_format(lctx->zclass, classname2,
01692                                               sizeof(classname2));
01693                         (*callbacks->error)(callbacks,
01694                                             "%s:%lu: class '%s' != "
01695                                             "zone class '%s'",
01696                                             source, line,
01697                                             classname1, classname2);
01698                         result = DNS_R_BADCLASS;
01699                         if (MANYERRS(lctx, result)) {
01700                                 SETRESULT(lctx, result);
01701                                 read_till_eol = ISC_TRUE;
01702                                 continue;
01703                         } else if (result != ISC_R_SUCCESS)
01704                                 goto insist_and_cleanup;
01705                 }
01706 
01707                 if (type == dns_rdatatype_ns && ictx->glue == NULL)
01708                         current_has_delegation = ISC_TRUE;
01709 
01710                 /*
01711                  * RFC1123: MD and MF are not allowed to be loaded from
01712                  * master files.
01713                  */
01714                 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
01715                     (lctx->options & DNS_MASTER_SLAVE) == 0 &&
01716                     (type == dns_rdatatype_md || type == dns_rdatatype_mf)) {
01717                         char typename[DNS_RDATATYPE_FORMATSIZE];
01718 
01719                         result = DNS_R_OBSOLETE;
01720 
01721                         dns_rdatatype_format(type, typename, sizeof(typename));
01722                         (*callbacks->error)(callbacks,
01723                                             "%s:%lu: %s '%s': %s",
01724                                             source, line,
01725                                             "type", typename,
01726                                             dns_result_totext(result));
01727                         if (MANYERRS(lctx, result)) {
01728                                 SETRESULT(lctx, result);
01729                         } else
01730                                 goto insist_and_cleanup;
01731                 }
01732 
01733                 /*
01734                  * Find a rdata structure.
01735                  */
01736                 if (rdcount == rdata_size) {
01737                         new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
01738                                                rdata_size, &current_list,
01739                                                &glue_list, mctx);
01740                         if (new_rdata == NULL) {
01741                                 result = ISC_R_NOMEMORY;
01742                                 goto log_and_cleanup;
01743                         }
01744                         rdata_size += RDSZ;
01745                         rdata = new_rdata;
01746                 }
01747 
01748                 /*
01749                  * Peek at the NS record.
01750                  */
01751                 if (type == dns_rdatatype_ns &&
01752                     lctx->zclass == dns_rdataclass_in &&
01753                     (lctx->options & DNS_MASTER_CHECKNS) != 0) {
01754 
01755                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
01756                         result = check_ns(lctx, &token, source, line);
01757                         isc_lex_ungettoken(lctx->lex, &token);
01758                         if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
01759                                 if (MANYERRS(lctx, result)) {
01760                                         SETRESULT(lctx, result);
01761                                 } else if (result != ISC_R_SUCCESS)
01762                                         goto insist_and_cleanup;
01763                         }
01764                 }
01765 
01766                 /*
01767                  * Check owner name.
01768                  */
01769                 options &= ~DNS_RDATA_CHECKREVERSE;
01770                 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
01771                         isc_boolean_t ok;
01772                         dns_name_t *name;
01773 
01774                         name = (ictx->glue != NULL) ? ictx->glue :
01775                                                       ictx->current;
01776                         ok = dns_rdata_checkowner(name, lctx->zclass, type,
01777                                                   ISC_TRUE);
01778                         if (!ok) {
01779                                 char namebuf[DNS_NAME_FORMATSIZE];
01780                                 const char *desc;
01781                                 dns_name_format(name, namebuf, sizeof(namebuf));
01782                                 result = DNS_R_BADOWNERNAME;
01783                                 desc = dns_result_totext(result);
01784                                 if (CHECKNAMESFAIL(lctx->options) ||
01785                                     type == dns_rdatatype_nsec3) {
01786                                         (*callbacks->error)(callbacks,
01787                                                             "%s:%lu: %s: %s",
01788                                                             source, line,
01789                                                             namebuf, desc);
01790                                         if (MANYERRS(lctx, result)) {
01791                                                 SETRESULT(lctx, result);
01792                                         } else if (result != ISC_R_SUCCESS)
01793                                                 goto cleanup;
01794                                 } else {
01795                                         (*callbacks->warn)(callbacks,
01796                                                            "%s:%lu: %s: %s",
01797                                                            source, line,
01798                                                            namebuf, desc);
01799                                 }
01800                         }
01801                         if (type == dns_rdatatype_ptr &&
01802                             (dns_name_issubdomain(name, &in_addr_arpa) ||
01803                              dns_name_issubdomain(name, &ip6_arpa) ||
01804                              dns_name_issubdomain(name, &ip6_int)))
01805                                 options |= DNS_RDATA_CHECKREVERSE;
01806                 }
01807 
01808                 /*
01809                  * Read rdata contents.
01810                  */
01811                 dns_rdata_init(&rdata[rdcount]);
01812                 target_ft = target;
01813                 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
01814                                             type, lctx->lex, ictx->origin,
01815                                             options, lctx->mctx, &target,
01816                                             callbacks);
01817                 if (MANYERRS(lctx, result)) {
01818                         SETRESULT(lctx, result);
01819                         continue;
01820                 } else if (result != ISC_R_SUCCESS)
01821                         goto insist_and_cleanup;
01822 
01823                 if (ictx->drop) {
01824                         target = target_ft;
01825                         continue;
01826                 }
01827 
01828                 if (type == dns_rdatatype_soa &&
01829                     (lctx->options & DNS_MASTER_ZONE) != 0 &&
01830                     dns_name_compare(ictx->current, lctx->top) != 0) {
01831                         char namebuf[DNS_NAME_FORMATSIZE];
01832                         dns_name_format(ictx->current, namebuf,
01833                                         sizeof(namebuf));
01834                         (*callbacks->error)(callbacks, "%s:%lu: SOA "
01835                                             "record not at top of zone (%s)",
01836                                             source, line, namebuf);
01837                         result = DNS_R_NOTZONETOP;
01838                         if (MANYERRS(lctx, result)) {
01839                                 SETRESULT(lctx, result);
01840                                 read_till_eol = ISC_TRUE;
01841                                 target = target_ft;
01842                                 continue;
01843                         } else if (result != ISC_R_SUCCESS)
01844                                 goto insist_and_cleanup;
01845                 }
01846 
01847                 if (type == dns_rdatatype_rrsig ||
01848                     type == dns_rdatatype_sig)
01849                         covers = dns_rdata_covers(&rdata[rdcount]);
01850                 else
01851                         covers = 0;
01852 
01853                 if (!lctx->ttl_known && !lctx->default_ttl_known) {
01854                         if (type == dns_rdatatype_soa) {
01855                                 (*callbacks->warn)(callbacks,
01856                                                    "%s:%lu: no TTL specified; "
01857                                                    "using SOA MINTTL instead",
01858                                                    source, line);
01859                                 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
01860                                 limit_ttl(callbacks, source, line, &lctx->ttl);
01861                                 lctx->default_ttl = lctx->ttl;
01862                                 lctx->default_ttl_known = ISC_TRUE;
01863                         } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
01864                                 /*
01865                                  * Zero TTL's are fine for hints.
01866                                  */
01867                                 lctx->ttl = 0;
01868                                 lctx->default_ttl = lctx->ttl;
01869                                 lctx->default_ttl_known = ISC_TRUE;
01870                         } else {
01871                                 (*callbacks->warn)(callbacks,
01872                                                    "%s:%lu: no TTL specified; "
01873                                                    "zone rejected",
01874                                                    source, line);
01875                                 result = DNS_R_NOTTL;
01876                                 if (MANYERRS(lctx, result)) {
01877                                         SETRESULT(lctx, result);
01878                                         lctx->ttl = 0;
01879                                 } else {
01880                                         goto insist_and_cleanup;
01881                                 }
01882                         }
01883                 } else if (!explicit_ttl && lctx->default_ttl_known) {
01884                         lctx->ttl = lctx->default_ttl;
01885                 } else if (!explicit_ttl && lctx->warn_1035) {
01886                         (*callbacks->warn)(callbacks,
01887                                            "%s:%lu: "
01888                                            "using RFC1035 TTL semantics",
01889                                            source, line);
01890                         lctx->warn_1035 = ISC_FALSE;
01891                 }
01892 
01893                 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
01894                         dns_rdata_rrsig_t sig;
01895                         result = dns_rdata_tostruct(&rdata[rdcount], &sig,
01896                                                     NULL);
01897                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
01898                         if (isc_serial_lt(sig.timeexpire, now)) {
01899                                 (*callbacks->warn)(callbacks,
01900                                                    "%s:%lu: "
01901                                                    "signature has expired",
01902                                                    source, line);
01903                                 lctx->warn_sigexpired = ISC_FALSE;
01904                         }
01905                 }
01906 
01907                 if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
01908                     lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
01909                     (lctx->options & DNS_MASTER_SLAVE) == 0) {
01910                         (*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
01911                                            " zone detected", source, line);
01912                         lctx->warn_tcr = ISC_FALSE;
01913                 }
01914 
01915                 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
01916                         /*
01917                          * Adjust the TTL for $DATE.  If the RR has already
01918                          * expired, ignore it.
01919                          */
01920                         if (lctx->ttl < ttl_offset)
01921                                 continue;
01922                         lctx->ttl -= ttl_offset;
01923                 }
01924 
01925                 /*
01926                  * Find type in rdatalist.
01927                  * If it does not exist create new one and prepend to list
01928                  * as this will minimise list traversal.
01929                  */
01930                 if (ictx->glue != NULL)
01931                         this = ISC_LIST_HEAD(glue_list);
01932                 else
01933                         this = ISC_LIST_HEAD(current_list);
01934 
01935                 while (this != NULL) {
01936                         if (this->type == type && this->covers == covers)
01937                                 break;
01938                         this = ISC_LIST_NEXT(this, link);
01939                 }
01940 
01941                 if (this == NULL) {
01942                         if (rdlcount == rdatalist_size) {
01943                                 new_rdatalist =
01944                                         grow_rdatalist(rdatalist_size + RDLSZ,
01945                                                        rdatalist,
01946                                                        rdatalist_size,
01947                                                        &current_list,
01948                                                        &glue_list,
01949                                                        mctx);
01950                                 if (new_rdatalist == NULL) {
01951                                         result = ISC_R_NOMEMORY;
01952                                         goto log_and_cleanup;
01953                                 }
01954                                 rdatalist = new_rdatalist;
01955                                 rdatalist_size += RDLSZ;
01956                         }
01957                         this = &rdatalist[rdlcount++];
01958                         dns_rdatalist_init(this);
01959                         this->type = type;
01960                         this->covers = covers;
01961                         this->rdclass = lctx->zclass;
01962                         this->ttl = lctx->ttl;
01963                         if (ictx->glue != NULL)
01964                                 ISC_LIST_INITANDPREPEND(glue_list, this, link);
01965                         else
01966                                 ISC_LIST_INITANDPREPEND(current_list, this,
01967                                                         link);
01968                 } else if (this->ttl != lctx->ttl) {
01969                         (*callbacks->warn)(callbacks,
01970                                            "%s:%lu: "
01971                                            "TTL set to prior TTL (%lu)",
01972                                            source, line, this->ttl);
01973                         lctx->ttl = this->ttl;
01974                 }
01975 
01976                 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
01977                     lctx->ttl > lctx->maxttl)
01978                 {
01979                         (callbacks->error)(callbacks,
01980                                    "dns_master_load: %s:%lu: "
01981                                    "TTL %d exceeds configured max-zone-ttl %d",
01982                                    source, line, lctx->ttl, lctx->maxttl);
01983                         result = ISC_R_RANGE;
01984                         goto log_and_cleanup;
01985                 }
01986 
01987                 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
01988                 if (ictx->glue != NULL)
01989                         ictx->glue_line = line;
01990                 else
01991                         ictx->current_line = line;
01992                 rdcount++;
01993 
01994                 /*
01995                  * We must have at least 64k as rdlen is 16 bits.
01996                  * If we don't commit everything we have so far.
01997                  */
01998                 if ((target.length - target.used) < MINTSIZ)
01999                         COMMITALL;
02000  next_line:
02001                 ;
02002         } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
02003 
02004         /*
02005          * Commit what has not yet been committed.
02006          */
02007         result = commit(callbacks, lctx, &current_list, ictx->current,
02008                         source, ictx->current_line);
02009         if (MANYERRS(lctx, result)) {
02010                 SETRESULT(lctx, result);
02011         } else if (result != ISC_R_SUCCESS)
02012                 goto insist_and_cleanup;
02013         result = commit(callbacks, lctx, &glue_list, ictx->glue,
02014                         source, ictx->glue_line);
02015         if (MANYERRS(lctx, result)) {
02016                 SETRESULT(lctx, result);
02017         } else if (result != ISC_R_SUCCESS)
02018                 goto insist_and_cleanup;
02019 
02020         if (!done) {
02021                 INSIST(lctx->done != NULL && lctx->task != NULL);
02022                 result = DNS_R_CONTINUE;
02023         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
02024                 result = lctx->result;
02025         } else if (result == ISC_R_SUCCESS && lctx->seen_include)
02026                 result = DNS_R_SEENINCLUDE;
02027         goto cleanup;
02028 
02029  log_and_cleanup:
02030         LOGIT(result);
02031 
02032  insist_and_cleanup:
02033         INSIST(result != ISC_R_SUCCESS);
02034 
02035  cleanup:
02036         while ((this = ISC_LIST_HEAD(current_list)) != NULL)
02037                 ISC_LIST_UNLINK(current_list, this, link);
02038         while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
02039                 ISC_LIST_UNLINK(glue_list, this, link);
02040         if (rdatalist != NULL)
02041                 isc_mem_put(mctx, rdatalist,
02042                             rdatalist_size * sizeof(*rdatalist));
02043         if (rdata != NULL)
02044                 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
02045         if (target_mem != NULL)
02046                 isc_mem_put(mctx, target_mem, target_size);
02047         if (include_file != NULL)
02048                 isc_mem_free(mctx, include_file);
02049         if (range != NULL)
02050                 isc_mem_free(mctx, range);
02051         if (lhs != NULL)
02052                 isc_mem_free(mctx, lhs);
02053         if (gtype != NULL)
02054                 isc_mem_free(mctx, gtype);
02055         if (rhs != NULL)
02056                 isc_mem_free(mctx, rhs);
02057         return (result);
02058 }
02059 
02060 static isc_result_t
02061 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
02062         isc_result_t result;
02063         dns_incctx_t *ictx;
02064         dns_incctx_t *new = NULL;
02065         isc_region_t r;
02066         int new_in_use;
02067 
02068         REQUIRE(master_file != NULL);
02069         REQUIRE(DNS_LCTX_VALID(lctx));
02070 
02071         ictx = lctx->inc;
02072         lctx->seen_include = ISC_TRUE;
02073 
02074         result = incctx_create(lctx->mctx, origin, &new);
02075         if (result != ISC_R_SUCCESS)
02076                 return (result);
02077 
02078         /*
02079          * Push origin_changed.
02080          */
02081         new->origin_changed = ictx->origin_changed;
02082 
02083         /* Set current domain. */
02084         if (ictx->glue != NULL || ictx->current != NULL) {
02085                 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
02086                         if (!new->in_use[new_in_use])
02087                                 break;
02088                 INSIST(new_in_use < NBUFS);
02089                 new->current_in_use = new_in_use;
02090                 new->current =
02091                         dns_fixedname_name(&new->fixed[new->current_in_use]);
02092                 new->in_use[new->current_in_use] = ISC_TRUE;
02093                 dns_name_toregion((ictx->glue != NULL) ?
02094                                    ictx->glue : ictx->current, &r);
02095                 dns_name_fromregion(new->current, &r);
02096                 new->drop = ictx->drop;
02097         }
02098 
02099         result = (lctx->openfile)(lctx, master_file);
02100         if (result != ISC_R_SUCCESS)
02101                 goto cleanup;
02102         new->parent = ictx;
02103         lctx->inc = new;
02104 
02105         if (lctx->include_cb != NULL)
02106                 lctx->include_cb(master_file, lctx->include_arg);
02107         return (ISC_R_SUCCESS);
02108 
02109  cleanup:
02110         incctx_destroy(lctx->mctx, new);
02111         return (result);
02112 }
02113 
02114 static inline isc_result_t
02115 read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer,
02116                size_t len, FILE *f)
02117 {
02118         isc_result_t result;
02119 
02120         if (do_read) {
02121                 INSIST(isc_buffer_availablelength(buffer) >= len);
02122                 result = isc_stdio_read(isc_buffer_used(buffer), 1, len,
02123                                         f, NULL);
02124                 if (result != ISC_R_SUCCESS)
02125                         return (result);
02126                 isc_buffer_add(buffer, (unsigned int)len);
02127         } else if (isc_buffer_remaininglength(buffer) < len)
02128                 return (ISC_R_RANGE);
02129 
02130         return (ISC_R_SUCCESS);
02131 }
02132 
02133 static isc_result_t
02134 load_header(dns_loadctx_t *lctx) {
02135         isc_result_t result = ISC_R_SUCCESS;
02136         dns_masterrawheader_t header;
02137         dns_rdatacallbacks_t *callbacks;
02138         size_t commonlen = sizeof(header.format) + sizeof(header.version);
02139         size_t remainder;
02140         unsigned char data[sizeof(header)];
02141         isc_buffer_t target;
02142 
02143         REQUIRE(DNS_LCTX_VALID(lctx));
02144 
02145         if (lctx->format != dns_masterformat_raw &&
02146             lctx->format != dns_masterformat_map)
02147                 return (ISC_R_NOTIMPLEMENTED);
02148 
02149         callbacks = lctx->callbacks;
02150         dns_master_initrawheader(&header);
02151 
02152         INSIST(commonlen <= sizeof(header));
02153         isc_buffer_init(&target, data, sizeof(data));
02154 
02155         result = isc_stdio_read(data, 1, commonlen, lctx->f, NULL);
02156         if (result != ISC_R_SUCCESS) {
02157                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02158                                  "isc_stdio_read failed: %s",
02159                                  isc_result_totext(result));
02160                 return (result);
02161         }
02162 
02163         isc_buffer_add(&target, (unsigned int)commonlen);
02164         header.format = isc_buffer_getuint32(&target);
02165         if (header.format != lctx->format) {
02166                 (*callbacks->error)(callbacks, "dns_master_load: "
02167                                     "file format mismatch (not %s)",
02168                                     lctx->format == dns_masterformat_map
02169                                             ? "map"
02170                                             : "raw");
02171                 return (ISC_R_NOTIMPLEMENTED);
02172         }
02173 
02174         header.version = isc_buffer_getuint32(&target);
02175 
02176         switch (header.version) {
02177         case 0:
02178                 remainder = sizeof(header.dumptime);
02179                 break;
02180         case DNS_RAWFORMAT_VERSION:
02181                 remainder = sizeof(header) - commonlen;
02182                 break;
02183         default:
02184                 (*callbacks->error)(callbacks,
02185                                     "dns_master_load: "
02186                                     "unsupported file format version");
02187                 return (ISC_R_NOTIMPLEMENTED);
02188         }
02189 
02190         result = isc_stdio_read(data + commonlen, 1, remainder, lctx->f, NULL);
02191         if (result != ISC_R_SUCCESS) {
02192                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02193                                  "isc_stdio_read failed: %s",
02194                                  isc_result_totext(result));
02195                 return (result);
02196         }
02197 
02198         isc_buffer_add(&target, (unsigned int)remainder);
02199         header.dumptime = isc_buffer_getuint32(&target);
02200         if (header.version == DNS_RAWFORMAT_VERSION) {
02201                 header.flags = isc_buffer_getuint32(&target);
02202                 header.sourceserial = isc_buffer_getuint32(&target);
02203                 header.lastxfrin = isc_buffer_getuint32(&target);
02204         }
02205 
02206         lctx->first = ISC_FALSE;
02207         lctx->header = header;
02208 
02209         return (ISC_R_SUCCESS);
02210 }
02211 
02212 static isc_result_t
02213 openfile_map(dns_loadctx_t *lctx, const char *master_file) {
02214         isc_result_t result;
02215 
02216         result = isc_stdio_open(master_file, "rb", &lctx->f);
02217         if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
02218                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02219                                  "isc_stdio_open() failed: %s",
02220                                  isc_result_totext(result));
02221         }
02222 
02223         return (result);
02224 }
02225 
02226 /*
02227  * Load a map format file, using mmap() to access RBT trees directly
02228  */
02229 static isc_result_t
02230 load_map(dns_loadctx_t *lctx) {
02231         isc_result_t result = ISC_R_SUCCESS;
02232         dns_rdatacallbacks_t *callbacks;
02233 
02234         REQUIRE(DNS_LCTX_VALID(lctx));
02235 
02236         callbacks = lctx->callbacks;
02237 
02238         if (lctx->first) {
02239                 result = load_header(lctx);
02240                 if (result != ISC_R_SUCCESS)
02241                         return (result);
02242 
02243                 result = (*callbacks->deserialize)
02244                           (callbacks->deserialize_private,
02245                            lctx->f, sizeof(dns_masterrawheader_t));
02246         }
02247 
02248         return (result);
02249 }
02250 
02251 static isc_result_t
02252 openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
02253         isc_result_t result;
02254 
02255         result = isc_stdio_open(master_file, "rb", &lctx->f);
02256         if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
02257                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02258                                  "isc_stdio_open() failed: %s",
02259                                  isc_result_totext(result));
02260         }
02261 
02262         return (result);
02263 }
02264 
02265 static isc_result_t
02266 load_raw(dns_loadctx_t *lctx) {
02267         isc_result_t result = ISC_R_SUCCESS;
02268         isc_boolean_t done = ISC_FALSE;
02269         unsigned int loop_cnt = 0;
02270         dns_rdatacallbacks_t *callbacks;
02271         unsigned char namebuf[DNS_NAME_MAXWIRE];
02272         dns_fixedname_t fixed;
02273         dns_name_t *name;
02274         rdatalist_head_t head, dummy;
02275         dns_rdatalist_t rdatalist;
02276         isc_mem_t *mctx = lctx->mctx;
02277         dns_rdata_t *rdata = NULL;
02278         unsigned int rdata_size = 0;
02279         int target_size = TSIZ;
02280         isc_buffer_t target, buf;
02281         unsigned char *target_mem = NULL;
02282         dns_decompress_t dctx;
02283 
02284         REQUIRE(DNS_LCTX_VALID(lctx));
02285         callbacks = lctx->callbacks;
02286         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
02287 
02288         if (lctx->first) {
02289                 result = load_header(lctx);
02290                 if (result != ISC_R_SUCCESS)
02291                         return (result);
02292         }
02293 
02294         ISC_LIST_INIT(head);
02295         ISC_LIST_INIT(dummy);
02296 
02297         /*
02298          * Allocate target_size of buffer space.  This is greater than twice
02299          * the maximum individual RR data size.
02300          */
02301         target_mem = isc_mem_get(mctx, target_size);
02302         if (target_mem == NULL) {
02303                 result = ISC_R_NOMEMORY;
02304                 goto cleanup;
02305         }
02306         isc_buffer_init(&target, target_mem, target_size);
02307 
02308         dns_fixedname_init(&fixed);
02309         name = dns_fixedname_name(&fixed);
02310 
02311         /*
02312          * In the following loop, we regard any error fatal regardless of
02313          * whether "MANYERRORS" is set in the context option.  This is because
02314          * normal errors should already have been checked at creation time.
02315          * Besides, it is very unlikely that we can recover from an error
02316          * in this format, and so trying to continue parsing erroneous data
02317          * does not really make sense.
02318          */
02319         for (loop_cnt = 0;
02320              (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
02321              loop_cnt++) {
02322                 unsigned int i, rdcount;
02323                 isc_uint16_t namelen;
02324                 isc_uint32_t totallen;
02325                 size_t minlen, readlen;
02326                 isc_boolean_t sequential_read = ISC_FALSE;
02327 
02328                 /* Read the data length */
02329                 isc_buffer_clear(&target);
02330                 INSIST(isc_buffer_availablelength(&target) >=
02331                        sizeof(totallen));
02332                 result = isc_stdio_read(target.base, 1, sizeof(totallen),
02333                                         lctx->f, NULL);
02334                 if (result == ISC_R_EOF) {
02335                         result = ISC_R_SUCCESS;
02336                         done = ISC_TRUE;
02337                         break;
02338                 }
02339                 if (result != ISC_R_SUCCESS)
02340                         goto cleanup;
02341                 isc_buffer_add(&target, sizeof(totallen));
02342                 totallen = isc_buffer_getuint32(&target);
02343                 /*
02344                  * Validation: the input data must at least contain the common
02345                  * header.
02346                  */
02347                 minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
02348                         sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
02349                         sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
02350                 if (totallen < minlen) {
02351                         result = ISC_R_RANGE;
02352                         goto cleanup;
02353                 }
02354                 totallen -= sizeof(totallen);
02355 
02356                 isc_buffer_clear(&target);
02357                 if (totallen > isc_buffer_availablelength(&target)) {
02358                         /*
02359                          * The default buffer size should typically be large
02360                          * enough to store the entire RRset.  We could try to
02361                          * allocate enough space if this is not the case, but
02362                          * it might cause a hazardous result when "totallen"
02363                          * is forged.  Thus, we'd rather take an inefficient
02364                          * but robust approach in this atypical case: read
02365                          * data step by step, and commit partial data when
02366                          * necessary.  Note that the buffer must be large
02367                          * enough to store the "header part", owner name, and
02368                          * at least one rdata (however large it is).
02369                          */
02370                         sequential_read = ISC_TRUE;
02371                         readlen = minlen - sizeof(totallen);
02372                 } else {
02373                         /*
02374                          * Typical case.  We can read the whole RRset at once
02375                          * with the default buffer.
02376                          */
02377                         readlen = totallen;
02378                 }
02379                 result = isc_stdio_read(target.base, 1, readlen,
02380                                         lctx->f, NULL);
02381                 if (result != ISC_R_SUCCESS)
02382                         goto cleanup;
02383                 isc_buffer_add(&target, (unsigned int)readlen);
02384 
02385                 /* Construct RRset headers */
02386                 dns_rdatalist_init(&rdatalist);
02387                 rdatalist.rdclass = isc_buffer_getuint16(&target);
02388                 rdatalist.type = isc_buffer_getuint16(&target);
02389                 rdatalist.covers = isc_buffer_getuint16(&target);
02390                 rdatalist.ttl =  isc_buffer_getuint32(&target);
02391                 rdcount = isc_buffer_getuint32(&target);
02392                 if (rdcount == 0 || rdcount > 0xffff) {
02393                         result = ISC_R_RANGE;
02394                         goto cleanup;
02395                 }
02396                 INSIST(isc_buffer_consumedlength(&target) <= readlen);
02397 
02398                 /* Owner name: length followed by name */
02399                 result = read_and_check(sequential_read, &target,
02400                                         sizeof(namelen), lctx->f);
02401                 if (result != ISC_R_SUCCESS)
02402                         goto cleanup;
02403                 namelen = isc_buffer_getuint16(&target);
02404                 if (namelen > sizeof(namebuf)) {
02405                         result = ISC_R_RANGE;
02406                         goto cleanup;
02407                 }
02408 
02409                 result = read_and_check(sequential_read, &target, namelen,
02410                                         lctx->f);
02411                 if (result != ISC_R_SUCCESS)
02412                         goto cleanup;
02413 
02414                 isc_buffer_setactive(&target, (unsigned int)namelen);
02415                 result = dns_name_fromwire(name, &target, &dctx, 0, NULL);
02416                 if (result != ISC_R_SUCCESS)
02417                         goto cleanup;
02418 
02419                 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
02420                     rdatalist.ttl > lctx->maxttl)
02421                 {
02422                         (callbacks->error)(callbacks,
02423                                            "dns_master_load: "
02424                                            "TTL %d exceeds configured "
02425                                            "max-zone-ttl %d",
02426                                            rdatalist.ttl, lctx->maxttl);
02427                         result = ISC_R_RANGE;
02428                         goto cleanup;
02429                 }
02430 
02431                 /* Rdata contents. */
02432                 if (rdcount > rdata_size) {
02433                         dns_rdata_t *new_rdata = NULL;
02434 
02435                         new_rdata = grow_rdata(rdcount + RDSZ, rdata,
02436                                                rdata_size, &head,
02437                                                &dummy, mctx);
02438                         if (new_rdata == NULL) {
02439                                 result = ISC_R_NOMEMORY;
02440                                 goto cleanup;
02441                         }
02442                         rdata_size = rdcount + RDSZ;
02443                         rdata = new_rdata;
02444                 }
02445 
02446         continue_read:
02447                 for (i = 0; i < rdcount; i++) {
02448                         isc_uint16_t rdlen;
02449 
02450                         dns_rdata_init(&rdata[i]);
02451 
02452                         if (sequential_read &&
02453                             isc_buffer_availablelength(&target) < MINTSIZ) {
02454                                 unsigned int j;
02455 
02456                                 INSIST(i > 0); /* detect an infinite loop */
02457 
02458                                 /* Partial Commit. */
02459                                 ISC_LIST_APPEND(head, &rdatalist, link);
02460                                 result = commit(callbacks, lctx, &head, name,
02461                                                 NULL, 0);
02462                                 for (j = 0; j < i; j++) {
02463                                         ISC_LIST_UNLINK(rdatalist.rdata,
02464                                                         &rdata[j], link);
02465                                         dns_rdata_reset(&rdata[j]);
02466                                 }
02467                                 if (result != ISC_R_SUCCESS)
02468                                         goto cleanup;
02469 
02470                                 /* Rewind the buffer and continue */
02471                                 isc_buffer_clear(&target);
02472 
02473                                 rdcount -= i;
02474 
02475                                 goto continue_read;
02476                         }
02477 
02478                         /* rdata length */
02479                         result = read_and_check(sequential_read, &target,
02480                                                 sizeof(rdlen), lctx->f);
02481                         if (result != ISC_R_SUCCESS)
02482                                 goto cleanup;
02483                         rdlen = isc_buffer_getuint16(&target);
02484 
02485                         /* rdata */
02486                         result = read_and_check(sequential_read, &target,
02487                                                 rdlen, lctx->f);
02488                         if (result != ISC_R_SUCCESS)
02489                                 goto cleanup;
02490                         isc_buffer_setactive(&target, (unsigned int)rdlen);
02491                         /*
02492                          * It is safe to have the source active region and
02493                          * the target available region be the same if
02494                          * decompression is disabled (see dctx above) and we
02495                          * are not downcasing names (options == 0).
02496                          */
02497                         isc_buffer_init(&buf, isc_buffer_current(&target),
02498                                         (unsigned int)rdlen);
02499                         result = dns_rdata_fromwire(&rdata[i],
02500                                                     rdatalist.rdclass,
02501                                                     rdatalist.type, &target,
02502                                                     &dctx, 0, &buf);
02503                         if (result != ISC_R_SUCCESS)
02504                                 goto cleanup;
02505                         ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
02506                 }
02507 
02508                 /*
02509                  * Sanity check.  Still having remaining space is not
02510                  * necessarily critical, but it very likely indicates broken
02511                  * or malformed data.
02512                  */
02513                 if (isc_buffer_remaininglength(&target) != 0) {
02514                         result = ISC_R_RANGE;
02515                         goto cleanup;
02516                 }
02517 
02518                 ISC_LIST_APPEND(head, &rdatalist, link);
02519 
02520                 /* Commit this RRset.  rdatalist will be unlinked. */
02521                 result = commit(callbacks, lctx, &head, name, NULL, 0);
02522 
02523                 for (i = 0; i < rdcount; i++) {
02524                         ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
02525                         dns_rdata_reset(&rdata[i]);
02526                 }
02527 
02528                 if (result != ISC_R_SUCCESS)
02529                         goto cleanup;
02530         }
02531 
02532         if (!done) {
02533                 INSIST(lctx->done != NULL && lctx->task != NULL);
02534                 result = DNS_R_CONTINUE;
02535         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
02536                 result = lctx->result;
02537 
02538         if (result == ISC_R_SUCCESS && callbacks->rawdata != NULL)
02539                 (*callbacks->rawdata)(callbacks->zone, &lctx->header);
02540 
02541  cleanup:
02542         if (rdata != NULL)
02543                 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
02544         if (target_mem != NULL)
02545                 isc_mem_put(mctx, target_mem, target_size);
02546         if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
02547                 (*callbacks->error)(callbacks, "dns_master_load: %s",
02548                                     dns_result_totext(result));
02549         }
02550 
02551         return (result);
02552 }
02553 
02554 isc_result_t
02555 dns_master_loadfile(const char *master_file, dns_name_t *top,
02556                     dns_name_t *origin,
02557                     dns_rdataclass_t zclass, unsigned int options,
02558                     dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
02559 {
02560         return (dns_master_loadfile5(master_file, top, origin, zclass,
02561                                      options, 0, callbacks, NULL, NULL,
02562                                      mctx, dns_masterformat_text, 0));
02563 }
02564 
02565 isc_result_t
02566 dns_master_loadfile2(const char *master_file, dns_name_t *top,
02567                      dns_name_t *origin,
02568                      dns_rdataclass_t zclass, unsigned int options,
02569                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
02570                      dns_masterformat_t format)
02571 {
02572         return (dns_master_loadfile5(master_file, top, origin, zclass,
02573                                      options, 0, callbacks, NULL, NULL,
02574                                      mctx, format, 0));
02575 }
02576 
02577 isc_result_t
02578 dns_master_loadfile3(const char *master_file, dns_name_t *top,
02579                      dns_name_t *origin, dns_rdataclass_t zclass,
02580                      unsigned int options, isc_uint32_t resign,
02581                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
02582                      dns_masterformat_t format)
02583 {
02584         return (dns_master_loadfile5(master_file, top, origin, zclass,
02585                                      options, resign, callbacks, NULL, NULL,
02586                                      mctx, format, 0));
02587 }
02588 
02589 isc_result_t
02590 dns_master_loadfile4(const char *master_file, dns_name_t *top,
02591                      dns_name_t *origin, dns_rdataclass_t zclass,
02592                      unsigned int options, isc_uint32_t resign,
02593                      dns_rdatacallbacks_t *callbacks,
02594                      dns_masterincludecb_t include_cb, void *include_arg,
02595                      isc_mem_t *mctx, dns_masterformat_t format)
02596 {
02597         return (dns_master_loadfile5(master_file, top, origin, zclass,
02598                                      options, resign, callbacks,
02599                                      include_cb, include_arg,
02600                                      mctx, format, 0));
02601 }
02602 
02603 isc_result_t
02604 dns_master_loadfile5(const char *master_file, dns_name_t *top,
02605                      dns_name_t *origin, dns_rdataclass_t zclass,
02606                      unsigned int options, isc_uint32_t resign,
02607                      dns_rdatacallbacks_t *callbacks,
02608                      dns_masterincludecb_t include_cb, void *include_arg,
02609                      isc_mem_t *mctx, dns_masterformat_t format,
02610                      dns_ttl_t maxttl)
02611 {
02612         dns_loadctx_t *lctx = NULL;
02613         isc_result_t result;
02614 
02615         result = loadctx_create(format, mctx, options, resign, top, zclass,
02616                                 origin, callbacks, NULL, NULL, NULL,
02617                                 include_cb, include_arg, NULL, &lctx);
02618         if (result != ISC_R_SUCCESS)
02619                 return (result);
02620 
02621         lctx->maxttl = maxttl;
02622 
02623         result = (lctx->openfile)(lctx, master_file);
02624         if (result != ISC_R_SUCCESS)
02625                 goto cleanup;
02626 
02627         result = (lctx->load)(lctx);
02628         INSIST(result != DNS_R_CONTINUE);
02629 
02630  cleanup:
02631         dns_loadctx_detach(&lctx);
02632         return (result);
02633 }
02634 
02635 isc_result_t
02636 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
02637                        dns_name_t *origin, dns_rdataclass_t zclass,
02638                        unsigned int options, dns_rdatacallbacks_t *callbacks,
02639                        isc_task_t *task, dns_loaddonefunc_t done,
02640                        void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
02641 {
02642         return (dns_master_loadfileinc4(master_file, top, origin, zclass,
02643                                         options, 0, callbacks, task, done,
02644                                         done_arg, lctxp, NULL, NULL, mctx,
02645                                         dns_masterformat_text));
02646 }
02647 
02648 isc_result_t
02649 dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
02650                         dns_name_t *origin, dns_rdataclass_t zclass,
02651                         unsigned int options, dns_rdatacallbacks_t *callbacks,
02652                         isc_task_t *task, dns_loaddonefunc_t done,
02653                         void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
02654                         dns_masterformat_t format)
02655 {
02656         return (dns_master_loadfileinc4(master_file, top, origin, zclass,
02657                                         options, 0, callbacks, task, done,
02658                                         done_arg, lctxp, NULL, NULL, mctx,
02659                                         format));
02660 }
02661 
02662 isc_result_t
02663 dns_master_loadfileinc3(const char *master_file, dns_name_t *top,
02664                         dns_name_t *origin, dns_rdataclass_t zclass,
02665                         unsigned int options, isc_uint32_t resign,
02666                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
02667                         dns_loaddonefunc_t done, void *done_arg,
02668                         dns_loadctx_t **lctxp, isc_mem_t *mctx,
02669                         dns_masterformat_t format)
02670 {
02671         return (dns_master_loadfileinc4(master_file, top, origin, zclass,
02672                                         options, resign, callbacks, task,
02673                                         done, done_arg, lctxp, NULL, NULL,
02674                                         mctx, format));
02675 }
02676 
02677 isc_result_t
02678 dns_master_loadfileinc4(const char *master_file, dns_name_t *top,
02679                         dns_name_t *origin, dns_rdataclass_t zclass,
02680                         unsigned int options, isc_uint32_t resign,
02681                         dns_rdatacallbacks_t *callbacks,
02682                         isc_task_t *task, dns_loaddonefunc_t done,
02683                         void *done_arg, dns_loadctx_t **lctxp,
02684                         dns_masterincludecb_t include_cb, void *include_arg,
02685                         isc_mem_t *mctx, dns_masterformat_t format)
02686 {
02687         options &= ~DNS_MASTER_CHECKTTL;
02688         return (dns_master_loadfileinc5(master_file, top, origin, zclass,
02689                                         options, resign, callbacks, task,
02690                                         done, done_arg, lctxp, include_cb,
02691                                         include_arg, mctx, format, 0));
02692 }
02693 
02694 isc_result_t
02695 dns_master_loadfileinc5(const char *master_file, dns_name_t *top,
02696                         dns_name_t *origin, dns_rdataclass_t zclass,
02697                         unsigned int options, isc_uint32_t resign,
02698                         dns_rdatacallbacks_t *callbacks,
02699                         isc_task_t *task, dns_loaddonefunc_t done,
02700                         void *done_arg, dns_loadctx_t **lctxp,
02701                         dns_masterincludecb_t include_cb, void *include_arg,
02702                         isc_mem_t *mctx, dns_masterformat_t format,
02703                         isc_uint32_t maxttl)
02704 {
02705         dns_loadctx_t *lctx = NULL;
02706         isc_result_t result;
02707 
02708         REQUIRE(task != NULL);
02709         REQUIRE(done != NULL);
02710 
02711         result = loadctx_create(format, mctx, options, resign, top, zclass,
02712                                 origin, callbacks, task, done, done_arg,
02713                                 include_cb, include_arg, NULL, &lctx);
02714         if (result != ISC_R_SUCCESS)
02715                 return (result);
02716 
02717         lctx->maxttl = maxttl;
02718 
02719         result = (lctx->openfile)(lctx, master_file);
02720         if (result != ISC_R_SUCCESS)
02721                 goto cleanup;
02722 
02723         result = task_send(lctx);
02724         if (result == ISC_R_SUCCESS) {
02725                 dns_loadctx_attach(lctx, lctxp);
02726                 return (DNS_R_CONTINUE);
02727         }
02728 
02729  cleanup:
02730         dns_loadctx_detach(&lctx);
02731         return (result);
02732 }
02733 
02734 isc_result_t
02735 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
02736                       dns_rdataclass_t zclass, unsigned int options,
02737                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
02738 {
02739         isc_result_t result;
02740         dns_loadctx_t *lctx = NULL;
02741 
02742         REQUIRE(stream != NULL);
02743 
02744         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02745                                 zclass, origin, callbacks, NULL, NULL, NULL,
02746                                 NULL, NULL, NULL, &lctx);
02747         if (result != ISC_R_SUCCESS)
02748                 goto cleanup;
02749 
02750         result = isc_lex_openstream(lctx->lex, stream);
02751         if (result != ISC_R_SUCCESS)
02752                 goto cleanup;
02753 
02754         result = (lctx->load)(lctx);
02755         INSIST(result != DNS_R_CONTINUE);
02756 
02757  cleanup:
02758         if (lctx != NULL)
02759                 dns_loadctx_detach(&lctx);
02760         return (result);
02761 }
02762 
02763 isc_result_t
02764 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
02765                          dns_rdataclass_t zclass, unsigned int options,
02766                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
02767                          dns_loaddonefunc_t done, void *done_arg,
02768                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
02769 {
02770         isc_result_t result;
02771         dns_loadctx_t *lctx = NULL;
02772 
02773         REQUIRE(stream != NULL);
02774         REQUIRE(task != NULL);
02775         REQUIRE(done != NULL);
02776 
02777         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02778                                 zclass, origin, callbacks, task, done,
02779                                 done_arg, NULL, NULL, NULL, &lctx);
02780         if (result != ISC_R_SUCCESS)
02781                 goto cleanup;
02782 
02783         result = isc_lex_openstream(lctx->lex, stream);
02784         if (result != ISC_R_SUCCESS)
02785                 goto cleanup;
02786 
02787         result = task_send(lctx);
02788         if (result == ISC_R_SUCCESS) {
02789                 dns_loadctx_attach(lctx, lctxp);
02790                 return (DNS_R_CONTINUE);
02791         }
02792 
02793  cleanup:
02794         if (lctx != NULL)
02795                 dns_loadctx_detach(&lctx);
02796         return (result);
02797 }
02798 
02799 isc_result_t
02800 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
02801                       dns_name_t *origin, dns_rdataclass_t zclass,
02802                       unsigned int options,
02803                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
02804 {
02805         isc_result_t result;
02806         dns_loadctx_t *lctx = NULL;
02807 
02808         REQUIRE(buffer != NULL);
02809 
02810         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02811                                 zclass, origin, callbacks, NULL, NULL, NULL,
02812                                 NULL, NULL, NULL, &lctx);
02813         if (result != ISC_R_SUCCESS)
02814                 return (result);
02815 
02816         result = isc_lex_openbuffer(lctx->lex, buffer);
02817         if (result != ISC_R_SUCCESS)
02818                 goto cleanup;
02819 
02820         result = (lctx->load)(lctx);
02821         INSIST(result != DNS_R_CONTINUE);
02822 
02823  cleanup:
02824         dns_loadctx_detach(&lctx);
02825         return (result);
02826 }
02827 
02828 isc_result_t
02829 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
02830                          dns_name_t *origin, dns_rdataclass_t zclass,
02831                          unsigned int options,
02832                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
02833                          dns_loaddonefunc_t done, void *done_arg,
02834                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
02835 {
02836         isc_result_t result;
02837         dns_loadctx_t *lctx = NULL;
02838 
02839         REQUIRE(buffer != NULL);
02840         REQUIRE(task != NULL);
02841         REQUIRE(done != NULL);
02842 
02843         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02844                                 zclass, origin, callbacks, task, done,
02845                                 done_arg, NULL, NULL, NULL, &lctx);
02846         if (result != ISC_R_SUCCESS)
02847                 return (result);
02848 
02849         result = isc_lex_openbuffer(lctx->lex, buffer);
02850         if (result != ISC_R_SUCCESS)
02851                 goto cleanup;
02852 
02853         result = task_send(lctx);
02854         if (result == ISC_R_SUCCESS) {
02855                 dns_loadctx_attach(lctx, lctxp);
02856                 return (DNS_R_CONTINUE);
02857         }
02858 
02859  cleanup:
02860         dns_loadctx_detach(&lctx);
02861         return (result);
02862 }
02863 
02864 isc_result_t
02865 dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
02866                      dns_name_t *origin, dns_rdataclass_t zclass,
02867                      unsigned int options,
02868                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
02869 {
02870         isc_result_t result;
02871         dns_loadctx_t *lctx = NULL;
02872 
02873         REQUIRE(lex != NULL);
02874 
02875         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02876                                 zclass, origin, callbacks, NULL, NULL, NULL,
02877                                 NULL, NULL, lex, &lctx);
02878         if (result != ISC_R_SUCCESS)
02879                 return (result);
02880 
02881         result = (lctx->load)(lctx);
02882         INSIST(result != DNS_R_CONTINUE);
02883 
02884         dns_loadctx_detach(&lctx);
02885         return (result);
02886 }
02887 
02888 isc_result_t
02889 dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
02890                         dns_name_t *origin, dns_rdataclass_t zclass,
02891                         unsigned int options,
02892                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
02893                         dns_loaddonefunc_t done, void *done_arg,
02894                         dns_loadctx_t **lctxp, isc_mem_t *mctx)
02895 {
02896         isc_result_t result;
02897         dns_loadctx_t *lctx = NULL;
02898 
02899         REQUIRE(lex != NULL);
02900         REQUIRE(task != NULL);
02901         REQUIRE(done != NULL);
02902 
02903         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
02904                                 zclass, origin, callbacks, task, done,
02905                                 done_arg, NULL, NULL, lex, &lctx);
02906         if (result != ISC_R_SUCCESS)
02907                 return (result);
02908 
02909         result = task_send(lctx);
02910         if (result == ISC_R_SUCCESS) {
02911                 dns_loadctx_attach(lctx, lctxp);
02912                 return (DNS_R_CONTINUE);
02913         }
02914 
02915         dns_loadctx_detach(&lctx);
02916         return (result);
02917 }
02918 
02919 /*
02920  * Grow the slab of dns_rdatalist_t structures.
02921  * Re-link glue and current list.
02922  */
02923 static dns_rdatalist_t *
02924 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
02925                rdatalist_head_t *current, rdatalist_head_t *glue,
02926                isc_mem_t *mctx)
02927 {
02928         dns_rdatalist_t *new;
02929         int rdlcount = 0;
02930         ISC_LIST(dns_rdatalist_t) save;
02931         dns_rdatalist_t *this;
02932 
02933         new = isc_mem_get(mctx, new_len * sizeof(*new));
02934         if (new == NULL)
02935                 return (NULL);
02936 
02937         ISC_LIST_INIT(save);
02938         while ((this = ISC_LIST_HEAD(*current)) != NULL) {
02939                 ISC_LIST_UNLINK(*current, this, link);
02940                 ISC_LIST_APPEND(save, this, link);
02941         }
02942         while ((this = ISC_LIST_HEAD(save)) != NULL) {
02943                 ISC_LIST_UNLINK(save, this, link);
02944                 INSIST(rdlcount < new_len);
02945                 new[rdlcount] = *this;
02946                 ISC_LIST_APPEND(*current, &new[rdlcount], link);
02947                 rdlcount++;
02948         }
02949 
02950         ISC_LIST_INIT(save);
02951         while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
02952                 ISC_LIST_UNLINK(*glue, this, link);
02953                 ISC_LIST_APPEND(save, this, link);
02954         }
02955         while ((this = ISC_LIST_HEAD(save)) != NULL) {
02956                 ISC_LIST_UNLINK(save, this, link);
02957                 INSIST(rdlcount < new_len);
02958                 new[rdlcount] = *this;
02959                 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
02960                 rdlcount++;
02961         }
02962 
02963         INSIST(rdlcount == old_len);
02964         if (old != NULL)
02965                 isc_mem_put(mctx, old, old_len * sizeof(*old));
02966         return (new);
02967 }
02968 
02969 /*
02970  * Grow the slab of rdata structs.
02971  * Re-link the current and glue chains.
02972  */
02973 static dns_rdata_t *
02974 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
02975            rdatalist_head_t *current, rdatalist_head_t *glue,
02976            isc_mem_t *mctx)
02977 {
02978         dns_rdata_t *new;
02979         int rdcount = 0;
02980         ISC_LIST(dns_rdata_t) save;
02981         dns_rdatalist_t *this;
02982         dns_rdata_t *rdata;
02983 
02984         new = isc_mem_get(mctx, new_len * sizeof(*new));
02985         if (new == NULL)
02986                 return (NULL);
02987         memset(new, 0, new_len * sizeof(*new));
02988 
02989         /*
02990          * Copy current relinking.
02991          */
02992         this = ISC_LIST_HEAD(*current);
02993         while (this != NULL) {
02994                 ISC_LIST_INIT(save);
02995                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
02996                         ISC_LIST_UNLINK(this->rdata, rdata, link);
02997                         ISC_LIST_APPEND(save, rdata, link);
02998                 }
02999                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
03000                         ISC_LIST_UNLINK(save, rdata, link);
03001                         INSIST(rdcount < new_len);
03002                         new[rdcount] = *rdata;
03003                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
03004                         rdcount++;
03005                 }
03006                 this = ISC_LIST_NEXT(this, link);
03007         }
03008 
03009         /*
03010          * Copy glue relinking.
03011          */
03012         this = ISC_LIST_HEAD(*glue);
03013         while (this != NULL) {
03014                 ISC_LIST_INIT(save);
03015                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
03016                         ISC_LIST_UNLINK(this->rdata, rdata, link);
03017                         ISC_LIST_APPEND(save, rdata, link);
03018                 }
03019                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
03020                         ISC_LIST_UNLINK(save, rdata, link);
03021                         INSIST(rdcount < new_len);
03022                         new[rdcount] = *rdata;
03023                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
03024                         rdcount++;
03025                 }
03026                 this = ISC_LIST_NEXT(this, link);
03027         }
03028         INSIST(rdcount == old_len || rdcount == 0);
03029         if (old != NULL)
03030                 isc_mem_put(mctx, old, old_len * sizeof(*old));
03031         return (new);
03032 }
03033 
03034 static isc_uint32_t
03035 resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) {
03036         dns_rdata_t *rdata;
03037         dns_rdata_rrsig_t sig;
03038         isc_uint32_t when;
03039 
03040         rdata = ISC_LIST_HEAD(this->rdata);
03041         INSIST(rdata != NULL);
03042         (void)dns_rdata_tostruct(rdata, &sig, NULL);
03043         when = sig.timeexpire - resign;
03044 
03045         rdata = ISC_LIST_NEXT(rdata, link);
03046         while (rdata != NULL) {
03047                 (void)dns_rdata_tostruct(rdata, &sig, NULL);
03048                 if (sig.timeexpire - resign < when)
03049                         when = sig.timeexpire - resign;
03050                 rdata = ISC_LIST_NEXT(rdata, link);
03051         }
03052         return (when);
03053 }
03054 
03055 /*
03056  * Convert each element from a rdatalist_t to rdataset then call commit.
03057  * Unlink each element as we go.
03058  */
03059 
03060 static isc_result_t
03061 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
03062        rdatalist_head_t *head, dns_name_t *owner,
03063        const char *source, unsigned int line)
03064 {
03065         dns_rdatalist_t *this;
03066         dns_rdataset_t dataset;
03067         isc_result_t result;
03068         char namebuf[DNS_NAME_FORMATSIZE];
03069         void    (*error)(struct dns_rdatacallbacks *, const char *, ...);
03070 
03071         this = ISC_LIST_HEAD(*head);
03072         error = callbacks->error;
03073 
03074         if (this == NULL)
03075                 return (ISC_R_SUCCESS);
03076         do {
03077                 dns_rdataset_init(&dataset);
03078                 RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
03079                               == ISC_R_SUCCESS);
03080                 dataset.trust = dns_trust_ultimate;
03081                 /*
03082                  * If this is a secure dynamic zone set the re-signing time.
03083                  */
03084                 if (dataset.type == dns_rdatatype_rrsig &&
03085                     (lctx->options & DNS_MASTER_RESIGN) != 0) {
03086                         dataset.attributes |= DNS_RDATASETATTR_RESIGN;
03087                         dataset.resign = resign_fromlist(this, lctx->resign);
03088                 }
03089                 result = ((*callbacks->add)(callbacks->add_private, owner,
03090                                             &dataset));
03091                 if (result == ISC_R_NOMEMORY) {
03092                         (*error)(callbacks, "dns_master_load: %s",
03093                                  dns_result_totext(result));
03094                 } else if (result != ISC_R_SUCCESS) {
03095                         dns_name_format(owner, namebuf, sizeof(namebuf));
03096                         if (source != NULL) {
03097                                 (*error)(callbacks, "%s: %s:%lu: %s: %s",
03098                                          "dns_master_load", source, line,
03099                                          namebuf, dns_result_totext(result));
03100                         } else {
03101                                 (*error)(callbacks, "%s: %s: %s",
03102                                          "dns_master_load", namebuf,
03103                                          dns_result_totext(result));
03104                         }
03105                 }
03106                 if (MANYERRS(lctx, result))
03107                         SETRESULT(lctx, result);
03108                 else if (result != ISC_R_SUCCESS)
03109                         return (result);
03110                 ISC_LIST_UNLINK(*head, this, link);
03111                 this = ISC_LIST_HEAD(*head);
03112         } while (this != NULL);
03113         return (ISC_R_SUCCESS);
03114 }
03115 
03116 /*
03117  * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
03118  */
03119 
03120 static isc_boolean_t
03121 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
03122         dns_rdatalist_t *this;
03123         dns_rdata_t *rdata;
03124         isc_region_t region;
03125         dns_name_t name;
03126 
03127         /*
03128          * Find NS rrset.
03129          */
03130         this = ISC_LIST_HEAD(*head);
03131         while (this != NULL) {
03132                 if (this->type == dns_rdatatype_ns)
03133                         break;
03134                 this = ISC_LIST_NEXT(this, link);
03135         }
03136         if (this == NULL)
03137                 return (ISC_FALSE);
03138 
03139         rdata = ISC_LIST_HEAD(this->rdata);
03140         while (rdata != NULL) {
03141                 dns_name_init(&name, NULL);
03142                 dns_rdata_toregion(rdata, &region);
03143                 dns_name_fromregion(&name, &region);
03144                 if (dns_name_compare(&name, owner) == 0)
03145                         return (ISC_TRUE);
03146                 rdata = ISC_LIST_NEXT(rdata, link);
03147         }
03148         return (ISC_FALSE);
03149 }
03150 
03151 static void
03152 load_quantum(isc_task_t *task, isc_event_t *event) {
03153         isc_result_t result;
03154         dns_loadctx_t *lctx;
03155 
03156         REQUIRE(event != NULL);
03157         lctx = event->ev_arg;
03158         REQUIRE(DNS_LCTX_VALID(lctx));
03159 
03160         if (lctx->canceled)
03161                 result = ISC_R_CANCELED;
03162         else
03163                 result = (lctx->load)(lctx);
03164         if (result == DNS_R_CONTINUE) {
03165                 event->ev_arg = lctx;
03166                 isc_task_send(task, &event);
03167         } else {
03168                 (lctx->done)(lctx->done_arg, result);
03169                 isc_event_free(&event);
03170                 dns_loadctx_detach(&lctx);
03171         }
03172 }
03173 
03174 static isc_result_t
03175 task_send(dns_loadctx_t *lctx) {
03176         isc_event_t *event;
03177 
03178         event = isc_event_allocate(lctx->mctx, NULL,
03179                                    DNS_EVENT_MASTERQUANTUM,
03180                                    load_quantum, lctx, sizeof(*event));
03181         if (event == NULL)
03182                 return (ISC_R_NOMEMORY);
03183         isc_task_send(lctx->task, &event);
03184         return (ISC_R_SUCCESS);
03185 }
03186 
03187 void
03188 dns_loadctx_cancel(dns_loadctx_t *lctx) {
03189         REQUIRE(DNS_LCTX_VALID(lctx));
03190 
03191         LOCK(&lctx->lock);
03192         lctx->canceled = ISC_TRUE;
03193         UNLOCK(&lctx->lock);
03194 }
03195 
03196 void
03197 dns_master_initrawheader(dns_masterrawheader_t *header) {
03198         memset(header, 0, sizeof(dns_masterrawheader_t));
03199 }

Generated on Tue Apr 28 17:40:58 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha