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

Generated on Fri Nov 23 00:48:29 2007 for ldns by  doxygen 1.5.3-20071008