00001
00002
00003
00004
00005
00006
00007
00008 #include "config.h"
00009 #include <stdlib.h>
00010 #include <unistd.h>
00011
00012 #include <errno.h>
00013
00014 #include <time.h>
00015
00016 #include <ldns/ldns.h>
00017
00018 #define MAX_FILENAME_LEN 250
00019
00020 #ifdef HAVE_SSL
00021 #include <openssl/err.h>
00022 #endif
00023
00024 void
00025 usage(FILE *fp, const char *prog) {
00026 fprintf(fp, "%s [OPTIONS] zonefile key [key [key]]\n", prog);
00027 fprintf(fp, " signs the zone with the given key(s)\n");
00028 fprintf(fp, " -e <date>\texpiration date\n");
00029 fprintf(fp, " -f <file>\toutput zone to file (default <name>.signed)\n");
00030 fprintf(fp, " -i <date>\tinception date\n");
00031 fprintf(fp, " -o <domain>\torigin for the zone\n");
00032 fprintf(fp, " -v\t\tprint version and exit\n");
00033 fprintf(fp, " keys must be specified by their base name: K<name>+<alg>+<id>\n");
00034 fprintf(fp, " both a .key and .private file must present\n");
00035 fprintf(fp, " A date can be a timestamp (seconds since the epoch), or of\n the form <YYYYMMdd[hhmmss]>\n");
00036 }
00037
00038 void check_tm(struct tm tm)
00039 {
00040 if (tm.tm_year < 70) {
00041 fprintf(stderr, "You cannot specify dates before 1970\n");
00042 exit(EXIT_FAILURE);
00043 }
00044 if (tm.tm_mon < 0 || tm.tm_mon > 11) {
00045 fprintf(stderr, "The month must be in the range 1 to 12\n");
00046 exit(EXIT_FAILURE);
00047 }
00048 if (tm.tm_mday < 1 || tm.tm_mday > 31) {
00049 fprintf(stderr, "The day must be in the range 1 to 31\n");
00050 exit(EXIT_FAILURE);
00051 }
00052
00053 if (tm.tm_hour < 0 || tm.tm_hour > 23) {
00054 fprintf(stderr, "The hour must be in the range 0-23\n");
00055 exit(EXIT_FAILURE);
00056 }
00057
00058 if (tm.tm_min < 0 || tm.tm_min > 59) {
00059 fprintf(stderr, "The minute must be in the range 0-59\n");
00060 exit(EXIT_FAILURE);
00061 }
00062
00063 if (tm.tm_sec < 0 || tm.tm_sec > 59) {
00064 fprintf(stderr, "The second must be in the range 0-59\n");
00065 exit(EXIT_FAILURE);
00066 }
00067
00068 }
00069
00070 int
00071 main(int argc, char *argv[])
00072 {
00073 const char *zonefile_name;
00074 FILE *zonefile = NULL;
00075 uint16_t default_ttl = LDNS_DEFAULT_TTL;
00076 int line_nr = 0;
00077 int c;
00078 int argi;
00079
00080 ldns_zone *orig_zone;
00081 ldns_rr_list *orig_rrs = NULL;
00082 ldns_rr *orig_soa = NULL;
00083 ldns_zone *signed_zone;
00084
00085 const char *keyfile_name_base;
00086 char *keyfile_name;
00087 FILE *keyfile = NULL;
00088 ldns_key *key = NULL;
00089 ldns_rr *pubkey;
00090 ldns_key_list *keys;
00091 ldns_status s;
00092
00093
00094 char *outputfile_name = NULL;
00095 FILE *outputfile;
00096
00097
00098
00099
00100 struct tm tm;
00101 uint32_t inception;
00102 uint32_t expiration;
00103 ldns_rdf *origin = NULL;
00104 uint16_t ttl = 0;
00105 ldns_rr_class class = LDNS_RR_CLASS_IN;
00106
00107 char *prog = strdup(argv[0]);
00108
00109 inception = 0;
00110 expiration = 0;
00111
00112 while ((c = getopt(argc, argv, "e:f:i:o:v")) != -1) {
00113 switch (c) {
00114 case 'e':
00115
00116
00117
00118
00119 memset(&tm, 0, sizeof(tm));
00120
00121 if (strlen(optarg) == 8 &&
00122 sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday)
00123 ) {
00124 tm.tm_year -= 1900;
00125 tm.tm_mon--;
00126 check_tm(tm);
00127 expiration = (uint32_t) mktime_from_utc(&tm);
00128 } else if (strlen(optarg) == 14 &&
00129 sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)
00130 ) {
00131 tm.tm_year -= 1900;
00132 tm.tm_mon--;
00133 check_tm(tm);
00134 expiration = (uint32_t) mktime_from_utc(&tm);
00135 } else {
00136 expiration = (uint32_t) atol(optarg);
00137 }
00138 break;
00139 case 'f':
00140 outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN);
00141 strncpy(outputfile_name, optarg, MAX_FILENAME_LEN);
00142 break;
00143 case 'i':
00144 memset(&tm, 0, sizeof(tm));
00145
00146 if (strlen(optarg) == 8 &&
00147 sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday)
00148 ) {
00149 tm.tm_year -= 1900;
00150 tm.tm_mon--;
00151 check_tm(tm);
00152 inception = (uint32_t) mktime_from_utc(&tm);
00153 } else if (strlen(optarg) == 14 &&
00154 sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)
00155 ) {
00156 tm.tm_year -= 1900;
00157 tm.tm_mon--;
00158 check_tm(tm);
00159 inception = (uint32_t) mktime_from_utc(&tm);
00160 } else {
00161 inception = (uint32_t) atol(optarg);
00162 }
00163 break;
00164 case 'o':
00165 if (ldns_str2rdf_dname(&origin, optarg) != LDNS_STATUS_OK) {
00166 fprintf(stderr, "Bad origin, not a correct domain name\n");
00167 usage(stderr, prog);
00168 exit(EXIT_FAILURE);
00169 }
00170
00171 break;
00172 case 'v':
00173 printf("zone signer version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
00174 exit(EXIT_SUCCESS);
00175 break;
00176 default:
00177 usage(stderr, prog);
00178 exit(EXIT_SUCCESS);
00179 }
00180 }
00181
00182 argc -= optind;
00183 argv += optind;
00184
00185 if (argc < 2) {
00186 usage(stdout, prog);
00187 exit(EXIT_FAILURE);
00188 } else {
00189 zonefile_name = argv[0];
00190 }
00191
00192
00193
00194 zonefile = fopen(zonefile_name, "r");
00195
00196 if (!zonefile) {
00197 fprintf(stderr, "Error: unable to read %s (%s)\n", zonefile_name, strerror(errno));
00198 exit(EXIT_FAILURE);
00199 } else {
00200 s = ldns_zone_new_frm_fp_l(&orig_zone, zonefile, origin, ttl, class, &line_nr);
00201 if (s != LDNS_STATUS_OK) {
00202 fprintf(stderr, "Zone not read, error: %s at %s line %d\n",
00203 ldns_get_errorstr_by_id(s),
00204 zonefile_name, line_nr);
00205 exit(EXIT_FAILURE);
00206 } else {
00207 orig_soa = ldns_zone_soa(orig_zone);
00208 if (!orig_soa) {
00209 fprintf(stderr, "Error reading zonefile: missing SOA record\n");
00210 exit(EXIT_FAILURE);
00211 }
00212 orig_rrs = ldns_zone_rrs(orig_zone);
00213 if (!orig_rrs) {
00214 fprintf(stderr, "Error reading zonefile: no resource records\n");
00215 exit(EXIT_FAILURE);
00216 }
00217 }
00218 fclose(zonefile);
00219 }
00220
00221 if (!origin) {
00222 origin = ldns_rr_owner(orig_soa);
00223 }
00224
00225 keys = ldns_key_list_new();
00226
00227
00228 argi = 1;
00229 while (argi < argc) {
00230 keyfile_name_base = argv[argi];
00231 keyfile_name = LDNS_XMALLOC(char, strlen(keyfile_name_base) + 9);
00232 snprintf(keyfile_name, strlen(keyfile_name_base) + 9, "%s.private", keyfile_name_base);
00233 keyfile = fopen(keyfile_name, "r");
00234 line_nr = 0;
00235 if (!keyfile) {
00236 fprintf(stderr, "Error: unable to read %s: %s\n", keyfile_name, strerror(errno));
00237 } else {
00238 s = ldns_key_new_frm_fp_l(&key, keyfile, &line_nr);
00239 fclose(keyfile);
00240 if (s == LDNS_STATUS_OK) {
00241
00242
00243
00244 if (expiration != 0) {
00245 ldns_key_set_expiration(key, expiration);
00246 }
00247 if (inception != 0) {
00248 ldns_key_set_inception(key, inception);
00249 }
00250
00251 LDNS_FREE(keyfile_name);
00252 keyfile_name = LDNS_XMALLOC(char, strlen(keyfile_name_base) + 5);
00253 snprintf(keyfile_name, strlen(keyfile_name_base) + 5, "%s.key", keyfile_name_base);
00254 keyfile = fopen(keyfile_name, "r");
00255 line_nr = 0;
00256 if (!keyfile) {
00257 fprintf(stderr, "Error: unable to read %s: %s\n", keyfile_name, strerror(errno));
00258 } else {
00259 if (ldns_rr_new_frm_fp_l(&pubkey, keyfile, &default_ttl, NULL, NULL, &line_nr) ==
00260 LDNS_STATUS_OK) {
00261 ldns_key_set_pubkey_owner(key, ldns_rdf_clone(ldns_rr_owner(pubkey)));
00262 ldns_key_set_flags(key, ldns_rdf2native_int16(ldns_rr_rdf(pubkey, 0)));
00263 ldns_key_set_keytag(key, ldns_calc_keytag(pubkey));
00264 }
00265 ldns_key_list_push_key(keys, key);
00266 ldns_zone_push_rr(orig_zone, ldns_rr_clone(pubkey));
00267 ldns_rr_free(pubkey);
00268 }
00269 LDNS_FREE(keyfile_name);
00270
00271 } else {
00272 fprintf(stderr, "Error reading key from %s at line %d\n", argv[argi], line_nr);
00273 }
00274 }
00275
00276 argi++;
00277 }
00278
00279 if (ldns_key_list_key_count(keys) < 1) {
00280 fprintf(stderr, "Error: no keys to sign with. Aborting.\n\n");
00281 usage(stderr, prog);
00282 exit(EXIT_FAILURE);
00283 }
00284
00285 signed_zone = ldns_zone_sign(orig_zone, keys);
00286
00287 if (!outputfile_name) {
00288 outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN);
00289 snprintf(outputfile_name, MAX_FILENAME_LEN, "%s.signed", zonefile_name);
00290 }
00291
00292 if (signed_zone) {
00293 outputfile = fopen(outputfile_name, "w");
00294 if (!outputfile) {
00295 fprintf(stderr, "Unable to open %s for writing: %s\n", outputfile_name, strerror(errno));
00296 } else {
00297 ldns_zone_print(outputfile, signed_zone);
00298 fclose(outputfile);
00299 }
00300 ldns_zone_deep_free(signed_zone);
00301 } else {
00302 fprintf(stderr, "Error signing zone.\n");
00303
00304 #ifdef HAVE_SSL
00305 if (ERR_peek_error()) {
00306 ERR_load_crypto_strings();
00307 ERR_print_errors_fp(stderr);
00308 ERR_free_strings();
00309 }
00310 #endif
00311 exit(EXIT_FAILURE);
00312 }
00313
00314 ldns_key_list_free(keys);
00315 ldns_zone_deep_free(orig_zone);
00316
00317 LDNS_FREE(outputfile_name);
00318
00319 free(prog);
00320 exit(EXIT_SUCCESS);
00321 }