>From 1638b90baf391ee1db9b88eb9ba96f5125be3d59 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Mon, 13 Feb 2012 09:07:14 -0500
Subject: [PATCH] SSH: Continue connecting to SSH server even when SSSD is not
 running in sss_ssh_knownhostsproxy

Additionally, don't drop the connection when the
sss_ssh_knownhostsproxy process receives a signal.

https://fedorahosted.org/sssd/ticket/1179
https://fedorahosted.org/sssd/ticket/1184
---
 src/sss_client/ssh/sss_ssh_knownhostsproxy.c |  182 ++++++++++++++------------
 1 files changed, 97 insertions(+), 85 deletions(-)

diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
index b95dbe8..686c65e 100644
--- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
+++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
@@ -41,26 +41,67 @@
 
 #define BUFFER_SIZE 8192
 
-/* run proxy command */
-static int run_proxy(char **args)
+static void
+update_known_hosts(TALLOC_CTX *mem_ctx,
+                   const char *file,
+                   const char *req_host,
+                   const char *host)
 {
+    struct sss_ssh_pubkey *pubkeys;
+    size_t num_pubkeys, i;
+    FILE *f;
+    char *repr;
     int ret;
 
-    execv(args[0], (char * const *)args);
+    /* look up public keys */
+    ret = sss_ssh_get_pubkeys(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS, host,
+                              &pubkeys, &num_pubkeys);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("sss_ssh_get_pubkeys failed() (%d): %s\n", ret, strerror(ret)));
+        ERROR("Error looking up public keys\n");
+        goto done;
+    }
 
-    ret = errno;
-    DEBUG(SSSDBG_OP_FAILURE, ("execv() failed (%d): %s\n",
-            ret, strerror(ret)));
-    ERROR("Failed to execute proxy command\n");
+    /* write known_hosts file */
+    /* FIXME: Do not overwrite the file, handle concurrent access */
+    f = fopen(file, "w");
+    if (!f) {
+        ret = errno;
+        DEBUG(SSSDBG_OP_FAILURE, ("fopen() failed (%d): %s\n",
+                ret, strerror(ret)));
+        ERROR("Can't open known hosts file\n");
+        goto done;
+    }
+
+    fprintf(f,
+            "# Generated by sss_ssh_knownhostsproxy. Please do not modify.\n");
 
-    return EXIT_FAILURE;
+    for (i = 0; i < num_pubkeys; i++) {
+        ret = sss_ssh_format_pubkey(mem_ctx, &pubkeys[i],
+                                    SSS_SSH_FORMAT_OPENSSH, &repr);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                    ("sss_ssh_format_pubkey() failed (%d): %s\n",
+                     ret, strerror(ret)));
+            continue;
+        }
+
+        fprintf(f, "%s %s\n", req_host, repr);
+    }
+
+done:
+    if (f) fclose(f);
 }
 
-/* connect to server */
-static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
+/* connect to server using socket */
+static int
+connect_socket(int af,
+               struct sockaddr *addr,
+               size_t addr_len)
 {
     int flags;
-    int sock;
+    int sock = -1;
     fd_set fds;
     char buffer[BUFFER_SIZE];
     ssize_t rd_len, wr_len, wr_offs;
@@ -72,7 +113,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         ret = errno;
         DEBUG(SSSDBG_OP_FAILURE, ("fcntl() failed (%d): %s\n",
                 ret, strerror(ret)));
-        return EXIT_FAILURE;
+        goto done;
     }
 
     ret = fcntl(0, F_SETFL, flags | O_NONBLOCK);
@@ -80,7 +121,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         ret = errno;
         DEBUG(SSSDBG_OP_FAILURE, ("fcntl() failed (%d): %s\n",
                 ret, strerror(ret)));
-        return EXIT_FAILURE;
+        goto done;
     }
 
     /* create socket */
@@ -90,7 +131,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         DEBUG(SSSDBG_OP_FAILURE, ("socket() failed (%d): %s\n",
                 ret, strerror(ret)));
         ERROR("Failed to open a socket\n");
-        return EXIT_FAILURE;
+        goto done;
     }
 
     /* connect to the server */
@@ -100,8 +141,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         DEBUG(SSSDBG_OP_FAILURE, ("connect() failed (%d): %s\n",
                 ret, strerror(ret)));
         ERROR("Failed to connect to the server\n");
-        close(sock);
-        return EXIT_FAILURE;
+        goto done;
     }
 
     /* set O_NONBLOCK on the socket */
@@ -110,8 +150,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         ret = errno;
         DEBUG(SSSDBG_OP_FAILURE, ("fcntl() failed (%d): %s\n",
                 ret, strerror(ret)));
-        close(sock);
-        return EXIT_FAILURE;
+        goto done;
     }
 
     ret = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
@@ -119,8 +158,7 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         ret = errno;
         DEBUG(SSSDBG_OP_FAILURE, ("fcntl() failed (%d): %s\n",
                 ret, strerror(ret)));
