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