$OpenBSD: patch-redir_c,v 1.1 2021/01/08 13:32:57 sthen Exp $

Add SSL/auth code
https://github.com/Openwsman/wsmancli/issues/10#issuecomment-751253133

Index: redir.c
--- redir.c.orig
+++ redir.c
@@ -29,9 +29,12 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/time.h>
 
 #include "tcp.h"
+#include "ssl.h"
 #include "redir.h"
+#include "auth.h"
 
 static const char *state_name[] = {
     [ REDIR_NONE      ] = "NONE",
@@ -100,7 +103,7 @@ static ssize_t redir_write(struct redir *r, const char
 
     if (r->trace)
 	hexdump("out", buf, count);
-    rc = write(r->sock, buf, count);
+    rc = sslwrite(r->ctx, buf, count);
     if (-1 == rc)
 	snprintf(r->err, sizeof(r->err), "write(socket): %s", strerror(errno));
     return rc;
@@ -142,8 +145,11 @@ const char *redir_state_desc(enum redir_state state)
 int redir_connect(struct redir *r)
 {
     static unsigned char *defport = "16994";
+    static unsigned char *sslport = "16995";
     struct addrinfo ai;
 
+    if (r->cacert)
+	defport = sslport;
     memset(&ai, 0, sizeof(ai));
     ai.ai_socktype = SOCK_STREAM;
     ai.ai_family = PF_UNSPEC;
@@ -151,6 +157,11 @@ int redir_connect(struct redir *r)
     redir_state(r, REDIR_CONNECT);
     r->sock = tcp_connect(&ai, NULL, NULL, r->host,
 			  strlen(r->port) ? r->port : defport);
+    r->ctx = sslinit(r->sock, r->cacert);
+    if(r->ctx == NULL) {
+	close(r->sock);
+	r->sock = -1;
+    }
     if (-1 == r->sock) {
         redir_state(r, REDIR_ERROR);
         /* FIXME: better error message */
@@ -179,11 +190,13 @@ int redir_stop(struct redir *r)
 
     redir_state(r, REDIR_CLOSED);
     redir_write(r, request, sizeof(request));
+    sslexit(r->ctx);
+    r->ctx = NULL;
     close(r->sock);
     return 0;
 }
 
-int redir_auth(struct redir *r)
+static int redir_auth_old(struct redir *r)
 {
     int ulen = strlen(r->user);
     int plen = strlen(r->pass);
@@ -205,6 +218,79 @@ int redir_auth(struct redir *r)
     return rc;
 }
 
+static int io(void *parm, unsigned char *data, int len, int mode)
+{
+    int rc;
+    struct redir *r;
+    struct timeval tv;
+    fd_set set;
+
+    switch(mode)
+    {
+    case READ:
+	r = (struct redir *)parm;
+	while (len) {
+	    FD_ZERO(&set);
+	    FD_SET(r->sock,&set);
+	    if (!sslready(r->ctx)) {
+		tv.tv_sec  = HEARTBEAT_INTERVAL * 4 / 1000;
+		tv.tv_usec = 0;
+		switch (select(r->sock+1,&set,NULL,NULL,&tv)) {
+		case -1:
+		    perror("select");
+		    return -1;
+		case 0:
+		    fprintf(stderr,"select: timeout\n");
+		    return -1;
+		}
+	    }
+	    rc = sslread(r->ctx, data, len);
+	    switch (rc) {
+	    case -1:
+		fprintf(stderr, "read(socket): %s", strerror(errno));
+		return -1;
+	    case 0:
+		fprintf(stderr, "EOF from socket");
+		return -1;
+	    default:
+		if (r->trace)
+		    hexdump("in ", data, rc);
+		data += rc;
+		len -= rc;
+	    }
+	}
+	return 0;
+
+    case WRITE:
+	r = (struct redir *)parm;
+	if (redir_write(r, data, len) != len)
+	    return -1;
+	return 0;
+
+    case RANDOM:
+	gettimeofday(&tv, NULL);
+	if (sizeof(tv) <= len)
+	    memcpy(data, &tv, sizeof(tv));
+	else
+	    memcpy(data, &tv, len);
+	return 0;
+    }
+
+    return -1;
+}
+
+int redir_auth(struct redir *r)
+{
+    int rc;
+
+    if (r->legacy)
+	return redir_auth_old(r);
+
+    redir_state(r, REDIR_AUTH);
+    rc = authenticate(0, r->user, r->pass, io, r);
+    return rc;
+}
+
 int redir_sol_start(struct redir *r)
 {
     unsigned char request[START_SOL_REDIRECTION_LENGTH] = {
@@ -280,7 +366,7 @@ int redir_sol_recv(struct redir *r)
 	   ready yet, but should be here Real Soon Now. */
 	flags = fcntl(r->sock,F_GETFL);
 	fcntl(r->sock,F_SETFL, flags & (~O_NONBLOCK));
-	count = read(r->sock, msg, count);
+	count = sslread(r->ctx, msg, count);
 	fcntl(r->sock,F_SETFL, flags);
 
 	switch (count) {
@@ -309,12 +395,13 @@ int redir_data(struct redir *r)
 {
     int rc, bshift;
 
+repeat:
     if (r->trace) {
 	fprintf(stderr, "in --\n");
 	if (r->blen)
 	    fprintf(stderr, "in : already have %d\n", r->blen);
     }
-    rc = read(r->sock, r->buf + r->blen, sizeof(r->buf) - r->blen);
+    rc = sslread(r->ctx, r->buf + r->blen, sizeof(r->buf) - r->blen);
     switch (rc) {
     case -1:
 	snprintf(r->err, sizeof(r->err), "read(socket): %s", strerror(errno));
@@ -456,18 +543,24 @@ int redir_data(struct redir *r)
 	memmove(r->buf, r->buf + bshift, r->blen - bshift);
 	r->blen -= bshift;
     }
+    if (r->ctx && sslready(r->ctx))
+	goto repeat;
     return 0;
 
 again:
     /* need more data, jump back into poll/select loop */
     if (r->trace)
 	fprintf(stderr, "in : need more data\n");
+    if (sslready(r->ctx))
+	goto repeat;
     return 0;
 
 err:
     if (r->trace)
 	fprintf(stderr, "in : ERROR (%s)\n", r->err);
     redir_state(r, REDIR_ERROR);
+    sslexit(r->ctx);
+    r->ctx = NULL;
     close(r->sock);
     return -1;
 }
