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 }