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 // some day: https://libssh2.org/examples/x11.html 9 // and https://stackoverflow.com/questions/1580750/example-code-of-libssh2-being-used-for-port-forwarding#_=_ 10 11 version(libssh_sftp_example) 12 void main() { 13 import std.socket; 14 15 if(libssh2_init(0)) 16 throw new Exception("libssh2_init"); 17 scope(exit) 18 libssh2_exit(); 19 20 auto socket = new Socket(AddressFamily.INET, SocketType.STREAM); 21 socket.connect(new InternetAddress("localhost", 22)); 22 scope(exit) socket.close(); 23 24 auto session = libssh2_session_init_ex(null, null, null, null); 25 if(session is null) throw new Exception("init session"); 26 scope(exit) 27 libssh2_session_disconnect_ex(session, 0, "normal", "EN"); 28 29 if(libssh2_session_handshake(session, socket.handle)) 30 throw new Exception("handshake"); 31 32 auto fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); 33 34 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)) 35 throw new Exception("auth"); 36 37 38 auto channel = libssh2_channel_open_ex(session, "session".ptr, "session".length, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, null, 0); 39 40 if(channel is null) 41 throw new Exception("channel open"); 42 43 scope(exit) 44 libssh2_channel_free(channel); 45 46 auto sftp_session = libssh2_sftp_init(session); 47 if(sftp_session is null) 48 throw new Exception("no sftp"); 49 scope(exit) libssh2_sftp_shutdown(sftp_session); 50 51 libssh2_session_set_blocking(session, 1); 52 53 auto filename = "/home/me/arsd/libssh2.d"; 54 auto handle = libssh2_sftp_open_ex(sftp_session, filename.ptr, cast(int) filename.length, LIBSSH2_FXF_READ, 0, LIBSSH2_SFTP_OPENFILE); 55 if(handle is null) throw new Exception("no file"); 56 scope(exit) libssh2_sftp_close_handle(handle); 57 58 char[1024] buffer; 59 again: 60 auto got = libssh2_sftp_read(handle, buffer.ptr, buffer.length); 61 62 import std.stdio; 63 writeln(buffer[0 .. got]); 64 if(got > 0) 65 goto again; 66 } 67 68 69 version(libssh_example) 70 void main() { 71 import std.socket; 72 73 if(libssh2_init(0)) 74 throw new Exception("libssh2_init"); 75 scope(exit) 76 libssh2_exit(); 77 78 auto socket = new Socket(AddressFamily.INET, SocketType.STREAM); 79 socket.connect(new InternetAddress("localhost", 22)); 80 scope(exit) socket.close(); 81 82 auto session = libssh2_session_init_ex(null, null, null, null); 83 if(session is null) throw new Exception("init session"); 84 scope(exit) 85 libssh2_session_disconnect_ex(session, 0, "normal", "EN"); 86 87 if(libssh2_session_handshake(session, socket.handle)) 88 throw new Exception("handshake"); 89 90 auto fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); 91 92 /* 93 import core.stdc.stdio; 94 for(int i = 0; i < 20; i++) 95 printf("%02X ", fingerprint[i]); 96 */ 97 98 /* 99 auto got = libssh2_userauth_list(session, "me", 2); 100 if(got is null) throw new Exception("list"); 101 import core.stdc.stdio; 102 printf("%s\n", got); 103 */ 104 105 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)) 106 throw new Exception("auth"); 107 108 109 auto channel = libssh2_channel_open_ex(session, "session".ptr, "session".length, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, null, 0); 110 111 if(channel is null) 112 throw new Exception("channel open"); 113 114 scope(exit) 115 libssh2_channel_free(channel); 116 117 libssh2_channel_setenv_ex(channel, "ELVISBG".dup.ptr, "ELVISBG".length, "dark".ptr, "dark".length); 118 119 if(libssh2_channel_request_pty_ex(channel, "xterm", "xterm".length, null, 0, 80, 24, 0, 0)) 120 throw new Exception("pty"); 121 122 if(libssh2_channel_process_startup(channel, "shell".ptr, "shell".length, null, 0)) 123 throw new Exception("process_startup"); 124 125 libssh2_keepalive_config(session, 0, 60); 126 libssh2_session_set_blocking(session, 0); 127 128 129 char[1024] buffer; 130 again: 131 auto got = libssh2_channel_read_ex(channel, 0, buffer.ptr, buffer.length); 132 if(got == LIBSSH2_ERROR_EAGAIN) { 133 import core.thread; 134 Thread.sleep(msecs(500)); 135 goto again; 136 } 137 138 import std.stdio; 139 writeln(buffer[0 .. got]); 140 } 141 142 143 144 145 import std.socket : socket_t; 146 147 version(Windows) { 148 pragma(lib, "libssh2"); 149 } else { 150 pragma(lib, "ssh2"); 151 } 152 153 version(X86) 154 alias ssize_t = int; 155 else version(X86_64) 156 alias ssize_t = long; 157 158 import core.stdc.config; 159 160 extern(C) { 161 struct LIBSSH2_SESSION {} 162 LIBSSH2_SESSION* libssh2_session_init_ex(void* myalloc, void* myfree, void* myrealloc, void* abstract_); 163 164 int libssh2_session_handshake(LIBSSH2_SESSION* session, socket_t socket); 165 166 enum int LIBSSH2_HOSTKEY_HASH_MD5 = 1; 167 enum int LIBSSH2_HOSTKEY_HASH_SHA1 = 2; 168 const(char)* libssh2_hostkey_hash(LIBSSH2_SESSION*, int hash_type); 169 170 /* sftp */ 171 struct LIBSSH2_SFTP {} 172 struct LIBSSH2_SFTP_HANDLE {} 173 LIBSSH2_SFTP* libssh2_sftp_init(LIBSSH2_SESSION *session); 174 int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); 175 c_ulong libssh2_sftp_last_error(LIBSSH2_SFTP *sftp); 176 int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); 177 int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); 178 179 enum LIBSSH2_SFTP_OPENFILE = 0; 180 enum LIBSSH2_SFTP_OPENDIR = 1; 181 182 /* Flags for rename_ex() */ 183 enum LIBSSH2_SFTP_RENAME_OVERWRITE = 0x00000001; 184 enum LIBSSH2_SFTP_RENAME_ATOMIC = 0x00000002; 185 enum LIBSSH2_SFTP_RENAME_NATIVE = 0x00000004; 186 187 /* Flags for stat_ex() */ 188 enum LIBSSH2_SFTP_STAT = 0; 189 enum LIBSSH2_SFTP_LSTAT = 1; 190 enum LIBSSH2_SFTP_SETSTAT = 2; 191 192 /* Flags for symlink_ex() */ 193 enum LIBSSH2_SFTP_SYMLINK = 0; 194 enum LIBSSH2_SFTP_READLINK = 1; 195 enum LIBSSH2_SFTP_REALPATH = 2; 196 197 /* Flags for sftp_mkdir() */ 198 enum LIBSSH2_SFTP_DEFAULT_MODE = -1; 199 200 /* SFTP attribute flag bits */ 201 enum LIBSSH2_SFTP_ATTR_SIZE = 0x00000001; 202 enum LIBSSH2_SFTP_ATTR_UIDGID = 0x00000002; 203 enum LIBSSH2_SFTP_ATTR_PERMISSIONS = 0x00000004; 204 enum LIBSSH2_SFTP_ATTR_ACMODTIME = 0x00000008; 205 enum LIBSSH2_SFTP_ATTR_EXTENDED = 0x80000000; 206 207 /* SFTP statvfs flag bits */ 208 enum LIBSSH2_SFTP_ST_RDONLY = 0x00000001; 209 enum LIBSSH2_SFTP_ST_NOSUID = 0x00000002; 210 211 enum LIBSSH2_SFTP_TYPE_REGULAR = 1; 212 enum LIBSSH2_SFTP_TYPE_DIRECTORY = 2; 213 enum LIBSSH2_SFTP_TYPE_SYMLINK = 3; 214 enum LIBSSH2_SFTP_TYPE_SPECIAL = 4; 215 enum LIBSSH2_SFTP_TYPE_UNKNOWN = 5; 216 enum LIBSSH2_SFTP_TYPE_SOCKET = 6; 217 enum LIBSSH2_SFTP_TYPE_CHAR_DEVICE = 7; 218 enum LIBSSH2_SFTP_TYPE_BLOCK_DEVICE = 8; 219 enum LIBSSH2_SFTP_TYPE_FIFO = 9; 220 221 222 /* File type */ 223 enum LIBSSH2_SFTP_S_IFMT = 0xF000; /* type of file mask */ 224 enum LIBSSH2_SFTP_S_IFIFO = 0x1000; /* named pipe (fifo) */ 225 enum LIBSSH2_SFTP_S_IFCHR = 0x2000; /* character special */ 226 enum LIBSSH2_SFTP_S_IFDIR = 0x4000; /* directory */ 227 enum LIBSSH2_SFTP_S_IFBLK = 0x6000; /* block special */ 228 enum LIBSSH2_SFTP_S_IFREG = 0x8000; /* regular */ 229 enum LIBSSH2_SFTP_S_IFLNK = 0xA000; /* symbolic link */ 230 enum LIBSSH2_SFTP_S_IFSOCK = 0xC000; /* socket */ 231 232 enum LIBSSH2_FXF_READ = 0x00000001; 233 enum LIBSSH2_FXF_WRITE = 0x00000002; 234 enum LIBSSH2_FXF_APPEND = 0x00000004; 235 enum LIBSSH2_FXF_CREAT = 0x00000008; 236 enum LIBSSH2_FXF_TRUNC = 0x00000010; 237 enum LIBSSH2_FXF_EXCL = 0x00000020; 238 239 enum LIBSSH2_FX { 240 OK = 0, 241 EOF = 1, 242 NO_SUCH_FILE = 2, 243 PERMISSION_DENIED = 3, 244 FAILURE = 4, 245 BAD_MESSAGE = 5, 246 NO_CONNECTION = 6, 247 CONNECTION_LOST = 7, 248 OP_UNSUPPORTED = 8, 249 INVALID_HANDLE = 9, 250 NO_SUCH_PATH = 10, 251 FILE_ALREADY_EXISTS = 11, 252 WRITE_PROTECT = 12, 253 NO_MEDIA = 13, 254 NO_SPACE_ON_FILESYSTEM = 14, 255 QUOTA_EXCEEDED = 15, 256 UNKNOWN_PRINCIPAL = 16, 257 LOCK_CONFLICT = 17, 258 DIR_NOT_EMPTY = 18, 259 NOT_A_DIRECTORY = 19, 260 INVALID_FILENAME = 20, 261 LINK_LOOP = 21, 262 } 263 264 LIBSSH2_SFTP_HANDLE * libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, uint filename_len, c_ulong flags, c_long mode, int open_type); 265 266 267 ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen); 268 ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count); 269 270 enum LIBSSH2_SFTP_ATTR { 271 SIZE = 0x00000001, 272 UIDGID = 0x00000002, 273 PERMISSIONS = 0x00000004, 274 ACMODTIME = 0x00000008, 275 EXTENDED = 0x80000000, 276 } 277 278 struct LIBSSH2_SFTP_ATTRIBUTES { 279 c_ulong flags; // see LIBSSH2_SFTP_ATTR 280 281 ulong filesize; 282 c_ulong uid, gid; 283 c_ulong permissions; 284 c_ulong atime, mtime; 285 } 286 287 int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, 288 char *buffer, size_t buffer_maxlen, 289 char *longentry, size_t longentry_maxlen, // longentry is just a user-friendly display 290 LIBSSH2_SFTP_ATTRIBUTES *attrs); 291 int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, 292 const char *path, 293 uint, 294 int stat_type, 295 LIBSSH2_SFTP_ATTRIBUTES *attrs); 296 int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, 297 LIBSSH2_SFTP_STATVFS *st); 298 int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, 299 const char *path, 300 size_t path_len, 301 LIBSSH2_SFTP_STATVFS *st); 302 int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, 303 const char *path, 304 uint); 305 int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, 306 const char *path, 307 uint, c_long mode); 308 int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, 309 const char *filename, 310 uint); 311 int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, 312 const char *path, 313 uint, 314 char *target, 315 uint, 316 int link_type); 317 int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, 318 const char *source_filename, 319 uint, 320 const char *dest_filename, 321 uint, 322 c_long flags); 323 324 struct LIBSSH2_SFTP_STATVFS { 325 ulong f_bsize; /* file system block size */ 326 ulong f_frsize; /* fragment size */ 327 ulong f_blocks; /* size of fs in f_frsize units */ 328 ulong f_bfree; /* # free blocks */ 329 ulong f_bavail; /* # free blocks for non-root */ 330 ulong f_files; /* # inodes */ 331 ulong f_ffree; /* # free inodes */ 332 ulong f_favail; /* # free inodes for non-root */ 333 ulong f_fsid; /* file system ID */ 334 ulong f_flag; /* mount flags */ 335 ulong f_namemax; /* maximum filename length */ 336 } 337 338 339 /* end sftp */ 340 341 int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, 342 const char *username, 343 uint username_len, 344 const char *password, 345 uint password_len, 346 void* passwd_change_cb); 347 //LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))); 348 349 //int libssh2_userauth_password(LIBSSH2_SESSION*, const char* username, const char* password); 350 int libssh2_userauth_publickey_fromfile_ex( 351 LIBSSH2_SESSION* session, 352 const char *username, 353 uint ousername_len, 354 const char *publickey, 355 const char *privatekey, 356 const char *passphrase); 357 358 struct LIBSSH2_LISTENER {} 359 LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, 360 int port, int *bound_port, 361 int queue_maxsize); 362 int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); 363 LIBSSH2_CHANNEL * libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener); 364 LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, 365 int port, const char *shost, int sport); 366 367 struct LIBSSH2_CHANNEL {} 368 LIBSSH2_CHANNEL* libssh2_channel_open_ex( 369 LIBSSH2_SESSION *session, 370 const char *channel_type, 371 uint channel_type_len, 372 uint window_size, 373 uint packet_size, 374 const char *message, 375 uint message_len); 376 // channel_open_session calls the above 377 378 int libssh2_channel_setenv_ex( 379 LIBSSH2_CHANNEL* channel, 380 char* varname, 381 uint varname_len, 382 const char *value, 383 uint value_len); 384 385 enum LIBSSH2_CHANNEL_WINDOW_DEFAULT = (256*1024); 386 enum LIBSSH2_CHANNEL_PACKET_DEFAULT = 32768; 387 388 int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf); 389 390 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); 391 392 int libssh2_channel_process_startup( 393 LIBSSH2_CHANNEL* channel, 394 const char *request, 395 uint request_len, 396 const char *message, 397 uint message_len); 398 399 400 int libssh2_channel_free(LIBSSH2_CHANNEL *channel); 401 int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang); 402 int libssh2_session_free(LIBSSH2_SESSION *session); 403 404 int libssh2_init(int flags); 405 void libssh2_exit(); 406 407 // stream_id 0 == normal, 1 == error. 408 ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, void *buf, size_t buflen); 409 410 ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, 411 int stream_id, const(void)* buf, 412 size_t buflen); 413 414 void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking); 415 416 void libssh2_keepalive_config(LIBSSH2_SESSION *session, 417 int want_reply, 418 uint interval); 419 420 int libssh2_keepalive_send(LIBSSH2_SESSION *session, 421 int *seconds_to_next); 422 423 LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport); 424 425 int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, 426 int width, int height, 427 int width_px, 428 int height_px); 429 430 char * 431 libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, 432 uint username_len); 433 434 int libssh2_channel_eof(LIBSSH2_CHANNEL*); 435 int libssh2_channel_close(LIBSSH2_CHANNEL*); 436 int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); 437 438 enum LIBSSH2_ERROR_EAGAIN = -37; 439 440 int libssh2_session_flag(LIBSSH2_SESSION*, int, int); 441 enum LIBSSH2_FLAG_SIGPIPE = 1; 442 enum LIBSSH2_FLAG_COMPRESS = 2; 443 444 445 int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, 446 int single_connection, 447 const char *auth_proto, 448 const char *auth_cookie, 449 int screen_number); 450 451 452 int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); 453 int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, char **exitsignal, size_t *exitsignal_len, char **errmsg, size_t *errmsg_len, char **langtag, size_t *langtag_len); 454 455 int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); 456 457 }