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 62extern const char *progname; 63 64/***************************************************************** 65** getnameappendix (progname, basename) 66** return a pointer to the substring in progname subsequent 67** following "<basename>-". 68*****************************************************************/ 69const 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*****************************************************************/ 98const 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", 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*****************************************************************/ 129char *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*****************************************************************/ 159char *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*****************************************************************/ 179char *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*****************************************************************/ 202int 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*****************************************************************/ 221char *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*****************************************************************/ 237char *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*****************************************************************/ 255void 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*****************************************************************/ 316const 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*****************************************************************/ 345char *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*****************************************************************/ 381int 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*****************************************************************/ 396int 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*****************************************************************/ 407size_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*****************************************************************/ 420int 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*****************************************************************/ 439int 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*****************************************************************/ 454int touch (const char *fname, time_t sec) 455{ 456 struct utimbuf utb; 457 458 utb.actime = utb.modtime = sec; 459 return utime (fname, &utb); 460} 461 462/***************************************************************** 463** linkfile (fromfile, tofile) 464*****************************************************************/ 465int linkfile (const char *fromfile, const char *tofile) 466{ 467 int ret; 468 469 /* fprintf (stderr, "linkfile (%s, %s)\n", fromfile, tofile); */ 470 if ( (ret = link (fromfile, tofile)) == -1 && errno == EEXIST ) 471 if ( unlink (tofile) == 0 ) 472 ret = link (fromfile, tofile); 473 474 return ret; 475} 476 477/***************************************************************** 478** copyfile (fromfile, tofile, dnskeyfile) 479** copy fromfile into tofile. 480** Add (optional) the content of dnskeyfile to tofile. 481*****************************************************************/ 482int copyfile (const char *fromfile, const char *tofile, const char *dnskeyfile) 483{ 484 FILE *infp; 485 FILE *outfp; 486 int c; 487 488 /* fprintf (stderr, "copyfile (%s, %s)\n", fromfile, tofile); */ 489 if ( (infp = fopen (fromfile, "r")) == NULL ) 490 return -1; 491 if ( (outfp = fopen (tofile, "w")) == NULL ) 492 { 493 fclose (infp); 494 return -2; 495 } 496 while ( (c = getc (infp)) != EOF ) 497 putc (c, outfp); 498 499 fclose (infp); 500 if ( dnskeyfile && *dnskeyfile && (infp = fopen (dnskeyfile, "r")) != NULL ) 501 { 502 while ( (c = getc (infp)) != EOF ) 503 putc (c, outfp); 504 fclose (infp); 505 } 506 fclose (outfp); 507 508 return 0; 509} 510 511/***************************************************************** 512** copyzonefile (fromfile, tofile, dnskeyfile) 513** copy a already signed zonefile and replace all zone DNSKEY 514** resource records by one "$INCLUDE dnskey.db" line 515*****************************************************************/ 516int copyzonefile (const char *fromfile, const char *tofile, const char *dnskeyfile) 517{ 518 FILE *infp; 519 FILE *outfp; 520 int len; 521 int dnskeys; 522 int multi_line_dnskey; 523 int bufoverflow; 524 char buf[1024]; 525 char *p; 526 527 if ( fromfile == NULL ) 528 infp = stdin; 529 else 530 if ( (infp = fopen (fromfile, "r")) == NULL ) 531 return -1; 532 if ( tofile == NULL ) 533 outfp = stdout; 534 else 535 if ( (outfp = fopen (tofile, "w")) == NULL ) 536 { 537 if ( fromfile ) 538 fclose (infp); 539 return -2; 540 } 541 542 multi_line_dnskey = 0; 543 dnskeys = 0; 544 bufoverflow = 0; 545 while ( fgets (buf, sizeof buf, infp) != NULL ) 546 { 547 p = buf; 548 if ( !bufoverflow && !multi_line_dnskey && (*p == '@' || isspace (*p)) ) /* check if DNSKEY RR */ 549 { 550 do 551 p++; 552 while ( isspace (*p) ) ; 553 554 /* skip TTL */ 555 while ( isdigit (*p) ) 556 p++; 557 558 while ( isspace (*p) ) 559 p++; 560 561 /* skip Class */ 562 if ( strncasecmp (p, "IN", 2) == 0 ) 563 { 564 p += 2; 565 while ( isspace (*p) ) 566 p++; 567 } 568 569 if ( strncasecmp (p, "DNSKEY", 6) == 0 ) /* bingo! */ 570 { 571 dnskeys++; 572 p += 6; 573 while ( *p ) 574 { 575 if ( *p == '(' ) 576 multi_line_dnskey = 1; 577 if ( *p == ')' ) 578 multi_line_dnskey = 0; 579 p++; 580 } 581 if ( dnskeys == 1 ) 582 fprintf (outfp, "$INCLUDE %s\n", dnskeyfile); 583 } 584 else 585 fputs (buf, outfp); 586 } 587 else 588 { 589 if ( bufoverflow ) 590 fprintf (stderr, "!! buffer overflow in copyzonefile() !!\n"); 591 if ( !multi_line_dnskey ) 592 fputs (buf, outfp); 593 else 594 { 595 while ( *p && *p != ')' ) 596 p++; 597 if ( *p == ')' ) 598 multi_line_dnskey = 0; 599 } 600 } 601 602 len = strlen (buf); 603 bufoverflow = buf[len-1] != '\n'; /* line too long ? */ 604 } 605 606 if ( fromfile ) 607 fclose (infp); 608 if ( tofile ) 609 fclose (outfp); 610 611 return 0; 612} 613 614/***************************************************************** 615** cmpfile (file1, file2) 616** returns -1 on error, 1 if the files differ and 0 if they 617** are identical. 618*****************************************************************/ 619int cmpfile (const char *file1, const char *file2) 620{ 621 FILE *fp1; 622 FILE *fp2; 623 int c1; 624 int c2; 625 626 /* fprintf (stderr, "cmpfile (%s, %s)\n", file1, file2); */ 627 if ( (fp1 = fopen (file1, "r")) == NULL ) 628 return -1; 629 if ( (fp2 = fopen (file2, "r")) == NULL ) 630 { 631 fclose (fp1); 632 return -1; 633 } 634 635 do { 636 c1 = getc (fp1); 637 c2 = getc (fp2); 638 } while ( c1 != EOF && c2 != EOF && c1 == c2 ); 639 640 fclose (fp1); 641 fclose (fp2); 642 643 if ( c1 == c2 ) 644 return 0; 645 return 1; 646} 647 648/***************************************************************** 649** file_age (fname) 650*****************************************************************/ 651int file_age (const char *fname) 652{ 653 time_t curr = time (NULL); 654 time_t mtime = file_mtime (fname); 655 656 return curr - mtime; 657} 658 659/***************************************************************** 660** file_mtime (fname) 661*****************************************************************/ 662time_t file_mtime (const char *fname) 663{ 664 struct stat st; 665 666 if ( stat (fname, &st) < 0 ) 667 return 0; 668 return st.st_mtime; 669} 670 671/***************************************************************** 672** is_exec_ok (prog) 673** Check if we are running as root or if the file owner of 674** "prog" do not match the current user or the file permissions 675** allows file modification for others then the owner. 676** The same condition will be checked for the group ownership. 677** return 1 if the execution of the command "prog" will not 678** open a big security whole, 0 otherwise 679*****************************************************************/ 680int is_exec_ok (const char *prog) 681{ 682 uid_t curr_uid; 683 struct stat st; 684 685 if ( stat (prog, &st) < 0 ) 686 return 0; 687 688 curr_uid = getuid (); 689 if ( curr_uid == 0 ) /* don't run the cmd if we are root */ 690 return 0; 691 692 /* if the file owner and the current user matches and */ 693 /* the file mode is not writable except for the owner, we are save */ 694 if ( curr_uid == st.st_uid && (st.st_mode & (S_IWGRP | S_IWOTH)) == 0 ) 695 return 1; 696 697 /* if the file group and the current group matches and */ 698 /* the file mode is not writable except for the group, we are also save */ 699 if ( getgid() != st.st_gid && (st.st_mode & (S_IWUSR | S_IWOTH)) == 0 ) 700 return 1; 701 702 return 0; 703} 704 705/***************************************************************** 706** fatal (fmt, ...) 707*****************************************************************/ 708void fatal (char *fmt, ...) 709{ 710 va_list ap; 711 712 va_start(ap, fmt); 713 if ( progname ) 714 fprintf (stderr, "%s: ", progname); 715 vfprintf (stderr, fmt, ap); 716 va_end(ap); 717 exit (127); 718} 719 720/***************************************************************** 721** error (fmt, ...) 722*****************************************************************/ 723void error (char *fmt, ...) 724{ 725 va_list ap; 726 727 va_start(ap, fmt); 728 vfprintf (stderr, fmt, ap); 729 va_end(ap); 730} 731 732/***************************************************************** 733** logmesg (fmt, ...) 734*****************************************************************/ 735void logmesg (char *fmt, ...) 736{ 737 va_list ap; 738 739#if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME 740 fprintf (stdout, "%s: ", progname); 741#endif 742 va_start(ap, fmt); 743 vfprintf (stdout, fmt, ap); 744 va_end(ap); 745} 746 747/***************************************************************** 748** verbmesg (verblvl, conf, fmt, ...) 749*****************************************************************/ 750void verbmesg (int verblvl, const zconf_t *conf, char *fmt, ...) 751{ 752 char str[511+1]; 753 va_list ap; 754 755 str[0] = '\0'; 756 va_start(ap, fmt); 757 vsnprintf (str, sizeof (str), fmt, ap); 758 va_end(ap); 759 760 //fprintf (stderr, "verbmesg (%d stdout=%d filelog=%d str = :%s:\n", verblvl, conf->verbosity, conf->verboselog, str); 761 if ( verblvl <= conf->verbosity ) /* check if we have to print this to stdout */ 762 logmesg (str); 763 764 str_chop (str, '\n'); 765 if ( verblvl <= conf->verboselog ) /* check logging to syslog and/or file */ 766 lg_mesg (LG_DEBUG, str); 767} 768 769 770/***************************************************************** 771** logflush () 772*****************************************************************/ 773void logflush () 774{ 775 fflush (stdout); 776} 777 778/***************************************************************** 779** timestr2time (timestr) 780** timestr should look like "20071211223901" for 12 dec 2007 22:39:01 781*****************************************************************/ 782time_t timestr2time (const char *timestr) 783{ 784 struct tm t; 785 time_t sec; 786 787 // fprintf (stderr, "timestr = \"%s\"\n", timestr); 788 if ( sscanf (timestr, "%4d%2d%2d%2d%2d%2d", 789 &t.tm_year, &t.tm_mon, &t.tm_mday, 790 &t.tm_hour, &t.tm_min, &t.tm_sec) != 6 ) 791 return 0L; 792 t.tm_year -= 1900; 793 t.tm_mon -= 1; 794 t.tm_isdst = 0; 795 796#if defined(HAVE_TIMEGM) && HAVE_TIMEGM 797 sec = timegm (&t); 798#else 799 { 800 char tzstr[31+1]; 801 char *tz; 802 803 tz = getenv("TZ"); 804 snprintf (tzstr, sizeof (tzstr), "TZ=%s", "UTC"); 805 putenv (tzstr); 806 tzset(); 807 sec = mktime(&t); 808 if (tz) 809 snprintf (tzstr, sizeof (tzstr), "TZ=%s", tz); 810 else 811 snprintf (tzstr, sizeof (tzstr), "TZ=%s", ""); 812 putenv (tzstr); 813 tzset(); 814 } 815#endif 816 817 return sec < 0L ? 0L : sec; 818} 819 820/***************************************************************** 821** time2str (sec, precison) 822** sec is seconds since 1.1.1970 823** precison is currently either 's' (for seconds) or 'm' (minutes) 824*****************************************************************/ 825char *time2str (time_t sec, int precision) 826{ 827 struct tm *t; 828 static char timestr[31+1]; /* 27+1 should be enough */ 829#if defined(HAVE_STRFTIME) && HAVE_STRFTIME 830 char tformat[127+1]; 831 832 timestr[0] = '\0'; 833 if ( sec <= 0L ) 834 return timestr; 835 t = localtime (&sec); 836 if ( precision == 's' ) 837 strcpy (tformat, "%b %d %Y %T"); 838 else 839 strcpy (tformat, "%b %d %Y %R"); 840# if PRINT_TIMEZONE 841 strcat (tformat, " %z"); 842# endif 843 strftime (timestr, sizeof (timestr), tformat, t); 844 845#else /* no strftime available */ 846 static char *mstr[] = { 847 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 848 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 849 }; 850 851 timestr[0] = '\0'; 852 if ( sec <= 0L ) 853 return timestr; 854 t = localtime (&sec); 855# if PRINT_TIMEZONE 856 { 857 int h, s; 858 859 s = abs (t->tm_gmtoff); 860 h = t->tm_gmtoff / 3600; 861 s = t->tm_gmtoff % 3600; 862 if ( precision == 's' ) 863 snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d %c%02d%02d", 864 mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900, 865 t->tm_hour, t->tm_min, t->tm_sec, 866 t->tm_gmtoff < 0 ? '-': '+', 867 h, s); 868 else 869 snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d %c%02d%02d", 870 mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900, 871 t->tm_hour, t->tm_min, 872 t->tm_gmtoff < 0 ? '-': '+', 873 h, s); 874 } 875# else 876 if ( precision == 's' ) 877 snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d", 878 mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900, 879 t->tm_hour, t->tm_min, t->tm_sec); 880 else 881 snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d", 882 mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900, 883 t->tm_hour, t->tm_min); 884# endif 885#endif 886 887 return timestr; 888} 889 890/***************************************************************** 891** time2isostr (sec, precison) 892** sec is seconds since 1.1.1970 893** precison is currently either 's' (for seconds) or 'm' (minutes) 894*****************************************************************/ 895char *time2isostr (time_t sec, int precision) 896{ 897 struct tm *t; 898 static char timestr[31+1]; /* 27+1 should be enough */ 899 900 timestr[0] = '\0'; 901 if ( sec <= 0L ) 902 return timestr; 903 904 t = gmtime (&sec); 905 if ( precision == 's' ) 906 snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d%02d", 907 t->tm_year + 1900, t->tm_mon+1, t->tm_mday, 908 t->tm_hour, t->tm_min, t->tm_sec); 909 else 910 snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d", 911 t->tm_year + 1900, t->tm_mon+1, t->tm_mday, 912 t->tm_hour, t->tm_min); 913 914 return timestr; 915} 916 917/***************************************************************** 918** age2str (sec) 919** !!Attention: This function is not reentrant 920*****************************************************************/ 921char *age2str (time_t sec) 922{ 923 static char str[20+1]; /* "2y51w6d23h50m55s" == 16+1 chars */ 924 int len; 925 int strsize = sizeof (str); 926 927 len = 0; 928# if PRINT_AGE_WITH_YEAR 929 if ( sec / (YEARSEC) > 0 ) 930 { 931 len += snprintf (str+len, strsize - len, "%1luy", sec / YEARSEC ); 932 sec %= (YEARSEC); 933 } 934 else 935 len += snprintf (str+len, strsize - len, " "); 936# endif 937 if ( sec / WEEKSEC > 0 ) 938 { 939 len += snprintf (str+len, strsize - len, "%2luw", (ulong) sec / WEEKSEC ); 940 sec %= WEEKSEC; 941 } 942 else 943 len += snprintf (str+len, strsize - len, " "); 944 if ( sec / DAYSEC > 0 ) 945 { 946 len += snprintf (str+len, strsize - len, "%2lud", sec / (ulong)DAYSEC); 947 sec %= DAYSEC; 948 } 949 else 950 len += snprintf (str+len, strsize - len, " "); 951 if ( sec / HOURSEC > 0 ) 952 { 953 len += snprintf (str+len, strsize - len, "%2luh", sec / (ulong)HOURSEC); 954 sec %= HOURSEC; 955 } 956 else 957 len += snprintf (str+len, strsize - len, " "); 958 if ( sec / MINSEC > 0 ) 959 { 960 len += snprintf (str+len, strsize - len, "%2lum", sec / (ulong)MINSEC); 961 sec %= MINSEC; 962 } 963 else 964 len += snprintf (str+len, strsize - len, " "); 965 if ( sec > 0 ) 966 snprintf (str+len, strsize - len, "%2lus", (ulong) sec); 967 else 968 len += snprintf (str+len, strsize - len, " "); 969 970 return str; 971} 972 973/***************************************************************** 974** start_timer () 975*****************************************************************/ 976time_t start_timer () 977{ 978 return (time(NULL)); 979} 980 981/***************************************************************** 982** stop_timer () 983*****************************************************************/ 984time_t stop_timer (time_t start) 985{ 986 time_t stop = time (NULL); 987 988 return stop - start; 989} 990 991 992/**************************************************************** 993** 994** int gensalt (saltstr, sizeofsaltstr, bits) 995** 996** generate a random hexstring of 'bits' salt and store it 997** in saltstr. return 1 on success, otherwise 0. 998** 999*****************************************************************/ 1000int gensalt (char *salt, size_t saltsize, int saltbits, unsigned int seed) 1001{ 1002 static char hexstr[] = "0123456789ABCDEF"; 1003 int saltlen = 0; /* current length of salt in hex nibbles */ 1004 int i; 1005 int hex; 1006 1007 if ( seed == 0 ) 1008 srandom (seed = (unsigned int)time (NULL)); 1009 1010 saltlen = saltbits / 4; 1011 if ( saltlen+1 > saltsize ) 1012 return 0; 1013 1014 for ( i = 0; i < saltlen; i++ ) 1015 { 1016 hex = random () % 16; 1017 assert ( hex >= 0 && hex < 16 ); 1018 salt[i] = hexstr[hex]; 1019 } 1020 salt[i] = '\0'; 1021 1022 return 1; 1023} 1024 1025 1026#ifdef COPYZONE_TEST 1027const char *progname; 1028main (int argc, char *argv[]) 1029{ 1030 progname = *argv; 1031 1032 if ( copyzonefile (argv[1], NULL) < 0 ) 1033 error ("can't copy zone file %s\n", argv[1]); 1034} 1035#endif 1036 1037#ifdef URL_TEST 1038const char *progname; 1039main (int argc, char *argv[]) 1040{ 1041 char *proto; 1042 char *host; 1043 char *port; 1044 char *para; 1045 char url[1024]; 1046 1047 progname = *argv; 1048 1049 proto = host = port = para = NULL; 1050 1051 if ( --argc <= 0 ) 1052 { 1053 fprintf (stderr, "usage: url_test <url>\n"); 1054 fprintf (stderr, "e.g.: url_test http://www.hznet.de:80/zkt\n"); 1055 exit (1); 1056 } 1057 1058 strcpy (url, argv[1]); 1059 parseurl (url, &proto, &host, &port, ¶); 1060 1061 if ( proto ) 1062 printf ("proto: \"%s\"\n", proto); 1063 if ( host ) 1064 printf ("host: \"%s\"\n", host); 1065 if ( port ) 1066 printf ("port: \"%s\"\n", port); 1067 if ( para ) 1068 printf ("para: \"%s\"\n", para); 1069 1070} 1071#endif 1072 1073