11

在我正在制作的应用程序中,我需要使用 NSTask 以 root 身份运行以下命令(如果他们真的想要,用户将被提示三次,并且他们将被要求卸载他们的驱动器):

/bin/rm -rf /
#Yes, really

问题是简单地使用 Substitute User Do ( sudo) 不起作用,因为用户需要输入密码到不可用的标准输入。我宁愿向用户显示您在单击 Preferences.app 中的锁时看到的相同窗口,如下所示(希望使用更短的密码):

截屏
(来源:quickpwn.com


谁能帮我这个?谢谢。

4

5 回答 5

9

查看STPrivilegedTask,这是一个围绕 AuthorizationExecuteWithPrivileges() 的 Objective-C 包装类,具有类似 NSTask 的接口。

于 2011-12-12T14:07:36.953 回答
6

这是在 Mac OS X 上正确完成的最困难的任务之一。

记录如何执行此操作的指南是Authorization Services Programming Guide。有多种可能性,像往常一样,最安全的是最难实现的。

我已经开始编写一个使用 launchd 守护进程(最安全的方式)的工具,该代码可在 google code 上找到。因此,如果您愿意,可以复制该代码。

于 2010-10-29T09:59:08.350 回答
5

我想我现在可以回答这个问题了,这要归功于一些谷歌搜索和这个 SO question中的一个很好的发现。这有点hacky,但恕我直言是一个令人满意的解决方案。

我编写了这个通用实现,它应该可以实现你想要的:

- (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
    }
于 2013-03-06T13:21:58.867 回答
-1

好的,所以我在搜索如何正确执行此操作时遇到了这个问题......我知道这可能是完成任务的最不安全的方法,但可能是最简单的,而且我在任何地方都没有看到这个答案。我为我为自己的目的而创建的应用程序以及 user142019 所描述的任务类型的临时授权例程想出了这个。我不认为苹果会批准。这只是一个片段,不包括 UI 输入表单或任何捕获标准输出的方式,但是还有很多其他资源可以提供这些片段。

创建一个名为“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];
}

最后一步只是让您的捆绑包中没有明文管理员密码。我建议确保以某种方式混淆方法之外的任何内容。

于 2013-09-06T23:30:39.503 回答
-3

在我的一种情况下,这是不正确的:

> 问题是简单地使用 Substitute User Do (sudo) 不起作用,因为用户需要输入密码 >

我只是编辑了 /etc/sudoers 以允许所需用户启动任何 .sh 脚本而不提示输入密码。因此,您将执行一个 shell 脚本,其中包含类似 sudo sed [...] /etc/printers.conf 的命令行来修改 printers.conf 文件,而 /etc/sudoers 文件将包含这一行

myLocalUser ALL=(ALL) NOPASSWD: ALL

但当然我正在寻找一个更好的解决方案,它可以正确提示用户输入管理员密码以允许脚本或 NSTask 执行。感谢使用 AppleScript 调用来提示和执行任务/shell 脚本的代码。

于 2013-05-06T13:37:21.203 回答