From 5be36b8f0a4331e3f356a829bcdf00a71f7b43ce Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@unixuser.org>
Date: Sun, 20 Dec 2009 06:06:55 +0900
Subject: [PATCH 3/3] Add an example to use ssh-agent API.

---
 example/Makefile.am  |    2 +-
 example/ssh2_agent.c |  229 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 230 insertions(+), 1 deletions(-)
 create mode 100644 example/ssh2_agent.c

diff --git a/example/Makefile.am b/example/Makefile.am
index cfa16d9..c396fdf 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -8,7 +8,7 @@ noinst_PROGRAMS = ssh2 \
 		sftp_write sftp_write_nonblock \
 		sftp_mkdir sftp_mkdir_nonblock \
 		sftp_RW_nonblock \
-		sftpdir sftpdir_nonblock ssh2_exec
+		sftpdir sftpdir_nonblock ssh2_exec ssh2_agent
 
 # the examples need the $(top_builddir)/src since when building outside of the
 # source dir they still need to reach the libssh2_config.h header
diff --git a/example/ssh2_agent.c b/example/ssh2_agent.c
new file mode 100644
index 0000000..a8e8519
--- /dev/null
+++ b/example/ssh2_agent.c
@@ -0,0 +1,229 @@
+/*
+ * Sample showing how to do SSH2 connect using ssh-agent.
+ *
+ * The sample code has default values for host name, user name:
+ *
+ * "ssh2_agent host user"
+ */
+
+#include "libssh2_config.h"
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifdef HAVE_WINDOWS_H
+# include <windows.h>
+#endif
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+# ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+# ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+const char *username="username";
+
+int main(int argc, char *argv[])
+{
+    unsigned long hostaddr;
+    int sock = -1, i, j, rc;
+    struct sockaddr_in sin;
+    const char *fingerprint;
+    char *userauthlist;
+    LIBSSH2_SESSION *session;
+    LIBSSH2_CHANNEL *channel;
+    LIBSSH2_AGENT *agent = NULL;
+    struct libssh2_agent_publickey *identity, *prev_identity = NULL;
+#ifdef WIN32
+    WSADATA wsadata;
+
+    WSAStartup(MAKEWORD(2,0), &wsadata);
+#endif
+
+    if (argc > 1) {
+        hostaddr = inet_addr(argv[1]);
+    } else {
+        hostaddr = htonl(0x7F000001);
+    }
+
+    if(argc > 2) {
+        username = argv[2];
+    }
+
+    /* Ultra basic "connect to port 22 on localhost".  Your code is
+     * responsible for creating the socket establishing the connection
+     */
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock == -1) {
+        fprintf(stderr, "failed to create socket!\n");
+        rc = 1;
+        goto shutdown;
+    }
+
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(22);
+    sin.sin_addr.s_addr = hostaddr;
+    if (connect(sock, (struct sockaddr*)(&sin),
+                sizeof(struct sockaddr_in)) != 0) {
+        fprintf(stderr, "failed to connect!\n");
+        goto shutdown;
+    }
+
+    /* Create a session instance and start it up. This will trade welcome
+     * banners, exchange keys, and setup crypto, compression, and MAC layers
+     */
+    session = libssh2_session_init();
+    if (libssh2_session_startup(session, sock)) {
+        fprintf(stderr, "Failure establishing SSH session\n");
+        return 1;
+    }
+
+    /* Connect to the ssh-agent */
+    agent = libssh2_agent_init(session);
+    if (!agent) {
+        fprintf(stderr, "Failure initializing ssh-agent support\n");
+        rc = 1;
+        goto shutdown;
+    }
+    if (libssh2_agent_connect(agent)) {
+        fprintf(stderr, "Failure connecting to ssh-agent\n");
+        rc = 1;
+        goto shutdown;
+    }
+    if (libssh2_agent_list_identities(agent)) {
+        fprintf(stderr, "Failure requesting identities to ssh-agent\n");
+        rc = 1;
+        goto shutdown;
+    }
+    while (1) {
+        rc = libssh2_agent_get_identity(agent, &identity, prev_identity);
+        if (rc == 1)
+            break;
+        if (rc < 0) {
+            fprintf(stderr,
+                    "Failure obtaining identity from ssh-agent support\n");
+            rc = 1;
+            goto shutdown;
+        }
+        if (libssh2_agent_userauth(agent, username, identity)) {
+            printf("\tAuthentication with username %s and "
+                   "public key %s failed!\n",
+                   username, identity->comment);
+        } else {
+            printf("\tAuthentication with username %s and "
+                   "public key %s succeeded!\n",
+                   username, identity->comment);
+            break;
+        }
+	prev_identity = identity;
+    }
+    if (rc) {
+        fprintf(stderr, "Couldn't continue authentication\n");
+        goto shutdown;
+    }
+
+    /* At this point we havn't authenticated. The first thing to do is check
+     * the hostkey's fingerprint against our known hosts Your app may have it
+     * hard coded, may go to a file, may present it to the user, that's your
+     * call
+     */
+    fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
+    printf("Fingerprint: ");
+    for(i = 0; i < 16; i++) {
+        printf("%02X ", (unsigned char)fingerprint[i]);
+    }
+    printf("\n");
+
+    /* check what authentication methods are available */
+    userauthlist = libssh2_userauth_list(session, username, strlen(username));
+    printf("Authentication methods: %s\n", userauthlist);
+    if (strstr(userauthlist, "publickey") == NULL) {
+        fprintf(stderr, "\"publickey\" authentication is not supported\n");
+        goto shutdown;
+    }
+
+    /* Request a shell */
+    if (!(channel = libssh2_channel_open_session(session))) {
+        fprintf(stderr, "Unable to open a session\n");
+        goto shutdown;
+    }
+
+    /* Some environment variables may be set,
+     * It's up to the server which ones it'll allow though
+     */
+    libssh2_channel_setenv(channel, "FOO", "bar");
+
+    /* Request a terminal with 'vanilla' terminal emulation
+     * See /etc/termcap for more options
+     */
+    if (libssh2_channel_request_pty(channel, "vanilla")) {
+        fprintf(stderr, "Failed requesting pty\n");
+        goto skip_shell;
+    }
+
+    /* Open a SHELL on that pty */
+    if (libssh2_channel_shell(channel)) {
+        fprintf(stderr, "Unable to request shell on allocated pty\n");
+        goto shutdown;
+    }
+
+    /* At this point the shell can be interacted with using
+     * libssh2_channel_read()
+     * libssh2_channel_read_stderr()
+     * libssh2_channel_write()
+     * libssh2_channel_write_stderr()
+     *
+     * Blocking mode may be (en|dis)abled with: libssh2_channel_set_blocking()
+     * If the server send EOF, libssh2_channel_eof() will return non-0
+     * To send EOF to the server use: libssh2_channel_send_eof()
+     * A channel can be closed with: libssh2_channel_close()
+     * A channel can be freed with: libssh2_channel_free()
+     */
+
+  skip_shell:
+    if (channel) {
+        libssh2_channel_free(channel);
+        channel = NULL;
+    }
+
+    /* Other channel types are supported via:
+     * libssh2_scp_send()
+     * libssh2_scp_recv()
+     * libssh2_channel_direct_tcpip()
+     */
+
+  shutdown:
+
+    libssh2_agent_disconnect(agent);
+    libssh2_agent_free(agent);
+
+    libssh2_session_disconnect(session,
+                               "Normal Shutdown, Thank you for playing");
+    libssh2_session_free(session);
+
+    if (sock != -1) {
+#ifdef WIN32
+        closesocket(sock);
+#else
+        close(sock);
+#endif
+    }
+
+    printf("all done!\n");
+    return rc;
+}
-- 
1.6.5.4

