Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /** |
michael@0 | 2 | util.c |
michael@0 | 3 | |
michael@0 | 4 | |
michael@0 | 5 | Copyright (C) 2001-2003, Network Resonance, Inc. |
michael@0 | 6 | Copyright (C) 2006, Network Resonance, Inc. |
michael@0 | 7 | All Rights Reserved |
michael@0 | 8 | |
michael@0 | 9 | Redistribution and use in source and binary forms, with or without |
michael@0 | 10 | modification, are permitted provided that the following conditions |
michael@0 | 11 | are met: |
michael@0 | 12 | |
michael@0 | 13 | 1. Redistributions of source code must retain the above copyright |
michael@0 | 14 | notice, this list of conditions and the following disclaimer. |
michael@0 | 15 | 2. Redistributions in binary form must reproduce the above copyright |
michael@0 | 16 | notice, this list of conditions and the following disclaimer in the |
michael@0 | 17 | documentation and/or other materials provided with the distribution. |
michael@0 | 18 | 3. Neither the name of Network Resonance, Inc. nor the name of any |
michael@0 | 19 | contributors to this software may be used to endorse or promote |
michael@0 | 20 | products derived from this software without specific prior written |
michael@0 | 21 | permission. |
michael@0 | 22 | |
michael@0 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' |
michael@0 | 24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
michael@0 | 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
michael@0 | 26 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
michael@0 | 27 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
michael@0 | 28 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
michael@0 | 29 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
michael@0 | 30 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
michael@0 | 31 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
michael@0 | 32 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
michael@0 | 33 | POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 34 | |
michael@0 | 35 | |
michael@0 | 36 | ekr@rtfm.com Wed Dec 26 17:19:36 2001 |
michael@0 | 37 | */ |
michael@0 | 38 | |
michael@0 | 39 | |
michael@0 | 40 | static char *RCSSTRING __UNUSED__ ="$Id: util.c,v 1.5 2007/11/21 00:09:13 adamcain Exp $"; |
michael@0 | 41 | |
michael@0 | 42 | #ifndef WIN32 |
michael@0 | 43 | #include <sys/uio.h> |
michael@0 | 44 | #include <pwd.h> |
michael@0 | 45 | #include <dirent.h> |
michael@0 | 46 | #endif |
michael@0 | 47 | #include <string.h> |
michael@0 | 48 | #include <errno.h> |
michael@0 | 49 | #include <ctype.h> |
michael@0 | 50 | #include <sys/stat.h> |
michael@0 | 51 | #ifdef OPENSSL |
michael@0 | 52 | #include <openssl/evp.h> |
michael@0 | 53 | #endif |
michael@0 | 54 | #include "nr_common.h" |
michael@0 | 55 | #include "r_common.h" |
michael@0 | 56 | #include "registry.h" |
michael@0 | 57 | #include "util.h" |
michael@0 | 58 | #include "r_log.h" |
michael@0 | 59 | |
michael@0 | 60 | int nr_util_default_log_facility=LOG_COMMON; |
michael@0 | 61 | |
michael@0 | 62 | int nr_get_filename(base,name,namep) |
michael@0 | 63 | char *base; |
michael@0 | 64 | char *name; |
michael@0 | 65 | char **namep; |
michael@0 | 66 | { |
michael@0 | 67 | int len=strlen(base)+strlen(name)+2; |
michael@0 | 68 | char *ret=0; |
michael@0 | 69 | int _status; |
michael@0 | 70 | |
michael@0 | 71 | if(!(ret=(char *)RMALLOC(len))) |
michael@0 | 72 | ABORT(R_NO_MEMORY); |
michael@0 | 73 | if(base[strlen(base)-1]!='/'){ |
michael@0 | 74 | sprintf(ret,"%s/%s",base,name); |
michael@0 | 75 | } |
michael@0 | 76 | else{ |
michael@0 | 77 | sprintf(ret,"%s%s",base,name); |
michael@0 | 78 | } |
michael@0 | 79 | *namep=ret; |
michael@0 | 80 | _status=0; |
michael@0 | 81 | abort: |
michael@0 | 82 | return(_status); |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | #if 0 |
michael@0 | 86 | int read_RSA_private_key(base,name,keyp) |
michael@0 | 87 | char *base; |
michael@0 | 88 | char *name; |
michael@0 | 89 | RSA **keyp; |
michael@0 | 90 | { |
michael@0 | 91 | char *keyfile=0; |
michael@0 | 92 | BIO *bio=0; |
michael@0 | 93 | FILE *fp=0; |
michael@0 | 94 | RSA *rsa=0; |
michael@0 | 95 | int r,_status; |
michael@0 | 96 | |
michael@0 | 97 | /* Load the keyfile */ |
michael@0 | 98 | if(r=get_filename(base,name,&keyfile)) |
michael@0 | 99 | ABORT(r); |
michael@0 | 100 | if(!(fp=fopen(keyfile,"r"))) |
michael@0 | 101 | ABORT(R_NOT_FOUND); |
michael@0 | 102 | if(!(bio=BIO_new(BIO_s_file()))) |
michael@0 | 103 | ABORT(R_NO_MEMORY); |
michael@0 | 104 | BIO_set_fp(bio,fp,BIO_NOCLOSE); |
michael@0 | 105 | |
michael@0 | 106 | if(!(rsa=PEM_read_bio_RSAPrivateKey(bio,0,0,0))) |
michael@0 | 107 | ABORT(R_NOT_FOUND); |
michael@0 | 108 | |
michael@0 | 109 | *keyp=rsa; |
michael@0 | 110 | _status=0; |
michael@0 | 111 | abort: |
michael@0 | 112 | return(_status); |
michael@0 | 113 | } |
michael@0 | 114 | #endif |
michael@0 | 115 | |
michael@0 | 116 | |
michael@0 | 117 | void nr_errprintf_log(const char *format,...) |
michael@0 | 118 | { |
michael@0 | 119 | va_list ap; |
michael@0 | 120 | |
michael@0 | 121 | va_start(ap,format); |
michael@0 | 122 | |
michael@0 | 123 | r_vlog(nr_util_default_log_facility,LOG_ERR,format,ap); |
michael@0 | 124 | |
michael@0 | 125 | va_end(ap); |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | void nr_errprintf_log2(void *ignore, const char *format,...) |
michael@0 | 129 | { |
michael@0 | 130 | va_list ap; |
michael@0 | 131 | |
michael@0 | 132 | va_start(ap,format); |
michael@0 | 133 | |
michael@0 | 134 | r_vlog(nr_util_default_log_facility,LOG_ERR,format,ap); |
michael@0 | 135 | |
michael@0 | 136 | va_end(ap); |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | |
michael@0 | 140 | int nr_fwrite_all(FILE *fp,UCHAR *buf,int len) |
michael@0 | 141 | { |
michael@0 | 142 | int r,_status; |
michael@0 | 143 | |
michael@0 | 144 | while(len){ |
michael@0 | 145 | r=fwrite(buf,1,len,fp); |
michael@0 | 146 | if(r==0) |
michael@0 | 147 | ABORT(R_IO_ERROR); |
michael@0 | 148 | |
michael@0 | 149 | len-=r; |
michael@0 | 150 | buf+=r; |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | _status=0; |
michael@0 | 154 | abort: |
michael@0 | 155 | return(_status); |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | int nr_read_data(fd,buf,len) |
michael@0 | 159 | int fd; |
michael@0 | 160 | char *buf; |
michael@0 | 161 | int len; |
michael@0 | 162 | { |
michael@0 | 163 | int r,_status; |
michael@0 | 164 | |
michael@0 | 165 | while(len){ |
michael@0 | 166 | r=NR_SOCKET_READ(fd,buf,len); |
michael@0 | 167 | if(r<=0) |
michael@0 | 168 | ABORT(R_EOD); |
michael@0 | 169 | |
michael@0 | 170 | buf+=r; |
michael@0 | 171 | len-=r; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | |
michael@0 | 175 | _status=0; |
michael@0 | 176 | abort: |
michael@0 | 177 | return(_status); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | #ifdef WIN32 |
michael@0 | 181 | // TODO |
michael@0 | 182 | #else |
michael@0 | 183 | int nr_drop_privileges(char *username) |
michael@0 | 184 | { |
michael@0 | 185 | int _status; |
michael@0 | 186 | |
michael@0 | 187 | /* Drop privileges */ |
michael@0 | 188 | if ((getuid() == 0) || geteuid()==0) { |
michael@0 | 189 | struct passwd *passwd; |
michael@0 | 190 | |
michael@0 | 191 | if ((passwd = getpwnam(CAPTURE_USER)) == 0){ |
michael@0 | 192 | r_log(LOG_GENERIC,LOG_EMERG,"Couldn't get user %s",CAPTURE_USER); |
michael@0 | 193 | ABORT(R_INTERNAL); |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | if(setuid(passwd->pw_uid)!=0){ |
michael@0 | 197 | r_log(LOG_GENERIC,LOG_EMERG,"Couldn't drop privileges"); |
michael@0 | 198 | ABORT(R_INTERNAL); |
michael@0 | 199 | } |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | _status=0; |
michael@0 | 203 | abort: |
michael@0 | 204 | return(_status); |
michael@0 | 205 | } |
michael@0 | 206 | #endif |
michael@0 | 207 | |
michael@0 | 208 | int nr_bin2hex(UCHAR *in,int len,UCHAR *out) |
michael@0 | 209 | { |
michael@0 | 210 | while(len){ |
michael@0 | 211 | sprintf((char*)out,"%.2x",in[0] & 0xff); |
michael@0 | 212 | |
michael@0 | 213 | in+=1; |
michael@0 | 214 | out+=2; |
michael@0 | 215 | |
michael@0 | 216 | len--; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | return(0); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | int nr_hex_ascii_dump(Data *data) |
michael@0 | 223 | { |
michael@0 | 224 | UCHAR *ptr=data->data; |
michael@0 | 225 | int len=data->len; |
michael@0 | 226 | |
michael@0 | 227 | while(len){ |
michael@0 | 228 | int i; |
michael@0 | 229 | int bytes=MIN(len,16); |
michael@0 | 230 | |
michael@0 | 231 | for(i=0;i<bytes;i++) |
michael@0 | 232 | printf("%.2x ",ptr[i]&255); |
michael@0 | 233 | /* Fill */ |
michael@0 | 234 | for(i=0;i<(16-bytes);i++) |
michael@0 | 235 | printf(" "); |
michael@0 | 236 | printf(" "); |
michael@0 | 237 | |
michael@0 | 238 | for(i=0;i<bytes;i++){ |
michael@0 | 239 | if(isprint(ptr[i])) |
michael@0 | 240 | printf("%c",ptr[i]); |
michael@0 | 241 | else |
michael@0 | 242 | printf("."); |
michael@0 | 243 | } |
michael@0 | 244 | printf("\n"); |
michael@0 | 245 | |
michael@0 | 246 | len-=bytes; |
michael@0 | 247 | ptr+=bytes; |
michael@0 | 248 | } |
michael@0 | 249 | return(0); |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | #ifdef OPENSSL |
michael@0 | 253 | int nr_sha1_file(char *filename,UCHAR *out) |
michael@0 | 254 | { |
michael@0 | 255 | EVP_MD_CTX md_ctx; |
michael@0 | 256 | FILE *fp=0; |
michael@0 | 257 | int r,_status; |
michael@0 | 258 | UCHAR buf[1024]; |
michael@0 | 259 | int out_len; |
michael@0 | 260 | |
michael@0 | 261 | EVP_MD_CTX_init(&md_ctx); |
michael@0 | 262 | |
michael@0 | 263 | if(!(fp=fopen(filename,"r"))){ |
michael@0 | 264 | r_log(LOG_COMMON,LOG_ERR,"Couldn't open file %s",filename); |
michael@0 | 265 | ABORT(R_NOT_FOUND); |
michael@0 | 266 | } |
michael@0 | 267 | |
michael@0 | 268 | EVP_DigestInit_ex(&md_ctx,EVP_sha1(),0); |
michael@0 | 269 | |
michael@0 | 270 | while(1){ |
michael@0 | 271 | r=fread(buf,1,sizeof(buf),fp); |
michael@0 | 272 | |
michael@0 | 273 | if(r<0){ |
michael@0 | 274 | r_log(LOG_COMMON,LOG_ERR,"Error reading from %s",filename); |
michael@0 | 275 | ABORT(R_INTERNAL); |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | if(!r) |
michael@0 | 279 | break; |
michael@0 | 280 | |
michael@0 | 281 | EVP_DigestUpdate(&md_ctx,buf,r); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | EVP_DigestFinal(&md_ctx,out,(unsigned int*)&out_len); |
michael@0 | 285 | if(out_len!=20) |
michael@0 | 286 | ABORT(R_INTERNAL); |
michael@0 | 287 | |
michael@0 | 288 | _status=0; |
michael@0 | 289 | abort: |
michael@0 | 290 | EVP_MD_CTX_cleanup(&md_ctx); |
michael@0 | 291 | if(fp) fclose(fp); |
michael@0 | 292 | |
michael@0 | 293 | return(_status); |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | #endif |
michael@0 | 297 | |
michael@0 | 298 | #ifdef WIN32 |
michael@0 | 299 | // TODO |
michael@0 | 300 | #else |
michael@0 | 301 | |
michael@0 | 302 | #if 0 |
michael@0 | 303 | |
michael@0 | 304 | #include <fts.h> |
michael@0 | 305 | |
michael@0 | 306 | int nr_rm_tree(char *path) |
michael@0 | 307 | { |
michael@0 | 308 | FTS *fts=0; |
michael@0 | 309 | FTSENT *p; |
michael@0 | 310 | int failed=0; |
michael@0 | 311 | int _status; |
michael@0 | 312 | char *argv[2]; |
michael@0 | 313 | |
michael@0 | 314 | argv[0]=path; |
michael@0 | 315 | argv[1]=0; |
michael@0 | 316 | |
michael@0 | 317 | if(!(fts=fts_open(argv,0,NULL))){ |
michael@0 | 318 | r_log_e(LOG_COMMON,LOG_ERR,"Couldn't open directory %s",path); |
michael@0 | 319 | ABORT(R_FAILED); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | while(p=fts_read(fts)){ |
michael@0 | 323 | switch(p->fts_info){ |
michael@0 | 324 | case FTS_D: |
michael@0 | 325 | break; |
michael@0 | 326 | case FTS_DOT: |
michael@0 | 327 | break; |
michael@0 | 328 | case FTS_ERR: |
michael@0 | 329 | r_log_e(LOG_COMMON,LOG_ERR,"Problem reading %s",p->fts_path); |
michael@0 | 330 | break; |
michael@0 | 331 | default: |
michael@0 | 332 | r_log(LOG_COMMON,LOG_DEBUG,"Removing %s",p->fts_path); |
michael@0 | 333 | errno=0; |
michael@0 | 334 | if(remove(p->fts_path)){ |
michael@0 | 335 | r_log_e(LOG_COMMON,LOG_ERR,"Problem removing %s",p->fts_path); |
michael@0 | 336 | failed=1; |
michael@0 | 337 | } |
michael@0 | 338 | } |
michael@0 | 339 | } |
michael@0 | 340 | |
michael@0 | 341 | if(failed) |
michael@0 | 342 | ABORT(R_FAILED); |
michael@0 | 343 | |
michael@0 | 344 | _status=0; |
michael@0 | 345 | abort: |
michael@0 | 346 | if(fts) fts_close(fts); |
michael@0 | 347 | return(_status); |
michael@0 | 348 | } |
michael@0 | 349 | #endif |
michael@0 | 350 | |
michael@0 | 351 | int nr_write_pid_file(char *pid_filename) |
michael@0 | 352 | { |
michael@0 | 353 | FILE *fp; |
michael@0 | 354 | int _status; |
michael@0 | 355 | |
michael@0 | 356 | if(!pid_filename) |
michael@0 | 357 | ABORT(R_BAD_ARGS); |
michael@0 | 358 | |
michael@0 | 359 | unlink(pid_filename); |
michael@0 | 360 | |
michael@0 | 361 | if(!(fp=fopen(pid_filename,"w"))){ |
michael@0 | 362 | r_log(LOG_GENERIC,LOG_CRIT,"Couldn't open PID file: %s",strerror(errno)); |
michael@0 | 363 | ABORT(R_NOT_FOUND); |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | fprintf(fp,"%d\n",getpid()); |
michael@0 | 367 | |
michael@0 | 368 | fclose(fp); |
michael@0 | 369 | |
michael@0 | 370 | chmod(pid_filename,S_IRUSR | S_IRGRP | S_IROTH); |
michael@0 | 371 | |
michael@0 | 372 | _status=0; |
michael@0 | 373 | abort: |
michael@0 | 374 | return(_status); |
michael@0 | 375 | } |
michael@0 | 376 | #endif |
michael@0 | 377 | |
michael@0 | 378 | int nr_reg_uint4_fetch_and_check(NR_registry key, UINT4 min, UINT4 max, int log_fac, int die, UINT4 *val) |
michael@0 | 379 | { |
michael@0 | 380 | int r,_status; |
michael@0 | 381 | UINT4 my_val; |
michael@0 | 382 | |
michael@0 | 383 | if(r=NR_reg_get_uint4(key,&my_val)){ |
michael@0 | 384 | r_log(log_fac,LOG_ERR,"Couldn't get key '%s', error %d",key,r); |
michael@0 | 385 | ABORT(r); |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | if((min>0) && (my_val<min)){ |
michael@0 | 389 | r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%lu, (min = %lu)",key,(unsigned long)my_val,(unsigned long)min); |
michael@0 | 390 | ABORT(R_BAD_DATA); |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | if(my_val>max){ |
michael@0 | 394 | r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%lu, (max = %lu)",key,(unsigned long)my_val,(unsigned long)max); |
michael@0 | 395 | ABORT(R_BAD_DATA); |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | *val=my_val; |
michael@0 | 399 | _status=0; |
michael@0 | 400 | |
michael@0 | 401 | abort: |
michael@0 | 402 | if(die && _status){ |
michael@0 | 403 | r_log(log_fac,LOG_CRIT,"Exiting due to invalid configuration (key '%s')",key); |
michael@0 | 404 | exit(1); |
michael@0 | 405 | } |
michael@0 | 406 | return(_status); |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_fac, int die, UINT8 *val) |
michael@0 | 410 | { |
michael@0 | 411 | int r,_status; |
michael@0 | 412 | UINT8 my_val; |
michael@0 | 413 | |
michael@0 | 414 | if(r=NR_reg_get_uint8(key,&my_val)){ |
michael@0 | 415 | r_log(log_fac,LOG_ERR,"Couldn't get key '%s', error %d",key,r); |
michael@0 | 416 | ABORT(r); |
michael@0 | 417 | } |
michael@0 | 418 | |
michael@0 | 419 | if(my_val<min){ |
michael@0 | 420 | r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%llu, (min = %llu)",key,my_val,min); |
michael@0 | 421 | ABORT(R_BAD_DATA); |
michael@0 | 422 | } |
michael@0 | 423 | |
michael@0 | 424 | if(my_val>max){ |
michael@0 | 425 | r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%llu, (max = %llu)",key,my_val,max); |
michael@0 | 426 | ABORT(R_BAD_DATA); |
michael@0 | 427 | } |
michael@0 | 428 | |
michael@0 | 429 | *val=my_val; |
michael@0 | 430 | _status=0; |
michael@0 | 431 | |
michael@0 | 432 | abort: |
michael@0 | 433 | if(die && _status){ |
michael@0 | 434 | r_log(log_fac,LOG_CRIT,"Exiting due to invalid configuration (key '%s')",key); |
michael@0 | 435 | exit(1); |
michael@0 | 436 | } |
michael@0 | 437 | return(_status); |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | #if defined(LINUX) || defined(WIN32) |
michael@0 | 441 | /*- |
michael@0 | 442 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
michael@0 | 443 | * All rights reserved. |
michael@0 | 444 | * |
michael@0 | 445 | * Redistribution and use in source and binary forms, with or without |
michael@0 | 446 | * modification, are permitted provided that the following conditions |
michael@0 | 447 | * are met: |
michael@0 | 448 | * 1. Redistributions of source code must retain the above copyright |
michael@0 | 449 | * notice, this list of conditions and the following disclaimer. |
michael@0 | 450 | * 2. Redistributions in binary form must reproduce the above copyright |
michael@0 | 451 | * notice, this list of conditions and the following disclaimer in the |
michael@0 | 452 | * documentation and/or other materials provided with the distribution. |
michael@0 | 453 | * 3. The name of the author may not be used to endorse or promote products |
michael@0 | 454 | * derived from this software without specific prior written permission. |
michael@0 | 455 | * |
michael@0 | 456 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
michael@0 | 457 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
michael@0 | 458 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
michael@0 | 459 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
michael@0 | 460 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
michael@0 | 461 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
michael@0 | 462 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
michael@0 | 463 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
michael@0 | 464 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
michael@0 | 465 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 466 | */ |
michael@0 | 467 | |
michael@0 | 468 | |
michael@0 | 469 | /* |
michael@0 | 470 | * Appends src to string dst of size siz (unlike strncat, siz is the |
michael@0 | 471 | * full size of dst, not space left). At most siz-1 characters |
michael@0 | 472 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
michael@0 | 473 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). |
michael@0 | 474 | * If retval >= siz, truncation occurred. |
michael@0 | 475 | */ |
michael@0 | 476 | size_t |
michael@0 | 477 | strlcat(dst, src, siz) |
michael@0 | 478 | char *dst; |
michael@0 | 479 | const char *src; |
michael@0 | 480 | size_t siz; |
michael@0 | 481 | { |
michael@0 | 482 | char *d = dst; |
michael@0 | 483 | const char *s = src; |
michael@0 | 484 | size_t n = siz; |
michael@0 | 485 | size_t dlen; |
michael@0 | 486 | |
michael@0 | 487 | /* Find the end of dst and adjust bytes left but don't go past end */ |
michael@0 | 488 | while (n-- != 0 && *d != '\0') |
michael@0 | 489 | d++; |
michael@0 | 490 | dlen = d - dst; |
michael@0 | 491 | n = siz - dlen; |
michael@0 | 492 | |
michael@0 | 493 | if (n == 0) |
michael@0 | 494 | return(dlen + strlen(s)); |
michael@0 | 495 | while (*s != '\0') { |
michael@0 | 496 | if (n != 1) { |
michael@0 | 497 | *d++ = *s; |
michael@0 | 498 | n--; |
michael@0 | 499 | } |
michael@0 | 500 | s++; |
michael@0 | 501 | } |
michael@0 | 502 | *d = '\0'; |
michael@0 | 503 | |
michael@0 | 504 | return(dlen + (s - src)); /* count does not include NUL */ |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | #endif /* LINUX or WIN32 */ |
michael@0 | 508 | |
michael@0 | 509 | #if defined(USE_OWN_INET_NTOP) || defined(WIN32) |
michael@0 | 510 | #include <errno.h> |
michael@0 | 511 | #ifdef WIN32 |
michael@0 | 512 | #include <Ws2ipdef.h> |
michael@0 | 513 | #ifndef EAFNOSUPPORT |
michael@0 | 514 | #define EAFNOSUPPORT WSAEAFNOSUPPORT |
michael@0 | 515 | #endif |
michael@0 | 516 | #else |
michael@0 | 517 | #include <sys/socket.h> |
michael@0 | 518 | #endif |
michael@0 | 519 | #define INET6 |
michael@0 | 520 | |
michael@0 | 521 | /* inet_ntop implementation from NetBSD */ |
michael@0 | 522 | |
michael@0 | 523 | /* |
michael@0 | 524 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
michael@0 | 525 | * Copyright (c) 1996-1999 by Internet Software Consortium. |
michael@0 | 526 | * |
michael@0 | 527 | * Permission to use, copy, modify, and distribute this software for any |
michael@0 | 528 | * purpose with or without fee is hereby granted, provided that the above |
michael@0 | 529 | * copyright notice and this permission notice appear in all copies. |
michael@0 | 530 | * |
michael@0 | 531 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
michael@0 | 532 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
michael@0 | 533 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
michael@0 | 534 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
michael@0 | 535 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
michael@0 | 536 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
michael@0 | 537 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
michael@0 | 538 | */ |
michael@0 | 539 | |
michael@0 | 540 | #if !defined(NS_INADDRSZ) |
michael@0 | 541 | # define NS_INADDRSZ 4 |
michael@0 | 542 | #endif |
michael@0 | 543 | #if !defined(NS_IN6ADDRSZ) |
michael@0 | 544 | # define NS_IN6ADDRSZ 16 |
michael@0 | 545 | #endif |
michael@0 | 546 | #if !defined(NS_INT16SZ) |
michael@0 | 547 | # define NS_INT16SZ 2 |
michael@0 | 548 | #endif |
michael@0 | 549 | |
michael@0 | 550 | /* |
michael@0 | 551 | * WARNING: Don't even consider trying to compile this on a system where |
michael@0 | 552 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. |
michael@0 | 553 | */ |
michael@0 | 554 | |
michael@0 | 555 | static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); |
michael@0 | 556 | #ifdef INET6 |
michael@0 | 557 | static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); |
michael@0 | 558 | #endif /* INET6 */ |
michael@0 | 559 | |
michael@0 | 560 | /* char * |
michael@0 | 561 | * inet_ntop(af, src, dst, size) |
michael@0 | 562 | * convert a network format address to presentation format. |
michael@0 | 563 | * return: |
michael@0 | 564 | * pointer to presentation format address (`dst'), or NULL (see errno). |
michael@0 | 565 | * author: |
michael@0 | 566 | * Paul Vixie, 1996. |
michael@0 | 567 | */ |
michael@0 | 568 | const char * |
michael@0 | 569 | inet_ntop(int af, const void *src, char *dst, size_t size) |
michael@0 | 570 | { |
michael@0 | 571 | |
michael@0 | 572 | switch (af) { |
michael@0 | 573 | case AF_INET: |
michael@0 | 574 | return (inet_ntop4(src, dst, size)); |
michael@0 | 575 | #ifdef INET6 |
michael@0 | 576 | case AF_INET6: |
michael@0 | 577 | return (inet_ntop6(src, dst, size)); |
michael@0 | 578 | #endif /* INET6 */ |
michael@0 | 579 | default: |
michael@0 | 580 | errno = EAFNOSUPPORT; |
michael@0 | 581 | return (NULL); |
michael@0 | 582 | } |
michael@0 | 583 | /* NOTREACHED */ |
michael@0 | 584 | } |
michael@0 | 585 | |
michael@0 | 586 | /* const char * |
michael@0 | 587 | * inet_ntop4(src, dst, size) |
michael@0 | 588 | * format an IPv4 address, more or less like inet_ntoa() |
michael@0 | 589 | * return: |
michael@0 | 590 | * `dst' (as a const) |
michael@0 | 591 | * notes: |
michael@0 | 592 | * (1) uses no statics |
michael@0 | 593 | * (2) takes a unsigned char* not an in_addr as input |
michael@0 | 594 | * author: |
michael@0 | 595 | * Paul Vixie, 1996. |
michael@0 | 596 | */ |
michael@0 | 597 | static const char * |
michael@0 | 598 | inet_ntop4(const unsigned char *src, char *dst, size_t size) |
michael@0 | 599 | { |
michael@0 | 600 | char tmp[sizeof "255.255.255.255"]; |
michael@0 | 601 | int l; |
michael@0 | 602 | |
michael@0 | 603 | l = snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u", |
michael@0 | 604 | src[0], src[1], src[2], src[3]); |
michael@0 | 605 | if (l <= 0 || (size_t) l >= size) { |
michael@0 | 606 | errno = ENOSPC; |
michael@0 | 607 | return (NULL); |
michael@0 | 608 | } |
michael@0 | 609 | strlcpy(dst, tmp, size); |
michael@0 | 610 | return (dst); |
michael@0 | 611 | } |
michael@0 | 612 | |
michael@0 | 613 | #ifdef INET6 |
michael@0 | 614 | /* const char * |
michael@0 | 615 | * inet_ntop6(src, dst, size) |
michael@0 | 616 | * convert IPv6 binary address into presentation (printable) format |
michael@0 | 617 | * author: |
michael@0 | 618 | * Paul Vixie, 1996. |
michael@0 | 619 | */ |
michael@0 | 620 | static const char * |
michael@0 | 621 | inet_ntop6(const unsigned char *src, char *dst, size_t size) |
michael@0 | 622 | { |
michael@0 | 623 | /* |
michael@0 | 624 | * Note that int32_t and int16_t need only be "at least" large enough |
michael@0 | 625 | * to contain a value of the specified size. On some systems, like |
michael@0 | 626 | * Crays, there is no such thing as an integer variable with 16 bits. |
michael@0 | 627 | * Keep this in mind if you think this function should have been coded |
michael@0 | 628 | * to use pointer overlays. All the world's not a VAX. |
michael@0 | 629 | */ |
michael@0 | 630 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; |
michael@0 | 631 | char *tp, *ep; |
michael@0 | 632 | struct { int base, len; } best, cur; |
michael@0 | 633 | unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; |
michael@0 | 634 | int i; |
michael@0 | 635 | int advance; |
michael@0 | 636 | |
michael@0 | 637 | /* |
michael@0 | 638 | * Preprocess: |
michael@0 | 639 | * Copy the input (bytewise) array into a wordwise array. |
michael@0 | 640 | * Find the longest run of 0x00's in src[] for :: shorthanding. |
michael@0 | 641 | */ |
michael@0 | 642 | memset(words, '\0', sizeof words); |
michael@0 | 643 | for (i = 0; i < NS_IN6ADDRSZ; i++) |
michael@0 | 644 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); |
michael@0 | 645 | best.base = -1; |
michael@0 | 646 | cur.base = -1; |
michael@0 | 647 | best.len = -1; /* XXX gcc */ |
michael@0 | 648 | cur.len = -1; /* XXX gcc */ |
michael@0 | 649 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
michael@0 | 650 | if (words[i] == 0) { |
michael@0 | 651 | if (cur.base == -1) |
michael@0 | 652 | cur.base = i, cur.len = 1; |
michael@0 | 653 | else |
michael@0 | 654 | cur.len++; |
michael@0 | 655 | } else { |
michael@0 | 656 | if (cur.base != -1) { |
michael@0 | 657 | if (best.base == -1 || cur.len > best.len) |
michael@0 | 658 | best = cur; |
michael@0 | 659 | cur.base = -1; |
michael@0 | 660 | } |
michael@0 | 661 | } |
michael@0 | 662 | } |
michael@0 | 663 | if (cur.base != -1) { |
michael@0 | 664 | if (best.base == -1 || cur.len > best.len) |
michael@0 | 665 | best = cur; |
michael@0 | 666 | } |
michael@0 | 667 | if (best.base != -1 && best.len < 2) |
michael@0 | 668 | best.base = -1; |
michael@0 | 669 | |
michael@0 | 670 | /* |
michael@0 | 671 | * Format the result. |
michael@0 | 672 | */ |
michael@0 | 673 | tp = tmp; |
michael@0 | 674 | ep = tmp + sizeof(tmp); |
michael@0 | 675 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
michael@0 | 676 | /* Are we inside the best run of 0x00's? */ |
michael@0 | 677 | if (best.base != -1 && i >= best.base && |
michael@0 | 678 | i < (best.base + best.len)) { |
michael@0 | 679 | if (i == best.base) |
michael@0 | 680 | *tp++ = ':'; |
michael@0 | 681 | continue; |
michael@0 | 682 | } |
michael@0 | 683 | /* Are we following an initial run of 0x00s or any real hex? */ |
michael@0 | 684 | if (i != 0) { |
michael@0 | 685 | if (tp + 1 >= ep) |
michael@0 | 686 | return (NULL); |
michael@0 | 687 | *tp++ = ':'; |
michael@0 | 688 | } |
michael@0 | 689 | /* Is this address an encapsulated IPv4? */ |
michael@0 | 690 | if (i == 6 && best.base == 0 && |
michael@0 | 691 | (best.len == 6 || |
michael@0 | 692 | (best.len == 7 && words[7] != 0x0001) || |
michael@0 | 693 | (best.len == 5 && words[5] == 0xffff))) { |
michael@0 | 694 | if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) |
michael@0 | 695 | return (NULL); |
michael@0 | 696 | tp += strlen(tp); |
michael@0 | 697 | break; |
michael@0 | 698 | } |
michael@0 | 699 | advance = snprintf(tp, (size_t)(ep - tp), "%x", words[i]); |
michael@0 | 700 | if (advance <= 0 || advance >= ep - tp) |
michael@0 | 701 | return (NULL); |
michael@0 | 702 | tp += advance; |
michael@0 | 703 | } |
michael@0 | 704 | /* Was it a trailing run of 0x00's? */ |
michael@0 | 705 | if (best.base != -1 && (best.base + best.len) == |
michael@0 | 706 | (NS_IN6ADDRSZ / NS_INT16SZ)) { |
michael@0 | 707 | if (tp + 1 >= ep) |
michael@0 | 708 | return (NULL); |
michael@0 | 709 | *tp++ = ':'; |
michael@0 | 710 | } |
michael@0 | 711 | if (tp + 1 >= ep) |
michael@0 | 712 | return (NULL); |
michael@0 | 713 | *tp++ = '\0'; |
michael@0 | 714 | |
michael@0 | 715 | /* |
michael@0 | 716 | * Check for overflow, copy, and we're done. |
michael@0 | 717 | */ |
michael@0 | 718 | if ((size_t)(tp - tmp) > size) { |
michael@0 | 719 | errno = ENOSPC; |
michael@0 | 720 | return (NULL); |
michael@0 | 721 | } |
michael@0 | 722 | strlcpy(dst, tmp, size); |
michael@0 | 723 | return (dst); |
michael@0 | 724 | } |
michael@0 | 725 | #endif /* INET6 */ |
michael@0 | 726 | |
michael@0 | 727 | #endif |
michael@0 | 728 | |
michael@0 | 729 | #ifdef WIN32 |
michael@0 | 730 | #include <time.h> |
michael@0 | 731 | /* this is only millisecond-accurate, but that should be OK */ |
michael@0 | 732 | |
michael@0 | 733 | int gettimeofday(struct timeval *tv, void *tz) |
michael@0 | 734 | { |
michael@0 | 735 | SYSTEMTIME st; |
michael@0 | 736 | FILETIME ft; |
michael@0 | 737 | ULARGE_INTEGER u; |
michael@0 | 738 | |
michael@0 | 739 | GetLocalTime (&st); |
michael@0 | 740 | |
michael@0 | 741 | /* strangely, the FILETIME is the number of 100 nanosecond (0.1 us) intervals |
michael@0 | 742 | * since the Epoch */ |
michael@0 | 743 | SystemTimeToFileTime(&st, &ft); |
michael@0 | 744 | u.HighPart = ft.dwHighDateTime; |
michael@0 | 745 | u.LowPart = ft.dwLowDateTime; |
michael@0 | 746 | |
michael@0 | 747 | tv->tv_sec = (long) (u.QuadPart / 10000000L); |
michael@0 | 748 | tv->tv_usec = (long) (st.wMilliseconds * 1000);; |
michael@0 | 749 | |
michael@0 | 750 | return 0; |
michael@0 | 751 | } |
michael@0 | 752 | |
michael@0 | 753 | int snprintf(char *buffer, size_t n, const char *format, ...) |
michael@0 | 754 | { |
michael@0 | 755 | va_list argp; |
michael@0 | 756 | int ret; |
michael@0 | 757 | va_start(argp, format); |
michael@0 | 758 | ret = _vscprintf(format, argp); |
michael@0 | 759 | vsnprintf_s(buffer, n, _TRUNCATE, format, argp); |
michael@0 | 760 | va_end(argp); |
michael@0 | 761 | return ret; |
michael@0 | 762 | } |
michael@0 | 763 | |
michael@0 | 764 | #endif |
michael@0 | 765 |