OpenDNSSEC-enforcer  2.1.10
zone_add_cmd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 .SE (The Internet Infrastructure Foundation).
3  * Copyright (c) 2014 OpenDNSSEC AB (svb)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 #include "config.h"
30 
31 #include "daemon/engine.h"
32 #include "cmdhandler.h"
34 #include "file.h"
35 #include "str.h"
36 #include "log.h"
37 #include "clientpipe.h"
38 #include "db/policy.h"
39 #include "db/zone_db.h"
41 #include "enforcer/enforce_task.h"
42 #include "hsmkey/hsm_key_factory.h"
43 
44 #include "keystate/zone_add_cmd.h"
45 
46 #include <limits.h>
47 #include <getopt.h>
48 
49 static const char *module_str = "zone_add_cmd";
50 
51 static void
52 usage(int sockfd)
53 {
54  client_printf(sockfd,
55  "zone add\n"
56  " --zone <zone> aka -z\n"
57  " [--policy <policy>] aka -p\n"
58  " [--signerconf <path>] aka -s\n"
59  " [--in-type <type>] aka -j\n"
60  );
61  client_printf(sockfd,
62  " [--input <path>] aka -i\n"
63  " [--out-type <type>] aka -q\n"
64  " [--output <path>] aka -o\n"
65  " [--xml] aka -u\n"
66  );
67 }
68 
69 static void
70 help(int sockfd)
71 {
72  client_printf(sockfd,
73  "Add a new zone to the enforcer database.\n"
74  "\nOptions:\n"
75  "zone name of the zone\n"
76  "policy name of the policy, if not set the default policy is used\n"
77  "signerconf specify a location for signer configuration file, default is /var/lib/opendnssec/signconf/\n"
78  "in-type specify the type of input, should be DNS or File, default is File \n"
79  "input specify a location for the unsigned zone, this location is set in conf.xml, default for File Adapter is /var/lib/opendnssec/unsigned/ and for DNS Adapter is /etc/opendnssec/addns.xml \n"
80  "out-type specify the type of output, should be DNS or File, default is File\n"
81  "output specify a location for the signed zone, this location is set in conf.xml, default path for File Adapter is /var/lib/opendnssec/signed/ and for DNS Adapter is /etc/opendnssec/addns.xml \n"
82  "xml update the zonelist.xml file\n\n"
83  );
84 }
85 
86 static int
87 run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
88 {
89  #define NARGV 18
90  char* buf;
91  const char* argv[NARGV];
92  int argc = 0;
93  const char *zone_name = NULL;
94  const char *policy_name = NULL;
95  const char *signconf = NULL;
96  const char *input = NULL;
97  const char *output = NULL;
98  const char *input_type = NULL;
99  const char *output_type = NULL;
100  char path[PATH_MAX];
101  int write_xml = 0;
102  policy_t* policy;
103  zone_db_t* zone;
104  int ret = 0;
105  int suspend = 0;
106  int long_index = 0, opt = 0;
107  db_connection_t* dbconn = getconnectioncontext(context);
108  engine_type* engine = getglobalcontext(context);
109 
110  static struct option long_options[] = {
111  {"zone", required_argument, 0, 'z'},
112  {"policy", required_argument, 0, 'p'},
113  {"signerconf", required_argument, 0, 's'},
114  {"input", required_argument, 0, 'i'},
115  {"output", required_argument, 0, 'o'},
116  {"in-type", required_argument, 0, 'j'},
117  {"out-type", required_argument, 0, 'q'},
118  {"xml", no_argument, 0, 'u'},
119  {"suspend", no_argument, 0, 'n'},
120  {0, 0, 0, 0}
121  };
122 
123  ods_log_debug("[%s] %s command", module_str, zone_add_funcblock.cmdname);
124 
125  if (!(buf = strdup(cmd))) {
126  client_printf_err(sockfd, "memory error\n");
127  return -1;
128  }
129  argc = ods_str_explode(buf, NARGV, argv);
130  if (argc == -1) {
131  client_printf_err(sockfd, "too many arguments\n");
132  ods_log_error("[%s] too many arguments for %s command",
133  module_str, zone_add_funcblock.cmdname);
134  free(buf);
135  return -1;
136  }
137 
138  optind = 0;
139  while ((opt = getopt_long(argc, (char* const*)argv, "z:p:s:i:o:j:q:un", long_options, &long_index)) != -1) {
140  switch (opt) {
141  case 'z':
142  zone_name = optarg;
143  break;
144  case 'p':
145  policy_name = optarg;
146  break;
147  case 's':
148  signconf = optarg;
149  break;
150  case 'i':
151  input = optarg;
152  break;
153  case 'o':
154  output = optarg;
155  break;
156  case 'j':
157  input_type = optarg;
158  break;
159  case 'q':
160  output_type = optarg;
161  break;
162  case 'u':
163  write_xml = 1;
164  break;
165  case 'n':
166  suspend = 1;
167  break;
168  default:
169  client_printf_err(sockfd, "unknown arguments\n");
170  ods_log_error("[%s] unknown arguments for %s command",
171  module_str, zone_add_funcblock.cmdname);
172  free(buf);
173  return -1;
174  }
175  }
176 
177  if (!zone_name) {
178  client_printf_err(sockfd, "expected option --zone <zone>\n");
179  free(buf);
180  return -1;
181  }
182 
183  if ((zone = zone_db_new_get_by_name(dbconn, zone_name))) {
184  client_printf_err(sockfd, "Unable to add zone, zone already exists!\n");
185  zone_db_free(zone);
186  free(buf);
187  return 1;
188  }
189 
190  if (!(policy = policy_new_get_by_name(dbconn, (policy_name ? policy_name : "default")))) {
191  client_printf_err(sockfd, "Unable to find policy %s needed for adding the zone!\n", (policy_name ? policy_name : "default"));
192  free(buf);
193  return 1;
194  }
195 
196  if (!(zone = zone_db_new(dbconn))) {
197  client_printf_err(sockfd, "Unable to add zone, memory allocation problem!\n");
198  }
199  if (zone_db_set_name(zone, zone_name)) {
200  client_printf_err(sockfd, "Unable to add zone, failed to set zone name!\n");
201  }
202  if (zone_db_set_policy_id(zone, policy_id(policy))) {
203  client_printf_err(sockfd, "Unable to add zone, failed to set policy!\n");
204  }
205  if (input_type) {
206  if (!strcasecmp(input_type, "DNS"))
207  input_type = "DNS";
208  else if (!strcasecmp(input_type, "File"))
209  input_type = "File";
210  else {
211  client_printf_err(sockfd, "Unable to add zone, %s is not a valid input type! in_type must be File or DNS.\n", input_type);
212  return 1;
213  }
214  if (zone_db_set_input_adapter_type(zone, input_type)) {
215  client_printf_err(sockfd, "Unable to add zone, failed to set input type!\n");
216  }
217  }
218  if (input) {
219  if (input[0] == '/') {
220  if (zone_db_set_input_adapter_uri(zone, input)) {
221  client_printf_err(sockfd, "Unable to add zone, failed to set input!\n");
222  }
223  }
224  else {
225  if (input_type && !strcasecmp(input_type, "DNS")) {
226  if (snprintf(path, sizeof(path), "%s/%s", OPENDNSSEC_CONFIG_DIR, input) >= (int)sizeof(path)
227  || zone_db_set_input_adapter_uri(zone, path))
228  {
229  client_printf_err(sockfd, "Unable to add zone, failed to set input!\n");
230  }
231  }
232  else {
233  if (snprintf(path, sizeof(path), "%s/unsigned/%s", OPENDNSSEC_STATE_DIR, input) >= (int)sizeof(path)
234  || zone_db_set_input_adapter_uri(zone, path))
235  {
236  client_printf_err(sockfd, "Unable to add zone, failed to set input!\n");
237  }
238  }
239  }
240  }
241  else {
242  if (input_type && !strcasecmp(input_type, "DNS")) {
243  if (snprintf(path, sizeof(path), "%s/addns.xml", OPENDNSSEC_CONFIG_DIR) >= (int)sizeof(path)
244  || zone_db_set_input_adapter_uri(zone, path))
245  {
246  client_printf_err(sockfd, "Unable to add zone, failed to set input!\n");
247  }
248  }
249  else {
250  if (snprintf(path, sizeof(path), "%s/unsigned/%s", OPENDNSSEC_STATE_DIR, zone_name) >= (int)sizeof(path)
251  || zone_db_set_input_adapter_uri(zone, path))
252  {
253  client_printf_err(sockfd, "Unable to add zone, failed to set input!\n");
254  }
255  }
256  }
257  client_printf(sockfd, "input is set to %s. \n", zone_db_input_adapter_uri(zone));
258  if (access(zone_db_input_adapter_uri(zone), F_OK) == -1) {
259  client_printf_err(sockfd, "WARNING: The input file %s for zone %s does not currently exist. The zone will be added to the database anyway. \n", zone_db_input_adapter_uri(zone), zone_name);
260  ods_log_warning("[%s] WARNING: The input file %s for zone %s does not currently exist. The zone will be added to the database anyway.", module_str, zone_db_input_adapter_uri(zone), zone_name);
261  }
262  else if (access(zone_db_input_adapter_uri(zone), R_OK)) {
263  client_printf_err(sockfd, "WARNING: Read access to input file %s for zone %s denied! \n ", zone_db_input_adapter_uri(zone), zone_name);
264  ods_log_warning("[%s] WARNING: Read access to input file %s for zone %s denied! ", module_str, zone_db_input_adapter_uri(zone), zone_name);
265  }
266 
267  if (output_type) {
268  if (!strcasecmp(output_type, "DNS"))
269  output_type = "DNS";
270  else if (!strcasecmp(output_type, "File"))
271  output_type = "File";
272  else {
273  client_printf_err(sockfd, "Unable to add zone, %s is not a valid output type! out_type must be File or DNS.\n", output_type);
274  return 1;
275  }
276  if (zone_db_set_output_adapter_type(zone, output_type)) {
277  client_printf_err(sockfd, "Unable to add zone, failed to set output type!\n");
278  }
279  }
280  if (output) {
281  if (output[0] == '/') {
282  if (zone_db_set_output_adapter_uri(zone, output)) {
283  client_printf_err(sockfd, "Unable to add zone, failed to set output!\n");
284  }
285  }
286  else {
287  if (output_type && !strcasecmp(output_type, "DNS")) {
288  if (snprintf(path, sizeof(path), "%s/%s", OPENDNSSEC_CONFIG_DIR, output) >= (int)sizeof(path)
289  || zone_db_set_output_adapter_uri(zone, path))
290  {
291  client_printf_err(sockfd, "Unable to add zone, failed to set output!\n");
292  }
293  }
294  else {
295  if (snprintf(path, sizeof(path), "%s/signed/%s", OPENDNSSEC_STATE_DIR, output) >= (int)sizeof(path)
296  || zone_db_set_output_adapter_uri(zone, path))
297  {
298  client_printf_err(sockfd, "Unable to add zone, failed to set output!\n");
299  }
300  }
301  }
302  }
303  else {
304  if(output_type && !strcasecmp(output_type, "DNS")) {
305  if (snprintf(path, sizeof(path), "%s/addns.xml", OPENDNSSEC_CONFIG_DIR) >= (int)sizeof(path)
306  || zone_db_set_output_adapter_uri(zone, path))
307  {
308  client_printf_err(sockfd, "Unable to add zone, failed to set output!\n");
309  }
310  }
311  else {
312  if (snprintf(path, sizeof(path), "%s/signed/%s", OPENDNSSEC_STATE_DIR, zone_name) >= (int)sizeof(path)
313  || zone_db_set_output_adapter_uri(zone, path))
314  {
315  client_printf_err(sockfd, "Unable to add zone, failed to set output!\n");
316  }
317  }
318  }
319 
320  client_printf(sockfd, "output is set to %s. \n", zone_db_output_adapter_uri(zone));
321  if (output_type && !strcasecmp(output_type, "DNS")) {
322  if (access(zone_db_output_adapter_uri(zone), F_OK) == -1) {
323  client_printf_err(sockfd, "WARNING: The output file %s for zone %s does not currently exist. The zone will be added to the database anyway. \n", zone_db_output_adapter_uri(zone), zone_name);
324  ods_log_warning("[%s] WARNING: The output file %s for zone %s does not currently exist. The zone will be added to the database anyway.", module_str, zone_db_output_adapter_uri(zone), zone_name);
325  }
326  else if (access(zone_db_output_adapter_uri(zone), R_OK)) {
327  client_printf_err(sockfd, "WARNING: Read access to output file %s for zone %s denied! \n ", zone_db_output_adapter_uri(zone), zone_name);
328  ods_log_warning("[%s] WARNING: Read access to output file %s for zone %s denied! ", module_str, zone_db_output_adapter_uri(zone), zone_name);
329  }
330  }
331 
332  if (signconf) {
333  if (signconf[0] == '/') {
334  if (zone_db_set_signconf_path(zone, signconf)) {
335  client_printf_err(sockfd, "Unable to add zone, failed to set signconf!\n");
336  }
337  }
338  else {
339  if (snprintf(path, sizeof(path), "%s/signconf/%s", OPENDNSSEC_STATE_DIR, signconf) >= (int)sizeof(path)
340  || zone_db_set_signconf_path(zone, path))
341  {
342  client_printf_err(sockfd, "Unable to add zone, failed to set signconf!\n");
343  }
344  }
345  }
346  else {
347  if (snprintf(path, sizeof(path), "%s/signconf/%s.xml", OPENDNSSEC_STATE_DIR, zone_name) >= (int)sizeof(path)
348  || zone_db_set_signconf_path(zone, path))
349  {
350  client_printf_err(sockfd, "Unable to add zone, failed to set signconf!\n");
351  }
352  }
353  if (suspend) {
354  if (zone_db_set_next_change(zone, -1)) {
355  ods_log_error("[%s] Cannot suspend zone %s, database error!", module_str, zone_name);
356  client_printf_err(sockfd, "Cannot suspend zone %s, database error!\n", zone_name);
357  }
358  }
359 
360  if (zone_db_create(zone)) {
361  client_printf_err(sockfd, "Unable to add zone, database error!\n");
362  zone_db_free(zone);
364  free(buf);
365  return 1;
366  }
367  ods_log_info("[%s] zone %s added [policy: %s]", module_str, zone_name, (policy_name ? policy_name : "default"));
368  client_printf(sockfd, "Zone %s added successfully\n", zone_name);
369  free(buf);
370 
371  if (write_xml) {
372  if (zonelist_update_add(sockfd, engine->config->zonelist_filename, zone, 1) != ZONELIST_UPDATE_OK) {
373  ods_log_error("[%s] zonelist %s updated failed", module_str, engine->config->zonelist_filename);
374  client_printf_err(sockfd, "Zonelist %s update failed!\n", engine->config->zonelist_filename);
375  ret = 1;
376  }
377  else {
378  ods_log_info("[%s] zonelist %s updated successfully", module_str, engine->config->zonelist_filename);
379  client_printf(sockfd, "Zonelist %s updated successfully\n", engine->config->zonelist_filename);
380  }
381  }
382 
383  if (snprintf(path, sizeof(path), "%s/%s", engine->config->working_dir, OPENDNSSEC_ENFORCER_ZONELIST) >= (int)sizeof(path)
384  || zonelist_update_add(sockfd, path, zone, 0) != ZONELIST_UPDATE_OK)
385  {
386  ods_log_error("[%s] internal zonelist update failed", module_str);
387  client_printf_err(sockfd, "Unable to update the internal zonelist %s, updates will not reach the Signer!\n", path);
388  ret = 1;
389  }
390  else {
391  ods_log_info("[%s] internal zonelist updated successfully", module_str);
392  }
393 
394  /*
395  * On successful generate HSM keys and add/flush enforce task.
396  */
397  if (!suspend) {
398  if (!engine->config->manual_keygen)
399  (void)hsm_key_factory_generate_policy(engine, dbconn, policy, 0);
400  ods_log_debug("[%s] Flushing enforce task", module_str);
401  (void)schedule_task(engine->taskq, enforce_task(engine, zone->name), 1, 0);
402  }
403 
405 
406  zone_db_free(zone);
407 
408  return ret;
409 }
410 
411 struct cmd_func_block zone_add_funcblock = {
412  "zone add", &usage, &help, NULL, &run
413 };
task_type * enforce_task(engine_type *engine, char const *owner)
Definition: enforce_task.c:145
db_connection_t * getconnectioncontext(cmdhandler_ctx_type *context)
engine_type * getglobalcontext(cmdhandler_ctx_type *context)
int hsm_key_factory_generate_policy(engine_type *engine, const db_connection_t *connection, const policy_t *policy, time_t duration)
const char * policy_name(const policy_t *policy)
Definition: policy.c:813
const db_value_t * policy_id(const policy_t *policy)
Definition: policy.c:805
void policy_free(policy_t *policy)
Definition: policy.c:518
policy_t * policy_new_get_by_name(const db_connection_t *connection, const char *name)
Definition: policy.c:2090
schedule_type * taskq
Definition: engine.h:60
engineconfig_type * config
Definition: engine.h:48
const char * working_dir
Definition: cfg.h:64
const char * zonelist_filename
Definition: cfg.h:57
int manual_keygen
Definition: cfg.h:74
Definition: policy.h:60
char * name
Definition: zone_db.h:53
struct cmd_func_block zone_add_funcblock
Definition: zone_add_cmd.c:411
#define NARGV
int zone_db_set_input_adapter_type(zone_db_t *zone, const char *input_adapter_type_text)
Definition: zone_db.c:1061
const char * zone_db_output_adapter_uri(const zone_db_t *zone)
Definition: zone_db.c:886
void zone_db_free(zone_db_t *zone)
Definition: zone_db.c:325
int zone_db_set_output_adapter_type(zone_db_t *zone, const char *output_adapter_type_text)
Definition: zone_db.c:1105
int zone_db_set_policy_id(zone_db_t *zone, const db_value_t *policy_id)
Definition: zone_db.c:918
zone_db_t * zone_db_new(const db_connection_t *connection)
Definition: zone_db.c:287
int zone_db_create(zone_db_t *zone)
Definition: zone_db.c:1206
int zone_db_set_signconf_path(zone_db_t *zone, const char *signconf_path_text)
Definition: zone_db.c:969
int zone_db_set_output_adapter_uri(zone_db_t *zone, const char *output_adapter_uri_text)
Definition: zone_db.c:1127
int zone_db_set_name(zone_db_t *zone, const char *name_text)
Definition: zone_db.c:937
const char * zone_db_input_adapter_uri(const zone_db_t *zone)
Definition: zone_db.c:870
int zone_db_set_next_change(zone_db_t *zone, int next_change)
Definition: zone_db.c:991
zone_db_t * zone_db_new_get_by_name(const db_connection_t *connection, const char *name)
Definition: zone_db.c:1569
int zone_db_set_input_adapter_uri(zone_db_t *zone, const char *input_adapter_uri_text)
Definition: zone_db.c:1083
int zonelist_update_add(int sockfd, const char *filename, const zone_db_t *zone, int comment)
#define ZONELIST_UPDATE_OK