This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Kizz's profile picture

Preventing Termination of a Shell Tab

Started by Kizz, 09 April 2015 - 04:25 PM
Kizz #1
Posted 09 April 2015 - 06:25 PM
Greetings!

I'm trying to make an operating system that runs a shell in the background (Advanced Computers). This shell simply shows a count down and contains "silent functions" which need to run for the operating system.

The problem is, I want to allow different levels of permissions for users. This causes two problems.

1. Any user can terminate the second shell tab even with
os.pullEvent = os.pullEventRaw
included in the shell program.

2. Anyone can edit my startup file once logged in. This means a guest could log in, edit my startup file, and steal or change other users passwords. Is there any way to encrypt or prevent opening/editing a file inside a CC environment?

Thank for the help!
Edited on 09 April 2015 - 04:38 PM
Kizz #2
Posted 09 April 2015 - 06:30 PM
I have discovered I can create a file 'edit' and prevent editing, but I don't want to completely remove the function. May rebuild edit and force it to prevent editing specific files. :D/>
Kizz #3
Posted 09 April 2015 - 06:37 PM
Update 2:

I poked around in the CC.jar file and got the edit program, rebuilt it and added:


if sPath=="startup" then
    print'Cannot edit this file!'
    return
end


This prevents anyone editing my startup from inside my OS. Which protects my passwords.

However, you can still terminate secondary shells.
Lupus590 #4
Posted 09 April 2015 - 06:39 PM
Make something check if the secondary shell is terminated and restart it if it is, not ideal I know, but will do until someone has proper fix.
Kizz #5
Posted 09 April 2015 - 07:04 PM
Unfortunately when you log into my OS, the current shell is in a non-running state. Therefore I have no way to 'listen' and take action when the other shell is terminated.

A really useful feature would be the ability to hide the shell, and make it un-callable, or just simply preventing it from being closed. Both would be suitable solutions.

The only reason I would like to have the shell visible is for logging and because it allows the user to see the time left they have before being auto logged out. I have a program that allows users to extend their time logged in, and they get automatically logged out when they are inactive for too long. This is for security.


Hiding the shell could work, but preventing termination is preferred. I even tried listening for the raw terminate event and it still just terminated before any event was discovered.
Edited on 09 April 2015 - 05:06 PM
valithor #6
Posted 09 April 2015 - 11:15 PM
Here is a little trick that I have used multiple times for resource packs for servers to prevent editing or even opening of a file. You would want to put this at the beginning or near the beginning of your OS.


local _fs = {}
local oldcomb = fs.combine
local oldlower = string.lower

local blockedpaths = {
  ["put"] = true,
  ["paths"] = true,
  ["here"] = true
}

for k,v in pairs(fs) do
  _fs[k] = function(path,...)
	if blockedpaths[oldcomb("/",path):oldlower()] then
	  return nil
	else
	  return v(path,...)
	end
  end
end

fs = _fs

That code above would block access to any file in the blockedpaths table from even being passed to a fs argument. It effectively blocks the file from all outside programs until computer restart.

Although this works i doubt you would want to take such drastic measure this would probably be enough

local oldOpen = fs.open
local oldComb = fs.combine
local oldLower = string.lower

fs.open = function(path,mode)
  if oldComb("/",path):oldLower() == (Your Path) then
	return oldOpen(path,mode)
  end
end

This prevents anything from editing the paths, while your fix still allows the file itself to be opened using fs.open and thus modified.

Btw even if you create a file named edit people can still use a exact path to /rom/programs/edit and access the old edit program.
edit:
As for your other problem I am unable to recreate it.
Edited on 09 April 2015 - 09:29 PM
Kizz #7
Posted 10 April 2015 - 12:20 AM
Hmm, interesting. I don't think I will have to worry about hackers with that much skill on my server ;D. If they are skilled enough to use a direct path or use the fs api, then they deserve to hack into my hut ;D.

I still am unsure as to why os.pullEvent = os.pullEventRaw is unable to stop termination on that shell. Maybe because I call the shell to open in a new tab from another shell?
valithor #8
Posted 10 April 2015 - 12:28 AM
I was testing it in the lua prompt by doing:


os.pullEvent = os.pullEventRaw
shell.openTab("shell")

And i was unable to terminate it.
Kizz #9
Posted 13 April 2015 - 07:34 PM
Fair enough. I will have to do some testing with this and see what I can do.
Kizz #10
Posted 15 April 2015 - 05:42 PM

os.pullEvent = os.pullEventRaw --<------------
function logout()
timetor=300
while timetor > 0 do
  term.clear()
  term.setCursorPos(1,1)
  timetor=timetor-1
  print('Welcome OP. System Online. Restarting in '..timetor..' seconds.')
  sleep(.95)
end
os.reboot()
end
function listener()
while true do
event,timer = os.pullEvent("extendme") --<----
  if timer > 0 then
   print("Extending time!")
   timetor=timetor+timer
  end
end
end
parallel.waitForAll(listener,logout)

Found the issue. If I try and use an event listener while 'os.pullEvent = os.pullEventRaw' then it will allow termination.

Is there a way around this?
Edited on 15 April 2015 - 03:46 PM
Bomb Bloke #11
Posted 15 April 2015 - 11:46 PM
I think it might be less that it "allows termination" and more that it "crashes".

os.pullEventRaw() always returns terminate events, no matter what filter you're using. So you'd want to change this sort of code:

event,timer = os.pullEvent("extendme") --<----
  if timer > 0 then
   print("Extending time!")
   timetor=timetor+timer
  end
