1 module libssh.server; 2 3 import std.string; 4 5 import libssh.c_bindings.libssh; 6 import libssh.c_bindings.callbacks; 7 import libssh.c_bindings.server; 8 import libssh.errors; 9 import libssh.utils; 10 import libssh.session; 11 import libssh.channel; 12 import libssh.message; 13 14 enum BindOption : int { 15 BindAddr = ssh_bind_options_e.SSH_BIND_OPTIONS_BINDADDR, 16 BindPort = ssh_bind_options_e.SSH_BIND_OPTIONS_BINDPORT, 17 BindPortStr = ssh_bind_options_e.SSH_BIND_OPTIONS_BINDPORT_STR, 18 Hostkey = ssh_bind_options_e.SSH_BIND_OPTIONS_HOSTKEY, 19 DsaKey = ssh_bind_options_e.SSH_BIND_OPTIONS_DSAKEY, 20 RsaKey = ssh_bind_options_e.SSH_BIND_OPTIONS_RSAKEY, 21 Banner = ssh_bind_options_e.SSH_BIND_OPTIONS_BANNER, 22 LogVerbosity = ssh_bind_options_e.SSH_BIND_OPTIONS_LOG_VERBOSITY, 23 LogVerbosityStr = ssh_bind_options_e.SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, 24 EcdsaKey = ssh_bind_options_e.SSH_BIND_OPTIONS_ECDSAKEY 25 } 26 27 class SSHBind : Disposable { 28 alias OnIncomingConnectionCallback = void delegate(); 29 30 @property OnIncomingConnectionCallback onIncomingConnectionCallback() { 31 return this._onIncomingConnectionCallback; 32 } 33 34 @property void onIncomingConnectionCallback(OnIncomingConnectionCallback cb) { 35 this._onIncomingConnectionCallback = cb; 36 if (cb is null) { 37 this._callbacks.incoming_connection = null; 38 } else { 39 this._callbacks.incoming_connection = &nativeOnIncomingConnection; 40 } 41 ssh_bind_set_callbacks(this._bind, &this._callbacks, cast(void*) this); 42 } 43 44 @property void blocking(bool v) { 45 ssh_bind_set_blocking(this._bind, v ? 1 : 0); 46 } 47 48 @property socket_t fd() { 49 return ssh_bind_get_fd(this._bind); 50 } 51 52 @property void fd(socket_t fd) { 53 ssh_bind_set_fd(this._bind, fd); 54 } 55 56 57 @property void hostkey(string v) { 58 this.setOption(BindOption.Hostkey, v); 59 } 60 61 @property void bindAddress(string v) { 62 this.setOption(BindOption.BindAddr, v); 63 } 64 65 @property void bindPort(ushort v) { 66 this.setOption(BindOption.BindPort, cast(uint) v); 67 } 68 69 @property void bindPortStr(string v) { 70 this.setOption(BindOption.BindPortStr, v); 71 } 72 73 @property void logVerbosity(LogVerbosity v) { 74 this.setOption(BindOption.LogVerbosity, cast(int) v); 75 } 76 77 @property void logVerbosityStr(string v) { 78 this.setOption(BindOption.LogVerbosityStr, v); 79 } 80 81 @property void dsaKey(string v) { 82 this.setOption(BindOption.DsaKey, v); 83 } 84 85 @property void rsaKey(string v) { 86 this.setOption(BindOption.RsaKey, v); 87 } 88 89 @property void ecdsaKey(string v) { 90 this.setOption(BindOption.EcdsaKey, v); 91 } 92 93 @property void banner(string v) { 94 this.setOption(BindOption.Banner, v); 95 } 96 97 98 SSHSession accept() { 99 auto session = new SSHSession(); 100 if (session is null) { 101 throw new SSHException("Error while preallocating session"); 102 } 103 scope(failure) session.dispose(); 104 105 return this.accept(session); 106 } 107 108 SSHSession accept(SSHSession session) { 109 auto rc = ssh_bind_accept(this._bind, session._session); 110 checkForRCError(rc, this._bind); 111 return session; 112 } 113 114 SSHSession accept(socket_t fd) { 115 auto session = new SSHSession(); 116 if (session is null) { 117 throw new SSHException("Error while preallocating session"); 118 } 119 scope(failure) session.dispose(); 120 121 return this.accept(session, fd); 122 } 123 124 SSHSession accept(SSHSession session, socket_t fd) { 125 auto rc = ssh_bind_accept_fd(this._bind, session._session, fd); 126 checkForRCError(rc, this._bind); 127 return session; 128 } 129 130 void listen() { 131 auto rc = ssh_bind_listen(this._bind); 132 checkForRCError(rc, this._bind); 133 } 134 135 void fdToAccept() { 136 ssh_bind_fd_toaccept(this._bind); 137 } 138 139 void setOption(T)(BindOption type, T value) { 140 auto rc = ssh_bind_options_set(this._bind, cast(ssh_bind_options_e) type, &value); 141 checkForRCError(rc, this._bind); 142 } 143 144 void setOption(BindOption type, string value) { 145 auto rc = ssh_bind_options_set(this._bind, cast(ssh_bind_options_e) type, toStrZ(value)); 146 checkForRCError(rc, this._bind); 147 } 148 149 void setOption(BindOption type, bool value) { 150 int intValue = value ? 1 : 0; 151 auto rc = ssh_bind_options_set(this._bind, cast(ssh_bind_options_e) type, &intValue); 152 checkForRCError(rc, this._bind); 153 } 154 155 void setOption(BindOption type, string[] value) { 156 auto rc = ssh_bind_options_set(this._bind, cast(ssh_bind_options_e) type, 157 toStrZ(join(value, ","))); 158 checkForRCError(rc, this._bind); 159 } 160 161 this() { 162 auto result = ssh_bind_new(); 163 if (result is null) { 164 throw new SSHException("Error while creating new bind object"); 165 } 166 this._bind = result; 167 168 ssh_callbacks_init(this._callbacks); 169 } 170 171 ~this() { 172 this._dispose(true); 173 } 174 175 override void dispose() { 176 this._dispose(false); 177 } 178 179 private { 180 void _dispose(bool fromDtor) { 181 if (this._bind !is null) { 182 ssh_bind_free(this._bind); 183 this._bind = null; 184 } 185 } 186 187 ssh_bind _bind; 188 ssh_bind_callbacks_struct _callbacks; 189 190 OnIncomingConnectionCallback _onIncomingConnectionCallback; 191 } 192 } 193 194 195 196 private { 197 extern (C) void nativeOnIncomingConnection(ssh_bind, void* userdata) { 198 auto bind = cast(SSHBind) userdata; 199 200 if (bind is null || bind._onIncomingConnectionCallback is null) { 201 return; 202 } 203 204 if (bind !is null) { 205 bind._onIncomingConnectionCallback(); 206 } 207 } 208 }