From 8a6829d8033e67d927da61c8f69501969252869e Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Sun, 9 Jun 2019 17:14:18 +0200 Subject: [PATCH] Running daemons as a different user is now possible. --- src/libc.cr | 57 +++++++++++++++++++++++++++++++++++++++ src/service.cr | 14 ++++++++-- src/service_definition.cr | 1 + 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/libc.cr diff --git a/src/libc.cr b/src/libc.cr new file mode 100644 index 0000000..1accad3 --- /dev/null +++ b/src/libc.cr @@ -0,0 +1,57 @@ + +lib LibC + struct Passwd + pw_name : Char* + pw_passwd : Char* + pw_uid : UInt + pw_gid : UInt + pw_gecos : Char* + pw_dir : UInt + pw_shell : Char* + end + + fun setuid(Int32) : Int32 + fun setgid(Int32) : Int32 + fun getpwnam(Char*) : Passwd* +end + +module System + def self.become_user(user_name : String) + pointer = LibC.getpwnam user_name.to_unsafe + + if pointer.null? + return nil + end + + passwd = pointer.value + + # FIXME: Probably should get some errno magic right now. + if 0 != LibC.setuid passwd.pw_uid + raise Exception.new "setuid failed" + end + + if 0 != LibC.setgid passwd.pw_gid + raise Exception.new "setuid failed" + end + + passwd + end +end +#def get_uid_gid(user_name : String) +# pointer = LibC.getpwnam user_name.to_unsafe +# +# if pointer.null? +# return nil +# end +# +# passwd = pointer.value +# +# {passwd.pw_uid, passwd.pw_gid} +#end + +#uid, gid = get_uid_gid("http").not_nil! +#LibC.setuid uid +#LibC.setgid gid + +#puts Process.run "whoami", output: Process::Redirect::Inherit + diff --git a/src/service.cr b/src/service.cr index a4eae56..f77516e 100644 --- a/src/service.cr +++ b/src/service.cr @@ -1,6 +1,8 @@ require "yaml" require "colorize" +require "./libc.cr" + def split_command(string) args = string.split /\ (?=([^\"]*\"[^\"]*\")*[^\"]*$)/ @@ -138,8 +140,16 @@ class Service puts " - #{check.name}" - # FIXME: Output? Only in debug mode? - child = Process.run "sh", ["-c", evaluate check.command], output: Process::Redirect::Inherit, error: Process::Redirect::Inherit + child = Process.fork do + @reference.user.try do |user| + unless System.become_user user + STDERR << "service: child could not setuid() to user '#{user}'.\n" + exit 1 + end + end + + Process.exec "sh", ["-c", evaluate check.command], output: Process::Redirect::Inherit, error: Process::Redirect::Inherit + end.wait if child.exit_status != 0 raise Service::Exception.new "Child process exited with status “#{child.exit_status}”." diff --git a/src/service_definition.cr b/src/service_definition.cr index 0f3ffdb..6be2c2e 100644 --- a/src/service_definition.cr +++ b/src/service_definition.cr @@ -31,6 +31,7 @@ class ServiceDefinition key: "stop-command" }, directory: String?, # Place to chdir to before running @command. + user: String?, # User that should run the service. environment: { type: Environment, default: Environment.root