control.c revision 1.3
1/* $NetBSD: control.c,v 1.3 2019/01/09 16:54:59 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 15/*! \file */ 16 17#include <config.h> 18 19#include <stdbool.h> 20 21#include <isc/app.h> 22#include <isc/event.h> 23#include <isc/lex.h> 24#include <isc/mem.h> 25#include <isc/string.h> 26#include <isc/timer.h> 27#include <isc/util.h> 28 29#include <dns/result.h> 30 31#include <isccc/alist.h> 32#include <isccc/cc.h> 33#include <isccc/result.h> 34 35#include <named/control.h> 36#include <named/globals.h> 37#include <named/log.h> 38#include <named/os.h> 39#include <named/server.h> 40#ifdef HAVE_LIBSCF 41#include <named/smf_globals.h> 42#endif 43 44static isc_result_t 45getcommand(isc_lex_t *lex, char **cmdp) { 46 isc_result_t result; 47 isc_token_t token; 48 49 REQUIRE(cmdp != NULL && *cmdp == NULL); 50 51 result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF, &token); 52 if (result != ISC_R_SUCCESS) 53 return (result); 54 55 isc_lex_ungettoken(lex, &token); 56 57 if (token.type != isc_tokentype_string) 58 return (ISC_R_FAILURE); 59 60 *cmdp = token.value.as_textregion.base; 61 62 return (ISC_R_SUCCESS); 63} 64 65static inline bool 66command_compare(const char *str, const char *command) { 67 return (strcasecmp(str, command) == 0); 68} 69 70/*% 71 * This function is called to process the incoming command 72 * when a control channel message is received. 73 */ 74isc_result_t 75named_control_docommand(isccc_sexpr_t *message, bool readonly, 76 isc_buffer_t **text) 77{ 78 isccc_sexpr_t *data; 79 char *cmdline = NULL; 80 char *command = NULL; 81 isc_result_t result; 82 int log_level; 83 isc_buffer_t src; 84 isc_lex_t *lex = NULL; 85#ifdef HAVE_LIBSCF 86 named_smf_want_disable = 0; 87#endif 88 89 data = isccc_alist_lookup(message, "_data"); 90 if (!isccc_alist_alistp(data)) { 91 /* 92 * No data section. 93 */ 94 return (ISC_R_FAILURE); 95 } 96 97 result = isccc_cc_lookupstring(data, "type", &cmdline); 98 if (result != ISC_R_SUCCESS) { 99 /* 100 * We have no idea what this is. 101 */ 102 return (result); 103 } 104 105 result = isc_lex_create(named_g_mctx, strlen(cmdline), &lex); 106 if (result != ISC_R_SUCCESS) 107 return (result); 108 109 isc_buffer_init(&src, cmdline, strlen(cmdline)); 110 isc_buffer_add(&src, strlen(cmdline)); 111 result = isc_lex_openbuffer(lex, &src); 112 if (result != ISC_R_SUCCESS) 113 goto cleanup; 114 115 result = getcommand(lex, &command); 116 if (result != ISC_R_SUCCESS) 117 goto cleanup; 118 119 /* 120 * Compare the 'command' parameter against all known control commands. 121 */ 122 if ((command_compare(command, NAMED_COMMAND_NULL) && 123 strlen(cmdline) == 4) || 124 command_compare(command, NAMED_COMMAND_STATUS)) 125 { 126 log_level = ISC_LOG_DEBUG(1); 127 } else { 128 log_level = ISC_LOG_INFO; 129 } 130 131 /* 132 * If this listener should have read-only access, reject 133 * restricted commands here. rndc nta is handled specially 134 * below. 135 */ 136 if (readonly && 137 !command_compare(command, NAMED_COMMAND_NTA) && 138 !command_compare(command, NAMED_COMMAND_NULL) && 139 !command_compare(command, NAMED_COMMAND_STATUS) && 140 !command_compare(command, NAMED_COMMAND_SHOWZONE) && 141 !command_compare(command, NAMED_COMMAND_TESTGEN) && 142 !command_compare(command, NAMED_COMMAND_ZONESTATUS)) 143 { 144 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 145 NAMED_LOGMODULE_CONTROL, log_level, 146 "rejecting restricted control channel " 147 "command '%s'", cmdline); 148 result = ISC_R_FAILURE; 149 goto cleanup; 150 } 151 152 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 153 NAMED_LOGMODULE_CONTROL, log_level, 154 "received control channel command '%s'", 155 cmdline); 156 157 if (command_compare(command, NAMED_COMMAND_RELOAD)) { 158 result = named_server_reloadcommand(named_g_server, lex, text); 159 } else if (command_compare(command, NAMED_COMMAND_RECONFIG)) { 160 result = named_server_reconfigcommand(named_g_server); 161 } else if (command_compare(command, NAMED_COMMAND_REFRESH)) { 162 result = named_server_refreshcommand(named_g_server, lex, text); 163 } else if (command_compare(command, NAMED_COMMAND_RETRANSFER)) { 164 result = named_server_retransfercommand(named_g_server, 165 lex, text); 166 } else if (command_compare(command, NAMED_COMMAND_HALT)) { 167#ifdef HAVE_LIBSCF 168 /* 169 * If we are managed by smf(5), AND in chroot, then 170 * we cannot connect to the smf repository, so just 171 * return with an appropriate message back to rndc. 172 */ 173 if (named_smf_got_instance == 1 && named_smf_chroot == 1) { 174 result = named_smf_add_message(text); 175 goto cleanup; 176 } 177 /* 178 * If we are managed by smf(5) but not in chroot, 179 * try to disable ourselves the smf way. 180 */ 181 if (named_smf_got_instance == 1 && named_smf_chroot == 0) 182 named_smf_want_disable = 1; 183 /* 184 * If named_smf_got_instance = 0, named_smf_chroot 185 * is not relevant and we fall through to 186 * isc_app_shutdown below. 187 */ 188#endif 189 /* Do not flush master files */ 190 named_server_flushonshutdown(named_g_server, false); 191 named_os_shutdownmsg(cmdline, *text); 192 isc_app_shutdown(); 193 result = ISC_R_SUCCESS; 194 } else if (command_compare(command, NAMED_COMMAND_STOP)) { 195 /* 196 * "stop" is the same as "halt" except it does 197 * flush master files. 198 */ 199#ifdef HAVE_LIBSCF 200 if (named_smf_got_instance == 1 && named_smf_chroot == 1) { 201 result = named_smf_add_message(text); 202 goto cleanup; 203 } 204 if (named_smf_got_instance == 1 && named_smf_chroot == 0) 205 named_smf_want_disable = 1; 206#endif 207 named_server_flushonshutdown(named_g_server, true); 208 named_os_shutdownmsg(cmdline, *text); 209 isc_app_shutdown(); 210 result = ISC_R_SUCCESS; 211 } else if (command_compare(command, NAMED_COMMAND_DUMPSTATS)) { 212 result = named_server_dumpstats(named_g_server); 213 } else if (command_compare(command, NAMED_COMMAND_QUERYLOG)) { 214 result = named_server_togglequerylog(named_g_server, lex); 215 } else if (command_compare(command, NAMED_COMMAND_DUMPDB)) { 216 named_server_dumpdb(named_g_server, lex, text); 217 result = ISC_R_SUCCESS; 218 } else if (command_compare(command, NAMED_COMMAND_SECROOTS)) { 219 result = named_server_dumpsecroots(named_g_server, lex, text); 220 } else if (command_compare(command, NAMED_COMMAND_TRACE)) { 221 result = named_server_setdebuglevel(named_g_server, lex); 222 } else if (command_compare(command, NAMED_COMMAND_NOTRACE)) { 223 named_g_debuglevel = 0; 224 isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); 225 result = ISC_R_SUCCESS; 226 } else if (command_compare(command, NAMED_COMMAND_FLUSH)) { 227 result = named_server_flushcache(named_g_server, lex); 228 } else if (command_compare(command, NAMED_COMMAND_FLUSHNAME)) { 229 result = named_server_flushnode(named_g_server, lex, false); 230 } else if (command_compare(command, NAMED_COMMAND_FLUSHTREE)) { 231 result = named_server_flushnode(named_g_server, lex, true); 232 } else if (command_compare(command, NAMED_COMMAND_STATUS)) { 233 result = named_server_status(named_g_server, text); 234 } else if (command_compare(command, NAMED_COMMAND_TSIGLIST)) { 235 result = named_server_tsiglist(named_g_server, text); 236 } else if (command_compare(command, NAMED_COMMAND_TSIGDELETE)) { 237 result = named_server_tsigdelete(named_g_server, lex, text); 238 } else if (command_compare(command, NAMED_COMMAND_FREEZE)) { 239 result = named_server_freeze(named_g_server, true, lex, 240 text); 241 } else if (command_compare(command, NAMED_COMMAND_UNFREEZE) || 242 command_compare(command, NAMED_COMMAND_THAW)) { 243 result = named_server_freeze(named_g_server, false, lex, 244 text); 245 } else if (command_compare(command, NAMED_COMMAND_SCAN)) { 246 result = ISC_R_SUCCESS; 247 named_server_scan_interfaces(named_g_server); 248 } else if (command_compare(command, NAMED_COMMAND_SYNC)) { 249 result = named_server_sync(named_g_server, lex, text); 250 } else if (command_compare(command, NAMED_COMMAND_RECURSING)) { 251 result = named_server_dumprecursing(named_g_server); 252 } else if (command_compare(command, NAMED_COMMAND_TIMERPOKE)) { 253 result = ISC_R_SUCCESS; 254 isc_timermgr_poke(named_g_timermgr); 255 } else if (command_compare(command, NAMED_COMMAND_NULL)) { 256 result = ISC_R_SUCCESS; 257 } else if (command_compare(command, NAMED_COMMAND_NOTIFY)) { 258 result = named_server_notifycommand(named_g_server, lex, text); 259 } else if (command_compare(command, NAMED_COMMAND_VALIDATION)) { 260 result = named_server_validation(named_g_server, lex, text); 261 } else if (command_compare(command, NAMED_COMMAND_SIGN) || 262 command_compare(command, NAMED_COMMAND_LOADKEYS)) { 263 result = named_server_rekey(named_g_server, lex, text); 264 } else if (command_compare(command, NAMED_COMMAND_ADDZONE) || 265 command_compare(command, NAMED_COMMAND_MODZONE)) { 266 result = named_server_changezone(named_g_server, cmdline, text); 267 } else if (command_compare(command, NAMED_COMMAND_DELZONE)) { 268 result = named_server_delzone(named_g_server, lex, text); 269 } else if (command_compare(command, NAMED_COMMAND_SHOWZONE)) { 270 result = named_server_showzone(named_g_server, lex, text); 271 } else if (command_compare(command, NAMED_COMMAND_SIGNING)) { 272 result = named_server_signing(named_g_server, lex, text); 273 } else if (command_compare(command, NAMED_COMMAND_ZONESTATUS)) { 274 result = named_server_zonestatus(named_g_server, lex, text); 275 } else if (command_compare(command, NAMED_COMMAND_NTA)) { 276 result = named_server_nta(named_g_server, lex, readonly, text); 277 } else if (command_compare(command, NAMED_COMMAND_TESTGEN)) { 278 result = named_server_testgen(lex, text); 279 } else if (command_compare(command, NAMED_COMMAND_MKEYS)) { 280 result = named_server_mkeys(named_g_server, lex, text); 281 } else if (command_compare(command, NAMED_COMMAND_DNSTAP) || 282 command_compare(command, NAMED_COMMAND_DNSTAPREOPEN)) { 283 result = named_server_dnstap(named_g_server, lex, text); 284 } else if (command_compare(command, NAMED_COMMAND_TCPTIMEOUTS)) { 285 result = named_server_tcptimeouts(lex, text); 286 } else if (command_compare(command, NAMED_COMMAND_SERVESTALE)) { 287 result = named_server_servestale(named_g_server, lex, text); 288 } else { 289 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 290 NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, 291 "unknown control channel command '%s'", 292 command); 293 result = DNS_R_UNKNOWNCOMMAND; 294 } 295 296 cleanup: 297 if (lex != NULL) 298 isc_lex_destroy(&lex); 299 300 return (result); 301} 302