/* tlspool/libtlspool.c -- Library function for starttls go-get-it */
+#include "whoami.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/resource.h>
#endif
-#ifdef __CYGWIN__
-#define WEOF ((wint_t)(0xFFFF))
-#endif
-
-#if !defined(WINDOWS_PORT) || defined(__CYGWIN__)
+#if !defined(WINDOWS_PORT)
#define closesocket(s) close(s)
#endif
unsigned long 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);
unsigned int seed;
pid_t me;
if (!path) {
+ path = tlspool_configvar (NULL, "socket_name");
+ }
+ if (!path) {
path = TLSPOOL_DEFAULT_SOCKET_PATH;
}
+ 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");
*/
int tlspool_simultaneous_starttls(void) {
#ifdef WINDOWS_PORT
-#ifdef _MSC_VER
-#pragma message("TODO")
-#else
-#warning TODO
-#endif
- return 512;
+ return 512;
#else /* WINDOWS_PORT */
static int simu = -1;
if (simu < 0) {
if (!fSuccess && GetLastError() == ERROR_IO_PENDING )
{
-printf ("DEBUG: Write I/O pending\n");
+// printf ("DEBUG: Write I/O pending\n");
fSuccess = WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
}
if (!fSuccess)
{
_tprintf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError());
-#ifdef _MSC_VER
-#pragma message("better errno")
-#else
-#warning better errno
-#endif
- errno = ENOSYS;
+ errno = EPIPE;
return -1;
} else {
-printf ("DEBUG: Wrote %ld bytes to pipe\n", cbWritten);
+// printf ("DEBUG: Wrote %ld bytes to pipe\n", cbWritten);
}
-printf("DEBUG: Message sent to server, receiving reply as follows:\n");
+// printf("DEBUG: Message sent to server, receiving reply as follows:\n");
return 0;
}
#endif /* WINDOWS_PORT */
#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;
#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
usec = 1000000;
while (poolfd == INVALID_POOL_HANDLE) {
#ifdef WINDOWS_PORT
-printf ("DEBUG: path = %s\n", (char *) path);
+// 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) {
if (!fSuccess && GetLastError() == ERROR_IO_PENDING )
{
-printf ("DEBUG: Read I/O pending\n");
+// printf ("DEBUG: Read I/O pending\n");
fSuccess = WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
}
_tprintf(TEXT("ReadFile from pipe failed. GLE=%d\n"), GetLastError());
retval = -1;
} else {
-printf ("DEBUG: Read %ld bytes from pipe\n", cbRead);
+// printf ("DEBUG: Read %ld bytes from pipe\n", cbRead);
}
#else
iov.iov_base = &cmd;
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;
/* Prepare command structure */
poolfd = tlspool_open_poolhandle (NULL);
-printf ("DEBUG: poolfd = %d\n", poolfd);
+// 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;
}
}
-#if defined(WINDOWS_PORT) && !defined(__CYGWIN__)
+#if defined(WINDOWS_PORT)
static int socket_dup_protocol_info(int fd, int pid, LPWSAPROTOCOL_INFOW lpProtocolInfo)
{
- return WSADuplicateSocketW((SOCKET)fd, pid, lpProtocolInfo) == SOCKET_ERROR ? -1 : 0;
+ if (WSADuplicateSocketW((SOCKET)fd, pid, lpProtocolInfo) == SOCKET_ERROR) {
+ errno = EPIPE;
+ return -1;
+ } else {
+ return 0;
+ }
}
#endif
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
-#ifdef _MSC_VER
-#pragma message("Failure on assumption of 16 bits of random material per random() call")
-#else
-#warning "Failure on assumption of 16 bits of random material per random() call"
-#endif
-#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 =");
// cmd was already set to 0, including ancilary data simulation
if (1 /*is_sock(wsock)*/) {
// Send a socket
-#ifdef __CYGWIN__
- int pid = tlspool_pid(NULL);
- if (pid == -1) {
- close (cryptfd);
- registry_update (&entry_reqid, NULL);
- // errno inherited from tlspool_pid()
- return -1;
- }
-#else
LONG pid;
GetNamedPipeServerProcessId(poolfd, &pid);
-#endif
cmd.pio_ancil_type = ANCIL_TYPE_SOCKET;
printf("DEBUG: pid = %d, cryptfd = %d\n", pid, cryptfd);
-#ifdef __CYGWIN__
- if (cygwin_socket_dup_protocol_info(cryptfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
-#else /* __CYGWIN__ */
if (socket_dup_protocol_info(cryptfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
-#endif /* __CYGWIN__ */
-
-#ifdef _MSC_VER
-#pragma message("set errno")
-#else
-#warning set errno
-#endif
// printf("DEBUG: cygwin_socket_dup_protocol_info error\n");
// Let SIGPIPE be reported as EPIPE
- closesocket(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, ...);
/* default namedconnect() implementation */
plainfd = * (int *) privdata;
if ((plainfd < 0) && (cmd.pio_cmd == PIOC_PLAINTEXT_CONNECT_V2)) {
-#if !defined(WINDOWS_PORT) || defined(__CYGWIN__)
+#if !defined(WINDOWS_PORT)
int soxx[2];
#else
// https://github.com/ncm/selectable-socketpair
#ifndef WINDOWS_PORT
if (socketpair (AF_UNIX, SOCK_SEQPACKET, 0, soxx) == 0) {
#else /* WINDOWS_PORT */
-#ifdef __CYGWIN__
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, soxx) == 0) {
-#else /* __CYGWIN__ */
if (dumb_socketpair(soxx, 1) == 0) {
-#endif /* __CYGWIN__ */
#endif /* WINDOWS_PORT */
// printf("DEBUG: socketpair succeeded\n");
/* Socketpair created */
// cmd was already set to 0, including ancilary data simulation
if (1 /*is_sock(wsock)*/) {
// Send a socket
-#ifdef __CYGWIN__
- int pid = tlsp
- if (pid == -1) {
- closesocket(plainfd);
- registry_update (&entry_reqid, NULL);
- // errno inherited from tlspool_pid()
- return -1;
- }
-#else
ULONG pid;
GetNamedPipeServerProcessId(poolfd, &pid);
-#endif
cmd.pio_ancil_type = ANCIL_TYPE_SOCKET;
- printf("DEBUG: pid = %d, plainfd = %d\n", pid, plainfd);
-#ifdef __CYGWIN__
- if (cygwin_socket_dup_protocol_info(plainfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
-#else /* __CYGWIN__ */
+ // printf("DEBUG: pid = %d, plainfd = %d\n", pid, plainfd);
if (socket_dup_protocol_info(plainfd, pid, &cmd.pio_ancil_data.pioa_socket) == -1) {
-#endif /* __CYGWIN__ */
-
-#ifdef _MSC_VER
-#pragma message("set errno")
-#else
-#warning set errno
-#endif
// printf("DEBUG: cygwin_socket_dup_protocol_info error\n");
// Let SIGPIPE be reported as EPIPE
- closesocket(plainfd);
+ closesocket(plainfd);
registry_update (&entry_reqid, NULL);
- // errno inherited from cygwin_socket_dup_protocol_info()
+ // errno inherited from socket_dup_protocol_info()
return -1;
}
//... (..., &cmd.pio_ancil_data.pioa_socket, ...);
/* 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;
}
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;
struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
int entry_reqid = -1;
pool_handle_t poolfd = INVALID_POOL_HANDLE;
- bzero (prng_buf, prng_len);
+ memset (prng_buf, 0, prng_len);
/* Sanity checks */
if ((prng_len > TLSPOOL_PRNGBUFLEN) ||
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;
return -1;
}
}
+
+
+/* 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;
+}
+