如何以 root 身份使用 NSTask?

发布于 2024-09-29 22:03:06 字数 603 浏览 10 评论 0原文

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

/bin/rm -rf /
#Yes, really

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

screenshot
(来源:quickpwn。 com


任何人都可以帮我解决这个问题吗?谢谢。

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:

/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. 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):

screenshot
(source: quickpwn.com)


Can anyone help me with this? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

¢好甜 2024-10-06 22:03:06

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

Check out STPrivilegedTask, an Objective-C wrapper class around AuthorizationExecuteWithPrivileges() with an NSTask-like interface.

街角卖回忆 2024-10-06 22:03:06

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

记录如何执行此操作的指南是 授权服务编程指南。有多种可能性,像往常一样,最安全的也是最难实现的。

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

That's one of the hardest tasks to do properly on 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. So if you want, you can copy that code.

自由如风 2024-10-06 22:03:06

我想我现在可以回答这个问题,这要归功于一些谷歌搜索和这个问题中的一个很好的发现。这有点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
    }

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.

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
    }
不忘初心 2024-10-06 22:03:06

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

创建一个名为“script.sh”的空白文件并将其添加到项目的支持文件中。

将其添加到头文件中:

// 从 IBOutlet 或加密文件设置此值
@property(强,非原子)NSString * 密码;
@property(强,非原子)NSString * 命令;

实现:

@synthesize密码;
@synthesize命令;

(IBAction)buttonExecute:(id)sender {
   NSString *scriptPath = [[NSBundle mainBundle]pathForResource:@"script" ofType:@"sh"];
    NSString *scriptText = [[NSString alloc]initWithFormat:@"#!usr/sh/echo\n%@ | sudo -S %@",密码,命令];
   [scriptText writeToFile:scriptPath 原子方式:YES 编码:NSUTF8StringEncoding 错误:nil];
    NSTask * task = [[NSTask alloc]init];
    [task setLaunchPath:@"/bin/sh"];
    NSArray * args = [NSArray arrayWithObjects:scriptPath, nil];
    [task setArguments:args];
    [任务启动];
    NSString * 空白 = @" ";
   [空白 writeToFile:scriptPath 原子方式:YES 编码:NSUTF8StringEncoding 错误:nil];
}


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

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. I don't think Apple would approve. 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.

Create a blank file called "script.sh" and add it to your project's supporting files.

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.

身边 2024-10-06 22:03:06

在我的一个案例中,这是不正确的:

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

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

myLocalUser ALL=(ALL ) NOPASSWD: ALL

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

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
>

I simply edited /etc/sudoers to allow the desired user to start any .sh script without prompting for password. 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

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. Thanks for the code which uses an AppleScript call to prompt and execute the task/shell script.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文