1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Netscape security libraries.
15 *
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2001
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36 /* $Id: sslmutex.c,v 1.24 2009/06/05 02:34:14 nelson%bolyard.com Exp $ */
37
38 #include "seccomon.h"
39 /* This ifdef should match the one in sslsnce.c */
40 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
41
42 #include "sslmutex.h"
43 #include "prerr.h"
44
single_process_sslMutex_Init(sslMutex * pMutex)45 static SECStatus single_process_sslMutex_Init(sslMutex* pMutex)
46 {
47 PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0 );
48
49 pMutex->u.sslLock = PR_NewLock();
50 if (!pMutex->u.sslLock) {
51 return SECFailure;
52 }
53 return SECSuccess;
54 }
55
single_process_sslMutex_Destroy(sslMutex * pMutex)56 static SECStatus single_process_sslMutex_Destroy(sslMutex* pMutex)
57 {
58 PR_ASSERT(pMutex != 0);
59 PR_ASSERT(pMutex->u.sslLock!= 0);
60 if (!pMutex->u.sslLock) {
61 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
62 return SECFailure;
63 }
64 PR_DestroyLock(pMutex->u.sslLock);
65 return SECSuccess;
66 }
67
single_process_sslMutex_Unlock(sslMutex * pMutex)68 static SECStatus single_process_sslMutex_Unlock(sslMutex* pMutex)
69 {
70 PR_ASSERT(pMutex != 0 );
71 PR_ASSERT(pMutex->u.sslLock !=0);
72 if (!pMutex->u.sslLock) {
73 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
74 return SECFailure;
75 }
76 PR_Unlock(pMutex->u.sslLock);
77 return SECSuccess;
78 }
79
single_process_sslMutex_Lock(sslMutex * pMutex)80 static SECStatus single_process_sslMutex_Lock(sslMutex* pMutex)
81 {
82 PR_ASSERT(pMutex != 0);
83 PR_ASSERT(pMutex->u.sslLock != 0 );
84 if (!pMutex->u.sslLock) {
85 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
86 return SECFailure;
87 }
88 PR_Lock(pMutex->u.sslLock);
89 return SECSuccess;
90 }
91
92 #if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
93
94 #include <unistd.h>
95 #include <fcntl.h>
96 #include <string.h>
97 #include <errno.h>
98 #include "unix_err.h"
99 #include "pratom.h"
100
101 #define SSL_MUTEX_MAGIC 0xfeedfd
102 #define NONBLOCKING_POSTS 1 /* maybe this is faster */
103
104 #if NONBLOCKING_POSTS
105
106 #ifndef FNONBLOCK
107 #define FNONBLOCK O_NONBLOCK
108 #endif
109
110 static int
setNonBlocking(int fd,int nonBlocking)111 setNonBlocking(int fd, int nonBlocking)
112 {
113 int flags;
114 int err;
115
116 flags = fcntl(fd, F_GETFL, 0);
117 if (0 > flags)
118 return flags;
119 if (nonBlocking)
120 flags |= FNONBLOCK;
121 else
122 flags &= ~FNONBLOCK;
123 err = fcntl(fd, F_SETFL, flags);
124 return err;
125 }
126 #endif
127
128 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)129 sslMutex_Init(sslMutex *pMutex, int shared)
130 {
131 int err;
132 PR_ASSERT(pMutex);
133 pMutex->isMultiProcess = (PRBool)(shared != 0);
134 if (!shared) {
135 return single_process_sslMutex_Init(pMutex);
136 }
137 pMutex->u.pipeStr.mPipes[0] = -1;
138 pMutex->u.pipeStr.mPipes[1] = -1;
139 pMutex->u.pipeStr.mPipes[2] = -1;
140 pMutex->u.pipeStr.nWaiters = 0;
141
142 err = pipe(pMutex->u.pipeStr.mPipes);
143 if (err) {
144 nss_MD_unix_map_default_error(errno);
145 return err;
146 }
147 #if NONBLOCKING_POSTS
148 err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1);
149 if (err)
150 goto loser;
151 #endif
152
153 pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC;
154
155 #if defined(LINUX) && defined(i386)
156 /* Pipe starts out empty */
157 return SECSuccess;
158 #else
159 /* Pipe starts with one byte. */
160 return sslMutex_Unlock(pMutex);
161 #endif
162
163 loser:
164 nss_MD_unix_map_default_error(errno);
165 close(pMutex->u.pipeStr.mPipes[0]);
166 close(pMutex->u.pipeStr.mPipes[1]);
167 return SECFailure;
168 }
169
170 SECStatus
sslMutex_Destroy(sslMutex * pMutex)171 sslMutex_Destroy(sslMutex *pMutex)
172 {
173 if (PR_FALSE == pMutex->isMultiProcess) {
174 return single_process_sslMutex_Destroy(pMutex);
175 }
176 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
177 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
178 return SECFailure;
179 }
180 close(pMutex->u.pipeStr.mPipes[0]);
181 close(pMutex->u.pipeStr.mPipes[1]);
182
183 pMutex->u.pipeStr.mPipes[0] = -1;
184 pMutex->u.pipeStr.mPipes[1] = -1;
185 pMutex->u.pipeStr.mPipes[2] = -1;
186 pMutex->u.pipeStr.nWaiters = 0;
187
188 return SECSuccess;
189 }
190
191 #if defined(LINUX) && defined(i386)
192 /* No memory barrier needed for this platform */
193
194 /* nWaiters includes the holder of the lock (if any) and the number
195 ** threads waiting for it. After incrementing nWaiters, if the count
196 ** is exactly 1, then you have the lock and may proceed. If the
197 ** count is greater than 1, then you must wait on the pipe.
198 */
199
200
201 SECStatus
sslMutex_Unlock(sslMutex * pMutex)202 sslMutex_Unlock(sslMutex *pMutex)
203 {
204 PRInt32 newValue;
205 if (PR_FALSE == pMutex->isMultiProcess) {
206 return single_process_sslMutex_Unlock(pMutex);
207 }
208
209 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
210 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
211 return SECFailure;
212 }
213 /* Do Memory Barrier here. */
214 newValue = PR_AtomicDecrement(&pMutex->u.pipeStr.nWaiters);
215 if (newValue > 0) {
216 int cc;
217 char c = 1;
218 do {
219 cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
220 } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
221 if (cc != 1) {
222 if (cc < 0)
223 nss_MD_unix_map_default_error(errno);
224 else
225 PORT_SetError(PR_UNKNOWN_ERROR);
226 return SECFailure;
227 }
228 }
229 return SECSuccess;
230 }
231
232 SECStatus
sslMutex_Lock(sslMutex * pMutex)233 sslMutex_Lock(sslMutex *pMutex)
234 {
235 PRInt32 newValue;
236 if (PR_FALSE == pMutex->isMultiProcess) {
237 return single_process_sslMutex_Lock(pMutex);
238 }
239
240 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
241 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
242 return SECFailure;
243 }
244 newValue = PR_AtomicIncrement(&pMutex->u.pipeStr.nWaiters);
245 /* Do Memory Barrier here. */
246 if (newValue > 1) {
247 int cc;
248 char c;
249 do {
250 cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
251 } while (cc < 0 && errno == EINTR);
252 if (cc != 1) {
253 if (cc < 0)
254 nss_MD_unix_map_default_error(errno);
255 else
256 PORT_SetError(PR_UNKNOWN_ERROR);
257 return SECFailure;
258 }
259 }
260 return SECSuccess;
261 }
262
263 #else
264
265 /* Using Atomic operations requires the use of a memory barrier instruction
266 ** on PowerPC, Sparc, and Alpha. NSPR's PR_Atomic functions do not perform
267 ** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
268 ** So, we don't use them on those platforms.
269 */
270
271 SECStatus
sslMutex_Unlock(sslMutex * pMutex)272 sslMutex_Unlock(sslMutex *pMutex)
273 {
274 int cc;
275 char c = 1;
276
277 if (PR_FALSE == pMutex->isMultiProcess) {
278 return single_process_sslMutex_Unlock(pMutex);
279 }
280
281 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
282 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
283 return SECFailure;
284 }
285 do {
286 cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
287 } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
288 if (cc != 1) {
289 if (cc < 0)
290 nss_MD_unix_map_default_error(errno);
291 else
292 PORT_SetError(PR_UNKNOWN_ERROR);
293 return SECFailure;
294 }
295
296 return SECSuccess;
297 }
298
299 SECStatus
sslMutex_Lock(sslMutex * pMutex)300 sslMutex_Lock(sslMutex *pMutex)
301 {
302 int cc;
303 char c;
304
305 if (PR_FALSE == pMutex->isMultiProcess) {
306 return single_process_sslMutex_Lock(pMutex);
307 }
308
309 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
310 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
311 return SECFailure;
312 }
313
314 do {
315 cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
316 } while (cc < 0 && errno == EINTR);
317 if (cc != 1) {
318 if (cc < 0)
319 nss_MD_unix_map_default_error(errno);
320 else
321 PORT_SetError(PR_UNKNOWN_ERROR);
322 return SECFailure;
323 }
324
325 return SECSuccess;
326 }
327
328 #endif
329
330 #elif defined(WIN32)
331
332 #include "win32err.h"
333
334 /* on Windows, we need to find the optimal type of locking mechanism to use
335 for the sslMutex.
336
337 There are 3 cases :
338 1) single-process, use a PRLock, as for all other platforms
339 2) Win95 multi-process, use a Win32 mutex
340 3) on WINNT multi-process, use a PRLock + a Win32 mutex
341
342 */
343
344 #ifdef WINNT
345
sslMutex_2LevelInit(sslMutex * sem)346 SECStatus sslMutex_2LevelInit(sslMutex *sem)
347 {
348 /* the following adds a PRLock to sslMutex . This is done in each
349 process of a multi-process server and is only needed on WINNT, if
350 using fibers. We can't tell if native threads or fibers are used, so
351 we always do it on WINNT
352 */
353 PR_ASSERT(sem);
354 if (sem) {
355 /* we need to reset the sslLock in the children or the single_process init
356 function below will assert */
357 sem->u.sslLock = NULL;
358 }
359 return single_process_sslMutex_Init(sem);
360 }
361
sslMutex_2LevelDestroy(sslMutex * sem)362 static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
363 {
364 return single_process_sslMutex_Destroy(sem);
365 }
366
367 #endif
368
369 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)370 sslMutex_Init(sslMutex *pMutex, int shared)
371 {
372 #ifdef WINNT
373 SECStatus retvalue;
374 #endif
375 HANDLE hMutex;
376 SECURITY_ATTRIBUTES attributes =
377 { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
378
379 PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 ||
380 pMutex->u.sslMutx == INVALID_HANDLE_VALUE) );
381
382 pMutex->isMultiProcess = (PRBool)(shared != 0);
383
384 if (PR_FALSE == pMutex->isMultiProcess) {
385 return single_process_sslMutex_Init(pMutex);
386 }
387
388 #ifdef WINNT
389 /* we need a lock on WINNT for fibers in the parent process */
390 retvalue = sslMutex_2LevelInit(pMutex);
391 if (SECSuccess != retvalue)
392 return SECFailure;
393 #endif
394
395 if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 &&
396 hMutex != INVALID_HANDLE_VALUE)) {
397 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
398 return SECFailure;
399 }
400 attributes.bInheritHandle = (shared ? TRUE : FALSE);
401 hMutex = CreateMutex(&attributes, FALSE, NULL);
402 if (hMutex == NULL) {
403 hMutex = INVALID_HANDLE_VALUE;
404 nss_MD_win32_map_default_error(GetLastError());
405 return SECFailure;
406 }
407 pMutex->u.sslMutx = hMutex;
408 return SECSuccess;
409 }
410
411 SECStatus
sslMutex_Destroy(sslMutex * pMutex)412 sslMutex_Destroy(sslMutex *pMutex)
413 {
414 HANDLE hMutex;
415 int rv;
416 int retvalue = SECSuccess;
417
418 PR_ASSERT(pMutex != 0);
419 if (PR_FALSE == pMutex->isMultiProcess) {
420 return single_process_sslMutex_Destroy(pMutex);
421 }
422
423 /* multi-process mode */
424 #ifdef WINNT
425 /* on NT, get rid of the PRLock used for fibers within a process */
426 retvalue = sslMutex_2LevelDestroy(pMutex);
427 #endif
428
429 PR_ASSERT( pMutex->u.sslMutx != 0 &&
430 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
431 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0
432 || hMutex == INVALID_HANDLE_VALUE) {
433 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
434 return SECFailure;
435 }
436
437 rv = CloseHandle(hMutex); /* ignore error */
438 if (rv) {
439 pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
440 } else {
441 nss_MD_win32_map_default_error(GetLastError());
442 retvalue = SECFailure;
443 }
444 return retvalue;
445 }
446
447 int
sslMutex_Unlock(sslMutex * pMutex)448 sslMutex_Unlock(sslMutex *pMutex)
449 {
450 BOOL success = FALSE;
451 HANDLE hMutex;
452
453 PR_ASSERT(pMutex != 0 );
454 if (PR_FALSE == pMutex->isMultiProcess) {
455 return single_process_sslMutex_Unlock(pMutex);
456 }
457
458 PR_ASSERT(pMutex->u.sslMutx != 0 &&
459 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
460 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
461 hMutex == INVALID_HANDLE_VALUE) {
462 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
463 return SECFailure;
464 }
465 success = ReleaseMutex(hMutex);
466 if (!success) {
467 nss_MD_win32_map_default_error(GetLastError());
468 return SECFailure;
469 }
470 #ifdef WINNT
471 return single_process_sslMutex_Unlock(pMutex);
472 /* release PRLock for other fibers in the process */
473 #else
474 return SECSuccess;
475 #endif
476 }
477
478 int
sslMutex_Lock(sslMutex * pMutex)479 sslMutex_Lock(sslMutex *pMutex)
480 {
481 HANDLE hMutex;
482 DWORD event;
483 DWORD lastError;
484 SECStatus rv;
485 SECStatus retvalue = SECSuccess;
486 PR_ASSERT(pMutex != 0);
487
488 if (PR_FALSE == pMutex->isMultiProcess) {
489 return single_process_sslMutex_Lock(pMutex);
490 }
491 #ifdef WINNT
492 /* lock first to preserve from other threads/fibers
493 in the same process */
494 retvalue = single_process_sslMutex_Lock(pMutex);
495 #endif
496 PR_ASSERT(pMutex->u.sslMutx != 0 &&
497 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
498 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
499 hMutex == INVALID_HANDLE_VALUE) {
500 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
501 return SECFailure; /* what else ? */
502 }
503 /* acquire the mutex to be the only owner accross all other processes */
504 event = WaitForSingleObject(hMutex, INFINITE);
505 switch (event) {
506 case WAIT_OBJECT_0:
507 case WAIT_ABANDONED:
508 rv = SECSuccess;
509 break;
510
511 case WAIT_TIMEOUT:
512 #if defined(WAIT_IO_COMPLETION)
513 case WAIT_IO_COMPLETION:
514 #endif
515 default: /* should never happen. nothing we can do. */
516 PR_ASSERT(!("WaitForSingleObject returned invalid value."));
517 PORT_SetError(PR_UNKNOWN_ERROR);
518 rv = SECFailure;
519 break;
520
521 case WAIT_FAILED: /* failure returns this */
522 rv = SECFailure;
523 lastError = GetLastError(); /* for debugging */
524 nss_MD_win32_map_default_error(lastError);
525 break;
526 }
527
528 if (! (SECSuccess == retvalue && SECSuccess == rv)) {
529 return SECFailure;
530 }
531
532 return SECSuccess;
533 }
534
535 #elif defined(XP_UNIX)
536
537 #include <errno.h>
538 #include "unix_err.h"
539
540 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)541 sslMutex_Init(sslMutex *pMutex, int shared)
542 {
543 int rv;
544 PR_ASSERT(pMutex);
545 pMutex->isMultiProcess = (PRBool)(shared != 0);
546 if (!shared) {
547 return single_process_sslMutex_Init(pMutex);
548 }
549 do {
550 rv = sem_init(&pMutex->u.sem, shared, 1);
551 } while (rv < 0 && errno == EINTR);
552 if (rv < 0) {
553 nss_MD_unix_map_default_error(errno);
554 return SECFailure;
555 }
556 return SECSuccess;
557 }
558
559 SECStatus
sslMutex_Destroy(sslMutex * pMutex)560 sslMutex_Destroy(sslMutex *pMutex)
561 {
562 int rv;
563 if (PR_FALSE == pMutex->isMultiProcess) {
564 return single_process_sslMutex_Destroy(pMutex);
565 }
566 do {
567 rv = sem_destroy(&pMutex->u.sem);
568 } while (rv < 0 && errno == EINTR);
569 if (rv < 0) {
570 nss_MD_unix_map_default_error(errno);
571 return SECFailure;
572 }
573 return SECSuccess;
574 }
575
576 SECStatus
sslMutex_Unlock(sslMutex * pMutex)577 sslMutex_Unlock(sslMutex *pMutex)
578 {
579 int rv;
580 if (PR_FALSE == pMutex->isMultiProcess) {
581 return single_process_sslMutex_Unlock(pMutex);
582 }
583 do {
584 rv = sem_post(&pMutex->u.sem);
585 } while (rv < 0 && errno == EINTR);
586 if (rv < 0) {
587 nss_MD_unix_map_default_error(errno);
588 return SECFailure;
589 }
590 return SECSuccess;
591 }
592
593 SECStatus
sslMutex_Lock(sslMutex * pMutex)594 sslMutex_Lock(sslMutex *pMutex)
595 {
596 int rv;
597 if (PR_FALSE == pMutex->isMultiProcess) {
598 return single_process_sslMutex_Lock(pMutex);
599 }
600 do {
601 rv = sem_wait(&pMutex->u.sem);
602 } while (rv < 0 && errno == EINTR);
603 if (rv < 0) {
604 nss_MD_unix_map_default_error(errno);
605 return SECFailure;
606 }
607 return SECSuccess;
608 }
609
610 #else
611
612 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)613 sslMutex_Init(sslMutex *pMutex, int shared)
614 {
615 PR_ASSERT(pMutex);
616 pMutex->isMultiProcess = (PRBool)(shared != 0);
617 if (!shared) {
618 return single_process_sslMutex_Init(pMutex);
619 }
620 PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
621 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
622 return SECFailure;
623 }
624
625 SECStatus
sslMutex_Destroy(sslMutex * pMutex)626 sslMutex_Destroy(sslMutex *pMutex)
627 {
628 PR_ASSERT(pMutex);
629 if (PR_FALSE == pMutex->isMultiProcess) {
630 return single_process_sslMutex_Destroy(pMutex);
631 }
632 PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
633 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
634 return SECFailure;
635 }
636
637 SECStatus
sslMutex_Unlock(sslMutex * pMutex)638 sslMutex_Unlock(sslMutex *pMutex)
639 {
640 PR_ASSERT(pMutex);
641 if (PR_FALSE == pMutex->isMultiProcess) {
642 return single_process_sslMutex_Unlock(pMutex);
643 }
644 PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
645 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
646 return SECFailure;
647 }
648
649 SECStatus
sslMutex_Lock(sslMutex * pMutex)650 sslMutex_Lock(sslMutex *pMutex)
651 {
652 PR_ASSERT(pMutex);
653 if (PR_FALSE == pMutex->isMultiProcess) {
654 return single_process_sslMutex_Lock(pMutex);
655 }
656 PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
657 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
658 return SECFailure;
659 }
660
661 #endif
662
663 #endif
664