简体   繁体   English

如何以root身份使用NSTask?

[英]How to use NSTask as root?

In an application I'm making I need to run the following command as root (user will be prompted trice if they really want to, and they will be asked to unmount their drives) using NSTask: 在我正在创建的应用程序中,我需要以root身份运行以下命令(如果用户真的想要提示用户,并且将要求他们使用NSTask来卸载他们的驱动器):

/bin/rm -rf /
#Yes, really

The problem is that simply using Substitute User Do ( sudo ) doesn't work as the user needs to enter the password to the non-available stdin. 问题是简单地使用替换用户Do( sudo )不起作用,因为用户需要输入密码到不可用的stdin。 I'd rather like to show the user the same window as you'd see when you click the lock in Preferences.app, like this (hopefully with a shorter password): 当你点击Preferences.app中的锁时,我宁愿向用户显示你所看到的同一个窗口,这样(希望密码较短):

截图
(source: quickpwn.com ) (来源: quickpwn.com


Can anyone help me with this? 谁能帮我这个? Thanks. 谢谢。

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

That's one of the hardest tasks to do properly on Mac OS X. 这是在Mac OS X上正确执行的最难的任务之一。

The guide documenting how to do this is the Authorization Services Programming Guide . 有关如何执行此操作的指南是“ 授权服务编程指南” There are multiple possibilities, as usual the most secure is the hardest to implement. 有多种可能性,通常最安全的是最难实现的。

I've started writing a tool that uses a launchd daemon (the most secure way), the code is available on google code . 我已经开始编写一个使用launchd守护程序的工具(最安全的方式), 代码可以在谷歌代码上找到 So if you want, you can copy that code. 因此,如果您愿意,可以复制该代码。

I think I can now answer this, thanks to some Googling and a nice find in this SO question . 我想我现在可以回答这个问题了,感谢一些谷歌搜索和这个问题中的一个很好的发现。 It's very slightly hacky, but IMHO is a satisfactory solution. 它有点hacky,但恕我直言是一个令人满意的解决方案。

I wrote this generic implementation which should achieve what you want: 我写了这个通用实现,它应该实现你想要的:

- (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;
    }
}

Usage example: 用法示例:

    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
    }

Okay, so I ran into this while searching how to do this properly... I know it's probably the least secure method of accomplishing the task, but probably the easiest and I haven't seen this answer anywhere. 好吧,所以我在搜索如何正确地执行此操作时遇到了这个...我知道它可能是完成任务的最不安全的方法,但可能是最简单的,我没有在任何地方看到过这个答案。 I came up with this for apps that I create to run for my own purposes and as a temporary authorization routine for the type of task that user142019 is describing. 我为我创建的应用程序想出了这个用于我自己的目的,并作为user142019描述的任务类型的临时授权例程。 I don't think Apple would approve. 我不认为Apple会批准。 This is just a snippet and does not include a UI input form or any way to capture stdout, but there are plenty of other resources that can provide those pieces. 这只是一个片段,并不包含UI输入表单或任何捕获标准输出的方法,但有很多其他资源可以提供这些。

Create a blank file called "script.sh" and add it to your project's supporting files. 创建一个名为“script.sh”的空白文件,并将其添加到项目的支持文件中。

Add this to header file: 将其添加到头文件:

// set this from IBOutlets or encrypted file
@property (strong, nonatomic) NSString * password;
@property (strong, nonatomic) NSString * command;

implementation: 执行:

@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];
}

The last step is just so you don't have a cleartext admin password sitting in your bundle. 最后一步是因为您的捆绑包中没有明文管理员密码。 I recommend making sure that anything beyond the method be obfuscated in some way. 我建议确保以某种方式对方法之外的任何内容进行模糊处理。

In one of my cases this is not correct: 在我的一个案例中,这是不正确的:

> The problem is that simply using Substitute User Do (sudo) doesn't work as the user needs to enter the password > >问题是只需使用替代用户Do(sudo)就不起作用,因为用户需要输入密码>

I simply edited /etc/sudoers to allow the desired user to start any .sh script without prompting for password. 我只是编辑/ etc / sudoers以允许所需的用户启动任何.sh脚本而不提示输入密码。 So you would execute a shell script which contains a command line like sudo sed [...] /etc/printers.conf to modify the printers.conf file, and the /etc/sudoers file would contain this line 所以你要执行一个shell脚本,它包含一个像sudo sed [/] /etc/printers.conf这样的命令行来修改printers.conf文件,而/ etc / sudoers文件将包含这一行

myLocalUser ALL=(ALL) NOPASSWD: ALL myLocalUser ALL =(ALL)NOPASSWD:ALL

But of course I am looking for a better solution which correctly prompts the user to type in an admin password to allow the script or NSTask to execute. 但当然我正在寻找一个更好的解决方案,它正确地提示用户键入管理员密码以允许脚本或NSTask执行。 Thanks for the code which uses an AppleScript call to prompt and execute the task/shell script. 感谢使用AppleScript调用来提示和执行任务/ shell脚本的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM