hamncheese/hamncheese/Scripts/process.gd
2023-09-29 19:18:57 -05:00

125 lines
4 KiB
GDScript

#
# Ham'n'Cheese
# Copyright (C) 2023-2024 Scott Duensing <scott@kangaroopunch.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
#
extends Node
var _udp := UDPServer.new()
var _ask_pass_password := ""
var _ask_pass_port := 0
var _ask_pass_script := ""
var _root_password = null
func _elevate_unix(program: String, arguments: PackedStringArray):
_root_password = await Dialog.password("Root Access Needed", "Password:")
if _root_password == null:
return -1
_ask_pass_password = Util.generate_password()
_ask_pass_script = OS.get_user_data_dir() + "/ask_pass.sh"
var ask_pass := FileAccess.open(_ask_pass_script, FileAccess.WRITE)
ask_pass.store_line("#!/usr/bin/env bash")
ask_pass.store_line("echo " + _ask_pass_password + " | nc -w1 -u 127.0.0.1 " + str(_ask_pass_port))
ask_pass.close()
OS.execute("chmod", ["+x", _ask_pass_script])
OS.set_environment("SUDO_ASKPASS", _ask_pass_script)
var options := ["-A", program]
options.append_array(arguments)
var pid = OS.create_process("sudo", options, false)
return pid
func _elevate_windows(program: String, arguments: PackedStringArray):
# powershell.exe -Command (Start-Process 'edge.exe' -ArgumentList 'stuff here' -Verb runAs -PassThru).Id
var pidFile := OS.get_user_data_dir() + "/elevate.pid"
var cmdFile := OS.get_user_data_dir() + "/elevate.cmd"
# Build the script to run.
var power := "@powershell.exe -Command (Start-Process '" + program + "'"
if arguments.size() > 0:
power += " -ArgumentList '" + " ".join(arguments) + "'"
power += " -Verb runAs -PassThru).Id > \"" + pidFile + "\""
var handle = FileAccess.open(cmdFile, FileAccess.WRITE)
handle.store_line(power)
handle.close()
# Run it.
var cmdPid := OS.create_process(cmdFile, [], true)
# Wait for PID to be created.
var pid := -1
var count := 5
while !FileAccess.file_exists(pidFile) and count > 0:
OS.delay_msec(500)
count -= 1
# We get a PID?
if count > 0:
# Read PID.
handle = FileAccess.open(pidFile, FileAccess.READ)
pid = int(handle.get_line())
handle.close()
# Wait for batch to exit.
if cmdPid > 0:
while OS.is_process_running(cmdPid):
OS.delay_msec(500)
# Clean up.
if FileAccess.file_exists(cmdFile):
DirAccess.remove_absolute(cmdFile)
if FileAccess.file_exists(pidFile):
DirAccess.remove_absolute(pidFile)
return pid
func _process(_delta):
if _udp.is_listening():
_udp.poll()
if _udp.is_connection_available():
var peer: PacketPeerUDP = _udp.take_connection()
var data := peer.get_packet().get_string_from_ascii()
if peer.get_packet_error() == OK:
if data.strip_edges() == _ask_pass_password:
if _root_password != null:
peer.put_packet(_root_password.to_ascii_buffer())
_root_password = null
peer.close()
func elevate(program: String, arguments: PackedStringArray = []):
if OS.get_name() == "Windows":
return _elevate_windows(program, arguments)
else:
return await _elevate_unix(program, arguments)
func is_elevated():
if OS.get_name() == "Windows":
# This will error if run by a standard user.
var result := OS.execute("net.exe", [ "sessions" ])
return true if result == 0 else false
else:
return false # We don't support this on UNIX.
func shutdown():
_udp.stop()
if _ask_pass_script != "":
if FileAccess.file_exists(_ask_pass_script):
DirAccess.remove_absolute(_ask_pass_script)
func startup(port: int):
_ask_pass_port = port
_udp.listen(_ask_pass_port, "127.0.0.1")