2  * The contents of this file are subject to the Mozilla Public 
   3  * License Version 1.1 (the "License"); you may not use this file 
   4  * except in compliance with the License. You may obtain a copy of 
   5  * the License at http://www.mozilla.org/MPL/ 
   7  * Software distributed under the License is distributed on an "AS 
   8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 
   9  * implied. See the License for the specific language governing 
  10  * rights and limitations under the License. 
  12  * The Original Code is the Netscape security libraries. 
  14  * The Initial Developer of the Original Code is Netscape 
  15  * Communications Corporation.  Portions created by Netscape are  
  16  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All 
  21  * Alternatively, the contents of this file may be used under the 
  22  * terms of the GNU General Public License Version 2 or later (the 
  23  * "GPL"), in which case the provisions of the GPL are applicable  
  24  * instead of those above.  If you wish to allow use of your  
  25  * version of this file only under the terms of the GPL and not to 
  26  * allow others to use your version of this file under the MPL, 
  27  * indicate your decision by deleting the provisions above and 
  28  * replace them with the notice and other provisions required by 
  29  * the GPL.  If you do not delete the provisions above, a recipient 
  30  * may use your version of this file under either the MPL or the 
  35  * secport.c - portability interfaces for security libraries 
  37  * This file abstracts out libc functionality that libsec depends on 
  39  * NOTE - These are not public interfaces 
  41  * $Id: secport.c,v 1.5 2004/10/27 20:36:36 dmitch Exp $ 
  61 #endif /* THREADMARK */ 
  63 #if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_OS2) || defined(XP_BEOS) 
  69 #define SET_ERROR_CODE  /* place holder for code to set PR error code. */ 
  72 typedef struct threadmark_mark_str 
{ 
  73   struct threadmark_mark_str 
*next
; 
  77 #endif /* THREADMARK */ 
  79 /* The value of this magic must change each time PORTArenaPool changes. */ 
  80 #define ARENAPOOL_MAGIC 0xB8AC9BDF  
  82 /* enable/disable mutex in PORTArenaPool */ 
  83 #define ARENA_POOL_LOCK         0 
  85 typedef struct PORTArenaPool_str 
{ 
  92   PRThread 
*marking_thread
; 
  93   threadmark_mark 
*first_mark
; 
  98 /* count of allocation failures. */ 
  99 unsigned long port_allocFailures
; 
 102 /* locations for registering Unicode conversion functions.   
 103  * XXX is this the appropriate location?  or should they be 
 104  *     moved to client/server specific locations? 
 106 PORTCharConversionFunc ucs4Utf8ConvertFunc
; 
 107 PORTCharConversionFunc ucs2Utf8ConvertFunc
; 
 108 PORTCharConversionWSwapFunc  ucs2AsciiConvertFunc
; 
 109 #endif  /* __APPLE__ */ 
 111 /* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc) 
 112  * use the PRUint32 type for the size parameter. Before we pass a size_t or 
 113  * unsigned long size to these functions, we need to ensure it is <= half of 
 114  * the maximum PRUint32 value to avoid truncation and catch a negative size. 
 116 #define MAX_SIZE (PR_UINT32_MAX >> 1) 
 119 PORT_Alloc(size_t bytes
) 
 123     if (bytes 
<= MAX_SIZE
) { 
 124         /* Always allocate a non-zero amount of bytes */ 
 125         rv 
= PR_Malloc(bytes 
? bytes 
: 1); 
 128         ++port_allocFailures
; 
 129         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 135 PORT_Realloc(void *oldptr
, size_t bytes
) 
 139     if (bytes 
<= MAX_SIZE
) { 
 140         rv 
= PR_Realloc(oldptr
, bytes
); 
 143         ++port_allocFailures
; 
 144         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 150 PORT_ZAlloc(size_t bytes
) 
 154     if (bytes 
<= MAX_SIZE
) { 
 155         /* Always allocate a non-zero amount of bytes */ 
 156         rv 
= PR_Calloc(1, bytes 
? bytes 
: 1); 
 159         ++port_allocFailures
; 
 160         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 174 PORT_ZFree(void *ptr
, size_t len
) 
 183 PORT_Strdup(const char *str
) 
 185     size_t len 
= PORT_Strlen(str
)+1; 
 188     newstr 
= (char *)PORT_Alloc(len
); 
 190         PORT_Memcpy(newstr
, str
, len
); 
 196 PORT_SetError(int value
) 
 198     PR_SetError(value
, 0); 
 205     return(PR_GetError()); 
 208 /********************* Arena code follows *****************************/ 
 211 PORT_NewArena(unsigned long chunksize
) 
 215     if (chunksize 
> MAX_SIZE
) { 
 216         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 219     pool 
= PORT_ZNew(PORTArenaPool
); 
 223     pool
->magic 
= ARENAPOOL_MAGIC
; 
 225     pool
->lock 
= PZ_NewLock(nssILockArena
); 
 227                 ++port_allocFailures
; 
 232     PL_InitArenaPool(&pool
->arena
, "security", (PRUint32
)chunksize
, sizeof(double)); 
 233     return(&pool
->arena
); 
 237 PORT_ArenaAlloc(PLArenaPool 
*arena
, size_t size
) 
 241     PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 247     if (size 
> MAX_SIZE
) { 
 250     /* Is it one of ours?  Assume so and check the magic */ 
 251     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 255                         /* Most likely one of ours.  Is there a thread id? */ 
 256                 if (pool
->marking_thread  
&& 
 257                         pool
->marking_thread 
!= PR_GetCurrentThread() ) { 
 258                         /* Another thread holds a mark in this arena */ 
 259                         PZ_Unlock(pool
->lock
); 
 260                         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 264                 #endif /* THREADMARK */ 
 265                 #endif /* ARENA_POOL_LOCK */ 
 266                 PL_ARENA_ALLOCATE(p
, arena
, (PRUint32
)size
); 
 268                 PZ_Unlock(pool
->lock
); 
 271                 PL_ARENA_ALLOCATE(p
, arena
, (PRUint32
)size
); 
 275         ++port_allocFailures
; 
 276         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 283 PORT_ArenaZAlloc(PLArenaPool 
*arena
, size_t size
) 
 290     p 
= PORT_ArenaAlloc(arena
, size
); 
 293         PORT_Memset(p
, 0, size
); 
 300  * If zero is true, zeroize the arena memory before freeing it. 
 303 PORT_FreeArena(PLArenaPool 
*arena
, PRBool zero
) 
 305     PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 307     PRLock 
*       lock 
= (PRLock 
*)0; 
 309     size_t         len  
= sizeof *arena
; 
 310     extern const PRVersionDescription 
* libVersionPoint(void); 
 312     static const PRVersionDescription 
* pvd
; 
 314     static PRBool  doFreeArenaPool 
= PR_FALSE
; 
 316     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 324         /* dmitch - not needed */ 
 326                 /* Each of NSPR's DLLs has a function libVersionPoint(). 
 327                 ** We could do a lot of extra work to be sure we're calling the 
 328                 ** one in the DLL that holds PR_FreeArenaPool, but instead we 
 329                 ** rely on the fact that ALL NSPR DLLs in the same directory 
 330                 ** must be from the same release, and we call which ever one we get.  
 332                 /* no need for thread protection here */ 
 333                 pvd 
= libVersionPoint(); 
 334                 if ((pvd
->vMajor 
> 4) ||  
 335                         (pvd
->vMajor 
== 4 && pvd
->vMinor 
> 1) || 
 336                         (pvd
->vMajor 
== 4 && pvd
->vMinor 
== 1 && pvd
->vPatch 
>= 1)) { 
 337                         const char *ev 
= PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST"); 
 338                         if (!ev
) doFreeArenaPool 
= PR_TRUE
; 
 343         PL_ClearArenaPool(arena
, 0); 
 346     if (doFreeArenaPool
) { 
 347                 PL_FreeArenaPool(arena
); 
 349                 PL_FinishArenaPool(arena
); 
 354                 PZ_DestroyLock(lock
); 
 357     PORT_ZFree(arena
, len
); 
 361 PORT_ArenaGrow(PLArenaPool 
*arena
, void *ptr
, size_t oldsize
, size_t newsize
) 
 363     PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 365     if (newsize 
> MAX_SIZE
) { 
 366         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 370     if (newsize 
< oldsize
) { 
 371         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
); // Not expected 
 375     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 379         /* Do we do a THREADMARK check here? */ 
 380             PL_ARENA_GROW(ptr
, arena
, (PRUint32
)oldsize
, (PRUint32
)( newsize 
- oldsize 
) ); 
 382             PZ_Unlock(pool
->lock
); 
 385         PL_ARENA_GROW(ptr
, arena
, (PRUint32
)oldsize
, (PRUint32
)( newsize 
- oldsize 
) ); 
 392 PORT_ArenaMark(PLArenaPool 
*arena
) 
 394 #if ARENA_MARK_ENABLE 
 397     PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 398     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 402           threadmark_mark 
*tm
, **pw
; 
 403           PRThread 
* currentThread 
= PR_GetCurrentThread(); 
 405             if (! pool
->marking_thread 
) { 
 407                 pool
->marking_thread 
= currentThread
; 
 408             } else if (currentThread 
!= pool
->marking_thread 
) { 
 409                 PZ_Unlock(pool
->lock
); 
 410                 PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 415             result 
= PL_ARENA_MARK(arena
); 
 416             PL_ARENA_ALLOCATE(tm
, arena
, sizeof(threadmark_mark
)); 
 418                 PZ_Unlock(pool
->lock
); 
 419                 PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 424             tm
->next 
= (threadmark_mark 
*)NULL
; 
 426             pw 
= &pool
->first_mark
; 
 433 #else /* THREADMARK */ 
 434         result 
= PL_ARENA_MARK(arena
); 
 435 #endif /* THREADMARK */ 
 436         PZ_Unlock(pool
->lock
); 
 438         /* a "pure" NSPR arena */ 
 439         result 
= PL_ARENA_MARK(arena
); 
 443         /* Some code in libsecurity_smime really checks for a nonzero  
 444          * return here, so... */ 
 450 PORT_ArenaRelease(PLArenaPool 
*arena
, void *mark
) 
 452 #if ARENA_MARK_ENABLE 
 453    PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 454     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 458             threadmark_mark 
**pw
, *tm
; 
 460             if (PR_GetCurrentThread() != pool
->marking_thread 
) { 
 461                 PZ_Unlock(pool
->lock
); 
 462                 PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 464                 return /* no error indication available */ ; 
 467             pw 
= &pool
->first_mark
; 
 468             while( *pw 
&& (mark 
!= (*pw
)->mark
) ) { 
 474                 PZ_Unlock(pool
->lock
); 
 475                 PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 477                 return /* no error indication available */ ; 
 481             *pw 
= (threadmark_mark 
*)NULL
; 
 483             PL_ARENA_RELEASE(arena
, mark
); 
 485             if (! pool
->first_mark 
) { 
 486                 pool
->marking_thread 
= (PRThread 
*)NULL
; 
 489 #else /* THREADMARK */ 
 490         PL_ARENA_RELEASE(arena
, mark
); 
 491 #endif /* THREADMARK */ 
 492         PZ_Unlock(pool
->lock
); 
 494         PL_ARENA_RELEASE(arena
, mark
); 
 496 #endif  /* ARENA_MARK_ENABLE */ 
 500 PORT_ArenaUnmark(PLArenaPool 
*arena
, void *mark
) 
 502 #if ARENA_MARK_ENABLE 
 504     PORTArenaPool 
*pool 
= (PORTArenaPool 
*)arena
; 
 505     if (ARENAPOOL_MAGIC 
== pool
->magic 
) { 
 506         threadmark_mark 
**pw
, *tm
; 
 510         if (PR_GetCurrentThread() != pool
->marking_thread 
) { 
 511             PZ_Unlock(pool
->lock
); 
 512             PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 514             return /* no error indication available */ ; 
 517         pw 
= &pool
->first_mark
; 
 518         while( ((threadmark_mark 
*)NULL 
!= *pw
) && (mark 
!= (*pw
)->mark
) ) { 
 522         if ((threadmark_mark 
*)NULL 
== *pw 
) { 
 524             PZ_Unlock(pool
->lock
); 
 525             PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 527             return /* no error indication available */ ; 
 531         *pw 
= (threadmark_mark 
*)NULL
; 
 533         if (! pool
->first_mark 
) { 
 534             pool
->marking_thread 
= (PRThread 
*)NULL
; 
 537         PZ_Unlock(pool
->lock
); 
 539 #endif  /* THREADMARK */ 
 540 #endif  /* ARENA_MARK_ENABLE */ 
 544 PORT_ArenaStrdup(PLArenaPool 
*arena
, const char *str
) { 
 545     size_t len 
= PORT_Strlen(str
)+1; 
 548     newstr 
= (char*)PORT_ArenaAlloc(arena
,len
); 
 550         PORT_Memcpy(newstr
,str
,len
); 
 555 /********************** end of arena functions ***********************/ 
 559 /****************** unicode conversion functions ***********************/ 
 561  * NOTE: These conversion functions all assume that the multibyte 
 562  * characters are going to be in NETWORK BYTE ORDER, not host byte 
 563  * order.  This is because the only time we deal with UCS-2 and UCS-4 
 564  * are when the data was received from or is going to be sent out 
 565  * over the wire (in, e.g. certificates). 
 569 PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc
) 
 571     ucs4Utf8ConvertFunc 
= convFunc
; 
 575 PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc
) 
 577     ucs2AsciiConvertFunc 
= convFunc
; 
 581 PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc
) 
 583     ucs2Utf8ConvertFunc 
= convFunc
; 
 587 /* dmitch - not needed */ 
 589 PORT_UCS4_UTF8Conversion(PRBool toUnicode
, unsigned char *inBuf
, 
 590                          unsigned int inBufLen
, unsigned char *outBuf
, 
 591                          unsigned int maxOutBufLen
, unsigned int *outBufLen
) 
 593     if(!ucs4Utf8ConvertFunc
) { 
 594       return sec_port_ucs4_utf8_conversion_function(toUnicode
, 
 595         inBuf
, inBufLen
, outBuf
, maxOutBufLen
, outBufLen
); 
 598     return (*ucs4Utf8ConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,  
 599                                   maxOutBufLen
, outBufLen
); 
 603 PORT_UCS2_UTF8Conversion(PRBool toUnicode
, unsigned char *inBuf
, 
 604                          unsigned int inBufLen
, unsigned char *outBuf
, 
 605                          unsigned int maxOutBufLen
, unsigned int *outBufLen
) 
 607     if(!ucs2Utf8ConvertFunc
) { 
 608       return sec_port_ucs2_utf8_conversion_function(toUnicode
, 
 609         inBuf
, inBufLen
, outBuf
, maxOutBufLen
, outBufLen
); 
 612     return (*ucs2Utf8ConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,  
 613                                   maxOutBufLen
, outBufLen
); 
 615 //#endif        /* __APPLE__ */ 
 618 PORT_UCS2_ASCIIConversion(PRBool toUnicode
, unsigned char *inBuf
, 
 619                           unsigned int inBufLen
, unsigned char *outBuf
, 
 620                           unsigned int maxOutBufLen
, unsigned int *outBufLen
, 
 623     if(!ucs2AsciiConvertFunc
) { 
 627     return (*ucs2AsciiConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,  
 628                                   maxOutBufLen
, outBufLen
, swapBytes
); 
 632 /* Portable putenv.  Creates/replaces an environment variable of the form 
 633  *  envVarName=envValue 
 636 NSS_PutEnv(const char * envVarName
, const char * envValue
) 
 638 #if  defined(XP_MAC) || defined(_WIN32_WCE) 
 641     SECStatus result 
= SECSuccess
; 
 647     setOK 
= SetEnvironmentVariable(envVarName
, envValue
); 
 654     encoded 
= (char *)PORT_ZAlloc(strlen(envVarName
) + 2 + strlen(envValue
)); 
 655     strcpy(encoded
, envVarName
); 
 656     strcat(encoded
, "="); 
 657     strcat(encoded
, envValue
); 
 659     putEnvFailed 
= putenv(encoded
); /* adopt. */ 
 668 #endif  /* __APPLE__ */