1 #include "libssh2_config.h"
2 #include <libssh2.h>
3 
4 #ifdef WIN32
5 #include <windows.h>
6 #include <winsock2.h>
7 #include <ws2tcpip.h>
8 #else
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <sys/time.h>
13 #endif
14 
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #ifdef HAVE_STDLIB_H
20 #include <stdlib.h>
21 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #include <sys/types.h>
26 #ifdef HAVE_SYS_SELECT_H
27 #include <sys/select.h>
28 #endif
29 
30 #ifndef INADDR_NONE
31 #define INADDR_NONE (in_addr_t)~0
32 #endif
33 
34 #ifndef HAVE_SNPRINTF
35 # ifdef HAVE__SNPRINTF
36 # define snprintf _snprintf
37 # endif
38 #endif
39 
40 const char *keyfile1 = "/home/username/.ssh/id_rsa.pub";
41 const char *keyfile2 = "/home/username/.ssh/id_rsa";
42 const char *username = "username";
43 const char *password = "";
44 
45 const char *server_ip = "127.0.0.1";
46 
47 enum {
48     AUTH_NONE = 0,
49     AUTH_PASSWORD,
50     AUTH_PUBLICKEY
51 };
52 
netconf_write(LIBSSH2_CHANNEL * channel,const char * buf,size_t len)53 static int netconf_write(LIBSSH2_CHANNEL *channel, const char *buf, size_t len)
54 {
55     int i;
56     ssize_t wr = 0;
57 
58     do {
59         i = libssh2_channel_write(channel, buf, len);
60         if(i < 0) {
61             fprintf(stderr, "libssh2_channel_write: %d\n", i);
62             return -1;
63         }
64         wr += i;
65     } while(i > 0 && wr < (ssize_t)len);
66 
67     return 0;
68 }
69 
netconf_read_until(LIBSSH2_CHANNEL * channel,const char * endtag,char * buf,size_t buflen)70 static int netconf_read_until(LIBSSH2_CHANNEL *channel, const char *endtag,
71                               char *buf, size_t buflen)
72 {
73     ssize_t len;
74     size_t rd = 0;
75     char *endreply = NULL, *specialsequence = NULL;
76 
77     memset(buf, 0, buflen);
78 
79     do {
80         len = libssh2_channel_read(channel, buf + rd, buflen - rd);
81         if(LIBSSH2_ERROR_EAGAIN == len)
82             continue;
83         else if(len < 0) {
84             fprintf(stderr, "libssh2_channel_read: %d\n", (int)len);
85             return -1;
86         }
87         rd += len;
88 
89         /* read more data until we see a rpc-reply closing tag followed by
90          * the special sequence ]]>]]> */
91 
92         /* really, this MUST be replaced with proper XML parsing! */
93 
94         endreply = strstr(buf, endtag);
95         if(endreply)
96             specialsequence = strstr(endreply, "]]>]]>");
97 
98     } while(!specialsequence && rd < buflen);
99 
100     if(!specialsequence) {
101         fprintf(stderr, "%s: ]]>]]> not found! read buffer too small?\n",
102                 __func__);
103         return -1;
104     }
105 
106     /* discard the special sequence so that only XML is returned */
107     rd = specialsequence - buf;
108     buf[rd] = 0;
109 
110     return rd;
111 }
112 
main(int argc,char * argv[])113 int main(int argc, char *argv[])
114 {
115     int rc, i, auth = AUTH_NONE;
116     struct sockaddr_in sin;
117     const char *fingerprint;
118     char *userauthlist;
119     LIBSSH2_SESSION *session;
120     LIBSSH2_CHANNEL *channel = NULL;
121     char buf[1048576]; /* avoid any buffer reallocation for simplicity */
122     ssize_t len;
123 
124 #ifdef WIN32
125     SOCKET sock = INVALID_SOCKET;
126     WSADATA wsadata;
127     int err;
128 
129     err = WSAStartup(MAKEWORD(2, 0), &wsadata);
130     if(err != 0) {
131         fprintf(stderr, "WSAStartup failed with error: %d\n", err);
132         return 1;
133     }
134 #else
135     int sock = -1;
136 #endif
137 
138     if(argc > 1)
139         server_ip = argv[1];
140     if(argc > 2)
141         username = argv[2];
142     if(argc > 3)
143         password = argv[3];
144 
145     rc = libssh2_init(0);
146     if(rc != 0) {
147         fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
148         return 1;
149     }
150 
151     /* Connect to SSH server */
152     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
153 #ifdef WIN32
154     if(sock == INVALID_SOCKET) {
155         fprintf(stderr, "failed to open socket!\n");
156         return -1;
157     }
158 #else
159     if(sock == -1) {
160         perror("socket");
161         return -1;
162     }
163 #endif
164 
165     sin.sin_family = AF_INET;
166     sin.sin_addr.s_addr = inet_addr(server_ip);
167     if(INADDR_NONE == sin.sin_addr.s_addr) {
168         fprintf(stderr, "inet_addr: Invalid IP address \"%s\"\n", server_ip);
169         return -1;
170     }
171     sin.sin_port = htons(830);
172     if(connect(sock, (struct sockaddr*)(&sin),
173                 sizeof(struct sockaddr_in)) != 0) {
174         fprintf(stderr, "Failed to connect to %s!\n", inet_ntoa(sin.sin_addr));
175         return -1;
176     }
177 
178     /* Create a session instance */
179     session = libssh2_session_init();
180     if(!session) {
181         fprintf(stderr, "Could not initialize SSH session!\n");
182         return -1;
183     }
184 
185     /* ... start it up. This will trade welcome banners, exchange keys,
186      * and setup crypto, compression, and MAC layers
187      */
188     rc = libssh2_session_handshake(session, sock);
189     if(rc) {
190         fprintf(stderr, "Error when starting up SSH session: %d\n", rc);
191         return -1;
192     }
193 
194     /* At this point we havn't yet authenticated.  The first thing to do
195      * is check the hostkey's fingerprint against our known hosts Your app
196      * may have it hard coded, may go to a file, may present it to the
197      * user, that's your call
198      */
199     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
200     fprintf(stderr, "Fingerprint: ");
201     for(i = 0; i < 20; i++)
202         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
203     fprintf(stderr, "\n");
204 
205     /* check what authentication methods are available */
206     userauthlist = libssh2_userauth_list(session, username, strlen(username));
207     fprintf(stderr, "Authentication methods: %s\n", userauthlist);
208     if(strstr(userauthlist, "password"))
209         auth |= AUTH_PASSWORD;
210     if(strstr(userauthlist, "publickey"))
211         auth |= AUTH_PUBLICKEY;
212 
213     /* check for options */
214     if(argc > 4) {
215         if((auth & AUTH_PASSWORD) && !strcasecmp(argv[4], "-p"))
216             auth = AUTH_PASSWORD;
217         if((auth & AUTH_PUBLICKEY) && !strcasecmp(argv[4], "-k"))
218             auth = AUTH_PUBLICKEY;
219     }
220 
221     if(auth & AUTH_PASSWORD) {
222         if(libssh2_userauth_password(session, username, password)) {
223             fprintf(stderr, "Authentication by password failed.\n");
224             goto shutdown;
225         }
226     }
227     else if(auth & AUTH_PUBLICKEY) {
228         if(libssh2_userauth_publickey_fromfile(session, username, keyfile1,
229                                                 keyfile2, password)) {
230             fprintf(stderr, "Authentication by public key failed!\n");
231             goto shutdown;
232         }
233         fprintf(stderr, "Authentication by public key succeeded.\n");
234     }
235     else {
236         fprintf(stderr, "No supported authentication methods found!\n");
237         goto shutdown;
238     }
239 
240     /* open a channel */
241     channel = libssh2_channel_open_session(session);
242     if(!channel) {
243         fprintf(stderr, "Could not open the channel!\n"
244                 "(Note that this can be a problem at the server!"
245                 " Please review the server logs.)\n");
246         goto shutdown;
247     }
248 
249     /* execute the subsystem on our channel */
250     if(libssh2_channel_subsystem(channel, "netconf")) {
251         fprintf(stderr, "Could not execute the \"netconf\" subsystem!\n"
252                 "(Note that this can be a problem at the server!"
253                 " Please review the server logs.)\n");
254         goto shutdown;
255     }
256 
257     /* NETCONF: https://tools.ietf.org/html/draft-ietf-netconf-ssh-06 */
258 
259     fprintf(stderr, "Sending NETCONF client <hello>\n");
260     snprintf(buf, sizeof(buf),
261       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
262       "<hello>"
263       "<capabilities>"
264       "<capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>"
265       "</capabilities>"
266       "</hello>\n"
267       "]]>]]>\n%n", (int *)&len);
268     if(-1 == netconf_write(channel, buf, len))
269         goto shutdown;
270 
271     fprintf(stderr, "Reading NETCONF server <hello>\n");
272     len = netconf_read_until(channel, "</hello>", buf, sizeof(buf));
273     if(-1 == len)
274         goto shutdown;
275 
276     fprintf(stderr, "Got %d bytes:\n----------------------\n%s",
277             (int)len, buf);
278 
279     fprintf(stderr, "Sending NETCONF <rpc>\n");
280     snprintf(buf, sizeof(buf),
281       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
282       "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
283       "<get-interface-information><terse/></get-interface-information>"
284       "</rpc>\n"
285       "]]>]]>\n%n", (int *)&len);
286     if(-1 == netconf_write(channel, buf, len))
287         goto shutdown;
288 
289     fprintf(stderr, "Reading NETCONF <rpc-reply>\n");
290     len = netconf_read_until(channel, "</rpc-reply>", buf, sizeof(buf));
291     if(-1 == len)
292         goto shutdown;
293 
294     fprintf(stderr, "Got %d bytes:\n----------------------\n%s",
295             (int)len, buf);
296 
297 shutdown:
298     if(channel)
299         libssh2_channel_free(channel);
300     libssh2_session_disconnect(session, "Client disconnecting normally");
301     libssh2_session_free(session);
302 
303 #ifdef WIN32
304     closesocket(sock);
305 #else
306     close(sock);
307 #endif
308 
309     libssh2_exit();
310 
311     return 0;
312 }
313