1 /++
2 	Minimal bindings for libssh2. (just what I needed for my terminal emulator, but I'd accept more, and even wrappers if you wanted to.)
3 
4 	Just link with it on Linux, but it'll need a couple dlls and a lib on windows.
5 +/
6 module arsd.libssh2;
7 
8 version(libssh_example)
9 void main() {
10 	import std.socket;
11 
12 	if(libssh2_init(0))
13 		throw new Exception("libssh2_init");
14 	scope(exit)
15 		libssh2_exit();
16 
17 	auto socket = new Socket(AddressFamily.INET, SocketType.STREAM);
18 	socket.connect(new InternetAddress("localhost", 22));
19 	scope(exit) socket.close();
20 
21 	auto session = libssh2_session_init_ex(null, null, null, null);
22 	if(session is null) throw new Exception("init session");
23 	scope(exit)
24 		libssh2_session_disconnect_ex(session, 0, "normal", "EN");
25 
26 	if(libssh2_session_handshake(session, socket.handle))
27 		throw new Exception("handshake");
28 
29 	auto fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
30 
31 	/*
32 	import core.stdc.stdio;
33 	for(int i = 0; i < 20; i++)
34 		printf("%02X ", fingerprint[i]);
35 	*/
36 
37 	/*
38 	auto got = libssh2_userauth_list(session, "me", 2);
39 	if(got is null) throw new Exception("list");
40 	import core.stdc.stdio;
41 	printf("%s\n", got);
42 	*/
43 
44 	if(auto err = libssh2_userauth_publickey_fromfile_ex(session, "me".ptr, "me".length, "/home/me/.ssh/id_rsa.pub", "/home/me/.ssh/id_rsa", null))
45 		throw new Exception("auth");
46 
47 
48 	auto channel = libssh2_channel_open_ex(session, "session".ptr, "session".length, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, null, 0);
49 
50 	if(channel is null)
51 		throw new Exception("channel open");
52 
53 	scope(exit)
54 		libssh2_channel_free(channel);
55 
56 	libssh2_channel_setenv_ex(channel, "ELVISBG".dup.ptr, "ELVISBG".length, "dark".ptr, "dark".length);
57 
58 	if(libssh2_channel_request_pty_ex(channel, "xterm", "xterm".length, null, 0, 80, 24, 0, 0))
59 		throw new Exception("pty");
60 
61 	if(libssh2_channel_process_startup(channel, "shell".ptr, "shell".length, null, 0))
62 		throw new Exception("process_startup");
63 
64 	libssh2_keepalive_config(session, 0, 60);
65 	libssh2_session_set_blocking(session, 0);
66 
67 
68 	char[1024] buffer;
69 	again:
70 	auto got = libssh2_channel_read_ex(channel, 0, buffer.ptr, buffer.length);
71 	if(got == LIBSSH2_ERROR_EAGAIN) {
72 		import core.thread;
73 		Thread.sleep(msecs(500));
74 		goto again;
75 	}
76 
77 	import std.stdio;
78 	writeln(buffer[0 .. got]);
79 }
80 
81 
82 
83 
84 alias socket_t = int;
85 
86 version(Windows) {
87 	pragma(lib, "libssh2");
88 } else {
89 	pragma(lib, "ssh2");
90 }
91 
92 version(X86)
93 	alias ssize_t = int;
94 else version(X86_64)
95 	alias ssize_t = long;
96 
97 extern(C) {
98 	struct LIBSSH2_SESSION {}
99 	LIBSSH2_SESSION* libssh2_session_init_ex(void* myalloc, void* myfree, void* myrealloc, void* abstract_);
100 
101 	int libssh2_session_handshake(LIBSSH2_SESSION* session, socket_t socket);
102 
103 	enum int LIBSSH2_HOSTKEY_HASH_MD5 = 1;
104 	enum int LIBSSH2_HOSTKEY_HASH_SHA1 = 2;
105 	const(char)* libssh2_hostkey_hash(LIBSSH2_SESSION*, int hash_type);
106 
107 	int libssh2_userauth_publickey_fromfile_ex(
108 		LIBSSH2_SESSION* session,
109 		const char *username,
110 		uint ousername_len,
111 		const char *publickey,
112 		const char *privatekey,
113 		const char *passphrase);
114 
115 	struct LIBSSH2_CHANNEL {}
116 	LIBSSH2_CHANNEL* libssh2_channel_open_ex(
117 		LIBSSH2_SESSION *session,
118 		const char *channel_type,
119 		uint channel_type_len,
120 		uint window_size,
121 		uint packet_size,
122 		const char *message,
123 		uint message_len); 
124 	// channel_open_session calls the above
125 
126 	int libssh2_channel_setenv_ex(
127 		LIBSSH2_CHANNEL* channel,
128 		char* varname,
129 		uint varname_len,
130 		const char *value,
131 		uint value_len);
132 
133 	enum LIBSSH2_CHANNEL_WINDOW_DEFAULT = (256*1024);
134 	enum LIBSSH2_CHANNEL_PACKET_DEFAULT = 32768;
135 
136 	int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, uint term_len, const char *modes, uint modes_len, int width, int height, int width_px, int height_px); 
137 
138 	int libssh2_channel_process_startup(
139 		LIBSSH2_CHANNEL* channel,
140 		const char *request,
141 		uint request_len,
142 		const char *message,
143 		uint message_len);
144  
145 
146 	int libssh2_channel_free(LIBSSH2_CHANNEL *channel); 
147 	int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang); 
148 	int libssh2_session_free(LIBSSH2_SESSION *session); 
149 
150 	int libssh2_init(int flags);
151 	void libssh2_exit();
152 
153 	// stream_id 0 == normal, 1 == error.
154 	ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, void *buf, size_t buflen);
155 
156 	ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
157                                   int stream_id, const(void)* buf,
158                                   size_t buflen);
159 
160 	void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking);
161 
162 	void libssh2_keepalive_config(LIBSSH2_SESSION *session,
163 		int want_reply,
164 		uint interval);
165 
166 	int libssh2_keepalive_send(LIBSSH2_SESSION *session,
167 		int *seconds_to_next);
168 
169 	LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport); 
170 
171 	int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel,
172 		int width, int height,
173 		int width_px,
174 		int height_px);
175 
176 	char *
177  libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username,
178                        uint username_len);
179 
180 	int libssh2_channel_eof(LIBSSH2_CHANNEL*);
181 	int libssh2_channel_close(LIBSSH2_CHANNEL*);
182 	int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
183 
184 	enum LIBSSH2_ERROR_EAGAIN = -37;
185 
186 	int libssh2_session_flag(LIBSSH2_SESSION*, int, int);
187 	enum LIBSSH2_FLAG_SIGPIPE = 1;
188 	enum LIBSSH2_FLAG_COMPRESS = 2;
189 
190 }