c++ - 在 MacOSX 下用 C 启动特权应用程序

标签 c++ macos qt privileges elevated-privileges

我正在为 MacOSX(使用 Qt 和 C++)编写安装程序/自动更新程序。我需要升级权限才能覆盖应用文件夹中的旧文件。

我的升级代码基于以下示例:http://www.michaelvobrien.com/blog/2009/07/authorizationexecutewithprivileges-a-simple-example/ 我尝试使用这样的管理员权限重新启动我现有的应用程序:

void MainDialog::EscalatePrivileges()
{
    AuthorizationRef authorizationRef;
    OSStatus status;

    status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);

    char* tool = QApplication::instance()->applicationFilePath().toLocal8Bit().data();
    char* args[] = { "STARTUPDATE", NULL };
    FILE* pipe = NULL;

    status = AuthorizationExecuteWithPrivileges(authorizationRef, tool, AuthorizationFlagDefaults, args, &pipe);
    QApplication::instance()->quit();
}

但是,我收到错误 -60031(无法启动工具)。 问题:

a) 为什么会失败?我怀疑是因为工作文件夹设置不正确...? (我可以通过某种方式设置工具的工作文件夹吗?)

编辑: 好的,想通了:args[] - 数组本身需要以 NULL 结尾。已经在上面的代码中修复了。

b) 其他互联网消息来源称,AuthorizationExecuteWithPrivileges 函数已被弃用,出于安全考虑不应使用。有人可以举例说明如何以更好的方式做到这一点吗?

最佳答案

也许我的回答对你来说来晚了,但我希望它能对其他 Qt 开发人员有所帮助。我在 Qt 中创建了一个项目来展示如何使用 SMJobBless 签名、安装和执行特权帮助工具;你可以在这里看到代码:https://github.com/mbsanchez/QtPrivilegedHelperExample

我创建了它,因为没有关于如何安装特权帮助工具的文档,什么是在 QtCreator 上用 C++ 开发的。

编辑: 我将解释执行此操作的过程。

问题:您有一个应用程序“AppA”,您希望使用 QtCreator 在 C++ 上开发的另一个应用程序“AppB”的管理权限执行该应用程序。

解决方案:由于 Mac Os X 10.7 已弃用 AuthorizationExecuteWithPrivileges 函数,因此您将改用 SMJobBless。但是关于 SMJobBless 的所有文档和示例都在 Xcode 上,直到现在还没有关于 C++ 的任何内容。

要使用 SMJobBless,您将开发第三个应用程序“AppC”,此应用程序通常称为辅助工具,将使用 SMJobBless 作为特权辅助工具安装,并由 launchd 作为守护进程执行。然后,就像AppC以管理员权限执行一样,AppC执行的任何应用程序都将获得管理员权限。因此,如果您从 AppC 执行 AppA,AppA 将以管理员权限运行。 这里有 3 件重要的事情:

  1. AppB 将使用 SMJobBless 安装特权帮助工具 (AppC),因此,AppB 需要一个 Info.plist 文件,其中包含 它可以安装的特权帮助工具(在本例中为 AppC)。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>CFBundleIdentifier</key>
        <string>com.example.AppB</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        ...
        <key>SMPrivilegedExecutables</key>
        <dict>
            <key>com.example.AppC</key>
            <string>anchor apple generic and identifier &quot;com.example.AppC&quot; and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = XXXXXXXXXX)</string>
        </dict>
    </dict>
    </plist>
    

    信息.plist

  2. AppC 需要两个 plist 文件,第一个包含有关 launchd 任务的信息,系统使用什么来启动 AppC 作为 一个守护进程(AppC 不会被 AppB 执行,一旦 AppC 被 已安装,将由系统启动);第二个有 有关哪些应用程序可以将其安装为辅助工具的信息(AppB 在这种情况下)。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.example.AppC</string>
        <key>StandardErrorPath</key>
        <string>/var/log/com.example.appc.log</string>
        <key>Sockets</key>
        <dict>
            <key>com.example.AppC</key>
            <dict>
                 <key>SockFamily</key>
                 <string>Unix</string>
                 <key>SockPathMode</key>
                 <integer>438</integer>
                 <key>SockPathName</key>
                 <string>/var/run/com.example.AppC.socket</string>
                 <key>SockType</key>
                 <string>Stream</string>
            </dict>
        </dict>
    </dict>
    </plist>
    

    AppC-Launchd.plist

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>CFBundleIdentifier</key>
        <string>com.example.AppC</string>
        ...
        <key>SMAuthorizedClients</key>
        <array>
            <string>anchor apple generic and identifier com.example.AppB and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = XXXXXXXXXX)</string>
        </array>
    </dict>
    </plist>
    

    AppC-Info.plist

  3. AppC 将通过在编译器的链接标志(QMAKE_LFLAGS in 制作)。这会将两个 plist 文件嵌入到 __TEXT 特权助手应用程序 (AppC) 的部分。

    QMAKE_LFLAGS += -sectcreate __TEXT __info_plist $$PWD/AppC-Info.plist -sectcreate __TEXT __launchd_plist $$PWD/AppC-Launchd.plist
    

    这个标志是在 AppC.pro 中设置的

  4. plist 文件中每次出现的 XXXXXXXXXX,都会针对您的苹果开发者证书的组织单位进行更改。

  5. AppB 和 AppC 将使用有效的苹果开发者进行签名 使用协同设计工具生成证书。
  6. AppC 将被复制到 Contents/Library/LaunchServices 中的 AppB 包中
  7. AppA 将被复制到 Contents/Resources 中 AppB 的 bundle 中
  8. AppB Info.plist 将被复制到 App Bundle 中。
  9. 接下来,您将使用编码工具签署 AppB Bundle。
  10. 此示例使用 unix 套接字将 AppB 与 AppC launchd 守护程序通信,然后 AppC 将启动服务器连接并等待来自 AppB 的命令,当 AppC 收到命令时它将执行 AppA(您可以使用 execvp C 函数或任何您想)。
  11. AppB 将启动客户端连接,并在需要运行 AppA 时向 AppC 发送命令。

我已尝试在此处解释所有细节,但我认为通过检查我的代码您会更好地了解解决方案。

关于c++ - 在 MacOSX 下用 C 启动特权应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17478228/

相关文章:

C++ 套接字连接问题

java - Eclipse 消耗大约 85% 的 CPU 和 3 GB RAM : very slow performance

macos - 开发者 ID 确保 Gatekeeper 接受?

c++ - Qt: 如何正确使用 moveToThread(this)?

c++ - 在 Qt 中的 C++ 中添加 C 函数时出现问题

c++ - 在 Qt 桌面应用程序上运行 Selenium

c++ - exe 可以小于其最大的声明缓冲区吗?

c++ - glGetUniformIndices 没有返回正确的索引

c++ - 在 CString::Format 中使用 CString 对象

java - gradlew 使用错误的 Java 版本