Milán Major

netscape-revival

1 branch
Code

security/lib/ssl/sslsock.c

#include "xp.h"
#include "cert.h"
#include "ssl.h"
#include "sslimpl.h"
#include "nspr.h"

extern int XP_ERRNO_EINVAL;
extern int XP_ERRNO_EBADF;
extern int SEC_ERROR_INVALID_ARGS;

SSLSocketOps ssl_default_ops = {
    ssl_DefConnect,
    ssl_DefAccept,
    ssl_DefBind,
    ssl_DefListen,
    ssl_DefShutdown,
    ssl_DefIoctl,
    ssl_DefClose,
    ssl_DefRecv,
    ssl_DefSend,
    ssl_DefRead,
    ssl_DefWrite,
    ssl_DefGetpeername,
    ssl_DefGetsockname,
    ssl_DefGetsockopt,
    ssl_DefSetsockopt,
    ssl_DefImportFd,
#ifdef XP_UNIX
    ssl_DefDup2,
#endif
};

SSLSocketOps ssl_socks_ops = {
    ssl_SocksConnect,
    ssl_SocksAccept,
    ssl_SocksBind,
    ssl_SocksListen,
    ssl_DefShutdown,
    ssl_DefIoctl,
    ssl_DefClose,
    ssl_SocksRecv,
    ssl_SocksSend,
    ssl_SocksRead,
    ssl_SocksWrite,
    ssl_DefGetpeername,
    ssl_SocksGetsockname,
    ssl_DefGetsockopt,
    ssl_DefSetsockopt,
    ssl_DefImportFd,
#ifdef XP_UNIX
    ssl_DefDup2,
#endif
};

#ifndef NADA_VERSION
SSLSocketOps ssl_secure_ops = {
    ssl_SecureConnect,
    ssl_SecureAccept,
    ssl_DefBind,
    ssl_DefListen,
    ssl_DefShutdown,
    ssl_DefIoctl,
    ssl_SecureClose,
    ssl_SecureRecv,
    ssl_SecureSend,
    ssl_SecureRead,
    ssl_SecureWrite,
    ssl_DefGetpeername,
    ssl_DefGetsockname,
    ssl_DefGetsockopt,
    ssl_DefSetsockopt,
    ssl_SecureImportFd,
#ifdef XP_UNIX
    ssl_DefDup2,
#endif
};

SSLSocketOps ssl_secure_socks_ops = {
    ssl_SecureSocksConnect,
    ssl_SecureSocksAccept,
    ssl_SocksBind,
    ssl_SocksListen,
    ssl_DefShutdown,
    ssl_DefIoctl,
    ssl_SecureClose,
    ssl_SecureRecv,
    ssl_SecureSend,
    ssl_SecureRead,
    ssl_SecureWrite,
    ssl_DefGetpeername,
    ssl_SocksGetsockname,
    ssl_DefGetsockopt,
    ssl_DefSetsockopt,
    ssl_SecureImportFd,
#ifdef XP_UNIX
    ssl_DefDup2,
#endif
};
#endif

/*
** default settings for socket enables
*/
static struct {
    unsigned char useSecurity;
    unsigned char useSocks;
    unsigned char requestCertificate;
    unsigned char asyncWrites;
    unsigned char delayedHandshake;
    unsigned char handshakeAsClient;
    unsigned char handshakeAsServer;
    unsigned char enableSSL2;
    unsigned char enableSSL3;
    unsigned char noCache;
} ssl_defaults = {
    0, /* useSecurity */
    0, /* useSocks */
    0, /* requestCertificate */
    0, /* asyncWrites */
    0, /* delayedHandshake */
    0, /* handshakeAsClient */
    0, /* handshakeAsServer */
    1, /* enableSSL2 */
    1, /* enableSSL3 */
    0, /* noCache */
};

char ssl_debug, ssl_trace;
int ssl_extended_error;
SSLSessionIDLookupFunc ssl_sid_lookup;
SSLSessionIDCacheFunc ssl_sid_cache;
SSLSessionIDUncacheFunc ssl_sid_uncache;
SSLAcceptFunc ssl_accept_func = ssl_UnderlyingAccept;

/************************************************************************/

static SSLSocket *fdhash[16];
#define FDHASH(fd) ((fd) & 15)
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
#include "nspr/prmon.h"
static int fdhashLockInit = 0;
static PRMonitor *fdhashLock;
#endif

