我正在为 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 件重要的事情:
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 "com.example.AppC" 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
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
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 中设置的
plist 文件中每次出现的 XXXXXXXXXX,都会针对您的苹果开发者证书的组织单位进行更改。
- AppB 和 AppC 将使用有效的苹果开发者进行签名 使用协同设计工具生成证书。
- AppC 将被复制到 Contents/Library/LaunchServices 中的 AppB 包中
- AppA 将被复制到 Contents/Resources 中 AppB 的 bundle 中
- AppB Info.plist 将被复制到 App Bundle 中。
- 接下来,您将使用编码工具签署 AppB Bundle。
- 此示例使用 unix 套接字将 AppB 与 AppC launchd 守护程序通信,然后 AppC 将启动服务器连接并等待来自 AppB 的命令,当 AppC 收到命令时它将执行 AppA(您可以使用 execvp C 函数或任何您想)。
- AppB 将启动客户端连接,并在需要运行 AppA 时向 AppC 发送命令。
我已尝试在此处解释所有细节,但我认为通过检查我的代码您会更好地了解解决方案。
关于c++ - 在 MacOSX 下用 C 启动特权应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17478228/