diff options
Diffstat (limited to 'bin/named/server.c')
-rw-r--r-- | bin/named/server.c | 216 |
1 files changed, 154 insertions, 62 deletions
diff --git a/bin/named/server.c b/bin/named/server.c index 5d97a6b7..e6c6ca6d 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -386,6 +386,12 @@ end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); static void newzone_cfgctx_destroy(void **cfgp); +static isc_result_t +putstr(isc_buffer_t *b, const char *str); + +isc_result_t +add_comment(FILE *fp, const char *viewname); + /*% * Configure a single view ACL at '*aclp'. Get its configuration from * 'vconfig' (for per-view configuration) and maybe from 'config' @@ -1928,15 +1934,14 @@ create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view, obj = NULL; (void)cfg_map_get(zoptions, "type", &obj); INSIST(obj != NULL); - if (strcasecmp(cfg_obj_asstring(obj), "forward") != 0) - continue; - - obj = NULL; - (void)cfg_map_get(zoptions, "forward", &obj); - if (obj == NULL) - continue; - if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) - continue; + if (strcasecmp(cfg_obj_asstring(obj), "forward") == 0) { + obj = NULL; + (void)cfg_map_get(zoptions, "forward", &obj); + if (obj == NULL) + continue; + if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) + continue; + } if (db == NULL) { CHECK(dns_db_create(view->mctx, "rbt", name, dns_dbtype_zone, view->rdclass, @@ -6501,16 +6506,18 @@ next_token(char **stringp, const char *delim) { */ static isc_result_t zone_from_args(ns_server_t *server, char *args, const char *zonetxt, - dns_zone_t **zonep, const char **zonename, isc_boolean_t skip) + dns_zone_t **zonep, const char **zonename, + isc_buffer_t *text, isc_boolean_t skip) { char *input, *ptr; char *classtxt; const char *viewtxt = NULL; - dns_fixedname_t name; + dns_fixedname_t fname; + dns_name_t *name; isc_result_t result; - isc_buffer_t buf; dns_view_t *view = NULL; dns_rdataclass_t rdclass; + char problem[DNS_NAME_FORMATSIZE + 500] = ""; REQUIRE(zonep != NULL && *zonep == NULL); REQUIRE(zonename == NULL || *zonename == NULL); @@ -6539,38 +6546,40 @@ zone_from_args(ns_server_t *server, char *args, const char *zonetxt, viewtxt = next_token(&input, " \t"); } - isc_buffer_constinit(&buf, zonetxt, strlen(zonetxt)); - isc_buffer_add(&buf, strlen(zonetxt)); - dns_fixedname_init(&name); - result = dns_name_fromtext(dns_fixedname_name(&name), - &buf, dns_rootname, 0, NULL); - if (result != ISC_R_SUCCESS) - goto fail1; + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + CHECK(dns_name_fromstring(name, zonetxt, 0, NULL)); if (classtxt != NULL) { isc_textregion_t r; r.base = classtxt; r.length = strlen(classtxt); - result = dns_rdataclass_fromtext(&rdclass, &r); - if (result != ISC_R_SUCCESS) - goto fail1; + CHECK(dns_rdataclass_fromtext(&rdclass, &r)); } else rdclass = dns_rdataclass_in; if (viewtxt == NULL) { - result = dns_viewlist_findzone(&server->viewlist, - dns_fixedname_name(&name), + result = dns_viewlist_findzone(&server->viewlist, name, ISC_TF(classtxt == NULL), rdclass, zonep); + if (result == ISC_R_NOTFOUND) + snprintf(problem, sizeof(problem), + "no matching zone '%s' in any view", + zonetxt); } else { result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass, &view); - if (result != ISC_R_SUCCESS) - goto fail1; + if (result != ISC_R_SUCCESS) { + snprintf(problem, sizeof(problem), + "no matching view '%s'", viewtxt); + goto report; + } - result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), - 0, NULL, zonep); - dns_view_detach(&view); + result = dns_zt_find(view->zonetable, name, 0, NULL, zonep); + if (result != ISC_R_SUCCESS) + snprintf(problem, sizeof(problem), + "no matching zone '%s' in view '%s'", + zonetxt, viewtxt); } /* Partial match? */ @@ -6578,7 +6587,20 @@ zone_from_args(ns_server_t *server, char *args, const char *zonetxt, dns_zone_detach(zonep); if (result == DNS_R_PARTIALMATCH) result = ISC_R_NOTFOUND; - fail1: + report: + if (result != ISC_R_SUCCESS) { + isc_result_t tresult; + + tresult = putstr(text, problem); + if (tresult == ISC_R_SUCCESS && + isc_buffer_availablelength(text) > 0U) + isc_buffer_putuint8(text, 0); + } + + cleanup: + if (view != NULL) + dns_view_detach(&view); + return (result); } @@ -6586,13 +6608,16 @@ zone_from_args(ns_server_t *server, char *args, const char *zonetxt, * Act on a "retransfer" command from the command channel. */ isc_result_t -ns_server_retransfercommand(ns_server_t *server, char *args) { +ns_server_retransfercommand(ns_server_t *server, char *args, + isc_buffer_t *text) +{ isc_result_t result; dns_zone_t *zone = NULL; dns_zone_t *raw = NULL; dns_zonetype_t type; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -6622,7 +6647,8 @@ ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { dns_zonetype_t type; const char *msg = NULL; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) { @@ -6682,7 +6708,8 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { dns_zone_t *zone = NULL; const unsigned char msg[] = "zone notify queued"; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -6702,17 +6729,25 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { isc_result_t ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { isc_result_t result; - dns_zone_t *zone = NULL; + dns_zone_t *zone = NULL, *raw = NULL; const unsigned char msg1[] = "zone refresh queued"; const unsigned char msg2[] = "not a slave or stub zone"; dns_zonetype_t type; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) return (ISC_R_UNEXPECTEDEND); + dns_zone_getraw(zone, &raw); + if (raw != NULL) { + dns_zone_detach(&zone); + dns_zone_attach(raw, &zone); + dns_zone_detach(&raw); + } + type = dns_zone_gettype(zone); if (type == dns_zone_slave || type == dns_zone_stub) { dns_zone_refresh(zone); @@ -7828,7 +7863,7 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { * Act on a "sign" or "loadkeys" command from the command channel. */ isc_result_t -ns_server_rekey(ns_server_t *server, char *args) { +ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text) { isc_result_t result; dns_zone_t *zone = NULL; dns_zonetype_t type; @@ -7838,7 +7873,8 @@ ns_server_rekey(ns_server_t *server, char *args) { if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0) fullsign = ISC_TRUE; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -7911,7 +7947,8 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) { arg = next_token(&args, " \t"); } - result = zone_from_args(server, args, arg, &zone, NULL, ISC_FALSE); + result = zone_from_args(server, args, arg, &zone, NULL, + text, ISC_FALSE); if (result != ISC_R_SUCCESS) return (result); @@ -7987,7 +8024,8 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, isc_boolean_t frozen; const char *msg = NULL; - result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE); + result = zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_TRUE); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) { @@ -8113,6 +8151,23 @@ ns_smf_add_message(isc_buffer_t *text) { #endif /* HAVE_LIBSCF */ /* + * Emit a comment at the top of the nzf file containing the viewname + * Expects the fp to already be open for writing + */ +#define HEADER1 "# New zone file for view: " +#define HEADER2 "\n# This file contains configuration for zones added by\n" \ + "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n" +isc_result_t +add_comment(FILE *fp, const char *viewname) { + isc_result_t result; + CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL)); + CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL)); + CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL)); + cleanup: + return (result); +} + +/* * Act on an "addzone" command from the command channel. */ isc_result_t @@ -8140,10 +8195,11 @@ ns_server_add_zone(ns_server_t *server, char *args) { FILE *fp = NULL; struct cfg_context *cfg = NULL; char namebuf[DNS_NAME_FORMATSIZE]; + off_t offset; /* Try to parse the argument string */ arglen = strlen(args); - isc_buffer_init(&argbuf, args, arglen); + isc_buffer_init(&argbuf, args, (unsigned int)arglen); isc_buffer_add(&argbuf, strlen(args)); CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, @@ -8213,6 +8269,9 @@ ns_server_add_zone(ns_server_t *server, char *args) { /* Open save file for write configuration */ CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); + CHECK(isc_stdio_tell(fp, &offset)); + if (offset == 0) + CHECK(add_comment(fp, view->name)); /* Mark view unfrozen so that zone can be added */ result = isc_task_beginexclusive(server->task); @@ -8312,20 +8371,22 @@ ns_server_add_zone(ns_server_t *server, char *args) { * Act on a "delzone" command from the command channel. */ isc_result_t -ns_server_del_zone(ns_server_t *server, char *args) { - isc_result_t result; - dns_zone_t *zone = NULL; - dns_view_t *view = NULL; - dns_db_t *dbp = NULL; - const char *filename = NULL; - char *tmpname = NULL; - char buf[1024]; - const char *zonename = NULL; - size_t znamelen = 0; - FILE *ifp = NULL, *ofp = NULL; +ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_view_t *view = NULL; + dns_db_t *dbp = NULL; + const char *filename = NULL; + char *tmpname = NULL; + char buf[1024]; + const char *zonename = NULL; + size_t znamelen = 0; + FILE *ifp = NULL, *ofp = NULL; + isc_boolean_t inheader = ISC_TRUE; /* Parse parameters */ - CHECK(zone_from_args(server, args, NULL, &zone, &zonename, ISC_TRUE)); + CHECK(zone_from_args(server, args, NULL, &zone, &zonename, + text, ISC_TRUE)); if (zone == NULL) { result = ISC_R_UNEXPECTEDEND; @@ -8367,28 +8428,44 @@ ns_server_del_zone(ns_server_t *server, char *args) { goto cleanup; } CHECK(isc_stdio_open(tmpname, "w", &ofp)); + CHECK(add_comment(ofp, view->name)); /* Look for the entry for that zone */ while (fgets(buf, 1024, ifp)) { - /* A 'zone' line */ - if (strncasecmp(buf, "zone", 4)) { + /* Skip initial comment, if any */ + if (inheader && *buf == '#') + continue; + if (*buf != '#') + inheader = ISC_FALSE; + + /* + * Any other lines not starting with zone, copy + * them out and continue. + */ + if (strncasecmp(buf, "zone", 4) != 0) { fputs(buf, ofp); continue; } p = buf+4; - /* Locate a name */ + /* This is a zone; find its name. */ while (*p && ((*p == '"') || isspace((unsigned char)*p))) p++; - /* Is that the zone we're looking for */ - if (strncasecmp(p, zonename, znamelen)) { + /* + * If it's not the zone we're looking for, copy + * it out and continue + */ + if (strncasecmp(p, zonename, znamelen) != 0) { fputs(buf, ofp); continue; } - /* And nothing else? */ + /* + * But if it is the zone we want, skip over it + * so it will be omitted from the new file + */ p += znamelen; if (isspace((unsigned char)*p) || *p == '"' || *p == '{') { @@ -8397,7 +8474,7 @@ ns_server_del_zone(ns_server_t *server, char *args) { break; } - /* Spit it out, keep looking */ + /* Copy the rest of the buffer out and continue */ fputs(buf, ofp); } @@ -8575,7 +8652,8 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) { } else CHECK(DNS_R_SYNTAX); - CHECK(zone_from_args(server, args, NULL, &zone, NULL, ISC_FALSE)); + CHECK(zone_from_args(server, args, NULL, &zone, NULL, + text, ISC_FALSE)); if (zone == NULL) CHECK(ISC_R_UNEXPECTEDEND); @@ -8630,7 +8708,7 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) { if (n >= isc_buffer_availablelength(text)) CHECK(ISC_R_NOSPACE); - isc_buffer_add(text, n); + isc_buffer_add(text, (unsigned int)n); } if (!first && isc_buffer_availablelength(text) > 0) isc_buffer_putuint8(text, 0); @@ -8653,3 +8731,17 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) { return (result); } + +static isc_result_t +putstr(isc_buffer_t *b, const char *str) { + size_t l = strlen(str); + + /* + * Use >= to leave space for NUL termination. + */ + if (l >= isc_buffer_availablelength(b)) + return (ISC_R_NOSPACE); + + isc_buffer_putmem(b, (const unsigned char *)str, l); + return (ISC_R_SUCCESS); +} |