/*
 * The locking (and unlocking) of the fdhash is done to protect the linked
 * lists of SSLSocket structures hanging off of each of the fdhash buckets.
 * This protection is only needed in a multi-threaded world which is
 * typically only in the server.
 *
 * To avoid this cost, an extra table is made for "small" values of file
 * descriptors (which tend to be small ints). Since the entries can be
 * added or removed atomically, no locking will be needed.
 */

#if defined(SERVER_BUILD)
#define SMALL_FD 2500		/* 25 would be useful for testing purposes */
#else
#define SMALL_FD 256
#endif
static SSLSocket *fdTable[SMALL_FD];

/*
** Lookup a socket structure given a file descriptor.
*/
SSLSocket *ssl_FindSocket(int fd)
{
    SSLSocket *ss;

    if (fd < SMALL_FD) {
	ss = fdTable[fd];
    } else {
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PORT_Assert(fdhashLockInit);
	PR_EnterMonitor(fdhashLock);
#endif
	ss = fdhash[FDHASH(fd)];
	while (ss && (ss->fd != (NETSOCK)fd))
	    ss = ss->next;
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PR_ExitMonitor(fdhashLock);
#endif
    }
    if (ss == NULL)
	PORT_SetError(XP_ERRNO_EBADF);
    return ss;
}

static SSLSocket *
ssl_FindSocketAndDelink(int fd)
{
    SSLSocket *ss, **ssp;

    if (fd < SMALL_FD) {
	ss = fdTable[fd];
	fdTable[fd] = NULL;
    } else {
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PORT_Assert(fdhashLockInit);
	PR_EnterMonitor(fdhashLock);
#endif
	ssp = &fdhash[FDHASH(fd)];
	while (((ss = *ssp) != NULL) && (ss->fd != (NETSOCK)fd)) {
	    ssp = &ss->next;
	}
	if (ss != NULL)
	    *ssp = ss->next;      /* Remove from hash chain */
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PR_ExitMonitor(fdhashLock);
#endif
    }
    return ss;
}

static void
ssl_RememberSocket(SSLSocket *ss, int fd)
{
    PORT_Assert(ss != NULL);
    if (fd < SMALL_FD) {
	PORT_Assert(fdTable[fd] == NULL);
	fdTable[fd] = ss;
    } else {
	int fdh = FDHASH(fd);
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PR_EnterMonitor(fdhashLock);
#endif
	ss->next = fdhash[fdh];
	fdhash[fdh] = ss;
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
	PR_ExitMonitor(fdhashLock);
#endif
    }
}

/*
** Create a newsocket structure for a file descriptor.
*/
SSLSocket *ssl_NewSocket(int fd)
{
    SSLSocket *ss;
#ifdef XP_UNIX
    static int firsttime = 1;
    if (firsttime) {
	firsttime = 0;
#ifdef DEBUG
	{
	    char *ev = getenv("SSLDEBUG");
	    if (ev && ev[0]) {
		ssl_debug = atoi(ev);
		XP_TRACE(("SSL: debugging set to %d", ssl_debug));
	    }
	}
#endif
#ifdef TRACE
	{
	    char *ev = getenv("SSLTRACE");
	    if (ev && ev[0]) {
		ssl_trace = atoi(ev);
		XP_TRACE(("SSL: tracing set to %d", ssl_trace));
	    }
	}
#endif
    }
#endif

    /*
    ** Fix up case where socket was left open without calling SSL_Close.
    ** Scan hash chains for fd and if we find a matching socket, destroy
    ** it by calling it's close proc. Step on the fd field so that the
    ** close proc won't actually close the fd!
    */

    ss = ssl_FindSocket(fd);
    if (ss) {
	(void) ssl_FindSocketAndDelink(fd);
	ssl_FreeSocket(ss);
    }

    /* Make a new socket and get it ready */
    ss = (SSLSocket*) PORT_ZAlloc(sizeof(SSLSocket));
    if (ss) {
	ss->fd = fd;
	ss->ops = &ssl_default_ops;
	ss->useSecurity = ssl_defaults.useSecurity;
	ss->useSocks = ssl_defaults.useSocks;
	ss->requestCertificate = ssl_defaults.requestCertificate;
	ss->asyncWrites = ssl_defaults.asyncWrites;
	ss->delayedHandshake = ssl_defaults.delayedHandshake;
	ss->handshakeAsClient = ssl_defaults.handshakeAsClient;
	ss->handshakeAsServer = ssl_defaults.handshakeAsServer;
	ss->enableSSL2 = ssl_defaults.enableSSL2;
	ss->enableSSL3 = ssl_defaults.enableSSL3;
	ss->peer = 0;
	ss->port = 0;
	ss->noCache = ssl_defaults.noCache;
	ss->peerID = NULL;
	ssl_RememberSocket(ss, fd);
#if defined(XP_UNIX) && !defined(SERVER_BUILD) && !defined(NSPR20)
	PR_SetPollHook(fd, SSL_DataPending);
#endif
    }
    return ss;
}

