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