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 }