125 lines
4 KiB
GDScript
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")
|