OpenDNSSEC-enforcer  2.1.4
ods-migrate.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 #include "config.h"
28 
29 #include <getopt.h>
30 #include <dlfcn.h>
31 #include <libxml/parser.h>
32 
33 #ifdef HAVE_SQLITE3
34 #include <sqlite3.h>
35 #endif
36 #ifdef HAVE_MYSQL
37 #include <mysql/mysql.h>
38 #endif
39 
40 #include "log.h"
41 #include "libhsm.h"
42 #include "daemon/cfg.h"
43 #include "libhsmdns.h"
44 extern hsm_repository_t* parse_conf_repositories(const char* cfgfile);
45 
47 char* argv0;
48 
49 static void
50 usage(void)
51 {
52  fprintf(stderr, "%s [-h] [-v] [-c <alternate-configuration>]\n", argv0);
53 }
54 
55 typedef void (*functioncast_t)(void);
56 extern functioncast_t functioncast(void*generic);
57 
59 functioncast(void*generic) {
60  functioncast_t* function = (functioncast_t*)&generic;
61  return *function;
62 }
63 
64 /****************************************************************************/
65 
67  void (*foreach)(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*));
68  void (*close)(void);
69 } dblayer;
70 
71 #ifdef HAVE_SQLITE3
72 
73 #define CHECKSQLITE(EX) do { dblayer_sqlite3.message = NULL; if((dblayer_sqlite3.status = (EX)) != SQLITE_OK) { fprintf(stderr, "%s: sql error: %s (%d)\n%s:%d: %s\n",argv0,(dblayer_sqlite3.message?dblayer_sqlite3.message:dblayer_sqlite3.sqlite3_errmsg(dblayer_sqlite3.handle)),dblayer_sqlite3.status,__FILE__,__LINE__,#EX); if(dblayer_sqlite3.message) dblayer_sqlite3.sqlite3_free(dblayer_sqlite3.message); } } while(0)
74 
75 struct dblayer_sqlite3_struct {
76  int status;
77  char* message;
78  void* library;
79  sqlite3* handle;
80  int (*sqlite3_prepare_v2)(sqlite3 *, const char *, int , sqlite3_stmt **, const char **);
81  int (*sqlite3_reset)(sqlite3_stmt *pStmt);
82  int (*sqlite3_bind_int)(sqlite3_stmt*, int, int);
83  int (*sqlite3_finalize)(sqlite3_stmt *pStmt);
84  int (*sqlite3_open)(const char *filename, sqlite3 **ppDb);
85  int (*sqlite3_exec)(sqlite3*, const char *sql, int (*callback)(void*, int, char**, char**), void *, char **errmsg);
86  int (*sqlite3_step)(sqlite3_stmt*);
87  int (*sqlite3_close)(sqlite3*);
88  const char* (*sqlite3_errmsg)(sqlite3*);
89  int (*sqlite3_free)(void*);
90 };
91 struct dblayer_sqlite3_struct dblayer_sqlite3;
92 
93 static void
94 dblayer_sqlite3_initialize(void)
95 {
96  void *handle;
97  char const *error;
98 
99  dlerror();
100  handle = dlopen(SQLITE3_SONAME, RTLD_NOW);
101  if ((error = dlerror()) != NULL) {
102  printf("Failed to load sqlite3 library. dlerror(): %s\n", error);
103  exit(1);
104  }
105 
106  dblayer_sqlite3.sqlite3_prepare_v2 = (int(*)(sqlite3*, const char*, int, sqlite3_stmt**, const char **))functioncast(dlsym(handle, "sqlite3_prepare_v2"));
107  dblayer_sqlite3.sqlite3_reset = (int(*)(sqlite3_stmt*)) functioncast(dlsym(handle, "sqlite3_reset"));
108  dblayer_sqlite3.sqlite3_bind_int = (int(*)(sqlite3_stmt*, int, int))functioncast(dlsym(handle, "sqlite3_bind_int"));
109  dblayer_sqlite3.sqlite3_finalize = (int(*)(sqlite3_stmt*))functioncast(dlsym(handle, "sqlite3_finalize"));
110  dblayer_sqlite3.sqlite3_open = (int(*)(const char*, sqlite3**)) functioncast(dlsym(handle, "sqlite3_open"));
111  dblayer_sqlite3.sqlite3_exec = (int(*)(sqlite3*, const char*, int(*)(void*, int, char**, char**), void*, char **)) functioncast(dlsym(handle, "sqlite3_exec"));
112  dblayer_sqlite3.sqlite3_step = (int(*)(sqlite3_stmt*)) functioncast(dlsym(handle, "sqlite3_step"));
113  dblayer_sqlite3.sqlite3_close = (int(*)(sqlite3*)) functioncast(dlsym(handle, "sqlite3_close"));
114  dblayer_sqlite3.sqlite3_errmsg = (const char*(*)(sqlite3*)) functioncast(dlsym(handle, "sqlite3_errmsg"));
115  dblayer_sqlite3.sqlite3_free = (int(*)(void*)) functioncast(dlsym(handle, "sqlite3_free"));
116 
117  if (!dblayer_sqlite3.sqlite3_open) {
118  printf("Failed to load sqlite3 library.\n");
119  exit(1);
120  }
121 }
122 
123 static void
124 dblayer_sqlite3_close(void)
125 {
126  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
127 }
128 
129 struct callbackoperation {
130  int (*compute)(char **argv, int* id, uint16_t *keytag);
131  sqlite3_stmt* updateStmt;
132 };
133 
134 static int
135 callback(void *cargo, int argc, char **argv, char **names)
136 {
137  int status;
138  int id;
139  uint16_t keytag;
140  struct callbackoperation* operation = (struct callbackoperation*) cargo;
141 
142  operation->compute(argv, &id, &keytag);
143 
144  CHECKSQLITE(dblayer_sqlite3.sqlite3_reset(operation->updateStmt));
145  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 1, keytag));
146  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 2, id));
147  do {
148  switch ((status = dblayer_sqlite3.sqlite3_step(operation->updateStmt))) {
149  case SQLITE_ROW:
150  break;
151  case SQLITE_DONE:
152  break;
153  case SQLITE_BUSY:
154  sleep(1);
155  break;
156  case SQLITE_ERROR:
157  case SQLITE_MISUSE:
158  default:
159  fprintf(stderr, "%s: sql error: %s\n", argv0, dblayer_sqlite3.sqlite3_errmsg(dblayer_sqlite3.handle));
160  break;
161  }
162  } while(status == SQLITE_BUSY);
163  return SQLITE_OK;
164 }
165 
166 static void
167 dblayer_sqlite3_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
168 {
169  struct callbackoperation operation;
170  const char* queryEnd;
171  operation.compute = compute;
172  CHECKSQLITE(dblayer_sqlite3.sqlite3_prepare_v2(dblayer_sqlite3.handle, updateQueryStr, strlen(updateQueryStr)+1, &operation.updateStmt, &queryEnd));
173  CHECKSQLITE(dblayer_sqlite3.sqlite3_exec(dblayer_sqlite3.handle, listQueryStr, callback, &operation, &dblayer_sqlite3.message));
174  CHECKSQLITE(dblayer_sqlite3.sqlite3_finalize(operation.updateStmt));
175  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
176 }
177 
178 static void
179 dblayer_sqlite3_open(const char *datastore) {
180  CHECKSQLITE(dblayer_sqlite3.sqlite3_open(datastore, &dblayer_sqlite3.handle));
181  dblayer.close = &dblayer_sqlite3_close;
182  dblayer.foreach = &dblayer_sqlite3_foreach;
183 }
184 
185 #endif
186 
187 /****************************************************************************/
188 
189 #ifdef HAVE_MYSQL
190 
191 struct dblayer_mysql_struct {
192  MYSQL* handle;
193 };
194 extern struct dblayer_mysql_struct dblayer_mysql;
195 struct dblayer_mysql_struct dblayer_mysql;
196 
197 
198 static void
199 dblayer_mysql_initialize(void) {
200  if (mysql_library_init(0, NULL, NULL)) {
201  fprintf(stderr, "could not initialize MySQL library\n");
202  exit(1);
203  }
204 }
205 
206 static void
207 dblayer_mysql_close(void)
208 {
209  if (dblayer_mysql.handle) {
210  mysql_close(dblayer_mysql.handle);
211  dblayer_mysql.handle = NULL;
212  }
213 }
214 
215 static void
216 dblayer_mysql_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
217 {
218  int id;
219  uint16_t keytag;
220  MYSQL_BIND bind[2];
221  MYSQL_STMT *updateStmt;
222  MYSQL_RES* res;
223  MYSQL_ROW row;
224  updateStmt = mysql_stmt_init(dblayer_mysql.handle);
225  mysql_stmt_prepare(updateStmt, updateQueryStr, strlen(updateQueryStr) + 1);
226  mysql_query(dblayer_mysql.handle, listQueryStr);
227  res = mysql_store_result(dblayer_mysql.handle);
228  if (!res) {
229  fprintf(stderr, "Failed to update db. Is it set correctly in conf.xml?\n");
230  exit(1);
231  }
232  mysql_num_fields(res);
233  while ((row = mysql_fetch_row(res))) {
234  compute(row, &id, &keytag);
235  memset(bind, 0, sizeof (bind));
236  bind[0].buffer = &keytag;
237  bind[0].buffer_length = sizeof(keytag);
238  bind[0].buffer_type = MYSQL_TYPE_SHORT;
239  bind[0].is_unsigned = 1;
240  bind[1].buffer = &id;
241  bind[1].buffer_length = sizeof(id);
242  bind[1].buffer_type = MYSQL_TYPE_LONG;
243  mysql_stmt_bind_param(updateStmt, bind);
244  mysql_stmt_execute(updateStmt);
245  mysql_stmt_affected_rows(updateStmt);
246  }
247  mysql_free_result(res);
248  mysql_stmt_close(updateStmt);
249 }
250 
251 static void
252 dblayer_mysql_open(const char* host, const char* user, const char* pass,
253  const char *rsrc, unsigned int port, const char *unix_socket)
254 {
255  dblayer_mysql.handle = mysql_init(NULL);
256  if (!mysql_real_connect(dblayer_mysql.handle, host, user, pass, rsrc, port, NULL, 0)) {
257  fprintf(stderr, "Failed to connect to database: Error: %s\n",
258  mysql_error(dblayer_mysql.handle));
259  exit(1);
260  }
261  dblayer.close = &dblayer_mysql_close;
262  dblayer.foreach = &dblayer_mysql_foreach;
263 
264 }
265 
266 #endif
267 
268 /****************************************************************************/
269 
270 static void
271 dblayer_initialize(void)
272 {
273 #ifdef HAVE_SQLITE3
274  dblayer_sqlite3_initialize();
275 #endif
276 #ifdef HAVE_MYSQL
277  dblayer_mysql_initialize();
278 #endif
279 }
280 
281 static void
282 dblayer_close(void) {
283  dblayer.close();
284 }
285 
286 static void
287 dblayer_finalize(void) {
288 #ifdef HAVE_MYSQL
289  mysql_library_end();
290 #endif
291 }
292 
293 static void
294 dblayer_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
295 {
297 }
298 
299 /****************************************************************************/
300 
301 const char* listQueryStr = "select keyData.id,keyData.algorithm,keyData.role,keyData.keytag,hsmKey.locator from keyData join hsmKey on keyData.hsmKeyId = hsmKey.id";
302 const char* updateQueryStr = "update keyData set keytag = ? where id = ?";
303 
304 static int
305 compute(char **argv, int* id, uint16_t* keytag)
306 {
307  char *locator;
308  int algorithm;
309  int ksk;
310 
311  *id = atoi(argv[0]);
312  algorithm = atoi(argv[1]);
313  ksk = (atoi(argv[2]) == 1);
314  *keytag = atoi(argv[3]);
315  locator = argv[4];
316  hsm_keytag(locator, algorithm, ksk, keytag);
317 
318  return 0;
319 }
320 
321 int
322 main(int argc, char* argv[])
323 {
324  ods_status status;
325  engineconfig_type* cfg;
326  int c;
327  int options_index = 0;
328  const char* cfgfile = ODS_SE_CFGFILE;
329  static struct option long_options[] = {
330  {"config", required_argument, 0, 'c'},
331  {"help", no_argument, 0, 'h'},
332  {"verbose", no_argument, 0, 'v'},
333  { 0, 0, 0, 0}
334  };
335 
336  argv0 = argv[0];
337 
338  /* parse the commandline */
339  while ((c=getopt_long(argc, argv, "c:hv", long_options, &options_index)) != -1) {
340  switch (c) {
341  case 'c':
342  cfgfile = optarg;
343  break;
344  case 'h':
345  usage();
346  exit(0);
347  case 'v':
348  ++verbosity;
349  break;
350  default:
351  usage();
352  exit(1);
353  }
354  }
355  argc -= optind;
356  argv += optind;
357  if (argc != 0) {
358  usage();
359  exit(1);
360  }
361 
362  ods_log_init("ods-migrate", 0, NULL, verbosity);
363 
364  xmlInitGlobals();
365  xmlInitParser();
366  xmlInitThreads();
367 
368  tzset(); /* for portability */
369 
370  /* Parse config file */
371  cfg = engine_config(cfgfile, verbosity, NULL);
372  cfg->verbosity = verbosity;
373  /* does it make sense? */
374  if (engine_config_check(cfg) != ODS_STATUS_OK) {
375  abort(); /* TODO give some error, abort */
376  }
377 
378  status = hsm_open2(parse_conf_repositories(cfgfile), hsm_prompt_pin);
379  if (status != HSM_OK) {
380  char* errorstr = hsm_get_error(NULL);
381  if (errorstr != NULL) {
382  fprintf(stderr, "%s", errorstr);
383  free(errorstr);
384  abort(); /* FIXME */
385  } else {
386  fprintf(stderr,"error opening libhsm (errno %i)\n", status);
387  }
388  return 1;
389  }
390  dblayer_initialize();
391 
392  switch (cfg->db_type) {
394 #ifdef HAVE_SQLITE3
395  dblayer_sqlite3_open(cfg->datastore);
396 #else
397  fprintf(stderr, "Database SQLite3 not available during compile-time.\n");
398 #endif
399  break;
401 #ifdef HAVE_MYSQL
402  dblayer_mysql_open(cfg->db_host, cfg->db_username, cfg->db_password, cfg->datastore, cfg->db_port, NULL);
403 #else
404  fprintf(stderr, "Database MySQL not available during compile-time.\n");
405 #endif
406  break;
408  default:
409  fprintf(stderr, "No database defined\n");
410  }
411 
412  dblayer_foreach(listQueryStr, updateQueryStr, &compute);
413 
414  hsm_close();
415 
417  /* dblayer_foreach for each frees something dblayer_close uses
418  * We better just let it leak. */
419  /* dblayer_close(); */
420  dblayer_finalize();
421  ods_log_close();
422 
423  xmlCleanupParser();
424  xmlCleanupGlobals();
425 
426  return 0;
427 }
void engine_config_cleanup(engineconfig_type *config)
Definition: cfg.c:278
const char * datastore
Definition: cfg.h:68
int verbosity
Definition: ods-migrate.c:46
struct dblayer_struct dblayer
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition: confparser.c:205
engineconfig_type * engine_config(const char *cfgfile, int cmdline_verbosity, engineconfig_type *oldcfg)
Definition: cfg.c:59
const char * db_host
Definition: cfg.h:69
const char * db_password
Definition: cfg.h:71
void(* close)(void)
Definition: ods-migrate.c:68
const char * db_username
Definition: cfg.h:70
const char * updateQueryStr
Definition: ods-migrate.c:302
void(* functioncast_t)(void)
Definition: ods-migrate.c:55
ods_status engine_config_check(engineconfig_type *config)
Definition: cfg.c:155
functioncast_t functioncast(void *generic)
Definition: ods-migrate.c:59
void(* foreach)(const char *listQueryStr, const char *updateQueryStr, int(*compute)(char **, int *, uint16_t *))
Definition: ods-migrate.c:67
char * argv0
Definition: ods-migrate.c:47
int main(int argc, char *argv[])
Definition: ods-migrate.c:322
engineconfig_database_type_t db_type
Definition: cfg.h:80
const char * listQueryStr
Definition: ods-migrate.c:301