OpenDNSSEC-enforcer  2.1.5
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 keytagcount;
305 
306 static int
307 compute(char **argv, int* id, uint16_t* keytag)
308 {
309  char *locator;
310  int algorithm;
311  int ksk;
312 
313  *id = atoi(argv[0]);
314  algorithm = atoi(argv[1]);
315  ksk = (atoi(argv[2]) == 1);
316  *keytag = atoi(argv[3]);
317  locator = argv[4];
318  hsm_keytag(locator, algorithm, ksk, keytag);
319  keytagcount += 1;
320 
321  return 0;
322 }
323 
324 int
325 main(int argc, char* argv[])
326 {
327  ods_status status;
328  engineconfig_type* cfg;
329  int c;
330  int options_index = 0;
331  const char* cfgfile = ODS_SE_CFGFILE;
332  static struct option long_options[] = {
333  {"config", required_argument, 0, 'c'},
334  {"help", no_argument, 0, 'h'},
335  {"verbose", no_argument, 0, 'v'},
336  { 0, 0, 0, 0}
337  };
338 
339  argv0 = argv[0];
340 
341  /* parse the commandline */
342  while ((c=getopt_long(argc, argv, "c:hv", long_options, &options_index)) != -1) {
343  switch (c) {
344  case 'c':
345  cfgfile = optarg;
346  break;
347  case 'h':
348  usage();
349  exit(0);
350  case 'v':
351  ++verbosity;
352  break;
353  default:
354  usage();
355  exit(1);
356  }
357  }
358  argc -= optind;
359  argv += optind;
360  if (argc != 0) {
361  usage();
362  exit(1);
363  }
364 
365  ods_log_init("ods-migrate", 0, NULL, verbosity);
366 
367  xmlInitGlobals();
368  xmlInitParser();
369  xmlInitThreads();
370 
371  tzset(); /* for portability */
372 
373  /* Parse config file */
374  printf("Reading config file '%s'..\n", cfgfile);
375  cfg = engine_config(cfgfile, verbosity, NULL);
376  cfg->verbosity = verbosity;
377  /* does it make sense? */
378  if (engine_config_check(cfg) != ODS_STATUS_OK) {
379  fprintf(stderr,"Configuration error.\n");
380  exit(1);
381  }
382 
383  printf("Connecting to HSM..\n");
384  status = hsm_open2(parse_conf_repositories(cfgfile), hsm_prompt_pin);
385  if (status != HSM_OK) {
386  char* errorstr = hsm_get_error(NULL);
387  if (errorstr != NULL) {
388  fprintf(stderr, "%s", errorstr);
389  free(errorstr);
390  } else {
391  fprintf(stderr,"error opening libhsm (errno %i)\n", status);
392  }
393  return 1;
394  }
395  dblayer_initialize();
396 
397  printf("Connecting to database..\n");
398  switch (cfg->db_type) {
400 #ifdef HAVE_SQLITE3
401  dblayer_sqlite3_open(cfg->datastore);
402 #else
403  fprintf(stderr, "Database SQLite3 not available during compile-time.\n");
404  exit(1);
405 #endif
406  break;
408 #ifdef HAVE_MYSQL
409  dblayer_mysql_open(cfg->db_host, cfg->db_username, cfg->db_password, cfg->datastore, cfg->db_port, NULL);
410 #else
411  fprintf(stderr, "Database MySQL not available during compile-time.\n");
412  exit(1);
413 #endif
414  break;
416  default:
417  fprintf(stderr, "No database defined, possible mismatch build\n");
418  fprintf(stderr, "and configuration for SQLite3 or MySQL.\n");
419  exit(1);
420  }
421 
422  keytagcount = 0;
423  printf("Computing keytags, this could take a while.\n");
424  dblayer_foreach(listQueryStr, updateQueryStr, &compute);
425  printf("Added keytags for %d keys.\n", keytagcount);
426 
427  printf("Finishing..\n");
428  hsm_close();
429 
431  /* dblayer_foreach for each frees something dblayer_close uses
432  * We better just let it leak. */
433  /* dblayer_close(); */
434  dblayer_finalize();
435  ods_log_close();
436 
437  xmlCleanupParser();
438  xmlCleanupGlobals();
439 
440  return 0;
441 }
engine_config_cleanup
void engine_config_cleanup(engineconfig_type *config)
Definition: cfg.c:278
cfg.h
main
int main(int argc, char *argv[])
Definition: ods-migrate.c:325
engineconfig_struct::datastore
const char * datastore
Definition: cfg.h:68
engineconfig_struct::db_type
engineconfig_database_type_t db_type
Definition: cfg.h:80
argv0
char * argv0
Definition: ods-migrate.c:47
verbosity
int verbosity
Definition: ods-migrate.c:46
engineconfig_struct
Definition: cfg.h:54
engineconfig_struct::db_username
const char * db_username
Definition: cfg.h:70
listQueryStr
const char * listQueryStr
Definition: ods-migrate.c:301
ENFORCER_DATABASE_TYPE_NONE
Definition: cfg.h:44
parse_conf_repositories
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition: confparser.c:205
updateQueryStr
const char * updateQueryStr
Definition: ods-migrate.c:302
dblayer_struct::foreach
void(* foreach)(const char *listQueryStr, const char *updateQueryStr, int(*compute)(char **, int *, uint16_t *))
Definition: ods-migrate.c:67
engine_config_check
ods_status engine_config_check(engineconfig_type *config)
Definition: cfg.c:155
ENFORCER_DATABASE_TYPE_MYSQL
Definition: cfg.h:46
engineconfig_struct::db_port
int db_port
Definition: cfg.h:76
engineconfig_struct::verbosity
int verbosity
Definition: cfg.h:75
dblayer_struct
Definition: ods-migrate.c:66
dblayer
struct dblayer_struct dblayer
functioncast
functioncast_t functioncast(void *generic)
Definition: ods-migrate.c:59
dblayer_struct::close
void(* close)(void)
Definition: ods-migrate.c:68
functioncast_t
void(* functioncast_t)(void)
Definition: ods-migrate.c:55
engineconfig_struct::db_host
const char * db_host
Definition: cfg.h:69
ENFORCER_DATABASE_TYPE_SQLITE
Definition: cfg.h:45
engineconfig_struct::db_password
const char * db_password
Definition: cfg.h:71
engine_config
engineconfig_type * engine_config(const char *cfgfile, int cmdline_verbosity, engineconfig_type *oldcfg)
Definition: cfg.c:59