security/nss/cmd/httpserv/httpserv.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include <stdio.h>
     6 #include <string.h>
     8 #include "secutil.h"
    10 #if defined(XP_UNIX)
    11 #include <unistd.h>
    12 #endif
    14 #if defined(_WINDOWS)
    15 #include <process.h>	/* for getpid() */
    16 #endif
    18 #include <signal.h>
    19 #include <stdlib.h>
    20 #include <errno.h>
    21 #include <fcntl.h>
    22 #include <stdarg.h>
    24 #include "nspr.h"
    25 #include "prio.h"
    26 #include "prerror.h"
    27 #include "prnetdb.h"
    28 #include "prclist.h"
    29 #include "plgetopt.h"
    30 #include "pk11func.h"
    31 #include "nss.h"
    32 #include "nssb64.h"
    33 #include "sechash.h"
    34 #include "cert.h"
    35 #include "certdb.h"
    36 #include "ocsp.h"
    37 #include "ocspti.h"
    38 #include "ocspi.h"
    40 #ifndef PORT_Sprintf
    41 #define PORT_Sprintf sprintf
    42 #endif
    44 #ifndef PORT_Strstr
    45 #define PORT_Strstr strstr
    46 #endif
    48 #ifndef PORT_Malloc
    49 #define PORT_Malloc PR_Malloc
    50 #endif
    52 static int handle_connection( PRFileDesc *, PRFileDesc *, int );
    54 /* data and structures for shutdown */
    55 static int	stopping;
    57 static PRBool  noDelay;
    58 static int	verbose;
    60 static PRThread * acceptorThread;
    62 static PRLogModuleInfo *lm;
    64 #define PRINTF  if (verbose)  printf
    65 #define FPRINTF if (verbose) fprintf
    66 #define FLUSH	if (verbose) { fflush(stdout); fflush(stderr); }
    67 #define VLOG(arg) PR_LOG(lm,PR_LOG_DEBUG,arg)
    69 static void
    70 Usage(const char *progName)
    71 {
    72     fprintf(stderr, 
    74 "Usage: %s -p port [-Dbv]\n"
    75 "         [-t threads] [-i pid_file]\n"
    76 "         [-A nickname -C crl-filename]... [-O method]\n"
    77 "         [-d dbdir] [-f password_file] [-w password] [-P dbprefix]\n"
    78 "-D means disable Nagle delays in TCP\n"
    79 "-b means try binding to the port and exit\n"
    80 "-v means verbose output\n"
    81 "-t threads -- specify the number of threads to use for connections.\n"
    82 "-i pid_file file to write the process id of httpserv\n"
    83 "Parameters -A, -C and -O are used to provide an OCSP server at /ocsp?\n"
    84 "-A a nickname of a CA certificate\n"
    85 "-C a CRL filename corresponding to the preceding CA nickname\n"
    86 "-O allowed HTTP methods for OCSP requests: get, post, all, random, get-unknown\n"
    87 "   random means: randomly fail if request method is GET, POST always works\n"
    88 "   get-unknown means: status unknown for GET, correct status for POST\n"
    89 "Multiple pairs of parameters -A and -C are allowed.\n"
    90 "If status for a cert from an unknown CA is requested, the cert from the\n"
    91 "first -A parameter will be used to sign the unknown status response.\n"
    92 "NSS database parameters are used only if OCSP parameters are used.\n"
    93 	,progName);
    94 }
    96 static const char *
    97 errWarn(char * funcString)
    98 {
    99     PRErrorCode  perr      = PR_GetError();
   100     const char * errString = SECU_Strerror(perr);
   102     fprintf(stderr, "httpserv: %s returned error %d:\n%s\n",
   103             funcString, perr, errString);
   104     return errString;
   105 }
   107 static void
   108 errExit(char * funcString)
   109 {
   110     errWarn(funcString);
   111     exit(3);
   112 }
   114 #define MAX_VIRT_SERVER_NAME_ARRAY_INDEX  10
   116 /**************************************************************************
   117 ** Begin thread management routines and data.
   118 **************************************************************************/
   119 #define MIN_THREADS 3
   120 #define DEFAULT_THREADS 8
   121 #define MAX_THREADS 4096
   122 #define MAX_PROCS 25
   123 static int  maxThreads = DEFAULT_THREADS;
   126 typedef struct jobStr {
   127     PRCList     link;
   128     PRFileDesc *tcp_sock;
   129     PRFileDesc *model_sock;
   130     int         requestCert;
   131 } JOB;
   133 static PZLock    * qLock; /* this lock protects all data immediately below */
   134 static PRLock    * lastLoadedCrlLock; /* this lock protects lastLoadedCrl variable */
   135 static PZCondVar * jobQNotEmptyCv;
   136 static PZCondVar * freeListNotEmptyCv;
   137 static PZCondVar * threadCountChangeCv;
   138 static int  threadCount;
   139 static PRCList  jobQ;
   140 static PRCList  freeJobs;
   141 static JOB *jobTable;
   143 SECStatus
   144 setupJobs(int maxJobs)
   145 {
   146     int i;
   148     jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB));
   149     if (!jobTable)
   150     	return SECFailure;
   152     PR_INIT_CLIST(&jobQ);
   153     PR_INIT_CLIST(&freeJobs);
   155     for (i = 0; i < maxJobs; ++i) {
   156 	JOB * pJob = jobTable + i;
   157 	PR_APPEND_LINK(&pJob->link, &freeJobs);
   158     }
   159     return SECSuccess;
   160 }
   162 typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
   164 typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
   166 typedef struct perThreadStr {
   167     PRFileDesc *a;
   168     PRFileDesc *b;
   169     int         c;
   170     int         rv;
   171     startFn  *  startFunc;
   172     PRThread *  prThread;
   173     runState	state;
   174 } perThread;
   176 static perThread *threads;
   178 void
   179 thread_wrapper(void * arg)
   180 {
   181     perThread * slot = (perThread *)arg;
   183     slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
   185     /* notify the thread exit handler. */
   186     PZ_Lock(qLock);
   187     slot->state = rs_zombie;
   188     --threadCount;
   189     PZ_NotifyAllCondVar(threadCountChangeCv);
   190     PZ_Unlock(qLock);
   191 }
   193 int 
   194 jobLoop(PRFileDesc *a, PRFileDesc *b, int c)
   195 {
   196     PRCList * myLink = 0;
   197     JOB     * myJob;
   199     PZ_Lock(qLock);
   200     do {
   201 	myLink = 0;
   202 	while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) {
   203             PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
   204 	}
   205 	if (!PR_CLIST_IS_EMPTY(&jobQ)) {
   206 	    myLink = PR_LIST_HEAD(&jobQ);
   207 	    PR_REMOVE_AND_INIT_LINK(myLink);
   208 	}
   209 	PZ_Unlock(qLock);
   210 	myJob = (JOB *)myLink;
   211 	/* myJob will be null when stopping is true and jobQ is empty */
   212 	if (!myJob) 
   213 	    break;
   214 	handle_connection( myJob->tcp_sock, myJob->model_sock, 
   215 			   myJob->requestCert);
   216 	PZ_Lock(qLock);
   217 	PR_APPEND_LINK(myLink, &freeJobs);
   218 	PZ_NotifyCondVar(freeListNotEmptyCv);
   219     } while (PR_TRUE);
   220     return 0;
   221 }
   224 SECStatus
   225 launch_threads(
   226     startFn    *startFunc,
   227     PRFileDesc *a,
   228     PRFileDesc *b,
   229     int         c,
   230     PRBool      local)
   231 {
   232     int i;
   233     SECStatus rv = SECSuccess;
   235     /* create the thread management serialization structs */
   236     qLock               = PZ_NewLock(nssILockSelfServ);
   237     jobQNotEmptyCv      = PZ_NewCondVar(qLock);
   238     freeListNotEmptyCv  = PZ_NewCondVar(qLock);
   239     threadCountChangeCv = PZ_NewCondVar(qLock);
   241     /* create monitor for crl reload procedure */
   242     lastLoadedCrlLock   = PR_NewLock();
   244     /* allocate the array of thread slots */
   245     threads = PR_Calloc(maxThreads, sizeof(perThread));
   246     if ( NULL == threads )  {
   247         fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
   248         return SECFailure;
   249     }
   250     /* 5 is a little extra, intended to keep the jobQ from underflowing. 
   251     ** That is, from going empty while not stopping and clients are still
   252     ** trying to contact us.
   253     */
   254     rv = setupJobs(maxThreads + 5);
   255     if (rv != SECSuccess)
   256     	return rv;
   258     PZ_Lock(qLock);
   259     for (i = 0; i < maxThreads; ++i) {
   260     	perThread * slot = threads + i;
   262 	slot->state = rs_running;
   263 	slot->a = a;
   264 	slot->b = b;
   265 	slot->c = c;
   266 	slot->startFunc = startFunc;
   267 	slot->prThread = PR_CreateThread(PR_USER_THREAD, 
   268 			thread_wrapper, slot, PR_PRIORITY_NORMAL, 
   269                         (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
   270                         PR_UNJOINABLE_THREAD, 0);
   271 	if (slot->prThread == NULL) {
   272 	    printf("httpserv: Failed to launch thread!\n");
   273 	    slot->state = rs_idle;
   274 	    rv = SECFailure;
   275 	    break;
   276 	} 
   278 	++threadCount;
   279     }
   280     PZ_Unlock(qLock); 
   282     return rv;
   283 }
   285 #define DESTROY_CONDVAR(name) if (name) { \
   286         PZ_DestroyCondVar(name); name = NULL; }
   287 #define DESTROY_LOCK(name) if (name) { \
   288         PZ_DestroyLock(name); name = NULL; }
   291 void
   292 terminateWorkerThreads(void)
   293 {
   294     VLOG(("httpserv: server_thead: waiting on stopping"));
   295     PZ_Lock(qLock);
   296     PZ_NotifyAllCondVar(jobQNotEmptyCv);
   297     while (threadCount > 0) {
   298 	PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT);
   299     }
   300     /* The worker threads empty the jobQ before they terminate. */
   301     PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ));
   302     PZ_Unlock(qLock); 
   304     DESTROY_CONDVAR(jobQNotEmptyCv);
   305     DESTROY_CONDVAR(freeListNotEmptyCv);
   306     DESTROY_CONDVAR(threadCountChangeCv);
   308     PR_DestroyLock(lastLoadedCrlLock);
   309     DESTROY_LOCK(qLock);
   310     PR_Free(jobTable);
   311     PR_Free(threads);
   312 }
   314 /**************************************************************************
   315 ** End   thread management routines.
   316 **************************************************************************/
   318 PRBool NoReuse         = PR_FALSE;
   319 PRBool disableLocking  = PR_FALSE;
   320 static secuPWData  pwdata = { PW_NONE, 0 };
   322 struct caRevoInfoStr
   323 {
   324     PRCList link;
   325     char *nickname;
   326     char *crlFilename;
   327     CERTCertificate *cert;
   328     CERTOCSPCertID *id;
   329     CERTSignedCrl *crl;
   330 };
   331 typedef struct caRevoInfoStr caRevoInfo;
   332 /* Created during app init. No locks necessary, 
   333  * because later on, only read access will occur. */
   334 static caRevoInfo *caRevoInfos = NULL;
   336 static enum { 
   337   ocspGetOnly, ocspPostOnly, ocspGetAndPost, ocspRandomGetFailure, ocspGetUnknown
   338 } ocspMethodsAllowed = ocspGetAndPost;
   340 static const char stopCmd[] = { "GET /stop " };
   341 static const char getCmd[]  = { "GET " };
   342 static const char EOFmsg[]  = { "EOF\r\n\r\n\r\n" };
   343 static const char outHeader[] = {
   344     "HTTP/1.0 200 OK\r\n"
   345     "Server: Generic Web Server\r\n"
   346     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
   347     "Content-type: text/plain\r\n"
   348     "\r\n"
   349 };
   350 static const char outOcspHeader[] = {
   351     "HTTP/1.0 200 OK\r\n"
   352     "Server: Generic OCSP Server\r\n"
   353     "Content-type: application/ocsp-response\r\n"
   354     "\r\n"
   355 };
   356 static const char outBadRequestHeader[] = {
   357     "HTTP/1.0 400 Bad Request\r\n"
   358     "Server: Generic OCSP Server\r\n"
   359     "\r\n"
   360 };
   362 void stop_server()
   363 {
   364     stopping = 1;
   365     PR_Interrupt(acceptorThread);
   366     PZ_TraceFlush();
   367 }
   369 /* Will only work if the original input to url encoding was
   370  * a base64 encoded buffer. Will only decode the sequences used
   371  * for encoding the special base64 characters, and fail if any
   372  * other encoded chars are found.
   373  * Will return SECSuccess if input could be processed.
   374  * Coversion is done in place.
   375  */
   376 static SECStatus
   377 urldecode_base64chars_inplace(char *buf)
   378 {
   379     char *walk;
   380     size_t remaining_bytes;
   382     if (!buf || !*buf)
   383 	return SECFailure;
   385     walk = buf;
   386     remaining_bytes = strlen(buf) + 1; /* include terminator */
   388     while (*walk) {
   389 	if (*walk == '%') {
   390 	    if (!PL_strncasecmp(walk, "%2B", 3)) {
   391 		*walk = '+';
   392 	    } else if (!PL_strncasecmp(walk, "%2F", 3)) {
   393 		*walk = '/';
   394 	    } else if (!PL_strncasecmp(walk, "%3D", 3)) {
   395 		*walk = '=';
   396 	    } else {
   397 		return SECFailure;
   398 	    }
   399 	    remaining_bytes -= 3;
   400 	    ++walk;
   401 	    memmove(walk, walk+2, remaining_bytes);
   402 	} else {
   403 	    ++walk;
   404 	    --remaining_bytes;
   405 	}
   406     }
   407     return SECSuccess;
   408 }
   410 int
   411 handle_connection( 
   412     PRFileDesc *tcp_sock,
   413     PRFileDesc *model_sock,
   414     int         requestCert
   415     )
   416 {
   417     PRFileDesc *       ssl_sock = NULL;
   418     PRFileDesc *       local_file_fd = NULL;
   419     char  *            pBuf;			/* unused space at end of buf */
   420     const char *       errString;
   421     PRStatus           status;
   422     int                bufRem;			/* unused bytes at end of buf */
   423     int                bufDat;			/* characters received in buf */
   424     int                newln    = 0;		/* # of consecutive newlns */
   425     int                firstTime = 1;
   426     int                reqLen;
   427     int                rv;
   428     int                numIOVs;
   429     PRSocketOptionData opt;
   430     PRIOVec            iovs[16];
   431     char               msgBuf[160];
   432     char               buf[10240];
   433     char               fileName[513];
   434     char *getData = NULL; /* inplace conversion */
   435     SECItem postData;
   436     PRBool isOcspRequest = PR_FALSE;
   437     PRBool isPost;
   439     postData.data = NULL;
   440     postData.len = 0;
   442     pBuf   = buf;
   443     bufRem = sizeof buf;
   445     VLOG(("httpserv: handle_connection: starting"));
   446     opt.option             = PR_SockOpt_Nonblocking;
   447     opt.value.non_blocking = PR_FALSE;
   448     PR_SetSocketOption(tcp_sock, &opt);
   450     VLOG(("httpserv: handle_connection: starting\n"));
   451 	ssl_sock = tcp_sock;
   453     if (noDelay) {
   454 	opt.option         = PR_SockOpt_NoDelay;
   455 	opt.value.no_delay = PR_TRUE;
   456 	status = PR_SetSocketOption(ssl_sock, &opt);
   457 	if (status != PR_SUCCESS) {
   458 	    errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
   459             if (ssl_sock) {
   460 	        PR_Close(ssl_sock);
   461             }
   462 	    return SECFailure;
   463 	}
   464     }
   466     while (1) {
   467 	const char *post;
   468 	const char *foundStr = NULL;
   469 	const char *tmp = NULL;
   471 	newln = 0;
   472 	reqLen = 0;
   474 	rv = PR_Read(ssl_sock, pBuf, bufRem - 1);
   475 	if (rv == 0 || 
   476 	    (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) {
   477 	    if (verbose)
   478 		errWarn("HDX PR_Read hit EOF");
   479 	    break;
   480 	}
   481 	if (rv < 0) {
   482 	    errWarn("HDX PR_Read");
   483 	    goto cleanup;
   484 	}
   485 	/* NULL termination */
   486 	pBuf[rv] = 0;
   487 	if (firstTime) {
   488 	    firstTime = 0;
   489 	}
   491 	pBuf   += rv;
   492 	bufRem -= rv;
   493 	bufDat = pBuf - buf;
   494 	/* Parse the input, starting at the beginning of the buffer.
   495 	 * Stop when we detect two consecutive \n's (or \r\n's) 
   496 	 * as this signifies the end of the GET or POST portion.
   497 	 * The posted data follows.
   498 	 */
   499 	while (reqLen < bufDat && newln < 2) {
   500 	    int octet = buf[reqLen++];
   501 	    if (octet == '\n') {
   502 		newln++;
   503 	    } else if (octet != '\r') {
   504 		newln = 0;
   505 	    }
   506 	}
   508 	/* came to the end of the buffer, or second newln
   509 	 * If we didn't get an empty line (CRLFCRLF) then keep on reading.
   510 	 */
   511 	if (newln < 2) 
   512 	    continue;
   514 	/* we're at the end of the HTTP request.
   515 	 * If the request is a POST, then there will be one more
   516 	 * line of data.
   517 	 * This parsing is a hack, but ok for SSL test purposes.
   518 	 */
   519 	post = PORT_Strstr(buf, "POST ");
   520 	if (!post || *post != 'P') 
   521 	    break;
   523 	postData.data = (void*)(buf + reqLen);
   525 	tmp = "content-length: ";
   526 	foundStr = PL_strcasestr(buf, tmp);
   527 	if (foundStr) {
   528 	    int expectedPostLen;
   529 	    int havePostLen;
   531 	    expectedPostLen = atoi(foundStr+strlen(tmp));
   532 	    havePostLen = bufDat - reqLen;
   533 	    if (havePostLen >= expectedPostLen) {
   534 		postData.len = expectedPostLen;
   535 		break;
   536 	    }
   537 	} else {
   538 	    /* use legacy hack */
   539 	    /* It's a post, so look for the next and final CR/LF. */
   540 	    while (reqLen < bufDat && newln < 3) {
   541 		int octet = buf[reqLen++];
   542 		if (octet == '\n') {
   543 		    newln++;
   544 		}
   545 	    }
   546 	    if (newln == 3)
   547 		break;
   548 	}
   549     } /* read loop */
   551     bufDat = pBuf - buf;
   552     if (bufDat) do {	/* just close if no data */
   553 	/* Have either (a) a complete get, (b) a complete post, (c) EOF */
   554 	if (reqLen > 0) {
   555 	    PRBool isGetOrPost = PR_FALSE;
   556 	    unsigned skipChars = 0;
   557 	    isPost = PR_FALSE;
   559 	    if (!strncmp(buf, getCmd, sizeof getCmd - 1)) {
   560 		isGetOrPost = PR_TRUE;
   561 		skipChars = 4;
   562 	    }
   563 	    else if (!strncmp(buf, "POST ", 5)) {
   564 		isGetOrPost = PR_TRUE;
   565 		isPost = PR_TRUE;
   566 		skipChars = 5;
   567 	    }
   569 	    if (isGetOrPost) {
   570 		char *      fnBegin = buf;
   571 		char *      fnEnd;
   572 		char *      fnstart = NULL;
   573 		PRFileInfo  info;
   575 		fnBegin += skipChars;
   577 		fnEnd = strpbrk(fnBegin, " \r\n");
   578 		if (fnEnd) {
   579 		    int fnLen = fnEnd - fnBegin;
   580 		    if (fnLen < sizeof fileName) {
   581 			strncpy(fileName, fnBegin, fnLen);
   582 			fileName[fnLen] = 0;	/* null terminate */
   583 			fnstart = fileName;
   584 			/* strip initial / because our root is the current directory*/
   585 			while (*fnstart && *fnstart=='/')
   586 			    ++fnstart;
   587 		    }
   588 		}
   589 		if (fnstart) {
   590 		    if (!strncmp(fnstart, "ocsp", 4)) {
   591 			if (isPost) {
   592 			    if (postData.data) {
   593 				isOcspRequest = PR_TRUE;
   594 			    }
   595 			} else {
   596 			    if (!strncmp(fnstart, "ocsp/", 5)) {
   597 				isOcspRequest = PR_TRUE;
   598 				getData = fnstart + 5;
   599 			    }
   600 			}
   601 		    } else {
   602 			/* try to open the file named.  
   603 			* If successful, then write it to the client.
   604 			*/
   605 			status = PR_GetFileInfo(fnstart, &info);
   606 			if (status == PR_SUCCESS &&
   607 			    info.type == PR_FILE_FILE &&
   608 			    info.size >= 0 ) {
   609 			    local_file_fd = PR_Open(fnstart, PR_RDONLY, 0);
   610 			}
   611 		    }
   612 		}
   613 	    }
   614 	}
   616 	numIOVs = 0;
   618 	iovs[numIOVs].iov_base = (char *)outHeader;
   619 	iovs[numIOVs].iov_len  = (sizeof(outHeader)) - 1;
   620 	numIOVs++;
   622 	if (isOcspRequest && caRevoInfos) {
   623 	    CERTOCSPRequest *request = NULL;
   624 	    PRBool failThisRequest = PR_FALSE;
   626 	    if (ocspMethodsAllowed == ocspGetOnly && postData.len) {
   627 		failThisRequest = PR_TRUE;
   628 	    } else if (ocspMethodsAllowed == ocspPostOnly && getData) {
   629 		failThisRequest = PR_TRUE;
   630 	    } else if (ocspMethodsAllowed == ocspRandomGetFailure && getData) {
   631 		if (!(rand() % 2)) {
   632 		    failThisRequest = PR_TRUE;
   633 		}
   634 	    }
   636 	    if (failThisRequest) {
   637 		PR_Write(ssl_sock, outBadRequestHeader, strlen(outBadRequestHeader));
   638 		break;
   639 	    }
   640 	    /* get is base64, post is binary.
   641 	     * If we have base64, convert into the (empty) postData array.
   642 	     */
   643 	    if (getData) {
   644 		if (urldecode_base64chars_inplace(getData) == SECSuccess) {
   645 		    NSSBase64_DecodeBuffer(NULL, &postData, getData, strlen(getData));
   646 		}
   647 	    }
   648 	    if (postData.len) {
   649 		request = CERT_DecodeOCSPRequest(&postData);
   650 	    }
   651 	    if (!request || !request->tbsRequest || 
   652 	        !request->tbsRequest->requestList ||
   653 	        !request->tbsRequest->requestList[0]) {
   654 		PORT_Sprintf(msgBuf, "Cannot decode OCSP request.\r\n");
   656 		iovs[numIOVs].iov_base = msgBuf;
   657 		iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
   658 		numIOVs++;
   659 	    } else {
   660 	      /* TODO: support more than one request entry */
   661 	      CERTOCSPCertID *reqid = request->tbsRequest->requestList[0]->reqCert;
   662 	      const caRevoInfo *revoInfo = NULL;
   663 	      PRBool unknown = PR_FALSE;
   664 	      PRBool revoked = PR_FALSE;
   665 	      PRTime nextUpdate = 0;
   666 	      PRTime revoDate = 0;
   667 	      PRCList *caRevoIter;
   669 	      caRevoIter = &caRevoInfos->link;
   670 	      do {
   671 		  CERTOCSPCertID *caid;
   673 		  revoInfo = (caRevoInfo*)caRevoIter;
   674 		  caid = revoInfo->id;
   676 		  if (SECOID_CompareAlgorithmID(&reqid->hashAlgorithm, 
   677 		                                &caid->hashAlgorithm) == SECEqual
   678 		      &&
   679 		      SECITEM_CompareItem(&reqid->issuerNameHash,
   680 					  &caid->issuerNameHash) == SECEqual
   681 		      &&
   682 		      SECITEM_CompareItem(&reqid->issuerKeyHash,
   683 					  &caid->issuerKeyHash) == SECEqual) {
   684 		      break;
   685 		  }
   686 		  revoInfo = NULL;
   687 		  caRevoIter = PR_NEXT_LINK(caRevoIter);
   688 	      } while (caRevoIter != &caRevoInfos->link);
   690 	      if (!revoInfo) {
   691 		  unknown = PR_TRUE;
   692 		  revoInfo = caRevoInfos;
   693 	      } else {
   694 		  CERTCrl *crl = &revoInfo->crl->crl;
   695 		  CERTCrlEntry *entry = NULL;
   696 		  DER_DecodeTimeChoice(&nextUpdate, &crl->nextUpdate);
   697 		  if (crl->entries) {
   698 		      int iv = 0;
   699 		      /* assign, not compare */
   700 		      while ((entry = crl->entries[iv++])) {
   701 			  if (SECITEM_CompareItem(&reqid->serialNumber,
   702 						  &entry->serialNumber) == SECEqual) {
   703 			      break;
   704 			  }
   705 		      }
   706 		  }
   707 		  if (entry) {
   708 		      /* revoked status response */
   709 		      revoked = PR_TRUE;
   710 		      DER_DecodeTimeChoice(&revoDate, &entry->revocationDate);
   711 		  } else {
   712 		      /* else good status response */
   713 		      if (!isPost && ocspMethodsAllowed == ocspGetUnknown) {
   714 			  unknown = PR_TRUE;
   715 			  nextUpdate = PR_Now() + 60*60*24 * PR_USEC_PER_SEC; /*tomorrow*/
   716 			  revoDate = PR_Now() - 60*60*24 * PR_USEC_PER_SEC; /*yesterday*/
   717 		      }
   718 		  }
   719 	      }
   721 	      {
   722 		  PRTime now = PR_Now();
   723 		  PLArenaPool *arena = NULL;
   724 		  CERTOCSPSingleResponse *sr;
   725 		  CERTOCSPSingleResponse **singleResponses;
   726 		  SECItem *ocspResponse;
   728 		  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   730 		  if (unknown) {
   731 		      sr = CERT_CreateOCSPSingleResponseUnknown(arena, reqid, now,
   732 								&nextUpdate);
   733 		  } else if (revoked) {
   734 		      sr = CERT_CreateOCSPSingleResponseRevoked(arena, reqid, now,
   735 			  &nextUpdate, revoDate, NULL);
   736 		  } else {
   737 		      sr = CERT_CreateOCSPSingleResponseGood(arena, reqid, now,
   738 							    &nextUpdate);
   739 		  }
   741 		  /* meaning of value 2: one entry + one end marker */
   742 		  singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse*, 2);
   743 		  singleResponses[0] = sr;
   744 		  singleResponses[1] = NULL;
   745 		  ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena, 
   746 				      revoInfo->cert, ocspResponderID_byName, now,
   747 				      singleResponses, &pwdata);
   749 		  if (!ocspResponse) {
   750 		      PORT_Sprintf(msgBuf, "Failed to encode response\r\n");
   751 		      iovs[numIOVs].iov_base = msgBuf;
   752 		      iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
   753 		      numIOVs++;
   754 		  } else {
   755 		      PR_Write(ssl_sock, outOcspHeader, strlen(outOcspHeader));
   756 		      PR_Write(ssl_sock, ocspResponse->data, ocspResponse->len);
   757 		      PORT_FreeArena(arena, PR_FALSE);
   758 		  }
   759 	      }
   760 	      break;
   761 	    }
   762 	} else if (local_file_fd) {
   763 	    PRInt32     bytes;
   764 	    int         errLen;
   765             bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader,
   766                                     sizeof outHeader - 1,
   767                                     PR_TRANSMITFILE_KEEP_OPEN,
   768                                     PR_INTERVAL_NO_TIMEOUT);
   769             if (bytes >= 0) {
   770                 bytes -= sizeof outHeader - 1;
   771                 FPRINTF(stderr, 
   772                         "httpserv: PR_TransmitFile wrote %d bytes from %s\n",
   773                         bytes, fileName);
   774                 break;
   775             }
   776             errString = errWarn("PR_TransmitFile");
   777             errLen = PORT_Strlen(errString);
   778             errLen = PR_MIN(errLen, sizeof msgBuf - 1);
   779             PORT_Memcpy(msgBuf, errString, errLen);
   780             msgBuf[errLen] = 0;
   782             iovs[numIOVs].iov_base = msgBuf;
   783             iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
   784             numIOVs++;
   785 	} else if (reqLen <= 0) {	/* hit eof */
   786 	    PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n",
   787 			 bufDat);
   789 	    iovs[numIOVs].iov_base = msgBuf;
   790 	    iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
   791 	    numIOVs++;
   792 	} else if (reqLen < bufDat) {
   793 	    PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", 
   794 	                 bufDat - reqLen);
   796 	    iovs[numIOVs].iov_base = msgBuf;
   797 	    iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
   798 	    numIOVs++;
   799 	}
   801 	if (reqLen > 0) {
   802 	    if (verbose > 1) 
   803 	    	fwrite(buf, 1, reqLen, stdout);	/* display it */
   805 	    iovs[numIOVs].iov_base = buf;
   806 	    iovs[numIOVs].iov_len  = reqLen;
   807 	    numIOVs++;
   808 	}
   810 	rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT);
   811 	if (rv < 0) {
   812 	    errWarn("PR_Writev");
   813 	    break;
   814 	}
   816     } while (0);
   818 cleanup:
   819     if (ssl_sock) {
   820         PR_Close(ssl_sock);
   821     } else if (tcp_sock) {
   822         PR_Close(tcp_sock);
   823     }
   824     if (local_file_fd)
   825 	PR_Close(local_file_fd);
   826     VLOG(("httpserv: handle_connection: exiting\n"));
   828     /* do a nice shutdown if asked. */
   829     if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) {
   830         VLOG(("httpserv: handle_connection: stop command"));
   831         stop_server();
   832     }
   833     VLOG(("httpserv: handle_connection: exiting"));
   834     return SECSuccess;	/* success */
   835 }
   837 #ifdef XP_UNIX
   839 void sigusr1_handler(int sig)
   840 {
   841     VLOG(("httpserv: sigusr1_handler: stop server"));
   842     stop_server();
   843 }
   845 #endif
   847 SECStatus
   848 do_accepts(
   849     PRFileDesc *listen_sock,
   850     PRFileDesc *model_sock,
   851     int         requestCert
   852     )
   853 {
   854     PRNetAddr   addr;
   855     PRErrorCode  perr;
   856 #ifdef XP_UNIX
   857     struct sigaction act;
   858 #endif
   860     VLOG(("httpserv: do_accepts: starting"));
   861     PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH);
   863     acceptorThread = PR_GetCurrentThread();
   864 #ifdef XP_UNIX
   865     /* set up the signal handler */
   866     act.sa_handler = sigusr1_handler;
   867     sigemptyset(&act.sa_mask);
   868     act.sa_flags = 0;
   869     if (sigaction(SIGUSR1, &act, NULL)) {
   870         fprintf(stderr, "Error installing signal handler.\n");
   871         exit(1);
   872     }
   873 #endif
   874     while (!stopping) {
   875 	PRFileDesc *tcp_sock;
   876 	PRCList    *myLink;
   878 	FPRINTF(stderr, "\n\n\nhttpserv: About to call accept.\n");
   879 	tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
   880 	if (tcp_sock == NULL) {
   881     	    perr      = PR_GetError();
   882 	    if ((perr != PR_CONNECT_RESET_ERROR &&
   883 	         perr != PR_PENDING_INTERRUPT_ERROR) || verbose) {
   884 		errWarn("PR_Accept");
   885 	    } 
   886 	    if (perr == PR_CONNECT_RESET_ERROR) {
   887 		FPRINTF(stderr, 
   888 		        "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
   889 		continue;
   890 	    }
   891 	    stopping = 1;
   892 	    break;
   893 	}
   895         VLOG(("httpserv: do_accept: Got connection\n"));
   897 	PZ_Lock(qLock);
   898 	while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
   899             PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
   900 	}
   901 	if (stopping) {
   902 	    PZ_Unlock(qLock);
   903             if (tcp_sock) {
   904 	        PR_Close(tcp_sock);
   905             }
   906 	    break;
   907 	}
   908 	myLink = PR_LIST_HEAD(&freeJobs);
   909 	PR_REMOVE_AND_INIT_LINK(myLink);
   910 	/* could release qLock here and reaquire it 7 lines below, but 
   911 	** why bother for 4 assignment statements? 
   912 	*/
   913 	{
   914 	    JOB * myJob = (JOB *)myLink;
   915 	    myJob->tcp_sock    = tcp_sock;
   916 	    myJob->model_sock  = model_sock;
   917 	    myJob->requestCert = requestCert;
   918 	}
   920 	PR_APPEND_LINK(myLink, &jobQ);
   921 	PZ_NotifyCondVar(jobQNotEmptyCv);
   922 	PZ_Unlock(qLock);
   923     }
   925     FPRINTF(stderr, "httpserv: Closing listen socket.\n");
   926     VLOG(("httpserv: do_accepts: exiting"));
   927     if (listen_sock) {
   928         PR_Close(listen_sock);
   929     }
   930     return SECSuccess;
   931 }
   933 PRFileDesc *
   934 getBoundListenSocket(unsigned short port)
   935 {
   936     PRFileDesc *       listen_sock;
   937     int                listenQueueDepth = 5 + (2 * maxThreads);
   938     PRStatus	       prStatus;
   939     PRNetAddr          addr;
   940     PRSocketOptionData opt;
   942     addr.inet.family = PR_AF_INET;
   943     addr.inet.ip     = PR_INADDR_ANY;
   944     addr.inet.port   = PR_htons(port);
   946     listen_sock = PR_NewTCPSocket();
   947     if (listen_sock == NULL) {
   948 	errExit("PR_NewTCPSocket");
   949     }
   951     opt.option = PR_SockOpt_Nonblocking;
   952     opt.value.non_blocking = PR_FALSE;
   953     prStatus = PR_SetSocketOption(listen_sock, &opt);
   954     if (prStatus < 0) {
   955         PR_Close(listen_sock);
   956 	errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)");
   957     }
   959     opt.option=PR_SockOpt_Reuseaddr;
   960     opt.value.reuse_addr = PR_TRUE;
   961     prStatus = PR_SetSocketOption(listen_sock, &opt);
   962     if (prStatus < 0) {
   963         PR_Close(listen_sock);
   964 	errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)");
   965     }
   967 #ifndef WIN95
   968     /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
   969      * after clean shutdown . See bug 331413 .
   970      * Don't do it in the WIN95 build configuration because clean shutdown is
   971      * not implemented, and PR_SockOpt_Linger causes a hang in ssl.sh .
   972      * See bug 332348 */
   973     opt.option=PR_SockOpt_Linger;
   974     opt.value.linger.polarity = PR_TRUE;
   975     opt.value.linger.linger = PR_SecondsToInterval(1);
   976     prStatus = PR_SetSocketOption(listen_sock, &opt);
   977     if (prStatus < 0) {
   978         PR_Close(listen_sock);
   979         errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
   980     }
   981 #endif
   983     prStatus = PR_Bind(listen_sock, &addr);
   984     if (prStatus < 0) {
   985         PR_Close(listen_sock);
   986 	errExit("PR_Bind");
   987     }
   989     prStatus = PR_Listen(listen_sock, listenQueueDepth);
   990     if (prStatus < 0) {
   991         PR_Close(listen_sock);
   992 	errExit("PR_Listen");
   993     }
   994     return listen_sock;
   995 }
   997 void
   998 server_main(
   999     PRFileDesc *        listen_sock,
  1000     int                 requestCert, 
  1001     SECKEYPrivateKey ** privKey,
  1002     CERTCertificate **  cert,
  1003     const char *expectedHostNameVal)
  1005     PRFileDesc *model_sock	= NULL;
  1007     /* Now, do the accepting, here in the main thread. */
  1008     do_accepts(listen_sock, model_sock, requestCert);
  1010     terminateWorkerThreads();
  1012         if (model_sock) {
  1013             PR_Close(model_sock);
  1018 int          numChildren;
  1019 PRProcess *  child[MAX_PROCS];
  1021 PRProcess *
  1022 haveAChild(int argc, char **argv, PRProcessAttr * attr)
  1024     PRProcess *  newProcess;
  1026     newProcess = PR_CreateProcess(argv[0], argv, NULL, attr);
  1027     if (!newProcess) {
  1028 	errWarn("Can't create new process.");
  1029     } else {
  1030 	child[numChildren++] = newProcess;
  1032     return newProcess;
  1035 /* slightly adjusted version of ocsp_CreateCertID (not using issuer) */
  1036 static CERTOCSPCertID *
  1037 ocsp_CreateSelfCAID(PLArenaPool *arena, CERTCertificate *cert, PRTime time)
  1039     CERTOCSPCertID *certID;
  1040     void *mark = PORT_ArenaMark(arena);
  1041     SECStatus rv;
  1043     PORT_Assert(arena != NULL);
  1045     certID = PORT_ArenaZNew(arena, CERTOCSPCertID);
  1046     if (certID == NULL) {
  1047 	goto loser;
  1050     rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1,
  1051 			       NULL);
  1052     if (rv != SECSuccess) {
  1053 	goto loser; 
  1056     if (CERT_GetSubjectNameDigest(arena, cert, SEC_OID_SHA1,
  1057                                   &(certID->issuerNameHash)) == NULL) {
  1058         goto loser;
  1060     certID->issuerSHA1NameHash.data = certID->issuerNameHash.data;
  1061     certID->issuerSHA1NameHash.len = certID->issuerNameHash.len;
  1063     if (CERT_GetSubjectNameDigest(arena, cert, SEC_OID_MD5,
  1064                                   &(certID->issuerMD5NameHash)) == NULL) {
  1065         goto loser;
  1068     if (CERT_GetSubjectNameDigest(arena, cert, SEC_OID_MD2,
  1069                                   &(certID->issuerMD2NameHash)) == NULL) {
  1070         goto loser;
  1073     if (CERT_GetSubjectPublicKeyDigest(arena, cert, SEC_OID_SHA1,
  1074 				       &certID->issuerKeyHash) == NULL) {
  1075 	goto loser;
  1077     certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data;
  1078     certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len;
  1079     /* cache the other two hash algorithms as well */
  1080     if (CERT_GetSubjectPublicKeyDigest(arena, cert, SEC_OID_MD5,
  1081 				       &certID->issuerMD5KeyHash) == NULL) {
  1082 	goto loser;
  1084     if (CERT_GetSubjectPublicKeyDigest(arena, cert, SEC_OID_MD2,
  1085 				       &certID->issuerMD2KeyHash) == NULL) {
  1086 	goto loser;
  1089     PORT_ArenaUnmark(arena, mark);
  1090     return certID;
  1092 loser:
  1093     PORT_ArenaRelease(arena, mark);
  1094     return NULL;
  1097 /* slightly adjusted version of CERT_CreateOCSPCertID */
  1098 CERTOCSPCertID*
  1099 cert_CreateSelfCAID(CERTCertificate *cert, PRTime time)
  1101     PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1102     CERTOCSPCertID *certID;
  1103     PORT_Assert(arena != NULL);
  1104     if (!arena)
  1105 	return NULL;
  1107     certID = ocsp_CreateSelfCAID(arena, cert, time);
  1108     if (!certID) {
  1109 	PORT_FreeArena(arena, PR_FALSE);
  1110 	return NULL;
  1112     certID->poolp = arena;
  1113     return certID;
  1116 int
  1117 main(int argc, char **argv)
  1119     char *               progName    = NULL;
  1120     const char *         dir         = ".";
  1121     char *               passwd      = NULL;
  1122     char *               pwfile      = NULL;
  1123     const char *         pidFile     = NULL;
  1124     char *               tmp;
  1125     PRFileDesc *         listen_sock;
  1126     int                  optionsFound = 0;
  1127     unsigned short       port        = 0;
  1128     SECStatus            rv;
  1129     PRStatus             prStatus;
  1130     PRBool               bindOnly = PR_FALSE;
  1131     PRBool               useLocalThreads = PR_FALSE;
  1132     PLOptState		*optstate;
  1133     PLOptStatus          status;
  1134     char                 emptyString[] = { "" };
  1135     char*                certPrefix = emptyString;
  1136     caRevoInfo		*revoInfo = NULL;
  1137     PRCList             *caRevoIter = NULL;
  1138     PRBool               provideOcsp = PR_FALSE;
  1140     tmp = strrchr(argv[0], '/');
  1141     tmp = tmp ? tmp + 1 : argv[0];
  1142     progName = strrchr(tmp, '\\');
  1143     progName = progName ? progName + 1 : tmp;
  1145     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  1147     /* please keep this list of options in ASCII collating sequence.
  1148     ** numbers, then capital letters, then lower case, alphabetical. 
  1149     */
  1150     optstate = PL_CreateOptState(argc, argv, 
  1151         "A:C:DO:P:bd:f:hi:p:t:vw:");
  1152     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  1153 	++optionsFound;
  1154 	switch(optstate->option) {
  1155 	/* A first, must be followed by C. Any other order is an error.
  1156 	 * A creates the object. C completes and moves into list.
  1157 	 */
  1158 	case 'A':
  1159 	  provideOcsp = PR_TRUE;
  1160 	  if (revoInfo) { Usage(progName); exit(0); }
  1161 	  revoInfo = PORT_New(caRevoInfo);
  1162 	  revoInfo->nickname = PORT_Strdup(optstate->value);
  1163 	  break;
  1164 	case 'C':
  1165 	  if (!revoInfo) { Usage(progName); exit(0); }
  1166 	  revoInfo->crlFilename = PORT_Strdup(optstate->value);
  1167 	  if (!caRevoInfos) {
  1168 	      PR_INIT_CLIST(&revoInfo->link);
  1169 	      caRevoInfos = revoInfo;
  1170 	  } else {
  1171 	      PR_APPEND_LINK(&revoInfo->link, &caRevoInfos->link);
  1173 	  revoInfo = NULL;
  1174 	  break;
  1176 	case 'O':
  1177 	  if (!PL_strcasecmp(optstate->value, "all")) {
  1178 	      ocspMethodsAllowed = ocspGetAndPost;
  1179 	  } else if (!PL_strcasecmp(optstate->value, "get")) {
  1180 	      ocspMethodsAllowed = ocspGetOnly;
  1181 	  } else if (!PL_strcasecmp(optstate->value, "post")) {
  1182 	      ocspMethodsAllowed = ocspPostOnly;
  1183 	  } else if (!PL_strcasecmp(optstate->value, "random")) {
  1184 	      ocspMethodsAllowed = ocspRandomGetFailure;
  1185 	  } else if (!PL_strcasecmp(optstate->value, "get-unknown")) {
  1186 	      ocspMethodsAllowed = ocspGetUnknown;
  1187 	  } else {
  1188 	      Usage(progName); exit(0);
  1190 	  break;
  1192 	case 'D': noDelay = PR_TRUE; break;
  1194 	case 'P': certPrefix = PORT_Strdup(optstate->value); break;
  1196         case 'b': bindOnly = PR_TRUE; break;
  1198 	case 'd': dir = optstate->value; break;
  1200 	case 'f':
  1201             pwdata.source = PW_FROMFILE;
  1202             pwdata.data = pwfile = PORT_Strdup(optstate->value);
  1203             break;
  1205         case 'h': Usage(progName); exit(0); break;
  1207 	case 'i': pidFile = optstate->value; break;
  1209 	case 'p': port = PORT_Atoi(optstate->value); break;
  1211 	case 't':
  1212 	    maxThreads = PORT_Atoi(optstate->value);
  1213 	    if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
  1214 	    if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
  1215 	    break;
  1217 	case 'v': verbose++; break;
  1219 	case 'w':
  1220             pwdata.source = PW_PLAINTEXT;
  1221             pwdata.data = passwd = PORT_Strdup(optstate->value);
  1222             break;
  1224 	default:
  1225 	case '?':
  1226 	    fprintf(stderr, "Unrecognized or bad option specified.\n");
  1227 	    fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1228 	    exit(4);
  1229 	    break;
  1232     PL_DestroyOptState(optstate);
  1233     if (status == PL_OPT_BAD) {
  1234 	fprintf(stderr, "Unrecognized or bad option specified.\n");
  1235 	fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1236 	exit(5);
  1238     if (!optionsFound) {
  1239 	Usage(progName);
  1240 	exit(51);
  1243     /* The -b (bindOnly) option is only used by the ssl.sh test
  1244      * script on Linux to determine whether a previous httpserv
  1245      * process has fully died and freed the port.  (Bug 129701)
  1246      */
  1247     if (bindOnly) {
  1248         listen_sock = getBoundListenSocket(port);
  1249         if (!listen_sock) {
  1250             exit(1);
  1252         if (listen_sock) {
  1253             PR_Close(listen_sock);
  1255         exit(0);
  1258     if (port == 0) {
  1259 	fprintf(stderr, "Required argument 'port' must be non-zero value\n");
  1260 	exit(7);
  1263     if (pidFile) {
  1264 	FILE *tmpfile=fopen(pidFile,"w+");
  1266 	if (tmpfile) {
  1267 	    fprintf(tmpfile,"%d",getpid());
  1268 	    fclose(tmpfile);
  1272     tmp = getenv("TMP");
  1273     if (!tmp)
  1274 	tmp = getenv("TMPDIR");
  1275     if (!tmp)
  1276 	tmp = getenv("TEMP");
  1277     /* we're an ordinary single process server. */
  1278     listen_sock = getBoundListenSocket(port);
  1279     prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
  1280     if (prStatus != PR_SUCCESS)
  1281         errExit("PR_SetFDInheritable");
  1283     lm = PR_NewLogModule("TestCase");
  1285     /* set our password function */
  1286     PK11_SetPasswordFunc(SECU_GetModulePassword);
  1288     if (provideOcsp) {
  1289 	/* Call the NSS initialization routines */
  1290 	rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB, NSS_INIT_READONLY);
  1291 	if (rv != SECSuccess) {
  1292 	    fputs("NSS_Init failed.\n", stderr);
  1293 		    exit(8);
  1296 	if (caRevoInfos) {
  1297 	  caRevoIter = &caRevoInfos->link;
  1298 	  do {
  1299 	      PRFileDesc *inFile;
  1300 	      int rv = SECFailure;
  1301 	      SECItem crlDER;
  1302 	      crlDER.data = NULL;
  1304 	      revoInfo = (caRevoInfo*)caRevoIter;
  1305 	      revoInfo->cert = CERT_FindCertByNickname(
  1306 		  CERT_GetDefaultCertDB(), revoInfo->nickname);
  1307 	      if (!revoInfo->cert) {
  1308 		  fprintf(stderr, "cannot find cert with nickname %s\n",
  1309 			  revoInfo->nickname);
  1310 		  exit(1);
  1312 	      inFile = PR_Open(revoInfo->crlFilename, PR_RDONLY, 0);
  1313 	      if (inFile) {
  1314 		rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
  1315 		PR_Close(inFile);
  1316 		inFile = NULL;
  1318 	      if (rv != SECSuccess) {
  1319 		  fprintf(stderr, "unable to read crl file %s\n",
  1320 			  revoInfo->crlFilename);
  1321 		  exit(1);
  1323 	      revoInfo->crl = 
  1324 		  CERT_DecodeDERCrlWithFlags(NULL, &crlDER, SEC_CRL_TYPE,
  1325 					     CRL_DECODE_DEFAULT_OPTIONS);
  1326 	      if (!revoInfo->crl) {
  1327 		  fprintf(stderr, "unable to decode crl file %s\n",
  1328 			  revoInfo->crlFilename);
  1329 		  exit(1);
  1331 	      if (CERT_CompareName(&revoInfo->crl->crl.name,
  1332 				   &revoInfo->cert->subject) != SECEqual) {
  1333 		  fprintf(stderr, "CRL %s doesn't match cert identified by preceding nickname %s\n",
  1334 			  revoInfo->crlFilename, revoInfo->nickname);
  1335 		  exit(1);
  1337 	      revoInfo->id = cert_CreateSelfCAID(revoInfo->cert, PR_Now());
  1338 	      caRevoIter = PR_NEXT_LINK(caRevoIter);
  1339 	  } while (caRevoIter != &caRevoInfos->link);
  1343 /* allocate the array of thread slots, and launch the worker threads. */
  1344     rv = launch_threads(&jobLoop, 0, 0, 0, useLocalThreads);
  1346     if (rv == SECSuccess) {
  1347 	server_main(listen_sock, 0, 0, 0,
  1348                     0);
  1351     VLOG(("httpserv: server_thread: exiting"));
  1353     if (provideOcsp) {
  1354 	if (caRevoInfos) {
  1355 	    PRCList *caRevoIter;
  1357 	    caRevoIter = &caRevoInfos->link;
  1358 	    do {
  1359 		caRevoInfo *revoInfo = (caRevoInfo*)caRevoIter;
  1360 		if (revoInfo->nickname)
  1361 		    PORT_Free(revoInfo->nickname);
  1362 		if (revoInfo->crlFilename)
  1363 		    PORT_Free(revoInfo->crlFilename);
  1364 		if (revoInfo->cert)
  1365 		    CERT_DestroyCertificate(revoInfo->cert);
  1366 		if (revoInfo->id)
  1367 		    CERT_DestroyOCSPCertID(revoInfo->id);
  1368 		if (revoInfo->crl)
  1369 		    SEC_DestroyCrl(revoInfo->crl);
  1371 		caRevoIter = PR_NEXT_LINK(caRevoIter);
  1372 	    } while (caRevoIter != &caRevoInfos->link);
  1375 	if (NSS_Shutdown() != SECSuccess) {
  1376 	    SECU_PrintError(progName, "NSS_Shutdown");
  1377 	    PR_Cleanup();
  1378 	    exit(1);
  1381     if (passwd) {
  1382         PORT_Free(passwd);
  1384     if (pwfile) {
  1385         PORT_Free(pwfile);
  1387     if (certPrefix && certPrefix != emptyString) {
  1388         PORT_Free(certPrefix);
  1390     PR_Cleanup();
  1391     printf("httpserv: normal termination\n");
  1392     return 0;

mercurial