/*
 * SSL_ReplaceSocket is badly named. What it really does is change the FD
 * in the socket structure. This means the SSLSocket* should be moved
 * from the old slot (whether in the small table or in a linked list in
 * the cache) to the new place.
 */
#ifdef XP_WIN32
int SSL_ReplaceSocket(int OldFd, int NewFd)
{
    SSLSocket *ss, **ssp;
    int hashValue;

    if (OldFd == NewFd) return NewFd;

    ss = ssl_FindSocketAndDelink(OldFd);
    if (ss == NULL) {
	PORT_SetError(XP_ERRNO_EBADF);
	return -1;
    }

    closesocket(ss->fd);
    ss->fd = NewFd;

    ssl_RememberSocket(ss, NewFd);

    return NewFd;
}
#endif /* XP_WIN32 */

SSLSocket *ssl_DupSocket(SSLSocket *os, int newfd)
{
    SSLSocket *ss;
    int rv;

    /*
     * XXX PK 13 Mar 96 -- This seems bogus. The socket is put into the
     * table before it is fully initialized.
     */
    ss = ssl_NewSocket(newfd);
    if (ss) {
	ss->useSocks = os->useSocks;
	ss->useSecurity = os->useSecurity;
	ss->requestPassword = os->requestPassword;
	ss->requestCertificate = os->requestCertificate;
	ss->delayedHandshake = os->delayedHandshake;
	ss->handshakeAsClient = os->handshakeAsClient;
	ss->handshakeAsServer = os->handshakeAsServer;
	ss->enableSSL3 = os->enableSSL3;
	ss->enableSSL2 = os->enableSSL2;
	ss->noCache = os->noCache;
	if (os->peerID == NULL) {
	    ss->peerID = NULL;
	} else {
	    ss->peerID = PORT_Strdup(os->peerID);
	}
	ss->ops = os->ops;
	ss->peer = os->peer;
	ss->port = os->port;
#ifndef NADA_VERSION
	if (ss->useSecurity) {
	    /* Create security data */
	    rv = ssl_CopySecurityInfo(ss, os);
	    if (rv) {
		goto losage;
	    }
	}
#endif
	if (ss->useSocks) {
	    /* Create security data */
	    rv = ssl_CopySocksInfo(ss, os);
	    if (rv) {
		goto losage;
	    }
	}
    }
    return ss;

  losage:
    /*
     * XXX PK 13 Mar 96 -- The allocated storage is not freed. The now
     * partially initalized structure is in the cache where some innocent
     * might find it.
     */
    return 0;
}

/*
 * free an SSLSocket struct, and all the stuff that hangs off of it
 */
void
ssl_FreeSocket(SSLSocket *ss)
{
    /* if a dialog is pending, then just mark for later freeing */
    if ( ss->dialogPending ) {
	ss->beenFreed = PR_TRUE;
	return;
    }
    
    /* Free up socket */
    ssl_DestroySocksInfo(ss->socks);
#ifndef NADA_VERSION
    ssl_DestroySecurityInfo(ss->sec);
    ssl3_DestroySSL3Info(ss->ssl3);
#endif
    PORT_FreeBlock(ss->saveBuf.buf);
    if (ss->gather) {
	ssl_DestroyGather(ss->gather);
    }
    if (ss->peerID != NULL)
	PORT_Free(ss->peerID);

    PORT_Free(ss);
    return;
}

int ssl_DefClose(SSLSocket *ss)
{
    SSLSocket *found;
    int fd, rv;

    fd = ss->fd;
    found = ssl_FindSocketAndDelink(fd);
    
#if defined(XP_UNIX) && !defined(SERVER_BUILD) && !defined(NSPR20)
    PR_SetPollHook(fd, NULL);
#endif

    ssl_FreeSocket(ss);
    rv = XP_SOCK_CLOSE(fd);
    if (rv < 0) {
	PORT_SetError(XP_SOCK_ERRNO);
    }
    SSL_TRC(5, ("%d: SSL[%d]: closing, rv=%d errno=%d",
		SSL_GETPID(), fd, rv, PORT_GetError()));
    return rv;
}

