/* tlspool/libtlspool.c -- Library function for starttls go-get-it */
+#include "whoami.h"
+#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <syslog.h>
#include <assert.h>
#include <stdint.h>
-#include <fcntl.h>
+#include <limits.h>
+#include <ctype.h>
#include <unistd.h>
#include <pthread.h>
-#include <io.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <tlspool/starttls.h>
+#include <tlspool/commands.h>
+
+#ifdef WINDOWS_PORT
+#include <winsock2.h>
+#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/resource.h>
+#endif
-#include <tlspool/starttls.h>
-#include <tlspool/commands.h>
+#if !defined(WINDOWS_PORT)
+#define closesocket(s) close(s)
+#endif
-#include <sys/cygwin.h>
+#ifdef WINDOWS_PORT
+#define PIPE_TIMEOUT 5000
+#define BUFSIZE 4096
+#define random rand
+#define srandom srand
+#define _tprintf printf
+#endif /* WINDOWS_PORT */
/* The master thread will run the receiving side of the socket that connects
* to the TLS Pool. The have_master_lock is used with _trylock() and will
static void *master_thread (void *path);
-static int poolfd = -1; /* Blocked retrieval with tlspool_socket() */
+static pool_handle_t poolfd = INVALID_POOL_HANDLE; /* Blocked retrieval with tlspool_socket() */
static pthread_cond_t updated_poolfd = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t prng_lock = PTHREAD_MUTEX_INITIALIZER;
-/*
- * Quick and dirty function to get the PID of the tlspool daemon
- */
-int tlspool_getpid () {
+/* Retrieve the process identity of the TLS Pool from the named file, or fall
+ * back on the default file if the name is set to NULL. Returns -1 on failure.
+ */
+int tlspool_pid (char *opt_pidfile) {
int fd;
+ char str_pid [256];
+ char *endptr;
+ size_t len;
+ unsigned long pid;
- if ((fd = open("/var/run/tlspool.pid", O_RDONLY)) != -1) {
- char str_pid[256];
-
- if (read(fd, str_pid, sizeof(str_pid)) != -1) {
- return atoi(str_pid);
+ if (opt_pidfile == NULL) {
+ opt_pidfile = tlspool_configvar (NULL, "daemon_pidfile");
+ }
+ if (opt_pidfile == NULL) {
+ opt_pidfile = TLSPOOL_DEFAULT_PIDFILE_PATH;
+ }
+ assert (opt_pidfile != NULL);
+ fd = open (opt_pidfile, O_RDONLY);
+ if (fd != -1) {
+ len = read (fd, str_pid, sizeof (str_pid) -1);
+ close (fd);
+ if ((len > 0) && (len < sizeof (str_pid))) {
+ str_pid [len] = '\0';
+ pid = strtoul (str_pid, &endptr, 10);
+ while ((endptr != NULL) && (isspace (*endptr))) {
+ endptr++;
+ }
+ if ((pid >= 0) && (pid <= INT_MAX) && (!*endptr)) {
+ return (int) pid;
+ }
}
}
return -1;
* on the poolfd. This is the process that actually contacts the TLS Pool
* and sets up the poolfd socket.
*/
-int tlspool_socket (char *path) {
- int poolfdsample = poolfd;
- if (poolfdsample < 0) {
+pool_handle_t tlspool_open_poolhandle (char *path) {
+ pool_handle_t poolfdsample = poolfd;
+ if (poolfdsample == INVALID_POOL_HANDLE) {
pthread_mutex_t local_cond_wait = PTHREAD_MUTEX_INITIALIZER;
//
// Now that we have established a (first) poolfd, start up
unsigned int seed;
pid_t me;
if (!path) {
+ path = tlspool_configvar (NULL, "socket_name");
+ }
+ if (!path) {
path = TLSPOOL_DEFAULT_SOCKET_PATH;
}
- if (strlen (path) + 1 > sizeof (((struct sockaddr_un *) NULL)->sun_path)) {
- syslog (LOG_ERR, "TLS Pool path name too long for UNIX domain socket");
- exit (1);
+ assert (path != NULL);
+ fprintf (stderr, "DEBUG: Opening TLS Pool on socket path %s\n", path);
+#ifndef WINDOWS_PORT
+ if (strlen(path) + 1 > sizeof(((struct sockaddr_un *) NULL)->sun_path)) {
+ syslog(LOG_ERR, "TLS Pool path name too long for UNIX domain socket");
+ exit(1);
}
- if (pthread_create (&thr, NULL, master_thread, (void *) path) != 0) {
- syslog (LOG_NOTICE, "Failed to create TLS Pool client master thread");
- pthread_mutex_unlock (&have_master_lock);
- close (poolfd);
- poolfd = -1;
- return -1;
+#endif
+ if (pthread_create(&thr, NULL, master_thread, (void *)path) != 0) {
+ syslog(LOG_NOTICE, "Failed to create TLS Pool client master thread");
+ pthread_mutex_unlock(&have_master_lock);
+ tlspool_close_poolhandle(poolfd);
+ poolfd = INVALID_POOL_HANDLE;
+ return INVALID_POOL_HANDLE;
}
pthread_detach (thr);
//
// shared mutex -- which is why we use a local mutex per
// thread: we don't need to wait for unique access.
assert (pthread_mutex_lock (&local_cond_wait) == 0);
- while (poolfdsample = poolfd, poolfdsample < 0) {
+ while (poolfdsample = poolfd, poolfdsample == INVALID_POOL_HANDLE) {
pthread_cond_wait (&updated_poolfd, &local_cond_wait);
}
pthread_mutex_unlock (&local_cond_wait);
* number of available file descriptors. Note: The result is cached, so
* don't use root to increase beyond max in setrlimit() after calling this.
*/
-int tlspool_simultaneous_starttls (void) {
+int tlspool_simultaneous_starttls(void) {
+#ifdef WINDOWS_PORT
+ return 512;
+#else /* WINDOWS_PORT */
static int simu = -1;
if (simu < 0) {
struct rlimit rlimit_nofile;
simu = rlimit_nofile.rlim_max / 2; // 2 FDs per STARTTLS
}
return simu;
+#endif /* WINDOWS_PORT */
}
struct registry_entry {
pthread_mutex_t *sig; /* Wait for master thread's recvmsg() */
struct tlspool_command *buf; /* Buffer to hold received command */
- int pfd; /* Client thread's assumed poolfd */
+ pool_handle_t pfd; /* Client thread's assumed poolfd */
};
static struct registry_entry **registry;
* is reset to -1.
*
* The return value is 0 on success, or -1 on failure; the most probable
- * cause for failure is
+ * cause for failure is
*/
static int registry_update (int *reqid, struct registry_entry *entry) {
static int simu = -1;
* Any outstanding registry entries will be sent an ERROR value at this
* time.
*/
-static void registry_flush (int poolfd) {
+static void registry_flush (pool_handle_t poolfd) {
int regid = tlspool_simultaneous_starttls ();
assert (pthread_mutex_lock (®istry_lock) == 0);
while (regid-- > 0) {
pthread_mutex_unlock (®istry_lock);
}
+#ifdef WINDOWS_PORT
+static pool_handle_t open_named_pipe (LPCTSTR lpszPipename)
+{
+ HANDLE hPipe;
+ //struct tlspool_command chBuf;
+ BOOL fSuccess = FALSE;
+ DWORD dwMode;
+
+ // Try to open a named pipe; wait for it, if necessary.
+
+ while (1)
+ {
+ hPipe = CreateFile(
+ lpszPipename, // pipe name
+ GENERIC_READ | // read and write access
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ FILE_FLAG_OVERLAPPED, // overlapped
+ NULL); // no template file
+
+ // Break if the pipe handle is valid.
+ if (hPipe != INVALID_POOL_HANDLE)
+ break;
+
+ // Exit if an error other than ERROR_PIPE_BUSY occurs.
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ _tprintf(TEXT("Could not open pipe. GLE=%d\n"), GetLastError());
+ return INVALID_POOL_HANDLE;
+ }
+
+ // All pipe instances are busy, so wait for 20 seconds.
+ if (!WaitNamedPipe(lpszPipename, 20000))
+ {
+ printf("Could not open pipe: 20 second wait timed out.");
+ return INVALID_POOL_HANDLE;
+ }
+ }
+ // The pipe connected; change to message-read mode.
+ dwMode = PIPE_READMODE_MESSAGE;
+ fSuccess = SetNamedPipeHandleState(
+ hPipe, // pipe handle
+ &dwMode, // new pipe mode
+ NULL, // don't set maximum bytes
+ NULL); // don't set maximum time
+ if (!fSuccess)
+ {
+ _tprintf(TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError());
+ return INVALID_POOL_HANDLE;
+ }
+ ULONG ServerProcessId;
+ if (GetNamedPipeServerProcessId(hPipe, &ServerProcessId)) {
+ printf("GetNamedPipeServerProcessId: ServerProcessId = %ld\n", ServerProcessId);
+ } else {
+ _tprintf(TEXT("GetNamedPipeServerProcessId failed. GLE=%d\n"), GetLastError());
+ }
+ return hPipe;
+}
+
+static int np_send_command(struct tlspool_command *cmd) {
+ DWORD cbToWrite, cbWritten;
+ OVERLAPPED overlapped;
+ BOOL fSuccess;
+
+ /* Send the request */
+ // Send a message to the pipe server.
+
+ cbToWrite = sizeof (struct tlspool_command);
+ _tprintf(TEXT("Sending %d byte cmd\n"), cbToWrite);
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ fSuccess = WriteFile(
+ poolfd, // pipe handle
+ cmd, // cmd message
+ cbToWrite, // cmd message length
+ NULL, // bytes written
+ &overlapped); // overlapped
+
+ if (!fSuccess && GetLastError() == ERROR_IO_PENDING )
+ {
+// printf ("DEBUG: Write I/O pending\n");
+ fSuccess = WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
+ }
+
+ if (fSuccess) {
+ fSuccess = GetOverlappedResult(poolfd, &overlapped, &cbWritten, TRUE);
+ }
+
+ if (!fSuccess)
+ {
+ _tprintf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError());
+ errno = EPIPE;
+ return -1;
+ } else {
+// printf ("DEBUG: Wrote %ld bytes to pipe\n", cbWritten);
+ }
+// printf("DEBUG: Message sent to server, receiving reply as follows:\n");
+ return 0;
+}
+#endif /* WINDOWS_PORT */
/* The master thread issues the recv() commands on the TLS Pool socket, and
* redistributes the result to the registry entries that are waiting for
* TLS Pool anew, using exponential back-off.
*/
static void *master_thread (void *path) {
+#ifndef WINDOWS_PORT
useconds_t usec;
struct sockaddr_un sun;
- struct tlspool_command cmd;
//NOT-USED// char anc [CMSG_SPACE(sizeof (int))];
struct iovec iov;
struct cmsghdr *cmsg;
struct msghdr mh = { 0 };
+#else
+ DWORD usec;
+#endif
+ struct tlspool_command cmd;
+ //NOT-USED// char anc [CMSG_SPACE(sizeof (int))];
struct registry_entry *entry;
+#ifdef WINDOWS_PORT
+ BOOL fSuccess = FALSE;
+ DWORD cbRead;
+#endif
+#ifndef WINDOWS_PORT
//
// Setup path information -- value and size were checked
- bzero (&sun, sizeof (sun));
+ memset (&sun, 0, sizeof (sun));
strcpy (sun.sun_path, (char *) path);
sun.sun_family = AF_UNIX;
+#endif
+
//
// Service forever
while (1) {
//
// If any old socket clients persist, tell them that the
// TLS Pool has been disconnected.
- if (poolfd >= 0) {
- int poolfdcopy = poolfd;
+ if (poolfd != INVALID_POOL_HANDLE) {
+ pool_handle_t poolfdcopy = poolfd;
// printf ("DEBUG: Removing old poolfd %d\n", poolfd);
- poolfd = -1;
- registry_flush (-1);
- close (poolfdcopy);
+ poolfd = INVALID_POOL_HANDLE;
+ registry_flush (INVALID_POOL_HANDLE);
+ tlspool_close_poolhandle (poolfdcopy);
}
//
// First, connect to the TLS Pool; upon failure, retry
// with 1s, 2s, 4s, 8s, 16s, 32s, 32s, 32s, ... intervals.
usec = 1000000;
- while (poolfd < 0) {
- int newpoolfd = socket (AF_UNIX, SOCK_STREAM, 0);
- if (newpoolfd != -1) {
+ while (poolfd == INVALID_POOL_HANDLE) {
+#ifdef WINDOWS_PORT
+// printf ("DEBUG: path = %s\n", (char *) path);
+ pool_handle_t newpoolfd = open_named_pipe ((LPCTSTR) path);
+// printf ("DEBUG: newpoolfd = %d\n", newpoolfd);
+ if (newpoolfd != INVALID_POOL_HANDLE) {
+ poolfd = newpoolfd;
+ }
+#else
+ pool_handle_t newpoolfd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (newpoolfd != INVALID_POOL_HANDLE) {
if (connect (newpoolfd, (struct sockaddr *) &sun, SUN_LEN (&sun)) == 0) {
// printf ("DEBUG: Succeeded connect() to TLS Pool\n");
poolfd = newpoolfd;
} else {
- close (newpoolfd);
- newpoolfd = -1;
+ tlspool_close_poolhandle (newpoolfd);
+ newpoolfd = INVALID_POOL_HANDLE;
}
}
// printf ("DEBUG: Trying new poolfd %d for path %s\n", poolfd, sun.sun_path);
+#endif
//
// Signal a newly set poolfd value to all waiting.
// Note that we do not need to claim a mutex first;
// printf ("DEBUG: Signalled slave threads with poolfd %d\n", poolfd);
//
// Wait before repeating, with exponential back-off
- if (poolfd < 0) {
- usleep (usec);
+ if (poolfd == INVALID_POOL_HANDLE) {
+#ifdef WINDOWS_PORT
+ Sleep(usec / 1000);
+#else
+ usleep(usec);
+#endif
usec <<= 1;
if (usec > 32000000) {
usec = 32000000;
// back up to the re-connection logic.
while (1) {
int retval;
+#ifdef WINDOWS_PORT
+ OVERLAPPED overlapped;
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ // Read from the pipe.
+ fSuccess = ReadFile(
+ poolfd, // pipe handle
+ &cmd, // buffer to receive reply
+ sizeof (cmd), // size of buffer
+ NULL, // number of bytes read
+ &overlapped); // not overlapped
+
+ if (!fSuccess && GetLastError() == ERROR_IO_PENDING )
+ {
+// printf ("DEBUG: Read I/O pending\n");
+ fSuccess = WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
+ }
+
+ if (fSuccess) {
+ fSuccess = GetOverlappedResult(poolfd, &overlapped, &cbRead, TRUE);
+ }
+
+ if (!fSuccess)
+ {
+ _tprintf(TEXT("ReadFile from pipe failed. GLE=%d\n"), GetLastError());
+ retval = -1;
+ } else {
+// printf ("DEBUG: Read %ld bytes from pipe\n", cbRead);
+ }
+#else
iov.iov_base = &cmd;
iov.iov_len = sizeof (cmd);
mh.msg_iov = &iov;
// printf ("DEBUG: recvmsg() returned -1 due to: %s\n", strerror (errno));
break;
}
+#endif /* WINDOWS_PORT */
//
// Determine where to post the received message
entry = registry [cmd.pio_reqid];
cmd.pio_cmd = PIOC_ERROR_V2;
cmd.pio_data.pioc_error.tlserrno = EPIPE;
strncpy (cmd.pio_data.pioc_error.message, "Client prematurely left TLS Pool negotiations", sizeof (cmd.pio_data.pioc_error.message));
+#ifdef WINDOWS_PORT
+ np_send_command (&cmd);
+#else
sendmsg (poolfd, &mh, MSG_NOSIGNAL);
+#endif
// Ignore errors
-printf ("DEBUG: Sent PIOC_ERROR_V2 as callback to TLS Pool\n");
+// printf ("DEBUG: Sent PIOC_ERROR_V2 as callback to TLS Pool\n");
}
// Do not attempt delivery
continue;
* doing that yet. Then, wait until a message has been received.
*/
static void registry_recvmsg (struct registry_entry *entry) {
- static int lastpoolfd = -1;
+ static pool_handle_t lastpoolfd = INVALID_POOL_HANDLE;
//
// Detect poolfd socket change for potential dangling recipients
if (entry->pfd != lastpoolfd) {
- lastpoolfd = tlspool_socket (NULL);
- if ((entry->pfd != lastpoolfd) && (lastpoolfd != -1)) {
+ lastpoolfd = tlspool_open_poolhandle (NULL);
+ if ((entry->pfd != lastpoolfd) && (lastpoolfd != INVALID_POOL_HANDLE)) {
// Signal PIOC_ERROR to outdated recipients.
// (That will include the current recipient.)
registry_flush (lastpoolfd);
}
//
// Now wait for the registered command structure to be filled
- // by the master thread. Note that the call to tlspool_socket()
+ // by the master thread. Note that the call to tlspool_open_poolhandle()
// above is made when this function is first called, and that
// routine ensures running of the master thread.
assert (pthread_mutex_lock (entry->sig) == 0);
pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
int entry_reqid = -1;
- int poolfd = -1;
- struct iovec iov;
- struct msghdr mh = { 0 };
+ pool_handle_t poolfd = INVALID_POOL_HANDLE;
/* Prepare command structure */
- poolfd = tlspool_socket (NULL);
- if (poolfd == -1) {
+ poolfd = tlspool_open_poolhandle (NULL);
+// printf ("DEBUG: poolfd = %d\n", poolfd);
+ if (poolfd == INVALID_POOL_HANDLE) {
errno = ENODEV;
return -1;
}
errno = EBUSY;
return -1;
}
- bzero (&cmd, sizeof (cmd)); /* Do not leak old stack info */
+ memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
cmd.pio_reqid = entry_reqid;
cmd.pio_cbid = 0;
cmd.pio_cmd = PIOC_PING_V2;
memcpy (&cmd.pio_data.pioc_ping, pingdata, sizeof (struct pioc_ping));
-
+#ifdef WINDOWS_PORT
+ if (np_send_command (&cmd) == -1) {
+ // errno inherited from np_send_command ()
+ registry_update (&entry_reqid, NULL);
+ return -1;
+ }
+#else
/* Send the request */
- iov.iov_base = &cmd;
- iov.iov_len = sizeof (cmd);
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- if (sendmsg (poolfd, &mh, MSG_NOSIGNAL) == -1) {
+ if (send (poolfd, &cmd, sizeof (cmd), MSG_NOSIGNAL) == -1) {
// Let SIGPIPE be reported as EPIPE
registry_update (&entry_reqid, NULL);
// errno inherited from sendmsg()
return -1;
}
-
+#endif
/* Await response and process it */
registry_recvmsg (®ent);
registry_update (&entry_reqid, NULL);
}
}
-#define SIO_ADDRESS_LIST_QUERY 0x48000016
-
-int is_sock(SOCKET winsock) {
- int rc;
- char buffer[1024];
-// PSOCKET_ADDRESS_LIST address_list = (PSOCKET_ADDRESS_LIST) buffer;
- DWORD cbOutBuffer = sizeof(buffer); // size of output buffer
- DWORD cbBytesReturned; // number of bytes returned
-
- rc = WSAIoctl(
- winsock, // descriptor identifying a socket
- SIO_ADDRESS_LIST_QUERY, // dwIoControlCode
- NULL, // lpvInBuffer
- 0, // cbInBuffer
- (LPVOID) buffer, // output buffer
- cbOutBuffer, // size of output buffer
- &cbBytesReturned, // number of bytes returned
- NULL, // OVERLAPPED structure
- NULL // completion routine
- );
-
- printf("is_sock winsock = %d, rc = %d\n", winsock, rc);
- return rc == 0;
-// printf("iAddressCount = %d", address_list->iAddressCount);
+#if defined(WINDOWS_PORT)
+static int socket_dup_protocol_info(int fd, int pid, LPWSAPROTOCOL_INFOW lpProtocolInfo)
+{
+ if (WSADuplicateSocketW((SOCKET)fd, pid, lpProtocolInfo) == SOCKET_ERROR) {
+ errno = EPIPE;
+ return -1;
+ } else {
+ return 0;
+ }
}
+#endif
/* The library function for starttls, which is normally called through one
* of the two inline variations below, which start client and server sides.
pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
int entry_reqid = -1;
- int poolfd = -1;
+ pool_handle_t poolfd = INVALID_POOL_HANDLE;
int plainfd = -1;
int sentfd = -1;
- char anc [CMSG_SPACE(sizeof (int))];
+#ifndef WINDOWS_PORT
struct iovec iov;
struct cmsghdr *cmsg;
struct msghdr mh = { 0 };
+ char anc[CMSG_SPACE(sizeof(int))];
+#endif
int processing;
int renegotiate = 0 != (tlsdata->flags & PIOF_STARTTLS_RENEGOTIATE);
/* Prepare command structure */
- poolfd = tlspool_socket (NULL);
- if (poolfd == -1) {
- close (cryptfd);
+ poolfd = tlspool_open_poolhandle (NULL);
+ if (poolfd == INVALID_POOL_HANDLE) {
+ closesocket(cryptfd);
errno = ENODEV;
return -1;
}
pthread_mutex_lock (&recvwait); // Will await unlock by master
/* Determine the request ID */
if (registry_update (&entry_reqid, ®ent) != 0) {
- close (cryptfd);
+ closesocket(cryptfd);
errno = EBUSY;
return -1;
}
- bzero (&cmd, sizeof (cmd)); /* Do not leak old stack info */
+ memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
cmd.pio_reqid = entry_reqid;
cmd.pio_cbid = 0;
cmd.pio_cmd = PIOC_STARTTLS_V2;
memcpy (&cmd.pio_data.pioc_starttls, tlsdata, sizeof (struct pioc_starttls));
-#if RAND_MAX < 0xfffff
-# error "Failure on assumption of 16 bits of random material per random() call"
-#endif
-
#if TLSPOOL_CTLKEYLEN != 16
# error "Failure on assumption of 16 bytes per ctlkey"
#endif
if (!renegotiate) {
assert (pthread_mutex_lock (&prng_lock) == 0);
+#if RAND_MAX >= 0xffffffff
+ * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
+ * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
+ * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 8] = random ();
+ * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
+#elif RAND_MAX >= 0xffff
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 2] = random ();
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [10] = random ();
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
* (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [14] = random ();
+#elif RAND_MAX >= 0xff
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 1] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 2] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 3] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 5] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 6] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 7] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 8] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 9] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [10] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [11] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [13] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [14] = random ();
+ * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [15] = random ();
+#else
+# error "Unsuitable random() function due to RAND_MAX value < 0xff"
+#endif
pthread_mutex_unlock (&prng_lock);
}
// printf ("DEBUG: ctlkey =");
// printf ("\n");
/* Send the request */
+#ifndef WINDOWS_PORT
iov.iov_base = &cmd;
- iov.iov_len = sizeof (cmd);
+ iov.iov_len = sizeof(cmd);
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
+#endif
if (!renegotiate) {
-#ifndef WINDOWS
+#ifndef WINDOWS_PORT
mh.msg_control = anc;
mh.msg_controllen = sizeof (anc);
cmsg = CMSG_FIRSTHDR (&mh);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
- * (int *) CMSG_DATA (cmsg) = cryptfd; /* cannot close it yet */
- cmsg->cmsg_len = CMSG_LEN (sizeof (int));
-#else /* ifdef WINDOWS */
+ *(int *)CMSG_DATA(cmsg) = cryptfd; /* cannot close it yet */
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+#else /* WINDOWS_PORT */
// cmd was already set to 0, including ancilary data simulation
if (1 /*is_sock(wsock)*/) {
// Send a socket
- int pid = tlspool_getpid();
+ LONG pid;
+
+ GetNamedPipeServerProcessId(poolfd, &pid);
cmd.pio_ancil_type = ANCIL_TYPE_SOCKET;
- printf("pid = %d, cryptfd = %d\n", pid, cryptfd);
- if (cygwin_socket_dup_protocol_info (cryptfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
- printf("cygwin_socket_dup_protocol_info error\n");
+ printf("DEBUG: pid = %d, cryptfd = %d\n", pid, cryptfd);
+ if (socket_dup_protocol_info(cryptfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
+ // printf("DEBUG: cygwin_socket_dup_protocol_info error\n");
// Let SIGPIPE be reported as EPIPE
- close (cryptfd);
+ closesocket(cryptfd);
registry_update (&entry_reqid, NULL);
- // errno inherited from sendmsg()
+ // errno inherited from socket_dup_protocol_info()
return -1;
}
//... (..., &cmd.pio_ancil_data.pioa_socket, ...);
cmd.pio_ancil_type = ANCIL_TYPE_FILEHANDLE;
//... (..., &cmd.pio_ancil_data.pioa_filehandle, ...);
}
-#endif /* WINDOWS */
+#endif /* WINDOWS_PORT */
+ }
+#ifdef WINDOWS_PORT
+ if (np_send_command (&cmd) == -1) {
+ close (cryptfd);
+ registry_update (&entry_reqid, NULL);
+ // errno inherited from np_send_command ()
+ return -1;
}
+#else
if (sendmsg (poolfd, &mh, MSG_NOSIGNAL) == -1) {
// Let SIGPIPE be reported as EPIPE
close (cryptfd);
// errno inherited from sendmsg()
return -1;
}
+#endif /* WINDOWS_PORT */
sentfd = cryptfd; /* Close anytime after response and before fn end */
/* Handle responses until success or error */
//NOTUSED// mh.msg_controllen = sizeof (anc);
registry_recvmsg (®ent);
if (sentfd >= 0) {
- close (sentfd);
+ closesocket(sentfd);
}
sentfd = -1;
switch (cmd.pio_cmd) {
/* default namedconnect() implementation */
plainfd = * (int *) privdata;
if ((plainfd < 0) && (cmd.pio_cmd == PIOC_PLAINTEXT_CONNECT_V2)) {
- int soxx [2];
+#if !defined(WINDOWS_PORT)
+ int soxx[2];
+#else
+ // https://github.com/ncm/selectable-socketpair
+ extern int dumb_socketpair(SOCKET socks[2], int make_overlapped);
+ SOCKET soxx[2];
+#endif
//TODO// Setup for TCP, UDP, SCTP
- if (socketpair (AF_UNIX, SOCK_STREAM, 0, soxx) == 0) {
- printf("HFM: socketpair succeeded\n");
+#ifndef WINDOWS_PORT
+ if (socketpair (AF_UNIX, SOCK_SEQPACKET, 0, soxx) == 0) {
+#else /* WINDOWS_PORT */
+ if (dumb_socketpair(soxx, 1) == 0) {
+#endif /* WINDOWS_PORT */
+ // printf("DEBUG: socketpair succeeded\n");
/* Socketpair created */
plainfd = soxx [0];
* (int *) privdata = soxx [1];
} else {
/* Socketpair failed */
- printf("HFM: socketpair failed\n");
+ // printf("DEBUG: socketpair failed\n");
cmd.pio_cmd = PIOC_ERROR_V2;
cmd.pio_data.pioc_error.tlserrno = errno;
plainfd = -1;
}
/* We may now have a value to send in plainfd */
if (plainfd >= 0) {
-#ifndef WINDOWS
+#ifndef WINDOWS_PORT
mh.msg_control = anc;
mh.msg_controllen = sizeof (anc);
cmsg = CMSG_FIRSTHDR (&mh);
cmsg->cmsg_type = SCM_RIGHTS;
* (int *) CMSG_DATA (cmsg) = plainfd;
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
-#else /* ifdef WINDOWS */
- SOCKET wsock = (SOCKET) get_osfhandle (plainfd);
-
+#else /* ifdef WINDOWS_PORT */
// cmd was already set to 0, including ancilary data simulation
if (1 /*is_sock(wsock)*/) {
// Send a socket
- int pid = tlspool_getpid();
+ ULONG pid;
+ GetNamedPipeServerProcessId(poolfd, &pid);
cmd.pio_ancil_type = ANCIL_TYPE_SOCKET;
- printf("pid = %d, plainfd = %d\n", pid, plainfd);
- if (cygwin_socket_dup_protocol_info (plainfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
- printf("cygwin_socket_dup_protocol_info error\n");
+ // printf("DEBUG: pid = %d, plainfd = %d\n", pid, plainfd);
+ if (socket_dup_protocol_info(plainfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
+ // printf("DEBUG: cygwin_socket_dup_protocol_info error\n");
// Let SIGPIPE be reported as EPIPE
- close (plainfd);
+ closesocket(plainfd);
registry_update (&entry_reqid, NULL);
- // errno inherited from sendmsg()
+ // errno inherited from socket_dup_protocol_info()
return -1;
}
//... (..., &cmd.pio_ancil_data.pioa_socket, ...);
cmd.pio_ancil_type = ANCIL_TYPE_FILEHANDLE;
//... (..., &cmd.pio_ancil_data.pioa_filehandle, ...);
}
-#endif /* WINDOWS */
+#endif /* WINDOWS_PORT */
}
+
/* Now supply plainfd in the callback response */
sentfd = plainfd;
+#ifdef WINDOWS_PORT
+ if (np_send_command (&cmd) == -1) {
+ if (sentfd >= 0) {
+ closesocket(sentfd);
+ sentfd = -1;
+ }
+ registry_update (&entry_reqid, NULL);
+ // errno inherited from np_send_command()
+ return -1;
+ }
+#else
if (sendmsg (poolfd, &mh, MSG_NOSIGNAL) == -1) {
// Let SIGPIPE be reported as EPIPE
if (sentfd >= 0) {
// errno inherited from sendmsg()
return -1;
}
+#endif /* WINDOWS_PORT */
break; // Loop around and try again
case PIOC_STARTTLS_V2:
/* Wheee!!! we're done */
/* Close the now-duplicated or now-erradicated plaintext fd */
memcpy (tlsdata, &cmd.pio_data.pioc_starttls, sizeof (struct pioc_starttls));
-printf ("DEBUG: Returning control key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", tlsdata->ctlkey [0], tlsdata->ctlkey [1], tlsdata->ctlkey [2], tlsdata->ctlkey [3], tlsdata->ctlkey [4], tlsdata->ctlkey [5], tlsdata->ctlkey [6], tlsdata->ctlkey [7], tlsdata->ctlkey [8], tlsdata->ctlkey [9], tlsdata->ctlkey [10], tlsdata->ctlkey [11], tlsdata->ctlkey [12], tlsdata->ctlkey [13], tlsdata->ctlkey [14], tlsdata->ctlkey [15]);
+// printf ("DEBUG: Returning control key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", tlsdata->ctlkey [0], tlsdata->ctlkey [1], tlsdata->ctlkey [2], tlsdata->ctlkey [3], tlsdata->ctlkey [4], tlsdata->ctlkey [5], tlsdata->ctlkey [6], tlsdata->ctlkey [7], tlsdata->ctlkey [8], tlsdata->ctlkey [9], tlsdata->ctlkey [10], tlsdata->ctlkey [11], tlsdata->ctlkey [12], tlsdata->ctlkey [13], tlsdata->ctlkey [14], tlsdata->ctlkey [15]);
registry_update (&entry_reqid, NULL);
return 0;
}
int retval;
/* Prepare command structure */
- poolfd = tlspool_socket (NULL);
- if (poolfd == -1) {
+ poolfd = tlspool_open_poolhandle (NULL);
+ if (poolfd == INVALID_POOL_HANDLE) {
errno = ENODEV;
return -1;
}
errno = EBUSY;
return -1;
}
- bzero (&cmd, sizeof (cmd)); /* Do not leak old stack info */
+ memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
cmd.pio_reqid = entry_reqid;
cmd.pio_cbid = 0;
cmd.pio_cmd = cmdcode;
memcpy (&cmd.pio_data.pioc_control.ctlkey, ctlkey, TLSPOOL_CTLKEYLEN);
// printf ("DEBUG: Using control key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", cmd.pio_data.pioc_control.ctlkey [0], cmd.pio_data.pioc_control.ctlkey [1], cmd.pio_data.pioc_control.ctlkey [2], cmd.pio_data.pioc_control.ctlkey [3], cmd.pio_data.pioc_control.ctlkey [4], cmd.pio_data.pioc_control.ctlkey [5], cmd.pio_data.pioc_control.ctlkey [6], cmd.pio_data.pioc_control.ctlkey [7], cmd.pio_data.pioc_control.ctlkey [8], cmd.pio_data.pioc_control.ctlkey [9], cmd.pio_data.pioc_control.ctlkey [10], cmd.pio_data.pioc_control.ctlkey [11], cmd.pio_data.pioc_control.ctlkey [12], cmd.pio_data.pioc_control.ctlkey [13], cmd.pio_data.pioc_control.ctlkey [14], cmd.pio_data.pioc_control.ctlkey [15]);
+#ifdef WINDOWS_PORT
+ if (np_send_command (&cmd) == -1) {
+ registry_update (&entry_reqid, NULL);
+ // errno inherited from np_send_command ()
+ return -1;
+ }
+#else
/* Send the request */
if (send (poolfd, &cmd, sizeof (cmd), MSG_NOSIGNAL) == -1) {
// Let SIGPIPE be reported as EPIPE
// errno inherited from send()
return -1;
}
-
+#endif
/* Receive the response */
registry_recvmsg (®ent);
switch (cmd.pio_cmd) {
* purposes, such as finding the same session key for both sides deriving from
* prior key negotiation; the protection of a ctlkey for such applications is
* important.
- *
+ *
* The inputs to this function must adhere to the following restrictions:
* - label must not be a NULL pointer, but opt_ctxvalue may be set to NULL
* to bypass the use of a context value. Note that passing an empty string
pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
int entry_reqid = -1;
- int poolfd = -1;
- struct iovec iov;
- struct msghdr mh = { 0 };
-
- bzero (prng_buf, prng_len);
+ pool_handle_t poolfd = INVALID_POOL_HANDLE;
+ memset (prng_buf, 0, prng_len);
/* Sanity checks */
if ((prng_len > TLSPOOL_PRNGBUFLEN) ||
errno = EINVAL;
return -1;
}
-
+
/* Prepare command structure */
- poolfd = tlspool_socket (NULL);
- if (poolfd == -1) {
+ poolfd = tlspool_open_poolhandle (NULL);
+ if (poolfd == INVALID_POOL_HANDLE) {
errno = ENODEV;
return -1;
}
errno = EBUSY;
return -1;
}
- bzero (&cmd, sizeof (cmd)); /* Do not leak old stack info */
+ memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
cmd.pio_reqid = entry_reqid;
cmd.pio_cbid = 0;
cmd.pio_cmd = PIOC_PRNG_V2;
cmd.pio_data.pioc_prng.in2_len = -1;
}
+#ifdef WINDOWS_PORT
+if (np_send_command (&cmd) == -1) {
+ // errno inherited from np_send_command ()
+ registry_update (&entry_reqid, NULL);
+ return -1;
+}
+#else
/* Send the request */
- iov.iov_base = &cmd;
- iov.iov_len = sizeof (cmd);
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- if (sendmsg (poolfd, &mh, MSG_NOSIGNAL) == -1) {
+ if (send (poolfd, &cmd, sizeof (cmd), MSG_NOSIGNAL) == -1) {
// Let SIGPIPE be reported as EPIPE
registry_update (&entry_reqid, NULL);
// errno inherited from sendmsg()
return -1;
}
-
+#endif
/* Await response and process it */
registry_recvmsg (®ent);
registry_update (&entry_reqid, NULL);
}
}
+
+/* Fetch a configuration variable value from the configuration file. This is not
+ * an efficient procedure, at best suited for startup of tools or daemons; it
+ * will iterate over the config file until it reads the desired value. The value
+ * returned is allocated and should be freed by the caller using free().
+ *
+ * When cfgfile is NULL, the environment variable TLSPOOL_CONFIGFILE is
+ * tried first, followed by the default setting from the macro
+ * TLSPOOL_DEFAULT_CONFIG_PATH as defined in <tlspool/starttls.h>.
+ *
+ * The value returned is NULL when the variable is not found, including when this
+ * is due to errors such as not being able to open the file.
+ */
+char *tlspool_configvar (char *cfgfile, char *varname) {
+ FILE *cf;
+ char line [514];
+ int linelen;
+ int eof = 0;
+ char *here;
+ struct cfgopt *curopt;
+ int found;
+ char *retval = NULL;
+
+ if (cfgfile == NULL) {
+ cfgfile = getenv ("TLSPOOL_CFGFILE");
+ }
+ if (cfgfile == NULL) {
+ cfgfile = TLSPOOL_DEFAULT_CONFIG_PATH;
+ }
+
+ assert (cfgfile != NULL);
+ assert (varname != NULL);
+
+ cf = fopen (cfgfile, "r");
+ if (cf == NULL) {
+ perror ("Failed to open configuration file");
+ goto cleanup;
+ }
+
+ while (!eof) {
+ if (!fgets (line, sizeof (line)-1, cf)) {
+ if (feof (cf)) {
+ eof = 1;
+ continue;
+ } else {
+ perror ("Error while reading configuration file");
+ exit (1);
+ }
+ }
+ linelen = strlen (line);
+ if (linelen == 0) {
+ eof = 1;
+ continue;
+ }
+ if (line [linelen-1] == (char) EOF) {
+ linelen--;
+ eof = 1;
+ }
+ if (line [linelen-1] != '\n') {
+ fprintf (stderr, "Configuration line too long\n");
+ goto cleanup;
+ }
+ line [--linelen] = 0;
+ if (linelen == 0) {
+ continue;
+ }
+ if (line [0] == '#') {
+ continue;
+ }
+ here = line;
+ while ((*here) && isspace (*here)) {
+ here++;
+ }
+ if (!*here) {
+ continue;
+ }
+ if (here != line) {
+ fprintf (stderr, "Configuration line starts with whitespace:\n%s\n", line);
+ goto cleanup;
+ }
+ while ((*here) && (*here != ' ')) {
+ here++;
+ }
+ if (!*here) {
+ fprintf (stderr, "Configuration line misses space after keyword:\n%s\n", line);
+ goto cleanup;
+ }
+ *here++ = '\0';
+ if (strcmp (varname, line) == 0) {
+ // Success! We set the return value and end the loop
+ retval = here;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (cf != NULL) {
+ fclose (cf);
+ cf = NULL;
+ }
+ return retval;
+}
+