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