1/* $NetBSD: zkt-ls.c,v 1.2 2011/02/16 03:47:02 christos Exp $ */ 2 3/***************************************************************** 4** 5** @(#) zkt-ls.c (c) Jan 2010 Holger Zuleger hznet.de 6** 7** Secure DNS zone key tool 8** A command to list dnssec keys 9** 10** Copyright (c) 2005 - 2010, Holger Zuleger HZnet. All rights reserved. 11** 12** This software is open source. 13** 14** Redistribution and use in source and binary forms, with or without 15** modification, are permitted provided that the following conditions 16** are met: 17** 18** Redistributions of source code must retain the above copyright notice, 19** this list of conditions and the following disclaimer. 20** 21** Redistributions in binary form must reproduce the above copyright notice, 22** this list of conditions and the following disclaimer in the documentation 23** and/or other materials provided with the distribution. 24** 25** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 26** be used to endorse or promote products derived from this software without 27** specific prior written permission. 28** 29** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 33** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39** POSSIBILITY OF SUCH DAMAGE. 40** 41*****************************************************************/ 42 43# include <stdio.h> 44# include <stdlib.h> /* abort(), exit(), ... */ 45# include <string.h> 46# include <dirent.h> 47# include <assert.h> 48# include <unistd.h> 49# include <ctype.h> 50 51#ifdef HAVE_CONFIG_H 52# include <config.h> 53#endif 54# include "config_zkt.h" 55#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 56# include <getopt.h> 57#endif 58 59# include "debug.h" 60# include "misc.h" 61# include "strlist.h" 62# include "zconf.h" 63# include "dki.h" 64# include "tcap.h" 65# include "zkt.h" 66 67extern int optopt; 68extern int opterr; 69extern int optind; 70extern char *optarg; 71const char *progname; 72 73char *labellist = NULL; 74 75int headerflag = 1; 76int ageflag = 0; 77int lifetime = 0; 78int lifetimeflag = 0; 79int timeflag = 1; 80int exptimeflag = 0; 81int pathflag = 0; 82int kskflag = 1; 83int zskflag = 1; 84int ljustflag = 0; 85int subdomain_before_parent = 1; 86 87static int dirflag = 0; 88static int recflag = RECURSIVE; 89static int trustedkeyflag = 0; 90static const char *view = ""; 91static const char *term = NULL; 92 93#if defined(COLOR_MODE) && COLOR_MODE 94# define short_options ":HKTV:afC::c:O:dhkLl:prstez" 95#else 96# define short_options ":HKTV:af:c:O:dhkLl:prstez" 97#endif 98#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 99static struct option long_options[] = { 100 {"list-dnskeys", no_argument, NULL, 'K'}, 101 {"list-trustedkeys", no_argument, NULL, 'T'}, 102 {"ksk", no_argument, NULL, 'k'}, 103 {"zsk", no_argument, NULL, 'z'}, 104 {"age", no_argument, NULL, 'a'}, 105 {"lifetime", no_argument, NULL, 'f'}, 106 {"time", no_argument, NULL, 't'}, 107 {"expire", no_argument, NULL, 'e'}, 108 {"recursive", no_argument, NULL, 'r'}, 109 {"leftjust", no_argument, NULL, 'L'}, 110 {"label-list", no_argument, NULL, 'l'}, 111 {"path", no_argument, NULL, 'p'}, 112 {"sort", no_argument, NULL, 's'}, 113 {"subdomain", no_argument, NULL, 's'}, 114 {"nohead", no_argument, NULL, 'h'}, 115 {"directory", no_argument, NULL, 'd'}, 116#if defined(COLOR_MODE) && COLOR_MODE 117 {"color", optional_argument, NULL, 'C'}, 118#endif 119 {"config", required_argument, NULL, 'c'}, 120 {"option", required_argument, NULL, 'O'}, 121 {"config-option", required_argument, NULL, 'O'}, 122 {"view", required_argument, NULL, 'V' }, 123 {"help", no_argument, NULL, 'H'}, 124 {0, 0, 0, 0} 125}; 126#endif 127 128static int parsedirectory (const char *dir, dki_t **listp, int sub_before); 129static void parsefile (const char *file, dki_t **listp, int sub_before); 130static void usage (char *mesg, zconf_t *cp); 131 132static void setglobalflags (zconf_t *config) 133{ 134 recflag = config->recursive; 135 ageflag = config->printage; 136 timeflag = config->printtime; 137 ljustflag = config->ljust; 138 term = config->colorterm; 139 if ( term && *term == '\0' ) 140 term = getenv ("TERM"); 141} 142 143int main (int argc, char *argv[]) 144{ 145 dki_t *data = NULL; 146 int c; 147 int opt_index; 148 int action; 149 const char *file; 150 const char *defconfname = NULL; 151 char *p; 152 char str[254+1]; 153 zconf_t *config; 154 155 progname = *argv; 156 if ( (p = strrchr (progname, '/')) ) 157 progname = ++p; 158 view = getnameappendix (progname, "zkt-ls"); 159 160 defconfname = getdefconfname (view); 161 config = loadconfig ("", (zconf_t *)NULL); /* load built in config */ 162 if ( fileexist (defconfname) ) /* load default config file */ 163 config = loadconfig (defconfname, config); 164 if ( config == NULL ) 165 fatal ("Out of memory\n"); 166 setglobalflags (config); 167 168 opterr = 0; 169 opt_index = 0; 170 action = 0; 171#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 172 while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 ) 173#else 174 while ( (c = getopt (argc, argv, short_options)) != -1 ) 175#endif 176 { 177 switch ( c ) 178 { 179#if defined(COLOR_MODE) && COLOR_MODE 180 case 'C': /* color mode on; optional with terminal name */ 181 if ( optarg ) 182 term = optarg; 183 else 184 term = getenv ("TERM"); 185 break; 186#endif 187 case 'T': 188 trustedkeyflag = 1; 189 subdomain_before_parent = 0; 190 zskflag = pathflag = 0; 191 /* fall through */ 192 case 'H': 193 case 'K': 194 case 'Z': 195 action = c; 196 break; 197 case 'a': /* age */ 198 ageflag = !ageflag; 199 break; 200 case 'f': /* key lifetime */ 201 lifetimeflag = !lifetimeflag; 202 break; 203 case 'V': /* view name */ 204 view = optarg; 205 defconfname = getdefconfname (view); 206 if ( fileexist (defconfname) ) /* load default config file */ 207 config = loadconfig (defconfname, config); 208 if ( config == NULL ) 209 fatal ("Out of memory\n"); 210 setglobalflags (config); 211 break; 212 case 'c': 213 config = loadconfig (optarg, config); 214 setglobalflags (config); 215 checkconfig (config); 216 break; 217 case 'O': /* read option from commandline */ 218 config = loadconfig_fromstr (optarg, config); 219 setglobalflags (config); 220 checkconfig (config); 221 break; 222 case 'd': /* ignore directory arg */ 223 dirflag = 1; 224 break; 225 case 'h': /* print no headline */ 226 headerflag = 0; 227 break; 228 case 'k': /* ksk only */ 229 zskflag = 0; 230 break; 231 case 'L': /* ljust */ 232 ljustflag = !ljustflag; 233 break; 234 case 'l': /* label list */ 235 labellist = prepstrlist (optarg, LISTDELIM); 236 if ( labellist == NULL ) 237 fatal ("Out of memory\n"); 238 break; 239 case 'p': /* print path */ 240 pathflag = 1; 241 break; 242 case 'r': /* switch recursive flag */ 243 recflag = !recflag; 244 break; 245 case 's': /* switch subdomain sorting flag */ 246 subdomain_before_parent = !subdomain_before_parent; 247 break; 248 case 't': /* time */ 249 timeflag = !timeflag; 250 break; 251 case 'e': /* expire time */ 252 exptimeflag = !exptimeflag; 253 break; 254 case 'z': /* zsk only */ 255 kskflag = 0; 256 break; 257 case ':': 258 snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n", 259 optopt); 260 usage (str, config); 261 break; 262 case '?': 263 if ( isprint (optopt) ) 264 snprintf (str, sizeof(str), "Unknown option \"-%c\".\n", 265 optopt); 266 else 267 snprintf (str, sizeof (str), "Unknown option char \\x%x.\n", 268 optopt); 269 usage (str, config); 270 break; 271 default: 272 abort(); 273 } 274 } 275 276 if ( kskflag == 0 && zskflag == 0 ) 277 kskflag = zskflag = 1; 278 279 tc_init (stdout, term); 280 281 c = optind; 282 do { 283 if ( c >= argc ) /* no args left */ 284 file = config->zonedir; /* use default directory */ 285 else 286 file = argv[c++]; 287 288 if ( is_directory (file) ) 289 parsedirectory (file, &data, subdomain_before_parent); 290 else 291 parsefile (file, &data, subdomain_before_parent); 292 293 } while ( c < argc ); /* for all arguments */ 294 295 switch ( action ) 296 { 297 case 'H': 298 usage ("", config); 299 case 'K': 300 zkt_list_dnskeys (data); 301 break; 302 case 'T': 303 zkt_list_trustedkeys (data); 304 break; 305 default: 306 zkt_list_keys (data); 307 } 308 309 tc_end (stdout, term); 310 311 return 0; 312} 313 314# define sopt_usage(mesg, value) fprintf (stderr, mesg, value) 315#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 316# define lopt_usage(mesg, value) fprintf (stderr, mesg, value) 317# define loptstr(lstr, sstr) lstr 318#else 319# define lopt_usage(mesg, value) 320# define loptstr(lstr, sstr) sstr 321#endif 322static void usage (char *mesg, zconf_t *cp) 323{ 324 fprintf (stderr, "Secure DNS Zone Key Tool %s\n", ZKT_VERSION); 325 fprintf (stderr, "\n"); 326 327 fprintf (stderr, "List keys in current or given directory (-r for recursive mode)\n"); 328 sopt_usage ("\tusage: %s [-adefhkLprtzC] [-c config] [file|dir ...]\n", progname); 329 fprintf (stderr, "\n"); 330 fprintf (stderr, "List public part of keys in DNSKEY RR format\n"); 331 sopt_usage ("\tusage: %s -K [-dhkrz] [-c config] [file|dir ...]\n", progname); 332 lopt_usage ("\tusage: %s --list-dnskeys [-dhkzr] [-c config] [file|dir ...]\n", progname); 333 fprintf (stderr, "\n"); 334 fprintf (stderr, "List keys (output is suitable for trusted-keys section)\n"); 335 sopt_usage ("\tusage: %s -T [-dhrz] [-c config] [file|dir ...]\n", progname); 336 lopt_usage ("\tusage: %s --list-trustedkeys [-dhzr] [-c config] [file|dir ...]\n", progname); 337 fprintf (stderr, "\n"); 338 339 fprintf (stderr, "General options \n"); 340 fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", "")); 341 fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE); 342 fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", "")); 343 fprintf (stderr, "\t\t read config options from commandline\n"); 344 fprintf (stderr, "\t-h%s\t no headline or trusted-key section header/trailer in -T mode\n", loptstr (", --nohead", "\t")); 345 fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t")); 346 fprintf (stderr, "\t-L%s\t print the domain name left justified (default: %s)\n", loptstr (", --leftjust", "\t"), ljustflag ? "on": "off"); 347 fprintf (stderr, "\t-l list%s", loptstr (", --label=\"list\"\n\t", "")); 348 fprintf (stderr, "\t\t print out only zone keys from the given domain list\n"); 349 fprintf (stderr, "\t-C[term]%s", loptstr (", --color[=\"term\"]\n\t", "")); 350 fprintf (stderr, "\t\t turn color mode on \n"); 351 fprintf (stderr, "\t-p%s\t show path of keyfile / create key in current directory\n", loptstr (", --path", "\t")); 352 fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off"); 353 fprintf (stderr, "\t-s%s\t change sorting of subdomains\n", loptstr(", --subdomain", "\t")); 354 fprintf (stderr, "\t-a%s\t print age of key (default: %s)\n", loptstr (", --age", "\t"), ageflag ? "on": "off"); 355 fprintf (stderr, "\t-t%s\t print key generation time (default: %s)\n", loptstr (", --time", "\t"), 356 timeflag ? "on": "off"); 357 fprintf (stderr, "\t-e%s\t print key expiration time\n", loptstr (", --expire", "\t")); 358 fprintf (stderr, "\t-f%s\t print key lifetime\n", loptstr (", --lifetime", "\t")); 359 fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t")); 360 fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t")); 361 if ( mesg && *mesg ) 362 fprintf (stderr, "%s\n", mesg); 363 exit (1); 364} 365 366static int parsedirectory (const char *dir, dki_t **listp, int sub_before) 367{ 368 dki_t *dkp; 369 DIR *dirp; 370 struct dirent *dentp; 371 char path[MAX_PATHSIZE+1]; 372 373 if ( dirflag ) 374 return 0; 375 376 dbg_val ("directory: opendir(%s)\n", dir); 377 if ( (dirp = opendir (dir)) == NULL ) 378 return 0; 379 380 while ( (dentp = readdir (dirp)) != NULL ) 381 { 382 if ( is_dotfilename (dentp->d_name) ) 383 continue; 384 385 dbg_val ("directory: check %s\n", dentp->d_name); 386 pathname (path, sizeof (path), dir, dentp->d_name, NULL); 387 if ( is_directory (path) && recflag ) 388 { 389 dbg_val ("directory: recursive %s\n", path); 390 parsedirectory (path, listp, sub_before); 391 } 392 else if ( is_keyfilename (dentp->d_name) ) 393 if ( (dkp = dki_read (dir, dentp->d_name)) ) 394 { 395 // fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name); 396#if defined (USE_TREE) && USE_TREE 397 dki_tadd (listp, dkp, sub_before); 398#else 399 dki_add (listp, dkp); 400#endif 401 } 402 } 403 closedir (dirp); 404 return 1; 405} 406 407static void parsefile (const char *file, dki_t **listp, int sub_before) 408{ 409 char path[MAX_PATHSIZE+1]; 410 dki_t *dkp; 411 412 /* file arg contains path ? ... */ 413 file = splitpath (path, sizeof (path), file); /* ... then split of */ 414 415 if ( is_keyfilename (file) ) /* plain file name looks like DNS key file ? */ 416 { 417 if ( (dkp = dki_read (path, file)) ) /* read DNS key file ... */ 418#if defined (USE_TREE) && USE_TREE 419 dki_tadd (listp, dkp, sub_before); /* ... and add to tree */ 420#else 421 dki_add (listp, dkp); /* ... and add to list */ 422#endif 423 else 424 error ("error parsing %s: (%s)\n", file, dki_geterrstr()); 425 } 426} 427