OpenDNSSEC-enforcer 2.1.10
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"
45extern hsm_repository_t* parse_conf_repositories(const char* cfgfile);
46
48char* argv0;
49
50static void
51usage(void)
52{
53 fprintf(stderr, "%s [-h] [-v] [-c <alternate-configuration>]\n", argv0);
54}
55
56typedef void (*functioncast_t)(void);
57extern functioncast_t functioncast(void*generic);
58
60functioncast(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
76struct 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};
92struct dblayer_sqlite3_struct dblayer_sqlite3;
93
94static void
95dblayer_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
124static void
125dblayer_sqlite3_close(void)
126{
127 dblayer_sqlite3.sqlite3_close(dblayer_sqlite3.handle);
128}
129
130struct callbackoperation {
131 int (*compute)(char **argv, int* id, uint16_t *keytag);
132 sqlite3_stmt* updateStmt;
133};
134
135static int
136callback(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
167static void
168dblayer_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
179static void
180dblayer_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
192struct dblayer_mysql_struct {
193 MYSQL* handle;
194};
195extern struct dblayer_mysql_struct dblayer_mysql;
196struct dblayer_mysql_struct dblayer_mysql;
197
198
199static void
200dblayer_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
207static void
208dblayer_mysql_close(void)
209{
210 if (dblayer_mysql.handle) {
211 mysql_close(dblayer_mysql.handle);
212 dblayer_mysql.handle = NULL;
213 }
214}
215
216static void
217dblayer_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
252static void
253dblayer_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
271static void
272dblayer_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
282static void
283dblayer_close(void) {
284 dblayer.close();
285}
286
287static void
288dblayer_finalize(void) {
289#ifdef HAVE_MYSQL
290 mysql_library_end();
291#endif
292}
293
294static void
295dblayer_foreach(const char* listQueryStr, const char* updateQueryStr, int (*compute)(char**,int*,uint16_t*))
296{
298}
299
300/****************************************************************************/
301
302const char* listQueryStr = "select keyData.id,keyData.algorithm,keyData.role,keyData.keytag,hsmKey.locator from keyData join hsmKey on keyData.hsmKeyId = hsmKey.id";
303const char* updateQueryStr = "update keyData set keytag = ? where id = ?";
304
305static int keytagcount;
306
307static int
308compute(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
325int
326main(int argc, char* argv[])
327{
328 ods_status status;
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
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition: confparser.c:205
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
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