OpenDNSSEC-enforcer  2.0.2
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("libsqlite3.so", 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 
118 static void
119 dblayer_sqlite3_close(void)
120 {
121  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
122 }
123 
124 struct callbackoperation {
125  int (*compute)(char **argv, int* id, uint16_t *keytag);
126  sqlite3_stmt* updateStmt;
127 };
128 
129 static int
130 callback(void *cargo, int argc, char **argv, char **names)
131 {
132  int status;
133  int id;
134  uint16_t keytag;
135  struct callbackoperation* operation = (struct callbackoperation*) cargo;
136 
137  operation->compute(argv, &id, &keytag);
138 
139  CHECKSQLITE(dblayer_sqlite3.sqlite3_reset(operation->updateStmt));
140  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 1, keytag));
141  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 2, id));
142  do {
143  switch ((status = dblayer_sqlite3.sqlite3_step(operation->updateStmt))) {
144  case SQLITE_ROW:
145  break;
146  case SQLITE_DONE:
147  break;
148  case SQLITE_BUSY:
149  sleep(1);
150  break;
151  case SQLITE_ERROR:
152  case SQLITE_MISUSE:
153  default:
154  fprintf(stderr, "%s: sql error: %s\n", argv0, dblayer_sqlite3.sqlite3_errmsg(dblayer_sqlite3.handle));
155  break;
156  }
157  } while(status == SQLITE_BUSY);
158  return SQLITE_OK;
159 }
160 
161 static void
162 dblayer_sqlite3_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
163 {
164  struct callbackoperation operation;
165  const char* queryEnd;
166  operation.compute = compute;
167  CHECKSQLITE(dblayer_sqlite3.sqlite3_prepare_v2(dblayer_sqlite3.handle, updateQueryStr, strlen(updateQueryStr)+1, &operation.updateStmt, &queryEnd));
168  CHECKSQLITE(dblayer_sqlite3.sqlite3_exec(dblayer_sqlite3.handle, listQueryStr, callback, &operation, &dblayer_sqlite3.message));
169  CHECKSQLITE(dblayer_sqlite3.sqlite3_finalize(operation.updateStmt));
170  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
171 }
172 
173 static void
174 dblayer_sqlite3_open(const char *datastore) {
175  CHECKSQLITE(dblayer_sqlite3.sqlite3_open(datastore, &dblayer_sqlite3.handle));
176  dblayer.close = &dblayer_sqlite3_close;
177  dblayer.foreach = &dblayer_sqlite3_foreach;
178 }
179 
180 #endif
181 
182 /****************************************************************************/
183 
184 #ifdef HAVE_MYSQL
185 
186 struct dblayer_mysql_struct {
187  MYSQL* handle;
188 };
189 extern struct dblayer_mysql_struct dblayer_mysql;
190 struct dblayer_mysql_struct dblayer_mysql;
191 
192 
193 static void
194 dblayer_mysql_initialize(void) {
195  if (mysql_library_init(0, NULL, NULL)) {
196  fprintf(stderr, "could not initialize MySQL library\n");
197  exit(1);
198  }
199 }
200 
201 static void
202 dblayer_mysql_close(void)
203 {
204  if (dblayer_mysql.handle) {
205  mysql_close(dblayer_mysql.handle);
206  dblayer_mysql.handle = NULL;
207  }
208 }
209 
210 static void
211 dblayer_mysql_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
212 {
213  int id;
214  uint16_t keytag;
215  MYSQL_BIND bind[2];
216  MYSQL_STMT *updateStmt;
217  MYSQL_RES* res;
218  MYSQL_ROW row;
219  updateStmt = mysql_stmt_init(dblayer_mysql.handle);
220  mysql_stmt_prepare(updateStmt, updateQueryStr, strlen(updateQueryStr) + 1);
221  mysql_query(dblayer_mysql.handle, listQueryStr);
222  res = mysql_store_result(dblayer_mysql.handle);
223  if (!res) {
224  fprintf(stderr, "Failed to update db. Is it set correctly in conf.xml?\n");
225  exit(1);
226  }
227  mysql_num_fields(res);
228  while ((row = mysql_fetch_row(res))) {
229  compute(row, &id, &keytag);
230  memset(bind, 0, sizeof (bind));
231  bind[0].buffer = &keytag;
232  bind[0].buffer_length = sizeof(keytag);
233  bind[0].buffer_type = MYSQL_TYPE_SHORT;
234  bind[0].is_unsigned = 1;
235  bind[1].buffer = &id;
236  bind[1].buffer_length = sizeof(id);
237  bind[1].buffer_type = MYSQL_TYPE_LONG;
238  mysql_stmt_bind_param(updateStmt, bind);
239  mysql_stmt_execute(updateStmt);
240  mysql_stmt_affected_rows(updateStmt);
241  }
242  mysql_free_result(res);
243  mysql_stmt_close(updateStmt);
244 }
245 
246 static void
247 dblayer_mysql_open(const char* host, const char* user, const char* pass,
248  const char *rsrc, unsigned int port, const char *unix_socket)
249 {
250  dblayer_mysql.handle = mysql_init(NULL);
251  if (!mysql_real_connect(dblayer_mysql.handle, host, user, pass, rsrc, port, NULL, 0)) {
252  fprintf(stderr, "Failed to connect to database: Error: %s\n",
253  mysql_error(dblayer_mysql.handle));
254  exit(1);
255  }
256  dblayer.close = &dblayer_mysql_close;
257  dblayer.foreach = &dblayer_mysql_foreach;
258 
259 }
260 
261 #endif
262 
263 /****************************************************************************/
264 
265 static void
266 dblayer_initialize(void)
267 {
268 #ifdef HAVE_SQLITE3
269  dblayer_sqlite3_initialize();
270 #endif
271 #ifdef HAVE_MYSQL
272  dblayer_mysql_initialize();
273 #endif
274 }
275 
276 static void
277 dblayer_close(void) {
278  dblayer.close();
279 }
280 
281 static void
282 dblayer_finalize(void) {
283 #ifdef HAVE_MYSQL
284  mysql_library_end();
285 #endif
286 }
287 
288 static void
289 dblayer_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
290 {
292 }
293 
294 /****************************************************************************/
295 
296 const char* listQueryStr = "select keyData.id,keyData.algorithm,keyData.role,keyData.keytag,hsmKey.locator from keyData join hsmKey on keyData.hsmKeyId = hsmKey.id";
297 const char* updateQueryStr = "update keyData set keytag = ? where id = ?";
298 
299 static int
300 compute(char **argv, int* id, uint16_t* keytag)
301 {
302  char *locator;
303  int algorithm;
304  int ksk;
305 
306  *id = atoi(argv[0]);
307  algorithm = atoi(argv[1]);
308  ksk = (atoi(argv[2]) == 1);
309  *keytag = atoi(argv[3]);
310  locator = argv[4];
311  hsm_keytag(locator, algorithm, ksk, keytag);
312 
313  return 0;
314 }
315 
316 int
317 main(int argc, char* argv[])
318 {
319  ods_status status;
320  engineconfig_type* cfg;
321  int c;
322  int options_index = 0;
323  const char* cfgfile = ODS_SE_CFGFILE;
324  static struct option long_options[] = {
325  {"config", required_argument, 0, 'c'},
326  {"help", no_argument, 0, 'h'},
327  {"verbose", no_argument, 0, 'v'},
328  { 0, 0, 0, 0}
329  };
330 
331  argv0 = argv[0];
332 
333  /* parse the commandline */
334  while ((c=getopt_long(argc, argv, "c:hv", long_options, &options_index)) != -1) {
335  switch (c) {
336  case 'c':
337  cfgfile = optarg;
338  break;
339  case 'h':
340  usage();
341  exit(0);
342  case 'v':
343  ++verbosity;
344  break;
345  default:
346  usage();
347  exit(1);
348  }
349  }
350  argc -= optind;
351  argv += optind;
352  if (argc != 0) {
353  usage();
354  exit(1);
355  }
356 
357  ods_log_init("ods-migrate", 0, NULL, verbosity);
358 
359  xmlInitGlobals();
360  xmlInitParser();
361  xmlInitThreads();
362 
363  tzset(); /* for portability */
364 
365  /* Parse config file */
366  cfg = engine_config(cfgfile, verbosity, NULL);
367  cfg->verbosity = verbosity;
368  /* does it make sense? */
369  if (engine_config_check(cfg) != ODS_STATUS_OK) {
370  abort(); /* TODO give some error, abort */
371  }
372 
373  status = hsm_open2(parse_conf_repositories(cfgfile), hsm_prompt_pin);
374  if (status != HSM_OK) {
375  char* errorstr = hsm_get_error(NULL);
376  if (errorstr != NULL) {
377  fprintf(stderr, "%s", errorstr);
378  free(errorstr);
379  abort(); /* FIXME */
380  } else {
381  fprintf(stderr,"error opening libhsm (errno %i)\n", status);
382  }
383  return 1;
384  }
385  dblayer_initialize();
386 
387  switch (cfg->db_type) {
389 #ifdef HAVE_SQLITE3
390  dblayer_sqlite3_open(cfg->datastore);
391 #else
392  fprintf(stderr, "Database SQLite3 not available during compile-time.\n");
393 #endif
394  break;
396 #ifdef HAVE_MYSQL
397  dblayer_mysql_open(cfg->db_host, cfg->db_username, cfg->db_password, cfg->datastore, cfg->db_port, NULL);
398 #else
399  fprintf(stderr, "Database MySQL not available during compile-time.\n");
400 #endif
401  break;
403  default:
404  fprintf(stderr, "No database defined\n");
405  }
406 
407  dblayer_foreach(listQueryStr, updateQueryStr, &compute);
408 
409  hsm_close();
410 
412  /* dblayer_foreach for each frees something dblayer_close uses
413  * We better just let it leak. */
414  /* dblayer_close(); */
415  dblayer_finalize();
416  ods_log_close();
417 
418  xmlCleanupParser();
419  xmlCleanupGlobals();
420  xmlCleanupThreads();
421 
422  return 0;
423 }
void engine_config_cleanup(engineconfig_type *config)
Definition: cfg.c:276
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:297
void(* functioncast_t)(void)
Definition: ods-migrate.c:55
ods_status engine_config_check(engineconfig_type *config)
Definition: cfg.c:153
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:317
engineconfig_database_type_t db_type
Definition: cfg.h:79
const char * listQueryStr
Definition: ods-migrate.c:296