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__ */