Back to index

lightning-sunbird  0.9+nobinonly
selfserv.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* -r flag is interepreted as follows:
00039  *     1 -r  means request, not require, on initial handshake.
00040  *     2 -r's mean request  and require, on initial handshake.
00041  *     3 -r's mean request, not require, on second handshake.
00042  *     4 -r's mean request  and require, on second handshake.
00043  */
00044 #include <stdio.h>
00045 #include <string.h>
00046 
00047 #include "secutil.h"
00048 
00049 #if defined(XP_UNIX)
00050 #include <unistd.h>
00051 #endif
00052 
00053 #if defined(_WINDOWS)
00054 #include <process.h> /* for getpid() */
00055 #endif
00056 
00057 #ifdef XP_OS2_VACPP
00058 #include <Process.h> /* for getpid() */
00059 #endif
00060 
00061 #include <signal.h>
00062 #include <stdlib.h>
00063 #include <errno.h>
00064 #include <fcntl.h>
00065 #include <stdarg.h>
00066 
00067 #include "nspr.h"
00068 #include "prio.h"
00069 #include "prerror.h"
00070 #include "prnetdb.h"
00071 #include "prclist.h"
00072 #include "plgetopt.h"
00073 #include "pk11func.h"
00074 #include "secitem.h"
00075 #include "nss.h"
00076 #include "ssl.h"
00077 #include "sslproto.h"
00078 #include "cert.h"
00079 #include "certt.h"
00080 
00081 #ifndef PORT_Sprintf
00082 #define PORT_Sprintf sprintf
00083 #endif
00084 
00085 #ifndef PORT_Strstr
00086 #define PORT_Strstr strstr
00087 #endif
00088 
00089 #ifndef PORT_Malloc
00090 #define PORT_Malloc PR_Malloc
00091 #endif
00092 
00093 int NumSidCacheEntries = 1024;
00094 
00095 static int handle_connection( PRFileDesc *, PRFileDesc *, int );
00096 
00097 static const char envVarName[] = { SSL_ENV_VAR_NAME };
00098 static const char inheritableSockName[] = { "SELFSERV_LISTEN_SOCKET" };
00099 
00100 static PRBool logStats = PR_FALSE;
00101 static int logPeriod = 30;
00102 static PRUint32 loggerOps = 0;
00103 
00104 const int ssl2CipherSuites[] = {
00105     SSL_EN_RC4_128_WITH_MD5,                     /* A */
00106     SSL_EN_RC4_128_EXPORT40_WITH_MD5,            /* B */
00107     SSL_EN_RC2_128_CBC_WITH_MD5,          /* C */
00108     SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
00109     SSL_EN_DES_64_CBC_WITH_MD5,                  /* E */
00110     SSL_EN_DES_192_EDE3_CBC_WITH_MD5,            /* F */
00111     0
00112 };
00113 
00114 const int ssl3CipherSuites[] = {
00115     -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
00116     -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA      * b */
00117     SSL_RSA_WITH_RC4_128_MD5,                    /* c */
00118     SSL_RSA_WITH_3DES_EDE_CBC_SHA,        /* d */
00119     SSL_RSA_WITH_DES_CBC_SHA,                    /* e */
00120     SSL_RSA_EXPORT_WITH_RC4_40_MD5,              /* f */
00121     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,          /* g */
00122     -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA,        * h */
00123     SSL_RSA_WITH_NULL_MD5,                /* i */
00124     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,          /* j */
00125     SSL_RSA_FIPS_WITH_DES_CBC_SHA,        /* k */
00126     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,  /* l */
00127     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,           /* m */
00128     SSL_RSA_WITH_RC4_128_SHA,                    /* n */
00129     -1, /* TLS_DHE_DSS_WITH_RC4_128_SHA,   * o */
00130     -1, /* SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,     * p */
00131     -1, /* SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,     * q */
00132     -1, /* SSL_DHE_RSA_WITH_DES_CBC_SHA,   * r */
00133     -1, /* SSL_DHE_DSS_WITH_DES_CBC_SHA,   * s */
00134     -1, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA,      * t */
00135     -1, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA,      * u */
00136     TLS_RSA_WITH_AES_128_CBC_SHA,                /* v */
00137     -1, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA,      * w */
00138     -1, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA,      * x */
00139     TLS_RSA_WITH_AES_256_CBC_SHA,                /* y */
00140     SSL_RSA_WITH_NULL_SHA,                /* z */
00141     0
00142 };
00143 
00144 /* data and structures for shutdown */
00145 static int    stopping;
00146 
00147 static PRBool  noDelay;
00148 static int     requestCert;
00149 static int    verbose;
00150 static SECItem       bigBuf;
00151 
00152 static PRThread * acceptorThread;
00153 
00154 static PRLogModuleInfo *lm;
00155 
00156 /* Add custom password handler because SECU_GetModulePassword 
00157  * makes automation of this program next to impossible.
00158  */
00159 
00160 char *
00161 ownPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
00162 {
00163        char * passwd = NULL;
00164 
00165        if ( (!retry) && arg ) {
00166               passwd = PL_strdup((char *)arg);
00167        }
00168 
00169        return passwd;
00170 }
00171 
00172 #define PRINTF  if (verbose)  printf
00173 #define FPRINTF if (verbose) fprintf
00174 #define FLUSH if (verbose) { fflush(stdout); fflush(stderr); }
00175 #define VLOG(arg) PR_LOG(lm,PR_LOG_DEBUG,arg)
00176 
00177 static void
00178 Usage(const char *progName)
00179 {
00180     fprintf(stderr, 
00181 
00182 "Usage: %s -n rsa_nickname -p port [-3BDENRSTblmrsvx] [-w password] [-t threads]\n"
00183 #ifdef NSS_ENABLE_ECC
00184 "         [-i pid_file] [-c ciphers] [-d dbdir] [-e ec_nickname] \n"
00185 "         [-f fortezza_nickname] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
00186 #else
00187 "         [-i pid_file] [-c ciphers] [-d dbdir] [-f fortezza_nickname] \n"
00188 "         [-L [seconds]] [-M maxProcs] [-P dbprefix] [-C SSLCacheEntries]\n"
00189 #endif /* NSS_ENABLE_ECC */
00190 "-S means disable SSL v2\n"
00191 "-3 means disable SSL v3\n"
00192 "-B bypasses the PKCS11 layer for SSL encryption and MACing\n"
00193 "-D means disable Nagle delays in TCP\n"
00194 "-E means disable export ciphersuites and SSL step down key gen\n"
00195 "-T means disable TLS\n"
00196 "-R means disable detection of rollback from TLS to SSL3\n"
00197 "-b means try binding to the port and exit\n"
00198 "-m means test the model-socket feature of SSL_ImportFD.\n"
00199 "-r flag is interepreted as follows:\n"
00200 "    1 -r  means request, not require, cert on initial handshake.\n"
00201 "    2 -r's mean request  and require, cert on initial handshake.\n"
00202 "    3 -r's mean request, not require, cert on second handshake.\n"
00203 "    4 -r's mean request  and require, cert on second handshake.\n"
00204 "-s means disable SSL socket locking for performance\n"
00205 "-v means verbose output\n"
00206 "-x means use export policy.\n"
00207 "-L seconds means log statistics every 'seconds' seconds (default=30).\n"
00208 "-M maxProcs tells how many processes to run in a multi-process server\n"
00209 "-N means do NOT use the server session cache.  Incompatible with -M.\n"
00210 "-t threads -- specify the number of threads to use for connections.\n"
00211 "-i pid_file file to write the process id of selfserve\n"
00212 "-l means use local threads instead of global threads\n"
00213 "-C SSLCacheEntries sets the maximum number of entries in the SSL session cache\n"
00214 "-c ciphers   Letter(s) chosen from the following list\n"
00215 "A    SSL2 RC4 128 WITH MD5\n"
00216 "B    SSL2 RC4 128 EXPORT40 WITH MD5\n"
00217 "C    SSL2 RC2 128 CBC WITH MD5\n"
00218 "D    SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
00219 "E    SSL2 DES 64 CBC WITH MD5\n"
00220 "F    SSL2 DES 192 EDE3 CBC WITH MD5\n"
00221 "\n"
00222 "c    SSL3 RSA WITH RC4 128 MD5\n"
00223 "d    SSL3 RSA WITH 3DES EDE CBC SHA\n"
00224 "e    SSL3 RSA WITH DES CBC SHA\n"
00225 "f    SSL3 RSA EXPORT WITH RC4 40 MD5\n"
00226 "g    SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
00227 "i    SSL3 RSA WITH NULL MD5\n"
00228 "j    SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
00229 "k    SSL3 RSA FIPS WITH DES CBC SHA\n"
00230 "l    SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
00231 "m    SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
00232 "n    SSL3 RSA WITH RC4 128 SHA\n"
00233 "v    SSL3 RSA WITH AES 128 CBC SHA\n"
00234 "y    SSL3 RSA WITH AES 256 CBC SHA\n"
00235 "z    SSL3 RSA WITH NULL SHA\n"
00236 "\n"
00237 ":WXYZ  Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
00238        ,progName);
00239 }
00240 
00241 static const char *
00242 errWarn(char * funcString)
00243 {
00244     PRErrorCode  perr      = PR_GetError();
00245     const char * errString = SECU_Strerror(perr);
00246 
00247     fprintf(stderr, "selfserv: %s returned error %d:\n%s\n",
00248             funcString, perr, errString);
00249     return errString;
00250 }
00251 
00252 static void
00253 errExit(char * funcString)
00254 {
00255     errWarn(funcString);
00256     exit(3);
00257 }
00258 
00259 
00260 /**************************************************************************
00261 ** 
00262 ** Routines for disabling SSL ciphers.
00263 **
00264 **************************************************************************/
00265 
00266 /* disable all the SSL cipher suites */
00267 void
00268 disableAllSSLCiphers(void)
00269 {
00270     const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
00271     int             i            = SSL_NumImplementedCiphers;
00272     SECStatus       rv;
00273 
00274     while (--i >= 0) {
00275        PRUint16 suite = cipherSuites[i];
00276         rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
00277        if (rv != SECSuccess) {
00278            printf("SSL_CipherPrefSetDefault rejected suite 0x%04x (i = %d)\n",
00279                  suite, i);
00280            errWarn("SSL_CipherPrefSetDefault");
00281        }
00282     }
00283 }
00284 
00285 /* disable all the export SSL cipher suites */
00286 SECStatus
00287 disableExportSSLCiphers(void)
00288 {
00289     const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
00290     int             i            = SSL_NumImplementedCiphers;
00291     SECStatus       rv           = SECSuccess;
00292     SSLCipherSuiteInfo info;
00293 
00294     while (--i >= 0) {
00295        PRUint16 suite = cipherSuites[i];
00296        SECStatus status;
00297        status = SSL_GetCipherSuiteInfo(suite, &info, sizeof info);
00298        if (status != SECSuccess) {
00299            printf("SSL_GetCipherSuiteInfo rejected suite 0x%04x (i = %d)\n",
00300                  suite, i);
00301            errWarn("SSL_GetCipherSuiteInfo");
00302            rv = SECFailure;
00303            continue;
00304        }
00305        if (info.cipherSuite != suite) {
00306            printf(
00307 "SSL_GetCipherSuiteInfo returned wrong suite! Wanted 0x%04x, Got 0x%04x\n",
00308                  suite, i);
00309            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00310            rv = SECFailure;
00311            continue;
00312        }
00313        /* should check here that info.length >= offsetof isExportable */
00314        if (info.isExportable) {
00315            status = SSL_CipherPolicySet(suite, SSL_NOT_ALLOWED);
00316            if (status != SECSuccess) {
00317               printf("SSL_CipherPolicySet rejected suite 0x%04x (i = %d)\n",
00318                      suite, i);
00319               errWarn("SSL_CipherPolicySet");
00320               rv = SECFailure;
00321            }
00322        }
00323     }
00324     return rv;
00325 }
00326 
00327 static SECStatus
00328 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
00329                    PRBool isServer)
00330 {
00331     SECStatus rv;
00332     CERTCertificate *    peerCert;
00333 
00334     peerCert = SSL_PeerCertificate(fd);
00335 
00336     PRINTF("selfserv: Subject: %s\nselfserv: Issuer : %s\n",
00337            peerCert->subjectName, peerCert->issuerName);
00338 
00339     rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
00340 
00341     if (rv == SECSuccess) {
00342        PRINTF("selfserv: -- SSL3: Certificate Validated.\n");
00343     } else {
00344        int err = PR_GetError();
00345        FPRINTF(stderr, "selfserv: -- SSL3: Certificate Invalid, err %d.\n%s\n", 
00346                 err, SECU_Strerror(err));
00347     }
00348     CERT_DestroyCertificate(peerCert);
00349     FLUSH;
00350     return rv;  
00351 }
00352 
00353 void 
00354 printSecurityInfo(PRFileDesc *fd)
00355 {
00356     CERTCertificate * cert      = NULL;
00357     SSL3Statistics *  ssl3stats = SSL_GetStatistics();
00358     SECStatus         result;
00359     SSLChannelInfo    channel;
00360     SSLCipherSuiteInfo suite;
00361 
00362     PRINTF(
00363        "selfserv: %ld cache hits; %ld cache misses, %ld cache not reusable\n",
00364        ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
00365        ssl3stats->hch_sid_cache_not_ok);
00366 
00367     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
00368     if (result == SECSuccess && 
00369         channel.length == sizeof channel && 
00370        channel.cipherSuite) {
00371        result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
00372                                    &suite, sizeof suite);
00373        if (result == SECSuccess) {
00374            FPRINTF(stderr, 
00375            "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
00376               channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
00377               suite.effectiveKeyBits, suite.symCipherName, 
00378               suite.macBits, suite.macAlgorithmName);
00379            FPRINTF(stderr, 
00380            "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n",
00381               channel.authKeyBits, suite.authAlgorithmName,
00382               channel.keaKeyBits,  suite.keaTypeName);
00383        }
00384     }
00385     if (requestCert)
00386        cert = SSL_PeerCertificate(fd);
00387     else
00388        cert = SSL_LocalCertificate(fd);
00389     if (cert) {
00390        char * ip = CERT_NameToAscii(&cert->issuer);
00391        char * sp = CERT_NameToAscii(&cert->subject);
00392         if (sp) {
00393            FPRINTF(stderr, "selfserv: subject DN: %s\n", sp);
00394            PORT_Free(sp);
00395        }
00396         if (ip) {
00397            FPRINTF(stderr, "selfserv: issuer  DN: %s\n", ip);
00398            PORT_Free(ip);
00399        }
00400        CERT_DestroyCertificate(cert);
00401        cert = NULL;
00402     }
00403     FLUSH;
00404 }
00405 
00406 static int MakeCertOK;
00407 
00408 static SECStatus
00409 myBadCertHandler( void *arg, PRFileDesc *fd)
00410 {
00411     int err = PR_GetError();
00412     if (!MakeCertOK)
00413        fprintf(stderr, 
00414            "selfserv: -- SSL: Client Certificate Invalid, err %d.\n%s\n", 
00415             err, SECU_Strerror(err));
00416     return (MakeCertOK ? SECSuccess : SECFailure);
00417 }
00418 
00419 /**************************************************************************
00420 ** Begin thread management routines and data.
00421 **************************************************************************/
00422 #define MIN_THREADS 3
00423 #define DEFAULT_THREADS 8
00424 #define MAX_THREADS 4096
00425 #define MAX_PROCS 25
00426 static int  maxThreads = DEFAULT_THREADS;
00427 
00428 
00429 typedef struct jobStr {
00430     PRCList     link;
00431     PRFileDesc *tcp_sock;
00432     PRFileDesc *model_sock;
00433     int         requestCert;
00434 } JOB;
00435 
00436 static PZLock    * qLock; /* this lock protects all data immediately below */
00437 static PRLock    * lastLoadedCrlLock; /* this lock protects lastLoadedCrl variable */
00438 static PZCondVar * jobQNotEmptyCv;
00439 static PZCondVar * freeListNotEmptyCv;
00440 static PZCondVar * threadCountChangeCv;
00441 static int  threadCount;
00442 static PRCList  jobQ;
00443 static PRCList  freeJobs;
00444 static JOB *jobTable;
00445 
00446 SECStatus
00447 setupJobs(int maxJobs)
00448 {
00449     int i;
00450 
00451     jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB));
00452     if (!jobTable)
00453        return SECFailure;
00454 
00455     PR_INIT_CLIST(&jobQ);
00456     PR_INIT_CLIST(&freeJobs);
00457 
00458     for (i = 0; i < maxJobs; ++i) {
00459        JOB * pJob = jobTable + i;
00460        PR_APPEND_LINK(&pJob->link, &freeJobs);
00461     }
00462     return SECSuccess;
00463 }
00464 
00465 typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
00466 
00467 typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
00468 
00469 typedef struct perThreadStr {
00470     PRFileDesc *a;
00471     PRFileDesc *b;
00472     int         c;
00473     int         rv;
00474     startFn  *  startFunc;
00475     PRThread *  prThread;
00476     runState  state;
00477 } perThread;
00478 
00479 static perThread *threads;
00480 
00481 void
00482 thread_wrapper(void * arg)
00483 {
00484     perThread * slot = (perThread *)arg;
00485 
00486     slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
00487 
00488     /* notify the thread exit handler. */
00489     PZ_Lock(qLock);
00490     slot->state = rs_zombie;
00491     --threadCount;
00492     PZ_NotifyAllCondVar(threadCountChangeCv);
00493     PZ_Unlock(qLock);
00494 }
00495 
00496 int 
00497 jobLoop(PRFileDesc *a, PRFileDesc *b, int c)
00498 {
00499     PRCList * myLink = 0;
00500     JOB     * myJob;
00501 
00502     PZ_Lock(qLock);
00503     do {
00504        myLink = 0;
00505        while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) {
00506             PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
00507        }
00508        if (!PR_CLIST_IS_EMPTY(&jobQ)) {
00509            myLink = PR_LIST_HEAD(&jobQ);
00510            PR_REMOVE_AND_INIT_LINK(myLink);
00511        }
00512        PZ_Unlock(qLock);
00513        myJob = (JOB *)myLink;
00514        /* myJob will be null when stopping is true and jobQ is empty */
00515        if (!myJob) 
00516            break;
00517        handle_connection( myJob->tcp_sock, myJob->model_sock, 
00518                         myJob->requestCert);
00519        PZ_Lock(qLock);
00520        PR_APPEND_LINK(myLink, &freeJobs);
00521        PZ_NotifyCondVar(freeListNotEmptyCv);
00522     } while (PR_TRUE);
00523     return 0;
00524 }
00525 
00526 
00527 SECStatus
00528 launch_threads(
00529     startFn    *startFunc,
00530     PRFileDesc *a,
00531     PRFileDesc *b,
00532     int         c,
00533     PRBool      local)
00534 {
00535     int i;
00536     SECStatus rv = SECSuccess;
00537 
00538     /* create the thread management serialization structs */
00539     qLock               = PZ_NewLock(nssILockSelfServ);
00540     jobQNotEmptyCv      = PZ_NewCondVar(qLock);
00541     freeListNotEmptyCv  = PZ_NewCondVar(qLock);
00542     threadCountChangeCv = PZ_NewCondVar(qLock);
00543 
00544     /* create monitor for crl reload procedure */
00545     lastLoadedCrlLock   = PR_NewLock();
00546 
00547     /* allocate the array of thread slots */
00548     threads = PR_Calloc(maxThreads, sizeof(perThread));
00549     if ( NULL == threads )  {
00550         fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
00551         return SECFailure;
00552     }
00553     /* 5 is a little extra, intended to keep the jobQ from underflowing. 
00554     ** That is, from going empty while not stopping and clients are still
00555     ** trying to contact us.
00556     */
00557     rv = setupJobs(maxThreads + 5);
00558     if (rv != SECSuccess)
00559        return rv;
00560 
00561     PZ_Lock(qLock);
00562     for (i = 0; i < maxThreads; ++i) {
00563        perThread * slot = threads + i;
00564 
00565        slot->state = rs_running;
00566        slot->a = a;
00567        slot->b = b;
00568        slot->c = c;
00569        slot->startFunc = startFunc;
00570        slot->prThread = PR_CreateThread(PR_USER_THREAD, 
00571                      thread_wrapper, slot, PR_PRIORITY_NORMAL, 
00572                         (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
00573                         PR_UNJOINABLE_THREAD, 0);
00574        if (slot->prThread == NULL) {
00575            printf("selfserv: Failed to launch thread!\n");
00576            slot->state = rs_idle;
00577            rv = SECFailure;
00578            break;
00579        } 
00580 
00581        ++threadCount;
00582     }
00583     PZ_Unlock(qLock); 
00584 
00585     return rv;
00586 }
00587 
00588 #define DESTROY_CONDVAR(name) if (name) { \
00589         PZ_DestroyCondVar(name); name = NULL; }
00590 #define DESTROY_LOCK(name) if (name) { \
00591         PZ_DestroyLock(name); name = NULL; }
00592        
00593 
00594 void
00595 terminateWorkerThreads(void)
00596 {
00597     VLOG(("selfserv: server_thead: waiting on stopping"));
00598     PZ_Lock(qLock);
00599     PZ_NotifyAllCondVar(jobQNotEmptyCv);
00600     while (threadCount > 0) {
00601        PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT);
00602     }
00603     /* The worker threads empty the jobQ before they terminate. */
00604     PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ));
00605     PZ_Unlock(qLock); 
00606 
00607     DESTROY_CONDVAR(jobQNotEmptyCv);
00608     DESTROY_CONDVAR(freeListNotEmptyCv);
00609     DESTROY_CONDVAR(threadCountChangeCv);
00610 
00611     PR_DestroyLock(lastLoadedCrlLock);
00612     DESTROY_LOCK(qLock);
00613     PR_Free(jobTable);
00614     PR_Free(threads);
00615 }
00616 
00617 static void 
00618 logger(void *arg)
00619 {
00620     PRFloat64 seconds;
00621     PRFloat64 opsPerSec;
00622     PRIntervalTime period;
00623     PRIntervalTime previousTime;
00624     PRIntervalTime latestTime;
00625     PRUint32 previousOps;
00626     PRUint32 ops;
00627     PRIntervalTime logPeriodTicks = PR_SecondsToInterval(logPeriod);
00628     PRFloat64 secondsPerTick = 1.0 / (PRFloat64)PR_TicksPerSecond();
00629 
00630     previousOps = loggerOps;
00631     previousTime = PR_IntervalNow();
00632  
00633     for (;;) {
00634        PR_Sleep(logPeriodTicks);
00635         latestTime = PR_IntervalNow();
00636         ops = loggerOps;
00637         period = latestTime - previousTime;
00638         seconds = (PRFloat64) period*secondsPerTick;
00639         opsPerSec = (ops - previousOps) / seconds;
00640         printf("%.2f ops/second, %d threads\n", opsPerSec, threadCount);
00641         fflush(stdout);
00642         previousOps = ops;
00643         previousTime = latestTime;
00644     }
00645 }
00646 
00647 
00648 /**************************************************************************
00649 ** End   thread management routines.
00650 **************************************************************************/
00651 
00652 PRBool useModelSocket  = PR_FALSE;
00653 PRBool disableSSL2     = PR_FALSE;
00654 PRBool disableSSL3     = PR_FALSE;
00655 PRBool disableTLS      = PR_FALSE;
00656 PRBool disableRollBack = PR_FALSE;
00657 PRBool NoReuse         = PR_FALSE;
00658 PRBool hasSidCache     = PR_FALSE;
00659 PRBool disableStepDown = PR_FALSE;
00660 PRBool bypassPKCS11    = PR_FALSE;
00661 PRBool disableLocking  = PR_FALSE;
00662 
00663 static const char stopCmd[] = { "GET /stop " };
00664 static const char getCmd[]  = { "GET " };
00665 static const char EOFmsg[]  = { "EOF\r\n\r\n\r\n" };
00666 static const char outHeader[] = {
00667     "HTTP/1.0 200 OK\r\n"
00668     "Server: Generic Web Server\r\n"
00669     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
00670     "Content-type: text/plain\r\n"
00671     "\r\n"
00672 };
00673 static const char crlCacheErr[]  = { "CRL ReCache Error: " };
00674 
00675 #ifdef FULL_DUPLEX_CAPABLE
00676 
00677 struct lockedVarsStr {
00678     PZLock *  lock;
00679     int              count;
00680     int              waiters;
00681     PZCondVar *      condVar;
00682 };
00683 
00684 typedef struct lockedVarsStr lockedVars;
00685 
00686 void 
00687 lockedVars_Init( lockedVars * lv)
00688 {
00689     lv->count   = 0;
00690     lv->waiters = 0;
00691     lv->lock    = PZ_NewLock(nssILockSelfServ);
00692     lv->condVar = PZ_NewCondVar(lv->lock);
00693 }
00694 
00695 void
00696 lockedVars_Destroy( lockedVars * lv)
00697 {
00698     PZ_DestroyCondVar(lv->condVar);
00699     lv->condVar = NULL;
00700 
00701     PZ_DestroyLock(lv->lock);
00702     lv->lock = NULL;
00703 }
00704 
00705 void
00706 lockedVars_WaitForDone(lockedVars * lv)
00707 {
00708     PZ_Lock(lv->lock);
00709     while (lv->count > 0) {
00710        PZ_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
00711     }
00712     PZ_Unlock(lv->lock);
00713 }
00714 
00715 int    /* returns count */
00716 lockedVars_AddToCount(lockedVars * lv, int addend)
00717 {
00718     int rv;
00719 
00720     PZ_Lock(lv->lock);
00721     rv = lv->count += addend;
00722     if (rv <= 0) {
00723        PZ_NotifyCondVar(lv->condVar);
00724     }
00725     PZ_Unlock(lv->lock);
00726     return rv;
00727 }
00728 
00729 int
00730 do_writes(
00731     PRFileDesc *     ssl_sock,
00732     PRFileDesc *     model_sock,
00733     int              requestCert
00734     )
00735 {
00736     int                     sent  = 0;
00737     int              count = 0;
00738     lockedVars *     lv = (lockedVars *)model_sock;
00739 
00740     VLOG(("selfserv: do_writes: starting"));
00741     while (sent < bigBuf.len) {
00742 
00743        count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent);
00744        if (count < 0) {
00745            errWarn("PR_Write bigBuf");
00746            break;
00747        }
00748        FPRINTF(stderr, "selfserv: PR_Write wrote %d bytes from bigBuf\n", count );
00749        sent += count;
00750     }
00751     if (count >= 0) {       /* last write didn't fail. */
00752        PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
00753     }
00754 
00755     /* notify the reader that we're done. */
00756     lockedVars_AddToCount(lv, -1);
00757     FLUSH;
00758     VLOG(("selfserv: do_writes: exiting"));
00759     return (sent < bigBuf.len) ? SECFailure : SECSuccess;
00760 }
00761 
00762 static int 
00763 handle_fdx_connection(
00764     PRFileDesc *       tcp_sock,
00765     PRFileDesc *       model_sock,
00766     int                requestCert
00767     )
00768 {
00769     PRFileDesc *       ssl_sock    = NULL;
00770     SECStatus          result;
00771     int                firstTime = 1;
00772     lockedVars         lv;
00773     PRSocketOptionData opt;
00774     char               buf[10240];
00775 
00776 
00777     VLOG(("selfserv: handle_fdx_connection: starting"));
00778     opt.option             = PR_SockOpt_Nonblocking;
00779     opt.value.non_blocking = PR_FALSE;
00780     PR_SetSocketOption(tcp_sock, &opt);
00781 
00782     if (useModelSocket && model_sock) {
00783        SECStatus rv;
00784        ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
00785        if (!ssl_sock) {
00786            errWarn("SSL_ImportFD with model");
00787            goto cleanup;
00788        }
00789        rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
00790        if (rv != SECSuccess) {
00791            errWarn("SSL_ResetHandshake");
00792            goto cleanup;
00793        }
00794     } else {
00795        ssl_sock = tcp_sock;
00796     }
00797 
00798     lockedVars_Init(&lv);
00799     lockedVars_AddToCount(&lv, 1);
00800 
00801     /* Attempt to launch the writer thread. */
00802     result = launch_thread(do_writes, ssl_sock, (PRFileDesc *)&lv, 
00803                            requestCert);
00804 
00805     if (result == SECSuccess) 
00806       do {
00807        /* do reads here. */
00808        int count;
00809        count = PR_Read(ssl_sock, buf, sizeof buf);
00810        if (count < 0) {
00811            errWarn("FDX PR_Read");
00812            break;
00813        }
00814        FPRINTF(stderr, "selfserv: FDX PR_Read read %d bytes.\n", count );
00815        if (firstTime) {
00816            firstTime = 0;
00817            printSecurityInfo(ssl_sock);
00818        }
00819     } while (lockedVars_AddToCount(&lv, 0) > 0);
00820 
00821     /* Wait for writer to finish */
00822     lockedVars_WaitForDone(&lv);
00823     lockedVars_Destroy(&lv);
00824     FLUSH;
00825 
00826 cleanup:
00827     if (ssl_sock) {
00828        PR_Close(ssl_sock);
00829     } else if (tcp_sock) {
00830        PR_Close(tcp_sock);
00831     }
00832 
00833     VLOG(("selfserv: handle_fdx_connection: exiting"));
00834     return SECSuccess;
00835 }
00836 
00837 #endif
00838 
00839 static SECItem *lastLoadedCrl = NULL;
00840 
00841 static SECStatus
00842 reload_crl(PRFileDesc *crlFile)
00843 {
00844     SECItem *crlDer;
00845     CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
00846     SECStatus rv;
00847 
00848     /* Read in the entire file specified with the -f argument */
00849     crlDer = PORT_Malloc(sizeof(SECItem));
00850     if (!crlDer) {
00851         errWarn("Can not allocate memory.");
00852         return SECFailure;
00853     }
00854 
00855     rv = SECU_ReadDERFromFile(crlDer, crlFile, PR_FALSE);
00856     if (rv != SECSuccess) {
00857         errWarn("Unable to read input file.");
00858         PORT_Free(crlDer);
00859         return SECFailure;
00860     }
00861 
00862     PR_Lock(lastLoadedCrlLock);
00863     rv = CERT_CacheCRL(certHandle, crlDer);
00864     if (rv == SECSuccess) {
00865         SECItem *tempItem = crlDer;
00866         if (lastLoadedCrl != NULL) {
00867             rv = CERT_UncacheCRL(certHandle, lastLoadedCrl);
00868             if (rv != SECSuccess) {
00869                 errWarn("Unable to uncache crl.");
00870                 goto loser;
00871             }
00872             crlDer = lastLoadedCrl;
00873         } else {
00874             crlDer = NULL;
00875         }
00876         lastLoadedCrl = tempItem;
00877     }
00878 
00879   loser:
00880     PR_Unlock(lastLoadedCrlLock);
00881     SECITEM_FreeItem(crlDer, PR_TRUE);
00882     return rv;
00883 }
00884 
00885 void stop_server()
00886 {
00887     stopping = 1;
00888     PR_Interrupt(acceptorThread);
00889     PZ_TraceFlush();
00890 }
00891 
00892 int
00893 handle_connection( 
00894     PRFileDesc *tcp_sock,
00895     PRFileDesc *model_sock,
00896     int         requestCert
00897     )
00898 {
00899     PRFileDesc *       ssl_sock = NULL;
00900     PRFileDesc *       local_file_fd = NULL;
00901     char  *            post;
00902     char  *            pBuf;                     /* unused space at end of buf */
00903     const char *       errString;
00904     PRStatus           status;
00905     int                bufRem;                   /* unused bytes at end of buf */
00906     int                bufDat;                   /* characters received in buf */
00907     int                newln    = 0;             /* # of consecutive newlns */
00908     int                firstTime = 1;
00909     int                reqLen;
00910     int                rv;
00911     int                numIOVs;
00912     PRSocketOptionData opt;
00913     PRIOVec            iovs[16];
00914     char               msgBuf[160];
00915     char               buf[10240];
00916     char               fileName[513];
00917     char               proto[128];
00918 
00919     pBuf   = buf;
00920     bufRem = sizeof buf;
00921 
00922     VLOG(("selfserv: handle_connection: starting"));
00923     opt.option             = PR_SockOpt_Nonblocking;
00924     opt.value.non_blocking = PR_FALSE;
00925     PR_SetSocketOption(tcp_sock, &opt);
00926 
00927     VLOG(("selfserv: handle_connection: starting\n"));
00928     if (useModelSocket && model_sock) {
00929        SECStatus rv;
00930        ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
00931        if (!ssl_sock) {
00932            errWarn("SSL_ImportFD with model");
00933            goto cleanup;
00934        }
00935        rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
00936        if (rv != SECSuccess) {
00937            errWarn("SSL_ResetHandshake");
00938            goto cleanup;
00939        }
00940     } else {
00941        ssl_sock = tcp_sock;
00942     }
00943 
00944     if (noDelay) {
00945        opt.option         = PR_SockOpt_NoDelay;
00946        opt.value.no_delay = PR_TRUE;
00947        status = PR_SetSocketOption(ssl_sock, &opt);
00948        if (status != PR_SUCCESS) {
00949            errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
00950             if (ssl_sock) {
00951                PR_Close(ssl_sock);
00952             }
00953            return SECFailure;
00954        }
00955     }
00956 
00957     while (1) {
00958        newln = 0;
00959        reqLen     = 0;
00960        rv = PR_Read(ssl_sock, pBuf, bufRem - 1);
00961        if (rv == 0 || 
00962            (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) {
00963            if (verbose)
00964               errWarn("HDX PR_Read hit EOF");
00965            break;
00966        }
00967        if (rv < 0) {
00968            errWarn("HDX PR_Read");
00969            goto cleanup;
00970        }
00971        /* NULL termination */
00972        pBuf[rv] = 0;
00973        if (firstTime) {
00974            firstTime = 0;
00975            printSecurityInfo(ssl_sock);
00976        }
00977 
00978        pBuf   += rv;
00979        bufRem -= rv;
00980        bufDat = pBuf - buf;
00981        /* Parse the input, starting at the beginning of the buffer.
00982         * Stop when we detect two consecutive \n's (or \r\n's) 
00983         * as this signifies the end of the GET or POST portion.
00984         * The posted data follows.
00985         */
00986        while (reqLen < bufDat && newln < 2) {
00987            int octet = buf[reqLen++];
00988            if (octet == '\n') {
00989               newln++;
00990            } else if (octet != '\r') {
00991               newln = 0;
00992            }
00993        }
00994 
00995        /* came to the end of the buffer, or second newln
00996         * If we didn't get an empty line (CRLFCRLF) then keep on reading.
00997         */
00998        if (newln < 2) 
00999            continue;
01000 
01001        /* we're at the end of the HTTP request.
01002         * If the request is a POST, then there will be one more
01003         * line of data.
01004         * This parsing is a hack, but ok for SSL test purposes.
01005         */
01006        post = PORT_Strstr(buf, "POST ");
01007        if (!post || *post != 'P') 
01008            break;
01009 
01010        /* It's a post, so look for the next and final CR/LF. */
01011        /* We should parse content length here, but ... */
01012        while (reqLen < bufDat && newln < 3) {
01013            int octet = buf[reqLen++];
01014            if (octet == '\n') {
01015               newln++;
01016            }
01017        }
01018        if (newln == 3)
01019            break;
01020     } /* read loop */
01021 
01022     bufDat = pBuf - buf;
01023     if (bufDat) do { /* just close if no data */
01024        /* Have either (a) a complete get, (b) a complete post, (c) EOF */
01025        if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) {
01026            char *      fnBegin = buf + 4;
01027            char *      fnEnd;
01028            PRFileInfo  info;
01029            /* try to open the file named.  
01030             * If succesful, then write it to the client.
01031             */
01032            fnEnd = strpbrk(fnBegin, " \r\n");
01033            if (fnEnd) {
01034               int fnLen = fnEnd - fnBegin;
01035               if (fnLen < sizeof fileName) {
01036                     char *real_fileName = fileName;
01037                     char *protoEnd = NULL;
01038                     strncpy(fileName, fnBegin, fnLen);
01039                     fileName[fnLen] = 0;  /* null terminate */
01040                     if ((protoEnd = strstr(fileName, "://")) != NULL) {
01041                         int protoLen = PR_MIN(protoEnd - fileName, sizeof(proto) - 1);
01042                         PL_strncpy(proto, fileName, protoLen);
01043                         proto[protoLen] = 0;
01044                         real_fileName= protoEnd + 3;
01045                     } else {
01046                         proto[0] = 0;
01047                     }
01048                   status = PR_GetFileInfo(real_fileName, &info);
01049                   if (status == PR_SUCCESS &&
01050                      info.type == PR_FILE_FILE &&
01051                      info.size >= 0 ) {
01052                      local_file_fd = PR_Open(real_fileName, PR_RDONLY, 0);
01053                   }
01054               }
01055            }
01056        }
01057        /* if user has requested client auth in a subsequent handshake,
01058         * do it here.
01059         */
01060        if (requestCert > 2) { /* request cert was 3 or 4 */
01061            CERTCertificate *  cert =  SSL_PeerCertificate(ssl_sock);
01062            if (cert) {
01063               CERT_DestroyCertificate(cert);
01064            } else {
01065               rv = SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE, 1);
01066               if (rv < 0) {
01067                   errWarn("second SSL_OptionSet SSL_REQUEST_CERTIFICATE");
01068                   break;
01069               }
01070               rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE, 
01071                             (requestCert == 4));
01072               if (rv < 0) {
01073                   errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
01074                   break;
01075               }
01076               rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
01077               if (rv != 0) {
01078                   errWarn("SSL_ReHandshake");
01079                   break;
01080               }
01081               rv = SSL_ForceHandshake(ssl_sock);
01082               if (rv < 0) {
01083                   errWarn("SSL_ForceHandshake");
01084                   break;
01085               }
01086            }
01087        }
01088 
01089        numIOVs = 0;
01090 
01091        iovs[numIOVs].iov_base = (char *)outHeader;
01092        iovs[numIOVs].iov_len  = (sizeof(outHeader)) - 1;
01093        numIOVs++;
01094 
01095        if (local_file_fd) {
01096            PRInt32     bytes;
01097            int         errLen;
01098            if (!PL_strlen(proto) || !PL_strcmp(proto, "file")) {
01099                 bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader,
01100                                         sizeof outHeader - 1,
01101                                         PR_TRANSMITFILE_KEEP_OPEN,
01102                                         PR_INTERVAL_NO_TIMEOUT);
01103                 if (bytes >= 0) {
01104                     bytes -= sizeof outHeader - 1;
01105                     FPRINTF(stderr, 
01106                             "selfserv: PR_TransmitFile wrote %d bytes from %s\n",
01107                             bytes, fileName);
01108                     break;
01109                 }
01110                 errString = errWarn("PR_TransmitFile");
01111                 errLen = PORT_Strlen(errString);
01112                 errLen = PR_MIN(errLen, sizeof msgBuf - 1);
01113                 PORT_Memcpy(msgBuf, errString, errLen);
01114                 msgBuf[errLen] = 0;
01115                 
01116                 iovs[numIOVs].iov_base = msgBuf;
01117                 iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
01118                 numIOVs++;
01119             }
01120             if (!PL_strcmp(proto, "crl")) {
01121                 if (reload_crl(local_file_fd) == SECFailure) {
01122                     errString = errWarn("CERT_CacheCRL");
01123                     if (!errString)
01124                         errString = "Unknow error";
01125                     PR_snprintf(msgBuf, sizeof(msgBuf), "%s%s ",
01126                                 crlCacheErr, errString);
01127                     
01128                     iovs[numIOVs].iov_base = msgBuf;
01129                     iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
01130                     numIOVs++;
01131                 } else {
01132                     FPRINTF(stderr, 
01133                             "selfserv: CRL %s reloaded.\n",
01134                             fileName);
01135                     break;
01136                 }
01137             }
01138        } else if (reqLen <= 0) {   /* hit eof */
01139            PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n",
01140                       bufDat);
01141 
01142            iovs[numIOVs].iov_base = msgBuf;
01143            iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
01144            numIOVs++;
01145        } else if (reqLen < bufDat) {
01146            PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", 
01147                         bufDat - reqLen);
01148 
01149            iovs[numIOVs].iov_base = msgBuf;
01150            iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
01151            numIOVs++;
01152        }
01153 
01154        if (reqLen > 0) {
01155            if (verbose > 1) 
01156               fwrite(buf, 1, reqLen, stdout);    /* display it */
01157 
01158            iovs[numIOVs].iov_base = buf;
01159            iovs[numIOVs].iov_len  = reqLen;
01160            numIOVs++;
01161 
01162 /*         printSecurityInfo(ssl_sock); */
01163        }
01164 
01165        iovs[numIOVs].iov_base = (char *)EOFmsg;
01166        iovs[numIOVs].iov_len  = sizeof EOFmsg - 1;
01167        numIOVs++;
01168 
01169        rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT);
01170        if (rv < 0) {
01171            errWarn("PR_Writev");
01172            break;
01173        }
01174     } while (0);
01175 
01176 cleanup:
01177     if (ssl_sock) {
01178         PR_Close(ssl_sock);
01179     } else if (tcp_sock) {
01180         PR_Close(tcp_sock);
01181     }
01182     if (local_file_fd)
01183        PR_Close(local_file_fd);
01184     VLOG(("selfserv: handle_connection: exiting\n"));
01185 
01186     /* do a nice shutdown if asked. */
01187     if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) {
01188         VLOG(("selfserv: handle_connection: stop command"));
01189         stop_server();
01190     }
01191     VLOG(("selfserv: handle_connection: exiting"));
01192     return SECSuccess;      /* success */
01193 }
01194 
01195 #ifdef XP_UNIX
01196 
01197 void sigusr1_handler(int sig)
01198 {
01199     VLOG(("selfserv: sigusr1_handler: stop server"));
01200     stop_server();
01201 }
01202 
01203 #endif
01204 
01205 SECStatus
01206 do_accepts(
01207     PRFileDesc *listen_sock,
01208     PRFileDesc *model_sock,
01209     int         requestCert
01210     )
01211 {
01212     PRNetAddr   addr;
01213     PRErrorCode  perr;
01214 #ifdef XP_UNIX
01215     struct sigaction act;
01216 #endif
01217 
01218     VLOG(("selfserv: do_accepts: starting"));
01219     PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH);
01220 
01221     acceptorThread = PR_GetCurrentThread();
01222 #ifdef XP_UNIX
01223     /* set up the signal handler */
01224     act.sa_handler = sigusr1_handler;
01225     sigemptyset(&act.sa_mask);
01226     act.sa_flags = 0;
01227     if (sigaction(SIGUSR1, &act, NULL)) {
01228         fprintf(stderr, "Error installing signal handler.\n");
01229         exit(1);
01230     }
01231 #endif
01232     while (!stopping) {
01233        PRFileDesc *tcp_sock;
01234        PRCList    *myLink;
01235 
01236        FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n");
01237        tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
01238        if (tcp_sock == NULL) {
01239            perr      = PR_GetError();
01240            if ((perr != PR_CONNECT_RESET_ERROR &&
01241                 perr != PR_PENDING_INTERRUPT_ERROR) || verbose) {
01242               errWarn("PR_Accept");
01243            } 
01244            if (perr == PR_CONNECT_RESET_ERROR) {
01245               FPRINTF(stderr, 
01246                       "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
01247               continue;
01248            }
01249            stopping = 1;
01250            break;
01251        }
01252 
01253         VLOG(("selfserv: do_accept: Got connection\n"));
01254 
01255         if (logStats) {
01256             loggerOps++;
01257         }
01258 
01259        PZ_Lock(qLock);
01260        while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
01261             PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
01262        }
01263        if (stopping) {
01264            PZ_Unlock(qLock);
01265             if (tcp_sock) {
01266                PR_Close(tcp_sock);
01267             }
01268            break;
01269        }
01270        myLink = PR_LIST_HEAD(&freeJobs);
01271        PR_REMOVE_AND_INIT_LINK(myLink);
01272        /* could release qLock here and reaquire it 7 lines below, but 
01273        ** why bother for 4 assignment statements? 
01274        */
01275        {
01276            JOB * myJob = (JOB *)myLink;
01277            myJob->tcp_sock    = tcp_sock;
01278            myJob->model_sock  = model_sock;
01279            myJob->requestCert = requestCert;
01280        }
01281 
01282        PR_APPEND_LINK(myLink, &jobQ);
01283        PZ_NotifyCondVar(jobQNotEmptyCv);
01284        PZ_Unlock(qLock);
01285     }
01286 
01287     FPRINTF(stderr, "selfserv: Closing listen socket.\n");
01288     VLOG(("selfserv: do_accepts: exiting"));
01289     if (listen_sock) {
01290         PR_Close(listen_sock);
01291     }
01292     return SECSuccess;
01293 }
01294 
01295 PRFileDesc *
01296 getBoundListenSocket(unsigned short port)
01297 {
01298     PRFileDesc *       listen_sock;
01299     int                listenQueueDepth = 5 + (2 * maxThreads);
01300     PRStatus         prStatus;
01301     PRNetAddr          addr;
01302     PRSocketOptionData opt;
01303 
01304     addr.inet.family = PR_AF_INET;
01305     addr.inet.ip     = PR_INADDR_ANY;
01306     addr.inet.port   = PR_htons(port);
01307 
01308     listen_sock = PR_NewTCPSocket();
01309     if (listen_sock == NULL) {
01310        errExit("PR_NewTCPSocket");
01311     }
01312 
01313     opt.option = PR_SockOpt_Nonblocking;
01314     opt.value.non_blocking = PR_FALSE;
01315     prStatus = PR_SetSocketOption(listen_sock, &opt);
01316     if (prStatus < 0) {
01317        errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)");
01318     }
01319 
01320     opt.option=PR_SockOpt_Reuseaddr;
01321     opt.value.reuse_addr = PR_TRUE;
01322     prStatus = PR_SetSocketOption(listen_sock, &opt);
01323     if (prStatus < 0) {
01324        errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)");
01325     }
01326 
01327 #ifndef WIN95
01328     /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
01329      * after clean shutdown . See bug 331413 .
01330      * Don't do it in the WIN95 build configuration because clean shutdown is
01331      * not implemented, and PR_SockOpt_Linger causes a hang in ssl.sh .
01332      * See bug 332348 */
01333     opt.option=PR_SockOpt_Linger;
01334     opt.value.linger.polarity = PR_TRUE;
01335     opt.value.linger.linger = PR_SecondsToInterval(1);
01336     prStatus = PR_SetSocketOption(listen_sock, &opt);
01337     if (prStatus < 0) {
01338         errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
01339     }
01340 #endif
01341 
01342     prStatus = PR_Bind(listen_sock, &addr);
01343     if (prStatus < 0) {
01344        errExit("PR_Bind");
01345     }
01346 
01347     prStatus = PR_Listen(listen_sock, listenQueueDepth);
01348     if (prStatus < 0) {
01349        errExit("PR_Listen");
01350     }
01351     return listen_sock;
01352 }
01353 
01354 void
01355 server_main(
01356     PRFileDesc *        listen_sock,
01357     int                 requestCert, 
01358     SECKEYPrivateKey ** privKey,
01359     CERTCertificate **  cert)
01360 {
01361     PRFileDesc *model_sock  = NULL;
01362     int         rv;
01363     SSLKEAType  kea;
01364     SECStatus secStatus;
01365 
01366     if (useModelSocket) {
01367        model_sock = PR_NewTCPSocket();
01368        if (model_sock == NULL) {
01369            errExit("PR_NewTCPSocket on model socket");
01370        }
01371        model_sock = SSL_ImportFD(NULL, model_sock);
01372        if (model_sock == NULL) {
01373            errExit("SSL_ImportFD");
01374        }
01375     } else {
01376        model_sock = listen_sock = SSL_ImportFD(NULL, listen_sock);
01377        if (listen_sock == NULL) {
01378            errExit("SSL_ImportFD");
01379        }
01380     }
01381 
01382     /* do SSL configuration. */
01383     /* all suites except RSA_NULL_MD5 are enabled by default */
01384 
01385 #if 0
01386     /* This is supposed to be true by default.
01387     ** Setting it explicitly should not be necessary.
01388     ** Let's test and make sure that's true.
01389     */
01390     rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1);
01391     if (rv < 0) {
01392        errExit("SSL_OptionSet SSL_SECURITY");
01393     }
01394 #endif
01395 
01396     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL3, !disableSSL3);
01397     if (rv != SECSuccess) {
01398        errExit("error enabling SSLv3 ");
01399     }
01400 
01401     rv = SSL_OptionSet(model_sock, SSL_ENABLE_TLS, !disableTLS);
01402     if (rv != SECSuccess) {
01403        errExit("error enabling TLS ");
01404     }
01405 
01406     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, !disableSSL2);
01407     if (rv != SECSuccess) {
01408        errExit("error enabling SSLv2 ");
01409     }
01410     
01411     rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack);
01412     if (rv != SECSuccess) {
01413        errExit("error enabling RollBack detection ");
01414     }
01415     if (disableStepDown) {
01416        rv = SSL_OptionSet(model_sock, SSL_NO_STEP_DOWN, PR_TRUE);
01417        if (rv != SECSuccess) {
01418            errExit("error disabling SSL StepDown ");
01419        }
01420     }
01421     if (bypassPKCS11) {
01422        rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, PR_TRUE);
01423        if (rv != SECSuccess) {
01424            errExit("error enabling PKCS11 bypass ");
01425        }
01426     }
01427     if (disableLocking) {
01428        rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, PR_TRUE);
01429        if (rv != SECSuccess) {
01430            errExit("error disabling SSL socket locking ");
01431        }
01432     } 
01433 
01434     for (kea = kt_rsa; kea < kt_kea_size; kea++) {
01435        if (cert[kea] != NULL) {
01436            secStatus = SSL_ConfigSecureServer(model_sock, 
01437                      cert[kea], privKey[kea], kea);
01438            if (secStatus != SECSuccess)
01439               errExit("SSL_ConfigSecureServer");
01440        }
01441     }
01442 
01443     if (bigBuf.data) { /* doing FDX */
01444        rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
01445        if (rv < 0) {
01446            errExit("SSL_OptionSet SSL_ENABLE_FDX");
01447        }
01448     }
01449 
01450     if (NoReuse) {
01451         rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
01452         if (rv < 0) {
01453             errExit("SSL_OptionSet SSL_NO_CACHE");
01454         }
01455     }
01456 
01457     /* This cipher is not on by default. The Acceptance test
01458      * would like it to be. Turn this cipher on.
01459      */
01460 
01461     secStatus = SSL_CipherPrefSetDefault( SSL_RSA_WITH_NULL_MD5, PR_TRUE);
01462     if ( secStatus != SECSuccess ) {
01463        errExit("SSL_CipherPrefSetDefault:SSL_RSA_WITH_NULL_MD5");
01464     }
01465 
01466 
01467     if (requestCert) {
01468        SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 
01469                                (void *)CERT_GetDefaultCertDB());
01470        if (requestCert <= 2) { 
01471            rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE, 1);
01472            if (rv < 0) {
01473               errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");
01474            }
01475            rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE, 
01476                            (requestCert == 2));
01477            if (rv < 0) {
01478               errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
01479            }
01480        }
01481     }
01482 
01483     if (MakeCertOK)
01484        SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
01485 
01486     /* end of ssl configuration. */
01487 
01488 
01489     /* Now, do the accepting, here in the main thread. */
01490     rv = do_accepts(listen_sock, model_sock, requestCert);
01491 
01492     terminateWorkerThreads();
01493 
01494     if (useModelSocket && model_sock) {
01495         if (model_sock) {
01496             PR_Close(model_sock);
01497         }
01498     }
01499 
01500 }
01501 
01502 SECStatus
01503 readBigFile(const char * fileName)
01504 {
01505     PRFileInfo  info;
01506     PRStatus  status;
01507     SECStatus rv     = SECFailure;
01508     int              count;
01509     int              hdrLen;
01510     PRFileDesc *local_file_fd = NULL;
01511 
01512     status = PR_GetFileInfo(fileName, &info);
01513 
01514     if (status == PR_SUCCESS &&
01515        info.type == PR_FILE_FILE &&
01516        info.size > 0 &&
01517        NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
01518 
01519        hdrLen      = PORT_Strlen(outHeader);
01520        bigBuf.len  = hdrLen + info.size;
01521        bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
01522        if (!bigBuf.data) {
01523            errWarn("PORT_Malloc");
01524            goto done;
01525        }
01526 
01527        PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
01528 
01529        count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
01530        if (count != info.size) {
01531            errWarn("PR_Read local file");
01532            goto done;
01533        }
01534        rv = SECSuccess;
01535 done:
01536         if (local_file_fd) {
01537             PR_Close(local_file_fd);
01538         }
01539     }
01540     return rv;
01541 }
01542 
01543 int          numChildren;
01544 PRProcess *  child[MAX_PROCS];
01545 
01546 PRProcess *
01547 haveAChild(int argc, char **argv, PRProcessAttr * attr)
01548 {
01549     PRProcess *  newProcess;
01550 
01551     newProcess = PR_CreateProcess(argv[0], argv, NULL, attr);
01552     if (!newProcess) {
01553        errWarn("Can't create new process.");
01554     } else {
01555        child[numChildren++] = newProcess;
01556     }
01557     return newProcess;
01558 }
01559 
01560 void
01561 beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc * listen_sock)
01562 {
01563     PRProcess *     newProcess;
01564     PRProcessAttr * attr;
01565     int             i;
01566     PRInt32         exitCode;
01567     PRStatus        rv;
01568 
01569     rv = PR_SetFDInheritable(listen_sock, PR_TRUE);
01570     if (rv != PR_SUCCESS)
01571        errExit("PR_SetFDInheritable");
01572 
01573     attr = PR_NewProcessAttr();
01574     if (!attr)
01575        errExit("PR_NewProcessAttr");
01576 
01577     rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName);
01578     if (rv != PR_SUCCESS)
01579        errExit("PR_ProcessAttrSetInheritableFD");
01580 
01581     for (i = 0; i < maxProcs; ++i) {
01582        newProcess = haveAChild(argc, argv, attr);
01583        if (!newProcess) 
01584            break;
01585     }
01586 
01587     rv = PR_SetFDInheritable(listen_sock, PR_FALSE);
01588     if (rv != PR_SUCCESS)
01589        errExit("PR_SetFDInheritable");
01590 
01591     while (numChildren > 0) {
01592        newProcess = child[numChildren - 1];
01593        PR_WaitProcess(newProcess, &exitCode);
01594        fprintf(stderr, "Child %d exited with exit code %x\n", 
01595               numChildren, exitCode);
01596        numChildren--;
01597     }
01598     exit(0);
01599 }
01600 
01601 #ifdef DEBUG_nelsonb
01602 
01603 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
01604 #define SSL_GETPID getpid
01605 #elif defined(_WIN32_WCE)
01606 #define SSL_GETPID GetCurrentProcessId
01607 #elif defined(WIN32)
01608 extern int __cdecl _getpid(void);
01609 #define SSL_GETPID _getpid
01610 #else
01611 #define SSL_GETPID() 0   
01612 #endif
01613 
01614 void
01615 WaitForDebugger(void)
01616 {
01617 
01618     int waiting       = 12;
01619     int myPid         = SSL_GETPID();
01620     PRIntervalTime    nrval = PR_SecondsToInterval(5);
01621 
01622     while (waiting) {
01623        printf("child %d is waiting to be debugged!\n", myPid);
01624        PR_Sleep(nrval); 
01625        --waiting;
01626     }
01627 }
01628 #endif
01629 
01630 #define HEXCHAR_TO_INT(c, i) \
01631     if (((c) >= '0') && ((c) <= '9')) { \
01632        i = (c) - '0'; \
01633     } else if (((c) >= 'a') && ((c) <= 'f')) { \
01634        i = (c) - 'a' + 10; \
01635     } else if (((c) >= 'A') && ((c) <= 'F')) { \
01636        i = (c) - 'A' + 10; \
01637     } else if ((c) == '\0') { \
01638        fprintf(stderr, "Invalid length of cipher string (-c :WXYZ).\n"); \
01639        exit(9); \
01640     } else { \
01641        fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"); \
01642        exit(9); \
01643     } 
01644 
01645 int
01646 main(int argc, char **argv)
01647 {
01648     char *               progName    = NULL;
01649     char *               nickName    = NULL;
01650 #ifdef NSS_ENABLE_ECC
01651     char *               ecNickName   = NULL;
01652 #endif
01653     char *               fNickName   = NULL;
01654     const char *         fileName    = NULL;
01655     char *               cipherString= NULL;
01656     const char *         dir         = ".";
01657     char *               passwd      = NULL;
01658     const char *         pidFile     = NULL;
01659     char *               tmp;
01660     char *               envString;
01661     PRFileDesc *         listen_sock;
01662     CERTCertificate *    cert   [kt_kea_size] = { NULL };
01663     SECKEYPrivateKey *   privKey[kt_kea_size] = { NULL };
01664     int                  optionsFound = 0;
01665     int                  maxProcs     = 1;
01666     unsigned short       port        = 0;
01667     SECStatus            rv;
01668     PRStatus             prStatus;
01669     PRBool               bindOnly = PR_FALSE;
01670     PRBool               useExportPolicy = PR_FALSE;
01671     PRBool               useLocalThreads = PR_FALSE;
01672     PLOptState              *optstate;
01673     PLOptStatus          status;
01674     PRThread             *loggerThread;
01675     PRBool               debugCache = PR_FALSE; /* bug 90518 */
01676     char*                certPrefix = "";
01677 
01678 
01679     tmp = strrchr(argv[0], '/');
01680     tmp = tmp ? tmp + 1 : argv[0];
01681     progName = strrchr(tmp, '\\');
01682     progName = progName ? progName + 1 : tmp;
01683 
01684     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
01685 
01686     /* please keep this list of options in ASCII collating sequence.
01687     ** numbers, then capital letters, then lower case, alphabetical. 
01688     */
01689     optstate = PL_CreateOptState(argc, argv, 
01690        "2:3BC:DEL:M:NP:RSTbc:d:e:f:hi:lmn:op:rst:vw:xy");
01691     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
01692        ++optionsFound;
01693        switch(optstate->option) {
01694        case '2': fileName = optstate->value; break;
01695 
01696        case '3': disableSSL3 = PR_TRUE; break;
01697 
01698        case 'B': bypassPKCS11 = PR_TRUE; break;
01699 
01700         case 'C': if (optstate->value) NumSidCacheEntries = PORT_Atoi(optstate->value); break;
01701 
01702        case 'D': noDelay = PR_TRUE; break;
01703        case 'E': disableStepDown = PR_TRUE; break;
01704 
01705         case 'L':
01706             logStats = PR_TRUE;
01707            if (optstate->value == NULL) {
01708               logPeriod = 30;
01709            } else {
01710                 logPeriod  = PORT_Atoi(optstate->value);
01711                 if (logPeriod <= 0) logPeriod = 30;
01712            }
01713             break;
01714 
01715        case 'M': 
01716            maxProcs = PORT_Atoi(optstate->value); 
01717            if (maxProcs < 1)         maxProcs = 1;
01718            if (maxProcs > MAX_PROCS) maxProcs = MAX_PROCS;
01719            break;
01720 
01721        case 'N': NoReuse = PR_TRUE; break;
01722 
01723        case 'R': disableRollBack = PR_TRUE; break;
01724         
01725         case 'S': disableSSL2 = PR_TRUE; break;
01726 
01727        case 'T': disableTLS = PR_TRUE; break;
01728 
01729        case 'b': bindOnly = PR_TRUE; break;
01730 
01731        case 'c': cipherString = strdup(optstate->value); break;
01732 
01733        case 'd': dir = optstate->value; break;
01734 
01735 #ifdef NSS_ENABLE_ECC
01736        case 'e': ecNickName = strdup(optstate->value); break;
01737 #endif /* NSS_ENABLE_ECC */
01738 
01739        case 'f': fNickName = strdup(optstate->value); break;
01740 
01741        case 'h': Usage(progName); exit(0); break;
01742 
01743        case 'i': pidFile = optstate->value; break;
01744 
01745         case 'l': useLocalThreads = PR_TRUE; break;
01746 
01747        case 'm': useModelSocket = PR_TRUE; break;
01748 
01749         case 'n': nickName = strdup(optstate->value); break;
01750 
01751         case 'P': certPrefix = strdup(optstate->value); break;
01752 
01753        case 'o': MakeCertOK = 1; break;
01754 
01755        case 'p': port = PORT_Atoi(optstate->value); break;
01756 
01757        case 'r': ++requestCert; break;
01758 
01759        case 's': disableLocking = PR_TRUE; break;
01760 
01761        case 't':
01762            maxThreads = PORT_Atoi(optstate->value);
01763            if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
01764            if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
01765            break;
01766 
01767        case 'v': verbose++; break;
01768 
01769        case 'w': passwd = strdup(optstate->value); break;
01770 
01771        case 'x': useExportPolicy = PR_TRUE; break;
01772 
01773        case 'y': debugCache = PR_TRUE; break;
01774 
01775        default:
01776        case '?':
01777            fprintf(stderr, "Unrecognized or bad option specified.\n");
01778            fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
01779            exit(4);
01780            break;
01781        }
01782     }
01783     PL_DestroyOptState(optstate);
01784     if (status == PL_OPT_BAD) {
01785        fprintf(stderr, "Unrecognized or bad option specified.\n");
01786        fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
01787        exit(5);
01788     }
01789     if (!optionsFound) {
01790        Usage(progName);
01791        exit(51);
01792     } 
01793 
01794     /* The -b (bindOnly) option is only used by the ssl.sh test
01795      * script on Linux to determine whether a previous selfserv
01796      * process has fully died and freed the port.  (Bug 129701)
01797      */
01798     if (bindOnly) {
01799        listen_sock = getBoundListenSocket(port);
01800        if (!listen_sock) {
01801            exit(1);
01802        }
01803         if (listen_sock) {
01804             PR_Close(listen_sock);
01805         }
01806        exit(0);
01807     }
01808 
01809     if ((nickName == NULL) && (fNickName == NULL) 
01810 #ifdef NSS_ENABLE_ECC
01811                                           && (ecNickName == NULL)
01812 #endif
01813     ) {
01814        fprintf(stderr, "Required arg '-n' (rsa nickname) not supplied.\n");
01815        fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
01816         exit(6);
01817     }
01818 
01819     if (port == 0) {
01820        fprintf(stderr, "Required argument 'port' must be non-zero value\n");
01821        exit(7);
01822     }
01823 
01824     if (NoReuse && maxProcs > 1) {
01825        fprintf(stderr, "-M and -N options are mutually exclusive.\n");
01826        exit(14);
01827     }
01828 
01829     if (pidFile) {
01830        FILE *tmpfile=fopen(pidFile,"w+");
01831 
01832        if (tmpfile) {
01833            fprintf(tmpfile,"%d",getpid());
01834            fclose(tmpfile);
01835        }
01836     }
01837 
01838     envString = getenv(envVarName);
01839     tmp = getenv("TMP");
01840     if (!tmp)
01841        tmp = getenv("TMPDIR");
01842     if (!tmp)
01843        tmp = getenv("TEMP");
01844     if (envString) {
01845        /* we're one of the children in a multi-process server. */
01846        listen_sock = PR_GetInheritedFD(inheritableSockName);
01847        if (!listen_sock)
01848            errExit("PR_GetInheritedFD");
01849 #ifndef WINNT
01850        /* we can't do this on NT because it breaks NSPR and
01851        PR_Accept will fail on the socket in the child process if
01852        the socket state is change to non inheritable
01853        It is however a security issue to leave it accessible,
01854        but it is OK for a test server such as selfserv.
01855        NSPR should fix it eventually . see bugzilla 101617
01856        and 102077
01857        */
01858        prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
01859        if (prStatus != PR_SUCCESS)
01860            errExit("PR_SetFDInheritable");
01861 #endif
01862 #ifdef DEBUG_nelsonb
01863        WaitForDebugger();
01864 #endif
01865        rv = SSL_InheritMPServerSIDCache(envString);
01866        if (rv != SECSuccess)
01867            errExit("SSL_InheritMPServerSIDCache");
01868        hasSidCache = PR_TRUE;
01869     } else if (maxProcs > 1) {
01870        /* we're going to be the parent in a multi-process server.  */
01871        listen_sock = getBoundListenSocket(port);
01872        rv = SSL_ConfigMPServerSIDCache(NumSidCacheEntries, 0, 0, tmp);
01873        if (rv != SECSuccess)
01874            errExit("SSL_ConfigMPServerSIDCache");
01875        hasSidCache = PR_TRUE;
01876        beAGoodParent(argc, argv, maxProcs, listen_sock);
01877        exit(99); /* should never get here */
01878     } else {
01879        /* we're an ordinary single process server. */
01880        listen_sock = getBoundListenSocket(port);
01881        prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
01882        if (prStatus != PR_SUCCESS)
01883            errExit("PR_SetFDInheritable");
01884        if (!NoReuse) {
01885            rv = SSL_ConfigServerSessionIDCache(NumSidCacheEntries, 
01886                                                0, 0, tmp);
01887            if (rv != SECSuccess)
01888               errExit("SSL_ConfigServerSessionIDCache");
01889            hasSidCache = PR_TRUE;
01890        }
01891     }
01892 
01893     lm = PR_NewLogModule("TestCase");
01894 
01895     if (fileName)
01896        readBigFile(fileName);
01897 
01898     /* set our password function */
01899     PK11_SetPasswordFunc( passwd ? ownPasswd : SECU_GetModulePassword);
01900 
01901     /* Call the libsec initialization routines */
01902     rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB, NSS_INIT_READONLY);
01903     if (rv != SECSuccess) {
01904        fputs("NSS_Init failed.\n", stderr);
01905               exit(8);
01906     }
01907 
01908     /* set the policy bits true for all the cipher suites. */
01909     if (useExportPolicy) {
01910        NSS_SetExportPolicy();
01911        if (disableStepDown) {
01912            fputs("selfserv: -x and -E options may not be used together\n", 
01913                  stderr);
01914            exit(98);
01915        }
01916     } else {
01917        NSS_SetDomesticPolicy();
01918        if (disableStepDown) {
01919            rv = disableExportSSLCiphers();
01920            if (rv != SECSuccess) {
01921               errExit("error disabling export ciphersuites ");
01922            }
01923        }
01924     }
01925 
01926     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
01927     if (cipherString) {
01928        int ndx;
01929 
01930        /* disable all the ciphers, then enable the ones we want. */
01931        disableAllSSLCiphers();
01932 
01933        while (0 != (ndx = *cipherString++)) {
01934            int  cipher;
01935 
01936            if (ndx == ':') {
01937               int ctmp;
01938 
01939               cipher = 0;
01940               HEXCHAR_TO_INT(*cipherString, ctmp)
01941               cipher |= (ctmp << 12);
01942               cipherString++;
01943               HEXCHAR_TO_INT(*cipherString, ctmp)
01944               cipher |= (ctmp << 8);
01945               cipherString++;
01946               HEXCHAR_TO_INT(*cipherString, ctmp)
01947               cipher |= (ctmp << 4);
01948               cipherString++;
01949               HEXCHAR_TO_INT(*cipherString, ctmp)
01950               cipher |= ctmp;
01951               cipherString++;
01952            } else {
01953               const int *cptr;
01954 
01955               if (! isalpha(ndx)) {
01956                   fprintf(stderr, 
01957                          "Non-alphabetic char in cipher string (-c arg).\n");
01958                   exit(9);
01959               }
01960               cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
01961               for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
01962                   /* do nothing */;
01963            }
01964            if (cipher > 0) {
01965               SECStatus status;
01966               status = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED);
01967               if (status != SECSuccess) 
01968                   SECU_PrintError(progName, "SSL_CipherPrefSet()");
01969            } else {
01970               fprintf(stderr, 
01971                      "Invalid cipher specification (-c arg).\n");
01972               exit(9);
01973            }
01974        }
01975     }
01976 
01977     if (nickName) {
01978        cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd);
01979        if (cert[kt_rsa] == NULL) {
01980            fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName);
01981            exit(10);
01982        }
01983        privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd);
01984        if (privKey[kt_rsa] == NULL) {
01985            fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", 
01986                    nickName);
01987            exit(11);
01988        }
01989     }
01990     if (fNickName) {
01991        cert[kt_fortezza] = PK11_FindCertFromNickname(fNickName, NULL);
01992        if (cert[kt_fortezza] == NULL) {
01993            fprintf(stderr, "selfserv: Can't find certificate %s\n", fNickName);
01994            exit(12);
01995        }
01996        privKey[kt_fortezza] = PK11_FindKeyByAnyCert(cert[kt_fortezza], NULL);
01997     }
01998 #ifdef NSS_ENABLE_ECC
01999     if (ecNickName) {
02000        cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, NULL);
02001        if (cert[kt_ecdh] == NULL) {
02002            fprintf(stderr, "selfserv: Can't find certificate %s\n",
02003                   ecNickName);
02004            exit(13);
02005        }
02006        privKey[kt_ecdh] = PK11_FindKeyByAnyCert(cert[kt_ecdh], NULL);
02007     }
02008 #endif /* NSS_ENABLE_ECC */
02009 
02010     /* allocate the array of thread slots, and launch the worker threads. */
02011     rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads);
02012 
02013     if (rv == SECSuccess && logStats) {
02014        loggerThread = PR_CreateThread(PR_SYSTEM_THREAD, 
02015                      logger, NULL, PR_PRIORITY_NORMAL, 
02016                         useLocalThreads ? PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
02017                         PR_UNJOINABLE_THREAD, 0);
02018        if (loggerThread == NULL) {
02019            fprintf(stderr, "selfserv: Failed to launch logger thread!\n");
02020            rv = SECFailure;
02021        } 
02022     }
02023 
02024     if (rv == SECSuccess) {
02025        server_main(listen_sock, requestCert, privKey, cert);
02026     }
02027 
02028     VLOG(("selfserv: server_thread: exiting"));
02029 
02030     {
02031        int i;
02032        for (i=0; i<kt_kea_size; i++) {
02033            if (cert[i]) {
02034               CERT_DestroyCertificate(cert[i]);
02035            }
02036            if (privKey[i]) {
02037               SECKEY_DestroyPrivateKey(privKey[i]);
02038            }
02039        }
02040     }
02041 
02042     if (debugCache) {
02043        nss_DumpCertificateCacheInfo();
02044     }
02045 
02046     free(nickName);
02047     free(passwd);
02048 
02049     if (hasSidCache) {
02050        SSL_ShutdownServerSessionIDCache();
02051     }
02052     if (NSS_Shutdown() != SECSuccess) {
02053        SECU_PrintError(progName, "NSS_Shutdown");
02054        PR_Cleanup();
02055        exit(1);
02056     }
02057     PR_Cleanup();
02058     printf("selfserv: normal termination\n");
02059     return 0;
02060 }
02061