Я пишу приложение Installer / Autoupdater для 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 (не удалось запустить инструмент).
Вопросы:
а) Почему это не удается? Я подозреваю его, потому что рабочая папка не установлена правильно …? (Можно ли как-то установить рабочую папку инструмента?)
РЕДАКТИРОВАТЬ: Хорошо, понял это: массив args [] — сам массив должен заканчиваться NULL. Уже исправлено в приведенном выше коде.
б) Другие интернет-источники говорят, что функция AuthorizationExecuteWithPrivileges устарела и не должна использоваться из-за соображений безопасности. Может кто-нибудь привести пример, как это сделать лучше?
Да, AuthorizationExecuteWithPrivileges устарела.
Apple теперь предоставляет более безопасный метод обработки приложений с повышенными правами, который заключается в выделении кода, требующего повышения прав, в другое вспомогательное приложение, которому предоставлено специальное разрешение и которое запущено с повышенными правами. Таким образом, если ваше приложение подверглось злоупотреблению из-за вредоносного ПО или внедрения кода, оно также не сможет получить повышенный доступ. Вспомогательное приложение также подписано вашим приложением, поэтому только ваше приложение может запросить его запуск.
Если вы посмотрите на Apple, Пример SMJobBless, это показывает, как вы делаете это. Начните с взгляда на ReadMe.txt и я бы также предложил выполнить поиск SMJobBless в Google, так как об этом довольно много говорят.
Возможно, мой ответ для вас запоздал, но я надеюсь, что он поможет другим разработчикам Qt. Я создал проект в Qt, чтобы показать, как подписывать, устанавливать исполняемый привилегированный вспомогательный инструмент с помощью SMJobBless; Вы можете увидеть код здесь: https://github.com/mbsanchez/QtPrivilegedHelperExample
Я создал его, потому что нет документации по установке привилегированного вспомогательного инструмента, который был разработан с C ++ на QtCreator.
Редактировать:
Я объясню процесс, которому я следовал, чтобы сделать это.
Проблема: у вас есть приложение «AppA», которое вы хотите запустить с правами администратора из другого приложения «AppB», разработанного на C ++ с использованием QtCreator.
Решение: начиная с Mac Os X 10.7 функция AuthorizationExecuteWithPrivileges устарела, поэтому вместо нее вы будете использовать SMJobBless. Но вся документация и примеры о SMJobBless есть на Xcode, и до сих пор на C ++ ничего не было.
Чтобы использовать SMJobBless, вы разработаете третье приложение «AppC», которое обычно называют вспомогательным инструментом и устанавливается как привилегированный вспомогательный инструмент с использованием SMJobBless и запускается в виде демона с помощью launchd. Затем, подобно тому, как AppC выполняется с правами администратора, любое приложение, выполняемое AppC, получит права администратора. Итак, если вы запустили AppA из AppC, AppA будет работать с правами администратора.
Здесь есть три важных вещи:
AppB установит привилегированный вспомогательный инструмент (AppC), используя SMJobBless, поэтому 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>
Info.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 будет связан с обоими файлами plist с помощью «-sectcreate __TEXT __info_plist myinfo.plist -sectcreate __TEXT __launchd_plist mylaunchd.plist» в флаге ссылки компилятора (QMAKE_LFLAGS в
QMAKE). Это встроит два файла plist в __TEXT
раздел привилегированного вспомогательного приложения (AppC).
QMAKE_LFLAGS += -sectcreate __TEXT __info_plist $$PWD/AppC-Info.plist -sectcreate __TEXT __launchd_plist $$PWD/AppC-Launchd.plist
Этот флаг был установлен в AppC.pro
каждый случай XXXXXXXXXX в plist-файлах будет изменен для подразделения организации вашего сертификата разработчика Apple.
Я попытался объяснить все детали здесь, но я думаю, что у вас будет лучшее представление о решении, изучив мой код.