OpenDNSSEC-enforcer  2.1.12
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 #include "db/key_data.h"
45 extern hsm_repository_t* parse_conf_repositories(const char* cfgfile);
46 
48 char* argv0;
49 
50 static void
51 usage(void)
52 {
53  fprintf(stderr, "%s [-h] [-v] [-c <alternate-configuration>]\n", argv0);
54 }
55 
56 typedef void (*functioncast_t)(void);
57 extern functioncast_t functioncast(void*generic);
58 
60 functioncast(void*generic) {
61  functioncast_t* function = (functioncast_t*)&generic;
62  return *function;
63 }
64 
65 /****************************************************************************/
66 
68  void (*foreach)(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*));
69  void (*close)(void);
71 
72 #ifdef HAVE_SQLITE3
73 
74 #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)
75 
76 struct dblayer_sqlite3_struct {
77  int status;
78  char* message;
79  void* library;
80  sqlite3* handle;
81  int (*sqlite3_prepare_v2)(sqlite3 *, const char *, int , sqlite3_stmt **, const char **);
82  int (*sqlite3_reset)(sqlite3_stmt *pStmt);
83  int (*sqlite3_bind_int)(sqlite3_stmt*, int, int);
84  int (*sqlite3_finalize)(sqlite3_stmt *pStmt);
85  int (*sqlite3_open)(const char *filename, sqlite3 **ppDb);
86  int (*sqlite3_exec)(sqlite3*, const char *sql, int (*callback)(void*, int, char**, char**), void *, char **errmsg);
87  int (*sqlite3_step)(sqlite3_stmt*);
88  int (*sqlite3_close)(sqlite3*);
89  const char* (*sqlite3_errmsg)(sqlite3*);
90  int (*sqlite3_free)(void*);
91 };
92 struct dblayer_sqlite3_struct dblayer_sqlite3;
93 
94 static void
95 dblayer_sqlite3_initialize(void)
96 {
97  void *handle;
98  char const *error;
99 
100  dlerror();
101  handle = dlopen(SQLITE3_SONAME, RTLD_NOW);
102  if ((error = dlerror()) != NULL) {
103  printf("Failed to load sqlite3 library. dlerror(): %s\n", error);
104  exit(1);
105  }
106 
107  dblayer_sqlite3.sqlite3_prepare_v2 = (int(*)(sqlite3*, const char*, int, sqlite3_stmt**, const char **))functioncast(dlsym(handle, "sqlite3_prepare_v2"));
108  dblayer_sqlite3.sqlite3_reset = (int(*)(sqlite3_stmt*)) functioncast(dlsym(handle, "sqlite3_reset"));
109  dblayer_sqlite3.sqlite3_bind_int = (int(*)(sqlite3_stmt*, int, int))functioncast(dlsym(handle, "sqlite3_bind_int"));
110  dblayer_sqlite3.sqlite3_finalize = (int(*)(sqlite3_stmt*))functioncast(dlsym(handle, "sqlite3_finalize"));
111  dblayer_sqlite3.sqlite3_open = (int(*)(const char*, sqlite3**)) functioncast(dlsym(handle, "sqlite3_open"));
112  dblayer_sqlite3.sqlite3_exec = (int(*)(sqlite3*, const char*, int(*)(void*, int, char**, char**), void*, char **)) functioncast(dlsym(handle, "sqlite3_exec"));
113  dblayer_sqlite3.sqlite3_step = (int(*)(sqlite3_stmt*)) functioncast(dlsym(handle, "sqlite3_step"));
114  dblayer_sqlite3.sqlite3_close = (int(*)(sqlite3*)) functioncast(dlsym(handle, "sqlite3_close"));
115  dblayer_sqlite3.sqlite3_errmsg = (const char*(*)(sqlite3*)) functioncast(dlsym(handle, "sqlite3_errmsg"));
116  dblayer_sqlite3.sqlite3_free = (int(*)(void*)) functioncast(dlsym(handle, "sqlite3_free"));
117 
118  if (!dblayer_sqlite3.sqlite3_open) {
119  printf("Failed to load sqlite3 library.\n");
120  exit(1);
121  }
122 }
123 
124 static void
125 dblayer_sqlite3_close(void)
126 {
127  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
128 }
129 
130 struct callbackoperation {
131  int (*compute)(char **argv, int* id, uint16_t *keytag);
132  sqlite3_stmt* updateStmt;
133 };
134 
135 static int
136 callback(void *cargo, int argc, char **argv, char **names)
137 {
138  int status;
139  int id;
140  uint16_t keytag;
141  struct callbackoperation* operation = (struct callbackoperation*) cargo;
142 
143  operation->compute(argv, &id, &keytag);
144 
145  CHECKSQLITE(dblayer_sqlite3.sqlite3_reset(operation->updateStmt));
146  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 1, keytag));
147  CHECKSQLITE(dblayer_sqlite3.sqlite3_bind_int(operation->updateStmt, 2, id));
148  do {
149  switch ((status = dblayer_sqlite3.sqlite3_step(operation->updateStmt))) {
150  case SQLITE_ROW:
151  break;
152  case SQLITE_DONE:
153  break;
154  case SQLITE_BUSY:
155  sleep(1);
156  break;
157  case SQLITE_ERROR:
158  case SQLITE_MISUSE:
159  default:
160  fprintf(stderr, "%s: sql error: %s\n", argv0, dblayer_sqlite3.sqlite3_errmsg(dblayer_sqlite3.handle));
161  break;
162  }
163  } while(status == SQLITE_BUSY);
164  return SQLITE_OK;
165 }
166 
167 static void
168 dblayer_sqlite3_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
169 {
170  struct callbackoperation operation;
171  const char* queryEnd;
172  operation.compute = compute;
173  CHECKSQLITE(dblayer_sqlite3.sqlite3_prepare_v2(dblayer_sqlite3.handle, updateQueryStr, strlen(updateQueryStr)+1, &operation.updateStmt, &queryEnd));
174  CHECKSQLITE(dblayer_sqlite3.sqlite3_exec(dblayer_sqlite3.handle, listQueryStr, callback, &operation, &dblayer_sqlite3.message));
175  CHECKSQLITE(dblayer_sqlite3.sqlite3_finalize(operation.updateStmt));
176  dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
177 }
178 
179 static void
180 dblayer_sqlite3_open(const char *datastore) {
181  CHECKSQLITE(dblayer_sqlite3.sqlite3_open(datastore, &dblayer_sqlite3.handle));
182  dblayer.close = &dblayer_sqlite3_close;
183  dblayer.foreach = &dblayer_sqlite3_foreach;
184 }
185 
186 #endif
187 
188 /****************************************************************************/
189 
190 #ifdef HAVE_MYSQL
191 
192 struct dblayer_mysql_struct {
193  MYSQL* handle;
194 };
195 extern struct dblayer_mysql_struct dblayer_mysql;
196 struct dblayer_mysql_struct dblayer_mysql;
197 
198 
199 static void
200 dblayer_mysql_initialize(void) {
201  if (mysql_library_init(0, NULL, NULL)) {
202  fprintf(stderr, "could not initialize MySQL library\n");
203  exit(1);
204  }
205 }
206 
207 static void
208 dblayer_mysql_close(void)
209 {
210  if (dblayer_mysql.handle) {
211  mysql_close(dblayer_mysql.handle);
212  dblayer_mysql.handle = NULL;
213  }
214 }
215 
216 static void
217 dblayer_mysql_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
218 {
219  int id;
220  uint16_t keytag;
221  MYSQL_BIND bind[2];
222  MYSQL_STMT *updateStmt;
223  MYSQL_RES* res;
224  MYSQL_ROW row;
225  updateStmt = mysql_stmt_init(dblayer_mysql.handle);
226  mysql_stmt_prepare(updateStmt, updateQueryStr, strlen(updateQueryStr) + 1);
227  mysql_query(dblayer_mysql.handle, listQueryStr);
228  res = mysql_store_result(dblayer_mysql.handle);
229  if (!res) {
230  fprintf(stderr, "Failed to update db. Is it set correctly in conf.xml?\n");
231  exit(1);
232  }
233  mysql_num_fields(res);
234  while ((row = mysql_fetch_row(res))) {
235  compute(row, &id, &keytag);
236  memset(bind, 0, sizeof (bind));
237  bind[0].buffer = &keytag;
238  bind[0].buffer_length = sizeof(keytag);
239  bind[0].buffer_type = MYSQL_TYPE_SHORT;
240  bind[0].is_unsigned = 1;
241  bind[1].buffer = &id;
242  bind[1].buffer_length = sizeof(id);
243  bind[1].buffer_type = MYSQL_TYPE_LONG;
244  mysql_stmt_bind_param(updateStmt, bind);
245  mysql_stmt_execute(updateStmt);
246  mysql_stmt_affected_rows(updateStmt);
247  }
248  mysql_free_result(res);
249  mysql_stmt_close(updateStmt);
250 }
251 
252 static void
253 dblayer_mysql_open(const char* host, const char* user, const char* pass,
254  const char *rsrc, unsigned int port, const char *unix_socket)
255 {
256  dblayer_mysql.handle = mysql_init(NULL);
257  if (!mysql_real_connect(dblayer_mysql.handle, host, user, pass, rsrc, port, NULL, 0)) {
258  fprintf(stderr, "Failed to connect to database: Error: %s\n",
259  mysql_error(dblayer_mysql.handle));
260  exit(1);
261  }
262  dblayer.close = &dblayer_mysql_close;
263  dblayer.foreach = &dblayer_mysql_foreach;
264 
265 }
266 
267 #endif
268 
269 /****************************************************************************/
270 
271 static void
272 dblayer_initialize(void)
273 {
274 #ifdef HAVE_SQLITE3
275  dblayer_sqlite3_initialize();
276 #endif
277 #ifdef HAVE_MYSQL
278  dblayer_mysql_initialize();
279 #endif
280 }
281 
282 static void
283 dblayer_close(void) {
284  dblayer.close();
285 }
286 
287 static void
288 dblayer_finalize(void) {
289 #ifdef HAVE_MYSQL
290  mysql_library_end();
291 #endif
292 }
293 
294 static void
295 dblayer_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
296 {
298 }
299 
300 /****************************************************************************/
301 
302 const char* listQueryStr = "select keyData.id,keyData.algorithm,keyData.role,keyData.keytag,hsmKey.locator from keyData join hsmKey on keyData.hsmKeyId = hsmKey.id";
303 const char* updateQueryStr = "update keyData set keytag = ? where id = ?";
304 
305 static int keytagcount;
306 
307 static int
308 compute(char **argv, int* id, uint16_t* keytag)
309 {
310  char *locator;
311  int algorithm;
312  int sep;
313 
314  *id = atoi(argv[0]);
315  algorithm = atoi(argv[1]);
316  sep = KEY_DATA_ROLE_SEP(atoi(argv[2]));
317  *keytag = atoi(argv[3]);
318  locator = argv[4];
319  hsm_keytag(locator, algorithm, sep, keytag);
320  keytagcount += 1;
321 
322  return 0;
323 }
324 
325 int
326 main(int argc, char* argv[])
327 {
328  ods_status status;
329  engineconfig_type* cfg;
330  int c;
331  int options_index = 0;
332  const char* cfgfile = ODS_SE_CFGFILE;
333  static struct option long_options[] = {
334  {"config", required_argument, 0, 'c'},
335  {"help", no_argument, 0, 'h'},
336  {"verbose", no_argument, 0, 'v'},
337  { 0, 0, 0, 0}
338  };
339 
340  argv0 = argv[0];
341 
342  /* parse the commandline */
343  while ((c=getopt_long(argc, argv, "c:hv", long_options, &options_index)) != -1) {
344  switch (c) {
345  case 'c':
346  cfgfile = optarg;
347  break;
348  case 'h':
349  usage();
350  exit(0);
351  case 'v':
352  ++verbosity;
353  break;
354  default:
355  usage();
356  exit(1);
357  }
358  }
359  argc -= optind;
360  argv += optind;
361  if (argc != 0) {
362  usage();
363  exit(1);
364  }
365 
366  ods_log_init("ods-migrate", 0, NULL, verbosity);
367 
368  xmlInitGlobals();
369  xmlInitParser();
370  xmlInitThreads();
371 
372  tzset(); /* for portability */
373 
374  /* Parse config file */
375  printf("Reading config file '%s'..\n", cfgfile);
376  cfg = engine_config(cfgfile, verbosity, NULL);
377  cfg->verbosity = verbosity;
378  /* does it make sense? */
379  if (engine_config_check(cfg) != ODS_STATUS_OK) {
380  fprintf(stderr,"Configuration error.\n");
381  exit(1);
382  }
383 
384  printf("Connecting to HSM..\n");
385  status = hsm_open2(parse_conf_repositories(cfgfile), hsm_prompt_pin);
386  if (status != HSM_OK) {
387  char* errorstr = hsm_get_error(NULL);
388  if (errorstr != NULL) {
389  fprintf(stderr, "%s", errorstr);
390  free(errorstr);
391  } else {
392  fprintf(stderr,"error opening libhsm (errno %i)\n", status);
393  }
394  return 1;
395  }
396  dblayer_initialize();
397 
398  printf("Connecting to database..\n");
399  switch (cfg->db_type) {
401 #ifdef HAVE_SQLITE3
402  dblayer_sqlite3_open(cfg->datastore);
403 #else
404  fprintf(stderr, "Database SQLite3 not available during compile-time.\n");
405  exit(1);
406 #endif
407  break;
409 #ifdef HAVE_MYSQL
410  dblayer_mysql_open(cfg->db_host, cfg->db_username, cfg->db_password, cfg->datastore, cfg->db_port, NULL);
411 #else
412  fprintf(stderr, "Database MySQL not available during compile-time.\n");
413  exit(1);
414 #endif
415  break;
417  default:
418  fprintf(stderr, "No database defined, possible mismatch build\n");
419  fprintf(stderr, "and configuration for SQLite3 or MySQL.\n");
420  exit(1);
421  }
422 
423  keytagcount = 0;
424  printf("Computing keytags, this could take a while.\n");
425  dblayer_foreach(listQueryStr, updateQueryStr, &compute);
426  printf("Added keytags for %d keys.\n", keytagcount);
427 
428  printf("Finishing..\n");
429  hsm_close();
430 
432  /* dblayer_foreach for each frees something dblayer_close uses
433  * We better just let it leak. */
434  /* dblayer_close(); */
435  dblayer_finalize();
436  ods_log_close();
437 
438  xmlCleanupParser();
439  xmlCleanupGlobals();
440 
441  return 0;
442 }
engineconfig_type * engine_config(const char *cfgfile, int cmdline_verbosity, engineconfig_type *oldcfg)
Definition: cfg.c:59
void engine_config_cleanup(engineconfig_type *config)
Definition: cfg.c:278
ods_status engine_config_check(engineconfig_type *config)
Definition: cfg.c:155
@ ENFORCER_DATABASE_TYPE_MYSQL
Definition: cfg.h:46
@ ENFORCER_DATABASE_TYPE_SQLITE
Definition: cfg.h:45
@ ENFORCER_DATABASE_TYPE_NONE
Definition: cfg.h:44
#define KEY_DATA_ROLE_SEP(role)
Definition: key_data.h:48
int main(int argc, char *argv[])
Definition: ods-migrate.c:326
int verbosity
Definition: ods-migrate.c:47
const char * updateQueryStr
Definition: ods-migrate.c:303
char * argv0
Definition: ods-migrate.c:48
functioncast_t functioncast(void *generic)
Definition: ods-migrate.c:60
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition: confparser.c:205
void(* functioncast_t)(void)
Definition: ods-migrate.c:56
struct dblayer_struct dblayer
const char * listQueryStr
Definition: ods-migrate.c:302
void(* close)(void)
Definition: ods-migrate.c:69
void(* foreach)(const char *listQueryStr, const char *updateQueryStr, int(*compute)(char **, int *, uint16_t *))
Definition: ods-migrate.c:68
const char * datastore
Definition: cfg.h:68
const char * db_password
Definition: cfg.h:71
engineconfig_database_type_t db_type
Definition: cfg.h:80
const char * db_username
Definition: cfg.h:70
const char * db_host
Definition: cfg.h:69