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