<div dir="ltr"><div><div><div>Hi!<br><br></div>As I mentioned in my previous post, ssh will change quite a lot in the upcoming release so please<br></div>try it when it comes and let me now if there are any further improvements that you need.<br>
<br></div>Regards Ingela Erlang/OTP team - Ericsson AB<br><div><div><div><div><div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/12/10 OvermindDL1 <span dir="ltr"><<a href="mailto:overminddl1@gmail.com" target="_blank">overminddl1@gmail.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Be calling the option with Exec added to it with a fixed<br>
handle_ssh_option test to test for if a fun as well.<br>
<div class="HOEnZb"><div class="h5"><br>
On Tue, Dec 10, 2013 at 3:15 PM, OvermindDL1 <<a href="mailto:overminddl1@gmail.com">overminddl1@gmail.com</a>> wrote:<br>
> Nevermind, and for future documentation I found this in ssh_cli.erl:<br>
> ```<br>
> start_shell(_ConnectionHandler, Cmd, #state{exec={M, F, A}} = State) -><br>
>     Group = group:start(self(), {M, F, A++[Cmd]}, [{echo, false}]),<br>
>     State#state{group = Group, buf = empty_buf()};<br>
> start_shell(ConnectionHandler, Cmd, #state{exec=Shell} = State) when<br>
> is_function(Shell) -><br>
><br>
>     ConnectionInfo = ssh_connection_handler:info(ConnectionHandler,<br>
>                                                  [peer, user]),<br>
>     {ok, User} =<br>
>         proplists:get_value(user, ConnectionInfo),<br>
>     ShellFun =<br>
>         case erlang:fun_info(Shell, arity) of<br>
>             {arity, 1} -><br>
>                 fun() -> Shell(Cmd) end;<br>
>             {arity, 2} -><br>
>                 fun() -> Shell(Cmd, User) end;<br>
>             {arity, 3} -><br>
>                 [{_, PeerAddr}] =<br>
>                     proplists:get_value(peer, ConnectionInfo),<br>
>                 fun() -> Shell(Cmd, User, PeerAddr) end;<br>
>             _ -><br>
>                 Shell<br>
>         end,<br>
>     Echo = get_echo(State#state.pty),<br>
>     Group = group:start(self(), ShellFun, [{echo,Echo}]),<br>
>     State#state{group = Group, buf = empty_buf()}.<br>
> ```<br>
> The exec property of the state record is set on init, so I figured I<br>
> could just pass in a fun instead like I can the shell option:<br>
> ```<br>
> {error,{eoptions,{exec,#Fun<msw_ssh_server.2.72054487>}}<br>
> ```<br>
> Nope.  But yet it looks like it should accept a fun fine, so... what<br>
> is going on.<br>
> I take a look at where ssh_cli is called and found this in<br>
> ssh_connection_handler.erl:<br>
> ```<br>
>     Shell = proplists:get_value(shell, Opts),<br>
>     Exec = proplists:get_value(exec, Opts),<br>
>     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),<br>
>     State#state{starter = Pid, connection_state = Connection#connection{<br>
>                                                     cli_spec = CliSpec,<br>
>                                                     exec = Exec,<br>
>                                                     system_supervisor<br>
> = SystemSup,<br>
><br>
> sub_system_supervisor = SubSystemSup,<br>
><br>
> connection_supervisor = ConnectionSup<br>
>                                                    }}.<br>
> ```<br>
> So, it seems the exec is set here as an option to the connection<br>
> state, and the exec is filtered on this in ssh.erl:<br>
> ```<br>
><br>
> handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),<br>
>                                                             is_atom(Function) -><br>
><br>
>     Opt;<br>
> ```<br>
> And that looks like it should work, but wait, remember what I said<br>
> about exec only being set on init in ssh_cli.erl, and look at the line<br>
> above that sets the default ssh_cli option:<br>
> ```<br>
>     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),<br>
> ```<br>
> Hmm, so it never sets the exec option in the ssh_cli, if it did then<br>
> it should actually be calling:<br>
> ```<br>
>     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell, Exec]}),<br>
> ```<br>
> Yet it is not.  So I removed my shell and exec options from ssh:daemon<br>
> and replaced it with a single option of:<br>
> ```<br>
>     {ssh_cli, {ssh_cli, [<br>
>         fun(User, PeerAddr) -> msw_ssh_server_shell:start(User, PeerAddr) end,<br>
>         fun(Cmd, User, PeerAddr) -> msw_ssh_server_shell:exec(Cmd,<br>
> User, PeerAddr) end]}},<br>
> ```<br>
> And badda bing it works.  I am not sure if this is the 'proper' way to<br>
> do it (and I would love to learn of a proper way if it exists), but it<br>
> works with both setting a shell, exec, and getting the User and<br>
> PeerAddress in both cases as well.<br>
><br>
> On Tue, Dec 10, 2013 at 2:26 PM, OvermindDL1 <<a href="mailto:overminddl1@gmail.com">overminddl1@gmail.com</a>> wrote:<br>
>> Another question while I am at it with this exec option, the 'shell'<br>
>> option gets a User and PeerAddr passed in, any way to do that with<br>
>> exec?  If I can at least get the User then I can allow them to issue<br>
>> one-off commands this way too, which would be quite useful for remote<br>
>> scripting.<br>
>><br>
>> On Tue, Dec 10, 2013 at 2:22 PM, OvermindDL1 <<a href="mailto:overminddl1@gmail.com">overminddl1@gmail.com</a>> wrote:<br>
>>> Ah all you are amazing, I never saw that option in the docs indeed and<br>
>>> looks like it should do what I want.  Thanks much for all the help!<br>
>>><br>
>>> On Tue, Dec 10, 2013 at 10:20 AM, Jakob Cederlund <<a href="mailto:jakobce@gmail.com">jakobce@gmail.com</a>> wrote:<br>
>>>> Actually, the sample cli module works quite all right. The problem is that<br>
>>>> the default implementation in ssh_cli for the "exec" thing in ssh is<br>
>>>> actually to execute it (using erl_scan and erl_eval and stuff). There is an<br>
>>>> undocumented option to ssh (actually to the ssh_cli module) that can be used<br>
>>>> to customize this. The option {exec, {M, F, []}} takes an exported function<br>
>>>> (M:F/1) that is called with the parameters given to the ssh commands as a<br>
>>>> string. This function should spawn a process that writes the desired output<br>
>>>> on stdout.<br>
>>>><br>
>>>> So to avoid the strange eval phenomenon, and provide another function that<br>
>>>> just echoes the parameters back, you can write a module x:<br>
>>>> -module(x).<br>
>>>> -export([exec/1]).<br>
>>>> exec(A) -> spawn(fun() -> io:format("~p\n", [A]), exit(normal) end).<br>
>>>><br>
>>>> and specify the function x:exec/1 as a call-back for the exec option:<br>
>>>> B=ssh_sample_cli:listen(8323, [{subsystems, []}, {exec, x, exec, ""]).<br>
>>>><br>
>>>> And then when you do:<br>
>>>>> ssh -p 8323 to.the.host 'lists:reverse("test").'<br>
>>>><br>
>>>> You get back:<br>
>>>> "list:reverse(\"test\")."<br>
>>>><br>
>>>> Hope this helps. (And sorry for the mess…)<br>
>>>> /Jakob<br>
>>>><br>
>>>><br>
>>>><br>
>>>> 2013/12/10 Ingela Andin <<a href="mailto:ingela.andin@gmail.com">ingela.andin@gmail.com</a>><br>
>>>>><br>
>>>>> Hi!<br>
>>>>><br>
>>>>> The CLI example in the SSH application must be seen as a hack. We intend<br>
>>>>> to clean it up and<br>
>>>>> extend the SSH documentation, when it gets prioritized I can not say. Well<br>
>>>>> anyway your CLI<br>
>>>>> implementation must take care of SSH exec request as well.  You can also<br>
>>>>> look at the ssh_cli.erl  module.<br>
>>>>> If I remember correctly there was a bug, before ssh-2.1.7, with regards to<br>
>>>>> the exec request  so that  it was not forwarded to CLI process but rather<br>
>>>>> always interpreted in the erlang shell environment.<br>
>>>>><br>
>>>>> Regards Ingela Erlang/OTP team - Ericsson AB<br>
>>>>><br>
>>>>><br>
>>>>><br>
>>>>> 2013/12/7 OvermindDL1 <<a href="mailto:overminddl1@gmail.com">overminddl1@gmail.com</a>><br>
>>>>>><br>
>>>>>> Greetings,<br>
>>>>>><br>
>>>>>> I am attempting to just create an SSH shell to connect to a system by<br>
>>>>>> users so they can do commands without the web interface, and as such I<br>
>>>>>> certainly do not want things like port forwarding or being able to run<br>
>>>>>> arbitrary erlang code, however I do not seem to be able to disable<br>
>>>>>> running arbitrary erlang code.  An example of the ssh_sample_cli<br>
>>>>>> included with erlang:<br>
>>>>>> """<br>
>>>>>> $ erl<br>
>>>>>> Erlang R16B02 (erts-5.10.3) [source] [64-bit] [smp:8:8]<br>
>>>>>> [async-threads:10] [hipe] [kernel-poll:false]<br>
>>>>>><br>
>>>>>> Eshell V5.10.3  (abort with ^G)<br>
>>>>>> 1> c(ssh_sample_cli).<br>
>>>>>> ssh_sample_cli.erl:146: Warning: this expression will fail with a<br>
>>>>>> 'badarith' exception<br>
>>>>>> {ok,ssh_sample_cli}<br>
>>>>>> 2> B=ssh_sample_cli:listen(8323, [{subsystems, []}]).<br>
>>>>>> {ok,<0.67.0>}<br>
>>>>>> """<br>
>>>>>><br>
>>>>>> And from another shell/computer:<br>
>>>>>> """<br>
>>>>>> $ ssh -p 8321 to.the.host<br>
>>>>>> myusername@to.the.host's password:<br>
>>>>>> Enter command<br>
>>>>>> CLI> help<br>
>>>>>> CLI Sample<br>
>>>>>> crash                  crash the cli<br>
>>>>>> exit                   exit application<br>
>>>>>> factors    <int>       prime factors of <int><br>
>>>>>> gcd        <int> <int> greatest common divisor<br>
>>>>>> help                   help text<br>
>>>>>> host                   print host addr<br>
>>>>>> lcm        <int> <int> least common multiplier<br>
>>>>>> prime      <int>       check for primality<br>
>>>>>> primes     <int>       print all primes up to <int><br>
>>>>>> rho        <int>       prime factors using rho's alg.<br>
>>>>>> self                   print my pid<br>
>>>>>> user                   print name of user<br>
>>>>>><br>
>>>>>> ---> ok<br>
>>>>>> CLI> exit<br>
>>>>>> ---> done<br>
>>>>>> Connection to to.the.host closed.<br>
>>>>>> """<br>
>>>>>><br>
>>>>>> So far so good (the main program where I have this implemented has a<br>
>>>>>> well running shell of its own), but lets try a couple other things:<br>
>>>>>> """<br>
>>>>>> $ sftp -P 8321 to.the.host<br>
>>>>>> myusername@to.the.host's password:<br>
>>>>>> subsystem request failed on channel 0<br>
>>>>>> Connection closed<br>
>>>>>> """<br>
>>>>>><br>
>>>>>> Also good, no file transfers can be done since the option subsystem is<br>
>>>>>> set to [], but notice:<br>
>>>>>> """<br>
>>>>>> $ ssh -p 8323 to.the.host 'lists:reverse("!?ti pots I od woh dna ereh<br>
>>>>>> gnineppah si tahw woN").'<br>
>>>>>> myusername@to.the.host's password:<br>
>>>>>> "Now what is happening here and how do I stop it?!"<br>
>>>>>> """<br>
>>>>>><br>
>>>>>> So... I can still run arbitrary erlang commands, how do I stop this?<br>
>>>>>> Unable to find an option to pass in or anything through a quick code<br>
>>>>>> perusal to no avail.  Help?<br>
>>>>>> _______________________________________________<br>
>>>>>> erlang-questions mailing list<br>
>>>>>> <a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
>>>>>> <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
>>>>><br>
>>>>><br>
>>>>><br>
>>>>> _______________________________________________<br>
>>>>> erlang-questions mailing list<br>
>>>>> <a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
>>>>> <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
>>>>><br>
>>>><br>
</div></div></blockquote></div><br></div></div></div></div></div></div></div>