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 = &nativeAuthCallback; 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 auto newSession = ssh_new(); 606 checkForNullError(newSession, "Error while creating session object"); 607 this(newSession); 608 } 609 610 ~this() { 611 this._dispose(true); 612 } 613 614 override void dispose() { 615 this._dispose(false); 616 } 617 618 /** 619 * Returns false if the session is in nonblocking mode, and call must be done again. 620 **/ 621 bool connect() { 622 auto rc = ssh_connect(this._session); 623 if (rc == SSH_AGAIN) { 624 return false; 625 } 626 checkForRCError(rc, this._session); 627 return true; 628 } 629 630 void disconnect() { 631 ssh_disconnect(this._session); 632 } 633 634 /** 635 * Returns false on timeout 636 **/ 637 bool blockingFlush(int timeout) { 638 auto rc = ssh_blocking_flush(this._session, timeout); 639 if (rc == SSH_AGAIN) { 640 return false; 641 } 642 checkForRCError(rc, this._session); 643 return true; 644 } 645 646 SSHSession getCopy() { 647 ssh_session newSession; 648 auto rc = ssh_options_copy(this._session, &newSession); 649 checkForRCError(rc, this._session); 650 return new SSHSession(newSession); 651 } 652 653 string getOption(SessionOption type) { 654 char* value; 655 auto rc = ssh_options_get(this._session, cast(ssh_options_e) type, &value); 656 checkForRCError(rc, this._session); 657 scope(exit) ssh_string_free_char(value); 658 return copyFromStrZ(value); 659 } 660 661 void setOption(T)(SessionOption type, T value) { 662 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, &value); 663 checkForRCError(rc, this._session); 664 } 665 666 void setOption(SessionOption type, string value) { 667 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, toStrZ(value)); 668 checkForRCError(rc, this._session); 669 } 670 671 void setOption(SessionOption type, bool value) { 672 int intValue = value ? 1 : 0; 673 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, &intValue); 674 checkForRCError(rc, this._session); 675 } 676 677 void setOption(SessionOption type, string[] value) { 678 auto rc = ssh_options_set(this._session, cast(ssh_options_e) type, toStrZ(join(value, ","))); 679 checkForRCError(rc, this._session); 680 } 681 682 void parseConfig(string fileName) { 683 auto rc = ssh_options_parse_config(this._session, toStrZ(fileName)); 684 checkForRCError(rc, this._session); 685 } 686 687 void sendDebug(string message, bool alwaysDisplay) { 688 auto rc = ssh_send_debug(this._session, toStrZ(message), alwaysDisplay ? 1 : 0); 689 checkForRCError(rc, this._session); 690 } 691 692 void sendIgnore(string message) { 693 auto rc = ssh_send_ignore(this._session, toStrZ(message)); 694 checkForRCError(rc, this._session); 695 } 696 697 void setFdExcept() { 698 ssh_set_fd_except(this._session); 699 } 700 701 void setFdToRead() { 702 ssh_set_fd_toread(this._session); 703 } 704 705 void setFdToWrite() { 706 ssh_set_fd_towrite(this._session); 707 } 708 709 void silentDisconnect() { 710 ssh_silent_disconnect(this._session); 711 } 712 713 void writeKnownHost() { 714 auto rc = ssh_write_knownhost(this._session); 715 checkForRCError(rc, this._session); 716 } 717 718 SSHChannel newChannel() { 719 auto result = ssh_channel_new(this._session); 720 checkForNullError(result, this._session); 721 722 return new SSHChannel(this, result); 723 } 724 725 SSHMessage getMessage() { 726 auto result = ssh_message_get(this._session); 727 if (result is null) { 728 return null; 729 } 730 return new SSHMessage(this, result); 731 } 732 733 734 AuthMethod userauthList(string username) { 735 return cast(AuthMethod) ssh_userauth_list(this._session, toStrZ(username)); 736 } 737 738 AuthState userauthNone(string username) { 739 auto rc = ssh_userauth_none(this._session, toStrZ(username)); 740 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 741 throw new SSHException(this._session); 742 } 743 return cast(AuthState) rc; 744 } 745 746 AuthState userauthPassword(string username, string password) { 747 auto rc = ssh_userauth_password(this._session, toStrZ(username), toStrZ(password)); 748 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 749 throw new SSHException(this._session); 750 } 751 return cast(AuthState) rc; 752 } 753 754 AuthState userauthPublicKey(string username, const SSHKey privateKey) { 755 assert(privateKey !is null); 756 757 auto rc = ssh_userauth_publickey(this._session, toStrZ(username), privateKey._key); 758 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 759 throw new SSHException(this._session); 760 } 761 return cast(AuthState) rc; 762 } 763 764 AuthState userauthTryPublicKey(string username, const SSHKey publicKey) { 765 assert(publicKey !is null); 766 767 auto rc = ssh_userauth_publickey(this._session, toStrZ(username), publicKey._key); 768 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 769 throw new SSHException(this._session); 770 } 771 return cast(AuthState) rc; 772 } 773 774 AuthState userauthPublicKeyAuto(string username, string passPhrase) { 775 auto rc = ssh_userauth_publickey_auto(this._session, toStrZ(username), toStrZ(passPhrase)); 776 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 777 throw new SSHException(this._session); 778 } 779 return cast(AuthState) rc; 780 } 781 782 version(Windows) { } else { 783 AuthState userauthAgent(string username) { 784 auto rc = ssh_userauth_agent(this._session, toStrZ(username)); 785 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 786 throw new SSHException(this._session); 787 } 788 return cast(AuthState) rc; 789 } 790 } 791 792 AuthState userauthGSSAPI() { 793 auto rc = ssh_userauth_gssapi(this._session); 794 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 795 throw new SSHException(this._session); 796 } 797 return cast(AuthState) rc; 798 } 799 800 AuthState userauthKeyboardInteractive(string username) { 801 auto rc = ssh_userauth_kbdint(this._session, toStrZ(username), null); 802 if (rc == ssh_auth_e.SSH_AUTH_ERROR) { 803 throw new SSHException(this._session); 804 } 805 return cast(AuthState) rc; 806 } 807 808 int userauthKeyboardInteractiveGetNAnswers() { 809 auto result = ssh_userauth_kbdint_getnanswers(this._session); 810 if (result == SSH_ERROR) { 811 throw new SSHException(this._session); 812 } 813 return result; 814 } 815 816 string userauthKeyboardInteractiveGetAnswer(uint i) { 817 auto result = ssh_userauth_kbdint_getanswer(this._session, i); 818 if (result is null) { 819 throw new SSHException(this._session); 820 } 821 return fromStrZ(result); 822 } 823 824 int userauthKeyboardInteractiveGetNPrompts() { 825 auto result = ssh_userauth_kbdint_getnprompts(this._session); 826 if (result == SSH_ERROR) { 827 throw new SSHException(this._session); 828 } 829 return result; 830 } 831 832 string userauthKeyboardInteractiveGetPrompt(uint i, out bool echo) { 833 char echoChar; 834 auto result = ssh_userauth_kbdint_getprompt(this._session, i, &echoChar); 835 if (result is null) { 836 throw new SSHException(this._session); 837 } 838 echo = echoChar == 0 ? false : true; 839 return fromStrZ(result); 840 } 841 842 string userauthKeyboardInteractiveGetPrompt(uint i) { 843 auto result = ssh_userauth_kbdint_getprompt(this._session, i, null); 844 if (result is null) { 845 throw new SSHException(this._session); 846 } 847 return fromStrZ(result); 848 } 849 850 string userauthKeyboardInteractiveGetInstruction() { 851 auto result = ssh_userauth_kbdint_getinstruction(this._session); 852 if (result is null) { 853 throw new SSHException(this._session); 854 } 855 return fromStrZ(result); 856 } 857 858 string userauthKeyboardInteractiveGetName() { 859 auto result = ssh_userauth_kbdint_getname(this._session); 860 if (result is null) { 861 throw new SSHException(this._session); 862 } 863 return fromStrZ(result); 864 } 865 866 void userauthKeyboardInteractiveSetAnswer(uint i, string answer) { 867 auto result = ssh_userauth_kbdint_setanswer(this._session, i, toStrZ(answer)); 868 checkForRCError(result, this._session); 869 } 870 871 872 SSHChannel acceptForward(int timeoutMs, out ushort destPort) { 873 int destPortInt; 874 auto result = ssh_channel_accept_forward(this._session, timeoutMs, &destPortInt); 875 if (result is null) { 876 return null; 877 } 878 destPort = cast(ushort) destPortInt; 879 return new SSHChannel(this, result); 880 } 881 882 SSHChannel acceptForward(int timeoutMs) { 883 auto result = ssh_channel_accept_forward(this._session, timeoutMs, null); 884 if (result is null) { 885 return null; 886 } 887 return new SSHChannel(this, result); 888 } 889 890 /** 891 * return false if in nonblocking mode and call has to be done again. 892 * */ 893 bool listenForward(string address, ushort port, out ushort boundPort) { 894 int boundPortInt; 895 auto rc = ssh_channel_listen_forward(this._session, toStrZ(address), port, &boundPortInt); 896 if (rc == SSH_AGAIN) { 897 return false; 898 } 899 checkForRCError(rc, this._session); 900 boundPort = cast(ushort) boundPortInt; 901 return true; 902 } 903 904 void cancelForward(string address, ushort port) { 905 auto rc = ssh_channel_cancel_forward(this._session, toStrZ(address), port); 906 checkForRCError(rc, this._session); 907 } 908 909 910 SSHSCP newScp(SCPMode mode, string location) { 911 auto result = ssh_scp_new(this._session, mode, toStrZ(location)); 912 checkForNullError(result, this._session); 913 return new SSHSCP(this, result); 914 } 915 916 SFTPSession newSFTP() { 917 auto result = sftp_new(this._session); 918 checkForNullError(result, this._session); 919 return new SFTPSession(this, result); 920 } 921 922 SFTPSession newSFTP(SSHChannel channel) { 923 auto result = sftp_new_channel(this._session, channel._channel); 924 checkForNullError(result, this._session); 925 return new SFTPSession(this, result); 926 } 927 928 version (LIBSSH_WITH_SERVER) { 929 SFTPSession newSFTPServer(SSHChannel channel) { 930 auto result = sftp_server_new(this._session, channel._channel); 931 mixin CheckForNullError!(result, this._session); 932 return new SFTPSession(this, result); 933 } 934 } 935 936 937 void handleKeyExchange() { 938 auto rc = ssh_handle_key_exchange(this._session); 939 checkForRCError(rc, this._session); 940 } 941 942 package { 943 this(ssh_session session) { 944 this._session = session; 945 946 ssh_callbacks_init(this._sessionCallbacks); 947 this._sessionCallbacks.userdata = cast(void*) this; 948 // 949 ssh_callbacks_init(this._serverCallbacks); 950 this._serverCallbacks.userdata = cast(void*) this; 951 952 this._authCallback = null; 953 } 954 955 ssh_session _session; 956 957 void registerChannel(SSHChannel ch) { 958 this._channels ~= ch; 959 } 960 961 void freeChannel(SSHChannel toDel) { 962 this._channels = remove!(a => a == toDel)(this._channels); 963 } 964 } 965 966 private { 967 ssh_callbacks_struct _sessionCallbacks; 968 ssh_server_callbacks_struct _serverCallbacks; 969 970 SSHChannel[] _channels = []; 971 972 OnConnectStatusChangedCallback _onConnectStatusChangedCallback; 973 OnLogCallback _onLogCallback; 974 OnGlobalRequestCallback _onGlobalRequestCallback; 975 AuthCallback _authCallback; 976 MessageCallback _messageCallback; 977 OpenRequestX11Callback _openRequestX11Callback; 978 979 ServerAuthGSSAPIMicCallback _serverAuthGSSAPIMicCallback; 980 ServerAuthNoneCallback _serverAuthNoneCallback; 981 ServerAuthPasswordCallback _serverAuthPasswordCallback; 982 ServerAuthPublicKeyCallback _serverAuthPublicKeyCallback; 983 ServerChannelOpenRequestCallback _serverChannelOpenRequestCallback; 984 ServerServiceRequestCallback _serverServiceRequestCallback; 985 ServerGSSAPIAcceptSecCtxCallback _serverGSSAPIAcceptSecCtxCallback; 986 ServerGSSAPISelectOidCallback _serverGSSAPISelectOidCallback; 987 988 void _dispose(bool fromDtor) { 989 if (this._session !is null) { 990 foreach (channel; this._channels) { 991 channel.dispose(); 992 } 993 this._channels = null; 994 995 ssh_free(this._session); 996 this._session = null; 997 } 998 } 999 } 1000 } 1001 1002 bool sshFinalize() { 1003 auto rc = ssh_finalize(); 1004 return rc == SSH_OK ? true : false; 1005 } 1006 1007 private { 1008 extern(C) void nativeConnectStatusCallback(void* userdata, float status) { 1009 auto session = cast(SSHSession) userdata; 1010 1011 if (session is null || session._onConnectStatusChangedCallback) { 1012 return; 1013 } 1014 1015 session._onConnectStatusChangedCallback(session, status); 1016 } 1017 1018 extern(C) void nativeLogFunction(ssh_session session, int priority, const char* message, 1019 void* userdata) { 1020 auto sessionObj = cast(SSHSession) userdata; 1021 1022 if (sessionObj is null || sessionObj._onLogCallback is null) { 1023 return; 1024 } 1025 1026 sessionObj._onLogCallback(sessionObj, cast(LogLevel) priority, fromStrZ(message)); 1027 } 1028 1029 extern(C) int nativeAuthCallback(const char *prompt, char *buf, size_t len, 1030 int echo, int verify, void *userdata) { 1031 auto session = cast(SSHSession) userdata; 1032 1033 if (session is null || session._authCallback is null) { 1034 return SSH_ERROR; 1035 } 1036 1037 try { 1038 auto result = session._authCallback(fromStrZ(prompt), echo == 0 ? false : true, 1039 verify == 0 ? false : true); 1040 if (result is null) { 1041 return SSH_ERROR; 1042 } 1043 1044 if (len < result.length + 1) { 1045 return SSH_ERROR; 1046 } 1047 1048 import core.stdc..string : memcpy; 1049 memcpy(buf, result.ptr, result.length); 1050 buf[result.length] = 0; 1051 1052 return SSH_OK; 1053 } catch (Exception) { 1054 return SSH_ERROR; 1055 } 1056 } 1057 1058 extern(C) void nativeOnGlobalRequest(ssh_session, ssh_message message, void* userdata) { 1059 auto sessionObj = cast(SSHSession) userdata; 1060 1061 if (sessionObj is null || sessionObj._onGlobalRequestCallback is null) { 1062 return; 1063 } 1064 1065 auto messageObj = new SSHMessage(sessionObj, message); 1066 scope(exit) messageObj.dispose(); 1067 sessionObj._onGlobalRequestCallback(sessionObj, messageObj); 1068 } 1069 1070 extern(C) int nativeOnMessageCallback(ssh_session session, ssh_message message, 1071 void* userdata) { 1072 auto sessionObj = cast(SSHSession) userdata; 1073 1074 if (sessionObj is null || sessionObj._messageCallback is null) { 1075 return SSH_ERROR; 1076 } 1077 1078 auto messageObj = new SSHMessage(sessionObj, message); 1079 scope(exit) messageObj.dispose(); 1080 1081 try { 1082 auto result = sessionObj._messageCallback(sessionObj, messageObj); 1083 if (!result) 1084 return SSH_ERROR; 1085 return SSH_OK; 1086 } catch (Exception) { 1087 return SSH_ERROR; 1088 } 1089 1090 } 1091 1092 extern(C) ssh_channel nativeOpenRequestX11Callback(ssh_session session, 1093 const char* originator_address, int originator_port, void* userdata) { 1094 auto sessionObj = cast(SSHSession) userdata; 1095 1096 if (sessionObj is null || sessionObj._openRequestX11Callback is null) { 1097 return null; 1098 } 1099 1100 try { 1101 auto result = sessionObj._openRequestX11Callback(sessionObj, 1102 fromStrZ(originator_address), cast(ushort) originator_port); 1103 if (result is null) { 1104 return null; 1105 } 1106 return result._channel; 1107 } catch (Exception) { 1108 return null; 1109 } 1110 } 1111 1112 extern(C) int nativeServerAuthGSSAPIMicCallback(ssh_session, const char* user, 1113 const char* principal, void* userdata) { 1114 auto sessionObj = cast(SSHSession) userdata; 1115 1116 if (sessionObj is null || sessionObj._serverAuthGSSAPIMicCallback is null) { 1117 return SSH_ERROR; 1118 } 1119 1120 try { 1121 return cast(int) sessionObj._serverAuthGSSAPIMicCallback(sessionObj, 1122 fromStrZ(user), fromStrZ(principal)); 1123 } catch (Exception) { 1124 return SSH_ERROR; 1125 } 1126 } 1127 1128 extern(C) int nativeServerAuthNoneCallback(ssh_session, const char* user, 1129 void* userdata) { 1130 auto sessionObj = cast(SSHSession) userdata; 1131 1132 if (sessionObj is null || sessionObj._serverAuthNoneCallback is null) { 1133 return SSH_ERROR; 1134 } 1135 1136 try { 1137 return cast(int) sessionObj._serverAuthNoneCallback(sessionObj, 1138 fromStrZ(user)); 1139 } catch (Exception) { 1140 return SSH_ERROR; 1141 } 1142 } 1143 1144 extern(C) int nativeServerAuthPasswordCallback(ssh_session, const char* user, 1145 const char* password, void* userdata) { 1146 auto sessionObj = cast(SSHSession) userdata; 1147 1148 if (sessionObj is null || sessionObj._serverAuthPasswordCallback is null) { 1149 return SSH_ERROR; 1150 } 1151 1152 try { 1153 return cast(int) sessionObj._serverAuthPasswordCallback(sessionObj, 1154 fromStrZ(user), fromStrZ(password)); 1155 } catch (Exception) { 1156 return SSH_ERROR; 1157 } 1158 } 1159 1160 extern(C) int nativeServerAuthPublicKeyCallback(ssh_session, const char* user, 1161 ssh_key_struct* key, byte signatureState, void* userdata) { 1162 auto sessionObj = cast(SSHSession) userdata; 1163 1164 if (sessionObj is null || sessionObj._serverAuthPublicKeyCallback is null) { 1165 return SSH_ERROR; 1166 } 1167 1168 try { 1169 return cast(int) sessionObj._serverAuthPublicKeyCallback(sessionObj, 1170 fromStrZ(user), new SSHKey(key), cast(PublicKeyState) signatureState); 1171 } catch (Exception) { 1172 return SSH_ERROR; 1173 } 1174 } 1175 1176 extern(C) ssh_channel nativeServerChannelOpenRequestCallback(ssh_session, void* userdata) { 1177 auto sessionObj = cast(SSHSession) userdata; 1178 1179 if (sessionObj is null || sessionObj._serverChannelOpenRequestCallback is null) { 1180 return null; 1181 } 1182 1183 try { 1184 auto result = sessionObj._serverChannelOpenRequestCallback(sessionObj); 1185 if (result is null) { 1186 return null; 1187 } 1188 return result._channel; 1189 } catch(Exception) { 1190 return null; 1191 } 1192 } 1193 1194 extern(C) int nativeServerServiceRequestCallback(ssh_session, const char* service, 1195 void* userdata) { 1196 auto sessionObj = cast(SSHSession) userdata; 1197 1198 if (sessionObj is null || sessionObj._serverServiceRequestCallback is null) { 1199 return SSH_ERROR; 1200 } 1201 1202 try { 1203 if (sessionObj._serverServiceRequestCallback(sessionObj, fromStrZ(service))) { 1204 return SSH_OK; 1205 } else { 1206 return SSH_ERROR; 1207 } 1208 } catch(Exception) { 1209 return SSH_ERROR; 1210 } 1211 } 1212 1213 extern(C) int nativeServerGSSAPIAcceptSecCtxCallback(ssh_session session, 1214 ssh_string input_token, ssh_string *output_token, void *userdata) { 1215 auto sessionObj = cast(SSHSession) userdata; 1216 1217 if (sessionObj is null || sessionObj._serverGSSAPIAcceptSecCtxCallback is null) { 1218 return SSH_ERROR; 1219 } 1220 1221 try { 1222 auto inputTokenData = ssh_string_data(input_token); 1223 auto inputTokenLen = ssh_string_len(input_token); 1224 string inputTokenStr = (cast(immutable(char)*) inputTokenData)[0 .. inputTokenLen]; 1225 string outputTokenStr; 1226 1227 auto result = sessionObj._serverGSSAPIAcceptSecCtxCallback(sessionObj, inputTokenStr, 1228 outputTokenStr); 1229 if (outputTokenStr is null) { 1230 *output_token = null; 1231 } else { 1232 *output_token = ssh_string_new(outputTokenStr.length); 1233 ssh_string_fill(*output_token, outputTokenStr.ptr, outputTokenStr.length); 1234 } 1235 1236 if (result) { 1237 return SSH_OK; 1238 } else { 1239 return SSH_ERROR; 1240 } 1241 } catch(Exception) { 1242 return SSH_ERROR; 1243 } 1244 } 1245 1246 extern(C) ssh_string nativeServerGSSAPISelectOidCallback(ssh_session session, const char* user, 1247 int n_oid, ssh_string* oids, void* userdata) { 1248 auto sessionObj = cast(SSHSession) userdata; 1249 1250 if (sessionObj is null || sessionObj._serverGSSAPISelectOidCallback is null) { 1251 string[] oidsArr = new string[n_oid]; 1252 for (auto i = 0; i < n_oid; i++) { 1253 auto oidData = ssh_string_data(oids[i]); 1254 auto oidLen = ssh_string_len(oids[i]); 1255 oidsArr[i] = (cast(immutable(char)*) oidData)[0 .. oidLen]; 1256 } 1257 auto result = sessionObj._serverGSSAPISelectOidCallback(sessionObj, 1258 fromStrZ(user), oidsArr); 1259 if (result is null) { 1260 return null; 1261 } 1262 1263 for (auto i = 0; i < n_oid; i++) { 1264 if (oidsArr[i] == result) { 1265 return oids[i]; 1266 } 1267 } 1268 1269 return null; 1270 } 1271 1272 try { 1273 return null; 1274 } catch(Exception) { 1275 return null; 1276 } 1277 } 1278 }