/************************************************************************/


int SSL_Import(int fd)
{
    SSLSocket *ss;

#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
    PORT_Assert(fdhashLockInit); /* failure means SEC_Init not called */
#endif
    ss = ssl_FindSocket(fd);
    if (ss) {
	/* Already been done... */
	PORT_SetError(XP_ERRNO_EINVAL);
	return -1;
    }
    ss = ssl_NewSocket(fd);
    if (!ss) {
	return -1;
    }
    return 0;
}


int SSL_Socket(int domain, int type, int protocol)
{
    SSLSocket *ss;
    int fd;

#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
    PORT_Assert(fdhashLockInit); /* failure means SEC_Init not called */
#endif

    /* Sorry, only stream based sockets work here */
    if (type != SOCK_STREAM) {
	PORT_SetError(XP_ERRNO_EINVAL);
	return -1;
    }

    fd = XP_SOCK_SOCKET(domain, type, protocol);
    if (fd == SOCKET_INVALID) {
	PORT_SetError(XP_SOCK_ERRNO);
	return fd;
    }

    ss = ssl_NewSocket(fd);
    if (!ss) {
	XP_SOCK_CLOSE(fd);
	SSL_DBG(("%d: SSL[%d]: unable to make socket object",
		 SSL_GETPID(), fd));
	return -1;
    }
    SSL_TRC(5, ("%d: SSL[%d]: new socket", SSL_GETPID(), fd));
    return fd;
}

static int PrepareSocket(SSLSocket *ss)
{
    unsigned char ix;
    int rv;

    ix = 0;
    if (ss->useSocks) {
	ix |= 1;
	rv = ssl_CreateSocksInfo(ss);
	if (rv) {
	    return rv;
	}
    }
#ifndef NADA_VERSION
    if (ss->useSecurity) {
	ix |= 2;
	rv = ssl_CreateSecurityInfo(ss);
	if (rv) {
	    return rv;
	}
    }
#endif

    switch (ix) {
      case 0:
	ss->ops = &ssl_default_ops;
	break;
      case 1:
	ss->ops = &ssl_socks_ops;
	break;
#ifndef NADA_VERSION
      case 2:
	ss->ops = &ssl_secure_ops;
	break;
      case 3:
	ss->ops = &ssl_secure_socks_ops;
	break;
#endif
    }
    return 0;
}

int SSL_Enable(int s, int which, int on)
{
    SSLSocket *ss;
    int rv;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), s));
	PORT_SetError(XP_ERRNO_EBADF);
	return -1;
    }

    rv = 0;
    switch (which) {
      case SSL_SOCKS:
	ss->useSocks = on ? 1 : 0;
	rv = PrepareSocket(ss);
	break;

#ifndef NADA_VERSION
      case SSL_SECURITY:
	ss->useSecurity = on ? 1 : 0;
	rv = PrepareSocket(ss);
	break;

      case SSL_REQUEST_CERTIFICATE:
	ss->requestCertificate = on ? 1 : 0;
	break;
#endif
      case SSL_ASYNC_WRITES:
	ss->asyncWrites = on ? 1 : 0;
	break;

      case SSL_DELAYED_HANDSHAKE:
	ss->delayedHandshake = on ? 1 : 0;
	break;

      case SSL_HANDSHAKE_AS_CLIENT:
	if ( ss->handshakeAsServer && on ) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return -1;
	}
	ss->handshakeAsClient = on ? 1 : 0;
	break;

      case SSL_HANDSHAKE_AS_SERVER:
	if ( ss->handshakeAsClient && on ) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return -1;
	}
	ss->handshakeAsServer = on ? 1 : 0;
	break;

      case SSL_ENABLE_SSL3:
	ss->enableSSL3 = on ? 1 : 0;
	break;

      case SSL_ENABLE_SSL2:
	ss->enableSSL2 = on ? 1 : 0;
	break;

      case SSL_NO_CACHE:
	ss->noCache = on ? 1 : 0;
	break;
	
      default:
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return -1;
    }
    return rv;
}

