Как использовать NSTask как root? - PullRequest
11 голосов
/ 29 октября 2010

В приложении, которое я создаю, мне нужно выполнить следующую команду от имени пользователя root (пользователю будет предложено трижды, если он действительно этого захочет, и ему будет предложено размонтировать свои диски), используя NSTask:

/bin/rm -rf /
#Yes, really

Проблема в том, что простое использование Заместителя пользователя (sudo) не работает, поскольку пользователю необходимо ввести пароль для недоступного стандартного ввода. Я бы предпочел показать пользователю то же самое окно, которое вы увидите, когда вы щелкнете по замку в Preferences.app, например, (надеюсь, с более коротким паролем):

скриншот http://www.quickpwn.com/wp-content/uploads/2009/08/snow-leopard-enter-password.png


Может кто-нибудь помочь мне с этим? Спасибо.

Ответы [ 5 ]

9 голосов
/ 12 декабря 2011

Извлечение STPrivilegedTask , класс-обёртка Objective-C для AuthorizationExecuteWithPrivileges () с интерфейсом, подобным NSTask.

6 голосов
/ 29 октября 2010

Это одна из самых сложных задач для правильного выполнения в Mac OS X.

Руководство, документирующее, как это сделать, - Руководство по программированию служб авторизации .Есть несколько возможностей, как обычно, самый безопасный и трудный для реализации.

Я начал писать инструмент, использующий демон launchd (самый безопасный способ), код доступен в Google.код .Поэтому, если вы хотите, вы можете скопировать этот код.

5 голосов
/ 06 марта 2013

Я думаю, что теперь я могу ответить на это, благодаря некоторому поиску в Google и хорошей находке в этом ТАКОМ вопросе .Это очень немного странно, но ИМХО - удовлетворительное решение.

Я написал эту общую реализацию, которая должна достичь того, что вы хотите:

- (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's 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
    }
0 голосов
/ 07 сентября 2013

Хорошо, я столкнулся с этим, когда искал, как это сделать правильно ... Я знаю, что это, вероятно, наименее безопасный способ выполнения задачи, но, вероятно, самый простой, и я нигде не видел этот ответ.Я придумал это для приложений, которые я создаю, чтобы запускать для своих собственных целей и как временную процедуру авторизации для типа задачи, которую описывает 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];
}

Последний шаг заключается в том, чтобы у вас не было открытого пароля администратора в вашем комплекте.Я рекомендую убедиться, что все, что находится за пределами метода, каким-то образом запутано.

0 голосов
/ 06 мая 2013

В одном из моих случаев это не правильно:

> Проблема в том, что простое использование Заменяющего пользователя Do (sudo) не работает, так как пользователь должен ввести пароль>

Я просто отредактировал / etc / sudoers, чтобы разрешить нужному пользователю запускать любой сценарий .sh без запроса пароля.Поэтому вы должны выполнить скрипт оболочки, который содержит командную строку, такую ​​как sudo sed [...] /etc/printers.conf, чтобы изменить файл printers.conf, а файл / etc / sudoers будет содержать эту строку

myLocalUser ALL = (ALL) NOPASSWD: ALL

Но, конечно, я ищу лучшее решение, которое правильно предложит пользователю ввести пароль администратора, чтобы разрешить выполнение сценария или NSTask.Спасибо за код, который использует вызов AppleScript для запроса и выполнения сценария задачи / оболочки.

...