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.
 
 
 
 

313 lines
8.5 KiB

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