1 module libssh.session; 2 3 import std..string; 4 import std.algorithm.mutation; 5 6 import libssh.c_bindings.libssh; 7 import libssh.c_bindings.callbacks; 8 import libssh.c_bindings.sftp; 9 import libssh.c_bindings.server; 10 import libssh.errors; 11 import libssh.utils; 12 import libssh.channel; 13 import libssh.message; 14 import libssh.logging; 15 import libssh.scp; 16 import libssh.key; 17 import libssh.sftp; 18 import libssh.message; 19 20 enum PollFlags : int { 21 ReadPending = SSH_READ_PENDING, 22 WritePending = SSH_WRITE_PENDING, 23 } 24 25 enum SessionStatusFlags : int { 26 Closed = SSH_CLOSED, 27 ReadPending = SSH_READ_PENDING, 28 ClosedError = SSH_CLOSED_ERROR, 29 WritePending = SSH_WRITE_PENDING, 30 } 31 32 enum ServerKnownState : int { 33 Ok = ssh_server_known_e.SSH_SERVER_KNOWN_OK, 34 Changed = ssh_server_known_e.SSH_SERVER_KNOWN_CHANGED, 35 FoundOther = ssh_server_known_e.SSH_SERVER_FOUND_OTHER, 36 NotKnown = ssh_server_known_e.SSH_SERVER_NOT_KNOWN, 37 FileNotFound = ssh_server_known_e.SSH_SERVER_FILE_NOT_FOUND, 38 } 39 40 enum SessionOption : int { 41 Host = ssh_options_e.SSH_OPTIONS_HOST, 42 Port = ssh_options_e.SSH_OPTIONS_PORT, 43 PortStr = ssh_options_e.SSH_OPTIONS_PORT_STR, 44 Fd = ssh_options_e.SSH_OPTIONS_FD, 45 User = ssh_options_e.SSH_OPTIONS_USER, 46 SshDir = ssh_options_e.SSH_OPTIONS_SSH_DIR, 47 Identity = ssh_options_e.SSH_OPTIONS_IDENTITY, 48 AddIdentity = ssh_options_e.SSH_OPTIONS_ADD_IDENTITY, 49 KnownHosts = ssh_options_e.SSH_OPTIONS_KNOWNHOSTS, 50 Timeout = ssh_options_e.SSH_OPTIONS_TIMEOUT, 51 TimeoutUsec = ssh_options_e.SSH_OPTIONS_TIMEOUT_USEC, 52 Ssh1 = ssh_options_e.SSH_OPTIONS_SSH1, 53 Ssh2 = ssh_options_e.SSH_OPTIONS_SSH2, 54 LogVerbosity = ssh_options_e.SSH_OPTIONS_LOG_VERBOSITY, 55 LogVerbosityStr = ssh_options_e.SSH_OPTIONS_LOG_VERBOSITY_STR, 56 CiphersCS = ssh_options_e.SSH_OPTIONS_CIPHERS_C_S, 57 CiphersSC = ssh_options_e.SSH_OPTIONS_CIPHERS_S_C, 58 CompressionCS = ssh_options_e.SSH_OPTIONS_COMPRESSION_C_S, 59 CompressionSC = ssh_options_e.SSH_OPTIONS_COMPRESSION_S_C, 60 ProxyCommand = ssh_options_e.SSH_OPTIONS_PROXYCOMMAND, 61 BindAddr = ssh_options_e.SSH_OPTIONS_BINDADDR, 62 StrictHostkeyCheck = ssh_options_e.SSH_OPTIONS_STRICTHOSTKEYCHECK, 63 Compression = ssh_options_e.SSH_OPTIONS_COMPRESSION, 64 CompressionLevel = ssh_options_e.SSH_OPTIONS_COMPRESSION_LEVEL, 65 KeyExchange = ssh_options_e.SSH_OPTIONS_KEY_EXCHANGE, 66 Hostkeys = ssh_options_e.SSH_OPTIONS_HOSTKEYS, 67 GssapiServerIdentity = ssh_options_e.SSH_OPTIONS_GSSAPI_SERVER_IDENTITY, 68 GssapiClientIdentity = ssh_options_e.SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY, 69 GssapiDelegateCredentials = ssh_options_e.SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, 70 HmacCS = ssh_options_e.SSH_OPTIONS_HMAC_C_S, 71 HmacSC = ssh_options_e.SSH_OPTIONS_HMAC_S_C, 72 } 73 74 enum SSHProtocolVersion { 75 SSH1 = 1, 76 SSH2 = 2 77 } 78 79 enum AuthState : int { 80 Success = ssh_auth_e.SSH_AUTH_SUCCESS, 81 Denied = ssh_auth_e.SSH_AUTH_DENIED, 82 Partial = ssh_auth_e.SSH_AUTH_PARTIAL, 83 Info = ssh_auth_e.SSH_AUTH_INFO, 84 Again = ssh_auth_e.SSH_AUTH_AGAIN, 85 } 86 87 enum AuthMethod : int { 88 Unknown = SSH_AUTH_METHOD_UNKNOWN, 89 None = SSH_AUTH_METHOD_NONE, 90 Password = SSH_AUTH_METHOD_PASSWORD, 91 PublicKey = SSH_AUTH_METHOD_PUBLICKEY, 92 Hostbased = SSH_AUTH_METHOD_HOSTBASED, 93 Interactive = SSH_AUTH_METHOD_INTERACTIVE, 94 GSSAPIMic = SSH_AUTH_METHOD_GSSAPI_MIC, 95 } 96 97 alias LogVerbosity = LogLevel; 98 alias GSSAPICreds = size_t; 99 100 class SSHSession : Disposable { 101 alias AuthCallback = string delegate(string prompt, bool echo, bool verify); 102 alias MessageCallback = bool delegate(SSHSession session, SSHMessage message); 103 alias OpenRequestX11Callback = SSHChannel delegate(SSHSession session, string originatorAddres, 104 ushort originatorPort); 105 alias OnConnectStatusChangedCallback = void delegate(SSHSession session, float v); 106 alias OnLogCallback = void delegate(SSHSession session, LogLevel level, string msg); 107 alias OnGlobalRequestCallback = void delegate(SSHSession session, SSHMessage message); 108 109 alias ServerAuthGSSAPIMicCallback = AuthState delegate(SSHSession session, string user, 110 string principal); 111 alias ServerAuthNoneCallback = AuthState delegate(SSHSession session, string user); 112 alias ServerAuthPasswordCallback = AuthState delegate(SSHSession session, string user, 113 string password); 114 alias ServerAuthPublicKeyCallback = AuthState delegate(SSHSession session, string user, 115 SSHKey publicKey, PublicKeyState signatureState); 116 alias ServerChannelOpenRequestCallback = SSHChannel delegate(SSHSession session); 117 alias ServerServiceRequestCallback = bool delegate(SSHSession session, string service); 118 alias ServerGSSAPIAcceptSecCtxCallback = bool delegate(SSHSession session, string inputToken, 119 out string outputToken); 120 alias ServerGSSAPISelectOidCallback = string delegate(SSHSession session, string user, 121 string[] oids); 122 123 @property OnConnectStatusChangedCallback onConnectStatusChangedCallback() { 124 return this._onConnectStatusChangedCallback; 125 } 126 127 @property void onConnectStatusChangedCallback(OnConnectStatusChangedCallback cb) { 128 this._onConnectStatusChangedCallback = cb; 129 if (cb is null) { 130 this._sessionCallbacks.connect_status_function = null; 131 } else { 132 this._sessionCallbacks.connect_status_function = &nativeConnectStatusCallback; 133 } 134 ssh_set_callbacks(this._session, &this._sessionCallbacks); 135 } 136 137 @property OnLogCallback onLogCallback() { 138 return this._onLogCallback; 139 } 140 141 @property void onLogCallback(OnLogCallback cb) { 142 this._onLogCallback = cb; 143 if (cb is null) { 144 this._sessionCallbacks.log_function = null; 145 } else { 146 this._sessionCallbacks.log_function = &nativeLogFunction; 147 } 148 ssh_set_callbacks(this._session, &this._sessionCallbacks); 149 } 150 151 @property OnGlobalRequestCallback onGlobalRequestCallback() { 152 return this._onGlobalRequestCallback; 153 } 154 155 @property void onGlobalRequestCallback(OnGlobalRequestCallback cb) { 156 this._onGlobalRequestCallback = cb; 157 if (cb is null) { 158 this._sessionCallbacks.global_request_function = null; 159 } else { 160 this._sessionCallbacks.global_request_function = &nativeOnGlobalRequest; 161 } 162 ssh_set_callbacks(this._session, &this._sessionCallbacks); 163 } 164 165 @property AuthCallback authCallback() { 166 return this._authCallback; 167 } 168 169 @property void authCallback(AuthCallback cb) { 170 this._authCallback = cb; 171 if (cb is null) { 172 this._sessionCallbacks.auth_function = null; 173 } else { 174 this._sessionCallbacks.auth_function = &nativeSessionAuthCallback; 175 } 176 ssh_set_callbacks(this._session, &this._sessionCallbacks); 177 } 178 179 @property MessageCallback messageCallback() { 180 return this._messageCallback; 181 } 182 183 @property void messageCallback(MessageCallback cb) { 184 this._messageCallback = cb; 185 if (cb is null) { 186 ssh_set_message_callback(this._session, null, null); 187 } else { 188 ssh_set_message_callback(this._session, &nativeOnMessageCallback, cast(void*) this); 189 } 190 } 191 192 @property OpenRequestX11Callback openRequestX11Callback() { 193 return this._openRequestX11Callback; 194 } 195 196 @property void openRequestX11Callback(OpenRequestX11Callback cb) { 197 this._openRequestX11Callback = cb; 198 if (cb is null) { 199 this._sessionCallbacks.channel_open_request_x11_function = null; 200 } else { 201 this._sessionCallbacks.channel_open_request_x11_function = &nativeOpenRequestX11Callback; 202 } 203 ssh_set_callbacks(this._session, &this._sessionCallbacks); 204 } 205 206 207 @property ServerAuthGSSAPIMicCallback serverAuthGSSAPIMicCallback() { 208 return this._serverAuthGSSAPIMicCallback; 209 } 210 211 @property void serverAuthGSSAPIMicCallback(ServerAuthGSSAPIMicCallback cb) { 212 this._serverAuthGSSAPIMicCallback = cb; 213 if (cb is null) { 214 this._serverCallbacks.auth_gssapi_mic_function = null; 215 } else { 216 this._serverCallbacks.auth_gssapi_mic_function = &nativeServerAuthGSSAPIMicCallback; 217 } 218 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 219 } 220 221 @property ServerAuthNoneCallback serverAuthNoneCallback() { 222 return this._serverAuthNoneCallback; 223 } 224 225 @property void serverAuthNoneCallback(ServerAuthNoneCallback cb) { 226 this._serverAuthNoneCallback = cb; 227 if (cb is null) { 228 this._serverCallbacks.auth_none_function = null; 229 } else { 230 this._serverCallbacks.auth_none_function = &nativeServerAuthNoneCallback; 231 } 232 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 233 } 234 235 @property ServerAuthPasswordCallback serverAuthPasswordCallback() { 236 return this._serverAuthPasswordCallback; 237 } 238 239 @property void serverAuthPasswordCallback(ServerAuthPasswordCallback cb) { 240 this._serverAuthPasswordCallback = cb; 241 if (cb is null) { 242 this._serverCallbacks.auth_password_function = null; 243 } else { 244 this._serverCallbacks.auth_password_function = &nativeServerAuthPasswordCallback; 245 } 246 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 247 } 248 249 @property ServerAuthPublicKeyCallback serverAuthPublicKeyCallback() { 250 return this._serverAuthPublicKeyCallback; 251 } 252 253 @property void serverAuthPublicKeyCallback(ServerAuthPublicKeyCallback cb) { 254 this._serverAuthPublicKeyCallback = cb; 255 if (cb is null) { 256 this._serverCallbacks.auth_pubkey_function = null; 257 } else { 258 this._serverCallbacks.auth_pubkey_function = &nativeServerAuthPublicKeyCallback; 259 } 260 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 261 } 262 263 @property ServerChannelOpenRequestCallback serverChannelOpenRequestCallback() { 264 return this._serverChannelOpenRequestCallback; 265 } 266 267 @property void serverChannelOpenRequestCallback(ServerChannelOpenRequestCallback cb) { 268 this._serverChannelOpenRequestCallback = cb; 269 if (cb is null) { 270 this._serverCallbacks.channel_open_request_session_function = null; 271 } else { 272 this._serverCallbacks.channel_open_request_session_function = 273 &nativeServerChannelOpenRequestCallback; 274 } 275 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 276 } 277 278 @property ServerServiceRequestCallback serverServiceRequestCallback() { 279 return this._serverServiceRequestCallback; 280 } 281 282 @property void serverServiceRequestCallback(ServerServiceRequestCallback cb) { 283 this._serverServiceRequestCallback = cb; 284 if (cb is null) { 285 this._serverCallbacks.service_request_function = null; 286 } else { 287 this._serverCallbacks.service_request_function = &nativeServerServiceRequestCallback; 288 } 289 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 290 } 291 292 @property ServerGSSAPIAcceptSecCtxCallback serverGSSAPIAcceptSecCtxCallback() { 293 return this._serverGSSAPIAcceptSecCtxCallback; 294 } 295 296 @property void serverGSSAPIAcceptSecCtxCallback(ServerGSSAPIAcceptSecCtxCallback cb) { 297 this._serverGSSAPIAcceptSecCtxCallback = cb; 298 if (cb is null) { 299 this._serverCallbacks.gssapi_accept_sec_ctx_function = null; 300 } else { 301 this._serverCallbacks.gssapi_accept_sec_ctx_function = 302 &nativeServerGSSAPIAcceptSecCtxCallback; 303 } 304 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 305 } 306 307 @property ServerGSSAPISelectOidCallback serverGSSAPISelectOidCallback() { 308 return this._serverGSSAPISelectOidCallback; 309 } 310 311 @property void serverGSSAPIVerifyMicCallback(ServerGSSAPISelectOidCallback cb) { 312 this._serverGSSAPISelectOidCallback = cb; 313 if (cb is null) { 314 this._serverCallbacks.gssapi_select_oid_function = null; 315 } else { 316 this._serverCallbacks.gssapi_select_oid_function = &nativeServerGSSAPISelectOidCallback; 317 } 318 ssh_set_server_callbacks(this._session, &this._serverCallbacks); 319 } 320 321 322 @property string cipherIn() { 323 return fromStrZ(ssh_get_cipher_in(this._session)); 324 } 325 326 @property string cipherOut() { 327 return fromStrZ(ssh_get_cipher_out(this._session)); 328 } 329 330 @property string hmacIn() { 331 return fromStrZ(ssh_get_hmac_in(this._session)); 332 } 333 334 @property string hmacOut() { 335 return fromStrZ(ssh_get_hmac_out(this._session)); 336 } 337 338 @property string kexAlgo() { 339 return fromStrZ(ssh_get_kex_algo(this._session)); 340 } 341 342 @property string clientBanner() { 343 return fromStrZ(ssh_get_clientbanner(this._session)); 344 } 345 346 @property string serverBanner() { 347 return fromStrZ(ssh_get_serverbanner(this._session)); 348 } 349 350 @property string disconnectMessage() { 351 return fromStrZ(ssh_get_disconnect_message(this._session)); 352 } 353 354 @property socket_t fd() { 355 return ssh_get_fd(this._session); 356 } 357 358 @property string issueBanner() { 359 auto result = ssh_get_issue_banner(this._session); 360 scope(exit) ssh_string_free_char(result); 361 return copyFromStrZ(result); 362 } 363 364 @property int openSSHVersion() { 365 return ssh_get_openssh_version(this._session); 366 } 367 368 @property PollFlags pollFlags() { 369 return cast(PollFlags) ssh_get_poll_flags(this._session); 370 } 371 372 @property SSHKey publicKey() { 373 ssh_key key; 374 auto rc = ssh_get_publickey(this._session, &key); 375 checkForRCError(rc, this._session); 376 return new SSHKey(key); 377 } 378 379 @property SessionStatusFlags status() { 380 return cast(SessionStatusFlags) ssh_get_status(this._session); 381 } 382 383 @property SSHProtocolVersion sshProtocolVersion() { 384 auto result = ssh_get_version(this._session); 385 if (result < 0) { 386 throw new SSHException(this._session); 387 } 388 return cast(SSHProtocolVersion) result; 389 } 390 391 @property bool isBlocking() { 392 return ssh_is_blocking(this._session) == 0 ? false : true; 393 } 394 395 @property void isBlocking(bool v) { 396 ssh_set_blocking(this._session, v ? 1 : 0); 397 } 398 399 @property bool isConnected() { 400 return ssh_is_connected(this._session) == 0 ? false : true; 401 } 402 403 @property ServerKnownState serverKnownState() { 404 auto result = ssh_is_server_known(this._session); 405 if (result == ssh_server_known_e.SSH_SERVER_ERROR) { 406 throw new SSHException(this._session); 407 } 408 return cast(ServerKnownState) result; 409 } 410 411 @property string lastError() { 412 return copyFromStrZ(ssh_get_error(this._session)); 413 } 414 415 @property void authMethods(AuthMethod am) { 416 ssh_set_auth_methods(this._session, cast(int) am); 417 } 418 419 420 @property string host() { 421 return this.getOption(SessionOption.Host); 422 } 423 424 @property void host(string s) { 425 this.setOption(SessionOption.Host, s); 426 } 427 428 @property ushort port() { 429 uint value; 430 auto rc = ssh_options_get_port(this._session, &value); 431 checkForRCError(rc, this._session); 432 return cast(ushort) value; 433 } 434 435 @property void port(ushort port) { 436 this.setOption(SessionOption.Port, cast(uint) port); 437 } 438 439 @property void port(string port) { 440 this.setOption(SessionOption.PortStr, port); 441 } 442 443 @property string user() { 444 return this.getOption(SessionOption.User); 445 } 446 447 @property void user(string v) { 448 this.setOption(SessionOption.User, v); 449 } 450 451 @property string identity() { 452 return this.getOption(SessionOption.Identity); 453 } 454 455 @property void identity(string v) { 456 this.setOption(SessionOption.Identity, v); 457 } 458 459 @property string proxyCommand() { 460 return this.getOption(SessionOption.ProxyCommand); 461 } 462 463 @property void proxyCommand(string v) { 464 this.setOption(SessionOption.ProxyCommand, v); 465 } 466 467 @property void fd(socket_t v) { 468 this.setOption(SessionOption.Fd, v); 469 } 470 471 @property void bindAddr(string v) { 472 this.setOption(SessionOption.BindAddr, v); 473 } 474 475 @property void sshDir(string v) { 476 this.setOption(SessionOption.SshDir, v); 477 } 478 479 @property void knownHosts(string v) { 480 this.setOption(SessionOption.KnownHosts, v); 481 } 482 483 @property void timeout(long v) { 484 this.setOption(SessionOption.Timeout, v); 485 } 486 487 @property void timeoutUSec(long v) { 488 this.setOption(SessionOption.TimeoutUsec, v); 489 } 490 491 @property void allowSSH1(bool v) { 492 this.setOption(SessionOption.Ssh1, v); 493 } 494 495 @property void allowSSH2(bool v) { 496 this.setOption(SessionOption.Ssh2, v); 497 } 498 499 @property void logVerbosity(LogVerbosity v) { 500 this.setOption(SessionOption.LogVerbosity, cast(int) v); 501 } 502 503 @property void ciphersCS(string[] v) { 504 this.setOption(SessionOption.CiphersCS, v); 505 } 506 507 @property void ciphersCS(string v) { 508 this.setOption(SessionOption.CiphersCS, v); 509 } 510 511 @property void ciphersSC(string[] v) { 512 this.setOption(SessionOption.CiphersSC, v); 513 } 514 515 @property void ciphersSC(string v) { 516 this.setOption(SessionOption.CiphersSC, v); 517 } 518 519 @property void keyExchange(string[] v) { 520 this.setOption(SessionOption.KeyExchange, v); 521 } 522 523 @property void keyExchange(string v) { 524 this.setOption(SessionOption.KeyExchange, v); 525 } 526 527 @property void hostkeys(string[] v) { 528 this.setOption(SessionOption.Hostkeys, v); 529 } 530 531 @property void hostkeys(string v) { 532 this.setOption(SessionOption.Hostkeys, v); 533 } 534 535 @property void compressionCS(bool v) { 536 this.setOption(SessionOption.CompressionCS, v ? "yes" : "no"); 537 } 538 539 @property void compressionCS(string[] v) { 540 this.setOption(SessionOption.CompressionCS, v); 541 } 542 543 @property void compressionCS(string v) { 544 this.setOption(SessionOption.CompressionCS, v); 545 } 546 547 @property void compressionSC(bool v) { 548 this.setOption(SessionOption.CompressionSC, v ? "yes" : "no"); 549 } 550 551 @property void compressionSC(string[] v) { 552 this.setOption(SessionOption.CompressionSC, v); 553 } 554 555 @property void compressionSC(string v) { 556 this.setOption(SessionOption.CompressionSC, v); 557 } 558 559 @property void compression(bool v) { 560 this.setOption(SessionOption.Compression, v ? "yes" : "no"); 561 } 562 563 @property void compression(string[] v) { 564 this.setOption(SessionOption.Compression, v); 565 } 566 567 @property void compression(string v) { 568 this.setOption(SessionOption.Compression, v); 569 } 570 571 @property void compressonLevel(int v) { 572 assert(v >= 1 && v <= 9); 573 this.setOption(SessionOption.CompressionLevel, v); 574 } 575 576 @property strictHostkeyCheck(bool v) { 577 this.setOption(SessionOption.StrictHostkeyCheck, v); 578 } 579 580 @property gssapiServerIdentity(string v) { 581 this.setOption(SessionOption.GssapiServerIdentity, v); 582 } 583 584 @property gssapiClientIdentity(string v) { 585 this.setOption(SessionOption.GssapiClientIdentity, v); 586 } 587 588 @property gssapiDelegateCredentials(bool v) { 589 this.setOption(SessionOption.GssapiDelegateCredentials, v); 590 } 591 592 593 version (LIBSSH_WITH_GSSAPI) { 594 @property GSSAPICreds gssapiCreds() { 595 return cast(GSSAPICreds) ssh_gssapi_get_creds(this._session); 596 } 597 598 @property void gssapiCreds(GSSAPICreds v) { 599 ssh_gssapi_set_creds(this._session, cast(ssh_gssapi_creds) v); 600 } 601 } 602 603 604 this() { 605 version(Windows) 606 { 607 if (!is_ssh_initialized()) 608 ssh_init(); 609 } 610 auto newSession = ssh_new(); 611 checkForNullError(newSession, "Error while creating session object"); 612 this(newSession); 613 } 614 615 ~this() { 616 this._dispose(true); 617 } 618 619 override void dispose() { 620 this._dispose(false); 621 } 622 623 /** 624 * Returns false if the session is in nonblocking mode, and call must be done again. 625 **/ 626 bool connect() { 627 auto rc = ssh_connect(this._session); 628 if (rc == SSH_AGAIN) { 629 return false; 630 } 631 checkForRCError(rc, this._session); 632 return true; 633 } 634 635 void disconnect() { 636 ssh_disconnect(this._session); 637 } 638 639 /** 640 * Returns false on timeout 641 **/ 642 bool blockingFlush(int timeout) { 643 auto rc = ssh_blocking_flush(this._session, timeout); 644 if (rc == SSH_AGAIN) { 645 return false; 646 } 647 checkForRCError(rc, this._session); 648 return true; 649 } 650 651 SSHSession getCopy() { 652 ssh_session newSession; 653 auto rc = ssh_options_copy(this._session, &newSession); 654 checkForRCError(rc, this._session); 655 return new SSHSession(newSession); 656 } 657 658 string getOption(SessionOption type) { 659 char* value; 660 auto rc = ssh_options_get(this._session, cast(ssh_options_e) type, &value); 661 checkForRCError(rc, this._session); 662 scope(exit) ssh_string_free_char(value); 663 return copyFromStrZ(value); 664 } 665 666 void setOption(T)(SessionOption type, T value) { 667 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, &value); 668 checkForRCError(rc, this._session); 669 } 670 671 void setOption(SessionOption type, string value) { 672 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, toStrZ(value)); 673 checkForRCError(rc, this._session); 674 } 675 676 void setOption(SessionOption type, bool value) { 677 int intValue = value ? 1 : 0; 678 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, &intValue); 679 checkForRCError(rc, this._session); 680 } 681 682 void setOption(SessionOption type, string[] value) { 683 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, toStrZ(join(value, ","))); 684 checkForRCError(rc, this._session); 685 } 686 687 void parseConfig(string fileName) { 688 auto rc = ssh_options_parse_config(this._session, toStrZ(fileName)); 689 checkForRCError(rc, this._session); 690 } 691 692 void sendDebug(string message, bool alwaysDisplay) { 693 auto rc = ssh_send_debug(this._session, toStrZ(message), alwaysDisplay ? 1 : 0); 694 checkForRCError(rc, this._session); 695 } 696 697 void sendIgnore(string message) { 698 auto rc = ssh_send_ignore(this._session, toStrZ(message)); 699 checkForRCError(rc, this._session); 700 } 701 702 void setFdExcept() { 703 ssh_set_fd_except(this._session); 704 } 705 706 void setFdToRead() { 707 ssh_set_fd_toread(this._session); 708 } 709 710 void setFdToWrite() { 711 ssh_set_fd_towrite(this._session); 712 } 713 714 void silentDisconnect() { 715 ssh_silent_disconnect(this._session); 716 } 717 718 void writeKnownHost() { 719 auto rc = ssh_write_knownhost(this._session); 720 checkForRCError(rc, this._session); 721 } 722 723 SSHChannel newChannel() { 724 auto result = ssh_channel_new(this._session); 725 checkForNullError(result, this._session); 726 727 return new SSHChannel(this, result); 728 } 729 730 SSHMessage getMessage() { 731 auto result = ssh_message_get(this._session); 732 if (result is null) { 733 return null; 734 } 735 return new SSHMessage(this, result); 736 } 737 738 739 AuthMethod userauthList(string username) { 740 return cast(AuthMethod) ssh_userauth_list(this._session, toStrZ(username)); 741 } 742 743 AuthState userauthNone(string username) { 744 auto rc = ssh_userauth_none(this._session, toStrZ(username)); 745 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 746 throw new SSHException(this._session); 747 } 748 return cast(AuthState) rc; 749 } 750 751 AuthState userauthPassword(string username, string password) { 752 auto rc = ssh_userauth_password(this._session, toStrZ(username), toStrZ(password)); 753 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 754 throw new SSHException(this._session); 755 } 756 return cast(AuthState) rc; 757 } 758 759 AuthState userauthPublicKey(string username, const SSHKey privateKey) { 760 assert(privateKey !is null); 761 762 auto rc = ssh_userauth_publickey(this._session, toStrZ(username), privateKey._key); 763 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 764 throw new SSHException(this._session); 765 } 766 return cast(AuthState) rc; 767 } 768 769 AuthState userauthTryPublicKey(string username, const SSHKey publicKey) { 770 assert(publicKey !is null); 771 772 auto rc = ssh_userauth_publickey(this._session, toStrZ(username), publicKey._key); 773 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 774 throw new SSHException(this._session); 775 } 776 return cast(AuthState) rc; 777 } 778 779 AuthState userauthPublicKeyAuto(string username, string passPhrase) { 780 auto rc = ssh_userauth_publickey_auto(this._session, toStrZ(username), toStrZ(passPhrase)); 781 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 782 throw new SSHException(this._session); 783 } 784 return cast(AuthState) rc; 785 } 786 787 version(Windows) { } else { 788 AuthState userauthAgent(string username) { 789 auto rc = ssh_userauth_agent(this._session, toStrZ(username)); 790 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 791 throw new SSHException(this._session); 792 } 793 return cast(AuthState) rc; 794 } 795 } 796 797 AuthState userauthGSSAPI() { 798 auto rc = ssh_userauth_gssapi(this._session); 799 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 800 throw new SSHException(this._session); 801 } 802 return cast(AuthState) rc; 803 } 804 805 AuthState userauthKeyboardInteractive(string username) { 806 auto rc = ssh_userauth_kbdint(this._session, toStrZ(username), null); 807 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 808 throw new SSHException(this._session); 809 } 810 return cast(AuthState) rc; 811 } 812 813 int userauthKeyboardInteractiveGetNAnswers() { 814 auto result = ssh_userauth_kbdint_getnanswers(this._session); 815 if (result == SSH_ERROR) { 816 throw new SSHException(this._session); 817 } 818 return result; 819 } 820 821 string userauthKeyboardInteractiveGetAnswer(uint i) { 822 auto result = ssh_userauth_kbdint_getanswer(this._session, i); 823 if (result is null) { 824 throw new SSHException(this._session); 825 } 826 return fromStrZ(result); 827 } 828 829 int userauthKeyboardInteractiveGetNPrompts() { 830 auto result = ssh_userauth_kbdint_getnprompts(this._session); 831 if (result == SSH_ERROR) { 832 throw new SSHException(this._session); 833 } 834 return result; 835 } 836 837 string userauthKeyboardInteractiveGetPrompt(uint i, out bool echo) { 838 char echoChar; 839 auto result = ssh_userauth_kbdint_getprompt(this._session, i, &echoChar); 840 if (result is null) { 841 throw new SSHException(this._session); 842 } 843 echo = echoChar == 0 ? false : true; 844 return fromStrZ(result); 845 } 846 847 string userauthKeyboardInteractiveGetPrompt(uint i) { 848 auto result = ssh_userauth_kbdint_getprompt(this._session, i, null); 849 if (result is null) { 850 throw new SSHException(this._session); 851 } 852 return fromStrZ(result); 853 } 854 855 string userauthKeyboardInteractiveGetInstruction() { 856 auto result = ssh_userauth_kbdint_getinstruction(this._session); 857 if (result is null) { 858 throw new SSHException(this._session); 859 } 860 return fromStrZ(result); 861 } 862 863 string userauthKeyboardInteractiveGetName() { 864 auto result = ssh_userauth_kbdint_getname(this._session); 865 if (result is null) { 866 throw new SSHException(this._session); 867 } 868 return fromStrZ(result); 869 } 870 871 void userauthKeyboardInteractiveSetAnswer(uint i, string answer) { 872 auto result = ssh_userauth_kbdint_setanswer(this._session, i, toStrZ(answer)); 873 checkForRCError(result, this._session); 874 } 875 876 877 SSHChannel acceptForward(int timeoutMs, out ushort destPort) { 878 int destPortInt; 879 auto result = ssh_channel_accept_forward(this._session, timeoutMs, &destPortInt); 880 if (result is null) { 881 return null; 882 } 883 destPort = cast(ushort) destPortInt; 884 return new SSHChannel(this, result); 885 } 886 887 SSHChannel acceptForward(int timeoutMs) { 888 auto result = ssh_channel_accept_forward(this._session, timeoutMs, null); 889 if (result is null) { 890 return null; 891 } 892 return new SSHChannel(this, result); 893 } 894 895 /** 896 * return false if in nonblocking mode and call has to be done again. 897 * */ 898 bool listenForward(string address, ushort port, out ushort boundPort) { 899 int boundPortInt; 900 auto rc = ssh_channel_listen_forward(this._session, toStrZ(address), port, &boundPortInt); 901 if (rc == SSH_AGAIN) { 902 return false; 903 } 904 checkForRCError(rc, this._session); 905 boundPort = cast(ushort) boundPortInt; 906 return true; 907 } 908 909 void cancelForward(string address, ushort port) { 910 auto rc = ssh_channel_cancel_forward(this._session, toStrZ(address), port); 911 checkForRCError(rc, this._session); 912 } 913 914 915 SSHSCP newScp(SCPMode mode, string location) { 916 auto result = ssh_scp_new(this._session, mode, toStrZ(location)); 917 checkForNullError(result, this._session); 918 return new SSHSCP(this, result); 919 } 920 921 SFTPSession newSFTP() { 922 auto result = sftp_new(this._session); 923 auto rc = sftp_init(result); 924 if (rc != SSH_OK) { 925 throw new SFTPException(rc, this._session); 926 } 927 checkForNullError(result, this._session); 928 return new SFTPSession(this, result); 929 } 930 931 SFTPSession newSFTP(SSHChannel channel) { 932 auto result = sftp_new_channel(this._session, channel._channel); 933 auto rc = sftp_init(result); 934 if (rc != SSH_OK) { 935 throw new SFTPException(rc, this._session); 936 } 937 checkForNullError(result, this._session); 938 checkForNullError(result, this._session); 939 return new SFTPSession(this, result); 940 } 941 942 version (LIBSSH_WITH_SERVER) { 943 SFTPSession newSFTPServer(SSHChannel channel) { 944 auto result = sftp_server_new(this._session, channel._channel); 945 mixin CheckForNullError!(result, this._session); 946 return new SFTPSession(this, result); 947 } 948 } 949 950 951 void handleKeyExchange() { 952 auto rc = ssh_handle_key_exchange(this._session); 953 checkForRCError(rc, this._session); 954 } 955 956 package { 957 this(ssh_session session) { 958 this._session = session; 959 960 ssh_callbacks_init(this._sessionCallbacks); 961 this._sessionCallbacks.userdata = cast(void*) this; 962 // 963 ssh_callbacks_init(this._serverCallbacks); 964 this._serverCallbacks.userdata = cast(void*) this; 965 966 this._authCallback = null; 967 } 968 969 ssh_session _session; 970 971 void registerChannel(SSHChannel ch) { 972 this._channels ~= ch; 973 } 974 975 void freeChannel(SSHChannel toDel) { 976 this._channels = remove!(a => a == toDel)(this._channels); 977 } 978 } 979 980 private { 981 ssh_callbacks_struct _sessionCallbacks; 982 ssh_server_callbacks_struct _serverCallbacks; 983 984 SSHChannel[] _channels = []; 985 986 OnConnectStatusChangedCallback _onConnectStatusChangedCallback; 987 OnLogCallback _onLogCallback; 988 OnGlobalRequestCallback _onGlobalRequestCallback; 989 AuthCallback _authCallback; 990 MessageCallback _messageCallback; 991 OpenRequestX11Callback _openRequestX11Callback; 992 993 ServerAuthGSSAPIMicCallback _serverAuthGSSAPIMicCallback; 994 ServerAuthNoneCallback _serverAuthNoneCallback; 995 ServerAuthPasswordCallback _serverAuthPasswordCallback; 996 ServerAuthPublicKeyCallback _serverAuthPublicKeyCallback; 997 ServerChannelOpenRequestCallback _serverChannelOpenRequestCallback; 998 ServerServiceRequestCallback _serverServiceRequestCallback; 999 ServerGSSAPIAcceptSecCtxCallback _serverGSSAPIAcceptSecCtxCallback; 1000 ServerGSSAPISelectOidCallback _serverGSSAPISelectOidCallback; 1001 1002 void _dispose(bool fromDtor) { 1003 if (this._session !is null) { 1004 foreach (channel; this._channels) { 1005 channel.dispose(); 1006 } 1007 this._channels = null; 1008 1009 ssh_free(this._session); 1010 this._session = null; 1011 } 1012 } 1013 } 1014 } 1015 1016 bool sshFinalize() { 1017 auto rc = ssh_finalize(); 1018 return rc == SSH_OK ? true : false; 1019 } 1020 1021 private { 1022 extern(C) void nativeConnectStatusCallback(void* userdata, float status) { 1023 auto session = cast(SSHSession) userdata; 1024 1025 if (session is null || session._onConnectStatusChangedCallback) { 1026 return; 1027 } 1028 1029 session._onConnectStatusChangedCallback(session, status); 1030 } 1031 1032 extern(C) void nativeLogFunction(ssh_session session, int priority, const char* message, 1033 void* userdata) { 1034 auto sessionObj = cast(SSHSession) userdata; 1035 1036 if (sessionObj is null || sessionObj._onLogCallback is null) { 1037 return; 1038 } 1039 1040 sessionObj._onLogCallback(sessionObj, cast(LogLevel) priority, fromStrZ(message)); 1041 } 1042 1043 extern(C) int nativeSessionAuthCallback(const char *prompt, char *buf, size_t len, 1044 int echo, int verify, void *userdata) { 1045 auto session = cast(SSHSession) userdata; 1046 1047 if (session is null || session._authCallback is null) { 1048 return SSH_ERROR; 1049 } 1050 1051 try { 1052 auto result = session._authCallback(fromStrZ(prompt), echo == 0 ? false : true, 1053 verify == 0 ? false : true); 1054 if (result is null) { 1055 return SSH_ERROR; 1056 } 1057 1058 if (len < result.length + 1) { 1059 return SSH_ERROR; 1060 } 1061 1062 import core.stdc..string : memcpy; 1063 memcpy(buf, result.ptr, result.length); 1064 buf[result.length] = 0; 1065 1066 return SSH_OK; 1067 } catch (Exception) { 1068 return SSH_ERROR; 1069 } 1070 } 1071 1072 extern(C) void nativeOnGlobalRequest(ssh_session, ssh_message message, void* userdata) { 1073 auto sessionObj = cast(SSHSession) userdata; 1074 1075 if (sessionObj is null || sessionObj._onGlobalRequestCallback is null) { 1076 return; 1077 } 1078 1079 auto messageObj = new SSHMessage(sessionObj, message); 1080 scope(exit) messageObj.dispose(); 1081 sessionObj._onGlobalRequestCallback(sessionObj, messageObj); 1082 } 1083 1084 extern(C) int nativeOnMessageCallback(ssh_session session, ssh_message message, 1085 void* userdata) { 1086 auto sessionObj = cast(SSHSession) userdata; 1087 1088 if (sessionObj is null || sessionObj._messageCallback is null) { 1089 return SSH_ERROR; 1090 } 1091 1092 auto messageObj = new SSHMessage(sessionObj, message); 1093 scope(exit) messageObj.dispose(); 1094 1095 try { 1096 auto result = sessionObj._messageCallback(sessionObj, messageObj); 1097 if (!result) 1098 return SSH_ERROR; 1099 return SSH_OK; 1100 } catch (Exception) { 1101 return SSH_ERROR; 1102 } 1103 1104 } 1105 1106 extern(C) ssh_channel nativeOpenRequestX11Callback(ssh_session session, 1107 const char* originator_address, int originator_port, void* userdata) { 1108 auto sessionObj = cast(SSHSession) userdata; 1109 1110 if (sessionObj is null || sessionObj._openRequestX11Callback is null) { 1111 return null; 1112 } 1113 1114 try { 1115 auto result = sessionObj._openRequestX11Callback(sessionObj, 1116 fromStrZ(originator_address), cast(ushort) originator_port); 1117 if (result is null) { 1118 return null; 1119 } 1120 return result._channel; 1121 } catch (Exception) { 1122 return null; 1123 } 1124 } 1125 1126 extern(C) int nativeServerAuthGSSAPIMicCallback(ssh_session, const char* user, 1127 const char* principal, void* userdata) { 1128 auto sessionObj = cast(SSHSession) userdata; 1129 1130 if (sessionObj is null || sessionObj._serverAuthGSSAPIMicCallback is null) { 1131 return SSH_ERROR; 1132 } 1133 1134 try { 1135 return cast(int) sessionObj._serverAuthGSSAPIMicCallback(sessionObj, 1136 fromStrZ(user), fromStrZ(principal)); 1137 } catch (Exception) { 1138 return SSH_ERROR; 1139 } 1140 } 1141 1142 extern(C) int nativeServerAuthNoneCallback(ssh_session, const char* user, 1143 void* userdata) { 1144 auto sessionObj = cast(SSHSession) userdata; 1145 1146 if (sessionObj is null || sessionObj._serverAuthNoneCallback is null) { 1147 return SSH_ERROR; 1148 } 1149 1150 try { 1151 return cast(int) sessionObj._serverAuthNoneCallback(sessionObj, 1152 fromStrZ(user)); 1153 } catch (Exception) { 1154 return SSH_ERROR; 1155 } 1156 } 1157 1158 extern(C) int nativeServerAuthPasswordCallback(ssh_session, const char* user, 1159 const char* password, void* userdata) { 1160 auto sessionObj = cast(SSHSession) userdata; 1161 1162 if (sessionObj is null || sessionObj._serverAuthPasswordCallback is null) { 1163 return SSH_ERROR; 1164 } 1165 1166 try { 1167 return cast(int) sessionObj._serverAuthPasswordCallback(sessionObj, 1168 fromStrZ(user), fromStrZ(password)); 1169 } catch (Exception) { 1170 return SSH_ERROR; 1171 } 1172 } 1173 1174 extern(C) int nativeServerAuthPublicKeyCallback(ssh_session, const char* user, 1175 ssh_key_struct* key, byte signatureState, void* userdata) { 1176 auto sessionObj = cast(SSHSession) userdata; 1177 1178 if (sessionObj is null || sessionObj._serverAuthPublicKeyCallback is null) { 1179 return SSH_ERROR; 1180 } 1181 1182 try { 1183 return cast(int) sessionObj._serverAuthPublicKeyCallback(sessionObj, 1184 fromStrZ(user), new SSHKey(key), cast(PublicKeyState) signatureState); 1185 } catch (Exception) { 1186 return SSH_ERROR; 1187 } 1188 } 1189 1190 extern(C) ssh_channel nativeServerChannelOpenRequestCallback(ssh_session, void* userdata) { 1191 auto sessionObj = cast(SSHSession) userdata; 1192 1193 if (sessionObj is null || sessionObj._serverChannelOpenRequestCallback is null) { 1194 return null; 1195 } 1196 1197 try { 1198 auto result = sessionObj._serverChannelOpenRequestCallback(sessionObj); 1199 if (result is null) { 1200 return null; 1201 } 1202 return result._channel; 1203 } catch(Exception) { 1204 return null; 1205 } 1206 } 1207 1208 extern(C) int nativeServerServiceRequestCallback(ssh_session, const char* service, 1209 void* userdata) { 1210 auto sessionObj = cast(SSHSession) userdata; 1211 1212 if (sessionObj is null || sessionObj._serverServiceRequestCallback is null) { 1213 return SSH_ERROR; 1214 } 1215 1216 try { 1217 if (sessionObj._serverServiceRequestCallback(sessionObj, fromStrZ(service))) { 1218 return SSH_OK; 1219 } else { 1220 return SSH_ERROR; 1221 } 1222 } catch(Exception) { 1223 return SSH_ERROR; 1224 } 1225 } 1226 1227 extern(C) int nativeServerGSSAPIAcceptSecCtxCallback(ssh_session session, 1228 ssh_string input_token, ssh_string *output_token, void *userdata) { 1229 auto sessionObj = cast(SSHSession) userdata; 1230 1231 if (sessionObj is null || sessionObj._serverGSSAPIAcceptSecCtxCallback is null) { 1232 return SSH_ERROR; 1233 } 1234 1235 try { 1236 auto inputTokenData = ssh_string_data(input_token); 1237 auto inputTokenLen = ssh_string_len(input_token); 1238 string inputTokenStr = (cast(immutable(char)*) inputTokenData)[0 .. inputTokenLen]; 1239 string outputTokenStr; 1240 1241 auto result = sessionObj._serverGSSAPIAcceptSecCtxCallback(sessionObj, inputTokenStr, 1242 outputTokenStr); 1243 if (outputTokenStr is null) { 1244 *output_token = null; 1245 } else { 1246 *output_token = ssh_string_new(outputTokenStr.length); 1247 ssh_string_fill(*output_token, outputTokenStr.ptr, outputTokenStr.length); 1248 } 1249 1250 if (result) { 1251 return SSH_OK; 1252 } else { 1253 return SSH_ERROR; 1254 } 1255 } catch(Exception) { 1256 return SSH_ERROR; 1257 } 1258 } 1259 1260 extern(C) ssh_string nativeServerGSSAPISelectOidCallback(ssh_session session, const char* user, 1261 int n_oid, ssh_string* oids, void* userdata) { 1262 auto sessionObj = cast(SSHSession) userdata; 1263 1264 if (sessionObj is null || sessionObj._serverGSSAPISelectOidCallback is null) { 1265 string[] oidsArr = new string[n_oid]; 1266 for (auto i = 0; i < n_oid; i++) { 1267 auto oidData = ssh_string_data(oids[i]); 1268 auto oidLen = ssh_string_len(oids[i]); 1269 oidsArr[i] = (cast(immutable(char)*) oidData)[0 .. oidLen]; 1270 } 1271 auto result = sessionObj._serverGSSAPISelectOidCallback(sessionObj, 1272 fromStrZ(user), oidsArr); 1273 if (result is null) { 1274 return null; 1275 } 1276 1277 for (auto i = 0; i < n_oid; i++) { 1278 if (oidsArr[i] == result) { 1279 return oids[i]; 1280 } 1281 } 1282 1283 return null; 1284 } 1285 1286 try { 1287 return null; 1288 } catch(Exception) { 1289 return null; 1290 } 1291 } 1292 }