STPrivilegedTask запрашивает пароль для каждой задачи

Я хотел бы начать много NSTasks, которые требуют прав root, я обнаружил, что должен использовать Apple Authorization Kit, и я нашел STPrivilegedTask, который предназначен для этого.

Дело в том, что когда я запускаю STPrivilegedTask, он будет запрашивать у меня пароль root каждый раз. Есть ли способ ввести пароль root для первой привилегированной задачи, а затем для других задач приложение будет помнить пароль root, поэтому пользователю не нужно будет вводить пароль снова и снова и снова?

Ответ 1

В зависимости от вашего варианта использования вы можете быть счастливы, просто заменив инициализацию authorizationRef в STPrivilegedTask -launch на что-то вроде...

// create authorization reference
static AuthorizationRef authorizationRef = NULL;
@synchronized(self) {
    if (!authorizationRef) {
        err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
        if (err != errAuthorizationSuccess) { return err; }
    }
}

... и затем удалив AuthorizationFree:

// free the auth ref
AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);

Это позволит вам запускать задачи без приглашения пароля для пять минут.

Если вам нужно больше управления, создайте Command Line Tool in Xcode, который выполняет нужные команды, используя обычные вызовы NSTask.

Когда вы запускаете инструмент с помощью STPrivilegedTask или AuthorizationExecuteWithPrivileges, команды NSTask будут запускаться с правами администратора (euid = 0).

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

Это намного сложнее, чтобы сделать это правильно, используя AuthorizationExecuteWithPrivileges.

Примечания к SMJobBless

SMJobBless запрашивает пароль и устанавливает помощника.

Когда вы разговариваете с помощником, запрос на ввод пароля не будет.

собственный пример Apple, это довольно запутанно, но есть other примеры.

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

Возможно, вы могли бы обеспечить соблюдение требований подписи кода (PROPERTY LISTSраздела этого документа), но я не смог найти примеров, которые сделайте это.

Я использовал AuthorizationExecuteWithPrivileges пару лет назад для установки демона launchd, но мне еще предстоит запутать себя с SMJobBless.

Ответ 2

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

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

 // run a terminal command for admin privileges available or not
NSString* csPluginDirectoryPath = [NSString stringWithFormat:@"%@/supportFiles",[CommonMethods getResourceFolderPath]];
NSString* tapPathCommand = [NSString stringWithFormat:@"chown root %@/tap.kext", csPluginDirectoryPath];

//if app has not admin privileges then it return error text
// if application has admin privileges it will return empty message
NSString* csErrorMessage = [self ExecuteSudoTerminalCommand:tapPathCommand];

if(csErrorMessage && [csErrorMessage length] > 2)
{
// go for admin privileges 
[self launchHelperTool];
}

-(NSString*) ExecuteSudoTerminalCommand:(NSString*) terminalCommands
{
    NSString* resultOfScript = @"";
    NSString* csScript = [NSString stringWithFormat:@"do shell script \"%@\"",terminalCommands];
    NSDictionary* errors = [NSDictionary dictionary];
    NSAppleScript* appleScript = [[NSAppleScript alloc] initWithSource:csScript];
    NSAppleEventDescriptor* descriptor = [appleScript executeAndReturnError:&errors];

    if(descriptor == nil)
    {
        resultOfScript = [errors objectForKey:@"NSAppleScriptErrorMessage"];

    }
    else
        resultOfScript = [descriptor stringValue];

    return resultOfScript;
}

-(void) launchHelperTool
{
    helperToolPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/Chameleon VPN"];

    NSBundle *thisBundle = [NSBundle mainBundle];
    NSString* commonDictionaryPath = [[thisBundle bundleURL] absoluteString];
    commonDictionaryPath = [commonDictionaryPath substringToIndex:commonDictionaryPath.length - 1];

    commonDictionaryPath = [commonDictionaryPath stringByReplacingOccurrencesOfString:@"file:/" withString:@""];

    NSArray *args = [NSArray arrayWithObjects:helperToolPath, commonDictionaryPath, nil];
    NSTask *task = [NSTask launchedTaskWithLaunchPath:helperToolPath arguments:args];
    [task waitUntilExit];

    int status = [task terminationStatus];
    if (status == 0)
    {
        NSLog(@"Task succeeded.");
    }
    else
    {
        NSLog(@"Task failed.");
        exit(0);
    }
}