-        close(sock);
-        return EXIT_FAILURE;
+        goto done;
     }
 
     while (1) {
@@ -136,43 +174,40 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
             ret = errno;
             DEBUG(SSSDBG_OP_FAILURE, ("select() failed (%d): %s\n",
                     ret, strerror(ret)));
-            close(sock);
-            return EXIT_FAILURE;
+            goto done;
         }
 
         /* read from standard input & write to socket */
         if (FD_ISSET(0, &fds)) {
             rd_len = read(0, buffer, BUFFER_SIZE);
             if (rd_len == -1) {
-                if (errno == EAGAIN) {
+                if (errno == EAGAIN || errno == EINTR) {
                     continue;
                 }
 
                 ret = errno;
                 DEBUG(SSSDBG_OP_FAILURE, ("read() failed (%d): %s\n",
                         ret, strerror(ret)));
-                close(sock);
-                return EXIT_FAILURE;
+                goto done;
             }
 
             wr_offs = 0;
             do {
                 wr_len = send(sock, buffer+wr_offs, rd_len-wr_offs, 0);
                 if (wr_len == -1) {
-                    if (errno == EAGAIN) {
+                    if (errno == EAGAIN || errno == EINTR) {
                         continue;
                     }
 
                     ret = errno;
                     DEBUG(SSSDBG_OP_FAILURE, ("send() failed (%d): %s\n",
                             ret, strerror(ret)));
-                    close(sock);
-                    return EXIT_FAILURE;
+                    goto done;
                 }
 
                 if (wr_len == 0) {
-                    close(sock);
-                    return EXIT_SUCCESS;
+                    ret = EOK;
+                    goto done;
                 }
 
                 wr_offs += wr_len;
@@ -183,41 +218,60 @@ static int run_connect(int af, struct sockaddr *addr, size_t addr_len)
         if (FD_ISSET(sock, &fds)) {
             rd_len = recv(sock, buffer, BUFFER_SIZE, 0);
             if (rd_len == -1) {
-                if (errno == EAGAIN) {
+                if (errno == EAGAIN || errno == EINTR) {
                     continue;
                 }
 
                 ret = errno;
                 DEBUG(SSSDBG_OP_FAILURE, ("recv() failed (%d): %s\n",
                         ret, strerror(ret)));
-                close(sock);
-                return EXIT_FAILURE;
+                goto done;
             }
 
             if (rd_len == 0) {
-                close(sock);
-                return EXIT_SUCCESS;
+                ret = EOK;
+                goto done;
             }
 
             wr_offs = 0;
             do {
                 wr_len = write(1, buffer+wr_offs, rd_len-wr_offs);
                 if (wr_len == -1) {
-                    if (errno == EAGAIN) {
+                    if (errno == EAGAIN || errno == EINTR) {
                         continue;
                     }
 
                     ret = errno;
                     DEBUG(SSSDBG_OP_FAILURE, ("write() failed (%d): %s\n",
                             ret, strerror(ret)));
-                    close(sock);
-                    return EXIT_FAILURE;
+                    goto done;
                 }
 
                 wr_offs += wr_len;
             } while(wr_offs < rd_len);
         }
     }
+
+done:
+    if (sock >= 0) close(sock);
+
+    return ret;
+}
+
+/* connect to server using proxy command */
+static int
+connect_proxy_command(char **args)
+{
+    int ret;
+
+    execv(args[0], (char * const *)args);
+
+    ret = errno;
+    DEBUG(SSSDBG_OP_FAILURE, ("execv() failed (%d): %s\n",
+            ret, strerror(ret)));
+    ERROR("Failed to execute proxy command\n");
+
+    return ret;
 }
 
 int main(int argc, const char **argv)
@@ -245,11 +299,7 @@ int main(int argc, const char **argv)
     const char *file;
     struct passwd *pwd;
     const char *host;
-    FILE *f;
     struct addrinfo ai_hint, *ai = NULL;
-    struct sss_ssh_pubkey *pubkeys;
-    size_t num_pubkeys, i;
-    char *repr;
     int ret;
 
     debug_prg_name = argv[0];
@@ -344,52 +394,14 @@ int main(int argc, const char **argv)
         host = ai[0].ai_canonname;
     }
 
-    /* look up public keys */
-    ret = sss_ssh_get_pubkeys(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS, host,
-                              &pubkeys, &num_pubkeys);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              ("sss_ssh_get_pubkeys failed() (%d): %s\n", ret, strerror(ret)));
-        ERROR("Error looking up public keys\n");
-        ret = EXIT_FAILURE;
-        goto fini;
-    }
-
-    /* write known_hosts file */
-    /* FIXME: Do not overwrite the file, handle concurrent access */
-    f = fopen(file, "w");
-    if (!f) {
-        ret = errno;
-        DEBUG(SSSDBG_OP_FAILURE, ("fopen() failed (%d): %s\n",
-                ret, strerror(ret)));
-        ERROR("Can't open known hosts file\n");
-        ret = EXIT_FAILURE;
-        goto fini;
-    }
-
-    fprintf(f,
-            "# Generated by sss_ssh_knownhostsproxy. Please do not modify.\n");
-
-    for (i = 0; i < num_pubkeys; i++) {
-        ret = sss_ssh_format_pubkey(mem_ctx, &pubkeys[i],
-                                    SSS_SSH_FORMAT_OPENSSH, &repr);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                    ("sss_ssh_format_pubkey() failed (%d): %s\n",
-                     ret, strerror(ret)));
-            continue;
-        }
-
-        fprintf(f, "%s %s\n", pc_host, repr);
-    }
-
-    fclose(f);
+    /* update the known_hosts file */
+    update_known_hosts(mem_ctx, file, pc_host, host);
 
     /* connect to server */
     if (pc_args) {
-        ret = run_proxy(discard_const(pc_args));
+        ret = connect_proxy_command(discard_const(pc_args));
     } else {
-        ret = run_connect(ai->ai_family, ai->ai_addr, ai->ai_addrlen);
+        ret = connect_socket(ai->ai_family, ai->ai_addr, ai->ai_addrlen);
     }
 
 fini:
@@ -397,5 +409,5 @@ fini:
     talloc_free(mem_ctx);
     if (ai) freeaddrinfo(ai);
 
-    return ret;
+    return (ret == EOK) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
1.7.6.5

