24
-include("ssh_connect.hrl").
26
-export([start/0, start/1, stop/0, attach/2, attach/3,
27
connect/3, close/1, daemon/1, daemon/2, daemon/3,
28
stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2,
29
shell/1, shell/2, shell/3]).
31
%%--------------------------------------------------------------------
32
%% Function: start([, Type]) -> ok
34
%% Type = permanent | transient | temporary
36
%% Description: Starts the inets application. Default type
37
%% is temporary. see application(3)
38
%%--------------------------------------------------------------------
29
40
application:start(ssh).
43
application:start(ssh, Type).
45
%%--------------------------------------------------------------------
46
%% Function: stop() -> ok
48
%% Description: Stops the inets application.
49
%%--------------------------------------------------------------------
32
51
application:stop(ssh).
53
%%--------------------------------------------------------------------
54
%% Function: connect(Host, Port, Options) -> ConnectionRef
58
%% Options - [{Option, Value}]
60
%% Description: Starts an ssh connection.
61
%%--------------------------------------------------------------------
62
connect(Host, Port, Options) ->
63
{SocketOpts, Opts} = handle_options(Options),
64
Timeout = proplists:get_value(timeout, Opts, ?DEFAULT_TIMEOUT),
65
DisableIpv6 = proplists:get_value(ip_v6_disabled, Opts, false),
66
{Address, Inet} = ip_address_and_inetopt(Host, DisableIpv6),
67
try sshc_sup:start_child([[{address, Address}, {port, Port},
69
{channel_pid, self()},
70
{socket_opts, [Inet | SocketOpts]},
71
{ssh_opts, [{host, Host}| Opts]}]]) of
72
{ok, ConnectionSup} ->
74
ssh_connection_sup:connection_manager(ConnectionSup),
76
{Manager, is_connected} ->
78
%% When the connection fails
79
%% ssh_connection_sup:connection_manager
80
%% might return undefined as the connection manager
81
%% could allready have terminated, so we will not
82
%% match the Manager in this case
83
{_, not_connected, {error, Reason}} ->
85
{_, not_connected, Other} ->
89
exit(ConnectionSup, shutdown),
94
{error, ssh_not_started}
97
%%--------------------------------------------------------------------
98
%% Function: close(ConnectionRef) -> ok
100
%% Description: Closes an ssh connection.
101
%%--------------------------------------------------------------------
102
close(ConnectionRef) ->
103
ssh_connection_manager:stop(ConnectionRef).
105
%%--------------------------------------------------------------------
106
%% Function: daemon(Port) ->
107
%% daemon(Port, Opts) ->
108
%% daemon(Address, Port, Options) -> SshSystemRef
110
%% Description: Starts a server listening for SSH connections
111
%% on the given port.
112
%%--------------------------------------------------------------------
116
daemon(Port, Opts) ->
117
daemon(any, Port, Opts).
119
daemon(HostAddr, Port, Opts) ->
120
Shell = proplists:get_value(shell, Opts, {shell, start, []}),
121
DisableIpv6 = proplists:get_value(ip_v6_disabled, Opts, false),
122
{Address, Inet} = case HostAddr of
124
{ok, Host} = inet:gethostname(),
125
ip_address_and_inetopt(Host, DisableIpv6);
126
Str when is_list(Str) ->
127
ip_address_and_inetopt(Str, DisableIpv6);
133
start_daemon(Address, Port, [{role, server},
134
{shell, Shell} | Opts], Inet).
136
%%--------------------------------------------------------------------
137
%% Function: stop_listener(SysRef) -> ok
138
%% stop_listener(Address, Port) -> ok
141
%% Description: Stops the listener, but leaves
142
%% existing connections started by the listener up and running.
143
%%--------------------------------------------------------------------
144
stop_listener(SysSup) ->
145
ssh_system_sup:stop_listener(SysSup).
146
stop_listener(Address, Port) ->
147
ssh_system_sup:stop_listener(Address, Port).
149
%%--------------------------------------------------------------------
150
%% Function: stop_daemon(SysRef) -> ok
151
%%% stop_daemon(Address, Port) -> ok
154
%% Description: Stops the listener and all connections started by
156
%%--------------------------------------------------------------------
157
stop_daemon(SysSup) ->
158
ssh_system_sup:stop_system(SysSup).
159
stop_daemon(Address, Port) ->
160
ssh_system_sup:stop_system(Address, Port).
162
%%--------------------------------------------------------------------
163
%% Function: shell(Host [,Port,Options]) ->
167
%% Options = [{Option, Value}]
169
%% Description: Starts an interactive shell to an SSH server on the
170
%% given <Host>. The function waits for user input,
171
%% and will not return until the remote shell is ended.(e.g. on
172
%% exit from the shell)
173
%%--------------------------------------------------------------------
175
shell(Host, ?SSH_DEFAULT_PORT, []).
176
shell(Host, Options) ->
177
shell(Host, ?SSH_DEFAULT_PORT, Options).
178
shell(Host, Port, Options) ->
179
ssh_ssh:connect(Host, Port, Options).
181
%% TODO: Should this be a supported API function, used by
182
%% sftp and ssh_ssh. Does it acctually work? Should be better tested
183
%% before made public!
184
attach(ConnectionRef, Timeout) ->
185
ssh_connection_manager:attach(ConnectionRef, Timeout).
187
attach(ConnectionRef, ChannelPid, Timeout) ->
188
ssh_connection_manager:attach(ConnectionRef, ChannelPid, Timeout).
190
%%--------------------------------------------------------------------
191
%%% Internal functions
192
%%--------------------------------------------------------------------
193
start_daemon(Address, Port, Options, Inet) ->
194
{SocketOpts, Opts} = handle_options([{ip, Address} | Options]),
195
case ssh_system_sup:system_supervisor(Address, Port) of
197
try sshd_sup:start_child([{address, Address},
198
{port, Port}, {role, server},
199
{socket_opts, [Inet | SocketOpts]},
200
{ssh_opts, Opts}]) of
203
{error, {already_started, _}} ->
207
{error, ssh_not_started}
210
case ssh_system_sup:restart_acceptor(Address, Port) of
218
handle_options(Opts) ->
219
handle_options(proplists:unfold(Opts), [], []).
220
handle_options([], SockOpts, Opts) ->
222
%% TODO: Could do some type checks here on plain ssh-opts
223
handle_options([{system_dir, _} = Opt | Rest], SockOpts, Opts) ->
224
handle_options(Rest, SockOpts, [Opt | Opts]);
225
handle_options([{user_dir, _} = Opt | Rest], SockOpts, Opts) ->
226
handle_options(Rest, SockOpts, [Opt | Opts]);
227
handle_options([{user_dir_fun, _} = Opt | Rest], SockOpts, Opts) ->
228
handle_options(Rest, SockOpts, [Opt | Opts]);
229
handle_options([{silently_accept_hosts, _} = Opt | Rest], SockOpts, Opts) ->
230
handle_options(Rest, SockOpts, [Opt | Opts]);
231
handle_options([{user_interaction, _} = Opt | Rest], SockOpts, Opts) ->
232
handle_options(Rest, SockOpts, [Opt | Opts]);
233
handle_options([{public_key_alg, _} = Opt | Rest], SockOpts, Opts) ->
234
handle_options(Rest, SockOpts, [Opt | Opts]);
235
handle_options([{connect_timeout, _} = Opt | Rest], SockOpts, Opts) ->
236
handle_options(Rest, SockOpts, [Opt | Opts]);
237
handle_options([{user, _} = Opt | Rest], SockOpts, Opts) ->
238
handle_options(Rest, SockOpts, [Opt | Opts]);
239
handle_options([{password, _} = Opt | Rest], SockOpts, Opts) ->
240
handle_options(Rest, SockOpts, [Opt | Opts]);
241
handle_options([{user_passwords, _} = Opt | Rest], SockOpts, Opts) ->
242
handle_options(Rest, SockOpts, [Opt | Opts]);
243
handle_options([{pwdfun, _} = Opt | Rest], SockOpts, Opts) ->
244
handle_options(Rest, SockOpts, [Opt | Opts]);
245
handle_options([{user_auth, _} = Opt | Rest], SockOpts, Opts) ->
246
handle_options(Rest, SockOpts, [Opt | Opts]);
247
handle_options([{key_cb, _} = Opt | Rest], SockOpts, Opts) ->
248
handle_options(Rest, SockOpts, [Opt | Opts]);
249
handle_options([{role, _} = Opt | Rest], SockOpts, Opts) ->
250
handle_options(Rest, SockOpts, [Opt | Opts]);
251
handle_options([{channel, _} = Opt | Rest], SockOpts, Opts) ->
252
handle_options(Rest, SockOpts, [Opt | Opts]);
253
handle_options([{compression, _} = Opt | Rest], SockOpts, Opts) ->
254
handle_options(Rest, SockOpts, [Opt | Opts]);
255
handle_options([{allow_user_interaction, _} = Opt | Rest], SockOpts, Opts) ->
256
handle_options(Rest, SockOpts, [Opt | Opts]);
257
handle_options([{passive_subsys, _} = Opt | Rest], SockOpts, Opts) ->
258
handle_options(Rest, SockOpts, [Opt | Opts]);
259
handle_options([{infofun, _} = Opt | Rest], SockOpts, Opts) ->
260
handle_options(Rest, SockOpts, [Opt | Opts]);
261
handle_options([{connectfun, _} = Opt | Rest], SockOpts, Opts) ->
262
handle_options(Rest, SockOpts, [Opt | Opts]);
263
handle_options([{disconnectfun , _} = Opt | Rest], SockOpts, Opts) ->
264
handle_options(Rest, SockOpts, [Opt | Opts]);
265
handle_options([{failfun, _} = Opt | Rest], SockOpts, Opts) ->
266
handle_options(Rest, SockOpts, [Opt | Opts]);
267
handle_options([{ip_v6_disabled, _} = Opt | Rest], SockOpts, Opts) ->
268
handle_options(Rest, SockOpts, [Opt | Opts]);
269
handle_options([{ip, _} = Opt | Rest], SockOpts, Opts) ->
270
handle_options(Rest, [Opt |SockOpts], Opts);
271
handle_options([{ifaddr, _} = Opt | Rest], SockOpts, Opts) ->
272
handle_options(Rest, [Opt |SockOpts], Opts);
273
handle_options([{fd, _} = Opt | Rest], SockOpts, Opts) ->
274
handle_options(Rest, [Opt | SockOpts], Opts);
275
handle_options([{nodelay, _} = Opt | Rest], SockOpts, Opts) ->
276
handle_options(Rest, [Opt | SockOpts], Opts);
277
handle_options([Opt | Rest], SockOpts, Opts) ->
278
handle_options(Rest, SockOpts, [Opt | Opts]).
281
ip_address_and_inetopt(Host, true) ->
282
{ok, Ip} = inet:getaddr(Host, inet),
285
ip_address_and_inetopt("localhost", false) ->
286
{ok, Host} = inet:gethostname(),
287
{_, Inet} = ip_address_and_inetopt(Host, false),
288
{ok, Ip} = inet:getaddr("localhost", Inet),
291
ip_address_and_inetopt(Host, false) ->
292
{{ok, Ip}, Inet} = case (catch inet:getaddr(Host,inet6)) of
293
{ok, {0, 0, 0, 0, 0, 16#ffff, _, _}} ->
294
{inet:getaddr(Host, inet), inet};
296
{{ok, IPAddr}, inet6};
298
{inet:getaddr(Host, inet), inet}