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, ¶ )
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, ¶);
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