end

… to something more along these lines:

event,timer = os.pullEvent("extendme")
  if event == "extendme" and timer > 0 then
   print("Extending time!")
   timetor=timetor+timer
  end
end

… as you would if the filter were not in place at all.
Kizz #12
Posted 16 April 2015 - 01:05 PM
I see and understand your code, and I even expected it to be the solution, but it still seems to crash on terminate. Maybe shell tabs override any attempt to terminate by simply shutting down and closing the tab?
Bomb Bloke #13
Posted 16 April 2015 - 01:15 PM
Maybe there's another area of code relying on the filter system? It's difficult to make suggestions without knowing what error messages your crash is providing you with, but take a read through and think about how each section of the script will behave if an unhandled terminate event suddenly goes into the queue.

Though, I suppose you could always make an automatic terminate-event-discarder:

os.pullEvent = function(filter)
	while true do
		local myEvent = {os.pullEventRaw(filter)}
		if myEvent[1] ~= "terminate" then return unpack(myEvent) end
	end
end
Kizz #14
Posted 16 April 2015 - 01:27 PM
Interesting. I applied the discarder and even still it just closes with no information.

This is my current code, maybe I misunderstood the discarder?


local osEvent=os.pullEvent
os.pullEvent=os.pullEventRaw
os.pullEvent = function(filter)
	    while true do
			    local myEvent = {os.pullEventRaw(filter)}
			    if myEvent[1] ~= "terminate" then return unpack(myEvent) end
	    end
end
function logout()
timetor=300
while timetor > 0 do
  term.clear()
  term.setCursorPos(1,1)
  timetor=timetor-1
  print('Welcome OP. System Online. Restarting in '..timetor..' seconds.')
  sleep(.95)
end
os.reboot()
end
function listener()
while true do 
  event,timer = os.pullEvent("extendme")
  if event == "extendme" and timer > 0 then
   print("Extending time!")
   timetor=timetor+timer
  end
end
end
parallel.waitForAll(listener,logout)
os.pullEvent=osEvent
Bomb Bloke #15
Posted 16 April 2015 - 01:36 PM
Trying it out, I find that code doesn't respond to the terminate combo as-is. Presumably there's more of it - where's the "extendme" events supposed to be coming from?
Kizz #16
Posted 16 April 2015 - 01:37 PM
As well this is the initial log-in script that calls the "master" program to run in the background.


local osEvent = os.pullEvent
os.pullEvent = os.pullEventRaw

while access~=1 do
print'Enter Password:'
pass=read("*")
access=0
  --sleep(1)
  term.clear()
  term.setCursorPos(1,1)
  if pass~="nou" and pass~="guest" then
  print'Wrong Password!'
  end
  if pass=="nou" then
  access=1
  shell.openTab("master")
  print'KOS Loading...'
  sleep(1)
		term.clear()
  term.setCursorPos(1,1)				  
  print'Welcome, Kizz, to Kizz OS!'
  print'Commands: '
  print'Logout - Logs user out. '
  print'Extend - Extends logout timer by x min.'
  print'Help - Shows more commands'
  user=1
  end
  if pass=="guest" then
  access=1
  shell.openTab("guest")
  print'KOS Loading...'
  sleep(1)
		term.clear()
  term.setCursorPos(1,1)	  
  print'Welcome, Guest, to Kizz OS!'
  print'Commands: '
  print'Logout - Logs user out. '
  print'Extend - Extends logout timer by x min.'
  print'Help - Shows more commands'
  user=0
  end

end

function logme()
  if user==1 then userName="Kizz" end
  if user==0 then userName="Guest" end

  if not fs.exists("log") then
  local h = fs.open("log", "a")
  h.write(" ")
  h.close()
  end

  if fs.exists("log") then
   local h = fs.open("log", "r")
   loglen=h.readAll()
   --print(loglen)
   if string.len(loglen)>1000000 then
   h.close()
   fs.delete("log")
   end
   h.close()
   local h = fs.open("log", "a")
   h.write(userName.." - Day: "..os.day().." | Time: "..os.time()..". \n")
   h.close()
  end


end


logme()
os.pullEvent=osEvent



Here is the extendme function:


print'How many minutes would you like to add?'
mint=io.read()
tonumber(mint)
mint=mint*60
os.queueEvent("extendme", mint)
print'Extended!'

Above all, I am using CCEmuRedux, maybe this is the emulators issue?
Edited on 16 April 2015 - 11:37 AM
Bomb Bloke #17
Posted 16 April 2015 - 01:47 PM
Your "initial" script runs first, and replaces the os.pullEvent pointer with one leading to os.pullEventRaw.

It then starts your "master" script, which tries to perform another replacement. That's redundant, but still ok.

The thing is, the "initial" script is starting the "master" script in a new tab, which means the latter's running in a separate co-routine and effectively doesn't block further execution of the former "initial" script. The former keeps running to completion, and the last thing it does before ending is re-instate the original os.pullEvent pointer.

So you end up with only the "master" script running, and it's doing so with the regular os.pullEvent function - the one rigged to crash your script if it sees a terminate event.
Edited on 16 April 2015 - 11:48 AM
Kizz #18
Posted 16 April 2015 - 02:11 PM
Oh my god. You're a lovely person! I removed the call to reset the os.pullEvent=osEvent from startup.

Then removed the call to replace os.pullEvent = os.pullEventRaw in master.

Boom. Works perfectly. :D/>

Thanks for the help!