OpenDNSSEC-enforcer 1.3.0
|
00001 /* 00002 * $Id: ksmutil.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2008-2009 Nominet UK. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 #define _GNU_SOURCE 00029 #include <stdio.h> 00030 #include <string.h> 00031 #include <stdlib.h> 00032 #include <unistd.h> 00033 #include <errno.h> 00034 #include <fcntl.h> 00035 #include <limits.h> 00036 00037 #include "config.h" 00038 00039 #include <getopt.h> 00040 #include <string.h> 00041 #include <syslog.h> 00042 #include <sys/stat.h> 00043 #include <pwd.h> 00044 #include <grp.h> 00045 00046 #include <ksm/ksmutil.h> 00047 #include <ksm/ksm.h> 00048 #include <ksm/database.h> 00049 #include "ksm/database_statement.h" 00050 #include "ksm/db_fields.h" 00051 #include <ksm/datetime.h> 00052 #include <ksm/string_util.h> 00053 #include <ksm/string_util2.h> 00054 #include "ksm/kmemsg.h" 00055 #include "ksm/kmedef.h" 00056 #include "ksm/dbsmsg.h" 00057 #include "ksm/dbsdef.h" 00058 #include "ksm/message.h" 00059 00060 #include <libhsm.h> 00061 #include <libhsmdns.h> 00062 #include <ldns/ldns.h> 00063 00064 #include <libxml/tree.h> 00065 #include <libxml/parser.h> 00066 #include <libxml/xpointer.h> 00067 #include <libxml/xpath.h> 00068 #include <libxml/xpathInternals.h> 00069 #include <libxml/relaxng.h> 00070 #include <libxml/xmlreader.h> 00071 #include <libxml/xmlsave.h> 00072 00073 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 00074 00075 /* Some value type flags */ 00076 #define INT_TYPE 0 00077 #define DURATION_TYPE 1 00078 #define BOOL_TYPE 2 00079 #define REPO_TYPE 3 00080 #define SERIAL_TYPE 4 00081 #define ROLLOVER_TYPE 5 00082 #define INT_TYPE_NO_FREE 6 00083 00084 #ifndef MAXPATHLEN 00085 # define MAXPATHLEN 4096 00086 #endif 00087 00088 /* We write one log message to syslog */ 00089 #ifdef LOG_DAEMON 00090 #define DEFAULT_LOG_FACILITY LOG_DAEMON 00091 #else 00092 #define DEFAULT_LOG_FACILITY LOG_USER 00093 #endif /* LOG_DAEMON */ 00094 00095 extern char *optarg; 00096 extern int optind; 00097 const char *progname = NULL; 00098 char *config = (char *) OPENDNSSEC_CONFIG_FILE; 00099 00100 char *o_keystate = NULL; 00101 char *o_algo = NULL; 00102 char *o_input = NULL; 00103 char *o_cka_id = NULL; 00104 char *o_size = NULL; 00105 char *o_interval = NULL; 00106 char *o_output = NULL; 00107 char *o_policy = NULL; 00108 char *o_repository = NULL; 00109 char *o_signerconf = NULL; 00110 char *o_keytype = NULL; 00111 char *o_time = NULL; 00112 char *o_retire = NULL; 00113 char *o_zone = NULL; 00114 char *o_keytag = NULL; 00115 static int all_flag = 0; 00116 static int ds_flag = 0; 00117 static int retire_flag = 1; 00118 static int verbose_flag = 0; 00119 static int xml_flag = 1; 00120 static int td_flag = 0; 00121 00122 static int restart_enforcerd(void); 00123 00124 void 00125 usage_general () 00126 { 00127 fprintf(stderr, 00128 " help\n" 00129 " --version aka -V\n"); 00130 } 00131 00132 void 00133 usage_setup () 00134 { 00135 fprintf(stderr, 00136 " setup\n" 00137 "\tImport config into a database (deletes current contents)\n"); 00138 } 00139 00140 void 00141 usage_control () 00142 { 00143 fprintf(stderr, 00144 " start|stop|notify\n" 00145 "\tStart, stop or SIGHUP the ods-enforcerd\n"); 00146 } 00147 00148 void 00149 usage_update () 00150 { 00151 fprintf(stderr, 00152 " update kasp\n" 00153 " update zonelist\n" 00154 " update conf\n" 00155 " update all\n" 00156 "\tUpdate database from config\n"); 00157 } 00158 00159 void 00160 usage_zoneadd () 00161 { 00162 fprintf(stderr, 00163 " zone add\n" 00164 "\t--zone <zone> aka -z\n" 00165 "\t[--policy <policy>] aka -p\n" 00166 "\t[--signerconf <signerconf.xml>] aka -s\n" 00167 "\t[--input <input>] aka -i\n" 00168 "\t[--output <output>] aka -o\n" 00169 "\t[--no-xml] aka -m\n"); 00170 } 00171 00172 void 00173 usage_zonedel () 00174 { 00175 fprintf(stderr, 00176 " zone delete\n" 00177 "\t--zone <zone> | --all aka -z / -a\n" 00178 "\t[--no-xml] aka -m\n"); 00179 } 00180 00181 void 00182 usage_zonelist () 00183 { 00184 fprintf(stderr, 00185 " zone list\n"); 00186 } 00187 00188 void 00189 usage_zone () 00190 { 00191 fprintf(stderr, 00192 "usage: %s [-f config] zone \n\n", 00193 progname); 00194 usage_zoneadd (); 00195 usage_zonedel (); 00196 usage_zonelist (); 00197 } 00198 00199 void 00200 usage_repo () 00201 { 00202 fprintf(stderr, 00203 " repository list\n"); 00204 } 00205 00206 void 00207 usage_policyexport () 00208 { 00209 fprintf(stderr, 00210 " policy export\n" 00211 "\t--policy [policy_name] | --all aka -p / -a\n"); 00212 } 00213 00214 void 00215 usage_policyimport () 00216 { 00217 fprintf(stderr, 00218 " policy import\n"); 00219 } 00220 00221 void 00222 usage_policylist () 00223 { 00224 fprintf(stderr, 00225 " policy list\n"); 00226 } 00227 00228 void 00229 usage_policypurge () 00230 { 00231 fprintf(stderr, 00232 " policy purge\n"); 00233 } 00234 00235 void 00236 usage_policy () 00237 { 00238 fprintf(stderr, 00239 "usage: %s [-f config] \n\n", 00240 progname); 00241 usage_policyexport (); 00242 usage_policyimport (); 00243 usage_policylist (); 00244 usage_policypurge (); 00245 } 00246 00247 void 00248 usage_keylist () 00249 { 00250 fprintf(stderr, 00251 " key list\n" 00252 "\t[--verbose]\n" 00253 "\t--zone <zone> | --all aka -z / -a\n" 00254 #if 0 00255 "\t(will appear soon:\n" 00256 "\t[--keystate <state>] aka -e\n" 00257 "\t[--keytype <type>] aka -t\n" 00258 "\t[--ds] aka -d)\n" 00259 #endif 00260 ); 00261 } 00262 00263 void 00264 usage_keyexport () 00265 { 00266 fprintf(stderr, 00267 " key export\n" 00268 "\t--zone <zone> | --all aka -z / -a\n" 00269 "\t[--keystate <state>] aka -e\n" 00270 "\t[--keytype <type>] aka -t\n" 00271 "\t[--ds] aka -d\n"); 00272 } 00273 00274 void 00275 usage_keyimport () 00276 { 00277 fprintf(stderr, 00278 " key import\n" 00279 "\t--cka_id <CKA_ID> aka -k\n" 00280 "\t--repository <repository> aka -r\n" 00281 "\t--zone <zone> aka -z\n" 00282 "\t--bits <size> aka -b\n" 00283 "\t--algorithm <algorithm> aka -g\n" 00284 "\t--keystate <state> aka -e\n" 00285 "\t--keytype <type> aka -t\n" 00286 "\t--time <time> aka -w\n" 00287 "\t[--retire <retire>] aka -y\n"); 00288 } 00289 00290 void 00291 usage_keyroll () 00292 { 00293 fprintf(stderr, 00294 " key rollover\n" 00295 "\t--zone zone [--keytype <type>] aka -z\n" 00296 " key rollover\n" 00297 "\t--policy policy [--keytype <type>] aka -p\n"); 00298 } 00299 00300 void 00301 usage_keypurge () 00302 { 00303 fprintf(stderr, 00304 " key purge\n" 00305 "\t--zone <zone> aka -z\n" 00306 " key purge\n" 00307 "\t--policy <policy> aka -p\n"); 00308 } 00309 00310 void 00311 usage_keygen () 00312 { 00313 fprintf(stderr, 00314 " key generate\n" 00315 "\t--policy <policy>\n" 00316 "\t--interval <interval>\n"); 00317 } 00318 00319 void 00320 usage_keykskretire () 00321 { 00322 fprintf(stderr, 00323 " key ksk-retire\n" 00324 "\t--zone <zone> aka -z\n" 00325 "\t--keytag <keytag> | --cka_id <CKA_ID> aka -x / -k\n"); 00326 } 00327 00328 void 00329 usage_keydsseen () 00330 { 00331 fprintf(stderr, 00332 " key ds-seen\n" 00333 /*"\t--zone <zone> (or --all) aka -z\n"*/ 00334 "\t--zone <zone> aka -z\n" 00335 "\t--keytag <keytag> | --cka_id <CKA_ID> aka -x / -k\n" 00336 "\t--no-retire\n"); 00337 } 00338 00339 void 00340 usage_key () 00341 { 00342 fprintf(stderr, 00343 "usage: %s [-f config] \n\n", 00344 progname); 00345 usage_keylist (); 00346 usage_keyexport (); 00347 usage_keyimport (); 00348 usage_keyroll (); 00349 usage_keypurge (); 00350 usage_keygen (); 00351 usage_keykskretire (); 00352 usage_keydsseen (); 00353 } 00354 00355 void 00356 usage_backup () 00357 { 00358 fprintf(stderr, 00359 " backup prepare\n" 00360 "\t--repository <repository> aka -r\n" 00361 " backup commit\n" 00362 "\t--repository <repository> aka -r\n" 00363 " backup rollback\n" 00364 "\t--repository <repository> aka -r\n" 00365 " backup list\n" 00366 "\t--repository <repository> aka -r\n" 00367 " backup done\n" 00368 "\t--repository <repository> aka -r\n"); 00369 } 00370 00371 void 00372 usage_rollover () 00373 { 00374 fprintf(stderr, 00375 " rollover list\n" 00376 "\t[--zone <zone>]\n"); 00377 } 00378 00379 void 00380 usage_database () 00381 { 00382 fprintf(stderr, 00383 " database backup\n" 00384 "\t[--output <output>] aka -o\n"); 00385 } 00386 00387 void 00388 usage_zonelist2 () 00389 { 00390 fprintf(stderr, 00391 " zonelist export\n" 00392 " zonelist import\n"); 00393 } 00394 00395 void 00396 usage () 00397 { 00398 fprintf(stderr, 00399 "usage: %s [-f config] command [options]\n\n", 00400 progname); 00401 00402 usage_general (); 00403 usage_setup (); 00404 usage_control (); 00405 usage_update (); 00406 usage_zoneadd (); 00407 usage_zonedel (); 00408 usage_zonelist (); 00409 usage_repo (); 00410 usage_policyexport (); 00411 usage_policylist (); 00412 usage_policypurge (); 00413 usage_keylist (); 00414 usage_keyexport (); 00415 usage_keyimport (); 00416 usage_keyroll (); 00417 usage_keypurge (); 00418 usage_keygen (); 00419 usage_keykskretire (); 00420 usage_keydsseen (); 00421 usage_backup (); 00422 usage_rollover (); 00423 usage_database (); 00424 usage_zonelist2 (); 00425 00426 } 00427 00428 void 00429 date_help() 00430 { 00431 fprintf(stderr, 00432 "\n\tAllowed date/time strings are of the form:\n" 00433 00434 "\tYYYYMMDD[HH[MM[SS]]] (all numeric)\n" 00435 "\n" 00436 "\tor D-MMM-YYYY[:| ]HH[:MM[:SS]] (alphabetic month)\n" 00437 "\tor DD-MMM-YYYY[:| ]HH[:MM[:SS]] (alphabetic month)\n" 00438 "\tor YYYY-MMM-DD[:| ]HH[:MM[:SS]] (alphabetic month)\n" 00439 "\n" 00440 "\tD-MM-YYYY[:| ]HH[:MM[:SS]] (numeric month)\n" 00441 "\tDD-MM-YYYY[:| ]HH[:MM[:SS]] (numeric month)\n" 00442 "\tor YYYY-MM-DD[:| ]HH[:MM[:SS]] (numeric month)\n" 00443 "\n" 00444 "\t... and the distinction between them is given by the location of the\n" 00445 "\thyphens.\n"); 00446 } 00447 00448 void 00449 states_help() 00450 { 00451 fprintf(stderr, 00452 "key states: GENERATE|PUBLISH|READY|ACTIVE|RETIRE|DEAD\n"); 00453 } 00454 00455 void 00456 types_help() 00457 { 00458 fprintf(stderr, 00459 "key types: KSK|ZSK\n"); 00460 } 00461 00462 /* 00463 * Do initial import of config files into database 00464 */ 00465 int 00466 cmd_setup () 00467 { 00468 DB_HANDLE dbhandle; 00469 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 00470 char* zone_list_filename; /* Extracted from conf.xml */ 00471 char* kasp_filename; /* Extracted from conf.xml */ 00472 int status = 0; 00473 00474 /* Database connection details */ 00475 char *dbschema = NULL; 00476 char *host = NULL; 00477 char *port = NULL; 00478 char *user = NULL; 00479 char *password = NULL; 00480 00481 char* setup_command = NULL; 00482 char* lock_filename = NULL; 00483 00484 int user_certain; 00485 printf("*WARNING* This will erase all data in the database; are you sure? [y/N] "); 00486 00487 user_certain = getchar(); 00488 if (user_certain != 'y' && user_certain != 'Y') { 00489 printf("Okay, quitting...\n"); 00490 exit(0); 00491 } 00492 00493 /* Right then, they asked for it */ 00494 00495 /* Read the database details out of conf.xml */ 00496 status = get_db_details(&dbschema, &host, &port, &user, &password); 00497 if (status != 0) { 00498 StrFree(host); 00499 StrFree(port); 00500 StrFree(dbschema); 00501 StrFree(user); 00502 StrFree(password); 00503 return(status); 00504 } 00505 00506 /* If we are in sqlite mode then take a lock out on a file to 00507 prevent multiple access (not sure that we can be sure that sqlite is 00508 safe for multiple processes to access). */ 00509 if (DbFlavour() == SQLITE_DB) { 00510 00511 /* Make sure that nothing is happening to the DB */ 00512 StrAppend(&lock_filename, dbschema); 00513 StrAppend(&lock_filename, ".our_lock"); 00514 00515 lock_fd = fopen(lock_filename, "w"); 00516 status = get_lite_lock(lock_filename, lock_fd); 00517 if (status != 0) { 00518 printf("Error getting db lock\n"); 00519 if (lock_fd != NULL) { 00520 fclose(lock_fd); 00521 } 00522 StrFree(lock_filename); 00523 StrFree(host); 00524 StrFree(port); 00525 StrFree(dbschema); 00526 StrFree(user); 00527 StrFree(password); 00528 return(1); 00529 } 00530 StrFree(lock_filename); 00531 00532 /* Run the setup script */ 00533 /* will look like: <SQL_BIN> <DBSCHEMA> < <SQL_SETUP> */ 00534 StrAppend(&setup_command, SQL_BIN); 00535 StrAppend(&setup_command, " "); 00536 StrAppend(&setup_command, dbschema); 00537 StrAppend(&setup_command, " < "); 00538 StrAppend(&setup_command, SQL_SETUP); 00539 00540 if (system(setup_command) != 0) 00541 { 00542 printf("Could not call db setup command:\n\t%s\n", setup_command); 00543 db_disconnect(lock_fd); 00544 StrFree(host); 00545 StrFree(port); 00546 StrFree(dbschema); 00547 StrFree(user); 00548 StrFree(password); 00549 StrFree(setup_command); 00550 return(1); 00551 } 00552 StrFree(setup_command); 00553 00554 /* If we are running as root then chmod the file so that the 00555 final user/group can access it. */ 00556 if (fix_file_perms(dbschema) != 0) 00557 { 00558 printf("Couldn't fix permissions on file %s\n", dbschema); 00559 printf("Will coninue with setup, but you may need to manually change ownership\n"); 00560 } 00561 } 00562 else { 00563 /* MySQL setup */ 00564 /* will look like: <SQL_BIN> -u <USER> -h <HOST> -P <PORT> -p<PASSWORD> <DBSCHEMA> < <SQL_SETUP> */ 00565 StrAppend(&setup_command, SQL_BIN); 00566 StrAppend(&setup_command, " -u "); 00567 StrAppend(&setup_command, user); 00568 if (host != NULL) { 00569 StrAppend(&setup_command, " -h "); 00570 StrAppend(&setup_command, host); 00571 if (port != NULL) { 00572 StrAppend(&setup_command, " -P "); 00573 StrAppend(&setup_command, port); 00574 } 00575 } 00576 if (password != NULL) { 00577 StrAppend(&setup_command, " -p"); 00578 StrAppend(&setup_command, password); 00579 } 00580 StrAppend(&setup_command, " "); 00581 StrAppend(&setup_command, dbschema); 00582 StrAppend(&setup_command, " < "); 00583 StrAppend(&setup_command, SQL_SETUP); 00584 00585 if (system(setup_command) != 0) 00586 { 00587 printf("Could not call db setup command:\n\t%s\n", setup_command); 00588 StrFree(host); 00589 StrFree(port); 00590 StrFree(dbschema); 00591 StrFree(user); 00592 StrFree(password); 00593 StrFree(setup_command); 00594 return(1); 00595 } 00596 StrFree(setup_command); 00597 } 00598 00599 /* try to connect to the database */ 00600 status = DbConnect(&dbhandle, dbschema, host, password, user, port); 00601 if (status != 0) { 00602 printf("Failed to connect to database\n"); 00603 db_disconnect(lock_fd); 00604 StrFree(host); 00605 StrFree(port); 00606 StrFree(dbschema); 00607 StrFree(user); 00608 StrFree(password); 00609 return(1); 00610 } 00611 00612 /* Free these up early */ 00613 StrFree(host); 00614 StrFree(port); 00615 StrFree(dbschema); 00616 StrFree(user); 00617 StrFree(password); 00618 00619 /* 00620 * Now we will read the conf.xml file again, but this time we will not validate. 00621 * Instead we just learn the location of the zonelist.xml and kasp.xml files. 00622 */ 00623 status = read_filenames(&zone_list_filename, &kasp_filename); 00624 if (status != 0) { 00625 printf("Failed to read conf.xml\n"); 00626 db_disconnect(lock_fd); 00627 return(1); 00628 } 00629 00630 /* 00631 * Now we will read the conf.xml file again, but this time we will not validate. 00632 * Instead we just extract the RepositoryList into the database 00633 */ 00634 status = update_repositories(); 00635 if (status != 0) { 00636 printf("Failed to update repositories\n"); 00637 db_disconnect(lock_fd); 00638 StrFree(zone_list_filename); 00639 return(1); 00640 } 00641 00642 /* 00643 * Now read the kasp.xml which should be in the same directory. 00644 * This lists all of the policies. 00645 */ 00646 status = update_policies(kasp_filename); 00647 if (status != 0) { 00648 printf("Failed to update policies\n"); 00649 printf("SETUP FAILED\n"); 00650 db_disconnect(lock_fd); 00651 StrFree(zone_list_filename); 00652 return(1); 00653 } 00654 00655 StrFree(kasp_filename); 00656 00657 /* 00658 * Take the zonelist we learnt above and read it, updating or inserting zone 00659 * records in the database as we go. 00660 */ 00661 status = update_zones(zone_list_filename); 00662 StrFree(zone_list_filename); 00663 if (status != 0) { 00664 printf("Failed to update zones\n"); 00665 db_disconnect(lock_fd); 00666 return(1); 00667 } 00668 00669 /* Release sqlite lock file (if we have it) */ 00670 db_disconnect(lock_fd); 00671 00672 DbDisconnect(dbhandle); 00673 00674 return 0; 00675 } 00676 00677 /* 00678 * Do incremental update of config files into database 00679 * 00680 * returns 0 on success 00681 * 1 on error (and will have sent a message to stdout) 00682 */ 00683 int 00684 cmd_update (const char* qualifier) 00685 { 00686 DB_HANDLE dbhandle; 00687 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 00688 char* zone_list_filename = NULL; /* Extracted from conf.xml */ 00689 char* kasp_filename = NULL; /* Extracted from conf.xml */ 00690 int status = 0; 00691 int done_something = 0; 00692 00693 /* try to connect to the database */ 00694 status = db_connect(&dbhandle, &lock_fd, 1); 00695 if (status != 0) { 00696 printf("Failed to connect to database\n"); 00697 db_disconnect(lock_fd); 00698 return(1); 00699 } 00700 00701 /* 00702 * Now we will read the conf.xml file again, but this time we will not validate. 00703 * Instead we just learn the location of the zonelist.xml and kasp.xml files. 00704 */ 00705 if (strncmp(qualifier, "ZONELIST", 8) == 0 || 00706 strncmp(qualifier, "KASP", 4) == 0 || 00707 strncmp(qualifier, "ALL", 3) == 0) { 00708 status = read_filenames(&zone_list_filename, &kasp_filename); 00709 if (status != 0) { 00710 printf("Failed to read conf.xml\n"); 00711 db_disconnect(lock_fd); 00712 return(1); 00713 } 00714 } 00715 00716 /* 00717 * Read the conf.xml file yet again, but this time we will not validate. 00718 * Instead we just extract the RepositoryList into the database. 00719 */ 00720 if (strncmp(qualifier, "CONF", 4) == 0 || 00721 strncmp(qualifier, "ALL", 3) == 0) { 00722 status = update_repositories(); 00723 if (status != 0) { 00724 printf("Failed to update repositories\n"); 00725 db_disconnect(lock_fd); 00726 if (strncmp(qualifier, "ALL", 3) == 0) { 00727 StrFree(kasp_filename); 00728 StrFree(zone_list_filename); 00729 } 00730 return(1); 00731 } 00732 done_something = 1; 00733 } 00734 00735 /* 00736 * Now read the kasp.xml which should be in the same directory. 00737 * This lists all of the policies. 00738 */ 00739 if (strncmp(qualifier, "KASP", 4) == 0 || 00740 strncmp(qualifier, "ALL", 3) == 0) { 00741 status = update_policies(kasp_filename); 00742 if (status != 0) { 00743 printf("Failed to update policies\n"); 00744 db_disconnect(lock_fd); 00745 StrFree(kasp_filename); 00746 StrFree(zone_list_filename); 00747 return(1); 00748 } 00749 done_something = 1; 00750 } 00751 00752 /* 00753 * Take the zonelist we learnt above and read it, updating or inserting zone 00754 * records in the database as we go. 00755 */ 00756 if (strncmp(qualifier, "ZONELIST", 8) == 0 || 00757 strncmp(qualifier, "ALL", 3) == 0) { 00758 status = update_zones(zone_list_filename); 00759 if (status != 0) { 00760 printf("Failed to update zones\n"); 00761 db_disconnect(lock_fd); 00762 StrFree(kasp_filename); 00763 StrFree(zone_list_filename); 00764 return(1); 00765 } 00766 done_something = 1; 00767 } 00768 00769 /* 00770 * See if we did anything, otherwise log an error 00771 */ 00772 if (done_something == 0) { 00773 printf("Unrecognised command update %s. Please specify one of:\n", qualifier); 00774 usage_update(); 00775 } else { 00776 /* Need to poke the enforcer to wake it up */ 00777 if (restart_enforcerd() != 0) 00778 { 00779 fprintf(stderr, "Could not HUP ods-enforcerd\n"); 00780 } 00781 } 00782 00783 00784 /* Release sqlite lock file (if we have it) */ 00785 db_disconnect(lock_fd); 00786 00787 DbDisconnect(dbhandle); 00788 00789 if (kasp_filename != NULL) { 00790 StrFree(kasp_filename); 00791 } 00792 if (zone_list_filename != NULL) { 00793 StrFree(zone_list_filename); 00794 } 00795 00796 return 0; 00797 } 00798 00799 /* 00800 * Add a zone to the config and database. 00801 * 00802 * Use XMLwriter to update the zonelist.xml found in conf.xml. 00803 * Then call update_zones to push these changes into the database. 00804 * zonelist.xml will be backed up, as will the DB file if we are using sqlite 00805 * 00806 */ 00807 int 00808 cmd_addzone () 00809 { 00810 DB_HANDLE dbhandle; 00811 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 00812 char* zonelist_filename = NULL; 00813 char* backup_filename = NULL; 00814 /* The settings that we need for the zone */ 00815 char* sig_conf_name = NULL; 00816 char* input_name = NULL; 00817 char* output_name = NULL; 00818 int policy_id = 0; 00819 int new_zone; /* ignored */ 00820 00821 DB_RESULT result; /* Result of parameter query */ 00822 KSM_PARAMETER data; /* Parameter information */ 00823 00824 xmlDocPtr doc = NULL; 00825 00826 int status = 0; 00827 00828 char *path = getcwd(NULL, MAXPATHLEN); 00829 if (path == NULL) { 00830 printf("Couldn't malloc path: %s\n", strerror(errno)); 00831 exit(1); 00832 } 00833 00834 /* See what arguments we were passed (if any) otherwise set the defaults */ 00835 if (o_zone == NULL) { 00836 printf("Please specify a zone with the --zone option\n"); 00837 usage_zone(); 00838 return(1); 00839 } 00840 00841 if (o_policy == NULL) { 00842 o_policy = StrStrdup("default"); 00843 } 00844 /* 00845 * Set defaults and turn any relative paths into absolute 00846 * (sort of, not the neatest output) 00847 */ 00848 if (o_signerconf == NULL) { 00849 StrAppend(&sig_conf_name, OPENDNSSEC_STATE_DIR); 00850 StrAppend(&sig_conf_name, "/signconf/"); 00851 StrAppend(&sig_conf_name, o_zone); 00852 StrAppend(&sig_conf_name, ".xml"); 00853 } 00854 else if (*o_signerconf != '/') { 00855 StrAppend(&sig_conf_name, path); 00856 StrAppend(&sig_conf_name, "/"); 00857 StrAppend(&sig_conf_name, o_signerconf); 00858 } else { 00859 StrAppend(&sig_conf_name, o_signerconf); 00860 } 00861 00862 if (o_input == NULL) { 00863 StrAppend(&input_name, OPENDNSSEC_STATE_DIR); 00864 StrAppend(&input_name, "/unsigned/"); 00865 StrAppend(&input_name, o_zone); 00866 } 00867 else if (*o_input != '/') { 00868 StrAppend(&input_name, path); 00869 StrAppend(&input_name, "/"); 00870 StrAppend(&input_name, o_input); 00871 } else { 00872 StrAppend(&input_name, o_input); 00873 } 00874 00875 if (o_output == NULL) { 00876 StrAppend(&output_name, OPENDNSSEC_STATE_DIR); 00877 StrAppend(&output_name, "/signed/"); 00878 StrAppend(&output_name, o_zone); 00879 } 00880 else if (*o_output != '/') { 00881 StrAppend(&output_name, path); 00882 StrAppend(&output_name, "/"); 00883 StrAppend(&output_name, o_output); 00884 } else { 00885 StrAppend(&output_name, o_output); 00886 } 00887 00888 free(path); 00889 00890 /* Set zonelist from the conf.xml that we have got */ 00891 status = read_zonelist_filename(&zonelist_filename); 00892 if (status != 0) { 00893 printf("couldn't read zonelist\n"); 00894 StrFree(zonelist_filename); 00895 StrFree(sig_conf_name); 00896 StrFree(input_name); 00897 StrFree(output_name); 00898 return(1); 00899 } 00900 00901 /* 00902 * Push this new zonelist into the database 00903 */ 00904 00905 /* try to connect to the database */ 00906 status = db_connect(&dbhandle, &lock_fd, 1); 00907 if (status != 0) { 00908 printf("Failed to connect to database\n"); 00909 db_disconnect(lock_fd); 00910 StrFree(zonelist_filename); 00911 StrFree(sig_conf_name); 00912 StrFree(input_name); 00913 StrFree(output_name); 00914 return(1); 00915 } 00916 00917 /* Now stick this zone into the database */ 00918 status = KsmPolicyIdFromName(o_policy, &policy_id); 00919 if (status != 0) { 00920 printf("Error, can't find policy : %s\n", o_policy); 00921 printf("Failed to update zones\n"); 00922 db_disconnect(lock_fd); 00923 StrFree(zonelist_filename); 00924 StrFree(sig_conf_name); 00925 StrFree(input_name); 00926 StrFree(output_name); 00927 return(1); 00928 } 00929 status = KsmImportZone(o_zone, policy_id, 1, &new_zone, sig_conf_name, input_name, output_name); 00930 if (status != 0) { 00931 if (status == -2) { 00932 printf("Failed to Import zone %s; it already exists\n", o_zone); 00933 } else if (status == -3) { 00934 printf("Failed to Import zone %s; it already exists both with and without a trailing dot\n", o_zone); 00935 } else { 00936 printf("Failed to Import zone\n"); 00937 } 00938 db_disconnect(lock_fd); 00939 StrFree(zonelist_filename); 00940 StrFree(sig_conf_name); 00941 StrFree(input_name); 00942 StrFree(output_name); 00943 return(1); 00944 } 00945 00946 /* If need be (keys shared on policy) link existing keys to zone */ 00947 /* First work out if the keys are shared on this policy */ 00948 status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id); 00949 if (status != 0) { 00950 printf("Can't retrieve shared-keys parameter for policy\n"); 00951 db_disconnect(lock_fd); 00952 StrFree(zonelist_filename); 00953 StrFree(sig_conf_name); 00954 StrFree(input_name); 00955 StrFree(output_name); 00956 return(1); 00957 } 00958 status = KsmParameter(result, &data); 00959 if (status != 0) { 00960 printf("Can't retrieve shared-keys parameter for policy\n"); 00961 db_disconnect(lock_fd); 00962 StrFree(zonelist_filename); 00963 StrFree(sig_conf_name); 00964 StrFree(input_name); 00965 StrFree(output_name); 00966 return(1); 00967 } 00968 KsmParameterEnd(result); 00969 00970 /* If the policy does not share keys then skip this */ 00971 if (data.value == 1) { 00972 status = LinkKeys(o_zone, policy_id); 00973 if (status != 0) { 00974 printf("Failed to Link Keys to zone\n"); 00975 /* Carry on and write the xml if the error code was 2 00976 (not enough keys) */ 00977 if (status != 2) { 00978 db_disconnect(lock_fd); 00979 StrFree(zonelist_filename); 00980 StrFree(sig_conf_name); 00981 StrFree(input_name); 00982 StrFree(output_name); 00983 return(1); 00984 } 00985 } 00986 } 00987 00988 /* Release sqlite lock file (if we have it) */ 00989 db_disconnect(lock_fd); 00990 DbDisconnect(dbhandle); 00991 00992 if (xml_flag == 1) { 00993 /* Read the file and add our new node in memory */ 00994 /* TODO don't add if it already exists */ 00995 xmlKeepBlanksDefault(0); 00996 xmlTreeIndentString = "\t"; 00997 doc = add_zone_node(zonelist_filename, o_zone, o_policy, sig_conf_name, input_name, output_name); 00998 00999 StrFree(sig_conf_name); 01000 StrFree(input_name); 01001 StrFree(output_name); 01002 01003 if (doc == NULL) { 01004 StrFree(zonelist_filename); 01005 return(1); 01006 } 01007 01008 /* Backup the current zonelist */ 01009 StrAppend(&backup_filename, zonelist_filename); 01010 StrAppend(&backup_filename, ".backup"); 01011 status = backup_file(zonelist_filename, backup_filename); 01012 StrFree(backup_filename); 01013 if (status != 0) { 01014 StrFree(zonelist_filename); 01015 return(status); 01016 } 01017 01018 /* Save our new one over, TODO should we validate it first? */ 01019 status = xmlSaveFormatFile(zonelist_filename, doc, 1); 01020 StrFree(zonelist_filename); 01021 xmlFreeDoc(doc); 01022 01023 if (status == -1) { 01024 printf("couldn't save zonelist\n"); 01025 return(1); 01026 } 01027 } 01028 01029 /* TODO - KICK THE ENFORCER? */ 01030 /* <matthijs> TODO - ods-signer update? */ 01031 01032 if (xml_flag == 0) { 01033 printf("Imported zone: %s into database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone); 01034 } else { 01035 printf("Imported zone: %s\n", o_zone); 01036 } 01037 01038 01039 return 0; 01040 } 01041 01042 /* 01043 * Delete a zone from the config 01044 */ 01045 int 01046 cmd_delzone () 01047 { 01048 01049 char* zonelist_filename = NULL; 01050 char* backup_filename = NULL; 01051 /* The settings that we need for the zone */ 01052 int zone_id = -1; 01053 int policy_id = -1; 01054 int zone_count = -1; 01055 01056 DB_RESULT result; /* Result of parameter query */ 01057 DB_RESULT result2; /* Result of zone count query */ 01058 KSM_PARAMETER shared; /* Parameter information */ 01059 01060 xmlDocPtr doc = NULL; 01061 01062 int status = 0; 01063 int user_certain; /* Continue ? */ 01064 01065 /* Database connection details */ 01066 DB_HANDLE dbhandle; 01067 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01068 01069 /* We should either have a policy name or --all but not both */ 01070 if (all_flag && o_zone != NULL) { 01071 printf("can not use --all with --zone\n"); 01072 return(1); 01073 } 01074 else if (!all_flag && o_zone == NULL) { 01075 printf("please specify either --zone <zone> or --all\n"); 01076 return(1); 01077 } 01078 01079 /* Warn and confirm if they have asked to delete all zones */ 01080 if (all_flag == 1) { 01081 printf("*WARNING* This will remove all zones from OpenDNSSEC; are you sure? [y/N] "); 01082 01083 user_certain = getchar(); 01084 if (user_certain != 'y' && user_certain != 'Y') { 01085 printf("Okay, quitting...\n"); 01086 exit(0); 01087 } 01088 } 01089 01090 /* try to connect to the database */ 01091 status = db_connect(&dbhandle, &lock_fd, 1); 01092 if (status != 0) { 01093 printf("Failed to connect to database\n"); 01094 db_disconnect(lock_fd); 01095 return(1); 01096 } 01097 01098 /* Put dot back in if we need to; delete zone is the only time we do this */ 01099 if (td_flag == 1) { 01100 StrAppend(&o_zone, "."); 01101 } 01102 /* 01103 * DO XML STUFF FIRST 01104 */ 01105 01106 if (xml_flag == 1) { 01107 /* Set zonelist from the conf.xml that we have got */ 01108 status = read_zonelist_filename(&zonelist_filename); 01109 if (status != 0) { 01110 printf("couldn't read zonelist\n"); 01111 db_disconnect(lock_fd); 01112 StrFree(zonelist_filename); 01113 return(1); 01114 } 01115 01116 /* Read the file and delete our zone node(s) in memory */ 01117 /* N.B. This is deliberately _not_ trailing dot agnostic; the user will have to ask to delete the exact zone */ 01118 doc = del_zone_node(zonelist_filename, o_zone); 01119 if (doc == NULL) { 01120 db_disconnect(lock_fd); 01121 StrFree(zonelist_filename); 01122 return(1); 01123 } 01124 01125 /* Backup the current zonelist */ 01126 StrAppend(&backup_filename, zonelist_filename); 01127 StrAppend(&backup_filename, ".backup"); 01128 status = backup_file(zonelist_filename, backup_filename); 01129 StrFree(backup_filename); 01130 if (status != 0) { 01131 StrFree(zonelist_filename); 01132 db_disconnect(lock_fd); 01133 return(status); 01134 } 01135 01136 /* Save our new one over, TODO should we validate it first? */ 01137 status = xmlSaveFormatFile(zonelist_filename, doc, 1); 01138 xmlFreeDoc(doc); 01139 StrFree(zonelist_filename); 01140 if (status == -1) { 01141 printf("Could not save %s\n", zonelist_filename); 01142 db_disconnect(lock_fd); 01143 return(1); 01144 } 01145 } 01146 01147 /* 01148 * NOW SORT OUT THE DATABASE (zone_id will still be -1 if we are deleting all) 01149 */ 01150 01151 /* See if the zone exists and get its ID, assuming we are not deleting all */ 01152 if (all_flag == 0) { 01153 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id); 01154 if (status != 0) { 01155 printf("Couldn't find zone %s\n", o_zone); 01156 db_disconnect(lock_fd); 01157 return(1); 01158 } 01159 01160 /* Get the shared_keys parameter */ 01161 status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id); 01162 if (status != 0) { 01163 db_disconnect(lock_fd); 01164 return(status); 01165 } 01166 status = KsmParameter(result, &shared); 01167 if (status != 0) { 01168 db_disconnect(lock_fd); 01169 return(status); 01170 } 01171 KsmParameterEnd(result); 01172 01173 /* how many zones on this policy (needed to unlink keys) */ 01174 status = KsmZoneCountInit(&result2, policy_id); 01175 if (status == 0) { 01176 status = KsmZoneCount(result2, &zone_count); 01177 } 01178 DbFreeResult(result2); 01179 } 01180 01181 /* Mark keys as dead if appropriate */ 01182 if (all_flag == 1 || (shared.value == 1 && zone_count == 1) || shared.value == 0) { 01183 status = KsmMarkKeysAsDead(zone_id); 01184 if (status != 0) { 01185 printf("Error: failed to mark keys as dead in database\n"); 01186 db_disconnect(lock_fd); 01187 return(status); 01188 } 01189 } 01190 01191 /* Finally, we can delete the zone (and any dnsseckeys entries) */ 01192 status = KsmDeleteZone(zone_id); 01193 01194 if (status != 0) { 01195 printf("Error: failed to remove zone%s from database\n", (all_flag == 1) ? "s" : ""); 01196 db_disconnect(lock_fd); 01197 return status; 01198 } 01199 01200 /* Call the signer_engine_cli to tell it that the zonelist has changed */ 01201 /* TODO Should we do this when we remove a zone? */ 01202 if (all_flag == 0) { 01203 if (system(SIGNER_CLI_UPDATE) != 0) 01204 { 01205 printf("Could not call signer engine\n"); 01206 } 01207 } 01208 01209 /* Release sqlite lock file (if we have it) */ 01210 db_disconnect(lock_fd); 01211 01212 if (xml_flag == 0) { 01213 printf("Deleted zone: %s from database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone); 01214 } 01215 01216 return 0; 01217 } 01218 01219 /* 01220 * List a zone 01221 */ 01222 int 01223 cmd_listzone () 01224 { 01225 01226 DB_HANDLE dbhandle; 01227 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01228 01229 char* zonelist_filename = NULL; 01230 int* zone_ids; /* List of zone_ids seen from zonelist.xml */ 01231 01232 xmlTextReaderPtr reader = NULL; 01233 int ret = 0; /* status of the XML parsing */ 01234 char* tag_name = NULL; 01235 01236 int file_zone_count = 0; /* As a quick check we will compare the number of */ 01237 int j = 0; /* Another counter */ 01238 char buffer[256]; /* For constructing part of the command */ 01239 char* sql = NULL; /* SQL "IN" query */ 01240 DB_RESULT result; /* Result of the query */ 01241 DB_ROW row = NULL; /* Row data */ 01242 char* temp_name = NULL; 01243 01244 int status = 0; 01245 01246 /* Set zonelist from the conf.xml that we have got */ 01247 status = read_zonelist_filename(&zonelist_filename); 01248 if (status != 0) { 01249 printf("couldn't read zonelist\n"); 01250 if (zonelist_filename != NULL) { 01251 StrFree(zonelist_filename); 01252 } 01253 return(1); 01254 } 01255 01256 /* try to connect to the database */ 01257 status = db_connect(&dbhandle, &lock_fd, 1); 01258 if (status != 0) { 01259 printf("Failed to connect to database\n"); 01260 db_disconnect(lock_fd); 01261 return(1); 01262 } 01263 01264 /* Read through the file counting zones TODO better way to do this? */ 01265 reader = xmlNewTextReaderFilename(zonelist_filename); 01266 if (reader != NULL) { 01267 ret = xmlTextReaderRead(reader); 01268 while (ret == 1) { 01269 tag_name = (char*) xmlTextReaderLocalName(reader); 01270 /* Found <Zone> */ 01271 if (strncmp(tag_name, "Zone", 4) == 0 01272 && strncmp(tag_name, "ZoneList", 8) != 0 01273 && xmlTextReaderNodeType(reader) == 1) { 01274 file_zone_count++; 01275 } 01276 /* Read the next line */ 01277 ret = xmlTextReaderRead(reader); 01278 StrFree(tag_name); 01279 } 01280 xmlFreeTextReader(reader); 01281 if (ret != 0) { 01282 printf("%s : failed to parse\n", zonelist_filename); 01283 } 01284 } else { 01285 printf("Unable to open %s\n", zonelist_filename); 01286 } 01287 01288 /* Allocate space for the list of zone IDs */ 01289 zone_ids = MemMalloc(file_zone_count * sizeof(int)); 01290 01291 /* Read the file and list the zones as we go */ 01292 list_zone_node(zonelist_filename, zone_ids); 01293 01294 /* Now see if there are any zones in the DB which are not in the file */ 01295 StrAppend(&sql, "select name from zones where id not in ("); 01296 for (j = 0; j < file_zone_count; ++j) { 01297 if (j != 0) { 01298 StrAppend(&sql, ","); 01299 } 01300 snprintf(buffer, sizeof(buffer), "%d", zone_ids[j]); 01301 StrAppend(&sql, buffer); 01302 } 01303 StrAppend(&sql, ")"); 01304 01305 status = DbExecuteSql(DbHandle(), sql, &result); 01306 if (status == 0) { 01307 status = DbFetchRow(result, &row); 01308 while (status == 0) { 01309 /* Got a row, print it */ 01310 DbString(row, 0, &temp_name); 01311 01312 printf("Found zone %s in DB but not zonelist.\n", temp_name); 01313 status = DbFetchRow(result, &row); 01314 } 01315 01316 /* Convert EOF status to success */ 01317 01318 if (status == -1) { 01319 status = 0; 01320 } 01321 01322 DbFreeResult(result); 01323 } 01324 01325 db_disconnect(lock_fd); 01326 DbDisconnect(dbhandle); 01327 01328 MemFree(zone_ids); 01329 StrFree(sql); 01330 StrFree(zonelist_filename); 01331 StrFree(temp_name); 01332 01333 return 0; 01334 } 01335 01336 /* 01337 * To export: 01338 * keys|ds for zone 01339 */ 01340 int 01341 cmd_exportkeys () 01342 { 01343 int status = 0; 01344 /* Database connection details */ 01345 DB_HANDLE dbhandle; 01346 01347 int zone_id = -1; 01348 int state_id = -1; 01349 int keytype_id = KSM_TYPE_KSK; 01350 01351 char *case_keytype = NULL; 01352 char *case_keystate = NULL; 01353 char *zone_name = NULL; 01354 01355 /* Key information */ 01356 hsm_key_t *key = NULL; 01357 ldns_rr *dnskey_rr = NULL; 01358 ldns_rr *ds_sha1_rr = NULL; 01359 ldns_rr *ds_sha256_rr = NULL; 01360 hsm_sign_params_t *sign_params = NULL; 01361 01362 char* sql = NULL; 01363 KSM_KEYDATA data; /* Data for each key */ 01364 DB_RESULT result; /* Result set from query */ 01365 size_t nchar; /* Number of characters written */ 01366 char buffer[256]; /* For constructing part of the command */ 01367 01368 /* See what arguments we were passed (if any) otherwise set the defaults */ 01369 /* Check keystate, can be state or keytype */ 01370 if (o_keystate != NULL) { 01371 case_keystate = StrStrdup(o_keystate); 01372 (void) StrToUpper(case_keystate); 01373 if (strncmp(case_keystate, "KEYPUBLISH", 10) == 0 || strncmp(o_keystate, "10", 2) == 0) { 01374 state_id = KSM_STATE_KEYPUBLISH; 01375 } 01376 else if (strncmp(case_keystate, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) { 01377 state_id = KSM_STATE_GENERATE; 01378 } 01379 else if (strncmp(case_keystate, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) { 01380 state_id = KSM_STATE_PUBLISH; 01381 } 01382 else if (strncmp(case_keystate, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) { 01383 state_id = KSM_STATE_READY; 01384 } 01385 else if (strncmp(case_keystate, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) { 01386 state_id = KSM_STATE_ACTIVE; 01387 } 01388 else if (strncmp(case_keystate, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) { 01389 state_id = KSM_STATE_RETIRE; 01390 } 01391 else if (strncmp(case_keystate, "DEAD", 4) == 0 || strncmp(o_keystate, "6", 1) == 0) { 01392 state_id = KSM_STATE_DEAD; 01393 } 01394 else if (strncmp(case_keystate, "DSSUB", 5) == 0 || strncmp(o_keystate, "7", 1) == 0) { 01395 state_id = KSM_STATE_DSSUB; 01396 } 01397 else if (strncmp(case_keystate, "DSPUBLISH", 9) == 0 || strncmp(o_keystate, "8", 1) == 0) { 01398 state_id = KSM_STATE_DSPUBLISH; 01399 } 01400 else if (strncmp(case_keystate, "DSREADY", 7) == 0 || strncmp(o_keystate, "9", 1) == 0) { 01401 state_id = KSM_STATE_DSREADY; 01402 } 01403 else { 01404 printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE, RETIRE, DEAD, DSSUB, DSPUBLISH, DSREADY or KEYPUBLISH\n", o_keystate); 01405 01406 StrFree(case_keystate); 01407 return(1); 01408 } 01409 StrFree(case_keystate); 01410 } 01411 01412 /* Check keytype */ 01413 if (o_keytype != NULL) { 01414 case_keytype = StrStrdup(o_keytype); 01415 (void) StrToUpper(case_keytype); 01416 if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) { 01417 keytype_id = KSM_TYPE_KSK; 01418 } 01419 else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) { 01420 keytype_id = KSM_TYPE_ZSK; 01421 } 01422 else { 01423 printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype); 01424 01425 StrFree(case_keytype); 01426 return(1); 01427 } 01428 StrFree(case_keytype); 01429 } 01430 01431 /* try to connect to the database */ 01432 status = db_connect(&dbhandle, NULL, 0); 01433 if (status != 0) { 01434 printf("Failed to connect to database\n"); 01435 return(1); 01436 } 01437 01438 /* check that the zone name is valid and use it to get some ids */ 01439 if (o_zone != NULL) { 01440 status = KsmZoneIdFromName(o_zone, &zone_id); 01441 if (status != 0) { 01442 /* Try again with td */ 01443 StrAppend(&o_zone, "."); 01444 status = KsmZoneIdFromName(o_zone, &zone_id); 01445 if (status != 0) { 01446 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 01447 return(status); 01448 } 01449 } 01450 } 01451 01452 status = hsm_open(config, hsm_prompt_pin, NULL); 01453 if (status) { 01454 hsm_print_error(NULL); 01455 exit(-1); 01456 } 01457 01458 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 01459 if (state_id != -1) { 01460 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, state_id, 0); 01461 } else { 01462 nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d)", 01463 KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB, 01464 KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY, KSM_STATE_KEYPUBLISH); 01465 if (nchar >= sizeof(buffer)) { 01466 status = -1; 01467 return status; 01468 } 01469 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, 0); 01470 01471 } 01472 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype_id, 1); 01473 if (zone_id != -1) { 01474 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 2); 01475 } 01476 DqsOrderBy(&sql, "STATE"); 01477 DqsEnd(&sql); 01478 01479 status = KsmKeyInitSql(&result, sql); 01480 if (status == 0) { 01481 status = KsmKey(result, &data); 01482 while (status == 0) { 01483 01484 /* Code to output the DNSKEY record (stolen from hsmutil) */ 01485 key = hsm_find_key_by_id(NULL, data.location); 01486 01487 if (!key) { 01488 printf("Key %s in DB but not repository\n", data.location); 01489 return -1; 01490 } 01491 01492 sign_params = hsm_sign_params_new(); 01493 /* If zone_id == -1 then we need to work out the zone name from data.zone_id */ 01494 if (zone_id == -1) { 01495 status = KsmZoneNameFromId(data.zone_id, &zone_name); 01496 if (status != 0) { 01497 printf("Error: unable to find zone name for id %d\n", zone_id); 01498 hsm_sign_params_free(sign_params); 01499 return(status); 01500 } 01501 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name); 01502 StrFree(zone_name); 01503 } 01504 else { 01505 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, o_zone); 01506 } 01507 01508 sign_params->algorithm = data.algorithm; 01509 sign_params->flags = LDNS_KEY_ZONE_KEY; 01510 if (keytype_id == KSM_TYPE_KSK) { 01511 sign_params->flags += LDNS_KEY_SEP_KEY; 01512 } 01513 dnskey_rr = hsm_get_dnskey(NULL, key, sign_params); 01514 sign_params->keytag = ldns_calc_keytag(dnskey_rr); 01515 01516 if (ds_flag == 0) { 01517 printf("\n;%s %s DNSKEY record:\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK")); 01518 ldns_rr_print(stdout, dnskey_rr); 01519 } 01520 else { 01521 01522 printf("\n;%s %s DS record (SHA1):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK")); 01523 ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1); 01524 ldns_rr_print(stdout, ds_sha1_rr); 01525 01526 printf("\n;%s %s DS record (SHA256):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK")); 01527 ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256); 01528 ldns_rr_print(stdout, ds_sha256_rr); 01529 } 01530 01531 hsm_sign_params_free(sign_params); 01532 hsm_key_free(key); 01533 status = KsmKey(result, &data); 01534 01535 } 01536 /* Convert EOF status to success */ 01537 if (status == -1) { 01538 status = 0; 01539 } 01540 01541 KsmKeyEnd(result); 01542 } 01543 01544 /* TODO when the above is working then replicate it twice for the case where keytype == -1 */ 01545 01546 if (dnskey_rr != NULL) { 01547 ldns_rr_free(dnskey_rr); 01548 } 01549 if (ds_sha1_rr != NULL) { 01550 ldns_rr_free(ds_sha1_rr); 01551 } 01552 if (ds_sha256_rr != NULL) { 01553 ldns_rr_free(ds_sha256_rr); 01554 } 01555 01556 DbDisconnect(dbhandle); 01557 01558 return 0; 01559 } 01560 01561 /* 01562 * To export: 01563 * policies (all, unless one is named) to xml 01564 */ 01565 int 01566 cmd_exportpolicy () 01567 { 01568 int status = 0; 01569 /* Database connection details */ 01570 DB_HANDLE dbhandle; 01571 01572 xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0"); 01573 xmlNodePtr root; 01574 KSM_POLICY *policy; 01575 01576 DB_RESULT result; /* Result set from query */ 01577 01578 /* We should either have a policy name or --all but not both */ 01579 if (all_flag && o_policy != NULL) { 01580 printf("can not use --all with --policy\n"); 01581 return(1); 01582 } 01583 else if (!all_flag && o_policy == NULL) { 01584 printf("please specify either --policy <policy> or --all\n"); 01585 return(1); 01586 } 01587 01588 /* try to connect to the database */ 01589 status = db_connect(&dbhandle, NULL, 0); 01590 if (status != 0) { 01591 printf("Failed to connect to database\n"); 01592 return(1); 01593 } 01594 01595 /* Make some space for the policy */ 01596 policy = (KSM_POLICY *)malloc(sizeof(KSM_POLICY)); 01597 policy->signer = (KSM_SIGNER_POLICY *)malloc(sizeof(KSM_SIGNER_POLICY)); 01598 policy->signature = (KSM_SIGNATURE_POLICY *)malloc(sizeof(KSM_SIGNATURE_POLICY)); 01599 policy->zone = (KSM_ZONE_POLICY *)malloc(sizeof(KSM_ZONE_POLICY)); 01600 policy->parent = (KSM_PARENT_POLICY *)malloc(sizeof(KSM_PARENT_POLICY)); 01601 policy->keys = (KSM_COMMON_KEY_POLICY *)malloc(sizeof(KSM_COMMON_KEY_POLICY)); 01602 policy->ksk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY)); 01603 policy->zsk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY)); 01604 policy->denial = (KSM_DENIAL_POLICY *)malloc(sizeof(KSM_DENIAL_POLICY)); 01605 policy->enforcer = (KSM_ENFORCER_POLICY *)malloc(sizeof(KSM_ENFORCER_POLICY)); 01606 /* policy->audit = (KSM_AUDIT_POLICY *)malloc(sizeof(KSM_AUDIT_POLICY)); */ 01607 policy->audit = (char *)calloc(KSM_POLICY_AUDIT_LENGTH, sizeof(char)); 01608 policy->description = (char *)calloc(KSM_POLICY_DESC_LENGTH, sizeof(char)); 01609 if (policy->signer == NULL || policy->signature == NULL || 01610 policy->zone == NULL || policy->parent == NULL || 01611 policy->keys == NULL || 01612 policy->ksk == NULL || policy->zsk == NULL || 01613 policy->denial == NULL || policy->enforcer == NULL) { 01614 fprintf(stderr, "Malloc for policy struct failed\n"); 01615 exit(1); 01616 } 01617 01618 /* Setup doc with a root node of <KASP> */ 01619 xmlKeepBlanksDefault(0); 01620 xmlTreeIndentString = " "; 01621 root = xmlNewDocNode(doc, NULL, (const xmlChar *)"KASP", NULL); 01622 (void) xmlDocSetRootElement(doc, root); 01623 01624 /* Read policies (all if policy_name == NULL; else named policy only) */ 01625 status = KsmPolicyInit(&result, o_policy); 01626 if (status == 0) { 01627 /* get the first policy */ 01628 status = KsmPolicy(result, policy); 01629 KsmPolicyRead(policy); 01630 01631 while (status == 0) { 01632 append_policy(doc, policy); 01633 01634 /* get next policy */ 01635 status = KsmPolicy(result, policy); 01636 KsmPolicyRead(policy); 01637 01638 } 01639 } 01640 01641 xmlSaveFormatFile("-", doc, 1); 01642 01643 xmlFreeDoc(doc); 01644 KsmPolicyFree(policy); 01645 01646 DbDisconnect(dbhandle); 01647 01648 return 0; 01649 } 01650 01651 /* 01652 * To export: 01653 * zonelist to xml 01654 */ 01655 int 01656 cmd_exportzonelist () 01657 { 01658 int status = 0; 01659 /* Database connection details */ 01660 DB_HANDLE dbhandle; 01661 01662 xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0"); 01663 xmlNodePtr root; 01664 KSM_ZONE *zone; 01665 int prev_policy_id = -1; 01666 01667 DB_RESULT result; /* Result set from query */ 01668 01669 /* try to connect to the database */ 01670 status = db_connect(&dbhandle, NULL, 0); 01671 if (status != 0) { 01672 printf("Failed to connect to database\n"); 01673 return(1); 01674 } 01675 01676 /* Make some space for the zone */ 01677 zone = (KSM_ZONE *)malloc(sizeof(KSM_ZONE)); 01678 if (zone == NULL) { 01679 fprintf(stderr, "Malloc for zone struct failed\n"); 01680 exit(1); 01681 } 01682 01683 /* Setup doc with a root node of <ZoneList> */ 01684 xmlKeepBlanksDefault(0); 01685 xmlTreeIndentString = " "; 01686 root = xmlNewDocNode(doc, NULL, (const xmlChar *)"ZoneList", NULL); 01687 (void) xmlDocSetRootElement(doc, root); 01688 01689 /* Read zones */ 01690 status = KsmZoneInit(&result, -1); 01691 if (status == 0) { 01692 /* get the first zone */ 01693 status = KsmZone(result, zone); 01694 01695 while (status == 0) { 01696 if (zone->policy_id != prev_policy_id) { 01697 prev_policy_id = zone->policy_id; 01698 status = get_policy_name_from_id(zone); 01699 if (status != 0) { 01700 fprintf(stderr, "Couldn't get name for policy with ID: %d, exiting...\n", zone->policy_id); 01701 return(1); 01702 } 01703 } 01704 append_zone(doc, zone); 01705 01706 /* get next zone */ 01707 status = KsmZone(result, zone); 01708 01709 } 01710 } 01711 01712 xmlSaveFormatFile("-", doc, 1); 01713 01714 xmlFreeDoc(doc); 01715 /*KsmZoneFree(zone);*/ 01716 01717 DbDisconnect(dbhandle); 01718 01719 return 0; 01720 } 01721 01722 /* 01723 * To rollover a zone (or all zones on a policy if keys are shared) 01724 */ 01725 int 01726 cmd_rollzone () 01727 { 01728 /* Database connection details */ 01729 DB_HANDLE dbhandle; 01730 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01731 DB_RESULT result; /* Result of parameter query */ 01732 KSM_PARAMETER data; /* Parameter information */ 01733 01734 int key_type = -1; 01735 int zone_id = -1; 01736 int policy_id = -1; 01737 01738 int status = 0; 01739 int user_certain; 01740 01741 /* If we were given a keytype, turn it into a number */ 01742 if (o_keytype != NULL) { 01743 StrToLower(o_keytype); 01744 key_type = KsmKeywordTypeNameToValue(o_keytype); 01745 } 01746 01747 /* try to connect to the database */ 01748 status = db_connect(&dbhandle, &lock_fd, 1); 01749 if (status != 0) { 01750 printf("Failed to connect to database\n"); 01751 db_disconnect(lock_fd); 01752 return(1); 01753 } 01754 01755 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id); 01756 if (status != 0) { 01757 /* Try again with td */ 01758 StrAppend(&o_zone, "."); 01759 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id); 01760 if (status != 0) { 01761 db_disconnect(lock_fd); 01762 return(status); 01763 } 01764 } 01765 01766 /* Get the shared_keys parameter */ 01767 status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id); 01768 if (status != 0) { 01769 db_disconnect(lock_fd); 01770 return(status); 01771 } 01772 status = KsmParameter(result, &data); 01773 if (status != 0) { 01774 db_disconnect(lock_fd); 01775 return(status); 01776 } 01777 KsmParameterEnd(result); 01778 01779 /* Warn and confirm if this will roll more than one zone */ 01780 if (data.value == 1) { 01781 printf("*WARNING* This zone shares keys with others, all instances of the active key on this zone will be retired; are you sure? [y/N] "); 01782 01783 user_certain = getchar(); 01784 if (user_certain != 'y' && user_certain != 'Y') { 01785 printf("Okay, quitting...\n"); 01786 db_disconnect(lock_fd); 01787 exit(0); 01788 } 01789 } 01790 01791 status = keyRoll(zone_id, -1, key_type); 01792 if (status != 0) { 01793 db_disconnect(lock_fd); 01794 return(status); 01795 } 01796 01797 /* Release sqlite lock file (if we have it) */ 01798 db_disconnect(lock_fd); 01799 01800 /* Need to poke the enforcer to wake it up */ 01801 if (restart_enforcerd() != 0) 01802 { 01803 fprintf(stderr, "Could not HUP ods-enforcerd\n"); 01804 } 01805 01806 DbDisconnect(dbhandle); 01807 01808 return 0; 01809 } 01810 01811 /* 01812 * To rollover all zones on a policy 01813 */ 01814 int 01815 cmd_rollpolicy () 01816 { 01817 /* Database connection details */ 01818 DB_HANDLE dbhandle; 01819 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01820 01821 DB_RESULT result; /* To see if the policy shares keys or not */ 01822 01823 int zone_count = -1; 01824 01825 int key_type = 0; 01826 int policy_id = 0; 01827 01828 int status = 0; 01829 int user_certain; 01830 01831 /* If we were given a keytype, turn it into a number */ 01832 if (o_keytype != NULL) { 01833 StrToLower(o_keytype); 01834 key_type = KsmKeywordTypeNameToValue(o_keytype); 01835 } 01836 01837 /* try to connect to the database */ 01838 status = db_connect(&dbhandle, &lock_fd, 1); 01839 if (status != 0) { 01840 printf("Failed to connect to database\n"); 01841 db_disconnect(lock_fd); 01842 return(1); 01843 } 01844 01845 status = KsmPolicyIdFromName(o_policy, &policy_id); 01846 if (status != 0) { 01847 printf("Error, can't find policy : %s\n", o_policy); 01848 db_disconnect(lock_fd); 01849 return(status); 01850 } 01851 01852 /* Warn and confirm */ 01853 printf("*WARNING* This will roll all keys on the policy; are you sure? [y/N] "); 01854 01855 user_certain = getchar(); 01856 if (user_certain != 'y' && user_certain != 'Y') { 01857 printf("Okay, quitting...\n"); 01858 db_disconnect(lock_fd); 01859 exit(0); 01860 } 01861 01862 /* Find out how many zones we will need to do */ 01863 /* how many zones on this policy */ 01864 status = KsmZoneCountInit(&result, policy_id); 01865 if (status == 0) { 01866 status = KsmZoneCount(result, &zone_count); 01867 } 01868 DbFreeResult(result); 01869 01870 if (status == 0) { 01871 /* make sure that we have at least one zone */ 01872 if (zone_count == 0) { 01873 printf("No zones on policy; nothing to roll\n"); 01874 db_disconnect(lock_fd); 01875 return status; 01876 } 01877 } else { 01878 printf("Couldn't count zones on policy; quitting...\n"); 01879 db_disconnect(lock_fd); 01880 exit(1); 01881 } 01882 01883 status = keyRoll(-1, policy_id, key_type); 01884 01885 /* Release sqlite lock file (if we have it) */ 01886 db_disconnect(lock_fd); 01887 01888 /* Need to poke the enforcer to wake it up */ 01889 if (restart_enforcerd() != 0) 01890 { 01891 fprintf(stderr, "Could not HUP ods-enforcerd\n"); 01892 } 01893 01894 DbDisconnect(dbhandle); 01895 01896 return 0; 01897 } 01898 01899 /* 01900 * purge dead keys from the database 01901 */ 01902 int 01903 cmd_keypurge () 01904 { 01905 int status = 0; 01906 01907 int policy_id = -1; 01908 int zone_id = -1; 01909 01910 /* Database connection details */ 01911 DB_HANDLE dbhandle; 01912 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01913 01914 /* try to connect to the database */ 01915 status = db_connect(&dbhandle, &lock_fd, 1); 01916 if (status != 0) { 01917 printf("Failed to connect to database\n"); 01918 db_disconnect(lock_fd); 01919 return(1); 01920 } 01921 01922 /* Turn policy name into an id (if provided) */ 01923 if (o_policy != NULL) { 01924 status = KsmPolicyIdFromName(o_policy, &policy_id); 01925 if (status != 0) { 01926 printf("Error: unable to find a policy named \"%s\" in database\n", o_policy); 01927 db_disconnect(lock_fd); 01928 return status; 01929 } 01930 } 01931 01932 /* Turn zone name into an id (if provided) */ 01933 if (o_zone != NULL) { 01934 status = KsmZoneIdFromName(o_zone, &zone_id); 01935 if (status != 0) { 01936 /* Try again with td */ 01937 StrAppend(&o_zone, "."); 01938 status = KsmZoneIdFromName(o_zone, &zone_id); 01939 if (status != 0) { 01940 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 01941 db_disconnect(lock_fd); 01942 return(status); 01943 } 01944 } 01945 } 01946 01947 status = PurgeKeys(zone_id, policy_id); 01948 01949 if (status != 0) { 01950 printf("Error: failed to purge dead keys\n"); 01951 db_disconnect(lock_fd); 01952 return status; 01953 } 01954 01955 /* Release sqlite lock file (if we have it) */ 01956 db_disconnect(lock_fd); 01957 01958 DbDisconnect(dbhandle); 01959 return 0; 01960 } 01961 01962 /* 01963 * note that fact that a backup has been performed 01964 */ 01965 int 01966 cmd_backup (const char* qualifier) 01967 { 01968 int status = 0; 01969 01970 int repo_id = -1; 01971 01972 /* Database connection details */ 01973 DB_HANDLE dbhandle; 01974 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 01975 01976 char* datetime = DtParseDateTimeString("now"); 01977 01978 /* Check datetime in case it came back NULL */ 01979 if (datetime == NULL) { 01980 printf("Couldn't turn \"now\" into a date, quitting...\n"); 01981 exit(1); 01982 } 01983 01984 /* try to connect to the database */ 01985 status = db_connect(&dbhandle, &lock_fd, 1); 01986 if (status != 0) { 01987 printf("Failed to connect to database\n"); 01988 db_disconnect(lock_fd); 01989 StrFree(datetime); 01990 return(1); 01991 } 01992 01993 /* Turn repo name into an id (if provided) */ 01994 if (o_repository != NULL) { 01995 status = KsmSmIdFromName(o_repository, &repo_id); 01996 if (status != 0) { 01997 printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); 01998 db_disconnect(lock_fd); 01999 StrFree(datetime); 02000 return status; 02001 } 02002 } 02003 02004 /* Do Pre first */ 02005 if (strncmp(qualifier, "PREPARE", 7) == 0 || 02006 strncmp(qualifier, "DONE", 4) == 0 ) { 02007 status = KsmMarkPreBackup(repo_id, datetime); 02008 if (status == -1) { 02009 printf("There were no keys to mark\n"); 02010 } 02011 else if (status != 0) { 02012 printf("Error: failed to mark pre_backup as done\n"); 02013 db_disconnect(lock_fd); 02014 StrFree(datetime); 02015 return status; 02016 } else { 02017 if (strncmp(qualifier, "PREPARE", 7) == 0) { 02018 if (o_repository != NULL) { 02019 printf("Marked repository %s as pre-backed up at %s\n", o_repository, datetime); 02020 } else { 02021 printf("Marked all repositories as pre-backed up at %s\n", datetime); 02022 } 02023 } 02024 } 02025 } 02026 02027 /* Then commit */ 02028 if (strncmp(qualifier, "COMMIT", 6) == 0 || 02029 strncmp(qualifier, "DONE", 4) == 0 ) { 02030 status = KsmMarkBackup(repo_id, datetime); 02031 if (status == -1) { 02032 printf("There were no keys to mark\n"); 02033 } 02034 else if (status != 0) { 02035 printf("Error: failed to mark backup as done\n"); 02036 db_disconnect(lock_fd); 02037 StrFree(datetime); 02038 return status; 02039 } else { 02040 if (o_repository != NULL) { 02041 printf("Marked repository %s as backed up at %s\n", o_repository, datetime); 02042 } else { 02043 printf("Marked all repositories as backed up at %s\n", datetime); 02044 } 02045 } 02046 } 02047 02048 /* Finally rollback */ 02049 if (strncmp(qualifier, "ROLLBACK", 6) == 0 ) { 02050 status = KsmRollbackMarkPreBackup(repo_id); 02051 if (status == -1) { 02052 printf("There were no keys to rollback\n"); 02053 } 02054 else if (status != 0) { 02055 printf("Error: failed to mark backup as done\n"); 02056 db_disconnect(lock_fd); 02057 StrFree(datetime); 02058 return status; 02059 } else { 02060 if (o_repository != NULL) { 02061 printf("Rolled back pre-backup of repository %s\n", o_repository); 02062 } else { 02063 printf("Rolled back pre-backup of all repositories\n"); 02064 } 02065 } 02066 } 02067 02068 StrFree(datetime); 02069 /* Release sqlite lock file (if we have it) */ 02070 db_disconnect(lock_fd); 02071 02072 DbDisconnect(dbhandle); 02073 return 0; 02074 } 02075 02076 /* 02077 * List rollovers 02078 */ 02079 int 02080 cmd_listrolls () 02081 { 02082 int status = 0; 02083 02084 int qualifier_id = -1; /* ID of qualifer (if given) */ 02085 02086 /* Database connection details */ 02087 DB_HANDLE dbhandle; 02088 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02089 02090 /* try to connect to the database */ 02091 status = db_connect(&dbhandle, &lock_fd, 1); 02092 if (status != 0) { 02093 printf("Failed to connect to database\n"); 02094 db_disconnect(lock_fd); 02095 return(1); 02096 } 02097 02098 /* Turn zone name into an id (if provided) */ 02099 if (o_zone != NULL) { 02100 status = KsmZoneIdFromName(o_zone, &qualifier_id); 02101 if (status != 0) { 02102 /* Try again with td */ 02103 StrAppend(&o_zone, "."); 02104 status = KsmZoneIdFromName(o_zone, &qualifier_id); 02105 if (status != 0) { 02106 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 02107 db_disconnect(lock_fd); 02108 return(status); 02109 } 02110 } 02111 } 02112 02113 printf("Rollovers:\n"); 02114 02115 status = KsmListRollovers(qualifier_id); 02116 02117 if (status != 0) { 02118 printf("Error: failed to list rollovers\n"); 02119 db_disconnect(lock_fd); 02120 return status; 02121 } 02122 02123 printf("\n"); 02124 02125 /* Release sqlite lock file (if we have it) */ 02126 db_disconnect(lock_fd); 02127 02128 DbDisconnect(dbhandle); 02129 return 0; 02130 } 02131 02132 /* 02133 * List backups 02134 */ 02135 int 02136 cmd_listbackups () 02137 { 02138 int status = 0; 02139 02140 int qualifier_id = -1; /* ID of qualifer (if given) */ 02141 02142 /* Database connection details */ 02143 DB_HANDLE dbhandle; 02144 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02145 02146 /* try to connect to the database */ 02147 status = db_connect(&dbhandle, &lock_fd, 0); 02148 if (status != 0) { 02149 printf("Failed to connect to database\n"); 02150 db_disconnect(lock_fd); 02151 return(1); 02152 } 02153 02154 /* Turn repo name into an id (if provided) */ 02155 if (o_repository != NULL) { 02156 status = KsmSmIdFromName(o_repository, &qualifier_id); 02157 if (status != 0) { 02158 printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); 02159 db_disconnect(lock_fd); 02160 return status; 02161 } 02162 } 02163 02164 printf("Backups:\n"); 02165 status = KsmListBackups(qualifier_id, verbose_flag); 02166 02167 if (status != 0) { 02168 printf("Error: failed to list backups\n"); 02169 db_disconnect(lock_fd); 02170 return status; 02171 } 02172 printf("\n"); 02173 02174 /* Release sqlite lock file (if we have it) */ 02175 db_disconnect(lock_fd); 02176 02177 DbDisconnect(dbhandle); 02178 return 0; 02179 } 02180 02181 /* 02182 * List repos 02183 */ 02184 int 02185 cmd_listrepo () 02186 { 02187 int status = 0; 02188 02189 /* Database connection details */ 02190 DB_HANDLE dbhandle; 02191 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02192 02193 /* try to connect to the database */ 02194 status = db_connect(&dbhandle, &lock_fd, 0); 02195 if (status != 0) { 02196 printf("Failed to connect to database\n"); 02197 db_disconnect(lock_fd); 02198 return(1); 02199 } 02200 02201 printf("Repositories:\n"); 02202 02203 status = KsmListRepos(); 02204 02205 if (status != 0) { 02206 printf("Error: failed to list repositories\n"); 02207 if (lock_fd != NULL) { 02208 fclose(lock_fd); 02209 } 02210 return status; 02211 } 02212 02213 printf("\n"); 02214 02215 /* Release sqlite lock file (if we have it) */ 02216 db_disconnect(lock_fd); 02217 02218 DbDisconnect(dbhandle); 02219 return 0; 02220 } 02221 02222 /* 02223 * List policy 02224 */ 02225 int 02226 cmd_listpolicy () 02227 { 02228 int status = 0; 02229 02230 /* Database connection details */ 02231 DB_HANDLE dbhandle; 02232 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02233 02234 /* try to connect to the database */ 02235 status = db_connect(&dbhandle, &lock_fd, 0); 02236 if (status != 0) { 02237 printf("Failed to connect to database\n"); 02238 db_disconnect(lock_fd); 02239 return(1); 02240 } 02241 02242 printf("Policies:\n"); 02243 02244 status = KsmListPolicies(); 02245 02246 if (status != 0) { 02247 printf("Error: failed to list policies\n"); 02248 db_disconnect(lock_fd); 02249 return status; 02250 } 02251 02252 printf("\n"); 02253 02254 /* Release sqlite lock file (if we have it) */ 02255 db_disconnect(lock_fd); 02256 02257 DbDisconnect(dbhandle); 02258 return 0; 02259 } 02260 02261 /* 02262 * List keys 02263 */ 02264 int 02265 cmd_listkeys () 02266 { 02267 int status = 0; 02268 int qualifier_id = -1; 02269 02270 /* Database connection details */ 02271 DB_HANDLE dbhandle; 02272 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02273 02274 /* try to connect to the database */ 02275 status = db_connect(&dbhandle, &lock_fd, 0); 02276 if (status != 0) { 02277 printf("Failed to connect to database\n"); 02278 db_disconnect(lock_fd); 02279 return(1); 02280 } 02281 02282 /* Turn zone name into an id (if provided) */ 02283 if (o_zone != NULL) { 02284 status = KsmZoneIdFromName(o_zone, &qualifier_id); 02285 if (status != 0) { 02286 /* Try again with td */ 02287 StrAppend(&o_zone, "."); 02288 status = KsmZoneIdFromName(o_zone, &qualifier_id); 02289 if (status != 0) { 02290 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 02291 db_disconnect(lock_fd); 02292 return(status); 02293 } 02294 } 02295 } 02296 02297 printf("Keys:\n"); 02298 02299 status = ListKeys(qualifier_id); 02300 02301 if (status != 0) { 02302 printf("Error: failed to list keys\n"); 02303 db_disconnect(lock_fd); 02304 return status; 02305 } 02306 02307 printf("\n"); 02308 02309 /* Release sqlite lock file (if we have it) */ 02310 db_disconnect(lock_fd); 02311 02312 DbDisconnect(dbhandle); 02313 return 0; 02314 } 02315 02316 /* 02317 * KSKretire 02318 find key (either by details provided or oldest active), 02319 make sure that it is unique and in active state, 02320 retire key and set its dead time, 02321 */ 02322 int 02323 cmd_kskretire() 02324 { 02325 int status = 0; 02326 int zone_id = -1; 02327 int policy_id = -1; 02328 int key_count = -1; 02329 int keytag_int = -1; 02330 int temp_key_state = -1; 02331 int temp_keypair_id = -1; 02332 char* temp_cka_id = NULL; /* This will be set if we find a single matching key */ 02333 int user_certain; /* Continue ? */ 02334 02335 /* Database connection details */ 02336 DB_HANDLE dbhandle; 02337 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02338 02339 char* datetime = DtParseDateTimeString("now"); 02340 02341 /* Check datetime in case it came back NULL */ 02342 if (datetime == NULL) { 02343 printf("Couldn't turn \"now\" into a date, quitting...\n"); 02344 StrFree(datetime); 02345 exit(1); 02346 } 02347 02348 /* Warn and confirm that they realise this will retire the old key */ 02349 printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] "); 02350 02351 user_certain = getchar(); 02352 if (user_certain != 'y' && user_certain != 'Y') { 02353 printf("Okay, quitting...\n"); 02354 exit(0); 02355 } 02356 02357 /* try to connect to the database */ 02358 status = db_connect(&dbhandle, &lock_fd, 1); 02359 if (status != 0) { 02360 printf("Failed to connect to database\n"); 02361 db_disconnect(lock_fd); 02362 StrFree(datetime); 02363 return(1); 02364 } 02365 02366 /* Turn zone name into an id (if provided) */ 02367 if (o_zone != NULL) { 02368 status = KsmZoneIdFromName(o_zone, &zone_id); 02369 if (status != 0) { 02370 /* Try again with td */ 02371 StrAppend(&o_zone, "."); 02372 status = KsmZoneIdFromName(o_zone, &zone_id); 02373 if (status != 0) { 02374 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 02375 db_disconnect(lock_fd); 02376 StrFree(datetime); 02377 return(status); 02378 } 02379 } 02380 } 02381 02382 /* Check the keytag is numeric */ 02383 if (o_keytag != NULL) { 02384 if (StrIsDigits(o_keytag)) { 02385 status = StrStrtoi(o_keytag, &keytag_int); 02386 if (status != 0) { 02387 printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag); 02388 db_disconnect(lock_fd); 02389 StrFree(datetime); 02390 return(status); 02391 } 02392 } else { 02393 printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag); 02394 db_disconnect(lock_fd); 02395 StrFree(datetime); 02396 return(1); 02397 } 02398 } 02399 02400 if (o_keytag == NULL && o_cka_id == NULL) { 02401 /* We will retire the oldest key if there are 2 or more active keys */ 02402 if (o_zone == NULL) { 02403 printf("Please provide a zone or details of the key to roll\n"); 02404 usage_keykskretire(); 02405 db_disconnect(lock_fd); 02406 StrFree(datetime); 02407 return(-1); 02408 } 02409 02410 status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id); 02411 if (status != 0) { 02412 printf("Error: failed to count active keys\n"); 02413 db_disconnect(lock_fd); 02414 StrFree(datetime); 02415 return status; 02416 } 02417 02418 /* If there are not at least 2 active keys then quit */ 02419 if (key_count < 2) { 02420 printf("Error: completing this action would leave no active keys on zone, quitting...\n"); 02421 db_disconnect(lock_fd); 02422 StrFree(datetime); 02423 return -1; 02424 } 02425 02426 /* We will need a policy id for the next bit */ 02427 status = KsmPolicyIdFromZoneId(zone_id, &policy_id); 02428 if (status != 0) { 02429 printf("Error: failed to find policy for zone\n"); 02430 db_disconnect(lock_fd); 02431 StrFree(datetime); 02432 return status; 02433 } 02434 02435 status = RetireOldKey(zone_id, policy_id, datetime); 02436 02437 if (status == 0) { 02438 printf("Old key retired\n"); 02439 } else { 02440 printf("Old key NOT retired\n"); 02441 } 02442 } else { 02443 02444 /* 02445 * Get a count of keys that match our specifiers, will also print out 02446 * matching keys; note that zone_id may be overwritten 02447 */ 02448 status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id); 02449 if (status != 0) { 02450 printf("Error: failed to count keys\n"); 02451 db_disconnect(lock_fd); 02452 StrFree(datetime); 02453 return status; 02454 } 02455 02456 /* If the keycount is more than 1 then display the cka_ids of the keys */ 02457 if (key_count > 1) { 02458 printf("More than one key matched your parameters, please include more information from the above keys\n"); 02459 db_disconnect(lock_fd); 02460 StrFree(datetime); 02461 return -1; 02462 } 02463 02464 /* If the keycount is 0 or the key is not ACTIVE then write a message and exit */ 02465 if (key_count == 0 || temp_key_state != KSM_STATE_ACTIVE) { 02466 printf("No keys in the ACTIVE state matched your parameters, please check the parameters\n"); 02467 db_disconnect(lock_fd); 02468 StrFree(datetime); 02469 return -1; 02470 } 02471 02472 status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id); 02473 if (status != 0) { 02474 printf("Error: failed to count active keys\n"); 02475 db_disconnect(lock_fd); 02476 StrFree(datetime); 02477 return status; 02478 } 02479 02480 /* If there are not at least 2 active keys then quit */ 02481 if (key_count < 2) { 02482 printf("Error: completing this action would leave no active keys on zone, quitting...\n"); 02483 db_disconnect(lock_fd); 02484 StrFree(datetime); 02485 return -1; 02486 } 02487 02488 /* We will need a policy id for the next bit */ 02489 status = KsmPolicyIdFromZoneId(zone_id, &policy_id); 02490 if (status != 0) { 02491 printf("Error: failed to find policy for zone\n"); 02492 db_disconnect(lock_fd); 02493 StrFree(datetime); 02494 return status; 02495 } 02496 02497 /* Retire the key */ 02498 status = ChangeKeyState(KSM_TYPE_KSK, temp_cka_id, zone_id, policy_id, datetime, KSM_STATE_RETIRE); 02499 02500 /* Let them know that it seemed to work */ 02501 if (status == 0) { 02502 printf("Key %s retired\n", temp_cka_id); 02503 } 02504 } 02505 02506 /* Release sqlite lock file (if we have it) */ 02507 db_disconnect(lock_fd); 02508 02509 DbDisconnect(dbhandle); 02510 02511 StrFree(datetime); 02512 02513 return status; 02514 } 02515 02516 /* 02517 * DS Seen 02518 mark key as having had its DS published 02519 i.e. change its state to ACTIVE and set the time 02520 also set the time at which it will go to RETIRED 02521 */ 02522 int 02523 cmd_dsseen() 02524 { 02525 int status = 0; 02526 int zone_id = -1; 02527 int policy_id = -1; 02528 int key_count = -1; 02529 int retired_count = -1; 02530 int keytag_int = -1; 02531 int temp_key_state = -1; 02532 int temp_keypair_id = -1; 02533 char* temp_cka_id = NULL; /* This will be set if we find a single matching key */ 02534 int user_certain; /* Continue ? */ 02535 02536 /* Database connection details */ 02537 DB_HANDLE dbhandle; 02538 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02539 02540 char logmsg[256]; /* For the message that we log when a key moves */ 02541 02542 char* datetime = DtParseDateTimeString("now"); 02543 02544 /* Check datetime in case it came back NULL */ 02545 if (datetime == NULL) { 02546 printf("Couldn't turn \"now\" into a date, quitting...\n"); 02547 StrFree(datetime); 02548 exit(1); 02549 } 02550 02551 /* Check that we have either a keytag or a cka_id */ 02552 if (o_keytag == NULL && o_cka_id == NULL) { 02553 printf("Please provide a keytag or a CKA_ID for the key (CKA_ID will be used if both are provided\n"); 02554 usage_keydsseen(); 02555 StrFree(datetime); 02556 return(-1); 02557 } 02558 02559 /* Warn and confirm that they realise this will retire the old key */ 02560 if (0) { 02561 printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] "); 02562 02563 user_certain = getchar(); 02564 if (user_certain != 'y' && user_certain != 'Y') { 02565 printf("Okay, quitting...\n"); 02566 exit(0); 02567 } 02568 } 02569 /* try to connect to the database */ 02570 status = db_connect(&dbhandle, &lock_fd, 1); 02571 if (status != 0) { 02572 printf("Failed to connect to database\n"); 02573 db_disconnect(lock_fd); 02574 StrFree(datetime); 02575 return(1); 02576 } 02577 02578 /* Turn zone name into an id (if provided) */ 02579 /* TODO sort out all flag */ 02580 /*if (o_zone == NULL && !all_flag) { 02581 printf("Please specify a zone or use the --all flag to indicate all zones using this key\n");*/ 02582 if (o_zone == NULL) { 02583 printf("Please specify a zone using the --zone flag\n"); 02584 usage_keydsseen(); 02585 StrFree(datetime); 02586 db_disconnect(lock_fd); 02587 return(-1); 02588 } 02589 else if (o_zone != NULL) { 02590 status = KsmZoneIdFromName(o_zone, &zone_id); 02591 if (status != 0) { 02592 /* Try again with td */ 02593 StrAppend(&o_zone, "."); 02594 status = KsmZoneIdFromName(o_zone, &zone_id); 02595 if (status != 0) { 02596 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 02597 db_disconnect(lock_fd); 02598 StrFree(datetime); 02599 return(status); 02600 } 02601 } 02602 } 02603 else if (all_flag) { 02604 printf("*WARNING* This will act on every zone where this key is in use; are you sure? [y/N] "); 02605 02606 user_certain = getchar(); 02607 if (user_certain != 'y' && user_certain != 'Y') { 02608 printf("Okay, quitting...\n"); 02609 exit(0); 02610 } 02611 02612 zone_id = -1; 02613 } 02614 02615 /* Check the keytag is numeric */ 02616 if (o_keytag != NULL) { 02617 if (StrIsDigits(o_keytag)) { 02618 status = StrStrtoi(o_keytag, &keytag_int); 02619 if (status != 0) { 02620 printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag); 02621 db_disconnect(lock_fd); 02622 StrFree(datetime); 02623 return(status); 02624 } 02625 } else { 02626 printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag); 02627 db_disconnect(lock_fd); 02628 StrFree(datetime); 02629 return(1); 02630 } 02631 } 02632 02633 /* 02634 * Get a count of keys that match our specifiers, will also print out 02635 * matching keys; note that zone_id may be overwritten 02636 */ 02637 status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id); 02638 if (status != 0) { 02639 printf("Error: failed to count keys\n"); 02640 db_disconnect(lock_fd); 02641 StrFree(datetime); 02642 return status; 02643 } 02644 02645 /* If the keycount is more than 1 then display the cka_ids of the keys */ 02646 if (key_count > 1) { 02647 printf("More than one key matched your parameters, please include more information from the above keys\n"); 02648 db_disconnect(lock_fd); 02649 StrFree(datetime); 02650 return -1; 02651 } 02652 02653 /* If the key is already active then write a message and exit */ 02654 if (temp_key_state == KSM_STATE_ACTIVE) { 02655 printf("Key is already active\n"); 02656 db_disconnect(lock_fd); 02657 StrFree(datetime); 02658 return -1; 02659 } 02660 02661 /* If the keycount is 0 then write a message and exit */ 02662 if (key_count == 0) { 02663 printf("No keys in the READY state matched your parameters, please check the parameters\n"); 02664 db_disconnect(lock_fd); 02665 StrFree(datetime); 02666 return -1; 02667 } 02668 02669 /* We will need a policy id for the next bit */ 02670 status = KsmPolicyIdFromZoneId(zone_id, &policy_id); 02671 if (status != 0) { 02672 printf("Error: failed to find policy for zone\n"); 02673 db_disconnect(lock_fd); 02674 StrFree(datetime); 02675 return status; 02676 } 02677 02678 /* Do stuff */ 02679 status = MarkDSSeen(temp_keypair_id, zone_id, policy_id, datetime, temp_key_state); 02680 02681 /* Let them know that it seemed to work */ 02682 if (status == 0) { 02683 snprintf(logmsg, 256, "Key %s made %s", temp_cka_id, (temp_key_state == KSM_STATE_READY) ? "active" : "into standby"); 02684 printf("%s\n", logmsg); 02685 02686 /* send the msg to syslog */ 02687 openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY); 02688 syslog(LOG_INFO, "%s", logmsg); 02689 closelog(); 02690 02691 } 02692 02693 /* Retire old key, unless asked not to */ 02694 if (temp_key_state == KSM_STATE_READY) { 02695 if (retire_flag == 1) { 02696 02697 /* We will retire the oldest key if there are 2 or more active keys */ 02698 status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id); 02699 if (status != 0) { 02700 printf("Error: failed to count active keys\n"); 02701 db_disconnect(lock_fd); 02702 StrFree(datetime); 02703 return status; 02704 } 02705 02706 /* If there are not at least 2 active keys then quit */ 02707 if (key_count < 2) { 02708 /* Count retired keys to work out if this is a new zone */ 02709 /* TODO MAKE SURE THIS IS RIGHT !!! */ 02710 status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_RETIRE, &retired_count, zone_id); 02711 if (status != 0) { 02712 printf("Error: failed to count retired keys\n"); 02713 db_disconnect(lock_fd); 02714 StrFree(datetime); 02715 return status; 02716 } 02717 02718 if (retired_count != 0) { 02719 printf("Error: retiring a key would leave no active keys on zone, skipping...\n"); 02720 } 02721 db_disconnect(lock_fd); 02722 StrFree(datetime); 02723 return -1; 02724 } 02725 02726 status = RetireOldKey(zone_id, policy_id, datetime); 02727 02728 /* Let them know that it seemed to work */ 02729 if (status == 0) { 02730 printf("Old key retired\n"); 02731 } else { 02732 printf("Old key NOT retired\n"); 02733 } 02734 } else { 02735 printf("Old key NOT retired\n"); 02736 } 02737 } 02738 02739 /* Need to poke the enforcer to wake it up */ 02740 if (restart_enforcerd() != 0) 02741 { 02742 fprintf(stderr, "Could not HUP ods-enforcerd\n"); 02743 } 02744 02745 /* Release sqlite lock file (if we have it) */ 02746 db_disconnect(lock_fd); 02747 02748 DbDisconnect(dbhandle); 02749 02750 StrFree(datetime); 02751 02752 return status; 02753 } 02754 02755 /* 02756 * import a key into the ksm and set its values as specified 02757 */ 02758 int 02759 cmd_import () 02760 { 02761 int status = 0; 02762 02763 /* some strings to hold upper case versions of arguments */ 02764 char* case_keytype = NULL; /* KSK or ZSK */ 02765 char* case_algorithm = NULL; /* RSASHA1 or RSASHA1-NSEC3-SHA1 (5 or 7) */ 02766 char* case_state = NULL; /* GENERATE, PUBLISH, READY, ACTIVE or RETIRE */ 02767 02768 int repo_id = -1; 02769 int zone_id = -1; 02770 int policy_id = -1; 02771 int cka_id_exists = -1; /* do we already have this id in the HSM */ 02772 int keytype_id = -1; 02773 int size_int = -1; 02774 int algo_id = -1; 02775 int state_id = -1; 02776 char form_time[KSM_TIME_LENGTH]; /* YYYY-MM-DD HH:MM:SS + NULL Time after we reformat it */ 02777 char form_opt_time[KSM_TIME_LENGTH]; /* Opt_time after we reformat it */ 02778 02779 DB_ID keypair_id = 0; /* This will be set when we enter the keypair */ 02780 DB_ID ignore = 0; /* This will be set when we enter the dnsseckey */ 02781 02782 struct tm datetime; /* Used for getting the date/time */ 02783 02784 /* Database connection details */ 02785 DB_HANDLE dbhandle; 02786 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 02787 02788 DB_RESULT result; /* Result of parameter query */ 02789 KSM_PARAMETER data; /* Parameter information */ 02790 02791 int user_certain; /* Continue ? */ 02792 02793 /* Chech that we got all arguments. */ 02794 02795 if (o_cka_id == NULL) { 02796 printf("Error: please specify a CKA_ID with the --cka_id <CKA_ID>\n"); 02797 return(1); 02798 } 02799 if (o_repository == NULL) { 02800 printf("Error: please specify a repository with the --repository <repository>\n"); 02801 return(1); 02802 } 02803 if (o_zone == NULL) { 02804 printf("Error: please specify a zone with the --zone <zone>\n"); 02805 return(1); 02806 } 02807 if (o_size == NULL) { 02808 printf("Error: please specify the number of bits with the --bits <size>\n"); 02809 return(1); 02810 } 02811 if (o_algo == NULL) { 02812 printf("Error: please specify the algorithm with the --algorithm <algorithm>\n"); 02813 return(1); 02814 } 02815 if (o_keystate == NULL) { 02816 printf("Error: please specify the state with the --keystate <state>\n"); 02817 return(1); 02818 } 02819 if (o_keytype == NULL) { 02820 printf("Error: please specify a keytype, KSK or ZSK, with the --keytype <type>\n"); 02821 return(1); 02822 } 02823 if (o_time == NULL) { 02824 printf("Error: please specify the time of when the key entered the given state with the --time <time>\n"); 02825 return(1); 02826 } 02827 02828 /* try to connect to the database */ 02829 status = db_connect(&dbhandle, &lock_fd, 1); 02830 if (status != 0) { 02831 printf("Failed to connect to database\n"); 02832 db_disconnect(lock_fd); 02833 return(1); 02834 } 02835 02836 /* check that the repository exists */ 02837 status = KsmSmIdFromName(o_repository, &repo_id); 02838 if (status != 0) { 02839 printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); 02840 db_disconnect(lock_fd); 02841 return status; 02842 } 02843 02844 /* check that the zone name is valid and use it to get some ids */ 02845 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id); 02846 if (status != 0) { 02847 /* Try again with td */ 02848 StrAppend(&o_zone, "."); 02849 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id); 02850 if (status != 0) { 02851 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); 02852 db_disconnect(lock_fd); 02853 return(status); 02854 } 02855 } 02856 02857 /* Check that the cka_id does not exist (in the specified HSM) */ 02858 status = (KsmCheckHSMkeyID(repo_id, o_cka_id, &cka_id_exists)); 02859 if (status != 0) { 02860 db_disconnect(lock_fd); 02861 return(status); 02862 } 02863 if (cka_id_exists == 1) { 02864 printf("Error: key with CKA_ID \"%s\" already exists in database\n", o_cka_id); 02865 db_disconnect(lock_fd); 02866 return(1); 02867 } 02868 02869 /* Check the Keytype */ 02870 case_keytype = StrStrdup(o_keytype); 02871 (void) StrToUpper(case_keytype); 02872 if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) { 02873 keytype_id = 257; 02874 } 02875 else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) { 02876 keytype_id = 256; 02877 } 02878 else { 02879 printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype); 02880 02881 db_disconnect(lock_fd); 02882 StrFree(case_keytype); 02883 return(1); 02884 } 02885 StrFree(case_keytype); 02886 02887 /* Check the size is numeric */ 02888 if (StrIsDigits(o_size)) { 02889 status = StrStrtoi(o_size, &size_int); 02890 if (status != 0) { 02891 printf("Error: Unable to convert bits \"%s\"; to an integer\n", o_size); 02892 db_disconnect(lock_fd); 02893 return(status); 02894 } 02895 } else { 02896 printf("Error: Bits \"%s\"; should be numeric only\n", o_size); 02897 db_disconnect(lock_fd); 02898 return(1); 02899 } 02900 02901 /* Check the algorithm */ 02902 if (StrIsDigits(o_algo)) { 02903 /* Accept it as-is; The HSM will tell us if the number is not valid */ 02904 status = StrStrtoi(o_algo, &algo_id); 02905 } else { 02906 /* Convert name to an id, we get 0 if it is unrecognised */ 02907 case_algorithm = StrStrdup(o_algo); 02908 (void) StrToLower(case_algorithm); 02909 02910 algo_id = KsmKeywordAlgorithmNameToValue(case_algorithm); 02911 StrFree(case_algorithm); 02912 } 02913 02914 if (status != 0 || algo_id == 0 || hsm_supported_algorithm(algo_id) != 0) { 02915 printf("Error: Key algorithm %s not supported; try one of RSASHA1, RSASHA1-NSEC3-SHA1 or RSASHA256\n", o_algo); 02916 db_disconnect(lock_fd); 02917 return(status); 02918 } 02919 02920 /* Check the state */ 02921 case_state = StrStrdup(o_keystate); 02922 (void) StrToUpper(case_state); 02923 if (strncmp(case_state, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) { 02924 state_id = 1; 02925 } 02926 else if (strncmp(case_state, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) { 02927 state_id = 2; 02928 } 02929 else if (strncmp(case_state, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) { 02930 state_id = 3; 02931 } 02932 else if (strncmp(case_state, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) { 02933 state_id = 4; 02934 } 02935 else if (strncmp(case_state, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) { 02936 state_id = 5; 02937 } 02938 else { 02939 printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE or RETIRE\n", o_keystate); 02940 02941 db_disconnect(lock_fd); 02942 StrFree(case_state); 02943 return(1); 02944 } 02945 StrFree(case_state); 02946 02947 /* Check, and convert, the time(s) */ 02948 status = DtGeneral(o_time, &datetime); 02949 if (status != 0) { 02950 printf("Error: unable to convert \"%s\" into a date\n", o_time); 02951 date_help(); 02952 02953 db_disconnect(lock_fd); 02954 return(status); 02955 } 02956 else { 02957 snprintf(form_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", 02958 datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday, 02959 datetime.tm_hour, datetime.tm_min, datetime.tm_sec); 02960 } 02961 02962 if (o_retire != NULL) { 02963 /* can only specify a retire time if the key is being inserted in the active state */ 02964 if (state_id != KSM_STATE_ACTIVE) { 02965 printf("Error: unable to specify retire time for a key in state \"%s\"\n", o_keystate); 02966 db_disconnect(lock_fd); 02967 return(status); 02968 } 02969 02970 status = DtGeneral(o_retire, &datetime); 02971 if (status != 0) { 02972 printf("Error: unable to convert retire time \"%s\" into a date\n", o_retire); 02973 date_help(); 02974 02975 db_disconnect(lock_fd); 02976 return(status); 02977 } 02978 else { 02979 snprintf(form_opt_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", 02980 datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday, 02981 datetime.tm_hour, datetime.tm_min, datetime.tm_sec); 02982 } 02983 } else { 02984 form_opt_time[0] = '\0'; 02985 } 02986 02987 /* Find out if this zone has any others on a "shared keys" policy and warn */ 02988 status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id); 02989 if (status != 0) { 02990 db_disconnect(lock_fd); 02991 return(status); 02992 } 02993 status = KsmParameter(result, &data); 02994 if (status != 0) { 02995 db_disconnect(lock_fd); 02996 return(status); 02997 } 02998 KsmParameterEnd(result); 02999 03000 /* Warn and confirm if this will roll more than one zone */ 03001 if (data.value == 1) { 03002 printf("*WARNING* This zone shares keys with others, the key will be added to all; are you sure? [y/N] "); 03003 03004 user_certain = getchar(); 03005 if (user_certain != 'y' && user_certain != 'Y') { 03006 printf("Okay, quitting...\n"); 03007 db_disconnect(lock_fd); 03008 exit(0); 03009 } 03010 } 03011 03012 /* create basic keypair */ 03013 status = KsmImportKeyPair(policy_id, o_cka_id, repo_id, size_int, algo_id, state_id, form_time, &keypair_id); 03014 if (status != 0) { 03015 printf("Error: couldn't import key\n"); 03016 db_disconnect(lock_fd); 03017 return(status); 03018 } 03019 03020 /* allocate key to zone(s) */ 03021 /* TODO might not need this any more */ 03022 /* if (data.value == 1) { 03023 status = KsmDnssecKeyCreateOnPolicy(policy_id, (int) keypair_id, keytype_id); 03024 } else {*/ 03025 status = KsmDnssecKeyCreate(zone_id, (int) keypair_id, keytype_id, state_id, form_time, &ignore); 03026 03027 if (status != 0) { 03028 printf("Error: couldn't allocate key to zone(s)\n"); 03029 db_disconnect(lock_fd); 03030 return(status); 03031 } 03032 03033 printf("Key imported into zone(s)\n"); 03034 03035 /* Release sqlite lock file (if we have it) */ 03036 db_disconnect(lock_fd); 03037 03038 DbDisconnect(dbhandle); 03039 return 0; 03040 } 03041 03042 /* 03043 * make a backup of a sqlite database 03044 */ 03045 int 03046 cmd_dbbackup () 03047 { 03048 /* Database details */ 03049 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 03050 03051 /* what we will read from the file */ 03052 char *dbschema = NULL; 03053 char *host = NULL; 03054 char *port = NULL; 03055 char *user = NULL; 03056 char *password = NULL; 03057 03058 int status; 03059 03060 char* backup_filename = NULL; 03061 char* lock_filename; 03062 03063 char *path = getenv("PWD"); 03064 03065 if (DbFlavour() != SQLITE_DB) { 03066 printf("Sorry, currently this utility can only backup a sqlite database file\n"); 03067 return -1; 03068 } 03069 03070 /* Read the database details out of conf.xml */ 03071 status = get_db_details(&dbschema, &host, &port, &user, &password); 03072 if (status != 0) { 03073 StrFree(host); 03074 StrFree(port); 03075 StrFree(dbschema); 03076 StrFree(user); 03077 StrFree(password); 03078 return(status); 03079 } 03080 03081 /* set up DB lock */ 03082 lock_filename = NULL; 03083 StrAppend(&lock_filename, dbschema); 03084 StrAppend(&lock_filename, ".our_lock"); 03085 03086 lock_fd = fopen(lock_filename, "w"); 03087 status = get_lite_lock(lock_filename, lock_fd); 03088 if (status != 0) { 03089 printf("Error getting db lock\n"); 03090 if (lock_fd != NULL) { 03091 fclose(lock_fd); 03092 } 03093 StrFree(host); 03094 StrFree(port); 03095 StrFree(dbschema); 03096 StrFree(user); 03097 StrFree(password); 03098 return(1); 03099 } 03100 StrFree(lock_filename); 03101 03102 /* Work out what file to output */ 03103 if (o_output == NULL) { 03104 StrAppend(&backup_filename, dbschema); 03105 StrAppend(&backup_filename, ".backup"); 03106 } else if (*o_output != '/') { 03107 StrAppend(&backup_filename, path); 03108 StrAppend(&backup_filename, "/"); 03109 StrAppend(&backup_filename, o_output); 03110 } else { 03111 StrAppend(&backup_filename, o_output); 03112 } 03113 03114 status = backup_file(dbschema, backup_filename); 03115 03116 StrFree(backup_filename); 03117 03118 /* Cleanup */ 03119 StrFree(host); 03120 StrFree(port); 03121 StrFree(dbschema); 03122 StrFree(user); 03123 StrFree(password); 03124 03125 /* Release sqlite lock */ 03126 db_disconnect(lock_fd); 03127 03128 return status; 03129 } 03130 03131 /* 03132 * Delete any policies with no zones 03133 */ 03134 int 03135 cmd_purgepolicy () 03136 { 03137 int status = 0; 03138 03139 char* kasp_filename = NULL; 03140 char* zonelist_filename = NULL; 03141 char* backup_filename = NULL; 03142 03143 DB_HANDLE dbhandle; 03144 FILE* lock_fd = NULL; 03145 KSM_POLICY *policy; 03146 DB_RESULT result; /* Result set from policy query */ 03147 DB_RESULT result2; /* Result set from zone count query */ 03148 char sql[KSM_SQL_SIZE]; 03149 int size = -1; 03150 char* sql2; 03151 03152 FILE *test; 03153 int zone_count = -1; 03154 03155 xmlDocPtr doc = NULL; 03156 03157 int user_certain; 03158 printf("*WARNING* This feature is experimental and has not been fully tested; are you sure? [y/N] "); 03159 03160 user_certain = getchar(); 03161 if (user_certain != 'y' && user_certain != 'Y') { 03162 printf("Okay, quitting...\n"); 03163 exit(0); 03164 } 03165 03166 /* Read the conf.xml file to learn the location of the kasp.xml file. */ 03167 status = read_filenames(&zonelist_filename, &kasp_filename); 03168 if (status != 0) { 03169 printf("Failed to read conf.xml\n"); 03170 db_disconnect(lock_fd); 03171 return(1); 03172 } 03173 03174 /* Backup the current kasp.xml */ 03175 StrAppend(&backup_filename, kasp_filename); 03176 StrAppend(&backup_filename, ".backup"); 03177 status = backup_file(kasp_filename, backup_filename); 03178 StrFree(backup_filename); 03179 if (status != 0) { 03180 StrFree(kasp_filename); 03181 db_disconnect(lock_fd); 03182 return(status); 03183 } 03184 03185 /* Check that we will be able to make the changes to kasp.xml */ 03186 if ((test = fopen(kasp_filename, "ab"))==NULL) { 03187 printf("Cannot open kasp.xml for writing: %s\n", strerror(errno)); 03188 return(-1); 03189 } else { 03190 fclose(test); 03191 } 03192 03193 /* try to connect to the database */ 03194 status = db_connect(&dbhandle, &lock_fd, 1); 03195 if (status != 0) { 03196 printf("Failed to connect to database\n"); 03197 db_disconnect(lock_fd); 03198 return(1); 03199 } 03200 03201 /* Start a transaction */ 03202 status = DbBeginTransaction(); 03203 if (status != 0) { 03204 /* Something went wrong */ 03205 03206 MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 03207 db_disconnect(lock_fd); 03208 return status; 03209 } 03210 03211 /* Loop through each policy */ 03212 policy = KsmPolicyAlloc(); 03213 if (policy == NULL) { 03214 printf("Malloc for policy struct failed\n"); 03215 exit(1); 03216 } 03217 03218 /* Read all policies */ 03219 status = KsmPolicyInit(&result, NULL); 03220 if (status == 0) { 03221 /* get the first policy */ 03222 status = KsmPolicy(result, policy); 03223 while (status == 0) { 03224 /* Count zones on this policy */ 03225 status = KsmZoneCountInit(&result2, policy->id); 03226 if (status == 0) { 03227 status = KsmZoneCount(result2, &zone_count); 03228 } 03229 DbFreeResult(result2); 03230 03231 if (status == 0) { 03232 /* Only carry on if we have no zones */ 03233 if (zone_count == 0) { 03234 printf("No zones on policy %s; purging...\n", policy->name); 03235 /* set keystate to 6 across the board */ 03236 size = snprintf(sql, KSM_SQL_SIZE, "update dnsseckeys set state = %d where keypair_id in (select id from keypairs where policy_id = %d)", KSM_STATE_DEAD, policy->id); 03237 03238 /* Quick check that we didn't run out of space */ 03239 if (size < 0 || size >= KSM_SQL_SIZE) { 03240 printf("Couldn't construct SQL to kill orphaned keys\n"); 03241 db_disconnect(lock_fd); 03242 KsmPolicyFree(policy); 03243 return -1; 03244 } 03245 03246 status = DbExecuteSqlNoResult(DbHandle(), sql); 03247 03248 /* Report any errors */ 03249 if (status != 0) { 03250 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 03251 db_disconnect(lock_fd); 03252 KsmPolicyFree(policy); 03253 return status; 03254 } 03255 03256 /* call purge keys on that policy (all zones) */ 03257 status = PurgeKeys(-1, policy->id); 03258 if (status != 0) { 03259 printf("Key purge failed for policy %s\n", policy->name); 03260 db_disconnect(lock_fd); 03261 KsmPolicyFree(policy); 03262 return status; 03263 } 03264 03265 /* Delete the policy from DB */ 03266 sql2 = DdsInit("parameters_policies"); 03267 DdsConditionInt(&sql2, "policy_id", DQS_COMPARE_EQ, policy->id, 0); 03268 DdsEnd(&sql2); 03269 status = DbExecuteSqlNoResult(DbHandle(), sql2); 03270 DdsFree(sql2); 03271 03272 if (status != 0) 03273 { 03274 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 03275 db_disconnect(lock_fd); 03276 KsmPolicyFree(policy); 03277 return status; 03278 } 03279 03280 sql2 = DdsInit("policies"); 03281 DdsConditionInt(&sql2, "id", DQS_COMPARE_EQ, policy->id, 0); 03282 DdsEnd(&sql2); 03283 status = DbExecuteSqlNoResult(DbHandle(), sql2); 03284 DdsFree(sql2); 03285 03286 if (status != 0) 03287 { 03288 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 03289 db_disconnect(lock_fd); 03290 KsmPolicyFree(policy); 03291 return status; 03292 } 03293 03294 /* Delete the policy from the XML */ 03295 /* Read the file and delete our policy node(s) in memory */ 03296 doc = del_policy_node(kasp_filename, policy->name); 03297 if (doc == NULL) { 03298 db_disconnect(lock_fd); 03299 KsmPolicyFree(policy); 03300 StrFree(kasp_filename); 03301 return(1); 03302 } 03303 03304 /* Save our new file over the old, TODO should we validate it first? */ 03305 status = xmlSaveFormatFile(kasp_filename, doc, 1); 03306 xmlFreeDoc(doc); 03307 if (status == -1) { 03308 printf("Could not save %s\n", kasp_filename); 03309 StrFree(kasp_filename); 03310 db_disconnect(lock_fd); 03311 KsmPolicyFree(policy); 03312 return(1); 03313 } 03314 03315 } 03316 } else { 03317 printf("Couldn't count zones on policy; quitting...\n"); 03318 db_disconnect(lock_fd); 03319 exit(1); 03320 } 03321 03322 /* get next policy */ 03323 status = KsmPolicy(result, policy); 03324 } 03325 /* Reset EOF */ 03326 if (status == -1) { 03327 status = 0; 03328 } 03329 DbFreeResult(result); 03330 } 03331 03332 /* Commit or Rollback */ 03333 if (status == 0) { 03334 /* Everything worked by the looks of it */ 03335 DbCommit(); 03336 } else { 03337 /* Whatever happened, it was not good */ 03338 DbRollback(); 03339 } 03340 03341 StrFree(kasp_filename); 03342 db_disconnect(lock_fd); 03343 KsmPolicyFree(policy); 03344 return status; 03345 } 03346 03347 /* 03348 * Send command to ods-control 03349 */ 03350 int 03351 cmd_control(char *command) 03352 { 03353 int status = 0; 03354 char* ods_control_cmd = NULL; 03355 char* ptr = command; 03356 03357 /* We need the command in lower case */ 03358 if (ptr) { 03359 while (*ptr) { 03360 *ptr = tolower((int) *ptr); 03361 ++ptr; 03362 } 03363 } 03364 03365 /* Call "ods-control enforcer COMMAND" */ 03366 StrAppend(&ods_control_cmd, ODS_EN_CONTROL); 03367 StrAppend(&ods_control_cmd, command); 03368 03369 status = system(ods_control_cmd); 03370 if (status != 0) 03371 { 03372 fprintf(stderr, "Couldn't run %s\n", ods_control_cmd); 03373 } 03374 03375 StrFree(ods_control_cmd); 03376 03377 return(status); 03378 } 03379 03380 /* 03381 * Fairly basic main, just pass most things through to their handlers 03382 */ 03383 int 03384 main (int argc, char *argv[]) 03385 { 03386 int result; 03387 int ch; 03388 char* case_command = NULL; 03389 char* case_verb = NULL; 03390 03391 int option_index = 0; 03392 static struct option long_options[] = 03393 { 03394 {"all", no_argument, 0, 'a'}, 03395 {"bits", required_argument, 0, 'b'}, 03396 {"config", required_argument, 0, 'c'}, 03397 {"ds", no_argument, 0, 'd'}, 03398 {"keystate", required_argument, 0, 'e'}, 03399 {"no-retire", no_argument, 0, 'f'}, 03400 {"algorithm", required_argument, 0, 'g'}, 03401 {"help", no_argument, 0, 'h'}, 03402 {"input", required_argument, 0, 'i'}, 03403 {"cka_id", required_argument, 0, 'k'}, 03404 {"no-xml", no_argument, 0, 'm'}, 03405 {"interval", required_argument, 0, 'n'}, 03406 {"output", required_argument, 0, 'o'}, 03407 {"policy", required_argument, 0, 'p'}, 03408 {"repository", required_argument, 0, 'r'}, 03409 {"signerconf", required_argument, 0, 's'}, 03410 {"keytype", required_argument, 0, 't'}, 03411 {"time", required_argument, 0, 'w'}, 03412 {"verbose", no_argument, 0, 'v'}, 03413 {"version", no_argument, 0, 'V'}, 03414 {"keytag", required_argument, 0, 'x'}, 03415 {"retire", required_argument, 0, 'y'}, 03416 {"zone", required_argument, 0, 'z'}, 03417 {0,0,0,0} 03418 }; 03419 03420 progname = argv[0]; 03421 03422 while ((ch = getopt_long(argc, argv, "ab:c:de:fg:hi:k:n:o:p:r:s:t:vVw:x:y:z:", long_options, &option_index)) != -1) { 03423 switch (ch) { 03424 case 'a': 03425 all_flag = 1; 03426 break; 03427 case 'b': 03428 o_size = StrStrdup(optarg); 03429 break; 03430 case 'c': 03431 config = StrStrdup(optarg); 03432 break; 03433 case 'd': 03434 ds_flag = 1; 03435 break; 03436 case 'e': 03437 o_keystate = StrStrdup(optarg); 03438 break; 03439 case 'f': 03440 retire_flag = 0; 03441 break; 03442 case 'g': 03443 o_algo = StrStrdup(optarg); 03444 break; 03445 case 'h': 03446 usage(); 03447 states_help(); 03448 types_help(); 03449 date_help(); 03450 exit(0); 03451 break; 03452 case 'i': 03453 o_input = StrStrdup(optarg); 03454 break; 03455 case 'k': 03456 o_cka_id = StrStrdup(optarg); 03457 break; 03458 case 'm': 03459 xml_flag = 0; 03460 break; 03461 case 'n': 03462 o_interval = StrStrdup(optarg); 03463 break; 03464 case 'o': 03465 o_output = StrStrdup(optarg); 03466 break; 03467 case 'p': 03468 o_policy = StrStrdup(optarg); 03469 break; 03470 case 'r': 03471 o_repository = StrStrdup(optarg); 03472 break; 03473 case 's': 03474 o_signerconf = StrStrdup(optarg); 03475 break; 03476 case 't': 03477 o_keytype = StrStrdup(optarg); 03478 break; 03479 case 'V': 03480 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); 03481 exit(0); 03482 break; 03483 case 'v': 03484 verbose_flag = 1; 03485 break; 03486 case 'w': 03487 o_time = StrStrdup(optarg); 03488 break; 03489 case 'x': 03490 o_keytag = StrStrdup(optarg); 03491 break; 03492 case 'y': 03493 o_retire = StrStrdup(optarg); 03494 break; 03495 case 'z': 03496 /* Remove trailing dot here */ 03497 o_zone = StrStrdup(optarg); 03498 if (strlen(o_zone) > 1 && o_zone[strlen(o_zone)-1] == '.') { 03499 o_zone[strlen(o_zone)-1] = '\0'; 03500 td_flag = 1; 03501 } 03502 03503 break; 03504 default: 03505 usage(); 03506 exit(1); 03507 } 03508 } 03509 argc -= optind; 03510 argv += optind; 03511 03512 if (!argc) { 03513 usage(); 03514 exit(1); 03515 } 03516 03517 03518 /*(void) KsmInit();*/ 03519 MsgInit(); 03520 MsgRegister(KME_MIN_VALUE, KME_MAX_VALUE, m_messages, ksm_log_msg); 03521 MsgRegister(DBS_MIN_VALUE, DBS_MAX_VALUE, d_messages, ksm_log_msg); 03522 03523 /* command should be one of SETUP UPDATE ZONE REPOSITORY POLICY KEY BACKUP or ROLLOVER */ 03524 case_command = StrStrdup(argv[0]); 03525 (void) StrToUpper(case_command); 03526 if (argc > 1) { 03527 /* verb should be stuff like ADD, LIST, DELETE, etc */ 03528 case_verb = StrStrdup(argv[1]); 03529 (void) StrToUpper(case_verb); 03530 } else { 03531 case_verb = StrStrdup("NULL"); 03532 } 03533 03534 03535 if (!strncmp(case_command, "SETUP", 5)) { 03536 argc --; 03537 argv ++; 03538 result = cmd_setup(); 03539 } else if (!strncmp(case_command, "UPDATE", 6)) { 03540 argc --; 03541 argv ++; 03542 result = cmd_update(case_verb); 03543 } else if (!strncmp(case_command, "START", 5) || 03544 !strncmp(case_command, "STOP", 4) || 03545 !strncmp(case_command, "NOTIFY", 6)) { 03546 argc --; 03547 argv ++; 03548 result = cmd_control(case_command); 03549 } else if (!strncmp(case_command, "ZONE", 4) && strlen(case_command) == 4) { 03550 argc --; argc --; 03551 argv ++; argv ++; 03552 03553 /* verb should be add, delete or list */ 03554 if (!strncmp(case_verb, "ADD", 3)) { 03555 result = cmd_addzone(); 03556 } else if (!strncmp(case_verb, "DELETE", 6)) { 03557 result = cmd_delzone(); 03558 } else if (!strncmp(case_verb, "LIST", 4)) { 03559 result = cmd_listzone(); 03560 } else { 03561 printf("Unknown command: zone %s\n", case_verb); 03562 usage_zone(); 03563 result = -1; 03564 } 03565 } else if (!strncmp(case_command, "REPOSITORY", 10)) { 03566 argc --; argc --; 03567 argv ++; argv ++; 03568 /* verb should be list */ 03569 if (!strncmp(case_verb, "LIST", 4)) { 03570 result = cmd_listrepo(); 03571 } else { 03572 printf("Unknown command: repository %s\n", case_verb); 03573 usage_repo(); 03574 result = -1; 03575 } 03576 } else if (!strncmp(case_command, "POLICY", 6)) { 03577 argc --; argc --; 03578 argv ++; argv ++; 03579 /* verb should be export, import, list or purge */ 03580 if (!strncmp(case_verb, "EXPORT", 6)) { 03581 result = cmd_exportpolicy(); 03582 } else if (!strncmp(case_verb, "IMPORT", 6)) { 03583 result = cmd_update("KASP"); 03584 } else if (!strncmp(case_verb, "LIST", 4)) { 03585 result = cmd_listpolicy(); 03586 } else if (!strncmp(case_verb, "PURGE", 5)) { 03587 result = cmd_purgepolicy(); 03588 } else { 03589 printf("Unknown command: policy %s\n", case_verb); 03590 usage_policy(); 03591 result = -1; 03592 } 03593 } else if (!strncmp(case_command, "KEY", 3)) { 03594 argc --; argc --; 03595 argv ++; argv ++; 03596 /* verb should be list, export import, rollover, purge, generate, ksk-retire or ds-seen */ 03597 if (!strncmp(case_verb, "LIST", 4)) { 03598 result = cmd_listkeys(); 03599 } 03600 else if (!strncmp(case_verb, "EXPORT", 6)) { 03601 result = cmd_exportkeys(); 03602 } 03603 else if (!strncmp(case_verb, "IMPORT", 6)) { 03604 result = cmd_import(); 03605 } 03606 else if (!strncmp(case_verb, "ROLLOVER", 8)) { 03607 /* Are we rolling a zone or a whole policy? */ 03608 if (o_zone != NULL && o_policy == NULL) { 03609 result = cmd_rollzone(); 03610 } 03611 else if (o_zone == NULL && o_policy != NULL) { 03612 result = cmd_rollpolicy(); 03613 } 03614 else { 03615 printf("Please provide either a zone OR a policy to rollover\n"); 03616 usage_keyroll(); 03617 result = -1; 03618 } 03619 } 03620 else if (!strncmp(case_verb, "PURGE", 5)) { 03621 if ((o_zone != NULL && o_policy == NULL) || 03622 (o_zone == NULL && o_policy != NULL)){ 03623 result = cmd_keypurge(); 03624 } 03625 else { 03626 printf("Please provide either a zone OR a policy to key purge\n"); 03627 usage_keypurge(); 03628 result = -1; 03629 } 03630 } 03631 else if (!strncmp(case_verb, "GENERATE", 8)) { 03632 result = cmd_genkeys(); 03633 } 03634 else if (!strncmp(case_verb, "KSK-RETIRE", 10)) { 03635 result = cmd_kskretire(); 03636 } 03637 else if (!strncmp(case_verb, "DS-SEEN", 7)) { 03638 result = cmd_dsseen(); 03639 } else { 03640 printf("Unknown command: key %s\n", case_verb); 03641 usage_key(); 03642 result = -1; 03643 } 03644 } else if (!strncmp(case_command, "BACKUP", 6)) { 03645 argc --; argc --; 03646 argv ++; argv ++; 03647 /* verb should be done, prepare, commit, rollback or list */ 03648 if (!strncmp(case_verb, "DONE", 4) || 03649 !strncmp(case_verb, "PREPARE", 7) || 03650 !strncmp(case_verb, "COMMIT", 6) || 03651 !strncmp(case_verb, "ROLLBACK", 8)) { 03652 result = cmd_backup(case_verb); 03653 } 03654 else if (!strncmp(case_verb, "LIST", 4)) { 03655 result = cmd_listbackups(); 03656 } else { 03657 printf("Unknown command: backup %s\n", case_verb); 03658 usage_backup(); 03659 result = -1; 03660 } 03661 } else if (!strncmp(case_command, "ROLLOVER", 8)) { 03662 argc --; argc --; 03663 argv ++; argv ++; 03664 if (!strncmp(case_verb, "LIST", 4)) { 03665 result = cmd_listrolls(); 03666 } else { 03667 printf("Unknown command: rollover %s\n", case_verb); 03668 usage_rollover(); 03669 result = -1; 03670 } 03671 } else if (!strncmp(case_command, "DATABASE", 8)) { 03672 argc --; argc --; 03673 argv ++; argv ++; 03674 /* verb should be backup */ 03675 if (!strncmp(case_verb, "BACKUP", 6)) { 03676 result = cmd_dbbackup(); 03677 } else { 03678 printf("Unknown command: database %s\n", case_verb); 03679 usage_database(); 03680 result = -1; 03681 } 03682 } else if (!strncmp(case_command, "ZONELIST", 8)) { 03683 argc --; argc --; 03684 argv ++; argv ++; 03685 /* verb should be import or export */ 03686 if (!strncmp(case_verb, "EXPORT", 6)) { 03687 result = cmd_exportzonelist(); 03688 } 03689 else if (!strncmp(case_verb, "IMPORT", 6)) { 03690 result = cmd_update("ZONELIST"); 03691 } else { 03692 printf("Unknown command: zonelist %s\n", case_verb); 03693 usage_zonelist2(); 03694 result = -1; 03695 } 03696 } else { 03697 printf("Unknown command: %s\n", argv[0]); 03698 usage(); 03699 result = -1; 03700 } 03701 03702 StrFree(case_command); 03703 StrFree(case_verb); 03704 03705 /*(void) hsm_close();*/ 03706 /*if (config) free(config);*/ 03707 03708 xmlCleanupParser(); 03709 xmlCleanupGlobals(); 03710 xmlCleanupThreads(); 03711 03712 exit(result); 03713 } 03714 03715 03716 /* 03717 * Given a conf.xml location connect to the database contained within it 03718 * 03719 * A lock will be taken out on the DB if it is SQLite; so it is important to release it 03720 * in the calling Fn when we are done with it. 03721 * If backup is set to 1 then a backup will be made (of a sqlite DB file) 03722 * 03723 * Returns 0 if a connection was made. 03724 * 1 if a connection could not be made. 03725 * -1 if any of the config files could not be read/parsed 03726 * 03727 */ 03728 int 03729 db_connect(DB_HANDLE *dbhandle, FILE** lock_fd, int backup) 03730 { 03731 /* what we will read from the file */ 03732 char *dbschema = NULL; 03733 char *host = NULL; 03734 char *port = NULL; 03735 char *user = NULL; 03736 char *password = NULL; 03737 03738 int status; 03739 03740 char* backup_filename = NULL; 03741 char* lock_filename; 03742 03743 /* Read the database details out of conf.xml */ 03744 status = get_db_details(&dbschema, &host, &port, &user, &password); 03745 if (status != 0) { 03746 StrFree(host); 03747 StrFree(port); 03748 StrFree(dbschema); 03749 StrFree(user); 03750 StrFree(password); 03751 return(status); 03752 } 03753 03754 /* If we are in sqlite mode then take a lock out on a file to 03755 prevent multiple access (not sure that we can be sure that sqlite is 03756 safe for multiple processes to access). */ 03757 if (DbFlavour() == SQLITE_DB) { 03758 03759 /* set up lock filename (it may have changed?) */ 03760 if (lock_fd != NULL) { 03761 lock_filename = NULL; 03762 StrAppend(&lock_filename, dbschema); 03763 StrAppend(&lock_filename, ".our_lock"); 03764 03765 *lock_fd = fopen(lock_filename, "w"); 03766 status = get_lite_lock(lock_filename, *lock_fd); 03767 if (status != 0) { 03768 printf("Error getting db lock\n"); 03769 if (*lock_fd != NULL) { 03770 fclose(*lock_fd); 03771 } 03772 StrFree(host); 03773 StrFree(port); 03774 StrFree(dbschema); 03775 StrFree(user); 03776 StrFree(password); 03777 return(1); 03778 } 03779 StrFree(lock_filename); 03780 } 03781 03782 /* Make a backup of the sqlite DB */ 03783 if (backup == 1) { 03784 StrAppend(&backup_filename, dbschema); 03785 StrAppend(&backup_filename, ".backup"); 03786 03787 status = backup_file(dbschema, backup_filename); 03788 03789 StrFree(backup_filename); 03790 03791 if (status == 1) { 03792 if (lock_fd != NULL) { 03793 fclose(*lock_fd); 03794 } 03795 StrFree(host); 03796 StrFree(port); 03797 StrFree(dbschema); 03798 StrFree(user); 03799 StrFree(password); 03800 return(status); 03801 } 03802 } 03803 03804 } 03805 03806 /* Finally we can do what we came here to do, connect to the database */ 03807 status = DbConnect(dbhandle, dbschema, host, password, user, port); 03808 03809 /* Cleanup */ 03810 StrFree(host); 03811 StrFree(port); 03812 StrFree(dbschema); 03813 StrFree(user); 03814 StrFree(password); 03815 03816 return(status); 03817 } 03818 03819 /* 03820 * Release the lock if the DB is SQLite 03821 * 03822 */ 03823 void 03824 db_disconnect(FILE* lock_fd) 03825 { 03826 int status = 0; 03827 03828 if (DbFlavour() == SQLITE_DB) { 03829 if (lock_fd != NULL) { 03830 status = release_lite_lock(lock_fd); 03831 if (status != 0) { 03832 printf("Error releasing db lock"); 03833 /*fclose(lock_fd);*/ 03834 return; 03835 } 03836 fclose(lock_fd); 03837 } 03838 } 03839 return; 03840 } 03841 03842 /* To overcome the potential differences in sqlite compile flags assume that it is not 03843 happy with multiple connections. 03844 03845 The following 2 functions take out a lock and release it 03846 */ 03847 03848 int get_lite_lock(char *lock_filename, FILE* lock_fd) 03849 { 03850 struct flock fl; 03851 struct timeval tv; 03852 03853 if (lock_fd == NULL) { 03854 printf("%s could not be opened\n", lock_filename); 03855 return 1; 03856 } 03857 03858 memset(&fl, 0, sizeof(struct flock)); 03859 fl.l_type = F_WRLCK; 03860 fl.l_whence = SEEK_SET; 03861 fl.l_pid = getpid(); 03862 03863 while (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) { 03864 if (errno == EACCES || errno == EAGAIN) { 03865 printf("%s already locked, sleep\n", lock_filename); 03866 03867 /* sleep for 10 seconds TODO make this configurable? */ 03868 tv.tv_sec = 10; 03869 tv.tv_usec = 0; 03870 select(0, NULL, NULL, NULL, &tv); 03871 03872 } else { 03873 printf("couldn't get lock on %s; %s\n", lock_filename, strerror(errno)); 03874 return 1; 03875 } 03876 } 03877 03878 return 0; 03879 03880 } 03881 03882 int release_lite_lock(FILE* lock_fd) 03883 { 03884 struct flock fl; 03885 03886 if (lock_fd == NULL) { 03887 return 1; 03888 } 03889 03890 memset(&fl, 0, sizeof(struct flock)); 03891 fl.l_type = F_UNLCK; 03892 fl.l_whence = SEEK_SET; 03893 03894 if (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) { 03895 return 1; 03896 } 03897 03898 return 0; 03899 } 03900 03901 /* 03902 * Now we will read the conf.xml file again, but this time we will not validate. 03903 * Instead we just learn the location of the zonelist.xml and kasp.xml files. 03904 */ 03905 int read_filenames(char** zone_list_filename, char** kasp_filename) 03906 { 03907 xmlTextReaderPtr reader = NULL; 03908 xmlDocPtr doc = NULL; 03909 xmlXPathContextPtr xpathCtx = NULL; 03910 xmlXPathObjectPtr xpathObj = NULL; 03911 int ret = 0; /* status of the XML parsing */ 03912 char* tag_name = NULL; 03913 char* temp_char = NULL; 03914 03915 xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile"; 03916 xmlChar *kaspfile_expr = (unsigned char*) "//Common/PolicyFile"; 03917 03918 /* Start reading the file; we will be looking for "Repository" tags */ 03919 reader = xmlNewTextReaderFilename(config); 03920 if (reader != NULL) { 03921 ret = xmlTextReaderRead(reader); 03922 while (ret == 1) { 03923 tag_name = (char*) xmlTextReaderLocalName(reader); 03924 /* Found <Common> */ 03925 if (strncmp(tag_name, "Common", 6) == 0 03926 && xmlTextReaderNodeType(reader) == 1) { 03927 03928 /* Expand this node and get the rest of the info with XPath */ 03929 xmlTextReaderExpand(reader); 03930 doc = xmlTextReaderCurrentDoc(reader); 03931 if (doc == NULL) { 03932 printf("Error: can not read Common section\n"); 03933 /* Don't return? try to parse the rest of the file? */ 03934 ret = xmlTextReaderRead(reader); 03935 continue; 03936 } 03937 03938 xpathCtx = xmlXPathNewContext(doc); 03939 if(xpathCtx == NULL) { 03940 printf("Error: can not create XPath context for Common section\n"); 03941 /* Don't return? try to parse the rest of the file? */ 03942 ret = xmlTextReaderRead(reader); 03943 continue; 03944 } 03945 03946 /* Evaluate xpath expression for ZoneListFile */ 03947 xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx); 03948 if(xpathObj == NULL) { 03949 printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr); 03950 /* Don't return? try to parse the rest of the file? */ 03951 ret = xmlTextReaderRead(reader); 03952 continue; 03953 } 03954 *zone_list_filename = NULL; 03955 temp_char = (char*) xmlXPathCastToString(xpathObj); 03956 StrAppend(zone_list_filename, temp_char); 03957 StrFree(temp_char); 03958 xmlXPathFreeObject(xpathObj); 03959 printf("zonelist filename set to %s.\n", *zone_list_filename); 03960 03961 /* Evaluate xpath expression for KaspFile */ 03962 xpathObj = xmlXPathEvalExpression(kaspfile_expr, xpathCtx); 03963 xmlXPathFreeContext(xpathCtx); 03964 if(xpathObj == NULL) { 03965 printf("Error: unable to evaluate xpath expression: %s\n", kaspfile_expr); 03966 /* Don't return? try to parse the rest of the file? */ 03967 ret = xmlTextReaderRead(reader); 03968 continue; 03969 } 03970 *kasp_filename = NULL; 03971 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 03972 /* 03973 * Found Something, set it 03974 */ 03975 temp_char = (char*) xmlXPathCastToString(xpathObj); 03976 StrAppend(kasp_filename, temp_char); 03977 StrFree(temp_char); 03978 } else { 03979 /* 03980 * Set a default 03981 */ 03982 /* XXX this should be parse from the the main config */ 03983 StrAppend(kasp_filename, OPENDNSSEC_CONFIG_DIR); 03984 StrAppend(kasp_filename, "/kasp.xml"); 03985 } 03986 printf("kasp filename set to %s.\n", *kasp_filename); 03987 03988 xmlXPathFreeObject(xpathObj); 03989 } 03990 /* Read the next line */ 03991 ret = xmlTextReaderRead(reader); 03992 03993 StrFree(tag_name); 03994 } 03995 xmlFreeTextReader(reader); 03996 if (ret != 0) { 03997 printf("%s : failed to parse\n", config); 03998 return(1); 03999 } 04000 } else { 04001 printf("Unable to open %s\n", config); 04002 return(1); 04003 } 04004 if (doc) { 04005 xmlFreeDoc(doc); 04006 } 04007 04008 return 0; 04009 } 04010 04011 /* 04012 * Read the conf.xml file yet again, but this time we will not validate. 04013 * Instead we just extract the RepositoryList into the database. 04014 */ 04015 int update_repositories() 04016 { 04017 int status = 0; 04018 xmlDocPtr doc = NULL; 04019 xmlXPathContextPtr xpathCtx = NULL; 04020 xmlXPathObjectPtr xpathObj = NULL; 04021 xmlNode *curNode; 04022 char* repo_name = NULL; 04023 char* repo_capacity = NULL; 04024 int require_backup = 0; 04025 int i = 0; 04026 04027 xmlChar *node_expr = (unsigned char*) "//Configuration/RepositoryList/Repository"; 04028 04029 /* Start reading the file; we will be looking for "Repository" tags */ 04030 /* Load XML document */ 04031 doc = xmlParseFile(config); 04032 if (doc == NULL) { 04033 printf("Unable to open %s\n", config); 04034 return(1); 04035 } 04036 04037 /* Create xpath evaluation context */ 04038 xpathCtx = xmlXPathNewContext(doc); 04039 if(xpathCtx == NULL) { 04040 xmlFreeDoc(doc); 04041 return(1); 04042 } 04043 04044 /* Evaluate xpath expression */ 04045 xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx); 04046 if(xpathObj == NULL) { 04047 xmlXPathFreeContext(xpathCtx); 04048 xmlFreeDoc(doc); 04049 return(1); 04050 } 04051 04052 if (xpathObj->nodesetval) { 04053 for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { 04054 04055 require_backup = 0; 04056 StrAppend(&repo_capacity, ""); 04057 04058 curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode; 04059 repo_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], 04060 (const xmlChar *)"name"); 04061 while (curNode) { 04062 if (xmlStrEqual(curNode->name, (const xmlChar *)"Capacity")) { 04063 repo_capacity = (char *) xmlNodeGetContent(curNode); 04064 } 04065 if (xmlStrEqual(curNode->name, (const xmlChar *)"RequireBackup")) { 04066 require_backup = 1; 04067 } 04068 04069 curNode = curNode->next; 04070 } 04071 04072 if (strlen(repo_name) != 0) { 04073 /* Log what we are about to do */ 04074 printf("Repository %s found\n", repo_name); 04075 if (strlen(repo_capacity) == 0) { 04076 printf("No Maximum Capacity set.\n"); 04077 /* 04078 * We have all the information, update/insert this repository 04079 */ 04080 status = KsmImportRepository(repo_name, "0", require_backup); 04081 } else { 04082 printf("Capacity set to %s.\n", repo_capacity); 04083 /* 04084 * We have all the information, update/insert this repository 04085 */ 04086 status = KsmImportRepository(repo_name, repo_capacity, require_backup); 04087 } 04088 if (require_backup == 0) { 04089 printf("RequireBackup NOT set; please make sure that you know the potential problems of using keys which are not recoverable\n"); 04090 } else { 04091 printf("RequireBackup set.\n"); 04092 } 04093 04094 if (status != 0) { 04095 printf("Error Importing Repository %s", repo_name); 04096 /* Don't return? try to parse the rest of the zones? */ 04097 } 04098 } else { 04099 printf("WARNING: Repository found with NULL name, skipping...\n"); 04100 } 04101 StrFree(repo_name); 04102 StrFree(repo_capacity); 04103 } 04104 } 04105 04106 if (xpathObj) { 04107 xmlXPathFreeObject(xpathObj); 04108 } 04109 if (xpathCtx) { 04110 xmlXPathFreeContext(xpathCtx); 04111 } 04112 if (doc) { 04113 xmlFreeDoc(doc); 04114 } 04115 04116 return 0; 04117 } 04118 04119 /* Read kasp.xml, validate it and grab each policy in it as we go. */ 04120 int update_policies(char* kasp_filename) 04121 { 04122 int status; 04123 04124 /* what we will read from the file */ 04125 char *policy_name = NULL; 04126 char *policy_description = NULL; 04127 04128 /* All of the XML stuff */ 04129 xmlDocPtr doc = NULL; 04130 xmlDocPtr pol_doc = NULL; 04131 xmlDocPtr rngdoc = NULL; 04132 xmlNode *curNode; 04133 xmlNode *childNode; 04134 xmlNode *childNode2; 04135 xmlNode *childNode3; 04136 xmlChar *opt_out_flag = (xmlChar *)"N"; 04137 xmlChar *share_keys_flag = (xmlChar *)"N"; 04138 xmlChar *man_roll_flag = (xmlChar *)"N"; 04139 xmlChar *rfc5011_flag = (xmlChar *)"N"; 04140 int standby_keys_flag = 0; 04141 xmlXPathContextPtr xpathCtx = NULL; 04142 xmlXPathObjectPtr xpathObj = NULL; 04143 xmlRelaxNGParserCtxtPtr rngpctx = NULL; 04144 xmlRelaxNGValidCtxtPtr rngctx = NULL; 04145 xmlRelaxNGPtr schema = NULL; 04146 int i = 0; 04147 04148 xmlChar *node_expr = (unsigned char*) "//Policy"; 04149 04150 04151 /* xmlChar *audit_expr = (unsigned char*) "//Policy/Audit"; */ 04152 int audit_found = 0; /* flag to say whether an Audit flag was found or not */ 04153 04154 KSM_POLICY *policy; 04155 04156 /* Some files, the xml and rng */ 04157 const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/kasp.rng"; 04158 char* kaspcheck_cmd = NULL; 04159 char* kaspcheck_cmd_version = NULL; 04160 04161 StrAppend(&kaspcheck_cmd, ODS_AU_KASPCHECK); 04162 StrAppend(&kaspcheck_cmd, " -k "); 04163 StrAppend(&kaspcheck_cmd, kasp_filename); 04164 04165 StrAppend(&kaspcheck_cmd_version, ODS_AU_KASPCHECK); 04166 StrAppend(&kaspcheck_cmd_version, " -v > /dev/null"); 04167 04168 /* Run kaspcheck */ 04169 status = system(kaspcheck_cmd_version); 04170 if (status == 0) 04171 { 04172 status = system(kaspcheck_cmd); 04173 if (status != 0) 04174 { 04175 fprintf(stderr, "ods-kaspcheck returned an error, please check your policy\n"); 04176 StrFree(kaspcheck_cmd); 04177 StrFree(kaspcheck_cmd_version); 04178 return(-1); 04179 } 04180 } 04181 else 04182 { 04183 fprintf(stderr, "Couldn't run ods-kaspcheck (Auditor is not installed), will carry on\n"); 04184 } 04185 04186 StrFree(kaspcheck_cmd); 04187 StrFree(kaspcheck_cmd_version); 04188 04189 /* Load XML document */ 04190 doc = xmlParseFile(kasp_filename); 04191 if (doc == NULL) { 04192 printf("Error: unable to parse file \"%s\"\n", kasp_filename); 04193 return(-1); 04194 } 04195 04196 /* Load rng document: TODO make the rng stuff optional? */ 04197 rngdoc = xmlParseFile(rngfilename); 04198 if (rngdoc == NULL) { 04199 printf("Error: unable to parse file \"%s\"\n", rngfilename); 04200 return(-1); 04201 } 04202 04203 /* Create an XML RelaxNGs parser context for the relax-ng document. */ 04204 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc); 04205 if (rngpctx == NULL) { 04206 printf("Error: unable to create XML RelaxNGs parser context\n"); 04207 return(-1); 04208 } 04209 04210 /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */ 04211 schema = xmlRelaxNGParse(rngpctx); 04212 if (schema == NULL) { 04213 printf("Error: unable to parse a schema definition resource\n"); 04214 return(-1); 04215 } 04216 04217 /* Create an XML RelaxNGs validation context based on the given schema */ 04218 rngctx = xmlRelaxNGNewValidCtxt(schema); 04219 if (rngctx == NULL) { 04220 printf("Error: unable to create RelaxNGs validation context based on the schema\n"); 04221 return(-1); 04222 } 04223 04224 /* Validate a document tree in memory. */ 04225 status = xmlRelaxNGValidateDoc(rngctx,doc); 04226 if (status != 0) { 04227 printf("Error validating file \"%s\"\n", kasp_filename); 04228 return(-1); 04229 } 04230 04231 /* Allocate some space for our policy */ 04232 policy = KsmPolicyAlloc(); 04233 if (policy == NULL) { 04234 printf("Malloc for policy struct failed"); 04235 exit(1); 04236 } 04237 04238 /* Create xpath evaluation context */ 04239 xpathCtx = xmlXPathNewContext(doc); 04240 if(xpathCtx == NULL) { 04241 xmlFreeDoc(doc); 04242 KsmPolicyFree(policy); 04243 return(1); 04244 } 04245 04246 /* Evaluate xpath expression */ 04247 xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx); 04248 if(xpathObj == NULL) { 04249 xmlXPathFreeContext(xpathCtx); 04250 xmlFreeDoc(doc); 04251 KsmPolicyFree(policy); 04252 return(1); 04253 } 04254 04255 if (xpathObj->nodesetval) { 04256 for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { 04257 04258 curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode; 04259 policy_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], (const xmlChar *)"name"); 04260 if (strlen(policy_name) == 0) { 04261 /* error */ 04262 printf("Error extracting policy name from %s\n", kasp_filename); 04263 break; 04264 } 04265 audit_found = 0; 04266 04267 printf("Policy %s found\n", policy_name); 04268 while (curNode) { 04269 if (xmlStrEqual(curNode->name, (const xmlChar *)"Description")) { 04270 policy_description = (char *) xmlNodeGetContent(curNode); 04271 04272 /* Insert or update this policy with the description found, 04273 we will need the policy_id too */ 04274 SetPolicyDefaults(policy, policy_name); 04275 status = KsmPolicyExists(policy_name); 04276 if (status == 0) { 04277 /* Policy exists; we will be updating it */ 04278 status = KsmPolicyRead(policy); 04279 if(status != 0) { 04280 printf("Error: unable to read policy %s; skipping\n", policy_name); 04281 curNode = curNode->next; 04282 break; 04283 } 04284 /* TODO Set description here ? */ 04285 } 04286 else { 04287 /* New policy, insert it and get the new policy_id */ 04288 status = KsmImportPolicy(policy_name, policy_description); 04289 if(status != 0) { 04290 printf("Error: unable to insert policy %s; skipping\n", policy_name); 04291 /* Don't return? try to parse the rest of the file? */ 04292 continue; 04293 } 04294 status = KsmPolicySetIdFromName(policy); 04295 04296 if (status != 0) { 04297 printf("Error: unable to get policy id for %s; skipping\n", policy_name); 04298 continue; 04299 } 04300 } 04301 } 04302 /* SIGNATURES */ 04303 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Signatures")) { 04304 childNode = curNode->children; 04305 while (childNode){ 04306 if (xmlStrEqual(childNode->name, (const xmlChar *)"Resign")) { 04307 SetParamOnPolicy(xmlNodeGetContent(childNode), "resign", "signature", policy->signature->resign, policy->id, DURATION_TYPE); 04308 } 04309 else if (xmlStrEqual(childNode->name, (const xmlChar *)"Refresh")) { 04310 SetParamOnPolicy(xmlNodeGetContent(childNode), "refresh", "signature", policy->signer->refresh, policy->id, DURATION_TYPE); 04311 } 04312 else if (xmlStrEqual(childNode->name, (const xmlChar *)"Validity")) { 04313 childNode2 = childNode->children; 04314 while (childNode2){ 04315 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Default")) { 04316 SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdefault", "signature", policy->signature->valdefault, policy->id, DURATION_TYPE); 04317 } 04318 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Denial")) { 04319 SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdenial", "signature", policy->signature->valdenial, policy->id, DURATION_TYPE); 04320 } 04321 childNode2 = childNode2->next; 04322 } 04323 } 04324 else if (xmlStrEqual(childNode->name, (const xmlChar *)"Jitter")) { 04325 SetParamOnPolicy(xmlNodeGetContent(childNode), "jitter", "signature", policy->signer->jitter, policy->id, DURATION_TYPE); 04326 } 04327 else if (xmlStrEqual(childNode->name, (const xmlChar *)"InceptionOffset")) { 04328 SetParamOnPolicy(xmlNodeGetContent(childNode), "clockskew", "signature", policy->signature->clockskew, policy->id, DURATION_TYPE); 04329 } 04330 childNode = childNode->next; 04331 } 04332 } /* End of Signatures */ 04333 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Denial")) { 04334 opt_out_flag = (xmlChar *)"N"; 04335 childNode = curNode->children; 04336 while (childNode){ 04337 if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC3")) { 04338 /* NSEC3 */ 04339 status = KsmParameterSet("version", "denial", 3, policy->id); 04340 if (status != 0) { 04341 printf("Error: unable to insert/update %s for policy\n", "Denial version"); 04342 } 04343 childNode2 = childNode->children; 04344 while (childNode2){ 04345 if (xmlStrEqual(childNode2->name, (const xmlChar *)"OptOut")) { 04346 opt_out_flag = (xmlChar *)"Y"; 04347 } 04348 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Resalt")) { 04349 SetParamOnPolicy(xmlNodeGetContent(childNode2), "resalt", "denial", policy->denial->resalt, policy->id, DURATION_TYPE); 04350 } 04351 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Hash")) { 04352 childNode3 = childNode2->children; 04353 while (childNode3){ 04354 if (xmlStrEqual(childNode3->name, (const xmlChar *)"Algorithm")) { 04355 SetParamOnPolicy(xmlNodeGetContent(childNode3), "algorithm", "denial", policy->denial->algorithm, policy->id, INT_TYPE); 04356 } 04357 else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Iterations")) { 04358 SetParamOnPolicy(xmlNodeGetContent(childNode3), "iterations", "denial", policy->denial->iteration, policy->id, INT_TYPE); 04359 } 04360 else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Salt")) { 04361 SetParamOnPolicy(xmlGetProp(childNode3, (const xmlChar *)"length"), "saltlength", "denial", policy->denial->saltlength, policy->id, INT_TYPE); 04362 } 04363 childNode3 = childNode3->next; 04364 } 04365 } 04366 04367 childNode2 = childNode2->next; 04368 } 04369 /* Set things that we flagged */ 04370 SetParamOnPolicy(opt_out_flag, "optout", "denial", policy->denial->optout, policy->id, BOOL_TYPE); 04371 } /* End of NSEC3 */ 04372 else if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC")) { 04373 status = KsmParameterSet("version", "denial", 1, policy->id); 04374 if (status != 0) { 04375 printf("Error: unable to insert/update %s for policy\n", "Denial version"); 04376 } 04377 } 04378 childNode = childNode->next; 04379 } 04380 } /* End of Denial */ 04381 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Keys")) { 04382 share_keys_flag = (xmlChar *)"N"; 04383 childNode = curNode->children; 04384 while (childNode){ 04385 if (xmlStrEqual(childNode->name, (const xmlChar *)"TTL")) { 04386 SetParamOnPolicy(xmlNodeGetContent(childNode), "ttl", "keys", policy->keys->ttl, policy->id, DURATION_TYPE); 04387 } 04388 else if (xmlStrEqual(childNode->name, (const xmlChar *)"RetireSafety")) { 04389 SetParamOnPolicy(xmlNodeGetContent(childNode), "retiresafety", "keys", policy->keys->retire_safety, policy->id, DURATION_TYPE); 04390 } 04391 else if (xmlStrEqual(childNode->name, (const xmlChar *)"PublishSafety")) { 04392 SetParamOnPolicy(xmlNodeGetContent(childNode), "publishsafety", "keys", policy->keys->publish_safety, policy->id, DURATION_TYPE); 04393 } 04394 else if (xmlStrEqual(childNode->name, (const xmlChar *)"ShareKeys")) { 04395 share_keys_flag = (xmlChar *)"Y"; 04396 } 04397 else if (xmlStrEqual(childNode->name, (const xmlChar *)"Purge")) { 04398 SetParamOnPolicy(xmlNodeGetContent(childNode), "purge", "keys", policy->keys->purge, policy->id, DURATION_TYPE); 04399 } 04400 /* KSK */ 04401 else if (xmlStrEqual(childNode->name, (const xmlChar *)"KSK")) { 04402 man_roll_flag = (xmlChar *)"N"; 04403 rfc5011_flag = (xmlChar *)"N"; 04404 childNode2 = childNode->children; 04405 while (childNode2){ 04406 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) { 04407 SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "ksk", policy->ksk->algorithm, policy->id, INT_TYPE); 04408 SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "ksk", policy->ksk->bits, policy->id, INT_TYPE); 04409 04410 } 04411 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) { 04412 SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "ksk", policy->ksk->lifetime, policy->id, DURATION_TYPE); 04413 } 04414 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) { 04415 if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "ksk", policy->ksk->sm, policy->id, REPO_TYPE) != 0) { 04416 printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n"); 04417 /* return the error, we do not want to continue */ 04418 xmlFreeDoc(pol_doc); 04419 xmlXPathFreeContext(xpathCtx); 04420 xmlRelaxNGFree(schema); 04421 xmlRelaxNGFreeValidCtxt(rngctx); 04422 xmlRelaxNGFreeParserCtxt(rngpctx); 04423 xmlFreeDoc(doc); 04424 xmlFreeDoc(rngdoc); 04425 KsmPolicyFree(policy); 04426 04427 return(1); 04428 } 04429 } 04430 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) { 04431 SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE); 04432 standby_keys_flag = 1; 04433 } 04434 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) { 04435 man_roll_flag = (xmlChar *)"Y"; 04436 } 04437 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RFC5011")) { 04438 rfc5011_flag = (xmlChar *)"Y"; 04439 } 04440 /*else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RolloverScheme")) { 04441 SetParamOnPolicy(xmlNodeGetContent(childNode2), "rollover_scheme", "ksk", policy->ksk->rollover_scheme, policy->id, ROLLOVER_TYPE); 04442 }*/ 04443 childNode2 = childNode2->next; 04444 } 04445 /* Set things that we flagged */ 04446 SetParamOnPolicy(man_roll_flag, "manual_rollover", "ksk", policy->ksk->manual_rollover, policy->id, BOOL_TYPE); 04447 SetParamOnPolicy(rfc5011_flag, "rfc5011", "ksk", policy->ksk->rfc5011, policy->id, BOOL_TYPE); 04448 if (standby_keys_flag == 0) { 04449 SetParamOnPolicy((xmlChar *)"0", "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE_NO_FREE); 04450 } else { 04451 standby_keys_flag = 0; 04452 } 04453 } /* End of KSK */ 04454 /* ZSK */ 04455 else if (xmlStrEqual(childNode->name, (const xmlChar *)"ZSK")) { 04456 man_roll_flag = (xmlChar *)"N"; 04457 childNode2 = childNode->children; 04458 while (childNode2){ 04459 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) { 04460 SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "zsk", policy->zsk->algorithm, policy->id, INT_TYPE); 04461 SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "zsk", policy->zsk->bits, policy->id, INT_TYPE); 04462 04463 } 04464 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) { 04465 SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "zsk", policy->zsk->lifetime, policy->id, DURATION_TYPE); 04466 } 04467 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) { 04468 if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "zsk", policy->zsk->sm, policy->id, REPO_TYPE) != 0) { 04469 printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n"); 04470 /* return the error, we do not want to continue */ 04471 xmlFreeDoc(pol_doc); 04472 xmlXPathFreeContext(xpathCtx); 04473 xmlRelaxNGFree(schema); 04474 xmlRelaxNGFreeValidCtxt(rngctx); 04475 xmlRelaxNGFreeParserCtxt(rngpctx); 04476 xmlFreeDoc(doc); 04477 xmlFreeDoc(rngdoc); 04478 KsmPolicyFree(policy); 04479 04480 return(1); 04481 } 04482 } 04483 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) { 04484 SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE); 04485 standby_keys_flag = 1; 04486 } 04487 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) { 04488 man_roll_flag = (xmlChar *)"Y"; 04489 } 04490 childNode2 = childNode2->next; 04491 } 04492 /* Set things that we flagged */ 04493 SetParamOnPolicy(man_roll_flag, "manual_rollover", "zsk", policy->zsk->manual_rollover, policy->id, BOOL_TYPE); 04494 } /* End of ZSK */ 04495 04496 childNode = childNode->next; 04497 } 04498 /* Set things that we flagged */ 04499 SetParamOnPolicy(share_keys_flag, "zones_share_keys", "keys", policy->keys->share_keys, policy->id, BOOL_TYPE); 04500 if (standby_keys_flag == 0) { 04501 SetParamOnPolicy((xmlChar *)"0", "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE_NO_FREE); 04502 } else { 04503 standby_keys_flag = 0; 04504 } 04505 04506 } /* End of Keys */ 04507 /* Zone */ 04508 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Zone")) { 04509 childNode = curNode->children; 04510 while (childNode){ 04511 if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) { 04512 SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "zone", policy->zone->propdelay, policy->id, DURATION_TYPE); 04513 } 04514 else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) { 04515 childNode2 = childNode->children; 04516 while (childNode2){ 04517 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) { 04518 SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "zone", policy->zone->soa_ttl, policy->id, DURATION_TYPE); 04519 } 04520 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) { 04521 SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "zone", policy->zone->soa_min, policy->id, DURATION_TYPE); 04522 } 04523 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Serial")) { 04524 SetParamOnPolicy(xmlNodeGetContent(childNode2), "serial", "zone", policy->zone->serial, policy->id, SERIAL_TYPE); 04525 } 04526 childNode2 = childNode2->next; 04527 } 04528 } 04529 childNode = childNode->next; 04530 } 04531 } /* End of Zone */ 04532 /* Parent */ 04533 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Parent")) { 04534 childNode = curNode->children; 04535 while (childNode){ 04536 if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) { 04537 SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "parent", policy->parent->propdelay, policy->id, DURATION_TYPE); 04538 } 04539 else if (xmlStrEqual(childNode->name, (const xmlChar *)"DS")) { 04540 childNode2 = childNode->children; 04541 while (childNode2){ 04542 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) { 04543 SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttlds", "parent", policy->parent->ds_ttl, policy->id, DURATION_TYPE); 04544 } 04545 childNode2 = childNode2->next; 04546 } 04547 } 04548 else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) { 04549 childNode2 = childNode->children; 04550 while (childNode2){ 04551 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) { 04552 SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "parent", policy->parent->soa_ttl, policy->id, DURATION_TYPE); 04553 } 04554 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) { 04555 SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "parent", policy->parent->soa_min, policy->id, DURATION_TYPE); 04556 } 04557 childNode2 = childNode2->next; 04558 } 04559 } 04560 childNode = childNode->next; 04561 } 04562 } /* End of Parent */ 04563 /* Audit */ 04564 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Audit")) { 04565 status = KsmImportAudit(policy->id, ""); 04566 childNode = curNode->children; 04567 while (childNode){ 04568 if (xmlStrEqual(childNode->name, (const xmlChar *)"Partial")) { 04569 status = KsmImportAudit(policy->id, "<Partial/>"); 04570 } 04571 childNode = childNode->next; 04572 } 04573 audit_found = 1; 04574 if(status != 0) { 04575 printf("Error: unable to insert Audit info for policy %s\n", policy->name); 04576 } 04577 } 04578 04579 curNode = curNode->next; 04580 } 04581 /* Indicate in the database if we didn't find an audit tag */ 04582 if (audit_found == 0) { 04583 status = KsmImportAudit(policy->id, "NULL"); 04584 } 04585 04586 /* Free up some stuff that we don't need any more */ 04587 StrFree(policy_name); 04588 StrFree(policy_description); 04589 04590 } /* End of <Policy> */ 04591 } 04592 04593 /* Cleanup */ 04594 xmlXPathFreeContext(xpathCtx); 04595 xmlRelaxNGFree(schema); 04596 xmlRelaxNGFreeValidCtxt(rngctx); 04597 xmlRelaxNGFreeParserCtxt(rngpctx); 04598 xmlFreeDoc(doc); 04599 xmlFreeDoc(rngdoc); 04600 KsmPolicyFree(policy); 04601 04602 return(status); 04603 } 04604 04605 /* Read zonelist (as passed in) and insert/update any zones seen */ 04606 int update_zones(char* zone_list_filename) 04607 { 04608 int status = 0; 04609 xmlTextReaderPtr reader = NULL; 04610 xmlDocPtr doc = NULL; 04611 xmlXPathContextPtr xpathCtx = NULL; 04612 xmlXPathObjectPtr xpathObj = NULL; 04613 int ret = 0; /* status of the XML parsing */ 04614 char* zone_name = NULL; 04615 char* policy_name = NULL; 04616 char* current_policy = NULL; 04617 char* current_signconf = NULL; 04618 char* current_input = NULL; 04619 char* current_output = NULL; 04620 char* temp_char = NULL; 04621 char* tag_name = NULL; 04622 int policy_id = 0; 04623 int new_zone = 0; /* flag to say if the zone is new or not */ 04624 int file_zone_count = 0; /* As a quick check we will compare the number of */ 04625 int db_zone_count = 0; /* zones in the file to the number in the database */ 04626 int* zone_ids; /* List of zone_ids seen from zonelist.xml */ 04627 int temp_id; 04628 04629 char* sql = NULL; 04630 DB_RESULT result; /* Result of the query */ 04631 DB_RESULT result2; /* Result of the query */ 04632 DB_RESULT result3; /* Result of the query */ 04633 DB_ROW row = NULL; /* Row data */ 04634 KSM_PARAMETER shared; /* Parameter information */ 04635 int seen_zone = 0; 04636 int temp_count = 0; 04637 int i = 0; 04638 04639 xmlChar *name_expr = (unsigned char*) "name"; 04640 xmlChar *policy_expr = (unsigned char*) "//Zone/Policy"; 04641 xmlChar *signconf_expr = (unsigned char*) "//Zone/SignerConfiguration"; 04642 xmlChar *input_expr = (unsigned char*) "//Zone/Adapters/Input/File"; 04643 xmlChar *output_expr = (unsigned char*) "//Zone/Adapters/Output/File"; 04644 04645 /* TODO validate the file ? */ 04646 /* Read through the file counting zones TODO better way to do this? */ 04647 reader = xmlNewTextReaderFilename(zone_list_filename); 04648 if (reader != NULL) { 04649 ret = xmlTextReaderRead(reader); 04650 while (ret == 1) { 04651 tag_name = (char*) xmlTextReaderLocalName(reader); 04652 /* Found <Zone> */ 04653 if (strncmp(tag_name, "Zone", 4) == 0 04654 && strncmp(tag_name, "ZoneList", 8) != 0 04655 && xmlTextReaderNodeType(reader) == 1) { 04656 file_zone_count++; 04657 } 04658 /* Read the next line */ 04659 ret = xmlTextReaderRead(reader); 04660 StrFree(tag_name); 04661 } 04662 xmlFreeTextReader(reader); 04663 if (ret != 0) { 04664 printf("%s : failed to parse\n", zone_list_filename); 04665 } 04666 } else { 04667 printf("Unable to open %s\n", zone_list_filename); 04668 } 04669 04670 /* Allocate space for the list of zone IDs */ 04671 zone_ids = MemMalloc(file_zone_count * sizeof(int)); 04672 04673 /* Start reading the file; we will be looking for "Zone" tags */ 04674 reader = xmlNewTextReaderFilename(zone_list_filename); 04675 if (reader != NULL) { 04676 ret = xmlTextReaderRead(reader); 04677 while (ret == 1) { 04678 tag_name = (char*) xmlTextReaderLocalName(reader); 04679 /* Found <Zone> */ 04680 if (strncmp(tag_name, "Zone", 4) == 0 04681 && strncmp(tag_name, "ZoneList", 8) != 0 04682 && xmlTextReaderNodeType(reader) == 1) { 04683 /* Get the repository name */ 04684 zone_name = NULL; 04685 temp_char = (char*) xmlTextReaderGetAttribute(reader, name_expr); 04686 StrAppend(&zone_name, temp_char); 04687 StrFree(temp_char); 04688 04689 /* 04690 It is tempting to remove the trailing dot here; however I am 04691 not sure that it is the right thing to do... It trashed my 04692 test setup by deleting the zone sion. and replacing it with 04693 sion (but of course none of the keys were moved). I think 04694 that allowing people to edit zonelist.xml means that we must 04695 allow them to add the td if they want to. 04696 */ 04697 04698 /* Make sure that we got something */ 04699 if (zone_name == NULL) { 04700 /* error */ 04701 printf("Error extracting zone name from %s\n", zone_list_filename); 04702 /* Don't return? try to parse the rest of the file? */ 04703 ret = xmlTextReaderRead(reader); 04704 continue; 04705 } 04706 04707 printf("Zone %s found\n", zone_name); 04708 04709 /* Expand this node and get the rest of the info with XPath */ 04710 xmlTextReaderExpand(reader); 04711 doc = xmlTextReaderCurrentDoc(reader); 04712 if (doc == NULL) { 04713 printf("Error: can not read zone \"%s\"; skipping\n", zone_name); 04714 /* Don't return? try to parse the rest of the zones? */ 04715 ret = xmlTextReaderRead(reader); 04716 continue; 04717 } 04718 04719 xpathCtx = xmlXPathNewContext(doc); 04720 if(xpathCtx == NULL) { 04721 printf("Error: can not create XPath context for \"%s\"; skipping zone\n", zone_name); 04722 /* Don't return? try to parse the rest of the zones? */ 04723 ret = xmlTextReaderRead(reader); 04724 continue; 04725 } 04726 04727 /* Extract the Policy name for this zone */ 04728 /* Evaluate xpath expression for policy */ 04729 xpathObj = xmlXPathEvalExpression(policy_expr, xpathCtx); 04730 if(xpathObj == NULL) { 04731 printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", policy_expr); 04732 /* Don't return? try to parse the rest of the zones? */ 04733 ret = xmlTextReaderRead(reader); 04734 continue; 04735 } 04736 04737 current_policy = NULL; 04738 temp_char = (char *)xmlXPathCastToString(xpathObj); 04739 StrAppend(¤t_policy, temp_char); 04740 StrFree(temp_char); 04741 printf("Policy set to %s.\n", current_policy); 04742 xmlXPathFreeObject(xpathObj); 04743 04744 /* If we have a different policy to last time get its ID */ 04745 if (policy_name == NULL || strcmp(current_policy, policy_name) != 0) { 04746 StrFree(policy_name); 04747 StrAppend(&policy_name, current_policy); 04748 04749 status = KsmPolicyIdFromName(policy_name, &policy_id); 04750 if (status != 0) { 04751 printf("Error, can't find policy : %s\n", policy_name); 04752 /* Don't return? try to parse the rest of the zones? */ 04753 ret = xmlTextReaderRead(reader); 04754 continue; 04755 } 04756 } 04757 04758 /* Extract the Signconf name for this zone */ 04759 /* Evaluate xpath expression */ 04760 xpathObj = xmlXPathEvalExpression(signconf_expr, xpathCtx); 04761 if(xpathObj == NULL) { 04762 printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", signconf_expr); 04763 /* Don't return? try to parse the rest of the zones? */ 04764 ret = xmlTextReaderRead(reader); 04765 continue; 04766 } 04767 04768 current_signconf = NULL; 04769 temp_char = (char *)xmlXPathCastToString(xpathObj); 04770 StrAppend(¤t_signconf, temp_char); 04771 StrFree(temp_char); 04772 xmlXPathFreeObject(xpathObj); 04773 04774 /* Extract the Input name for this zone */ 04775 /* Evaluate xpath expression */ 04776 xpathObj = xmlXPathEvalExpression(input_expr, xpathCtx); 04777 if(xpathObj == NULL) { 04778 printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", input_expr); 04779 /* Don't return? try to parse the rest of the zones? */ 04780 ret = xmlTextReaderRead(reader); 04781 continue; 04782 } 04783 04784 current_input = NULL; 04785 temp_char = (char *)xmlXPathCastToString(xpathObj); 04786 StrAppend(¤t_input, temp_char); 04787 StrFree(temp_char); 04788 xmlXPathFreeObject(xpathObj); 04789 04790 /* Extract the Output name for this zone */ 04791 /* Evaluate xpath expression */ 04792 xpathObj = xmlXPathEvalExpression(output_expr, xpathCtx); 04793 xmlXPathFreeContext(xpathCtx); 04794 if(xpathObj == NULL) { 04795 printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", output_expr); 04796 /* Don't return? try to parse the rest of the zones? */ 04797 ret = xmlTextReaderRead(reader); 04798 continue; 04799 } 04800 04801 current_output = NULL; 04802 temp_char = (char *)xmlXPathCastToString(xpathObj); 04803 StrAppend(¤t_output, temp_char); 04804 StrFree(temp_char); 04805 xmlXPathFreeObject(xpathObj); 04806 04807 /* 04808 * Now we have all the information update/insert this repository 04809 */ 04810 status = KsmImportZone(zone_name, policy_id, 0, &new_zone, current_signconf, current_input, current_output); 04811 if (status != 0) { 04812 if (status == -3) { 04813 printf("Error Importing zone %s; it already exists both with and without a trailing dot\n", zone_name); 04814 } else { 04815 printf("Error Importing Zone %s\n", zone_name); 04816 } 04817 /* Don't return? try to parse the rest of the zones? */ 04818 ret = xmlTextReaderRead(reader); 04819 continue; 04820 } 04821 04822 /* If need be link existing keys to zone */ 04823 if (new_zone == 1) { 04824 printf("Added zone %s to database\n", zone_name); 04825 /* WITH NEW KEYSHARING LEAVE THIS TO THE ENFORCER TODO - CHECK THIS IS RIGHT */ 04826 /* 04827 status = KsmLinkKeys(zone_name, policy_id); 04828 if (status != 0) { 04829 printf("Failed to Link Keys to zone\n"); 04830 ret = xmlTextReaderRead(reader); 04831 continue; 04832 }*/ 04833 } 04834 04835 /* make a note of the zone_id */ 04836 status = KsmZoneIdFromName(zone_name, &temp_id); 04837 if (status != 0) { 04838 printf("Error: unable to find a zone named \"%s\" in database\n", zone_name); 04839 printf("Error: Possibly two domains differ only by having a trailing dot or not?\n"); 04840 StrFree(zone_ids); 04841 return(status); 04842 } 04843 04844 /* We malloc'd this above */ 04845 zone_ids[i] = temp_id; 04846 i++; 04847 04848 StrFree(zone_name); 04849 StrFree(current_policy); 04850 StrFree(current_signconf); 04851 StrFree(current_input); 04852 StrFree(current_output); 04853 04854 new_zone = 0; 04855 04856 } 04857 /* Read the next line */ 04858 ret = xmlTextReaderRead(reader); 04859 StrFree(tag_name); 04860 } 04861 xmlFreeTextReader(reader); 04862 if (ret != 0) { 04863 printf("%s : failed to parse\n", zone_list_filename); 04864 } 04865 } else { 04866 printf("Unable to open %s\n", zone_list_filename); 04867 } 04868 if (doc) { 04869 xmlFreeDoc(doc); 04870 } 04871 StrFree(policy_name); 04872 04873 /* Now see how many zones are in the database */ 04874 sql = DqsCountInit(DB_ZONE_TABLE); 04875 DqsEnd(&sql); 04876 04877 /* Execute query and free up the query string */ 04878 status = DbIntQuery(DbHandle(), &db_zone_count, sql); 04879 DqsFree(sql); 04880 04881 /* If the 2 numbers match then our work is done */ 04882 if (file_zone_count == db_zone_count) { 04883 StrFree(zone_ids); 04884 return 0; 04885 } 04886 /* If the file count is larger then something went wrong */ 04887 else if (file_zone_count > db_zone_count) { 04888 printf("Failed to add all zones from zonelist\n"); 04889 StrFree(zone_ids); 04890 return(1); 04891 } 04892 04893 /* If we get here we need to do some deleting, get each zone in the db 04894 * and see if it is in the zone_list that we built earlier */ 04895 /* In case there are thousands of zones we don't use an "IN" clause*/ 04896 sql = DqsSpecifyInit(DB_ZONE_TABLE, "id, name, policy_id"); 04897 DqsOrderBy(&sql, "ID"); 04898 DqsEnd(&sql); 04899 04900 status = DbExecuteSql(DbHandle(), sql, &result); 04901 04902 if (status == 0) { 04903 status = DbFetchRow(result, &row); 04904 while (status == 0) { 04905 DbInt(row, 0, &temp_id); 04906 DbString(row, 1, &zone_name); 04907 DbInt(row, 2, &policy_id); 04908 04909 seen_zone = 0; 04910 for (i = 0; i < db_zone_count; ++i) { 04911 if (temp_id == zone_ids[i]) { 04912 seen_zone = 1; 04913 break; 04914 } 04915 } 04916 04917 if (seen_zone == 0) { 04918 /* We need to delete this zone */ 04919 /* Get the shared_keys parameter */ 04920 printf("Removing zone %s from database\n", zone_name); 04921 04922 status = KsmParameterInit(&result2, "zones_share_keys", "keys", policy_id); 04923 if (status != 0) { 04924 DbFreeRow(row); 04925 DbStringFree(zone_name); 04926 StrFree(zone_ids); 04927 return(status); 04928 } 04929 status = KsmParameter(result2, &shared); 04930 if (status != 0) { 04931 DbFreeRow(row); 04932 DbStringFree(zone_name); 04933 StrFree(zone_ids); 04934 return(status); 04935 } 04936 KsmParameterEnd(result2); 04937 04938 /* how many zones on this policy (needed to unlink keys) */ 04939 status = KsmZoneCountInit(&result3, policy_id); 04940 if (status == 0) { 04941 status = KsmZoneCount(result3, &temp_count); 04942 } 04943 DbFreeResult(result3); 04944 04945 /* Mark keys as dead if appropriate */ 04946 if ((shared.value == 1 && temp_count == 1) || shared.value == 0) { 04947 status = KsmMarkKeysAsDead(temp_id); 04948 if (status != 0) { 04949 printf("Error: failed to mark keys as dead in database\n"); 04950 StrFree(zone_ids); 04951 return(status); 04952 } 04953 } 04954 04955 /* Finally, we can delete the zone (and any dnsseckeys entries) */ 04956 status = KsmDeleteZone(temp_id); 04957 } 04958 04959 status = DbFetchRow(result, &row); 04960 } 04961 /* Convert EOF status to success */ 04962 04963 if (status == -1) { 04964 status = 0; 04965 } 04966 DbFreeResult(result); 04967 } 04968 04969 DusFree(sql); 04970 DbFreeRow(row); 04971 DbStringFree(zone_name); 04972 StrFree(zone_ids); 04973 04974 return 0; 04975 } 04976 04977 /* 04978 * This encapsulates all of the steps needed to insert/update a parameter value 04979 * try to update the policy value, if it has changed 04980 * TODO possible bug where parmeters which have a value of 0 are not written (because we 04981 * only write what looks like it has changed 04982 */ 04983 int SetParamOnPolicy(const xmlChar* new_value, const char* name, const char* category, int current_value, int policy_id, int value_type) 04984 { 04985 int status = 0; 04986 int value = 0; 04987 char* temp_char = (char *)new_value; 04988 04989 /* extract the value into an int */ 04990 if (value_type == DURATION_TYPE) { 04991 if (strlen(temp_char) != 0) { 04992 status = DtXMLIntervalSeconds(temp_char, &value); 04993 if (status > 0) { 04994 printf("Error: unable to convert interval %s to seconds, error: %i\n", temp_char, status); 04995 StrFree(temp_char); 04996 return status; 04997 } 04998 else if (status == -1) { 04999 printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char); 05000 } 05001 StrFree(temp_char); 05002 } else { 05003 value = -1; 05004 } 05005 } 05006 else if (value_type == BOOL_TYPE) { 05007 /* Do we have an empty tag or no tag? */ 05008 if (strncmp(temp_char, "Y", 1) == 0) { 05009 value = 1; 05010 } else { 05011 value = 0; 05012 } 05013 } 05014 else if (value_type == REPO_TYPE) { 05015 /* We need to convert the repository name into an id */ 05016 status = KsmSmIdFromName(temp_char, &value); 05017 if (status != 0) { 05018 printf("Error: unable to find repository %s\n", temp_char); 05019 StrFree(temp_char); 05020 return status; 05021 } 05022 StrFree(temp_char); 05023 } 05024 else if (value_type == SERIAL_TYPE) { 05025 /* We need to convert the serial name into an id */ 05026 status = KsmSerialIdFromName(temp_char, &value); 05027 if (status != 0) { 05028 printf("Error: unable to find serial type %s\n", temp_char); 05029 StrFree(temp_char); 05030 return status; 05031 } 05032 StrFree(temp_char); 05033 } 05034 else if (value_type == ROLLOVER_TYPE) { 05035 /* We need to convert the rollover scheme name into an id */ 05036 value = KsmKeywordRollNameToValue(temp_char); 05037 if (value == 0) { 05038 printf("Error: unable to find rollover scheme %s\n", temp_char); 05039 StrFree(temp_char); 05040 return status; 05041 } 05042 StrFree(temp_char); 05043 } 05044 else { 05045 status = StrStrtoi(temp_char, &value); 05046 if (status != 0) { 05047 printf("Error: unable to convert %s to int\n", temp_char); 05048 StrFree(temp_char); 05049 return status; 05050 } 05051 if (value_type != INT_TYPE_NO_FREE) { 05052 StrFree(temp_char); 05053 } 05054 } 05055 05056 /* Now update the policy with what we found, if it is different */ 05057 if (value != current_value || current_value == 0) { 05058 status = KsmParameterSet(name, category, value, policy_id); 05059 if (status != 0) { 05060 printf("Error: unable to insert/update %s for policy\n", name); 05061 printf("Error: Is your database schema up to date?\n"); 05062 return status; 05063 } 05064 05065 /* Special step if salt length changed make sure that the salt is 05066 regenerated when the enforcer runs next */ 05067 if (strncmp(name, "saltlength", 10) == 0) { 05068 status = KsmPolicyNullSaltStamp(policy_id); 05069 if (status != 0) { 05070 printf("Error: unable to insert/update %s for policy\n", name); 05071 printf("Error: Is your database schema up to date?\n"); 05072 return status; 05073 } 05074 } 05075 } 05076 05077 return 0; 05078 } 05079 05080 void SetPolicyDefaults(KSM_POLICY *policy, char *name) 05081 { 05082 if (policy == NULL) { 05083 printf("Error, no policy provided"); 05084 return; 05085 } 05086 05087 if (name) { 05088 snprintf(policy->name, KSM_NAME_LENGTH, "%s", name); 05089 } 05090 05091 policy->signer->refresh = 0; 05092 policy->signer->jitter = 0; 05093 policy->signer->propdelay = 0; 05094 policy->signer->soamin = 0; 05095 policy->signer->soattl = 0; 05096 policy->signer->serial = 0; 05097 05098 policy->signature->clockskew = 0; 05099 policy->signature->resign = 0; 05100 policy->signature->valdefault = 0; 05101 policy->signature->valdenial = 0; 05102 05103 policy->denial->version = 0; 05104 policy->denial->resalt = 0; 05105 policy->denial->algorithm = 0; 05106 policy->denial->iteration = 0; 05107 policy->denial->optout = 0; 05108 policy->denial->ttl = 0; 05109 policy->denial->saltlength = 0; 05110 05111 policy->keys->ttl = 0; 05112 policy->keys->retire_safety = 0; 05113 policy->keys->publish_safety = 0; 05114 policy->keys->share_keys = 0; 05115 policy->keys->purge = -1; 05116 05117 policy->ksk->algorithm = 0; 05118 policy->ksk->bits = 0; 05119 policy->ksk->lifetime = 0; 05120 policy->ksk->sm = 0; 05121 policy->ksk->overlap = 0; 05122 policy->ksk->ttl = 0; 05123 policy->ksk->rfc5011 = 0; 05124 policy->ksk->type = KSM_TYPE_KSK; 05125 policy->ksk->standby_keys = 0; 05126 policy->ksk->manual_rollover = 0; 05127 policy->ksk->rollover_scheme = KSM_ROLL_DEFAULT; 05128 05129 policy->zsk->algorithm = 0; 05130 policy->zsk->bits = 0; 05131 policy->zsk->lifetime = 0; 05132 policy->zsk->sm = 0; 05133 policy->zsk->overlap = 0; 05134 policy->zsk->ttl = 0; 05135 policy->zsk->rfc5011 = 0; 05136 policy->zsk->type = KSM_TYPE_ZSK; 05137 policy->zsk->standby_keys = 0; 05138 policy->zsk->manual_rollover = 0; 05139 policy->zsk->rollover_scheme = 0; 05140 05141 policy->enforcer->keycreate = 0; 05142 policy->enforcer->backup_interval = 0; 05143 policy->enforcer->keygeninterval = 0; 05144 05145 policy->zone->propdelay = 0; 05146 policy->zone->soa_ttl = 0; 05147 policy->zone->soa_min = 0; 05148 policy->zone->serial = 0; 05149 05150 policy->parent->propdelay = 0; 05151 policy->parent->ds_ttl = 0; 05152 policy->parent->soa_ttl = 0; 05153 policy->parent->soa_min = 0; 05154 05155 } 05156 05157 /* make a backup of a file 05158 * Returns 0 on success 05159 * 1 on error 05160 * -1 if it could read the original but not open the backup 05161 */ 05162 int backup_file(const char* orig_file, const char* backup_file) 05163 { 05164 FILE *from, *to; 05165 int ch; 05166 05167 errno = 0; 05168 /* open source file */ 05169 if((from = fopen( orig_file, "rb"))==NULL) { 05170 if (errno == ENOENT) { 05171 printf("File %s does not exist, nothing to backup\n", orig_file); 05172 return(0); 05173 } 05174 else { 05175 printf("Cannot open source file.\n"); 05176 return(1); /* No point in trying to connect */ 05177 } 05178 } 05179 05180 /* open destination file */ 05181 if((to = fopen(backup_file, "wb"))==NULL) { 05182 printf("Cannot open destination file, will not make backup.\n"); 05183 fclose(from); 05184 return(-1); 05185 } 05186 else { 05187 /* copy the file */ 05188 while(!feof(from)) { 05189 ch = fgetc(from); 05190 if(ferror(from)) { 05191 printf("Error reading source file.\n"); 05192 fclose(from); 05193 fclose(to); 05194 return(1); 05195 } 05196 if(!feof(from)) fputc(ch, to); 05197 if(ferror(to)) { 05198 printf("Error writing destination file.\n"); 05199 fclose(from); 05200 fclose(to); 05201 return(1); 05202 } 05203 } 05204 05205 if(fclose(from)==EOF) { 05206 printf("Error closing source file.\n"); 05207 fclose(to); 05208 return(1); 05209 } 05210 05211 if(fclose(to)==EOF) { 05212 printf("Error closing destination file.\n"); 05213 return(1); 05214 } 05215 } 05216 return(0); 05217 } 05218 05219 /* 05220 * Given a conf.xml location extract the database details contained within it 05221 * 05222 * The caller will need to StrFree the char**s passed in 05223 * 05224 * Returns 0 if a full set of details was found 05225 * 1 if something didn't look right 05226 * -1 if any of the config files could not be read/parsed 05227 * 05228 */ 05229 int 05230 get_db_details(char** dbschema, char** host, char** port, char** user, char** password) 05231 { 05232 /* All of the XML stuff */ 05233 xmlDocPtr doc; 05234 xmlDocPtr rngdoc; 05235 xmlXPathContextPtr xpathCtx; 05236 xmlXPathObjectPtr xpathObj; 05237 xmlRelaxNGParserCtxtPtr rngpctx; 05238 xmlRelaxNGValidCtxtPtr rngctx; 05239 xmlRelaxNGPtr schema; 05240 xmlChar *litexpr = (unsigned char*) "//Configuration/Enforcer/Datastore/SQLite"; 05241 xmlChar *mysql_host = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host"; 05242 xmlChar *mysql_port = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host/@port"; 05243 xmlChar *mysql_db = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Database"; 05244 xmlChar *mysql_user = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Username"; 05245 xmlChar *mysql_pass = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Password"; 05246 05247 int status; 05248 int db_found = 0; 05249 char* temp_char = NULL; 05250 05251 /* Some files, the xml and rng */ 05252 const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng"; 05253 05254 /* Load XML document */ 05255 doc = xmlParseFile(config); 05256 if (doc == NULL) { 05257 printf("Error: unable to parse file \"%s\"\n", config); 05258 return(-1); 05259 } 05260 05261 /* Load rng document: TODO make the rng stuff optional? */ 05262 rngdoc = xmlParseFile(rngfilename); 05263 if (rngdoc == NULL) { 05264 printf("Error: unable to parse file \"%s\"\n", rngfilename); 05265 xmlFreeDoc(doc); 05266 return(-1); 05267 } 05268 05269 /* Create an XML RelaxNGs parser context for the relax-ng document. */ 05270 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc); 05271 xmlFreeDoc(rngdoc); 05272 if (rngpctx == NULL) { 05273 printf("Error: unable to create XML RelaxNGs parser context\n"); 05274 xmlFreeDoc(doc); 05275 return(-1); 05276 } 05277 05278 /* parse a schema definition resource and build an internal XML Schema structure which can be used to validate instances. */ 05279 schema = xmlRelaxNGParse(rngpctx); 05280 xmlRelaxNGFreeParserCtxt(rngpctx); 05281 if (schema == NULL) { 05282 printf("Error: unable to parse a schema definition resource\n"); 05283 xmlFreeDoc(doc); 05284 return(-1); 05285 } 05286 05287 /* Create an XML RelaxNGs validation context based on the given schema */ 05288 rngctx = xmlRelaxNGNewValidCtxt(schema); 05289 if (rngctx == NULL) { 05290 printf("Error: unable to create RelaxNGs validation context based on the schema\n"); 05291 xmlRelaxNGFree(schema); 05292 xmlFreeDoc(doc); 05293 return(-1); 05294 } 05295 05296 /* Validate a document tree in memory. */ 05297 status = xmlRelaxNGValidateDoc(rngctx,doc); 05298 xmlRelaxNGFreeValidCtxt(rngctx); 05299 xmlRelaxNGFree(schema); 05300 if (status != 0) { 05301 printf("Error validating file \"%s\"\n", config); 05302 xmlFreeDoc(doc); 05303 return(-1); 05304 } 05305 05306 /* Now parse a value out of the conf */ 05307 /* Create xpath evaluation context */ 05308 xpathCtx = xmlXPathNewContext(doc); 05309 if(xpathCtx == NULL) { 05310 printf("Error: unable to create new XPath context\n"); 05311 xmlFreeDoc(doc); 05312 return(-1); 05313 } 05314 05315 /* Evaluate xpath expression for SQLite file location */ 05316 xpathObj = xmlXPathEvalExpression(litexpr, xpathCtx); 05317 if(xpathObj == NULL) { 05318 printf("Error: unable to evaluate xpath expression: %s\n", litexpr); 05319 xmlXPathFreeContext(xpathCtx); 05320 xmlFreeDoc(doc); 05321 return(-1); 05322 } 05323 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 05324 db_found = SQLITE_DB; 05325 temp_char = (char *)xmlXPathCastToString(xpathObj); 05326 StrAppend(dbschema, temp_char); 05327 StrFree(temp_char); 05328 fprintf(stderr, "SQLite database set to: %s\n", *dbschema); 05329 } 05330 xmlXPathFreeObject(xpathObj); 05331 05332 if (db_found == 0) { 05333 db_found = MYSQL_DB; 05334 05335 /* Get all of the MySQL stuff read in too */ 05336 /* HOST, optional */ 05337 xpathObj = xmlXPathEvalExpression(mysql_host, xpathCtx); 05338 if(xpathObj == NULL) { 05339 printf("Error: unable to evaluate xpath expression: %s\n", mysql_host); 05340 xmlXPathFreeContext(xpathCtx); 05341 xmlFreeDoc(doc); 05342 return(-1); 05343 } 05344 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 05345 temp_char = (char *)xmlXPathCastToString(xpathObj); 05346 StrAppend(host, temp_char); 05347 StrFree(temp_char); 05348 fprintf(stderr, "MySQL database host set to: %s\n", *host); 05349 } 05350 xmlXPathFreeObject(xpathObj); 05351 05352 /* PORT, optional */ 05353 xpathObj = xmlXPathEvalExpression(mysql_port, xpathCtx); 05354 if(xpathObj == NULL) { 05355 printf("Error: unable to evaluate xpath expression: %s\n", mysql_port); 05356 xmlXPathFreeContext(xpathCtx); 05357 xmlFreeDoc(doc); 05358 return(-1); 05359 } 05360 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 05361 temp_char = (char *)xmlXPathCastToString(xpathObj); 05362 StrAppend(port, temp_char); 05363 StrFree(temp_char); 05364 fprintf(stderr, "MySQL database port set to: %s\n", *port); 05365 } 05366 xmlXPathFreeObject(xpathObj); 05367 05368 /* SCHEMA */ 05369 xpathObj = xmlXPathEvalExpression(mysql_db, xpathCtx); 05370 if(xpathObj == NULL) { 05371 printf("Error: unable to evaluate xpath expression: %s\n", mysql_db); 05372 xmlXPathFreeContext(xpathCtx); 05373 xmlFreeDoc(doc); 05374 return(-1); 05375 } 05376 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 05377 temp_char = (char *)xmlXPathCastToString(xpathObj); 05378 StrAppend(dbschema, temp_char); 05379 StrFree(temp_char); 05380 fprintf(stderr, "MySQL database schema set to: %s\n", *dbschema); 05381 } else { 05382 db_found = 0; 05383 } 05384 xmlXPathFreeObject(xpathObj); 05385 05386 /* DB USER */ 05387 xpathObj = xmlXPathEvalExpression(mysql_user, xpathCtx); 05388 if(xpathObj == NULL) { 05389 printf("Error: unable to evaluate xpath expression: %s\n", mysql_user); 05390 xmlXPathFreeContext(xpathCtx); 05391 xmlFreeDoc(doc); 05392 return(-1); 05393 } 05394 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 05395 temp_char = (char *)xmlXPathCastToString(xpathObj); 05396 StrAppend(user, temp_char); 05397 StrFree(temp_char); 05398 fprintf(stderr, "MySQL database user set to: %s\n", *user); 05399 } else { 05400 db_found = 0; 05401 } 05402 xmlXPathFreeObject(xpathObj); 05403 05404 /* DB PASSWORD */ 05405 xpathObj = xmlXPathEvalExpression(mysql_pass, xpathCtx); 05406 if(xpathObj == NULL) { 05407 printf("Error: unable to evaluate xpath expression: %s\n", mysql_pass); 05408 xmlXPathFreeContext(xpathCtx); 05409 xmlFreeDoc(doc); 05410 return(-1); 05411 } 05412 /* password may be blank */ 05413 temp_char = (char *)xmlXPathCastToString(xpathObj); 05414 StrAppend(password, temp_char); 05415 StrFree(temp_char); 05416 xmlXPathFreeObject(xpathObj); 05417 05418 fprintf(stderr, "MySQL database password set\n"); 05419 05420 } 05421 05422 xmlXPathFreeContext(xpathCtx); 05423 xmlFreeDoc(doc); 05424 05425 /* Check that we found one or the other database */ 05426 if(db_found == 0) { 05427 printf("Error: unable to find complete database connection expression\n"); 05428 return(-1); 05429 } 05430 05431 /* Check that we found the right database type */ 05432 if (db_found != DbFlavour()) { 05433 printf("Error: database in config file does not match libksm\n"); 05434 return(-1); 05435 } 05436 05437 return(status); 05438 } 05439 05440 /* 05441 * Read the conf.xml file, we will not validate as that was done as we read the database. 05442 * Instead we just extract the RepositoryList into the database and also learn the 05443 * location of the zonelist. 05444 */ 05445 int read_zonelist_filename(char** zone_list_filename) 05446 { 05447 xmlTextReaderPtr reader = NULL; 05448 xmlDocPtr doc = NULL; 05449 xmlXPathContextPtr xpathCtx = NULL; 05450 xmlXPathObjectPtr xpathObj = NULL; 05451 int ret = 0; /* status of the XML parsing */ 05452 char* temp_char = NULL; 05453 char* tag_name = NULL; 05454 05455 xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile"; 05456 05457 /* Start reading the file; we will be looking for "Common" tags */ 05458 reader = xmlNewTextReaderFilename(config); 05459 if (reader != NULL) { 05460 ret = xmlTextReaderRead(reader); 05461 while (ret == 1) { 05462 tag_name = (char*) xmlTextReaderLocalName(reader); 05463 /* Found <Common> */ 05464 if (strncmp(tag_name, "Common", 6) == 0 05465 && xmlTextReaderNodeType(reader) == 1) { 05466 05467 /* Expand this node and get the rest of the info with XPath */ 05468 xmlTextReaderExpand(reader); 05469 doc = xmlTextReaderCurrentDoc(reader); 05470 if (doc == NULL) { 05471 printf("Error: can not read Common section\n"); 05472 /* Don't return? try to parse the rest of the file? */ 05473 ret = xmlTextReaderRead(reader); 05474 continue; 05475 } 05476 05477 xpathCtx = xmlXPathNewContext(doc); 05478 if(xpathCtx == NULL) { 05479 printf("Error: can not create XPath context for Common section\n"); 05480 /* Don't return? try to parse the rest of the file? */ 05481 ret = xmlTextReaderRead(reader); 05482 continue; 05483 } 05484 05485 /* Evaluate xpath expression for ZoneListFile */ 05486 xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx); 05487 if(xpathObj == NULL) { 05488 printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr); 05489 /* Don't return? try to parse the rest of the file? */ 05490 ret = xmlTextReaderRead(reader); 05491 continue; 05492 } 05493 *zone_list_filename = NULL; 05494 temp_char = (char *)xmlXPathCastToString(xpathObj); 05495 xmlXPathFreeObject(xpathObj); 05496 StrAppend(zone_list_filename, temp_char); 05497 StrFree(temp_char); 05498 printf("zonelist filename set to %s.\n", *zone_list_filename); 05499 } 05500 /* Read the next line */ 05501 ret = xmlTextReaderRead(reader); 05502 StrFree(tag_name); 05503 } 05504 xmlFreeTextReader(reader); 05505 if (ret != 0) { 05506 printf("%s : failed to parse\n", config); 05507 return(1); 05508 } 05509 } else { 05510 printf("Unable to open %s\n", config); 05511 return(1); 05512 } 05513 if (xpathCtx) { 05514 xmlXPathFreeContext(xpathCtx); 05515 } 05516 if (doc) { 05517 xmlFreeDoc(doc); 05518 } 05519 05520 return 0; 05521 } 05522 05523 xmlDocPtr add_zone_node(const char *docname, 05524 const char *zone_name, 05525 const char *policy_name, 05526 const char *sig_conf_name, 05527 const char *input_name, 05528 const char *output_name) 05529 { 05530 xmlDocPtr doc; 05531 xmlNodePtr cur; 05532 xmlNodePtr newzonenode; 05533 xmlNodePtr newadaptnode; 05534 xmlNodePtr newinputnode; 05535 xmlNodePtr newoutputnode; 05536 doc = xmlParseFile(docname); 05537 if (doc == NULL ) { 05538 fprintf(stderr,"Document not parsed successfully. \n"); 05539 return (NULL); 05540 } 05541 cur = xmlDocGetRootElement(doc); 05542 if (cur == NULL) { 05543 fprintf(stderr,"empty document\n"); 05544 xmlFreeDoc(doc); 05545 return (NULL); 05546 } 05547 if (xmlStrcmp(cur->name, (const xmlChar *) "ZoneList")) { 05548 fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList"); 05549 xmlFreeDoc(doc); 05550 return (NULL); 05551 } 05552 newzonenode = xmlNewTextChild(cur, NULL, (const xmlChar *)"Zone", NULL); 05553 (void) xmlNewProp(newzonenode, (const xmlChar *)"name", (const xmlChar *)zone_name); 05554 05555 (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"Policy", (const xmlChar *)policy_name); 05556 05557 (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)sig_conf_name); 05558 05559 newadaptnode = xmlNewChild (newzonenode, NULL, (const xmlChar *)"Adapters", NULL); 05560 05561 newinputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Input", NULL); 05562 05563 (void) xmlNewTextChild (newinputnode, NULL, (const xmlChar *)"File", (const xmlChar *)input_name); 05564 05565 newoutputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Output", NULL); 05566 05567 (void) xmlNewTextChild (newoutputnode, NULL, (const xmlChar *)"File", (const xmlChar *)output_name); 05568 05569 return(doc); 05570 } 05571 05572 xmlDocPtr del_zone_node(const char *docname, 05573 const char *zone_name) 05574 { 05575 xmlDocPtr doc; 05576 xmlNodePtr root; 05577 xmlNodePtr cur; 05578 05579 doc = xmlParseFile(docname); 05580 if (doc == NULL ) { 05581 fprintf(stderr,"Document not parsed successfully. \n"); 05582 return (NULL); 05583 } 05584 root = xmlDocGetRootElement(doc); 05585 if (root == NULL) { 05586 fprintf(stderr,"empty document\n"); 05587 xmlFreeDoc(doc); 05588 return (NULL); 05589 } 05590 if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) { 05591 fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList"); 05592 xmlFreeDoc(doc); 05593 return (NULL); 05594 } 05595 05596 /* If we are removing all zones then just replace the root node with an empty one */ 05597 if (all_flag == 1) { 05598 cur = root->children; 05599 while (cur != NULL) 05600 { 05601 xmlUnlinkNode(cur); 05602 xmlFreeNode(cur); 05603 05604 cur = root->children; 05605 } 05606 } 05607 else { 05608 05609 /* Zone nodes are children of the root */ 05610 for(cur = root->children; cur != NULL; cur = cur->next) 05611 { 05612 /* is this the zone we are looking for? */ 05613 if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) zone_name) == 0) 05614 { 05615 xmlUnlinkNode(cur); 05616 05617 cur = root->children; /* May pass through multiple times, but will remove all instances of the zone */ 05618 } 05619 } 05620 xmlFreeNode(cur); 05621 } 05622 05623 return(doc); 05624 } 05625 05626 void list_zone_node(const char *docname, int *zone_ids) 05627 { 05628 xmlDocPtr doc; 05629 xmlNodePtr root; 05630 xmlNodePtr cur; 05631 xmlNodePtr pol; 05632 xmlChar *polChar = NULL; 05633 xmlChar *propChar = NULL; 05634 05635 int temp_id; 05636 int i = 0; 05637 int status = 0; 05638 05639 doc = xmlParseFile(docname); 05640 if (doc == NULL ) { 05641 fprintf(stderr,"Document not parsed successfully. \n"); 05642 return; 05643 } 05644 root = xmlDocGetRootElement(doc); 05645 if (root == NULL) { 05646 fprintf(stderr,"empty document\n"); 05647 xmlFreeDoc(doc); 05648 return; 05649 } 05650 if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) { 05651 fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList"); 05652 xmlFreeDoc(doc); 05653 return; 05654 } 05655 05656 /* Zone nodes are children of the root */ 05657 for(cur = root->children; cur != NULL; cur = cur->next) 05658 { 05659 if (xmlStrcmp( cur->name, (const xmlChar *)"Zone") == 0) { 05660 propChar = xmlGetProp(cur, (xmlChar *) "name"); 05661 printf("Found Zone: %s", propChar); 05662 05663 /* make a note of the zone_id */ 05664 status = KsmZoneIdFromName((char *) propChar, &temp_id); 05665 xmlFree(propChar); 05666 if (status != 0) { 05667 printf(" (zone not in database)"); 05668 zone_ids[i] = 0; 05669 } else { 05670 zone_ids[i] = temp_id; 05671 i++; 05672 } 05673 05674 /* Print the policy name for this zone */ 05675 for(pol = cur->children; pol != NULL; pol = pol->next) 05676 { 05677 if (xmlStrcmp( pol->name, (const xmlChar *)"Policy") == 0) 05678 { 05679 polChar = xmlNodeGetContent(pol); 05680 printf("; on policy %s\n", polChar); 05681 xmlFree(polChar); 05682 } 05683 } 05684 } 05685 } 05686 05687 xmlFreeDoc(doc); 05688 05689 return; 05690 } 05691 05692 /* 05693 * Given a doc that has the start of the kasp-like xml and a policy structure 05694 * create the policy tag and contents in that doc 05695 */ 05696 int append_policy(xmlDocPtr doc, KSM_POLICY *policy) 05697 { 05698 xmlNodePtr root; 05699 xmlNodePtr policy_node; 05700 xmlNodePtr signatures_node; 05701 xmlNodePtr validity_node; 05702 xmlNodePtr denial_node; 05703 xmlNodePtr nsec_node; 05704 xmlNodePtr hash_node; 05705 xmlNodePtr salt_node; 05706 xmlNodePtr keys_node; 05707 xmlNodePtr ksk_node; 05708 xmlNodePtr ksk_alg_node; 05709 xmlNodePtr zsk_node; 05710 xmlNodePtr zsk_alg_node; 05711 xmlNodePtr zone_node; 05712 xmlNodePtr zone_soa_node; 05713 xmlNodePtr parent_node; 05714 xmlNodePtr parent_ds_node; 05715 xmlNodePtr parent_soa_node; 05716 05717 char temp_time[32]; 05718 05719 root = xmlDocGetRootElement(doc); 05720 if (root == NULL) { 05721 fprintf(stderr,"empty document\n"); 05722 return(1); 05723 } 05724 if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) { 05725 fprintf(stderr,"document of the wrong type, root node != %s", "KASP"); 05726 return(1); 05727 } 05728 05729 policy_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Policy", NULL); 05730 (void) xmlNewProp(policy_node, (const xmlChar *)"name", (const xmlChar *)policy->name); 05731 (void) xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Description", (const xmlChar *)policy->description); 05732 05733 /* SIGNATURES */ 05734 signatures_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Signatures", NULL); 05735 snprintf(temp_time, 32, "PT%dS", policy->signature->resign); 05736 (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Resign", (const xmlChar *)temp_time); 05737 snprintf(temp_time, 32, "PT%dS", policy->signer->refresh); 05738 (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Refresh", (const xmlChar *)temp_time); 05739 validity_node = xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Validity", NULL); 05740 snprintf(temp_time, 32, "PT%dS", policy->signature->valdefault); 05741 (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Default", (const xmlChar *)temp_time); 05742 snprintf(temp_time, 32, "PT%dS", policy->signature->valdenial); 05743 (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Denial", (const xmlChar *)temp_time); 05744 snprintf(temp_time, 32, "PT%dS", policy->signer->jitter); 05745 (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Jitter", (const xmlChar *)temp_time); 05746 snprintf(temp_time, 32, "PT%dS", policy->signature->clockskew); 05747 (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"InceptionOffset", (const xmlChar *)temp_time); 05748 05749 /* DENIAL */ 05750 denial_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Denial", NULL); 05751 if (policy->denial->version == 1) /* NSEC */ 05752 { 05753 (void) xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC", NULL); 05754 } 05755 else /* NSEC3 */ 05756 { 05757 nsec_node = xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC3", NULL); 05758 if (policy->denial->optout == 1) 05759 { 05760 (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"OptOut", NULL); 05761 } 05762 snprintf(temp_time, 32, "PT%dS", policy->denial->resalt); 05763 (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Resalt", (const xmlChar *)temp_time); 05764 hash_node = xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Hash", NULL); 05765 snprintf(temp_time, 32, "%d", policy->denial->algorithm); 05766 (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time); 05767 snprintf(temp_time, 32, "%d", policy->denial->iteration); 05768 (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Iteration", (const xmlChar *)temp_time); 05769 snprintf(temp_time, 32, "%d", policy->denial->saltlength); 05770 salt_node = xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Salt", NULL); 05771 (void) xmlNewProp(salt_node, (const xmlChar *)"length", (const xmlChar *)temp_time); 05772 } 05773 05774 /* KEYS */ 05775 keys_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Keys", NULL); 05776 snprintf(temp_time, 32, "PT%dS", policy->keys->ttl); 05777 (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time); 05778 snprintf(temp_time, 32, "PT%dS", policy->keys->retire_safety); 05779 (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"RetireSafety", (const xmlChar *)temp_time); 05780 snprintf(temp_time, 32, "PT%dS", policy->keys->publish_safety); 05781 (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"PublishSafety", (const xmlChar *)temp_time); 05782 if (policy->keys->share_keys == 1) 05783 { 05784 (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ShareKeys", NULL); 05785 } 05786 if (policy->keys->purge != -1) { 05787 snprintf(temp_time, 32, "PT%dS", policy->keys->purge); 05788 (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"Purge", (const xmlChar *)temp_time); 05789 } 05790 /*(void) xmlNewDocComment(doc, (const xmlChar *)"Parameters that are different for zsks and ksks");*/ 05791 /* KSK */ 05792 ksk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"KSK", NULL); 05793 snprintf(temp_time, 32, "%d", policy->ksk->algorithm); 05794 ksk_alg_node = xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time); 05795 snprintf(temp_time, 32, "%d", policy->ksk->bits); 05796 (void) xmlNewProp(ksk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time); 05797 snprintf(temp_time, 32, "PT%dS", policy->ksk->lifetime); 05798 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time); 05799 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->ksk->sm_name); 05800 snprintf(temp_time, 32, "%d", policy->ksk->standby_keys); 05801 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time); 05802 if (policy->ksk->manual_rollover == 1) 05803 { 05804 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"ManualRollover", NULL); 05805 } 05806 if (policy->ksk->rfc5011 == 1) 05807 { 05808 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RFC5011", NULL); 05809 } 05810 /* if (policy->ksk->rollover_scheme != 0) 05811 { 05812 (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RolloverScheme", (const xmlChar *) KsmKeywordRollValueToName(policy->ksk->rollover_scheme)); 05813 }*/ 05814 05815 /* ZSK */ 05816 zsk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ZSK", NULL); 05817 snprintf(temp_time, 32, "%d", policy->zsk->algorithm); 05818 zsk_alg_node = xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time); 05819 snprintf(temp_time, 32, "%d", policy->zsk->bits); 05820 (void) xmlNewProp(zsk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time); 05821 snprintf(temp_time, 32, "PT%dS", policy->zsk->lifetime); 05822 (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time); 05823 (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->zsk->sm_name); 05824 snprintf(temp_time, 32, "%d", policy->zsk->standby_keys); 05825 (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time); 05826 if (policy->zsk->manual_rollover == 1) 05827 { 05828 (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"ManualRollover", NULL); 05829 } 05830 05831 /* ZONE */ 05832 zone_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Zone", NULL); 05833 snprintf(temp_time, 32, "PT%dS", policy->zone->propdelay); 05834 (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time); 05835 zone_soa_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SOA", NULL); 05836 snprintf(temp_time, 32, "PT%dS", policy->zone->soa_ttl); 05837 (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time); 05838 snprintf(temp_time, 32, "PT%dS", policy->zone->soa_min); 05839 (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time); 05840 (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Serial", (const xmlChar *) KsmKeywordSerialValueToName(policy->zone->serial)); 05841 05842 /* PARENT */ 05843 parent_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Parent", NULL); 05844 snprintf(temp_time, 32, "PT%dS", policy->parent->propdelay); 05845 (void) xmlNewTextChild(parent_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time); 05846 parent_ds_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"DS", NULL); 05847 snprintf(temp_time, 32, "PT%dS", policy->parent->ds_ttl); 05848 (void) xmlNewTextChild(parent_ds_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time); 05849 parent_soa_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"SOA", NULL); 05850 snprintf(temp_time, 32, "PT%dS", policy->parent->soa_ttl); 05851 (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time); 05852 snprintf(temp_time, 32, "PT%dS", policy->parent->soa_min); 05853 (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time); 05854 05855 /* AUDIT (Currently this either exists and is empty or it doesn't) */ 05856 if (strncmp(policy->audit, "NULL", 4) != 0) { 05857 (void) xmlNewChild(policy_node, NULL, (const xmlChar *)"Audit", NULL); 05858 } 05859 05860 return(0); 05861 } 05862 05863 /* 05864 * Delete a policy node from kasp.xml 05865 */ 05866 xmlDocPtr del_policy_node(const char *docname, 05867 const char *policy_name) 05868 { 05869 xmlDocPtr doc; 05870 xmlNodePtr root; 05871 xmlNodePtr cur; 05872 05873 doc = xmlParseFile(docname); 05874 if (doc == NULL ) { 05875 fprintf(stderr,"Document not parsed successfully. \n"); 05876 return (NULL); 05877 } 05878 root = xmlDocGetRootElement(doc); 05879 if (root == NULL) { 05880 fprintf(stderr,"empty document\n"); 05881 xmlFreeDoc(doc); 05882 return (NULL); 05883 } 05884 if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) { 05885 fprintf(stderr,"document of the wrong type, root node != %s", "KASP"); 05886 xmlFreeDoc(doc); 05887 return (NULL); 05888 } 05889 05890 05891 /* Policy nodes are children of the root */ 05892 for(cur = root->children; cur != NULL; cur = cur->next) 05893 { 05894 /* is this the zone we are looking for? */ 05895 if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) policy_name) == 0) 05896 { 05897 xmlUnlinkNode(cur); 05898 05899 cur = root->children; /* May pass through multiple times, but will remove all instances of the policy */ 05900 } 05901 } 05902 xmlFreeNode(cur); 05903 05904 return(doc); 05905 } 05906 05907 /* 05908 * CallBack to print key info to stdout 05909 */ 05910 int printKey(void* context, KSM_KEYDATA* key_data) 05911 { 05912 if (key_data->state == KSM_STATE_RETIRE && strcasecmp(key_data->retire, (char *)context) == 0) { 05913 if (key_data->keytype == KSM_TYPE_KSK) 05914 { 05915 fprintf(stdout, "KSK:"); 05916 } 05917 if (key_data->keytype == KSM_TYPE_ZSK) 05918 { 05919 fprintf(stdout, "ZSK:"); 05920 } 05921 fprintf(stdout, " %s Retired\n", key_data->location); 05922 } 05923 05924 return 0; 05925 } 05926 05927 /* 05928 * log function suitable for libksm callback 05929 */ 05930 void 05931 ksm_log_msg(const char *format) 05932 { 05933 fprintf(stderr, "%s\n", format); 05934 } 05935 05936 /*+ 05937 * ListKeys - Output a list of Keys 05938 * 05939 * 05940 * Arguments: 05941 * 05942 * int zone_id 05943 * ID of the zone (-1 for all) 05944 * 05945 * Returns: 05946 * int 05947 * Status return. 0 on success. 05948 * other on fail 05949 */ 05950 05951 int ListKeys(int zone_id) 05952 { 05953 char* sql = NULL; /* SQL query */ 05954 int status = 0; /* Status return */ 05955 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 05956 DB_RESULT result; /* Result of the query */ 05957 DB_ROW row = NULL; /* Row data */ 05958 int done_row = 0; /* Have we printed a row this loop? */ 05959 05960 char* temp_zone = NULL; /* place to store zone name returned */ 05961 int temp_type = 0; /* place to store key type returned */ 05962 int temp_state = 0; /* place to store key state returned */ 05963 char* temp_ready = NULL; /* place to store ready date returned */ 05964 char* temp_active = NULL; /* place to store active date returned */ 05965 char* temp_retire = NULL; /* place to store retire date returned */ 05966 char* temp_dead = NULL; /* place to store dead date returned */ 05967 char* temp_loc = NULL; /* place to store location returned */ 05968 char* temp_hsm = NULL; /* place to store hsm returned */ 05969 int temp_alg = 0; /* place to store algorithm returned */ 05970 05971 /* Key information */ 05972 hsm_key_t *key = NULL; 05973 ldns_rr *dnskey_rr = NULL; 05974 hsm_sign_params_t *sign_params = NULL; 05975 05976 if (verbose_flag) { 05977 /* connect to the HSM */ 05978 status = hsm_open(config, hsm_prompt_pin, NULL); 05979 if (status) { 05980 hsm_print_error(NULL); 05981 return(-1); 05982 } 05983 } 05984 05985 /* Select rows */ 05986 StrAppend(&sql, "select z.name, k.keytype, k.state, k.ready, k.active, k.retire, k.dead, k.location, s.name, k.algorithm from securitymodules s, zones z, KEYDATA_VIEW k where z.id = k.zone_id and s.id = k.securitymodule_id and state != 6 and zone_id is not null "); 05987 if (zone_id != -1) { 05988 StrAppend(&sql, "and zone_id = "); 05989 snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id); 05990 StrAppend(&sql, stringval); 05991 } 05992 StrAppend(&sql, " order by zone_id"); 05993 05994 DusEnd(&sql); 05995 05996 status = DbExecuteSql(DbHandle(), sql, &result); 05997 05998 if (status == 0) { 05999 status = DbFetchRow(result, &row); 06000 if (verbose_flag == 1) { 06001 printf("Zone: Keytype: State: Date of next transition: CKA_ID: Repository: Keytag:\n"); 06002 } 06003 else { 06004 printf("Zone: Keytype: State: Date of next transition:\n"); 06005 } 06006 while (status == 0) { 06007 /* Got a row, print it */ 06008 DbString(row, 0, &temp_zone); 06009 DbInt(row, 1, &temp_type); 06010 DbInt(row, 2, &temp_state); 06011 DbString(row, 3, &temp_ready); 06012 DbString(row, 4, &temp_active); 06013 DbString(row, 5, &temp_retire); 06014 DbString(row, 6, &temp_dead); 06015 DbString(row, 7, &temp_loc); 06016 DbString(row, 8, &temp_hsm); 06017 DbInt(row, 9, &temp_alg); 06018 done_row = 0; 06019 06020 if (temp_state == KSM_STATE_PUBLISH) { 06021 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready); 06022 done_row = 1; 06023 } 06024 else if (temp_state == KSM_STATE_READY) { 06025 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_type == KSM_TYPE_KSK) ? "waiting for ds-seen" : "next rollover"); 06026 done_row = 1; 06027 } 06028 else if (temp_state == KSM_STATE_ACTIVE) { 06029 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_retire == NULL) ? "(not scheduled)" : temp_retire); 06030 done_row = 1; 06031 } 06032 else if (temp_state == KSM_STATE_RETIRE) { 06033 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_dead == NULL) ? "(not scheduled)" : temp_dead); 06034 done_row = 1; 06035 } 06036 else if (temp_state == KSM_STATE_DSSUB) { 06037 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "waiting for ds-seen"); 06038 done_row = 1; 06039 } 06040 else if (temp_state == KSM_STATE_DSPUBLISH) { 06041 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready); 06042 done_row = 1; 06043 } 06044 else if (temp_state == KSM_STATE_DSREADY) { 06045 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "When required"); 06046 done_row = 1; 06047 } 06048 else if (temp_state == KSM_STATE_KEYPUBLISH) { 06049 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_active == NULL) ? "(not scheduled)" : temp_active); 06050 done_row = 1; 06051 } 06052 06053 if (done_row == 1 && verbose_flag == 1) { 06054 key = hsm_find_key_by_id(NULL, temp_loc); 06055 if (!key) { 06056 printf("%-33s %s NOT IN repository\n", temp_loc, temp_hsm); 06057 } else { 06058 sign_params = hsm_sign_params_new(); 06059 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, temp_zone); 06060 sign_params->algorithm = temp_alg; 06061 sign_params->flags = LDNS_KEY_ZONE_KEY; 06062 if (temp_type == KSM_TYPE_KSK) { 06063 sign_params->flags += LDNS_KEY_SEP_KEY; 06064 } 06065 dnskey_rr = hsm_get_dnskey(NULL, key, sign_params); 06066 sign_params->keytag = ldns_calc_keytag(dnskey_rr); 06067 06068 printf("%-33s %-33s %d\n", temp_loc, temp_hsm, sign_params->keytag); 06069 06070 hsm_sign_params_free(sign_params); 06071 hsm_key_free(key); 06072 } 06073 } 06074 else if (done_row == 1) { 06075 printf("\n"); 06076 } 06077 06078 status = DbFetchRow(result, &row); 06079 } 06080 06081 /* Convert EOF status to success */ 06082 06083 if (status == -1) { 06084 status = 0; 06085 } 06086 06087 DbFreeResult(result); 06088 } 06089 06090 DusFree(sql); 06091 DbFreeRow(row); 06092 06093 DbStringFree(temp_zone); 06094 DbStringFree(temp_ready); 06095 DbStringFree(temp_active); 06096 DbStringFree(temp_retire); 06097 DbStringFree(temp_dead); 06098 DbStringFree(temp_loc); 06099 DbStringFree(temp_hsm); 06100 06101 if (dnskey_rr != NULL) { 06102 ldns_rr_free(dnskey_rr); 06103 } 06104 06105 return status; 06106 } 06107 06108 /*+ 06109 * PurgeKeys - Purge dead Keys 06110 * 06111 * 06112 * Arguments: 06113 * 06114 * int zone_id 06115 * ID of the zone 06116 * 06117 * int policy_id 06118 * ID of the policy 06119 * 06120 * N.B. Only one of the arguments should be set, the other should be -1 06121 * 06122 * Returns: 06123 * int 06124 * Status return. 0 on success. 06125 * other on fail 06126 */ 06127 06128 int PurgeKeys(int zone_id, int policy_id) 06129 { 06130 char* sql = NULL; /* SQL query */ 06131 char* sql1 = NULL; /* SQL query */ 06132 char* sql2 = NULL; /* SQL query */ 06133 char* sql3 = NULL; /* SQL query */ 06134 int status = 0; /* Status return */ 06135 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 06136 DB_RESULT result; /* Result of the query */ 06137 DB_ROW row = NULL; /* Row data */ 06138 06139 int temp_id = -1; /* place to store the key id returned */ 06140 char* temp_loc = NULL; /* place to store location returned */ 06141 int count = 0; /* How many keys don't match the purge */ 06142 06143 int done_something = 0; /* have we done anything? */ 06144 06145 /* Key information */ 06146 hsm_key_t *key = NULL; 06147 06148 if ((zone_id == -1 && policy_id == -1) || 06149 (zone_id != -1 && policy_id != -1)){ 06150 printf("Please provide either a zone OR a policy to key purge\n"); 06151 usage_keypurge(); 06152 return(1); 06153 } 06154 06155 /* connect to the HSM */ 06156 status = hsm_open(config, hsm_prompt_pin, NULL); 06157 if (status) { 06158 hsm_print_error(NULL); 06159 return(-1); 06160 } 06161 06162 /* Select rows */ 06163 StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 "); 06164 if (zone_id != -1) { 06165 StrAppend(&sql, "and zone_id = "); 06166 snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id); 06167 StrAppend(&sql, stringval); 06168 } 06169 if (policy_id != -1) { 06170 StrAppend(&sql, "and policy_id = "); 06171 snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id); 06172 StrAppend(&sql, stringval); 06173 } 06174 DusEnd(&sql); 06175 06176 status = DbExecuteSql(DbHandle(), sql, &result); 06177 06178 if (status == 0) { 06179 status = DbFetchRow(result, &row); 06180 while (status == 0) { 06181 /* Got a row, check it */ 06182 DbInt(row, 0, &temp_id); 06183 DbString(row, 1, &temp_loc); 06184 06185 sql1 = DqsCountInit("dnsseckeys"); 06186 DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 06187 DdsConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1); 06188 DqsEnd(&sql1); 06189 06190 status = DbIntQuery(DbHandle(), &count, sql1); 06191 DqsFree(sql1); 06192 06193 if (status != 0) { 06194 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 06195 DbStringFree(temp_loc); 06196 DbFreeRow(row); 06197 return status; 06198 } 06199 06200 /* If the count is zero then there is no reason not to purge this key */ 06201 if (count == 0) { 06202 06203 done_something = 1; 06204 06205 /* Delete from dnsseckeys */ 06206 sql2 = DdsInit("dnsseckeys"); 06207 DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 06208 DdsEnd(&sql); 06209 06210 status = DbExecuteSqlNoResult(DbHandle(), sql2); 06211 DdsFree(sql2); 06212 if (status != 0) 06213 { 06214 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 06215 DbStringFree(temp_loc); 06216 DbFreeRow(row); 06217 return status; 06218 } 06219 06220 /* Delete from keypairs */ 06221 sql3 = DdsInit("keypairs"); 06222 DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0); 06223 DdsEnd(&sql); 06224 06225 status = DbExecuteSqlNoResult(DbHandle(), sql3); 06226 DdsFree(sql3); 06227 if (status != 0) 06228 { 06229 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 06230 DbStringFree(temp_loc); 06231 DbFreeRow(row); 06232 return status; 06233 } 06234 06235 /* Delete from the HSM */ 06236 key = hsm_find_key_by_id(NULL, temp_loc); 06237 06238 if (!key) { 06239 printf("Key not found: %s\n", temp_loc); 06240 DbStringFree(temp_loc); 06241 DbFreeRow(row); 06242 return -1; 06243 } 06244 06245 status = hsm_remove_key(NULL, key); 06246 06247 hsm_key_free(key); 06248 06249 if (!status) { 06250 printf("Key remove successful.\n"); 06251 } else { 06252 printf("Key remove failed.\n"); 06253 DbStringFree(temp_loc); 06254 DbFreeRow(row); 06255 return -1; 06256 } 06257 } 06258 06259 /* NEXT! */ 06260 status = DbFetchRow(result, &row); 06261 } 06262 06263 /* Convert EOF status to success */ 06264 06265 if (status == -1) { 06266 status = 0; 06267 } 06268 06269 DbFreeResult(result); 06270 } 06271 06272 if (done_something == 0) { 06273 printf("No keys to purge.\n"); 06274 } 06275 06276 DusFree(sql); 06277 DbFreeRow(row); 06278 06279 DbStringFree(temp_loc); 06280 06281 return status; 06282 } 06283 06284 int cmd_genkeys() 06285 { 06286 int status = 0; 06287 06288 int interval = -1; 06289 06290 KSM_POLICY* policy; 06291 hsm_ctx_t *ctx = NULL; 06292 06293 char *rightnow; 06294 int i = 0; 06295 char *id; 06296 hsm_key_t *key = NULL; 06297 char *hsm_error_message = NULL; 06298 DB_ID ignore = 0; 06299 int ksks_needed = 0; /* Total No of ksks needed before next generation run */ 06300 int zsks_needed = 0; /* Total No of zsks needed before next generation run */ 06301 int keys_in_queue = 0; /* number of unused keys */ 06302 int new_keys = 0; /* number of keys required */ 06303 unsigned int current_count = 0; /* number of keys already in HSM */ 06304 06305 DB_RESULT result; 06306 int zone_count = 0; /* Number of zones on policy */ 06307 06308 int same_keys = 0; /* Do ksks and zsks look the same ? */ 06309 int ksks_created = 0; /* Were any KSKs created? */ 06310 06311 /* Database connection details */ 06312 DB_HANDLE dbhandle; 06313 FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ 06314 06315 /* try to connect to the database */ 06316 status = db_connect(&dbhandle, &lock_fd, 1); 06317 if (status != 0) { 06318 printf("Failed to connect to database\n"); 06319 db_disconnect(lock_fd); 06320 return(1); 06321 } 06322 06323 policy = KsmPolicyAlloc(); 06324 if (policy == NULL) { 06325 printf("Malloc for policy struct failed\n"); 06326 db_disconnect(lock_fd); 06327 exit(1); 06328 } 06329 06330 if (o_policy == NULL) { 06331 printf("Please provide a policy name with the --policy option\n"); 06332 db_disconnect(lock_fd); 06333 KsmPolicyFree(policy); 06334 return(1); 06335 } 06336 if (o_interval == NULL) { 06337 printf("Please provide an interval with the --interval option\n"); 06338 db_disconnect(lock_fd); 06339 KsmPolicyFree(policy); 06340 return(1); 06341 } 06342 06343 SetPolicyDefaults(policy, o_policy); 06344 06345 status = KsmPolicyExists(o_policy); 06346 if (status == 0) { 06347 /* Policy exists */ 06348 status = KsmPolicyRead(policy); 06349 if(status != 0) { 06350 printf("Error: unable to read policy %s from database\n", o_policy); 06351 db_disconnect(lock_fd); 06352 KsmPolicyFree(policy); 06353 return status; 06354 } 06355 } else { 06356 printf("Error: policy %s doesn't exist in database\n", o_policy); 06357 db_disconnect(lock_fd); 06358 KsmPolicyFree(policy); 06359 return status; 06360 } 06361 06362 if (policy->shared_keys == 1 ) { 06363 printf("Key sharing is On\n"); 06364 } else { 06365 printf("Key sharing is Off\n"); 06366 } 06367 06368 status = DtXMLIntervalSeconds(o_interval, &interval); 06369 if (status > 0) { 06370 printf("Error: unable to convert Interval %s to seconds, error: ", o_interval); 06371 switch (status) { 06372 case 1: /* This has gone away, will now return 2 */ 06373 printf("invalid interval-type.\n"); 06374 break; 06375 case 2: 06376 printf("unable to translate string.\n"); 06377 break; 06378 case 3: 06379 printf("interval too long to be an int. E.g. Maximum is ~68 years on a system with 32-bit integers.\n"); 06380 break; 06381 case 4: 06382 printf("invalid pointers or text string NULL.\n"); 06383 break; 06384 default: 06385 printf("unknown\n"); 06386 } 06387 db_disconnect(lock_fd); 06388 KsmPolicyFree(policy); 06389 return status; 06390 } 06391 else if (status == -1) { 06392 printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", o_interval); 06393 } 06394 06395 /* Connect to the hsm */ 06396 status = hsm_open(config, hsm_prompt_pin, NULL); 06397 if (status) { 06398 hsm_error_message = hsm_get_error(ctx); 06399 if (hsm_error_message) { 06400 printf("%s\n", hsm_error_message); 06401 free(hsm_error_message); 06402 } else { 06403 /* decode the error code ourselves 06404 TODO find if there is a better way to do this (and can all of these be returned? are there others?) */ 06405 switch (status) { 06406 case HSM_ERROR: 06407 printf("hsm_open() result: HSM error\n"); 06408 break; 06409 case HSM_PIN_INCORRECT: 06410 printf("hsm_open() result: incorrect PIN\n"); 06411 break; 06412 case HSM_CONFIG_FILE_ERROR: 06413 printf("hsm_open() result: config file error\n"); 06414 break; 06415 case HSM_REPOSITORY_NOT_FOUND: 06416 printf("hsm_open() result: repository not found\n"); 06417 break; 06418 case HSM_NO_REPOSITORIES: 06419 printf("hsm_open() result: no repositories\n"); 06420 break; 06421 default: 06422 printf("hsm_open() result: %d", status); 06423 } 06424 } 06425 db_disconnect(lock_fd); 06426 KsmPolicyFree(policy); 06427 exit(1); 06428 } 06429 printf("HSM opened successfully.\n"); 06430 ctx = hsm_create_context(); 06431 06432 rightnow = DtParseDateTimeString("now"); 06433 06434 /* Check datetime in case it came back NULL */ 06435 if (rightnow == NULL) { 06436 printf("Couldn't turn \"now\" into a date, quitting...\n"); 06437 db_disconnect(lock_fd); 06438 KsmPolicyFree(policy); 06439 exit(1); 06440 } 06441 06442 if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) { 06443 same_keys = 1; 06444 } else { 06445 same_keys = 0; 06446 } 06447 06448 /* How many zones on this policy */ 06449 status = KsmZoneCountInit(&result, policy->id); 06450 if (status == 0) { 06451 status = KsmZoneCount(result, &zone_count); 06452 } 06453 DbFreeResult(result); 06454 06455 if (status == 0) { 06456 /* make sure that we have at least one zone */ 06457 if (zone_count == 0) { 06458 printf("No zones on policy %s, skipping...", policy->name); 06459 db_disconnect(lock_fd); 06460 if (ctx) { 06461 hsm_destroy_context(ctx); 06462 } 06463 hsm_close(); 06464 KsmPolicyFree(policy); 06465 return status; 06466 } 06467 } else { 06468 printf("Could not count zones on policy %s", policy->name); 06469 db_disconnect(lock_fd); 06470 if (ctx) { 06471 hsm_destroy_context(ctx); 06472 } 06473 hsm_close(); 06474 KsmPolicyFree(policy); 06475 return status; 06476 } 06477 06478 /* Find out how many ksk keys are needed for the POLICY */ 06479 status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count); 06480 if (status != 0) { 06481 printf("Could not predict ksk requirement for next interval for %s\n", policy->name); 06482 /* TODO exit? continue with next policy? */ 06483 } 06484 /* Find out how many suitable keys we have */ 06485 status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_KSK); 06486 if (status != 0) { 06487 printf("Could not count current ksk numbers for policy %s\n", policy->name); 06488 /* TODO exit? continue with next policy? */ 06489 } 06490 /* Correct for shared keys */ 06491 if (policy->shared_keys == KSM_KEYS_SHARED) { 06492 keys_in_queue /= zone_count; 06493 } 06494 06495 new_keys = ksks_needed - keys_in_queue; 06496 /* fprintf(stderr, "keygen(ksk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, ksks_needed, keys_in_queue); */ 06497 06498 /* Check capacity of HSM will not be exceeded */ 06499 if (policy->ksk->sm_capacity != 0 && new_keys > 0) { 06500 current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name); 06501 if (current_count >= policy->ksk->sm_capacity) { 06502 printf("Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name); 06503 new_keys = 0; 06504 } 06505 else if (current_count + new_keys > policy->ksk->sm_capacity) { 06506 printf("Repository %s is nearly full, will create %lu KSKs for policy %s (reduced from %d)\n", policy->ksk->sm_name, policy->ksk->sm_capacity - current_count, policy->name, new_keys); 06507 new_keys = policy->ksk->sm_capacity - current_count; 06508 } 06509 } 06510 06511 /* Create the required keys */ 06512 for (i=new_keys ; i > 0 ; i--){ 06513 if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) { 06514 /* NOTE: for now we know that libhsm only supports RSA keys */ 06515 key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits); 06516 if (key) { 06517 if (verbose_flag) { 06518 printf("Created key in repository %s\n", policy->ksk->sm_name); 06519 } 06520 } else { 06521 printf("Error creating key in repository %s\n", policy->ksk->sm_name); 06522 hsm_error_message = hsm_get_error(ctx); 06523 if (hsm_error_message) { 06524 printf("%s\n", hsm_error_message); 06525 free(hsm_error_message); 06526 } 06527 db_disconnect(lock_fd); 06528 KsmPolicyFree(policy); 06529 exit(1); 06530 } 06531 id = hsm_get_key_id(ctx, key); 06532 hsm_key_free(key); 06533 status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore); 06534 if (status != 0) { 06535 printf("Error creating key in Database\n"); 06536 hsm_error_message = hsm_get_error(ctx); 06537 if (hsm_error_message) { 06538 printf("%s\n", hsm_error_message); 06539 free(hsm_error_message); 06540 } 06541 db_disconnect(lock_fd); 06542 KsmPolicyFree(policy); 06543 exit(1); 06544 } 06545 printf("Created KSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->ksk->bits, 06546 policy->ksk->algorithm, id, policy->ksk->sm_name); 06547 free(id); 06548 } else { 06549 printf("Key algorithm %d unsupported by libhsm.\n", policy->ksk->algorithm); 06550 db_disconnect(lock_fd); 06551 KsmPolicyFree(policy); 06552 exit(1); 06553 } 06554 } 06555 ksks_created = new_keys; 06556 06557 /* Find out how many zsk keys are needed */ 06558 keys_in_queue = 0; 06559 new_keys = 0; 06560 current_count = 0; 06561 06562 /* Find out how many zsk keys are needed for the POLICY */ 06563 status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, interval, &zsks_needed, 0, zone_count); 06564 if (status != 0) { 06565 printf("Could not predict zsk requirement for next interval for %s\n", policy->name); 06566 /* TODO exit? continue with next policy? */ 06567 } 06568 /* Find out how many suitable keys we have */ 06569 status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK); 06570 if (status != 0) { 06571 printf("Could not count current zsk numbers for policy %s\n", policy->name); 06572 /* TODO exit? continue with next policy? */ 06573 } 06574 /* Correct for shared keys */ 06575 if (policy->shared_keys == KSM_KEYS_SHARED) { 06576 keys_in_queue /= zone_count; 06577 } 06578 /* Might have to account for ksks */ 06579 if (same_keys) { 06580 keys_in_queue -= ksks_needed; 06581 } 06582 06583 new_keys = zsks_needed - keys_in_queue; 06584 /* fprintf(stderr, "keygen(zsk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, zsks_needed, keys_in_queue); */ 06585 06586 /* Check capacity of HSM will not be exceeded */ 06587 if (policy->zsk->sm_capacity != 0 && new_keys > 0) { 06588 current_count = hsm_count_keys_repository(ctx, policy->zsk->sm_name); 06589 if (current_count >= policy->zsk->sm_capacity) { 06590 printf("Repository %s is full, cannot create more ZSKs for policy %s\n", policy->zsk->sm_name, policy->name); 06591 new_keys = 0; 06592 } 06593 else if (current_count + new_keys > policy->zsk->sm_capacity) { 06594 printf("Repository %s is nearly full, will create %lu ZSKs for policy %s (reduced from %d)\n", policy->zsk->sm_name, policy->zsk->sm_capacity - current_count, policy->name, new_keys); 06595 new_keys = policy->zsk->sm_capacity - current_count; 06596 } 06597 } 06598 06599 /* Create the required keys */ 06600 for (i = new_keys ; i > 0 ; i--) { 06601 if (hsm_supported_algorithm(policy->zsk->algorithm) == 0) { 06602 /* NOTE: for now we know that libhsm only supports RSA keys */ 06603 key = hsm_generate_rsa_key(ctx, policy->zsk->sm_name, policy->zsk->bits); 06604 if (key) { 06605 if (verbose_flag) { 06606 printf("Created key in repository %s\n", policy->zsk->sm_name); 06607 } 06608 } else { 06609 printf("Error creating key in repository %s\n", policy->zsk->sm_name); 06610 hsm_error_message = hsm_get_error(ctx); 06611 if (hsm_error_message) { 06612 printf("%s\n", hsm_error_message); 06613 free(hsm_error_message); 06614 } 06615 db_disconnect(lock_fd); 06616 KsmPolicyFree(policy); 06617 exit(1); 06618 } 06619 id = hsm_get_key_id(ctx, key); 06620 hsm_key_free(key); 06621 status = KsmKeyPairCreate(policy->id, id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, rightnow, &ignore); 06622 if (status != 0) { 06623 printf("Error creating key in Database\n"); 06624 hsm_error_message = hsm_get_error(ctx); 06625 if (hsm_error_message) { 06626 printf("%s\n", hsm_error_message); 06627 free(hsm_error_message); 06628 } 06629 db_disconnect(lock_fd); 06630 KsmPolicyFree(policy); 06631 exit(1); 06632 } 06633 printf("Created ZSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->zsk->bits, 06634 policy->zsk->algorithm, id, policy->zsk->sm_name); 06635 free(id); 06636 } else { 06637 printf("Key algorithm %d unsupported by libhsm.\n", policy->zsk->algorithm); 06638 db_disconnect(lock_fd); 06639 KsmPolicyFree(policy); 06640 exit(1); 06641 } 06642 } 06643 StrFree(rightnow); 06644 06645 /* Log if a backup needs to be run for these keys */ 06646 if (ksks_created && policy->ksk->require_backup) { 06647 printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->ksk->sm_name); 06648 } 06649 if (new_keys && policy->zsk->require_backup && (policy->zsk->sm != policy->ksk->sm)) { 06650 printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->zsk->sm_name); 06651 } 06652 06653 /* 06654 * Destroy HSM context 06655 */ 06656 if (ctx) { 06657 hsm_destroy_context(ctx); 06658 } 06659 status = hsm_close(); 06660 printf("all done! hsm_close result: %d\n", status); 06661 06662 KsmPolicyFree(policy); 06663 06664 /* Release sqlite lock file (if we have it) */ 06665 db_disconnect(lock_fd); 06666 06667 return status; 06668 } 06669 06670 /* Make sure (if we can) that the permissions on a file are correct for the user/group in conf.xml */ 06671 06672 int fix_file_perms(const char *dbschema) 06673 { 06674 struct stat stat_ret; 06675 06676 int status = 0; 06677 06678 xmlDocPtr doc = NULL; 06679 xmlDocPtr rngdoc = NULL; 06680 xmlXPathContextPtr xpathCtx = NULL; 06681 xmlXPathObjectPtr xpathObj = NULL; 06682 xmlRelaxNGParserCtxtPtr rngpctx = NULL; 06683 xmlRelaxNGValidCtxtPtr rngctx = NULL; 06684 xmlRelaxNGPtr schema = NULL; 06685 xmlChar *user_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/User"; 06686 xmlChar *group_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/Group"; 06687 06688 char* filename = OPENDNSSEC_CONFIG_FILE; 06689 char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng"; 06690 char* temp_char = NULL; 06691 06692 struct passwd *pwd; 06693 struct group *grp; 06694 06695 int uid = -1; 06696 int gid = -1; 06697 char *username = NULL; 06698 char *groupname = NULL; 06699 06700 printf("fixing permissions on file %s\n", dbschema); 06701 /* First see if we are running as root, if not then return */ 06702 if (geteuid() != 0) { 06703 return 0; 06704 } 06705 06706 /* Now see if the file exists, if it does not then return */ 06707 if (stat(dbschema, &stat_ret) != 0) { 06708 printf("cannot stat file %s: %s", dbschema, strerror(errno)); 06709 return -1; 06710 } 06711 06712 /* OKAY... read conf.xml for the user and group */ 06713 /* Load XML document */ 06714 doc = xmlParseFile(filename); 06715 if (doc == NULL) { 06716 printf("Error: unable to parse file \"%s\"", filename); 06717 return(-1); 06718 } 06719 06720 /* Load rng document */ 06721 rngdoc = xmlParseFile(rngfilename); 06722 if (rngdoc == NULL) { 06723 printf("Error: unable to parse file \"%s\"", rngfilename); 06724 return(-1); 06725 } 06726 06727 /* Create an XML RelaxNGs parser context for the relax-ng document. */ 06728 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc); 06729 if (rngpctx == NULL) { 06730 printf("Error: unable to create XML RelaxNGs parser context"); 06731 return(-1); 06732 } 06733 06734 /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */ 06735 schema = xmlRelaxNGParse(rngpctx); 06736 if (schema == NULL) { 06737 printf("Error: unable to parse a schema definition resource"); 06738 return(-1); 06739 } 06740 06741 /* Create an XML RelaxNGs validation context based on the given schema */ 06742 rngctx = xmlRelaxNGNewValidCtxt(schema); 06743 if (rngctx == NULL) { 06744 printf("Error: unable to create RelaxNGs validation context based on the schema"); 06745 return(-1); 06746 } 06747 06748 /* Validate a document tree in memory. */ 06749 status = xmlRelaxNGValidateDoc(rngctx,doc); 06750 if (status != 0) { 06751 printf("Error validating file \"%s\"", filename); 06752 return(-1); 06753 } 06754 06755 /* Now parse a value out of the conf */ 06756 /* Create xpath evaluation context */ 06757 xpathCtx = xmlXPathNewContext(doc); 06758 if(xpathCtx == NULL) { 06759 printf("Error: unable to create new XPath context"); 06760 xmlFreeDoc(doc); 06761 return(-1); 06762 } 06763 06764 /* Set the group if specified */ 06765 xpathObj = xmlXPathEvalExpression(group_expr, xpathCtx); 06766 if(xpathObj == NULL) { 06767 printf("Error: unable to evaluate xpath expression: %s", group_expr); 06768 xmlXPathFreeContext(xpathCtx); 06769 xmlFreeDoc(doc); 06770 return(-1); 06771 } 06772 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 06773 temp_char = (char*) xmlXPathCastToString(xpathObj); 06774 StrAppend(&groupname, temp_char); 06775 StrFree(temp_char); 06776 xmlXPathFreeObject(xpathObj); 06777 } else { 06778 groupname = NULL; 06779 } 06780 06781 /* Set the user to drop to if specified */ 06782 xpathObj = xmlXPathEvalExpression(user_expr, xpathCtx); 06783 if(xpathObj == NULL) { 06784 printf("Error: unable to evaluate xpath expression: %s", user_expr); 06785 xmlXPathFreeContext(xpathCtx); 06786 xmlFreeDoc(doc); 06787 return(-1); 06788 } 06789 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 06790 temp_char = (char*) xmlXPathCastToString(xpathObj); 06791 StrAppend(&username, temp_char); 06792 StrFree(temp_char); 06793 xmlXPathFreeObject(xpathObj); 06794 } else { 06795 username = NULL; 06796 } 06797 06798 /* Free up the xml stuff, we are done with it */ 06799 xmlXPathFreeContext(xpathCtx); 06800 xmlRelaxNGFree(schema); 06801 xmlRelaxNGFreeValidCtxt(rngctx); 06802 xmlRelaxNGFreeParserCtxt(rngpctx); 06803 xmlFreeDoc(doc); 06804 xmlFreeDoc(rngdoc); 06805 06806 /* Set uid and gid if required */ 06807 if (username != NULL) { 06808 /* Lookup the user id in /etc/passwd */ 06809 if ((pwd = getpwnam(username)) == NULL) { 06810 printf("user '%s' does not exist. cannot chown %s...\n", username, dbschema); 06811 return(1); 06812 } else { 06813 uid = pwd->pw_uid; 06814 } 06815 endpwent(); 06816 } 06817 if (groupname) { 06818 /* Lookup the group id in /etc/groups */ 06819 if ((grp = getgrnam(groupname)) == NULL) { 06820 printf("group '%s' does not exist. cannot chown %s...\n", groupname, dbschema); 06821 exit(1); 06822 } else { 06823 gid = grp->gr_gid; 06824 } 06825 endgrent(); 06826 } 06827 06828 /* Change ownership of the db file */ 06829 if (chown(dbschema, uid, gid) == -1) { 06830 printf("cannot chown(%u,%u) %s: %s", 06831 (unsigned) uid, (unsigned) gid, dbschema, strerror(errno)); 06832 return -1; 06833 } 06834 06835 /* and change ownership of the lock file */ 06836 temp_char = NULL; 06837 StrAppend(&temp_char, dbschema); 06838 StrAppend(&temp_char, ".our_lock"); 06839 06840 if (chown(temp_char, uid, gid) == -1) { 06841 printf("cannot chown(%u,%u) %s: %s", 06842 (unsigned) uid, (unsigned) gid, temp_char, strerror(errno)); 06843 StrFree(temp_char); 06844 return -1; 06845 } 06846 06847 StrFree(temp_char); 06848 06849 return 0; 06850 } 06851 06852 /*+ 06853 * CountKeys - Find how many Keys match our criteria 06854 * 06855 * 06856 * Arguments: 06857 * 06858 * int zone_id 06859 * ID of the zone (-1 for all) 06860 * 06861 * int keytag 06862 * keytag provided (-1 if not specified) 06863 * 06864 * const char * cka_id 06865 * cka_id provided (NULL if not) 06866 * 06867 * int * key_count (returned) 06868 * count of keys matching the information specified 06869 * 06870 * char ** temp_cka_id (returned) 06871 * cka_id of key found 06872 * 06873 * int * temp_key_state (returned) 06874 * What state is the key in (only used if _one_ key returned) 06875 * 06876 * int * temp_keypair_id (returned) 06877 * ID of the key found (only used if _one_ key returned) 06878 * Returns: 06879 * int 06880 * Status return. 0 on success. 06881 * other on fail 06882 */ 06883 06884 int CountKeys(int *zone_id, int keytag, const char *cka_id, int *key_count, char **temp_cka_id, int *temp_key_state, int *temp_keypair_id) 06885 { 06886 char* sql = NULL; /* SQL query */ 06887 int status = 0; /* Status return */ 06888 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 06889 DB_RESULT result; /* Result of the query */ 06890 DB_ROW row = NULL; /* Row data */ 06891 06892 char buffer[256]; /* For constructing part of the command */ 06893 size_t nchar; /* Number of characters written */ 06894 06895 int done_row = 0; /* Have we found a key this loop? */ 06896 06897 int temp_zone_id = 0; /* place to store zone_id returned */ 06898 char* temp_loc = NULL; /* place to store location returned */ 06899 int temp_alg = 0; /* place to store algorithm returned */ 06900 int temp_state = 0; /* place to store state returned */ 06901 int temp_keypair = 0; /* place to store id returned */ 06902 06903 int temp_count = 0; /* Count of keys found */ 06904 06905 /* Key information */ 06906 hsm_key_t *key = NULL; 06907 ldns_rr *dnskey_rr = NULL; 06908 hsm_sign_params_t *sign_params = NULL; 06909 06910 /* connect to the HSM */ 06911 status = hsm_open(config, hsm_prompt_pin, NULL); 06912 if (status) { 06913 hsm_print_error(NULL); 06914 return(-1); 06915 } 06916 06917 /* Select rows */ 06918 nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d)", 06919 KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB); 06920 if (nchar >= sizeof(buffer)) { 06921 printf("Error: Overran buffer in CountKeys\n"); 06922 return(-1); 06923 } 06924 06925 /* TODO do I need to use the view */ 06926 StrAppend(&sql, "select k.zone_id, k.location, k.algorithm, k.state, k.id from KEYDATA_VIEW k where state in "); 06927 StrAppend(&sql, buffer); 06928 StrAppend(&sql, " and zone_id is not null and k.keytype = 257"); 06929 06930 if (*zone_id != -1) { 06931 StrAppend(&sql, " and zone_id = "); 06932 snprintf(stringval, KSM_INT_STR_SIZE, "%d", *zone_id); 06933 StrAppend(&sql, stringval); 06934 } 06935 if (cka_id != NULL) { 06936 StrAppend(&sql, " and k.location = '"); 06937 StrAppend(&sql, cka_id); 06938 StrAppend(&sql, "'"); 06939 } 06940 /* where location is unique? */ 06941 StrAppend(&sql, " group by location"); 06942 06943 DusEnd(&sql); 06944 06945 status = DbExecuteSql(DbHandle(), sql, &result); 06946 06947 /* loop round printing out the cka_id of any key that matches 06948 * if only one does then we are good, if not then we will write a 06949 * message asking for further clarification */ 06950 /* Note that we only need to do each key, not each instance of a key */ 06951 if (status == 0) { 06952 status = DbFetchRow(result, &row); 06953 while (status == 0) { 06954 /* Got a row, process it */ 06955 DbInt(row, 0, &temp_zone_id); 06956 DbString(row, 1, &temp_loc); 06957 DbInt(row, 2, &temp_alg); 06958 DbInt(row, 3, &temp_state); 06959 DbInt(row, 4, &temp_keypair); 06960 06961 done_row = 0; 06962 06963 if (keytag == -1 && cka_id == NULL) 06964 { 06965 *temp_key_state = temp_state; 06966 } 06967 06968 key = hsm_find_key_by_id(NULL, temp_loc); 06969 if (!key) { 06970 printf("cka_id %-33s in DB but NOT IN repository\n", temp_loc); 06971 } else if (keytag != -1) { 06972 sign_params = hsm_sign_params_new(); 06973 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "temp_zone"); 06974 sign_params->algorithm = temp_alg; 06975 sign_params->flags = LDNS_KEY_ZONE_KEY; 06976 sign_params->flags += LDNS_KEY_SEP_KEY; 06977 06978 dnskey_rr = hsm_get_dnskey(NULL, key, sign_params); 06979 sign_params->keytag = ldns_calc_keytag(dnskey_rr); 06980 06981 /* Have we matched our keytag? */ 06982 if (keytag == sign_params->keytag) { 06983 temp_count++; 06984 done_row = 1; 06985 *temp_cka_id = NULL; 06986 StrAppend(temp_cka_id, temp_loc); 06987 *zone_id = temp_zone_id; 06988 *temp_key_state = temp_state; 06989 *temp_keypair_id = temp_keypair; 06990 printf("Found key with CKA_ID %s\n", temp_loc); 06991 } 06992 06993 hsm_sign_params_free(sign_params); 06994 } 06995 if (key && cka_id != NULL && strncmp(cka_id, temp_loc, strlen(temp_loc)) == 0) { 06996 /* Or have we matched a provided cka_id */ 06997 if (done_row == 0) { 06998 temp_count++; 06999 *temp_cka_id = NULL; 07000 StrAppend(temp_cka_id, temp_loc); 07001 *zone_id = temp_zone_id; 07002 *temp_key_state = temp_state; 07003 *temp_keypair_id = temp_keypair; 07004 printf("Found key with CKA_ID %s\n", temp_loc); 07005 } 07006 } 07007 07008 if (key) { 07009 hsm_key_free(key); 07010 } 07011 07012 status = DbFetchRow(result, &row); 07013 } 07014 07015 /* Convert EOF status to success */ 07016 07017 if (status == -1) { 07018 status = 0; 07019 } 07020 07021 DbFreeResult(result); 07022 } 07023 07024 *key_count = temp_count; 07025 07026 DusFree(sql); 07027 DbFreeRow(row); 07028 07029 DbStringFree(temp_loc); 07030 07031 if (dnskey_rr != NULL) { 07032 ldns_rr_free(dnskey_rr); 07033 } 07034 07035 return status; 07036 } 07037 07038 /*+ 07039 * MarkDSSeen - Indicate that the DS record has been observed: 07040 * Change the state of the key to ACTIVE 07041 * 07042 * Arguments: 07043 * 07044 * const char * cka_id 07045 * cka_id of key to make active 07046 * 07047 * int zone_id 07048 * ID of the zone 07049 * 07050 * int policy_id 07051 * ID of the policy 07052 * 07053 * const char * datetime 07054 * when this is happening 07055 * 07056 * int key_state 07057 * state that the key is in 07058 * 07059 * Returns: 07060 * int 07061 * Status return. 0 on success. 07062 * other on fail 07063 */ 07064 07065 int MarkDSSeen(int keypair_id, int zone_id, int policy_id, const char *datetime, int key_state) 07066 { 07067 char* sql1 = NULL; /* SQL query */ 07068 int status = 0; /* Status return */ 07069 07070 char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */ 07071 unsigned int nchar; /* Number of characters converted */ 07072 07073 KSM_PARCOLL collection; /* Collection of parameters for zone */ 07074 int deltat; /* Time interval */ 07075 07076 (void) zone_id; 07077 07078 /* Set collection defaults */ 07079 KsmCollectionInit(&collection); 07080 07081 /* Get the values of the parameters */ 07082 status = KsmParameterCollection(&collection, policy_id); 07083 if (status != 0) { 07084 printf("Error: failed to read policy\n"); 07085 return status; 07086 } 07087 07088 /* 0) Start a transaction */ 07089 status = DbBeginTransaction(); 07090 if (status != 0) { 07091 /* Something went wrong */ 07092 07093 MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07094 return status; 07095 } 07096 07097 /* 1) Change the state of the selected Key */ 07098 if (key_state == KSM_STATE_READY) { 07099 /* We are making a key active */ 07100 07101 /* Set the interval until Retire */ 07102 deltat = collection.ksklife; 07103 07104 #ifdef USE_MYSQL 07105 nchar = snprintf(buffer, sizeof(buffer), 07106 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07107 #else 07108 nchar = snprintf(buffer, sizeof(buffer), 07109 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07110 #endif /* USE_MYSQL */ 07111 07112 sql1 = DusInit("dnsseckeys"); 07113 DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0); 07114 DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_ACTIVE), datetime, 1); 07115 StrAppend(&sql1, ", RETIRE = "); 07116 StrAppend(&sql1, buffer); 07117 07118 DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0); 07119 DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07120 DusEnd(&sql1); 07121 } 07122 else { 07123 /* We are making a standby key DSpublish */ 07124 07125 /* Set the interval until DSReady */ 07126 deltat = collection.kskttl + collection.kskpropdelay + 07127 collection.pub_safety; 07128 07129 #ifdef USE_MYSQL 07130 nchar = snprintf(buffer, sizeof(buffer), 07131 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07132 #else 07133 nchar = snprintf(buffer, sizeof(buffer), 07134 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07135 #endif /* USE_MYSQL */ 07136 07137 sql1 = DusInit("dnsseckeys"); 07138 DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0); 07139 DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_PUBLISH), datetime, 1); 07140 StrAppend(&sql1, ", READY = "); 07141 StrAppend(&sql1, buffer); 07142 07143 DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0); 07144 DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07145 DusEnd(&sql1); 07146 } 07147 07148 status = DbExecuteSqlNoResult(DbHandle(), sql1); 07149 DusFree(sql1); 07150 07151 /* Report any errors */ 07152 if (status != 0) { 07153 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07154 DbRollback(); 07155 return status; 07156 } 07157 07158 /* 3) Commit or Rollback */ 07159 if (status == 0) { /* It actually can't be anything else */ 07160 /* Everything worked by the looks of it */ 07161 DbCommit(); 07162 } else { 07163 /* Whatever happened, it was not good */ 07164 DbRollback(); 07165 } 07166 07167 return status; 07168 } 07169 07170 /*+ 07171 * RetireOldKey - Retire the old KSK 07172 * 07173 * 07174 * Arguments: 07175 * 07176 * int zone_id 07177 * ID of the zone 07178 * 07179 * int policy_id 07180 * ID of the policy 07181 * 07182 * const char * datetime 07183 * when this is happening 07184 * 07185 * Returns: 07186 * int 07187 * Status return. 0 on success. 07188 * other on fail 07189 */ 07190 07191 int RetireOldKey(int zone_id, int policy_id, const char *datetime) 07192 { 07193 char* sql2 = NULL; /* SQL query */ 07194 int status = 0; /* Status return */ 07195 char* where_clause = NULL; 07196 int id = -1; /* ID of key to retire */ 07197 07198 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 07199 char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */ 07200 unsigned int nchar; /* Number of characters converted */ 07201 07202 KSM_PARCOLL collection; /* Collection of parameters for zone */ 07203 int deltat; /* Time interval */ 07204 07205 /* Set collection defaults */ 07206 KsmCollectionInit(&collection); 07207 07208 /* Get the values of the parameters */ 07209 status = KsmParameterCollection(&collection, policy_id); 07210 if (status != 0) { 07211 printf("Error: failed to read policy\n"); 07212 return status; 07213 } 07214 07215 /* 0) Start a transaction */ 07216 status = DbBeginTransaction(); 07217 if (status != 0) { 07218 /* Something went wrong */ 07219 07220 MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07221 return status; 07222 } 07223 07224 /* 1) Retire the oldest active key, and set its deadtime */ 07225 /* work out which key */ 07226 snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id); 07227 StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = "); 07228 StrAppend(&where_clause, stringval); 07229 StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = "); 07230 StrAppend(&where_clause, stringval); 07231 StrAppend(&where_clause, ")"); 07232 07233 /* Execute query and free up the query string */ 07234 status = DbIntQuery(DbHandle(), &id, where_clause); 07235 StrFree(where_clause); 07236 if (status != 0) 07237 { 07238 printf("Error: failed to find ID of key to retire\n"); 07239 DbRollback(); 07240 return status; 07241 } 07242 07243 /* work out what its deadtime should become */ 07244 deltat = collection.dsttl + collection.kskpropdelay + collection.ret_safety; 07245 07246 #ifdef USE_MYSQL 07247 nchar = snprintf(buffer, sizeof(buffer), 07248 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07249 #else 07250 nchar = snprintf(buffer, sizeof(buffer), 07251 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07252 #endif /* USE_MYSQL */ 07253 07254 sql2 = DusInit("dnsseckeys"); 07255 DusSetInt(&sql2, "STATE", KSM_STATE_RETIRE, 0); 07256 DusSetString(&sql2, KsmKeywordStateValueToName(KSM_STATE_RETIRE), datetime, 1); 07257 StrAppend(&sql2, ", DEAD = "); 07258 StrAppend(&sql2, buffer); 07259 DusConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, id, 0); 07260 DusConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07261 07262 status = DbExecuteSqlNoResult(DbHandle(), sql2); 07263 DusFree(sql2); 07264 07265 /* Report any errors */ 07266 if (status != 0) { 07267 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07268 DbRollback(); 07269 return status; 07270 } 07271 07272 /* 2) Commit or Rollback */ 07273 if (status == 0) { /* It actually can't be anything else */ 07274 /* Everything worked by the looks of it */ 07275 DbCommit(); 07276 } else { 07277 /* Whatever happened, it was not good */ 07278 DbRollback(); 07279 } 07280 07281 return status; 07282 } 07283 07284 /* 07285 * CountKeysInState - Count Keys in given state 07286 * 07287 * Description: 07288 * Counts the number of keys in the given state. 07289 * 07290 * Arguments: 07291 * int keytype 07292 * Either KSK or ZSK, depending on the key type 07293 * 07294 * int keystate 07295 * State of keys to count 07296 * 07297 * int* count 07298 * Number of keys meeting the condition. 07299 * 07300 * int zone_id 07301 * ID of zone that we are looking at (-1 == all zones) 07302 * 07303 * Returns: 07304 * int 07305 * Status return. 0 => success, Other => error, in which case a message 07306 * will have been output. 07307 -*/ 07308 07309 int CountKeysInState(int keytype, int keystate, int* count, int zone_id) 07310 { 07311 int clause = 0; /* Clause counter */ 07312 char* sql = NULL; /* SQL command */ 07313 int status; /* Status return */ 07314 07315 sql = DqsCountInit("KEYDATA_VIEW"); 07316 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 07317 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, keystate, clause++); 07318 if (zone_id != -1) { 07319 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 07320 } 07321 DqsEnd(&sql); 07322 07323 status = DbIntQuery(DbHandle(), count, sql); 07324 DqsFree(sql); 07325 07326 if (status != 0) { 07327 printf("Error in CountKeysInState\n"); 07328 } 07329 07330 return status; 07331 } 07332 07333 /*+ 07334 * ChangeKeyState - Change the state of the specified key 07335 * 07336 * Arguments: 07337 * 07338 * int keytype 07339 * type of key we are dealing with 07340 * 07341 * const char * cka_id 07342 * cka_id of key to change 07343 * 07344 * int zone_id 07345 * ID of the zone 07346 * 07347 * int policy_id 07348 * ID of the policy 07349 * 07350 * const char * datetime 07351 * when this is happening 07352 * 07353 * int keystate 07354 * state that the key should be moved to 07355 * 07356 * Returns: 07357 * int 07358 * Status return. 0 on success. 07359 * other on fail 07360 * 07361 * TODO take keytimings out of here 07362 */ 07363 07364 int ChangeKeyState(int keytype, const char *cka_id, int zone_id, int policy_id, const char *datetime, int keystate) 07365 { 07366 char* sql1 = NULL; /* SQL query */ 07367 int status = 0; /* Status return */ 07368 07369 int count = 0; /* Count of keys whose date will be set */ 07370 char* sql = NULL; /* For creating the SQL command */ 07371 int where = 0; /* For the SQL selection */ 07372 int i = 0; /* A counter */ 07373 int j = 0; /* Another counter */ 07374 char* insql = NULL; /* SQL "IN" clause */ 07375 int* keyids; /* List of IDs of keys to promote */ 07376 DB_RESULT result; /* List result set */ 07377 KSM_KEYDATA data; /* Data for this key */ 07378 07379 char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */ 07380 unsigned int nchar; /* Number of characters converted */ 07381 07382 KSM_PARCOLL collection; /* Collection of parameters for zone */ 07383 int deltat = 0; /* Time interval */ 07384 07385 (void) zone_id; 07386 07387 /* Set collection defaults */ 07388 KsmCollectionInit(&collection); 07389 07390 /* Get the values of the parameters */ 07391 status = KsmParameterCollection(&collection, policy_id); 07392 if (status != 0) { 07393 printf("Error: failed to read policy\n"); 07394 return status; 07395 } 07396 07397 /* Count how many keys will have their state changed */ 07398 07399 sql = DqsCountInit("KEYDATA_VIEW"); 07400 DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++); 07401 if (zone_id != -1) { 07402 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 07403 } 07404 DqsEnd(&sql); 07405 07406 status = DbIntQuery(DbHandle(), &count, sql); 07407 DqsFree(sql); 07408 07409 if (status != 0) { 07410 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07411 return status; 07412 } 07413 07414 if (count == 0) { 07415 /* Nothing to do, error? */ 07416 return status; 07417 } 07418 07419 /* Allocate space for the list of key IDs */ 07420 keyids = MemMalloc(count * sizeof(int)); 07421 07422 /* Get the list of IDs */ 07423 07424 where = 0; 07425 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 07426 DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++); 07427 if (zone_id != -1) { 07428 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 07429 } 07430 DqsEnd(&sql); 07431 07432 status = KsmKeyInitSql(&result, sql); 07433 DqsFree(sql); 07434 07435 if (status == 0) { 07436 while (status == 0) { 07437 status = KsmKey(result, &data); 07438 if (status == 0) { 07439 keyids[i] = data.keypair_id; 07440 i++; 07441 } 07442 } 07443 07444 /* Convert EOF status to success */ 07445 07446 if (status == -1) { 07447 status = 0; 07448 } else { 07449 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07450 StrFree(keyids); 07451 return status; 07452 } 07453 07454 KsmKeyEnd(result); 07455 07456 } else { 07457 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07458 StrFree(keyids); 07459 return status; 07460 } 07461 07462 /* 07463 * Now construct the "IN" statement listing the IDs of the keys we 07464 * are planning to change the state of. 07465 */ 07466 07467 StrAppend(&insql, "("); 07468 for (j = 0; j < i; ++j) { 07469 if (j != 0) { 07470 StrAppend(&insql, ","); 07471 } 07472 snprintf(buffer, sizeof(buffer), "%d", keyids[j]); 07473 StrAppend(&insql, buffer); 07474 } 07475 StrAppend(&insql, ")"); 07476 07477 /* 0) Start a transaction */ 07478 status = DbBeginTransaction(); 07479 if (status != 0) { 07480 /* Something went wrong */ 07481 07482 MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07483 StrFree(keyids); 07484 return status; 07485 } 07486 07487 /* 1) Change the state of the selected Key */ 07488 if (keystate == KSM_STATE_ACTIVE) { 07489 /* We are making a key active */ 07490 07491 /* Set the interval until Retire */ 07492 deltat = collection.ksklife; 07493 07494 #ifdef USE_MYSQL 07495 nchar = snprintf(buffer, sizeof(buffer), 07496 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07497 #else 07498 nchar = snprintf(buffer, sizeof(buffer), 07499 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07500 #endif /* USE_MYSQL */ 07501 07502 sql1 = DusInit("dnsseckeys"); 07503 DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0); 07504 DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_ACTIVE), datetime, 1); 07505 StrAppend(&sql1, ", RETIRE = "); 07506 StrAppend(&sql1, buffer); 07507 07508 DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0); 07509 if (zone_id != -1) { 07510 DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07511 } 07512 DusEnd(&sql1); 07513 } 07514 else if (keystate == KSM_STATE_RETIRE) { 07515 /* We are making a key retired */ 07516 07517 /* Set the interval until Dead */ 07518 if (keytype == KSM_TYPE_ZSK) { 07519 deltat = collection.zsksiglife + collection.propdelay + collection.ret_safety; 07520 } 07521 else if (keytype == KSM_TYPE_KSK) { 07522 deltat = collection.kskttl + collection.kskpropdelay + 07523 collection.ret_safety; /* Ipp */ 07524 } 07525 07526 #ifdef USE_MYSQL 07527 nchar = snprintf(buffer, sizeof(buffer), 07528 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07529 #else 07530 nchar = snprintf(buffer, sizeof(buffer), 07531 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07532 #endif /* USE_MYSQL */ 07533 07534 sql1 = DusInit("dnsseckeys"); 07535 DusSetInt(&sql1, "STATE", KSM_STATE_RETIRE, 0); 07536 DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_RETIRE), datetime, 1); 07537 StrAppend(&sql1, ", DEAD = "); 07538 StrAppend(&sql1, buffer); 07539 07540 DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0); 07541 if (zone_id != -1) { 07542 DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07543 } 07544 DusEnd(&sql1); 07545 } 07546 else if (keystate == KSM_STATE_DSPUBLISH) { 07547 /* Set the interval until DSReady */ 07548 deltat = collection.kskttl + collection.kskpropdelay + 07549 collection.pub_safety; 07550 07551 #ifdef USE_MYSQL 07552 nchar = snprintf(buffer, sizeof(buffer), 07553 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat); 07554 #else 07555 nchar = snprintf(buffer, sizeof(buffer), 07556 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat); 07557 #endif /* USE_MYSQL */ 07558 07559 sql1 = DusInit("dnsseckeys"); 07560 DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0); 07561 DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_PUBLISH), datetime, 1); 07562 StrAppend(&sql1, ", READY = "); 07563 StrAppend(&sql1, buffer); 07564 07565 DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0); 07566 if (zone_id != -1) { 07567 DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 07568 } 07569 DusEnd(&sql1); 07570 } 07571 else { 07572 printf("Moving to keystate %s not implemented yet\n", KsmKeywordStateValueToName(keystate)); 07573 StrFree(keyids); 07574 return -1; 07575 } 07576 07577 status = DbExecuteSqlNoResult(DbHandle(), sql1); 07578 DusFree(sql1); 07579 07580 StrFree(keyids); 07581 07582 /* Report any errors */ 07583 if (status != 0) { 07584 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 07585 DbRollback(); 07586 return status; 07587 } 07588 07589 /* 3) Commit or Rollback */ 07590 if (status == 0) { /* It actually can't be anything else */ 07591 /* Everything worked by the looks of it */ 07592 DbCommit(); 07593 } else { 07594 /* Whatever happened, it was not good */ 07595 DbRollback(); 07596 } 07597 07598 return status; 07599 } 07600 07601 static int restart_enforcerd() 07602 { 07603 /* ToDo: This should really be rewritten so that it will read 07604 OPENDNSSEC_ENFORCER_PIDFILE and send a SIGHUP itself */ 07605 return system(RESTART_ENFORCERD_CMD); 07606 } 07607 07608 /* 07609 * Read the conf.xml file, we will not validate as that was done as we read the database. 07610 * Instead we just extract the RepositoryList into the database and also learn the 07611 * location of the zonelist. 07612 */ 07613 int get_conf_key_info(int* interval, int* man_key_gen) 07614 { 07615 int status = 0; 07616 int mysec = 0; 07617 xmlDocPtr doc = NULL; 07618 xmlXPathContextPtr xpathCtx = NULL; 07619 xmlXPathObjectPtr xpathObj = NULL; 07620 char* temp_char = NULL; 07621 07622 xmlChar *iv_expr = (unsigned char*) "//Configuration/Enforcer/Interval"; 07623 xmlChar *mk_expr = (unsigned char*) "//Configuration/Enforcer/ManualKeyGeneration"; 07624 07625 /* Load XML document */ 07626 doc = xmlParseFile(config); 07627 if (doc == NULL) { 07628 printf("Error: unable to parse file \"%s\"\n", config); 07629 return(-1); 07630 } 07631 07632 /* Create xpath evaluation context */ 07633 xpathCtx = xmlXPathNewContext(doc); 07634 if(xpathCtx == NULL) { 07635 printf("Error: unable to create new XPath context\n"); 07636 xmlFreeDoc(doc); 07637 return(-1); 07638 } 07639 07640 /* Evaluate xpath expression for interval */ 07641 xpathObj = xmlXPathEvalExpression(iv_expr, xpathCtx); 07642 if(xpathObj == NULL) { 07643 printf("Error: unable to evaluate xpath expression: %s", iv_expr); 07644 xmlXPathFreeContext(xpathCtx); 07645 xmlFreeDoc(doc); 07646 return(-1); 07647 } 07648 07649 temp_char = (char *)xmlXPathCastToString(xpathObj); 07650 status = DtXMLIntervalSeconds(temp_char, &mysec); 07651 if (status > 0) { 07652 printf("Error: unable to convert Interval %s to seconds, error: %i\n", temp_char, status); 07653 StrFree(temp_char); 07654 return status; 07655 } 07656 else if (status == -1) { 07657 printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char); 07658 } 07659 *interval = mysec; 07660 StrFree(temp_char); 07661 xmlXPathFreeObject(xpathObj); 07662 07663 /* Evaluate xpath expression for Manual key generation */ 07664 xpathObj = xmlXPathEvalExpression(mk_expr, xpathCtx); 07665 if(xpathObj == NULL) { 07666 printf("Error: unable to evaluate xpath expression: %s\n", mk_expr); 07667 xmlXPathFreeContext(xpathCtx); 07668 xmlFreeDoc(doc); 07669 return(-1); 07670 } 07671 07672 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 07673 /* Manual key generation tag is present */ 07674 *man_key_gen = 1; 07675 } 07676 else { 07677 /* Tag absent */ 07678 *man_key_gen = 0; 07679 } 07680 xmlXPathFreeObject(xpathObj); 07681 07682 if (xpathCtx) { 07683 xmlXPathFreeContext(xpathCtx); 07684 } 07685 if (doc) { 07686 xmlFreeDoc(doc); 07687 } 07688 07689 return 0; 07690 } 07691 07692 /* TODO put this fn and the one below somewhere that we can call it from here and the enforcer */ 07693 /*+ 07694 * LinkKeys - Create required entries in Dnsseckeys table for zones added to policies 07695 * (i.e. when keysharing is turned on) 07696 * 07697 * Description: 07698 * Allocates a key in the database. 07699 * 07700 * Arguments: 07701 * const char* zone_name 07702 * name of zone 07703 * 07704 * int policy_id 07705 * ID of policy which the zone is on 07706 * 07707 * int interval 07708 * Enforcer run interval 07709 * 07710 * int man_key_gen 07711 * Manual Key Generation flag 07712 * 07713 * Returns: 07714 * int 07715 * Status return. 0=> Success, non-zero => error. 07716 -*/ 07717 07718 int LinkKeys(const char* zone_name, int policy_id) 07719 { 07720 int status = 0; 07721 07722 int interval = -1; /* Enforcer interval */ 07723 int man_key_gen = -1; /* Manual key generation flag */ 07724 07725 int zone_id = 0; /* id of zone supplied */ 07726 KSM_POLICY* policy; 07727 07728 /* Unused parameter */ 07729 (void)policy_id; 07730 07731 /* Get some info from conf.xml */ 07732 status = get_conf_key_info(&interval, &man_key_gen); 07733 if (status != 0) { 07734 printf("Failed to Link Keys to zone\n"); 07735 return(1); 07736 } 07737 07738 status = KsmZoneIdFromName(zone_name, &zone_id); 07739 if (status != 0) { 07740 return(status); 07741 } 07742 07743 policy = KsmPolicyAlloc(); 07744 if (policy == NULL) { 07745 printf("Malloc for policy struct failed\n"); 07746 exit(1); 07747 } 07748 SetPolicyDefaults(policy, o_policy); 07749 07750 status = KsmPolicyExists(o_policy); 07751 if (status == 0) { 07752 /* Policy exists */ 07753 status = KsmPolicyRead(policy); 07754 if(status != 0) { 07755 printf("Error: unable to read policy %s from database\n", o_policy); 07756 KsmPolicyFree(policy); 07757 return status; 07758 } 07759 } else { 07760 printf("Error: policy %s doesn't exist in database\n", o_policy); 07761 KsmPolicyFree(policy); 07762 return status; 07763 } 07764 07765 /* Make sure that enough keys are allocated to this zone */ 07766 status = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, interval, zone_name, man_key_gen, 0); 07767 if (status != 0) { 07768 printf("Error allocating zsks to zone %s", zone_name); 07769 KsmPolicyFree(policy); 07770 return(status); 07771 } 07772 status = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, interval, zone_name, man_key_gen, policy->ksk->rollover_scheme); 07773 if (status != 0) { 07774 printf("Error allocating ksks to zone %s", zone_name); 07775 KsmPolicyFree(policy); 07776 return(status); 07777 } 07778 07779 KsmPolicyFree(policy); 07780 return 0; 07781 } 07782 07783 /* allocateKeysToZone 07784 * 07785 * Description: 07786 * Allocates existing keys to zones 07787 * 07788 * Arguments: 07789 * policy 07790 * policy that the keys were created for 07791 * key_type 07792 * KSK or ZSK 07793 * zone_id 07794 * ID of zone in question 07795 * interval 07796 * time before next run 07797 * zone_name 07798 * just in case we need to log something 07799 * man_key_gen 07800 * lack of keys may be an issue for the user to fix 07801 * int rollover_scheme 07802 * KSK rollover scheme in use 07803 * 07804 * Returns: 07805 * int 07806 * Status return. 0=> Success, non-zero => error. 07807 * 1 == error with input 07808 * 2 == not enough keys to satisfy policy 07809 * 3 == database error 07810 -*/ 07811 07812 07813 int allocateKeysToZone(KSM_POLICY *policy, int key_type, int zone_id, uint16_t interval, const char* zone_name, int man_key_gen, int rollover_scheme) 07814 { 07815 int status = 0; 07816 int keys_needed = 0; 07817 int keys_in_queue = 0; 07818 int keys_pending_retirement = 0; 07819 int new_keys = 0; 07820 int key_pair_id = 0; 07821 int i = 0; 07822 DB_ID ignore = 0; 07823 KSM_PARCOLL collection; /* Parameters collection */ 07824 char* datetime = DtParseDateTimeString("now"); 07825 07826 /* Check datetime in case it came back NULL */ 07827 if (datetime == NULL) { 07828 printf("Couldn't turn \"now\" into a date, quitting..."); 07829 exit(1); 07830 } 07831 07832 if (policy == NULL) { 07833 printf("NULL policy sent to allocateKeysToZone"); 07834 StrFree(datetime); 07835 return 1; 07836 } 07837 07838 if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) { 07839 printf("Unknown keytype: %i in allocateKeysToZone", key_type); 07840 StrFree(datetime); 07841 return 1; 07842 } 07843 07844 /* Get list of parameters */ 07845 status = KsmParameterCollection(&collection, policy->id); 07846 if (status != 0) { 07847 StrFree(datetime); 07848 return status; 07849 } 07850 07851 /* Make sure that enough keys are allocated to this zone */ 07852 /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */ 07853 status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1); 07854 if (status != 0) { 07855 printf("Could not predict key requirement for next interval for %s", zone_name); 07856 StrFree(datetime); 07857 return 3; 07858 } 07859 07860 /* How many do we have ? TODO should this include the currently active key?*/ 07861 status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id); 07862 if (status != 0) { 07863 printf("Could not count current key numbers for zone %s", zone_name); 07864 StrFree(datetime); 07865 return 3; 07866 } 07867 07868 /* or about to retire */ 07869 status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval); 07870 if (status != 0) { 07871 printf("Could not count keys which may retire before the next run (for zone %s)", zone_name); 07872 StrFree(datetime); 07873 return 3; 07874 } 07875 07876 StrFree(datetime); 07877 new_keys = keys_needed - (keys_in_queue - keys_pending_retirement); 07878 07879 /* fprintf(stderr, "comm(%d) %s: new_keys(%d) = keys_needed(%d) - (keys_in_queue(%d) - keys_pending_retirement(%d))\n", key_type, zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement); */ 07880 07881 /* Allocate keys */ 07882 for (i=0 ; i < new_keys ; i++){ 07883 key_pair_id = 0; 07884 if (key_type == KSM_TYPE_KSK) { 07885 status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id); 07886 if (status == -1 || key_pair_id == 0) { 07887 if (man_key_gen == 0) { 07888 printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name); 07889 printf("ods-enforcerd will create some more keys on its next run"); 07890 } 07891 else { 07892 printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name); 07893 printf("please use \"ods-ksmutil key generate\" to create some more keys."); 07894 } 07895 return 2; 07896 } 07897 else if (status != 0) { 07898 printf("Could not get an unallocated ksk for zone: %s", zone_name); 07899 return 3; 07900 } 07901 } else { 07902 status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id); 07903 if (status == -1 || key_pair_id == 0) { 07904 if (man_key_gen == 0) { 07905 printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name); 07906 printf("ods-enforcerd will create some more keys on its next run"); 07907 } 07908 else { 07909 printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name); 07910 printf("please use \"ods-ksmutil key generate\" to create some more keys."); 07911 } 07912 return 2; 07913 } 07914 else if (status != 0) { 07915 printf("Could not get an unallocated zsk for zone: %s", zone_name); 07916 return 3; 07917 } 07918 } 07919 if(key_pair_id > 0) { 07920 status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, &ignore); 07921 /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */ 07922 } else { 07923 /* This shouldn't happen */ 07924 printf("KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name); 07925 exit(1); 07926 } 07927 07928 } 07929 07930 return status; 07931 } 07932 07933 07934 /* keyRoll 07935 * 07936 * Description: 07937 * Rolls keys far enough for the enforcer to take over 07938 * 07939 * Arguments: 07940 * zone_id 07941 * ID of zone in question (-1 == all) 07942 * policy_id 07943 * policy that should be rolled (-1 == all) 07944 * key_type 07945 * KSK or ZSK (-1 == all) 07946 * 07947 * Returns: 07948 * int 07949 * Status return. 0=> Success, non-zero => error. 07950 -*/ 07951 07952 int keyRoll(int zone_id, int policy_id, int key_type) 07953 { 07954 07955 int status = 0; 07956 int size = -1; 07957 07958 char* sql = NULL; /* SQL query */ 07959 char* sql1 = NULL; /* SQL query */ 07960 char sql2[KSM_SQL_SIZE]; 07961 DB_RESULT result1; /* Result of the query */ 07962 DB_ROW row = NULL; /* Row data */ 07963 int temp_id = -1; /* place to store the key id returned */ 07964 int temp_type = -1; /* place to store the key type returned */ 07965 int temp_zone_id = -1; /* place to store the zone id returned */ 07966 int where = 0; 07967 int j = 0; 07968 DB_RESULT result2; /* Result of the query */ 07969 DB_RESULT result3; /* Result of the query */ 07970 DB_ROW row2 = NULL; /* Row data */ 07971 char* insql1 = NULL; /* SQL query */ 07972 char* insql2 = NULL; /* SQL query */ 07973 char buffer[32]; /* For integer conversion */ 07974 07975 char* datetime = DtParseDateTimeString("now"); 07976 07977 /* Check datetime in case it came back NULL */ 07978 if (datetime == NULL) { 07979 printf("Couldn't turn \"now\" into a date, quitting...\n"); 07980 StrFree(datetime); 07981 exit(1); 07982 } 07983 07984 /* retire the active key(s) */ 07985 /* Find the key ID */ 07986 sql = DqsSpecifyInit("KEYDATA_VIEW","id, keytype"); 07987 if (zone_id != -1) { 07988 DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, where++); 07989 } 07990 if (policy_id != -1) { 07991 DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++); 07992 } 07993 DqsConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++); 07994 if (key_type != -1) { 07995 DqsConditionInt(&sql, "keytype", DQS_COMPARE_EQ, key_type, where++); 07996 } 07997 DqsEnd(&sql); 07998 07999 status = DbExecuteSql(DbHandle(), sql, &result1); 08000 08001 if (status == 0) { 08002 status = DbFetchRow(result1, &row); 08003 while (status == 0) { 08004 /* Got a row, deal with it */ 08005 DbInt(row, 0, &temp_id); 08006 DbInt(row, 1, &temp_type); 08007 08008 sql1 = DusInit("keypairs"); 08009 DusSetInt(&sql1, "fixedDate", 1, 0); 08010 DusSetInt(&sql1, "compromisedflag", 1, 1); 08011 08012 DusConditionInt(&sql1, "id", DQS_COMPARE_EQ, temp_id, 0); 08013 DusEnd(&sql1); 08014 status = DbExecuteSqlNoResult(DbHandle(), sql1); 08015 DusFree(sql1); 08016 08017 /* Report any errors */ 08018 if (status != 0) { 08019 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08020 DbFreeRow(row); 08021 return status; 08022 } 08023 08024 /* Loop over instances of this key: */ 08025 /* active-> set retire time */ 08026 sql1 = DusInit("dnsseckeys"); 08027 DusSetString(&sql1, "RETIRE", datetime, 0); 08028 08029 DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 08030 DusConditionInt(&sql1, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, 1); 08031 DusEnd(&sql1); 08032 status = DbExecuteSqlNoResult(DbHandle(), sql1); 08033 DusFree(sql1); 08034 08035 /* Report any errors */ 08036 if (status != 0) { 08037 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08038 DbFreeRow(row); 08039 return status; 08040 } 08041 08042 /* other-> move to dead */ 08043 sql1 = DusInit("dnsseckeys"); 08044 DusSetString(&sql1, "DEAD", datetime, 0); 08045 DusSetInt(&sql1, "state", KSM_STATE_DEAD, 1); 08046 08047 DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 08048 DusConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_ACTIVE, 1); 08049 DusEnd(&sql1); 08050 status = DbExecuteSqlNoResult(DbHandle(), sql1); 08051 DusFree(sql1); 08052 08053 /* Report any errors */ 08054 if (status != 0) { 08055 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08056 DbFreeRow(row); 08057 return status; 08058 } 08059 08060 /* Promote any standby keys if we need to, i.e. we retired a KSK 08061 and there is nothing able to take over from it */ 08062 if (temp_type == KSM_TYPE_KSK) { 08063 /* find each zone in turn */ 08064 /* Depressingly MySQL can't run the following sql; so we need 08065 to build it by parts... There has to be a better way to do 08066 this. 08067 size = snprintf(sql2, KSM_SQL_SIZE, "update dnsseckeys set state = %d where state = %d and zone_id in (select zone_id from dnsseckeys where retire = \"%s\" and keypair_id = %d) and zone_id not in (select zone_id from KEYDATA_VIEW where policy_id = %d and keytype = %d and state in (%d,%d))", KSM_STATE_KEYPUBLISH, KSM_STATE_DSREADY, datetime, temp_id, policy_id, KSM_TYPE_KSK, KSM_STATE_PUBLISH, KSM_STATE_READY); */ 08068 08069 /* First INSQL: select zone_id from dnsseckeys where retire = "DATETIME" and keypair_id = temp_id*/ 08070 08071 size = snprintf(sql2, KSM_SQL_SIZE, "select zone_id from dnsseckeys where retire = \"%s\" and keypair_id = %d", datetime, temp_id); 08072 status = DbExecuteSql(DbHandle(), sql2, &result2); 08073 if (status == 0) { 08074 status = DbFetchRow(result2, &row2); 08075 while (status == 0) { 08076 /* Got a row, print it */ 08077 DbInt(row2, 0, &temp_zone_id); 08078 08079 if (j != 0) { 08080 StrAppend(&insql1, ","); 08081 } 08082 snprintf(buffer, sizeof(buffer), "%d", temp_zone_id); 08083 StrAppend(&insql1, buffer); 08084 j++; 08085 08086 status = DbFetchRow(result2, &row2); 08087 } 08088 08089 /* Convert EOF status to success */ 08090 08091 if (status == -1) { 08092 status = 0; 08093 } 08094 08095 DbFreeResult(result2); 08096 } 08097 08098 /* Second INSQL: select zone_id from KEYDATA_VIEW where policy_id = policy_id and keytype = KSK and state in (publish,ready) */ 08099 08100 size = snprintf(sql2, KSM_SQL_SIZE, "select zone_id from KEYDATA_VIEW where policy_id = %d and keytype = %d and state in (%d,%d)", policy_id, KSM_TYPE_KSK, KSM_STATE_PUBLISH, KSM_STATE_READY); 08101 j=0; 08102 status = DbExecuteSql(DbHandle(), sql2, &result3); 08103 if (status == 0) { 08104 status = DbFetchRow(result3, &row2); 08105 while (status == 0) { 08106 /* Got a row, print it */ 08107 DbInt(row2, 0, &temp_zone_id); 08108 08109 if (j != 0) { 08110 StrAppend(&insql2, ","); 08111 } 08112 snprintf(buffer, sizeof(buffer), "%d", temp_zone_id); 08113 StrAppend(&insql2, buffer); 08114 j++; 08115 08116 status = DbFetchRow(result3, &row2); 08117 } 08118 08119 /* Convert EOF status to success */ 08120 08121 if (status == -1) { 08122 status = 0; 08123 } 08124 08125 DbFreeResult(result3); 08126 } 08127 DbFreeRow(row2); 08128 08129 /* Finally we can do the update */ 08130 size = snprintf(sql2, KSM_SQL_SIZE, "update dnsseckeys set state = %d where state = %d and zone_id in (%s) and zone_id not in (%s)", KSM_STATE_KEYPUBLISH, KSM_STATE_DSREADY, insql1, insql2); 08131 08132 /* Quick check that we didn't run out of space */ 08133 if (size < 0 || size >= KSM_SQL_SIZE) { 08134 printf("Couldn't construct SQL to promote standby key\n"); 08135 DbFreeRow(row); 08136 return -1; 08137 } 08138 08139 status = DbExecuteSqlNoResult(DbHandle(), sql2); 08140 08141 /* Report any errors */ 08142 if (status != 0) { 08143 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08144 DbFreeRow(row); 08145 return status; 08146 } 08147 } 08148 08149 /* NEXT KEY */ 08150 status = DbFetchRow(result1, &row); 08151 } 08152 08153 /* Convert EOF status to success */ 08154 if (status == -1) { 08155 status = 0; 08156 } 08157 DbFreeResult(result1); 08158 } 08159 DqsFree(sql); 08160 DbFreeRow(row); 08161 08162 StrFree(datetime); 08163 08164 return status; 08165 } 08166 08167 int get_policy_name_from_id(KSM_ZONE *zone) 08168 { 08169 int where = 0; /* WHERE clause value */ 08170 char* sql = NULL; /* SQL query */ 08171 DB_RESULT result; /* Handle converted to a result object */ 08172 DB_ROW row = NULL; /* Row data */ 08173 int status = 0; /* Status return */ 08174 08175 /* Construct the query */ 08176 08177 sql = DqsSpecifyInit("policies","id, name"); 08178 DqsConditionInt(&sql, "ID", DQS_COMPARE_EQ, zone->policy_id, where++); 08179 DqsOrderBy(&sql, "id"); 08180 08181 /* Execute query and free up the query string */ 08182 status = DbExecuteSql(DbHandle(), sql, &result); 08183 DqsFree(sql); 08184 08185 if (status != 0) 08186 { 08187 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08188 DbFreeResult(result); 08189 return status; 08190 } 08191 08192 /* Get the next row from the data */ 08193 status = DbFetchRow(result, &row); 08194 if (status == 0) { 08195 DbStringBuffer(row, DB_POLICY_NAME, zone->policy_name, KSM_NAME_LENGTH*sizeof(char)); 08196 } 08197 else if (status == -1) {} 08198 /* No rows to return (but no error) */ 08199 else { 08200 printf("SQL failed: %s\n", DbErrmsg(DbHandle())); 08201 return status; 08202 } 08203 08204 DbFreeRow(row); 08205 DbFreeResult(result); 08206 return status; 08207 } 08208 08209 int append_zone(xmlDocPtr doc, KSM_ZONE *zone) 08210 { 08211 xmlNodePtr root; 08212 xmlNodePtr zone_node; 08213 xmlNodePtr adapters_node; 08214 xmlNodePtr input_node; 08215 xmlNodePtr output_node; 08216 08217 root = xmlDocGetRootElement(doc); 08218 if (root == NULL) { 08219 fprintf(stderr,"empty document\n"); 08220 return(1); 08221 } 08222 if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) { 08223 fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList"); 08224 return(1); 08225 } 08226 08227 zone_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Zone", NULL); 08228 (void) xmlNewProp(zone_node, (const xmlChar *)"name", (const xmlChar *)zone->name); 08229 08230 /* Policy */ 08231 (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Policy", (const xmlChar *)zone->policy_name); 08232 08233 /* SignConf */ 08234 (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)zone->signconf); 08235 08236 /* Adapters */ 08237 adapters_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Adapters", NULL); 08238 /* Input */ 08239 input_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Input", NULL); 08240 (void) xmlNewTextChild(input_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->input); 08241 /* Output */ 08242 output_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Output", NULL); 08243 (void) xmlNewTextChild(output_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->output); 08244 08245 08246 return(0); 08247 }