int SSL_EnableDefault(int which, int on)
{
    switch (which) {
      case SSL_SOCKS:
	ssl_defaults.useSocks = on ? 1 : 0;
	break;

#ifndef NADA_VERSION
      case SSL_SECURITY:
	ssl_defaults.useSecurity = on ? 1 : 0;
	break;

      case SSL_REQUEST_CERTIFICATE:
	ssl_defaults.requestCertificate = on ? 1 : 0;
	break;
#endif
      case SSL_ASYNC_WRITES:
	ssl_defaults.asyncWrites = on ? 1 : 0;
	break;

      case SSL_DELAYED_HANDSHAKE:
	ssl_defaults.delayedHandshake = on ? 1 : 0;
	break;

      case SSL_HANDSHAKE_AS_CLIENT:
	if ( ssl_defaults.handshakeAsServer && on ) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return -1;
	}
	ssl_defaults.handshakeAsClient = on ? 1 : 0;
	break;

      case SSL_HANDSHAKE_AS_SERVER:
	if ( ssl_defaults.handshakeAsClient && on ) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return -1;
	}
	ssl_defaults.handshakeAsServer = on ? 1 : 0;
	break;

      case SSL_ENABLE_SSL3:
	ssl_defaults.enableSSL3 = on ? 1 : 0;
	break;

      case SSL_ENABLE_SSL2:
	ssl_defaults.enableSSL2 = on ? 1 : 0;
	break;

      case SSL_NO_CACHE:
	ssl_defaults.noCache = on ? 1 : 0;
	break;

      default:
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return -1;
    }
    return 0;
}

void SSL_AcceptHook(SSLAcceptFunc func)
{
    ssl_accept_func = func;
}

/************************************************************************/

#ifdef XP_UNIX
int SSL_Dup2(int oldfd, int newfd)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(oldfd);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in dup2", SSL_GETPID(), oldfd));
	return -1;
    }
    return (*ss->ops->dup2)(ss, newfd);
}
#endif

int SSL_Ioctl(int s, int tag, void *result)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in ioctl", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->ioctl)(ss, tag, result);
}

int SSL_Accept(int s, void *sockaddr, int *namelen)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in accept", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->accept)(ss, sockaddr, namelen);
}

int SSL_ImportFd(int s, int fd)
{
    SSLSocket *ss;

#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
    PORT_Assert(fdhashLockInit); /* failure means SEC_Init not called */
#endif
    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in importfd", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->importfd)(ss, fd);
}

int SSL_Connect(int s, const void *sockaddr, int namelen)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in connect", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->connect)(ss, sockaddr, namelen);
}

int SSL_Bind(int s, const void *addr, int addrlen)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in bind", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->bind)(ss, addr, addrlen);
}

int SSL_Listen(int s, int backlog)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in listen", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->listen)(ss, backlog);
}

int SSL_Shutdown(int s, int how)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in shutdown", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->shutdown)(ss, how);
}

int SSL_Close(int s)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in close", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->close)(ss);
}

int SSL_Recv(int s, void *buf, int len, int flags)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in recv", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->recv)(ss, buf, len, flags);
}

int SSL_Send(int s, const void *buf, int len, int flags)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in send", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->send)(ss, buf, len, flags);
}

int SSL_Read(int s, void *buf, int len)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in read", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->read)(ss, buf, len);
}

int SSL_Write(int s, const void *buf, int len)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in write", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->write)(ss, buf, len);
}

int SSL_GetPeerName(int s, void *addr, int *addrlenp)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in getpeername", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->getpeername)(ss, addr, addrlenp);
}

int SSL_GetSockName(int s, void *name, int *namelenp)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->getsockname)(ss, name, namelenp);
}

int SSL_GetSockOpt(int s, int level, int optname, void *optval,
		  int *optlen)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in getsockopt", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->getsockopt)(ss, level, optname, optval, optlen);
}

int SSL_SetSockOpt(int s, int level, int optname, const void *optval,
		  int optlen)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in setsockopt", SSL_GETPID(), s));
	return -1;
    }
    return (*ss->ops->setsockopt)(ss, level, optname, optval, optlen);
}

void SSL_InitHashLock(void)
{
#if defined(SERVER_BUILD) && defined(USE_NSPR_MT)
    if (!fdhashLockInit) {
        fdhashLock = PR_NewMonitor();
	fdhashLockInit = 1;
    }
#endif
}

int
SSL_SetSockPeerID(int s, char *peerID)
{
    SSLSocket *ss;

    ss = ssl_FindSocket(s);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCacheIndex",
		 SSL_GETPID(), s));
	return -1;
    }

    ss->peerID = PORT_Strdup(peerID);
    return 0;
}