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