geom_gate userland utility improvements
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

372 lines
10 KiB

  1. /*
  2. * Run it like this:
  3. *
  4. * $ ./ssh2_echo 127.0.0.1 user password
  5. *
  6. * The code sends a 'cat' command, and then writes a lot of data to it only to
  7. * check that reading the returned data sums up to the same amount.
  8. *
  9. */
  10. #include "libssh2_config.h"
  11. #include <libssh2.h>
  12. #ifdef HAVE_WINSOCK2_H
  13. # include <winsock2.h>
  14. #endif
  15. #ifdef HAVE_SYS_SOCKET_H
  16. # include <sys/socket.h>
  17. #endif
  18. #ifdef HAVE_NETINET_IN_H
  19. # include <netinet/in.h>
  20. #endif
  21. #ifdef HAVE_SYS_SELECT_H
  22. # include <sys/select.h>
  23. #endif
  24. # ifdef HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #ifdef HAVE_ARPA_INET_H
  28. # include <arpa/inet.h>
  29. #endif
  30. #ifdef HAVE_SYS_TIME_H
  31. #include <sys/time.h>
  32. #endif
  33. #include <sys/types.h>
  34. #ifdef HAVE_STDLIB_H
  35. #include <stdlib.h>
  36. #endif
  37. #include <fcntl.h>
  38. #include <errno.h>
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
  42. {
  43. struct timeval timeout;
  44. int rc;
  45. fd_set fd;
  46. fd_set *writefd = NULL;
  47. fd_set *readfd = NULL;
  48. int dir;
  49. timeout.tv_sec = 10;
  50. timeout.tv_usec = 0;
  51. FD_ZERO(&fd);
  52. FD_SET(socket_fd, &fd);
  53. /* now make sure we wait in the correct direction */
  54. dir = libssh2_session_block_directions(session);
  55. if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
  56. readfd = &fd;
  57. if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
  58. writefd = &fd;
  59. rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
  60. return rc;
  61. }
  62. #define BUFSIZE 32000
  63. int main(int argc, char *argv[])
  64. {
  65. const char *hostname = "127.0.0.1";
  66. const char *commandline = "cat";
  67. const char *username = "user";
  68. const char *password = "password";
  69. unsigned long hostaddr;
  70. int sock;
  71. struct sockaddr_in sin;
  72. const char *fingerprint;
  73. LIBSSH2_SESSION *session;
  74. LIBSSH2_CHANNEL *channel;
  75. int rc;
  76. int exitcode = 0;
  77. char *exitsignal = (char *)"none";
  78. size_t len;
  79. LIBSSH2_KNOWNHOSTS *nh;
  80. int type;
  81. #ifdef WIN32
  82. WSADATA wsadata;
  83. int err;
  84. err = WSAStartup(MAKEWORD(2, 0), &wsadata);
  85. if(err != 0) {
  86. fprintf(stderr, "WSAStartup failed with error: %d\n", err);
  87. return 1;
  88. }
  89. #endif
  90. if(argc > 1)
  91. /* must be ip address only */
  92. hostname = argv[1];
  93. if(argc > 2) {
  94. username = argv[2];
  95. }
  96. if(argc > 3) {
  97. password = argv[3];
  98. }
  99. rc = libssh2_init(0);
  100. if(rc != 0) {
  101. fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
  102. return 1;
  103. }
  104. hostaddr = inet_addr(hostname);
  105. /* Ultra basic "connect to port 22 on localhost"
  106. * Your code is responsible for creating the socket establishing the
  107. * connection
  108. */
  109. sock = socket(AF_INET, SOCK_STREAM, 0);
  110. sin.sin_family = AF_INET;
  111. sin.sin_port = htons(22);
  112. sin.sin_addr.s_addr = hostaddr;
  113. if(connect(sock, (struct sockaddr*)(&sin),
  114. sizeof(struct sockaddr_in)) != 0) {
  115. fprintf(stderr, "failed to connect!\n");
  116. return -1;
  117. }
  118. /* Create a session instance */
  119. session = libssh2_session_init();
  120. if(!session)
  121. return -1;
  122. /* tell libssh2 we want it all done non-blocking */
  123. libssh2_session_set_blocking(session, 0);
  124. /* ... start it up. This will trade welcome banners, exchange keys,
  125. * and setup crypto, compression, and MAC layers
  126. */
  127. while((rc = libssh2_session_handshake(session, sock)) ==
  128. LIBSSH2_ERROR_EAGAIN);
  129. if(rc) {
  130. fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
  131. return -1;
  132. }
  133. nh = libssh2_knownhost_init(session);
  134. if(!nh) {
  135. /* eeek, do cleanup here */
  136. return 2;
  137. }
  138. /* read all hosts from here */
  139. libssh2_knownhost_readfile(nh, "known_hosts",
  140. LIBSSH2_KNOWNHOST_FILE_OPENSSH);
  141. /* store all known hosts to here */
  142. libssh2_knownhost_writefile(nh, "dumpfile",
  143. LIBSSH2_KNOWNHOST_FILE_OPENSSH);
  144. fingerprint = libssh2_session_hostkey(session, &len, &type);
  145. if(fingerprint) {
  146. struct libssh2_knownhost *host;
  147. int check = libssh2_knownhost_checkp(nh, hostname, 22,
  148. fingerprint, len,
  149. LIBSSH2_KNOWNHOST_TYPE_PLAIN|
  150. LIBSSH2_KNOWNHOST_KEYENC_RAW,
  151. &host);
  152. fprintf(stderr, "Host check: %d, key: %s\n", check,
  153. (check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
  154. host->key:"<none>");
  155. /*****
  156. * At this point, we could verify that 'check' tells us the key is
  157. * fine or bail out.
  158. *****/
  159. }
  160. else {
  161. /* eeek, do cleanup here */
  162. return 3;
  163. }
  164. libssh2_knownhost_free(nh);
  165. if(strlen(password) != 0) {
  166. /* We could authenticate via password */
  167. while((rc = libssh2_userauth_password(session, username, password)) ==
  168. LIBSSH2_ERROR_EAGAIN);
  169. if(rc) {
  170. fprintf(stderr, "Authentication by password failed.\n");
  171. exit(1);
  172. }
  173. }
  174. libssh2_trace(session, LIBSSH2_TRACE_SOCKET);
  175. /* Exec non-blocking on the remove host */
  176. while((channel = libssh2_channel_open_session(session)) == NULL &&
  177. libssh2_session_last_error(session, NULL, NULL, 0) ==
  178. LIBSSH2_ERROR_EAGAIN) {
  179. waitsocket(sock, session);
  180. }
  181. if(channel == NULL) {
  182. fprintf(stderr, "Error\n");
  183. exit(1);
  184. }
  185. while((rc = libssh2_channel_exec(channel, commandline)) ==
  186. LIBSSH2_ERROR_EAGAIN)
  187. waitsocket(sock, session);
  188. if(rc != 0) {
  189. fprintf(stderr, "exec error\n");
  190. exit(1);
  191. }
  192. else {
  193. LIBSSH2_POLLFD *fds = NULL;
  194. int running = 1;
  195. int bufsize = BUFSIZE;
  196. char buffer[BUFSIZE];
  197. int totsize = 1500000;
  198. int totwritten = 0;
  199. int totread = 0;
  200. int partials = 0;
  201. int rereads = 0;
  202. int rewrites = 0;
  203. int i;
  204. for(i = 0; i < BUFSIZE; i++)
  205. buffer[i] = 'A';
  206. fds = malloc(sizeof (LIBSSH2_POLLFD));
  207. if(!fds) {
  208. fprintf(stderr, "malloc failed\n");
  209. exit(1);
  210. }
  211. fds[0].type = LIBSSH2_POLLFD_CHANNEL;
  212. fds[0].fd.channel = channel;
  213. fds[0].events = LIBSSH2_POLLFD_POLLIN | LIBSSH2_POLLFD_POLLOUT;
  214. do {
  215. int rc = (libssh2_poll(fds, 1, 10));
  216. int act = 0;
  217. if(rc < 1)
  218. continue;
  219. if(fds[0].revents & LIBSSH2_POLLFD_POLLIN) {
  220. int n = libssh2_channel_read(channel, buffer, sizeof(buffer));
  221. act++;
  222. if(n == LIBSSH2_ERROR_EAGAIN) {
  223. rereads++;
  224. fprintf(stderr, "will read again\n");
  225. }
  226. else if(n < 0) {
  227. fprintf(stderr, "read failed\n");
  228. exit(1);
  229. }
  230. else {
  231. totread += n;
  232. fprintf(stderr, "read %d bytes (%d in total)\n",
  233. n, totread);
  234. }
  235. }
  236. if(fds[0].revents & LIBSSH2_POLLFD_POLLOUT) {
  237. act++;
  238. if(totwritten < totsize) {
  239. /* we have not written all data yet */
  240. int left = totsize - totwritten;
  241. int size = (left < bufsize) ? left : bufsize;
  242. int n = libssh2_channel_write_ex(channel, 0, buffer, size);
  243. if(n == LIBSSH2_ERROR_EAGAIN) {
  244. rewrites++;
  245. fprintf(stderr, "will write again\n");
  246. }
  247. else if(n < 0) {
  248. fprintf(stderr, "write failed\n");
  249. exit(1);
  250. }
  251. else {
  252. totwritten += n;
  253. fprintf(stderr, "wrote %d bytes (%d in total)",
  254. n, totwritten);
  255. if(left >= bufsize && n != bufsize) {
  256. partials++;
  257. fprintf(stderr, " PARTIAL");
  258. }
  259. fprintf(stderr, "\n");
  260. }
  261. }
  262. else {
  263. /* all data written, send EOF */
  264. rc = libssh2_channel_send_eof(channel);
  265. if(rc == LIBSSH2_ERROR_EAGAIN) {
  266. fprintf(stderr, "will send eof again\n");
  267. }
  268. else if(rc < 0) {
  269. fprintf(stderr, "send eof failed\n");
  270. exit(1);
  271. }
  272. else {
  273. fprintf(stderr, "sent eof\n");
  274. /* we're done writing, stop listening for OUT events */
  275. fds[0].events &= ~LIBSSH2_POLLFD_POLLOUT;
  276. }
  277. }
  278. }
  279. if(fds[0].revents & LIBSSH2_POLLFD_CHANNEL_CLOSED) {
  280. if(!act) /* don't leave loop until we have read all data */
  281. running = 0;
  282. }
  283. } while(running);
  284. exitcode = 127;
  285. while((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
  286. waitsocket(sock, session);
  287. if(rc == 0) {
  288. exitcode = libssh2_channel_get_exit_status(channel);
  289. libssh2_channel_get_exit_signal(channel, &exitsignal,
  290. NULL, NULL, NULL, NULL, NULL);
  291. }
  292. if(exitsignal)
  293. fprintf(stderr, "\nGot signal: %s\n", exitsignal);
  294. libssh2_channel_free(channel);
  295. channel = NULL;
  296. fprintf(stderr, "\nrereads: %d rewrites: %d totwritten %d\n",
  297. rereads, rewrites, totwritten);
  298. if(totwritten != totread) {
  299. fprintf(stderr, "\n*** FAIL bytes written: %d bytes "
  300. "read: %d ***\n", totwritten, totread);
  301. exit(1);
  302. }
  303. }
  304. libssh2_session_disconnect(session,
  305. "Normal Shutdown, Thank you for playing");
  306. libssh2_session_free(session);
  307. #ifdef WIN32
  308. closesocket(sock);
  309. #else
  310. close(sock);
  311. #endif
  312. fprintf(stderr, "all done\n");
  313. libssh2_exit();
  314. return exitcode;
  315. }