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