You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多用户嵌入式系统中user1调用D-Bus systemd启停服务遇权限错误

问题描述

我在一个包含root、user1等多用户的嵌入式系统中,以user1身份运行C++二进制文件时,调用systemd启停服务接口会触发权限错误,以root身份运行则正常。

相关代码、测试程序、service文件及错误输出如下:

C++调用代码

#include <iostream>
#include <systemd/sd-bus.h>


static void SDCallMethodSS(
  sd_bus* bus,
  const std::string& name,
  const std::string& method)
{
  sd_bus_error err = SD_BUS_ERROR_NULL;
  sd_bus_message* msg = nullptr;
  int r;

  r = sd_bus_call_method(bus,
      "org.freedesktop.systemd1",
      "/org/freedesktop/systemd1",
      "org.freedesktop.systemd1.Manager",
      method.c_str(),
      &err,
      &msg,
      "ss",
      name.c_str(),  "replace" );

  if (r < 0)
  {
    std::string err_str("Could not send " + method +
                        " command to systemd for service: " + name +
                        ". Error: " + err.message );

    sd_bus_error_free(&err);
    sd_bus_message_unref(msg);
    throw std::runtime_error(err_str);
  }

  char* response;
  r = sd_bus_message_read(msg, "o", &response);
  if (r < 0)
  {
          std::cerr<< "Failed to parse response message: " << strerror(-r) << std::endl;;
  }

  sd_bus_error_free(&err);
  sd_bus_message_unref(msg);
}

int main() {
  int r;
  sd_bus *bus = NULL;

  r = sd_bus_open_system(&bus);
  if (r < 0) {
          std::cerr<< "Failed to connect to system bus: " << strerror(-r) << std::endl;
    return -1;
  }

  try{
    SDCallMethodSS(bus, std::string("foo-daemon.service"), std::string("StopUnit"));
  } catch (std::exception& e) {
    std::cout << "Exception in SDCallMethodSS(): " << e.what() << std::endl;
    return -2;
  }
}

测试程序foo-daemon

#include <unistd.h>

int main()
{
  while(1){
    sleep(1);
  }

}

service文件(路径:/etc/systemd/system/foo-daemon.service)

[Unit]
Description=Foo

[Service]
ExecStart=/usr/local/bin/foo-daemon

[Install]
WantedBy=multi-user.target

user1运行时错误输出

Exception in SDCallMethodSS(): Could not send StopUnit command to systemd for service: foo-daemon.service. Error: Permission denied

解决方案

以下几种方法可解决user1的权限问题,按需选择:

方法1:添加PolicyKit规则精准授权

创建PolicyKit规则文件/etc/polkit-1/rules.d/50-foo-daemon.rules,内容如下:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        action.lookup("unit") == "foo-daemon.service" &&
        subject.user == "user1") {
        return polkit.Result.YES;
    }
});

该规则仅允许user1对foo-daemon.service执行启停等unit管理操作,权限范围精准,无需重启服务即可生效。

方法2:给二进制文件添加系统管理能力

若系统支持Linux Capabilities,可给调用程序添加CAP_SYS_ADMIN权限:

sudo setcap cap_sys_admin+ep /path/to/your/cpp_binary

此方法让user1运行该二进制时拥有systemd管理所需权限,但权限范围较宽,仅在必要时使用。

方法3:让服务以user1身份运行

修改foo-daemon.service文件,让服务本身以user1身份启动,此时user1默认拥有管理该服务的权限:

  1. 更新service文件内容:
[Unit]
Description=Foo

[Service]
ExecStart=/usr/local/bin/foo-daemon
User=user1

[Install]
WantedBy=multi-user.target
  1. 重新加载systemd配置并重启服务:
sudo systemctl daemon-reload
sudo systemctl restart foo-daemon.service

此方法适合服务本身不需要root权限的场景。


内容的提问来源于stack exchange,提问作者preetam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 06:57:37