Add run as user and group parameters for the service (#7747)

* Prevent running service as root unless required

* Allow specifying the user to launch service
This commit is contained in:
frytimo
2026-02-18 12:36:08 -04:00
committed by GitHub
parent 379b369a38
commit ba45d527ed
2 changed files with 85 additions and 0 deletions

View File

@@ -5,6 +5,13 @@
*/
class event_guard_service extends service {
/**
* Permit this service to run as root user
*
* @var boolean
*/
protected static $allow_run_as_root = true;
/**
* database object
* @var database

View File

@@ -84,6 +84,27 @@ abstract class service {
* @var string
*/
private static $pid_file = "";
/**
* Allows the service to run as root
*
* The child class should override this value if required. It is recommended to run services as a non-root user
* for security reasons. If this value is set to false and the service is started as root, the service will exit
* with an error message.
*
* @var bool
*/
protected static $allow_run_as_root = false;
protected static $posix_username = null;
protected static $posix_groupname = null;
protected static $user_name = null;
protected static $group_name = null;
protected static $uid = null;
protected static $gid = null;
/**
* Track the internal loop. It is recommended to use this variable to control the loop inside the run function. See
* the example below the class for a more complete explanation
@@ -302,6 +323,39 @@ abstract class service {
//parse the cli options and store them statically
self::parse_service_command_options();
// If a group name is specified, then run the service under this group
if (self::$posix_groupname !== null) {
$group_record = posix_getgrnam(self::$posix_groupname);
if ($group_record === false) {
die("Group " . self::$posix_groupname . " not found\n");
}
posix_setgid($group_record['gid']);
}
// If a user name is specified, then run the service under this user
$record = posix_getpwuid(posix_geteuid());
if (self::$posix_username !== null) {
$record = posix_getpwnam(self::$posix_username);
if ($record === false) {
die("User " . self::$posix_username . " not found\n");
}
posix_setuid($record['uid']);
}
self::$uid = $record['uid'] ?? 0;
self::$gid = $record['gid'] ?? 0;
self::$user_name = $record['name'] ?? 'unknown';
self::$group_name = posix_getgrgid(self::$gid)['name'] ?? 'unknown';
// Check if we are running as root when not allowed
if (posix_geteuid() === 0) {
if (static::$allow_run_as_root) {
self::log("Root user permitted for this service.", LOG_DEBUG);
} else {
self::log("Running as root is not allowed for this service. Please run as a non-root user.", LOG_ERR);
exit(0);
}
}
//fork process
if (self::$daemon_mode) {
//force launching in a separate process
@@ -480,6 +534,20 @@ abstract class service {
$help_options[$index]['long_description'] = '--show-timestamp';
$help_options[$index]['functions'][] = 'show_timestamp';
$index++;
$help_options[$index]['short_option'] = 'u:';
$help_options[$index]['long_option'] = 'user:';
$help_options[$index]['description'] = 'Set the user to run the service as. This will drop privileges to the specified user after starting the service. The user must exist on the system and have permissions to read the configuration file and write to the PID file.';
$help_options[$index]['short_description'] = '-u <username>';
$help_options[$index]['long_description'] = '--user <username>';
$help_options[$index]['functions'][] = 'set_username';
$index++;
$help_options[$index]['short_option'] = 'g:';
$help_options[$index]['long_option'] = 'group:';
$help_options[$index]['description'] = 'Set the group to run the service as. This will drop privileges to the specified group after starting the service. The group must exist on the system and have permissions to read the configuration file and write to the PID file.';
$help_options[$index]['short_description'] = '-g <groupname>';
$help_options[$index]['long_description'] = '--group <groupname>';
$help_options[$index]['functions'][] = 'set_groupname';
$index++;
$help_options[$index]['short_option'] = 'x';
$help_options[$index]['long_option'] = 'exit';
$help_options[$index]['description'] = 'Exit the service gracefully';
@@ -490,6 +558,14 @@ abstract class service {
return $help_options;
}
protected static function set_username($username) {
self::$posix_username = $username;
}
protected static function set_groupname($groupname) {
self::$posix_groupname = $groupname;
}
/**
* Called when the display_help_message is run in the base class for extra command line parameter explanation
*/
@@ -648,6 +724,8 @@ abstract class service {
self::log("PID File : " . self::$pid_file, LOG_INFO);
self::log("Log level : " . self::log_level_to_string(self::$log_level), LOG_INFO);
self::log("Timestamps: " . (self::$show_timestamp_log ? "Yes" : "No"), LOG_INFO);
self::log("User : " . self::$user_name . " (" . self::$uid . ")", LOG_INFO);
self::log("Group : " . self::$group_name . " (" . self::$gid . ")", LOG_INFO);
// Save the pid file
$success = file_put_contents(self::$pid_file, $pid);