Ответ 1
Отметьте STPrivilegedTask, класс оболочки Objective-C вокруг AuthorizationExecuteWithPrivileges() с интерфейсом, подобным NSTask.
В приложении, которое я создаю, мне нужно запустить следующую команду от имени пользователя root (пользователю будет предложено трижды, если он действительно этого захочет, и ему будет предложено размонтировать свои диски), используя NSTask:
/bin/rm -rf /
#Yes, really
Проблема в том, что простое использование Заместителя пользователя (sudo
) не работает, так как пользователю необходимо ввести пароль для недоступного стандартного ввода. Я бы предпочел, чтобы пользователь показывал то же окно, которое вы видите при нажатии на замок в Preferences.app, например, (надеюсь, с более коротким паролем):
(источник: quickpwn.com)
Кто-нибудь может мне с этим помочь? Благодарю.
Отметьте STPrivilegedTask, класс оболочки Objective-C вокруг AuthorizationExecuteWithPrivileges() с интерфейсом, подобным NSTask.
Это одна из самых сложных задач для работы в Mac OS X.
Руководство, в котором описано, как это сделать, - Руководство по программированию служб авторизации. Существует несколько возможностей, так как наиболее безопасным является наиболее безопасное.
Я начал писать инструмент, в котором используется демон launchd (самый безопасный способ), код доступен в коде google. Поэтому, если вы хотите, вы можете скопировать этот код.
Думаю, теперь я могу ответить на этот вопрос, благодаря некоторому Googling и приятной находке в этом вопросе SO. Это очень немного взломанно, но IMHO является удовлетворительным решением.
Я написал эту общую реализацию, которая должна достичь того, чего вы хотите:
- (BOOL) runProcessAsAdministrator:(NSString*)scriptPath
withArguments:(NSArray *)arguments
output:(NSString **)output
errorDescription:(NSString **)errorDescription {
NSString * allArgs = [arguments componentsJoinedByString:@" "];
NSString * fullScript = [NSString stringWithFormat:@"%@ %@", scriptPath, allArgs];
NSDictionary *errorInfo = [NSDictionary new];
NSString *script = [NSString stringWithFormat:@"do shell script \"%@\" with administrator privileges", fullScript];
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];
// Check errorInfo
if (! eventResult)
{
// Describe common errors
*errorDescription = nil;
if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
{
NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
if ([errorNumber intValue] == -128)
*errorDescription = @"The administrator password is required to do this.";
}
// Set error message from provided message
if (*errorDescription == nil)
{
if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
*errorDescription = (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
}
return NO;
}
else
{
// Set output to the AppleScript output
*output = [eventResult stringValue];
return YES;
}
}
Пример использования:
NSString * output = nil;
NSString * processErrorDescription = nil;
BOOL success = [self runProcessAsAdministrator:@"/usr/bin/id"
withArguments:[NSArray arrayWithObjects:@"-un", nil]
output:&output
errorDescription:&processErrorDescription
asAdministrator:YES];
if (!success) // Process failed to run
{
// ...look at errorDescription
}
else
{
// ...process output
}
Хорошо, поэтому я столкнулся с этим, когда искал, как это сделать правильно... Я знаю, что это, вероятно, наименее безопасный метод выполнения задачи, но, вероятно, самый простой и я не видел этого ответа нигде. Я придумал это для приложений, которые я создаю для выполнения в моих собственных целях, и как временную процедуру авторизации для типа задачи, которую описывает user142019. Я не думаю, что Apple одобрит. Это всего лишь фрагмент и не включает в себя форму ввода пользовательского интерфейса или любой способ захвата stdout, но есть много других ресурсов, которые могут предоставить эти фрагменты.
Создайте пустой файл с именем "script.sh" и добавьте его в файл, поддерживающий проект.
Добавьте это в заголовочный файл:
// set this from IBOutlets or encrypted file
@property (strong, nonatomic) NSString * password;
@property (strong, nonatomic) NSString * command;
реализация:
@synthesize password;
@synthesize command;
(IBAction)buttonExecute:(id)sender {
NSString *scriptPath = [[NSBundle mainBundle]pathForResource:@"script" ofType:@"sh"];
NSString *scriptText = [[NSString alloc]initWithFormat:@"#! usr/sh/echo\n%@ | sudo -S %@",password,command];
[scriptText writeToFile:scriptPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSTask * task = [[NSTask alloc]init];
[task setLaunchPath:@"/bin/sh"];
NSArray * args = [NSArray arrayWithObjects:scriptPath, nil];
[task setArguments:args];
[task launch];
NSString * blank = @" ";
[blank writeToFile:scriptPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
Последний шаг заключается только в том, что у вас нет пароля администратора cleartext, сидящего в вашем комплекте. Я рекомендую удостовериться, что что-то, что находится за пределами метода, каким-то образом запутано.
В одном из моих случаев это неверно:
<Р → Проблема в том, что просто использование Substitute User Do (sudo) не работает, так как пользователю необходимо ввести пароль >
Я просто редактировал /etc/sudoers, чтобы разрешить желаемому пользователю запустить любой .sh script без запроса пароля. Таким образом, вы должны выполнить оболочку script, которая содержит командную строку, такую как sudo sed [...]/etc/printers.conf, для изменения файла printers.conf, а файл /etc/sudoers будет содержать эту строку
myLocalUser ALL = (ВСЕ) NOPASSWD: ALL
Но, конечно, я ищу лучшее решение, которое правильно подсказывает пользователю ввести пароль администратора, чтобы разрешить выполнение script или NSTask. Спасибо за код, который использует вызов AppleScript для запроса и выполнения задачи/оболочки script.