1 /*	$NetBSD: zkt-ls.c,v 1.1.1.1 2015/07/08 15:37:48 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 
67 extern  int	optopt;
68 extern  int	opterr;
69 extern  int	optind;
70 extern  char	*optarg;
71 const	char	*progname;
72 
73 char	*labellist = NULL;
74 
75 int	headerflag = 1;
76 int	ageflag = 0;
77 int	lifetime = 0;
78 int	lifetimeflag = 0;
79 int	timeflag = 1;
80 int	exptimeflag = 0;
81 int	pathflag = 0;
82 int	kskflag = 1;
83 int	zskflag = 1;
84 int	ljustflag = 0;
85 int	subdomain_before_parent = 1;
86 
87 static	int	dirflag = 0;
88 static	int	recflag = RECURSIVE;
89 static	int	trustedkeyflag = 0;
90 static	int	managedkeyflag = 0;
91 static	const	char	*view = "";
92 static	const	char	*term = NULL;
93 
94 #if defined(COLOR_MODE) && COLOR_MODE
95 # define	short_options	":HKTMV:afC::c:O:dhkLl:prstez"
96 #else
97 # define	short_options	":HKTMV:af:c:O:dhkLl:prstez"
98 #endif
99 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
100 static struct option long_options[] = {
101 	{"list-dnskeys",	no_argument, NULL, 'K'},
102 	{"list-trustedkeys",	no_argument, NULL, 'T'},
103 	{"list-managedkeys",	no_argument, NULL, 'M'},
104 	{"ksk",			no_argument, NULL, 'k'},
105 	{"zsk",			no_argument, NULL, 'z'},
106 	{"age",			no_argument, NULL, 'a'},
107 	{"lifetime",		no_argument, NULL, 'f'},
108 	{"time",		no_argument, NULL, 't'},
109 	{"expire",		no_argument, NULL, 'e'},
110 	{"recursive",		no_argument, NULL, 'r'},
111 	{"leftjust",		no_argument, NULL, 'L'},
112 	{"label-list",		no_argument, NULL, 'l'},
113 	{"path",		no_argument, NULL, 'p'},
114 	{"sort",		no_argument, NULL, 's'},
115 	{"subdomain",		no_argument, NULL, 's'},
116 	{"nohead",		no_argument, NULL, 'h'},
117 	{"directory",		no_argument, NULL, 'd'},
118 #if defined(COLOR_MODE) && COLOR_MODE
119 	{"color",		optional_argument, NULL, 'C'},
120 #endif
121 	{"config",		required_argument, NULL, 'c'},
122 	{"option",		required_argument, NULL, 'O'},
123 	{"config-option",	required_argument, NULL, 'O'},
124 	{"view",		required_argument, NULL, 'V' },
125 	{"help",		no_argument, NULL, 'H'},
126 	{0, 0, 0, 0}
127 };
128 #endif
129 
130 static	int	parsedirectory (const char *dir, dki_t **listp, int sub_before);
131 static	void	parsefile (const char *file, dki_t **listp, int sub_before);
132 static	void    usage (char *mesg, zconf_t *cp);
133 
setglobalflags(zconf_t * config)134 static	void	setglobalflags (zconf_t *config)
135 {
136 	recflag = config->recursive;
137 	ageflag = config->printage;
138 	timeflag = config->printtime;
139 	ljustflag = config->ljust;
140 	term = config->colorterm;
141 	if ( term && *term == '\0' )
142 		term = getenv ("TERM");
143 }
144 
main(int argc,char * argv[])145 int	main (int argc, char *argv[])
146 {
147 	dki_t	*data = NULL;
148 	int	c;
149 	int	opt_index;
150 	int	action;
151 	const	char	*file;
152 	const	char	*defconfname = NULL;
153 	char	*p;
154 	char	str[254+1];
155 	zconf_t	*config;
156 
157 	progname = *argv;
158 	if ( (p = strrchr (progname, '/')) )
159 		progname = ++p;
160 	view = getnameappendix (progname, "zkt-ls");
161 
162 	defconfname = getdefconfname (view);
163 	config = loadconfig ("", (zconf_t *)NULL);	/* load built in config */
164 	if ( fileexist (defconfname) )			/* load default config file */
165 		config = loadconfig (defconfname, config);
166 	if ( config == NULL )
167 		fatal ("Out of memory\n");
168 	setglobalflags (config);
169 
170         opterr = 0;
171 	opt_index = 0;
172 	action = 0;
173 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
174 	while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 )
175 #else
176 	while ( (c = getopt (argc, argv, short_options)) != -1 )
177 #endif
178 	{
179 		switch ( c )
180 		{
181 #if defined(COLOR_MODE) && COLOR_MODE
182 		case 'C':	/* color mode on; optional with terminal name */
183 			if ( optarg )
184 				term = optarg;
185 			else
186 				term = getenv ("TERM");
187 			break;
188 #endif
189 		case 'M':
190 			managedkeyflag = 1;
191 			subdomain_before_parent = 0;
192 			zskflag = pathflag = 0;
193 			action = c;
194 			break;
195 		case 'T':
196 			trustedkeyflag = 1;
197 			subdomain_before_parent = 0;
198 			zskflag = pathflag = 0;
199 			/* fall through */
200 		case 'H':
201 		case 'K':
202 		case 'Z':
203 			action = c;
204 			break;
205 		case 'a':		/* age */
206 			ageflag = !ageflag;
207 			break;
208 		case 'f':		/* key lifetime */
209 			lifetimeflag = !lifetimeflag;
210 			break;
211 		case 'V':		/* view name */
212 			view = optarg;
213 			defconfname = getdefconfname (view);
214 			if ( fileexist (defconfname) )		/* load default config file */
215 				config = loadconfig (defconfname, config);
216 			if ( config == NULL )
217 				fatal ("Out of memory\n");
218 			setglobalflags (config);
219 			break;
220 		case 'c':
221 			config = loadconfig (optarg, config);
222 			setglobalflags (config);
223 			checkconfig (config);
224 			break;
225 		case 'O':		/* read option from commandline */
226 			config = loadconfig_fromstr (optarg, config);
227 			setglobalflags (config);
228 			checkconfig (config);
229 			break;
230 		case 'd':		/* ignore directory arg */
231 			dirflag = 1;
232 			break;
233 		case 'h':		/* print no headline */
234 			headerflag = 0;
235 			break;
236 		case 'k':		/* ksk only */
237 			zskflag = 0;
238 			break;
239 		case 'L':		/* ljust */
240 			ljustflag = !ljustflag;
241 			break;
242 		case 'l':		/* label list */
243 			labellist = prepstrlist (optarg, LISTDELIM);
244 			if ( labellist == NULL )
245 				fatal ("Out of memory\n");
246 			break;
247 		case 'p':		/* print path */
248 			pathflag = 1;
249 			break;
250 		case 'r':		/* switch recursive flag */
251 			recflag = !recflag;
252 			break;
253 		case 's':		/* switch subdomain sorting flag */
254 			subdomain_before_parent = !subdomain_before_parent;
255 			break;
256 		case 't':		/* time */
257 			timeflag = !timeflag;
258 			break;
259 		case 'e':		/* expire time */
260 			exptimeflag = !exptimeflag;
261 			break;
262 		case 'z':		/* zsk only */
263 			kskflag = 0;
264 			break;
265 		case ':':
266 			snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n",
267 										optopt);
268 			usage (str, config);
269 			break;
270 		case '?':
271 			if ( isprint (optopt) )
272 				snprintf (str, sizeof(str), "Unknown option \"-%c\".\n",
273 										optopt);
274 			else
275 				snprintf (str, sizeof (str), "Unknown option char \\x%x.\n",
276 										optopt);
277 			usage (str, config);
278 			break;
279 		default:
280 			abort();
281 		}
282 	}
283 
284 	if ( kskflag == 0 && zskflag == 0 )
285 		kskflag = zskflag = 1;
286 
287 	tc_init (stdout, term);
288 
289 	c = optind;
290 	do {
291 		if ( c >= argc )		/* no args left */
292 			file = config->zonedir;	/* use default directory */
293 		else
294 			file = argv[c++];
295 
296 		if ( is_directory (file) )
297 			parsedirectory (file, &data, subdomain_before_parent);
298 		else
299 			parsefile (file, &data, subdomain_before_parent);
300 
301 	}  while ( c < argc );	/* for all arguments */
302 
303 	switch ( action )
304 	{
305 	case 'H':
306 		usage ("", config);
307 	case 'K':
308 		zkt_list_dnskeys (data);
309 		break;
310 	case 'T':
311 		zkt_list_trustedkeys (data);
312 		break;
313 	case 'M':
314 		zkt_list_managedkeys (data);
315 		break;
316 	default:
317 		zkt_list_keys (data);
318 	}
319 
320 	tc_end (stdout, term);
321 
322 	return 0;
323 }
324 
325 # define	sopt_usage(mesg, value)	fprintf (stderr, mesg, value)
326 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
327 # define	lopt_usage(mesg, value)	fprintf (stderr, mesg, value)
328 # define	loptstr(lstr, sstr)	lstr
329 #else
330 # define	lopt_usage(mesg, value)
331 # define	loptstr(lstr, sstr)	sstr
332 #endif
usage(char * mesg,zconf_t * cp)333 static	void    usage (char *mesg, zconf_t *cp)
334 {
335         fprintf (stderr, "Secure DNS Zone Key Tool %s\n", ZKT_VERSION);
336         fprintf (stderr, "\n");
337 
338         fprintf (stderr, "List keys in current or given directory (-r for recursive mode)\n");
339         sopt_usage ("\tusage: %s [-adefhkLprtzC] [-c config] [file|dir ...]\n", progname);
340         fprintf (stderr, "\n");
341         fprintf (stderr, "List public part of keys in DNSKEY RR format\n");
342         sopt_usage ("\tusage: %s -K [-dhkrz] [-c config] [file|dir ...]\n", progname);
343         lopt_usage ("\tusage: %s --list-dnskeys [-dhkzr] [-c config] [file|dir ...]\n", progname);
344         fprintf (stderr, "\n");
345         fprintf (stderr, "List keys (output is suitable for trusted-keys section)\n");
346         sopt_usage ("\tusage: %s -T [-dhrz] [-c config] [file|dir ...]\n", progname);
347         lopt_usage ("\tusage: %s --list-trustedkeys [-dhzr] [-c config] [file|dir ...]\n", progname);
348         fprintf (stderr, "\n");
349         fprintf (stderr, "List managed keys (output is suitable for managed-keys section)\n");
350         sopt_usage ("\tusage: %s -M [-dhrz] [-c config] [file|dir ...]\n", progname);
351         lopt_usage ("\tusage: %s --list-managedkeys [-dhzr] [-c config] [file|dir ...]\n", progname);
352         fprintf (stderr, "\n");
353 
354         fprintf (stderr, "General options \n");
355         fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", ""));
356 	fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE);
357         fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", ""));
358 	fprintf (stderr, "\t\t read config options from commandline\n");
359         fprintf (stderr, "\t-h%s\t no headline or trusted/managed-key section header/trailer in -T/-M mode\n", loptstr (", --nohead", "\t"));
360         fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t"));
361         fprintf (stderr, "\t-L%s\t print the domain name left justified (default: %s)\n", loptstr (", --leftjust", "\t"), ljustflag ? "on": "off");
362         fprintf (stderr, "\t-l list%s", loptstr (", --label=\"list\"\n\t", ""));
363         fprintf (stderr, "\t\t print out only zone keys from the given domain list\n");
364         fprintf (stderr, "\t-C[term]%s", loptstr (", --color[=\"term\"]\n\t", ""));
365         fprintf (stderr, "\t\t turn color mode on \n");
366         fprintf (stderr, "\t-p%s\t show path of keyfile / create key in current directory\n", loptstr (", --path", "\t"));
367         fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off");
368         fprintf (stderr, "\t-s%s\t change sorting of subdomains\n", loptstr(", --subdomain", "\t"));
369         fprintf (stderr, "\t-a%s\t print age of key (default: %s)\n", loptstr (", --age", "\t"), ageflag ? "on": "off");
370         fprintf (stderr, "\t-t%s\t print key generation time (default: %s)\n", loptstr (", --time", "\t"),
371 								timeflag ? "on": "off");
372         fprintf (stderr, "\t-e%s\t print key expiration time\n", loptstr (", --expire", "\t"));
373         fprintf (stderr, "\t-f%s\t print key lifetime\n", loptstr (", --lifetime", "\t"));
374         fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t"));
375         fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t"));
376         if ( mesg && *mesg )
377                 fprintf (stderr, "%s\n", mesg);
378         exit (1);
379 }
380 
parsedirectory(const char * dir,dki_t ** listp,int sub_before)381 static	int	parsedirectory (const char *dir, dki_t **listp, int sub_before)
382 {
383 	dki_t	*dkp;
384 	DIR	*dirp;
385 	struct  dirent  *dentp;
386 	char	path[MAX_PATHSIZE+1];
387 
388 	if ( dirflag )
389 		return 0;
390 
391 	dbg_val ("directory: opendir(%s)\n", dir);
392 	if ( (dirp = opendir (dir)) == NULL )
393 		return 0;
394 
395 	while ( (dentp = readdir (dirp)) != NULL )
396 	{
397 		if ( is_dotfilename (dentp->d_name) )
398 			continue;
399 
400 		dbg_val ("directory: check %s\n", dentp->d_name);
401 		pathname (path, sizeof (path), dir, dentp->d_name, NULL);
402 		if ( is_directory (path) && recflag )
403 		{
404 			dbg_val ("directory: recursive %s\n", path);
405 			parsedirectory (path, listp, sub_before);
406 		}
407 		else if ( is_keyfilename (dentp->d_name) )
408 			if ( (dkp = dki_read (dir, dentp->d_name)) )
409 			{
410 				// fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name);
411 #if defined (USE_TREE) && USE_TREE
412 				dki_tadd (listp, dkp, sub_before);
413 #else
414 				dki_add (listp, dkp);
415 #endif
416 			}
417 	}
418 	closedir (dirp);
419 	return 1;
420 }
421 
parsefile(const char * file,dki_t ** listp,int sub_before)422 static	void	parsefile (const char *file, dki_t **listp, int sub_before)
423 {
424 	char	path[MAX_PATHSIZE+1];
425 	dki_t	*dkp;
426 
427 	/* file arg contains path ? ... */
428 	file = splitpath (path, sizeof (path), file);	/* ... then split of */
429 
430 	if ( is_keyfilename (file) )	/* plain file name looks like DNS key file ? */
431 	{
432 		if ( (dkp = dki_read (path, file)) )	/* read DNS key file ... */
433 #if defined (USE_TREE) && USE_TREE
434 			dki_tadd (listp, dkp, sub_before);		/* ... and add to tree */
435 #else
436 			dki_add (listp, dkp);		/* ... and add to list */
437 #endif
438 		else
439 			error ("error parsing %s: (%s)\n", file, dki_geterrstr());
440 	}
441 }
442