1 /*	$NetBSD: misc.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $	*/
2 
3 /*****************************************************************
4 **
5 **	@(#) misc.c -- helper functions for the dnssec zone key tools
6 **
7 **	Copyright (c) Jan 2005, Holger Zuleger HZnet. All rights reserved.
8 **
9 **	This software is open source.
10 **
11 **	Redistribution and use in source and binary forms, with or without
12 **	modification, are permitted provided that the following conditions
13 **	are met:
14 **
15 **	Redistributions of source code must retain the above copyright notice,
16 **	this list of conditions and the following disclaimer.
17 **
18 **	Redistributions in binary form must reproduce the above copyright notice,
19 **	this list of conditions and the following disclaimer in the documentation
20 **	and/or other materials provided with the distribution.
21 **
22 **	Neither the name of Holger Zuleger HZnet nor the names of its contributors may
23 **	be used to endorse or promote products derived from this software without
24 **	specific prior written permission.
25 **
26 **	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 **	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 **	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 **	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30 **	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 **	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 **	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 **	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 **	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 **	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 **	POSSIBILITY OF SUCH DAMAGE.
37 **
38 *****************************************************************/
39 # include <stdio.h>
40 # include <string.h>
41 # include <stdlib.h>
42 # include <unistd.h>	/* for link(), unlink() */
43 # include <ctype.h>
44 # include <sys/types.h>
45 # include <sys/stat.h>
46 # include <time.h>
47 # include <utime.h>
48 # include <assert.h>
49 # include <errno.h>
50 # include <fcntl.h>
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54 # include "config_zkt.h"
55 # include "zconf.h"
56 # include "log.h"
57 # include "debug.h"
58 #define extern
59 # include "misc.h"
60 #undef extern
61 
62 # define	TAINTEDCHARS	"`$@;&<>|"
63 
64 extern	const	char	*progname;
65 
66 /*****************************************************************
67 **	getnameappendix (progname, basename)
68 **	return a pointer to the substring in progname subsequent
69 **	following "<basename>-".
70 *****************************************************************/
71 const	char	*getnameappendix (const char *progname, const char *basename)
72 {
73 	const	char	*p;
74 	int	baselen;
75 
76 	assert (progname != NULL);
77 	assert (basename != NULL);
78 
79 	if ( (p = strrchr (progname, '/')) != NULL )
80 		p++;
81 	else
82 		p = progname;
83 
84 	baselen = strlen (basename);
85 	if ( strncmp (p, basename, baselen-1) == 0 && *(p+baselen) == '-' )
86 	{
87 		p += baselen + 1;
88 		if ( *p )
89 			return p;
90 	}
91 
92 	return NULL;
93 }
94 
95 /*****************************************************************
96 **	getdefconfname (view)
97 **	returns a pointer to a dynamic string containing the
98 **	default configuration file name
99 *****************************************************************/
100 const	char	*getdefconfname (const char *view)
101 {
102 	char	*p;
103 	char	*file;
104 	char	*buf;
105 	int	size;
106 
107 	if ( (file = getenv ("ZKT_CONFFILE")) == NULL )
108 		file = CONFIG_FILE;
109 	dbg_val2 ("getdefconfname (%s) file = %s\n", view ? view : "NULL", file);
110 
111 	if ( view == NULL || *view == '\0' || (p = strrchr (file, '.')) == NULL )
112 		return strdup (file);
113 
114 	size = strlen (file) + strlen (view) + 1 + 1;
115 	if ( (buf = malloc (size)) == NULL )
116 		return strdup (file);
117 
118 	dbg_val1 ("0123456789o123456789o123456789\tsize=%d\n", size);
119 	dbg_val4 ("%.*s-%s%s\n", p - file, file, view, p);
120 
121 	snprintf (buf, size, "%.*s-%s%s", (int)(p - file), file, view, p);
122 	return buf;
123 }
124 
125 /*****************************************************************
126 **	domain_canonicdup (s)
127 **	returns NULL or a pointer to a dynamic string containing the
128 **	canonic (all lower case letters and ending with a '.')
129 **	domain name
130 *****************************************************************/
131 char	*domain_canonicdup (const char *s)
132 {
133 	char	*new;
134 	char	*p;
135 	int	len;
136 	int	add_dot;
137 
138 	if ( s == NULL )
139 		return NULL;
140 
141 	add_dot = 0;
142 	len = strlen (s);
143 	if ( len > 0 && s[len-1] != '.' )
144 		add_dot = len++;
145 
146 	if ( (new = p = malloc (len + 1)) == NULL )
147 		return NULL;
148 
149 	while ( *s )
150 		*p++ = tolower (*s++);
151 	if ( add_dot )
152 		*p++ = '.';
153 	*p = '\0';
154 
155 	return new;
156 }
157 #if 0		/* replaced by domain_canonicdup */
158 /*****************************************************************
159 **	str_tolowerdup (s)
160 *****************************************************************/
161 char	*str_tolowerdup (const char *s)
162 {
163 	char	*new;
164 	char	*p;
165 
166 	if ( s == NULL || (new = p = malloc (strlen (s) + 1)) == NULL )
167 		return NULL;
168 
169 	while ( *s )
170 		*p++ = tolower (*s++);
171 	*p = '\0';
172 
173 	return new;
174 }
175 #endif
176 
177 /*****************************************************************
178 **	str_delspace (s)
179 **	Remove in string 's' all white space char
180 *****************************************************************/
181 char	*str_delspace (char *s)
182 {
183 	char	*start;
184 	char	*p;
185 
186 	if ( !s )	/* no string present ? */
187 		return NULL;
188 
189 	start = s;
190 	for ( p = s; *p; p++ )
191 		if ( !isspace (*p) )
192 			*s++ = *p;	/* copy each nonspace */
193 
194 	*s = '\0';	/* terminate string */
195 
196 	return start;
197 }
198 
199 /*****************************************************************
200 **	in_strarr (str, arr, cnt)
201 **	check if string array 'arr' contains the string 'str'
202 **	return 1 if true or 'arr' or 'str' is empty, otherwise 0
203 *****************************************************************/
204 int	in_strarr (const char *str, char *const arr[], int cnt)
205 {
206 	if ( arr == NULL || cnt <= 0 )
207 		return 1;
208 
209 	if ( str == NULL || *str == '\0' )
210 		return 0;
211 
212 	while ( --cnt >= 0 )
213 		if ( strcmp (str, arr[cnt]) == 0 )
214 			return 1;
215 
216 	return 0;
217 }
218 
219 /*****************************************************************
220 **	str_untaint (s)
221 **	Remove in string 's' all TAINTED chars
222 *****************************************************************/
223 char	*str_untaint (char *str)
224 {
225 	char	*p;
226 
227 	assert (str != NULL);
228 
229 	for ( p = str; *p; p++ )
230 		if ( strchr (TAINTEDCHARS, *p) )
231 			*p = ' ';
232 	return str;
233 }
234 
235 /*****************************************************************
236 **	str_chop (str, c)
237 **	delete all occurrences of char 'c' at the end of string 's'
238 *****************************************************************/
239 char	*str_chop (char *str, char c)
240 {
241 	int	len;
242 
243 	assert (str != NULL);
244 
245 	len = strlen (str) - 1;
246 	while ( len >= 0 && str[len] == c )
247 		str[len--] = '\0';
248 
249 	return str;
250 }
251 
252 /*****************************************************************
253 **	parseurl (url, &proto, &host, &port, &para )
254 **	parses the given url (e.g. "proto://host.with.domain:port/para")
255 **	and set the pointer variables to the corresponding part of the string.
256 *****************************************************************/
257 void	parseurl (char *url, char **proto, char **host, char **port, char **para)
258 {
259 	char	*start;
260 	char	*p;
261 
262 	assert ( url != NULL );
263 
264 	/* parse protocol */
265 	if ( (p = strchr (url, ':')) == NULL )	/* no protocol string given ? */
266 		p = url;
267 	else					/* looks like a protocol string */
268 		if ( p[1] == '/' && p[2] == '/' )	/* protocol string ? */
269 		{
270 			*p = '\0';
271 			p += 3;
272 			if ( proto )
273 				*proto = url;
274 		}
275 		else				/* no protocol string found ! */
276 			p = url;
277 
278 	/* parse host */
279 	if ( *p == '[' )	/* ipv6 address as hostname ? */
280 	{
281 		for ( start = ++p; *p && *p != ']'; p++ )
282 			;
283 		if ( *p )
284 			*p++ = '\0';
285 	}
286 	else
287 		for ( start = p; *p && *p != ':' && *p != '/'; p++ )
288 			;
289 	if ( host )
290 		*host = start;
291 
292 	/* parse port */
293 	if ( *p == ':' )
294 	{
295 		*p++ = '\0';
296 		for ( start = p; *p && isdigit (*p); p++ )
297 			;
298 		if ( *p )
299 			*p++ = '\0';
300 		if ( port )
301 			*port = start;
302 	}
303 
304 	if ( *p == '/' )
305 		*p++ = '\0';
306 
307 	if ( *p && para )
308 		*para = p;
309 }
310 
311 /*****************************************************************
312 **	splitpath (path, pathsize, filename)
313 **	if filename is build of "path/file" then copy filename to path
314 **	and split of the filename part.
315 **	return pointer to filename part in path or NULL if path is too
316 **	small to hold "path+filename"
317 *****************************************************************/
318 const	char	*splitpath (char *path, size_t psize, const char *filename)
319 {
320 	char 	*p;
321 
322 	if ( !path )
323 		return NULL;
324 
325 	*path = '\0';
326 	if ( !filename )
327 		return filename;
328 
329 	if ( (p = strrchr (filename, '/')) )	/* file arg contains path ? */
330 	{
331 		if ( strlen (filename) + 1 > psize )
332 			return filename;
333 
334 		strcpy (path, filename);	/* copy whole filename to path */
335 		path[p-filename] = '\0';	/* split of the file part */
336 		filename = ++p;
337 	}
338 	return filename;
339 }
340 
341 /*****************************************************************
342 **	pathname (path, size, dir, file, ext)
343 **	Concatenate 'dir', 'file' and 'ext' (if not null) to build
344 **	a pathname, and store the result in the character array
345 **	with length 'size' pointed to by 'path'.
346 *****************************************************************/
347 char	*pathname (char *path, size_t size, const char *dir, const char *file, const char *ext)
348 {
349 	int	len;
350 
351 	if ( path == NULL || file == NULL )
352 		return path;
353 
354 	len = strlen (file) + 1;
355 	if ( dir )
356 		len += strlen (dir);
357 	if ( ext )
358 		len += strlen (ext);
359 	if ( len > size )
360 		return path;
361 
362 	*path = '\0';
363 	if ( dir && *dir )
364 	{
365 		len = sprintf (path, "%s", dir);
366 		if ( path[len-1] != '/' )
367 		{
368 			path[len++] = '/';
369 			path[len] = '\0';
370 		}
371 	}
372 	strcat (path, file);
373 	if ( ext )
374 		strcat (path, ext);
375 	return path;
376 }
377 
378 /*****************************************************************
379 **	is_directory (name)
380 **	Check if the given pathname 'name' exists and is a directory.
381 **	returns 0 | 1
382 *****************************************************************/
383 int	is_directory (const char *name)
384 {
385 	struct	stat	st;
386 
387 	if ( !name || !*name )
388 		return 0;
389 
390 	return ( stat (name, &st) == 0 && S_ISDIR (st.st_mode) );
391 }
392 
393 /*****************************************************************
394 **	fileexist (name)
395 **	Check if a file with the given pathname 'name' exists.
396 **	returns 0 | 1
397 *****************************************************************/
398 int	fileexist (const char *name)
399 {
400 	struct	stat	st;
401 	return ( stat (name, &st) == 0 && S_ISREG (st.st_mode) );
402 }
403 
404 /*****************************************************************
405 **	filesize (name)
406 **	return the size of the file with the given pathname 'name'.
407 **	returns -1 if the file not exist
408 *****************************************************************/
409 size_t	filesize (const char *name)
410 {
411 	struct	stat	st;
412 	if  ( stat (name, &st) == -1 )
413 		return -1L;
414 	return ( st.st_size );
415 }
416 
417 /*****************************************************************
418 **	is_keyfilename (name)
419 **	Check if the given name looks like a dnssec (public)
420 **	keyfile name. Returns 0 | 1
421 *****************************************************************/
422 int	is_keyfilename (const char *name)
423 {
424 	int	len;
425 
426 	if ( name == NULL || *name != 'K' )
427 		return 0;
428 
429 	len = strlen (name);
430 	if ( len > 4 && strcmp (&name[len - 4], ".key") == 0 )
431 		return 1;
432 
433 	return 0;
434 }
435 
436 /*****************************************************************
437 **	is_dotfilename (name)
438 **	Check if the given pathname 'name' looks like "." or "..".
439 **	Returns 0 | 1
440 *****************************************************************/
441 int	is_dotfilename (const char *name)
442 {
443 	if ( name && (
444 	     (name[0] == '.' && name[1] == '\0') ||
445 	     (name[0] == '.' && name[1] == '.' && name[2] == '\0')) )
446 		return 1;
447 
448 	return 0;
449 }
450 
451 /*****************************************************************
452 **	touch (name, sec)
453 **	Set the modification time of the given pathname 'fname' to
454 **	'sec'.	Returns 0 on success.
455 *****************************************************************/
456 int	touch (const char *fname, time_t sec)
457 {
458 	struct	utimbuf	utb;
459 
460 	utb.actime = utb.modtime = sec;
461 	return utime (fname, &utb);
462 }
463 
464 /*****************************************************************
465 **	linkfile (fromfile, tofile)
466 *****************************************************************/
467 int	linkfile (const char *fromfile, const char *tofile)
468 {
469 	int	ret;
470 
471 	/* fprintf (stderr, "linkfile (%s, %s)\n", fromfile, tofile); */
472 	if ( (ret = link (fromfile, tofile)) == -1 && errno == EEXIST )
473 		if ( unlink (tofile) == 0 )
474 			ret = link (fromfile, tofile);
475 
476 	return ret;
477 }
478 
479 /*****************************************************************
480 **	copyfile (fromfile, tofile, dnskeyfile)
481 **	copy fromfile into tofile.
482 **	Add (optional) the content of dnskeyfile to tofile.
483 *****************************************************************/
484 int	copyfile (const char *fromfile, const char *tofile, const char *dnskeyfile)
485 {
486 	FILE	*infp;
487 	FILE	*outfp;
488 	int	c;
489 
490 	/* fprintf (stderr, "copyfile (%s, %s)\n", fromfile, tofile); */
491 	if ( (infp = fopen (fromfile, "r")) == NULL )
492 		return -1;
493 	if ( (outfp = fopen (tofile, "w")) == NULL )
494 	{
495 		fclose (infp);
496 		return -2;
497 	}
498 	while ( (c = getc (infp)) != EOF )
499 		putc (c, outfp);
500 
501 	fclose (infp);
502 	if ( dnskeyfile && *dnskeyfile && (infp = fopen (dnskeyfile, "r")) != NULL )
503 	{
504 		while ( (c = getc (infp)) != EOF )
505 			putc (c, outfp);
506 		fclose (infp);
507 	}
508 	fclose (outfp);
509 
510 	return 0;
511 }
512 
513 /*****************************************************************
514 **	copyzonefile (fromfile, tofile, dnskeyfile)
515 **	copy a already signed zonefile and replace all zone DNSKEY
516 **	resource records by one "$INCLUDE dnskey.db" line
517 *****************************************************************/
518 int	copyzonefile (const char *fromfile, const char *tofile, const char *dnskeyfile)
519 {
520 	FILE	*infp;
521 	FILE	*outfp;
522 	int	len;
523 	int	dnskeys;
524 	int	multi_line_dnskey;
525 	int	bufoverflow;
526 	char	buf[1024];
527 	char	*p;
528 
529 	if ( fromfile == NULL )
530 		infp = stdin;
531 	else
532 		if ( (infp = fopen (fromfile, "r")) == NULL )
533 			return -1;
534 	if ( tofile == NULL )
535 		outfp = stdout;
536 	else
537 		if ( (outfp = fopen (tofile, "w")) == NULL )
538 		{
539 			if ( fromfile )
540 				fclose (infp);
541 			return -2;
542 		}
543 
544 	multi_line_dnskey = 0;
545 	dnskeys = 0;
546 	bufoverflow = 0;
547 	while ( fgets (buf, sizeof buf, infp) != NULL )
548 	{
549 		p = buf;
550 		if ( !bufoverflow && !multi_line_dnskey && (*p == '@' || isspace (*p)) )	/* check if DNSKEY RR */
551 		{
552 			do
553 				p++;
554 			while ( isspace (*p) ) ;
555 
556 			/* skip TTL */
557 			while ( isdigit (*p) )
558 				p++;
559 
560 			while ( isspace (*p) )
561 				p++;
562 
563 			/* skip Class */
564 			if ( strncasecmp (p, "IN", 2) == 0 )
565 			{
566 				p += 2;
567 				while ( isspace (*p) )
568 					p++;
569 			}
570 
571 			if ( strncasecmp (p, "DNSKEY", 6) == 0 )	/* bingo! */
572 			{
573 				dnskeys++;
574 				p += 6;
575 				while ( *p )
576 				{
577 					if ( *p == '(' )
578 						multi_line_dnskey = 1;
579 					if ( *p == ')' )
580 						multi_line_dnskey = 0;
581 					p++;
582 				}
583 				if ( dnskeys == 1 )
584 					fprintf (outfp, "$INCLUDE %s\n", dnskeyfile);
585 			}
586 			else
587 				fputs (buf, outfp);
588 		}
589 		else
590 		{
591 			if ( bufoverflow )
592 				fprintf (stderr, "!! buffer overflow in copyzonefile() !!\n");
593 			if ( !multi_line_dnskey )
594 				fputs (buf, outfp);
595 			else
596 			{
597 				while ( *p && *p != ')' )
598 					p++;
599 				if ( *p == ')' )
600 					multi_line_dnskey = 0;
601 			}
602 		}
603 
604 		len = strlen (buf);
605 		bufoverflow = buf[len-1] != '\n';	/* line too long ? */
606 	}
607 
608 	if ( fromfile )
609 		fclose (infp);
610 	if ( tofile )
611 		fclose (outfp);
612 
613 	return 0;
614 }
615 
616 /*****************************************************************
617 **	cmpfile (file1, file2)
618 **	returns -1 on error, 1 if the files differ and 0 if they
619 **	are identical.
620 *****************************************************************/
621 int	cmpfile (const char *file1, const char *file2)
622 {
623 	FILE	*fp1;
624 	FILE	*fp2;
625 	int	c1;
626 	int	c2;
627 
628 	/* fprintf (stderr, "cmpfile (%s, %s)\n", file1, file2); */
629 	if ( (fp1 = fopen (file1, "r")) == NULL )
630 		return -1;
631 	if ( (fp2 = fopen (file2, "r")) == NULL )
632 	{
633 		fclose (fp1);
634 		return -1;
635 	}
636 
637 	do {
638 		c1 = getc (fp1);
639 		c2 = getc (fp2);
640 	}  while ( c1 != EOF && c2 != EOF && c1 == c2 );
641 
642 	fclose (fp1);
643 	fclose (fp2);
644 
645 	if ( c1 == c2 )
646 		return 0;
647 	return 1;
648 }
649 
650 /*****************************************************************
651 **	file_age (fname)
652 *****************************************************************/
653 int	file_age (const char *fname)
654 {
655 	time_t	curr = time (NULL);
656 	time_t	mtime = file_mtime (fname);
657 
658 	return curr - mtime;
659 }
660 
661 /*****************************************************************
662 **	file_mtime (fname)
663 *****************************************************************/
664 time_t	file_mtime (const char *fname)
665 {
666 	struct	stat	st;
667 
668 	if ( stat (fname, &st) < 0 )
669 		return 0;
670 	return st.st_mtime;
671 }
672 
673 /*****************************************************************
674 **	is_exec_ok (prog)
675 **	Check if we are running as root or if the file owner of
676 **	"prog" do not match the current user or the file permissions
677 **	allows file modification for others then the owner.
678 **	The same condition will be checked for the group ownership.
679 **	return 1 if the execution of the command "prog" will not
680 **	open a big security whole, 0 otherwise
681 *****************************************************************/
682 int	is_exec_ok (const char *prog)
683 {
684 	uid_t	curr_uid;
685 	struct	stat	st;
686 
687 	if ( stat (prog, &st) < 0 )
688 		return 0;
689 
690 	curr_uid = getuid ();
691 	if ( curr_uid == 0 )			/* don't run the cmd if we are root */
692 		return 0;
693 
694 	/* if the file owner and the current user matches and */
695 	/* the file mode is not writable except for the owner, we are save */
696 	if ( curr_uid == st.st_uid && (st.st_mode & (S_IWGRP | S_IWOTH)) == 0 )
697 		return 1;
698 
699 	/* if the file group and the current group matches and */
700 	/* the file mode is not writable except for the group, we are also save */
701 	if ( getgid() != st.st_gid && (st.st_mode & (S_IWUSR | S_IWOTH)) == 0 )
702 		return 1;
703 
704 	return 0;
705 }
706 
707 /*****************************************************************
708 **	fatal (fmt, ...)
709 *****************************************************************/
710 void fatal (char *fmt, ...)
711 {
712         va_list ap;
713 
714         va_start(ap, fmt);
715         if ( progname )
716 		fprintf (stderr, "%s: ", progname);
717         vfprintf (stderr, fmt, ap);
718         va_end(ap);
719         exit (127);
720 }
721 
722 /*****************************************************************
723 **	error (fmt, ...)
724 *****************************************************************/
725 void error (char *fmt, ...)
726 {
727         va_list ap;
728 
729         va_start(ap, fmt);
730         vfprintf (stderr, fmt, ap);
731         va_end(ap);
732 }
733 
734 /*****************************************************************
735 **	logmesg (fmt, ...)
736 *****************************************************************/
737 void logmesg (char *fmt, ...)
738 {
739         va_list ap;
740 
741 #if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME
742         fprintf (stdout, "%s: ", progname);
743 #endif
744         va_start(ap, fmt);
745         vfprintf (stdout, fmt, ap);
746         va_end(ap);
747 }
748 
749 /*****************************************************************
750 **	verbmesg (verblvl, conf, fmt, ...)
751 *****************************************************************/
752 void	verbmesg (int verblvl, const zconf_t *conf, char *fmt, ...)
753 {
754 	char	str[511+1];
755         va_list ap;
756 
757 	str[0] = '\0';
758 	va_start(ap, fmt);
759 	vsnprintf (str, sizeof (str), fmt, ap);
760 	va_end(ap);
761 
762 	//fprintf (stderr, "verbmesg (%d stdout=%d filelog=%d str = :%s:\n", verblvl, conf->verbosity, conf->verboselog, str);
763 	if ( verblvl <= conf->verbosity )	/* check if we have to print this to stdout */
764 		logmesg (str);
765 
766 	str_chop (str, '\n');
767 	if ( verblvl <= conf->verboselog )	/* check logging to syslog and/or file */
768 		lg_mesg (LG_DEBUG, str);
769 }
770 
771 
772 /*****************************************************************
773 **	logflush ()
774 *****************************************************************/
775 void logflush ()
776 {
777         fflush (stdout);
778 }
779 
780 /*****************************************************************
781 **	timestr2time (timestr)
782 **	timestr should look like "20071211223901" for 12 dec 2007 22:39:01
783 *****************************************************************/
784 time_t	timestr2time (const char *timestr)
785 {
786 	struct	tm	t;
787 	time_t	sec;
788 
789 	// fprintf (stderr, "timestr = \"%s\"\n", timestr);
790 	if ( sscanf (timestr, "%4d%2d%2d%2d%2d%2d",
791 			&t.tm_year, &t.tm_mon, &t.tm_mday,
792 			&t.tm_hour, &t.tm_min, &t.tm_sec) != 6 )
793 		return 0L;
794 	t.tm_year -= 1900;
795 	t.tm_mon -= 1;
796 	t.tm_isdst = 0;
797 
798 #if defined(HAVE_TIMEGM) && HAVE_TIMEGM
799 	sec = timegm (&t);
800 #else
801 	{
802 	char	tzstr[31+1];
803 	char	*tz;
804 
805 	tz = getenv("TZ");
806 	snprintf (tzstr, sizeof (tzstr), "TZ=%s", "UTC");
807 	putenv (tzstr);
808 	tzset();
809 	sec = mktime(&t);
810 	if (tz)
811 		snprintf (tzstr, sizeof (tzstr), "TZ=%s", tz);
812 	else
813 		snprintf (tzstr, sizeof (tzstr), "TZ=%s", "");
814 	putenv (tzstr);
815 	tzset();
816 	}
817 #endif
818 
819 	return sec < 0L ? 0L : sec;
820 }
821 
822 /*****************************************************************
823 **	time2str (sec, precison)
824 **	sec is seconds since 1.1.1970
825 **	precison is currently either 's' (for seconds) or 'm' (minutes)
826 *****************************************************************/
827 char	*time2str (time_t sec, int precision)
828 {
829 	struct	tm	*t;
830 	static	char	timestr[31+1];	/* 27+1 should be enough */
831 #if defined(HAVE_STRFTIME) && HAVE_STRFTIME
832 	char	tformat[127+1];
833 
834 	timestr[0] = '\0';
835 	if ( sec <= 0L )
836 		return timestr;
837 	t = localtime (&sec);
838 	if ( precision == 's' )
839 		strcpy (tformat, "%b %d %Y %T");
840 	else
841 		strcpy (tformat, "%b %d %Y %R");
842 # if PRINT_TIMEZONE
843 	strcat (tformat, " %z");
844 # endif
845 	strftime (timestr, sizeof (timestr), tformat, t);
846 
847 #else	/* no strftime available */
848 	static	char	*mstr[] = {
849 			"Jan", "Feb", "Mar", "Apr", "May", "Jun",
850 			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
851 	};
852 
853 	timestr[0] = '\0';
854 	if ( sec <= 0L )
855 		return timestr;
856 	t = localtime (&sec);
857 # if PRINT_TIMEZONE
858 	{
859 	int	h,	s;
860 
861 	s = abs (t->tm_gmtoff);
862 	h = t->tm_gmtoff / 3600;
863 	s = t->tm_gmtoff % 3600;
864 	if ( precision == 's' )
865 		snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d %c%02d%02d",
866 			mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
867 			t->tm_hour, t->tm_min, t->tm_sec,
868 			t->tm_gmtoff < 0 ? '-': '+',
869 			h, s);
870 	else
871 		snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d %c%02d%02d",
872 			mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
873 			t->tm_hour, t->tm_min,
874 			t->tm_gmtoff < 0 ? '-': '+',
875 			h, s);
876 	}
877 # else
878 	if ( precision == 's' )
879 		snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d",
880 			mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
881 			t->tm_hour, t->tm_min, t->tm_sec);
882 	else
883 		snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d",
884 			mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
885 			t->tm_hour, t->tm_min);
886 # endif
887 #endif
888 
889 	return timestr;
890 }
891 
892 /*****************************************************************
893 **	time2isostr (sec, precison)
894 **	sec is seconds since 1.1.1970
895 **	precison is currently either 's' (for seconds) or 'm' (minutes)
896 *****************************************************************/
897 char	*time2isostr (time_t sec, int precision)
898 {
899 	struct	tm	*t;
900 	static	char	timestr[31+1];	/* 27+1 should be enough */
901 
902 	timestr[0] = '\0';
903 	if ( sec <= 0L )
904 		return timestr;
905 
906 	t = gmtime (&sec);
907 	if ( precision == 's' )
908 		snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d%02d",
909 			t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
910 			t->tm_hour, t->tm_min, t->tm_sec);
911 	else
912 		snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d",
913 			t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
914 			t->tm_hour, t->tm_min);
915 
916 	return timestr;
917 }
918 
919 /*****************************************************************
920 **	age2str (sec)
921 **	!!Attention: This function is not reentrant
922 *****************************************************************/
923 char	*age2str (time_t sec)
924 {
925 	static	char	str[20+1];	/* "2y51w6d23h50m55s" == 16+1 chars */
926 	int	len;
927 	int	strsize = sizeof (str);
928 
929 	len = 0;
930 # if PRINT_AGE_WITH_YEAR
931 	if ( sec / (YEARSEC) > 0 )
932 	{
933 		len += snprintf (str+len, strsize - len, "%1luy", sec / YEARSEC );
934 		sec %= (YEARSEC);
935 	}
936 	else
937 		len += snprintf (str+len, strsize - len, "  ");
938 # endif
939 	if ( sec / WEEKSEC > 0 )
940 	{
941 		len += snprintf (str+len, strsize - len, "%2luw", (ulong) sec / WEEKSEC );
942 		sec %= WEEKSEC;
943 	}
944 	else
945 		len += snprintf (str+len, strsize - len, "   ");
946 	if ( sec / DAYSEC > 0 )
947 	{
948 		len += snprintf (str+len, strsize - len, "%2lud", sec / (ulong)DAYSEC);
949 		sec %= DAYSEC;
950 	}
951 	else
952 		len += snprintf (str+len, strsize - len, "   ");
953 	if ( sec / HOURSEC > 0 )
954 	{
955 		len += snprintf (str+len, strsize - len, "%2luh", sec / (ulong)HOURSEC);
956 		sec %= HOURSEC;
957 	}
958 	else
959 		len += snprintf (str+len, strsize - len, "   ");
960 	if ( sec / MINSEC > 0 )
961 	{
962 		len += snprintf (str+len, strsize - len, "%2lum", sec / (ulong)MINSEC);
963 		sec %= MINSEC;
964 	}
965 	else
966 		len += snprintf (str+len, strsize - len, "   ");
967 	if ( sec > 0 )
968 		snprintf (str+len, strsize - len, "%2lus", (ulong) sec);
969 	else
970 		len += snprintf (str+len, strsize - len, "   ");
971 
972 	return str;
973 }
974 
975 /*****************************************************************
976 **	start_timer ()
977 *****************************************************************/
978 time_t	start_timer ()
979 {
980 	return (time(NULL));
981 }
982 
983 /*****************************************************************
984 **	stop_timer ()
985 *****************************************************************/
986 time_t	stop_timer (time_t start)
987 {
988 	time_t	stop = time (NULL);
989 
990 	return stop - start;
991 }
992 
993 
994 /****************************************************************
995 **
996 **	int	gensalt (saltstr, sizeofsaltstr, bits)
997 **
998 **	generate a random hexstring of 'bits' salt and store it
999 **	in saltstr. return 1 on success, otherwise 0.
1000 **
1001 *****************************************************************/
1002 int	gensalt (char *salt, size_t saltsize, int saltbits, unsigned int seed)
1003 {
1004 	static	char	hexstr[] = "0123456789ABCDEF";
1005 	int	saltlen = 0;	/* current length of salt in hex nibbles */
1006 	int	i;
1007 	int	hex;
1008 
1009 	if ( seed == 0 )
1010 		srandom (seed = (unsigned int)time (NULL));
1011 
1012 	saltlen = saltbits / 4;
1013 	if ( saltlen+1 > saltsize )
1014 		return 0;
1015 
1016 	for ( i = 0; i < saltlen; i++ )
1017 	{
1018 		hex = random () % 16;
1019 		assert ( hex >= 0 && hex < 16 );
1020 		salt[i] = hexstr[hex];
1021 	}
1022 	salt[i] = '\0';
1023 
1024 	return 1;
1025 }
1026 
1027 
1028 #ifdef COPYZONE_TEST
1029 const char *progname;
1030 main (int argc, char *argv[])
1031 {
1032 	progname = *argv;
1033 
1034 	if ( copyzonefile (argv[1], NULL) < 0 )
1035 		error ("can't copy zone file %s\n", argv[1]);
1036 }
1037 #endif
1038 
1039 #ifdef URL_TEST
1040 const char *progname;
1041 main (int argc, char *argv[])
1042 {
1043 	char	*proto;
1044 	char	*host;
1045 	char	*port;
1046 	char	*para;
1047 	char	url[1024];
1048 
1049 	progname = *argv;
1050 
1051 	proto = host = port = para = NULL;
1052 
1053 	if ( --argc <= 0 )
1054 	{
1055 		fprintf (stderr, "usage: url_test <url>\n");
1056 		fprintf (stderr, "e.g.: url_test http://www.hznet.de:80/zkt\n");
1057 		exit (1);
1058 	}
1059 
1060 	strcpy (url, argv[1]);
1061 	parseurl (url, &proto, &host, &port, &para);
1062 
1063 	if ( proto )
1064 		printf ("proto: \"%s\"\n", proto);
1065 	if ( host )
1066 		printf ("host: \"%s\"\n", host);
1067 	if ( port )
1068 		printf ("port: \"%s\"\n", port);
1069 	if ( para )
1070 		printf ("para: \"%s\"\n", para);
1071 
1072 }
1073 #endif
1074 
1075