ldns-signzone.c

Go to the documentation of this file.
00001 /*
00002  * ldns-signzone signs a zone file
00003  * 
00004  * (c) NLnet Labs, 2005
00005  * See the file LICENSE for the license
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         /* we need to know the origin before reading ksk's,
00098          * so keep an array of filenames until we know it
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                         /* try to parse YYYYMMDD first,
00116                          * if that doesn't work, it
00117                          * should be a timestamp (seconds since epoch)
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         /* read zonefile first to find origin if not specified */
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         /* read the ZSKs */
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                                 /* set times in key? they will end up
00242                                    in the rrsigs
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 }

Generated on Thu Nov 29 14:14:59 2007 for ldns by  doxygen 1.5.1