Added tlspool_configvar() to libtlspool
[tlspool] / lib / libtlspool.c
index 1b96467..a57949d 100644 (file)
@@ -1,5 +1,7 @@
 /* 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
 
@@ -71,8 +69,12 @@ int tlspool_pid (char *opt_pidfile) {
        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);
@@ -110,8 +112,13 @@ pool_handle_t tlspool_open_poolhandle (char *path) {
                        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");
@@ -158,12 +165,7 @@ pool_handle_t tlspool_open_poolhandle (char *path) {
  */
 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) {
@@ -362,7 +364,7 @@ static int np_send_command(struct tlspool_command *cmd) {
 
        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;
        }
 
@@ -373,17 +375,12 @@ printf ("DEBUG: Write I/O pending\n");
        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 */
@@ -408,7 +405,6 @@ 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;
@@ -427,7 +423,7 @@ static void *master_thread (void *path) {
 #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
@@ -451,7 +447,7 @@ static void *master_thread (void *path) {
                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) {
@@ -518,7 +514,7 @@ printf ("DEBUG: path = %s\n", (char *) path);
 
                        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;
                        }
 
@@ -531,7 +527,7 @@ printf ("DEBUG: Read I/O pending\n");
                                _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;
@@ -574,7 +570,7 @@ printf ("DEBUG: Read %ld bytes from pipe\n", cbRead);
                                        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;
@@ -642,7 +638,7 @@ int tlspool_ping (pingpool_t *pingdata) {
 
        /* 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;
@@ -655,7 +651,7 @@ printf ("DEBUG: poolfd = %d\n", poolfd);
                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;
@@ -695,10 +691,15 @@ printf ("DEBUG: poolfd = %d\n", poolfd);
        }
 }
 
-#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
 
@@ -779,26 +780,24 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
                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 ();
@@ -807,6 +806,26 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
                * (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 =");
@@ -833,37 +852,17 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
                // 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, ...);
@@ -917,7 +916,7 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
                                /* 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
@@ -928,11 +927,7 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
 #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 */
@@ -961,36 +956,16 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
                                // 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, ...);
@@ -1042,7 +1017,7 @@ int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
        /* 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;
 }
@@ -1075,7 +1050,7 @@ int _tlspool_control_command (int cmdcode, uint8_t *ctlkey) {
                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;
@@ -1167,7 +1142,7 @@ int tlspool_prng (char *label, char *opt_ctxvalue,
        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) ||
@@ -1194,7 +1169,7 @@ int tlspool_prng (char *label, char *opt_ctxvalue,
                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;
@@ -1243,3 +1218,107 @@ if (np_send_command (&cmd) == -1) {
                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;
+}
+