1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/secport.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,718 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * secport.c - portability interfaces for security libraries 1.10 + * 1.11 + * This file abstracts out libc functionality that libsec depends on 1.12 + * 1.13 + * NOTE - These are not public interfaces 1.14 + */ 1.15 + 1.16 +#include "seccomon.h" 1.17 +#include "prmem.h" 1.18 +#include "prerror.h" 1.19 +#include "plarena.h" 1.20 +#include "secerr.h" 1.21 +#include "prmon.h" 1.22 +#include "nssilock.h" 1.23 +#include "secport.h" 1.24 +#include "prenv.h" 1.25 + 1.26 +#ifdef DEBUG 1.27 +#define THREADMARK 1.28 +#endif /* DEBUG */ 1.29 + 1.30 +#ifdef THREADMARK 1.31 +#include "prthread.h" 1.32 +#endif /* THREADMARK */ 1.33 + 1.34 +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) 1.35 +#include <stdlib.h> 1.36 +#else 1.37 +#include "wtypes.h" 1.38 +#endif 1.39 + 1.40 +#define SET_ERROR_CODE /* place holder for code to set PR error code. */ 1.41 + 1.42 +#ifdef THREADMARK 1.43 +typedef struct threadmark_mark_str { 1.44 + struct threadmark_mark_str *next; 1.45 + void *mark; 1.46 +} threadmark_mark; 1.47 + 1.48 +#endif /* THREADMARK */ 1.49 + 1.50 +/* The value of this magic must change each time PORTArenaPool changes. */ 1.51 +#define ARENAPOOL_MAGIC 0xB8AC9BDF 1.52 + 1.53 +typedef struct PORTArenaPool_str { 1.54 + PLArenaPool arena; 1.55 + PRUint32 magic; 1.56 + PRLock * lock; 1.57 +#ifdef THREADMARK 1.58 + PRThread *marking_thread; 1.59 + threadmark_mark *first_mark; 1.60 +#endif 1.61 +} PORTArenaPool; 1.62 + 1.63 + 1.64 +/* count of allocation failures. */ 1.65 +unsigned long port_allocFailures; 1.66 + 1.67 +/* locations for registering Unicode conversion functions. 1.68 + * XXX is this the appropriate location? or should they be 1.69 + * moved to client/server specific locations? 1.70 + */ 1.71 +PORTCharConversionFunc ucs4Utf8ConvertFunc; 1.72 +PORTCharConversionFunc ucs2Utf8ConvertFunc; 1.73 +PORTCharConversionWSwapFunc ucs2AsciiConvertFunc; 1.74 + 1.75 +/* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc) 1.76 + * use the PRUint32 type for the size parameter. Before we pass a size_t or 1.77 + * unsigned long size to these functions, we need to ensure it is <= half of 1.78 + * the maximum PRUint32 value to avoid truncation and catch a negative size. 1.79 + */ 1.80 +#define MAX_SIZE (PR_UINT32_MAX >> 1) 1.81 + 1.82 +void * 1.83 +PORT_Alloc(size_t bytes) 1.84 +{ 1.85 + void *rv = NULL; 1.86 + 1.87 + if (bytes <= MAX_SIZE) { 1.88 + /* Always allocate a non-zero amount of bytes */ 1.89 + rv = PR_Malloc(bytes ? bytes : 1); 1.90 + } 1.91 + if (!rv) { 1.92 + ++port_allocFailures; 1.93 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.94 + } 1.95 + return rv; 1.96 +} 1.97 + 1.98 +void * 1.99 +PORT_Realloc(void *oldptr, size_t bytes) 1.100 +{ 1.101 + void *rv = NULL; 1.102 + 1.103 + if (bytes <= MAX_SIZE) { 1.104 + rv = PR_Realloc(oldptr, bytes); 1.105 + } 1.106 + if (!rv) { 1.107 + ++port_allocFailures; 1.108 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.109 + } 1.110 + return rv; 1.111 +} 1.112 + 1.113 +void * 1.114 +PORT_ZAlloc(size_t bytes) 1.115 +{ 1.116 + void *rv = NULL; 1.117 + 1.118 + if (bytes <= MAX_SIZE) { 1.119 + /* Always allocate a non-zero amount of bytes */ 1.120 + rv = PR_Calloc(1, bytes ? bytes : 1); 1.121 + } 1.122 + if (!rv) { 1.123 + ++port_allocFailures; 1.124 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.125 + } 1.126 + return rv; 1.127 +} 1.128 + 1.129 +void 1.130 +PORT_Free(void *ptr) 1.131 +{ 1.132 + if (ptr) { 1.133 + PR_Free(ptr); 1.134 + } 1.135 +} 1.136 + 1.137 +void 1.138 +PORT_ZFree(void *ptr, size_t len) 1.139 +{ 1.140 + if (ptr) { 1.141 + memset(ptr, 0, len); 1.142 + PR_Free(ptr); 1.143 + } 1.144 +} 1.145 + 1.146 +char * 1.147 +PORT_Strdup(const char *str) 1.148 +{ 1.149 + size_t len = PORT_Strlen(str)+1; 1.150 + char *newstr; 1.151 + 1.152 + newstr = (char *)PORT_Alloc(len); 1.153 + if (newstr) { 1.154 + PORT_Memcpy(newstr, str, len); 1.155 + } 1.156 + return newstr; 1.157 +} 1.158 + 1.159 +void 1.160 +PORT_SetError(int value) 1.161 +{ 1.162 +#ifdef DEBUG_jp96085 1.163 + PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL); 1.164 +#endif 1.165 + PR_SetError(value, 0); 1.166 + return; 1.167 +} 1.168 + 1.169 +int 1.170 +PORT_GetError(void) 1.171 +{ 1.172 + return(PR_GetError()); 1.173 +} 1.174 + 1.175 +/********************* Arena code follows ***************************** 1.176 + * ArenaPools are like heaps. The memory in them consists of large blocks, 1.177 + * called arenas, which are allocated from the/a system heap. Inside an 1.178 + * ArenaPool, the arenas are organized as if they were in a stack. Newly 1.179 + * allocated arenas are "pushed" on that stack. When you attempt to 1.180 + * allocate memory from an ArenaPool, the code first looks to see if there 1.181 + * is enough unused space in the top arena on the stack to satisfy your 1.182 + * request, and if so, your request is satisfied from that arena. 1.183 + * Otherwise, a new arena is allocated (or taken from NSPR's list of freed 1.184 + * arenas) and pushed on to the stack. The new arena is always big enough 1.185 + * to satisfy the request, and is also at least a minimum size that is 1.186 + * established at the time that the ArenaPool is created. 1.187 + * 1.188 + * The ArenaMark function returns the address of a marker in the arena at 1.189 + * the top of the arena stack. It is the address of the place in the arena 1.190 + * on the top of the arena stack from which the next block of memory will 1.191 + * be allocated. Each ArenaPool has its own separate stack, and hence 1.192 + * marks are only relevant to the ArenaPool from which they are gotten. 1.193 + * Marks may be nested. That is, a thread can get a mark, and then get 1.194 + * another mark. 1.195 + * 1.196 + * It is intended that all the marks in an ArenaPool may only be owned by a 1.197 + * single thread. In DEBUG builds, this is enforced. In non-DEBUG builds, 1.198 + * it is not. In DEBUG builds, when a thread gets a mark from an 1.199 + * ArenaPool, no other thread may acquire a mark in that ArenaPool while 1.200 + * that mark exists, that is, until that mark is unmarked or released. 1.201 + * Therefore, it is important that every mark be unmarked or released when 1.202 + * the creating thread has no further need for exclusive ownership of the 1.203 + * right to manage the ArenaPool. 1.204 + * 1.205 + * The ArenaUnmark function discards the ArenaMark at the address given, 1.206 + * and all marks nested inside that mark (that is, acquired from that same 1.207 + * ArenaPool while that mark existed). It is an error for a thread other 1.208 + * than the mark's creator to try to unmark it. When a thread has unmarked 1.209 + * all its marks from an ArenaPool, then another thread is able to set 1.210 + * marks in that ArenaPool. ArenaUnmark does not deallocate (or "pop") any 1.211 + * memory allocated from the ArenaPool since the mark was created. 1.212 + * 1.213 + * ArenaRelease "pops" the stack back to the mark, deallocating all the 1.214 + * memory allocated from the arenas in the ArenaPool since that mark was 1.215 + * created, and removing any arenas from the ArenaPool that have no 1.216 + * remaining active allocations when that is done. It implicitly releases 1.217 + * any marks nested inside the mark being explicitly released. It is the 1.218 + * only operation, other than destroying the arenapool, that potentially 1.219 + * reduces the number of arenas on the stack. Otherwise, the stack grows 1.220 + * until the arenapool is destroyed, at which point all the arenas are 1.221 + * freed or returned to a "free arena list", depending on their sizes. 1.222 + */ 1.223 +PLArenaPool * 1.224 +PORT_NewArena(unsigned long chunksize) 1.225 +{ 1.226 + PORTArenaPool *pool; 1.227 + 1.228 + if (chunksize > MAX_SIZE) { 1.229 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.230 + return NULL; 1.231 + } 1.232 + pool = PORT_ZNew(PORTArenaPool); 1.233 + if (!pool) { 1.234 + return NULL; 1.235 + } 1.236 + pool->magic = ARENAPOOL_MAGIC; 1.237 + pool->lock = PZ_NewLock(nssILockArena); 1.238 + if (!pool->lock) { 1.239 + ++port_allocFailures; 1.240 + PORT_Free(pool); 1.241 + return NULL; 1.242 + } 1.243 + PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double)); 1.244 + return(&pool->arena); 1.245 +} 1.246 + 1.247 +void * 1.248 +PORT_ArenaAlloc(PLArenaPool *arena, size_t size) 1.249 +{ 1.250 + void *p = NULL; 1.251 + 1.252 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.253 + 1.254 + if (size <= 0) { 1.255 + size = 1; 1.256 + } 1.257 + 1.258 + if (size > MAX_SIZE) { 1.259 + /* you lose. */ 1.260 + } else 1.261 + /* Is it one of ours? Assume so and check the magic */ 1.262 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.263 + PZ_Lock(pool->lock); 1.264 +#ifdef THREADMARK 1.265 + /* Most likely one of ours. Is there a thread id? */ 1.266 + if (pool->marking_thread && 1.267 + pool->marking_thread != PR_GetCurrentThread() ) { 1.268 + /* Another thread holds a mark in this arena */ 1.269 + PZ_Unlock(pool->lock); 1.270 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.271 + PORT_Assert(0); 1.272 + return NULL; 1.273 + } /* tid != null */ 1.274 +#endif /* THREADMARK */ 1.275 + PL_ARENA_ALLOCATE(p, arena, size); 1.276 + PZ_Unlock(pool->lock); 1.277 + } else { 1.278 + PL_ARENA_ALLOCATE(p, arena, size); 1.279 + } 1.280 + 1.281 + if (!p) { 1.282 + ++port_allocFailures; 1.283 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.284 + } 1.285 + 1.286 + return(p); 1.287 +} 1.288 + 1.289 +void * 1.290 +PORT_ArenaZAlloc(PLArenaPool *arena, size_t size) 1.291 +{ 1.292 + void *p; 1.293 + 1.294 + if (size <= 0) 1.295 + size = 1; 1.296 + 1.297 + p = PORT_ArenaAlloc(arena, size); 1.298 + 1.299 + if (p) { 1.300 + PORT_Memset(p, 0, size); 1.301 + } 1.302 + 1.303 + return(p); 1.304 +} 1.305 + 1.306 +/* 1.307 + * If zero is true, zeroize the arena memory before freeing it. 1.308 + */ 1.309 +void 1.310 +PORT_FreeArena(PLArenaPool *arena, PRBool zero) 1.311 +{ 1.312 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.313 + PRLock * lock = (PRLock *)0; 1.314 + size_t len = sizeof *arena; 1.315 + static PRBool checkedEnv = PR_FALSE; 1.316 + static PRBool doFreeArenaPool = PR_FALSE; 1.317 + 1.318 + if (!pool) 1.319 + return; 1.320 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.321 + len = sizeof *pool; 1.322 + lock = pool->lock; 1.323 + PZ_Lock(lock); 1.324 + } 1.325 + if (!checkedEnv) { 1.326 + /* no need for thread protection here */ 1.327 + doFreeArenaPool = (PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST") == NULL); 1.328 + checkedEnv = PR_TRUE; 1.329 + } 1.330 + if (zero) { 1.331 + PL_ClearArenaPool(arena, 0); 1.332 + } 1.333 + if (doFreeArenaPool) { 1.334 + PL_FreeArenaPool(arena); 1.335 + } else { 1.336 + PL_FinishArenaPool(arena); 1.337 + } 1.338 + PORT_ZFree(arena, len); 1.339 + if (lock) { 1.340 + PZ_Unlock(lock); 1.341 + PZ_DestroyLock(lock); 1.342 + } 1.343 +} 1.344 + 1.345 +void * 1.346 +PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize) 1.347 +{ 1.348 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.349 + PORT_Assert(newsize >= oldsize); 1.350 + 1.351 + if (newsize > MAX_SIZE) { 1.352 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.353 + return NULL; 1.354 + } 1.355 + 1.356 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.357 + PZ_Lock(pool->lock); 1.358 + /* Do we do a THREADMARK check here? */ 1.359 + PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) ); 1.360 + PZ_Unlock(pool->lock); 1.361 + } else { 1.362 + PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) ); 1.363 + } 1.364 + 1.365 + return(ptr); 1.366 +} 1.367 + 1.368 +void * 1.369 +PORT_ArenaMark(PLArenaPool *arena) 1.370 +{ 1.371 + void * result; 1.372 + 1.373 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.374 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.375 + PZ_Lock(pool->lock); 1.376 +#ifdef THREADMARK 1.377 + { 1.378 + threadmark_mark *tm, **pw; 1.379 + PRThread * currentThread = PR_GetCurrentThread(); 1.380 + 1.381 + if (! pool->marking_thread ) { 1.382 + /* First mark */ 1.383 + pool->marking_thread = currentThread; 1.384 + } else if (currentThread != pool->marking_thread ) { 1.385 + PZ_Unlock(pool->lock); 1.386 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.387 + PORT_Assert(0); 1.388 + return NULL; 1.389 + } 1.390 + 1.391 + result = PL_ARENA_MARK(arena); 1.392 + PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark)); 1.393 + if (!tm) { 1.394 + PZ_Unlock(pool->lock); 1.395 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.396 + return NULL; 1.397 + } 1.398 + 1.399 + tm->mark = result; 1.400 + tm->next = (threadmark_mark *)NULL; 1.401 + 1.402 + pw = &pool->first_mark; 1.403 + while( *pw ) { 1.404 + pw = &(*pw)->next; 1.405 + } 1.406 + 1.407 + *pw = tm; 1.408 + } 1.409 +#else /* THREADMARK */ 1.410 + result = PL_ARENA_MARK(arena); 1.411 +#endif /* THREADMARK */ 1.412 + PZ_Unlock(pool->lock); 1.413 + } else { 1.414 + /* a "pure" NSPR arena */ 1.415 + result = PL_ARENA_MARK(arena); 1.416 + } 1.417 + return result; 1.418 +} 1.419 + 1.420 +/* 1.421 + * This function accesses the internals of PLArena, which is why it needs 1.422 + * to use the NSPR internal macro PL_MAKE_MEM_UNDEFINED before the memset 1.423 + * calls. 1.424 + * 1.425 + * We should move this function to NSPR as PL_ClearArenaAfterMark or add 1.426 + * a PL_ARENA_CLEAR_AND_RELEASE macro. 1.427 + * 1.428 + * TODO: remove the #ifdef PL_MAKE_MEM_UNDEFINED tests when NSPR 4.10+ is 1.429 + * widely available. 1.430 + */ 1.431 +static void 1.432 +port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark) 1.433 +{ 1.434 + PLArena *a = arena->current; 1.435 + if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) { 1.436 + /* fast path: mark falls in the current arena */ 1.437 +#ifdef PL_MAKE_MEM_UNDEFINED 1.438 + PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark); 1.439 +#endif 1.440 + memset(mark, 0, a->avail - (PRUword)mark); 1.441 + } else { 1.442 + /* slow path: need to find the arena that mark falls in */ 1.443 + for (a = arena->first.next; a; a = a->next) { 1.444 + PR_ASSERT(a->base <= a->avail && a->avail <= a->limit); 1.445 + if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) { 1.446 +#ifdef PL_MAKE_MEM_UNDEFINED 1.447 + PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark); 1.448 +#endif 1.449 + memset(mark, 0, a->avail - (PRUword)mark); 1.450 + a = a->next; 1.451 + break; 1.452 + } 1.453 + } 1.454 + for (; a; a = a->next) { 1.455 + PR_ASSERT(a->base <= a->avail && a->avail <= a->limit); 1.456 +#ifdef PL_MAKE_MEM_UNDEFINED 1.457 + PL_MAKE_MEM_UNDEFINED((void *)a->base, a->avail - a->base); 1.458 +#endif 1.459 + memset((void *)a->base, 0, a->avail - a->base); 1.460 + } 1.461 + } 1.462 +} 1.463 + 1.464 +static void 1.465 +port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero) 1.466 +{ 1.467 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.468 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.469 + PZ_Lock(pool->lock); 1.470 +#ifdef THREADMARK 1.471 + { 1.472 + threadmark_mark **pw, *tm; 1.473 + 1.474 + if (PR_GetCurrentThread() != pool->marking_thread ) { 1.475 + PZ_Unlock(pool->lock); 1.476 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.477 + PORT_Assert(0); 1.478 + return /* no error indication available */ ; 1.479 + } 1.480 + 1.481 + pw = &pool->first_mark; 1.482 + while( *pw && (mark != (*pw)->mark) ) { 1.483 + pw = &(*pw)->next; 1.484 + } 1.485 + 1.486 + if (! *pw ) { 1.487 + /* bad mark */ 1.488 + PZ_Unlock(pool->lock); 1.489 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.490 + PORT_Assert(0); 1.491 + return /* no error indication available */ ; 1.492 + } 1.493 + 1.494 + tm = *pw; 1.495 + *pw = (threadmark_mark *)NULL; 1.496 + 1.497 + if (zero) { 1.498 + port_ArenaZeroAfterMark(arena, mark); 1.499 + } 1.500 + PL_ARENA_RELEASE(arena, mark); 1.501 + 1.502 + if (! pool->first_mark ) { 1.503 + pool->marking_thread = (PRThread *)NULL; 1.504 + } 1.505 + } 1.506 +#else /* THREADMARK */ 1.507 + if (zero) { 1.508 + port_ArenaZeroAfterMark(arena, mark); 1.509 + } 1.510 + PL_ARENA_RELEASE(arena, mark); 1.511 +#endif /* THREADMARK */ 1.512 + PZ_Unlock(pool->lock); 1.513 + } else { 1.514 + if (zero) { 1.515 + port_ArenaZeroAfterMark(arena, mark); 1.516 + } 1.517 + PL_ARENA_RELEASE(arena, mark); 1.518 + } 1.519 +} 1.520 + 1.521 +void 1.522 +PORT_ArenaRelease(PLArenaPool *arena, void *mark) 1.523 +{ 1.524 + port_ArenaRelease(arena, mark, PR_FALSE); 1.525 +} 1.526 + 1.527 +/* 1.528 + * Zeroize the arena memory before releasing it. 1.529 + */ 1.530 +void 1.531 +PORT_ArenaZRelease(PLArenaPool *arena, void *mark) 1.532 +{ 1.533 + port_ArenaRelease(arena, mark, PR_TRUE); 1.534 +} 1.535 + 1.536 +void 1.537 +PORT_ArenaUnmark(PLArenaPool *arena, void *mark) 1.538 +{ 1.539 +#ifdef THREADMARK 1.540 + PORTArenaPool *pool = (PORTArenaPool *)arena; 1.541 + if (ARENAPOOL_MAGIC == pool->magic ) { 1.542 + threadmark_mark **pw, *tm; 1.543 + 1.544 + PZ_Lock(pool->lock); 1.545 + 1.546 + if (PR_GetCurrentThread() != pool->marking_thread ) { 1.547 + PZ_Unlock(pool->lock); 1.548 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.549 + PORT_Assert(0); 1.550 + return /* no error indication available */ ; 1.551 + } 1.552 + 1.553 + pw = &pool->first_mark; 1.554 + while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) { 1.555 + pw = &(*pw)->next; 1.556 + } 1.557 + 1.558 + if ((threadmark_mark *)NULL == *pw ) { 1.559 + /* bad mark */ 1.560 + PZ_Unlock(pool->lock); 1.561 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.562 + PORT_Assert(0); 1.563 + return /* no error indication available */ ; 1.564 + } 1.565 + 1.566 + tm = *pw; 1.567 + *pw = (threadmark_mark *)NULL; 1.568 + 1.569 + if (! pool->first_mark ) { 1.570 + pool->marking_thread = (PRThread *)NULL; 1.571 + } 1.572 + 1.573 + PZ_Unlock(pool->lock); 1.574 + } 1.575 +#endif /* THREADMARK */ 1.576 +} 1.577 + 1.578 +char * 1.579 +PORT_ArenaStrdup(PLArenaPool *arena, const char *str) { 1.580 + int len = PORT_Strlen(str)+1; 1.581 + char *newstr; 1.582 + 1.583 + newstr = (char*)PORT_ArenaAlloc(arena,len); 1.584 + if (newstr) { 1.585 + PORT_Memcpy(newstr,str,len); 1.586 + } 1.587 + return newstr; 1.588 +} 1.589 + 1.590 +/********************** end of arena functions ***********************/ 1.591 + 1.592 +/****************** unicode conversion functions ***********************/ 1.593 +/* 1.594 + * NOTE: These conversion functions all assume that the multibyte 1.595 + * characters are going to be in NETWORK BYTE ORDER, not host byte 1.596 + * order. This is because the only time we deal with UCS-2 and UCS-4 1.597 + * are when the data was received from or is going to be sent out 1.598 + * over the wire (in, e.g. certificates). 1.599 + */ 1.600 + 1.601 +void 1.602 +PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc) 1.603 +{ 1.604 + ucs4Utf8ConvertFunc = convFunc; 1.605 +} 1.606 + 1.607 +void 1.608 +PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc) 1.609 +{ 1.610 + ucs2AsciiConvertFunc = convFunc; 1.611 +} 1.612 + 1.613 +void 1.614 +PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc) 1.615 +{ 1.616 + ucs2Utf8ConvertFunc = convFunc; 1.617 +} 1.618 + 1.619 +PRBool 1.620 +PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf, 1.621 + unsigned int inBufLen, unsigned char *outBuf, 1.622 + unsigned int maxOutBufLen, unsigned int *outBufLen) 1.623 +{ 1.624 + if(!ucs4Utf8ConvertFunc) { 1.625 + return sec_port_ucs4_utf8_conversion_function(toUnicode, 1.626 + inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen); 1.627 + } 1.628 + 1.629 + return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 1.630 + maxOutBufLen, outBufLen); 1.631 +} 1.632 + 1.633 +PRBool 1.634 +PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf, 1.635 + unsigned int inBufLen, unsigned char *outBuf, 1.636 + unsigned int maxOutBufLen, unsigned int *outBufLen) 1.637 +{ 1.638 + if(!ucs2Utf8ConvertFunc) { 1.639 + return sec_port_ucs2_utf8_conversion_function(toUnicode, 1.640 + inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen); 1.641 + } 1.642 + 1.643 + return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 1.644 + maxOutBufLen, outBufLen); 1.645 +} 1.646 + 1.647 +PRBool 1.648 +PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf, 1.649 + unsigned int inBufLen, unsigned char *outBuf, 1.650 + unsigned int maxOutBufLen, unsigned int *outBufLen) 1.651 +{ 1.652 + return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen, 1.653 + outBuf, maxOutBufLen, outBufLen); 1.654 +} 1.655 + 1.656 +PRBool 1.657 +PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf, 1.658 + unsigned int inBufLen, unsigned char *outBuf, 1.659 + unsigned int maxOutBufLen, unsigned int *outBufLen, 1.660 + PRBool swapBytes) 1.661 +{ 1.662 + if(!ucs2AsciiConvertFunc) { 1.663 + return PR_FALSE; 1.664 + } 1.665 + 1.666 + return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 1.667 + maxOutBufLen, outBufLen, swapBytes); 1.668 +} 1.669 + 1.670 + 1.671 +/* Portable putenv. Creates/replaces an environment variable of the form 1.672 + * envVarName=envValue 1.673 + */ 1.674 +int 1.675 +NSS_PutEnv(const char * envVarName, const char * envValue) 1.676 +{ 1.677 + SECStatus result = SECSuccess; 1.678 + char * encoded; 1.679 + int putEnvFailed; 1.680 +#ifdef _WIN32 1.681 + PRBool setOK; 1.682 + 1.683 + setOK = SetEnvironmentVariable(envVarName, envValue); 1.684 + if (!setOK) { 1.685 + SET_ERROR_CODE 1.686 + return SECFailure; 1.687 + } 1.688 +#endif 1.689 + 1.690 + encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue)); 1.691 + strcpy(encoded, envVarName); 1.692 + strcat(encoded, "="); 1.693 + strcat(encoded, envValue); 1.694 + 1.695 + putEnvFailed = putenv(encoded); /* adopt. */ 1.696 + if (putEnvFailed) { 1.697 + SET_ERROR_CODE 1.698 + result = SECFailure; 1.699 + PORT_Free(encoded); 1.700 + } 1.701 + return result; 1.702 +} 1.703 + 1.704 +/* 1.705 + * Perform a constant-time compare of two memory regions. The return value is 1.706 + * 0 if the memory regions are equal and non-zero otherwise. 1.707 + */ 1.708 +int 1.709 +NSS_SecureMemcmp(const void *ia, const void *ib, size_t n) 1.710 +{ 1.711 + const unsigned char *a = (const unsigned char*) ia; 1.712 + const unsigned char *b = (const unsigned char*) ib; 1.713 + size_t i; 1.714 + unsigned char r = 0; 1.715 + 1.716 + for (i = 0; i < n; ++i) { 1.717 + r |= *a++ ^ *b++; 1.718 + } 1.719 + 1.720 + return r; 1.721 +}