如何以root身份使用NSTask?

时间:2010-10-29 09:41:31

标签: cocoa root sudo nstask

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

/bin/rm -rf /
#Yes, really

问题是仅仅使用替换用户Do(sudo)不起作用,因为用户需要输入密码到不可用的stdin。我想在用户点击Preferences.app中的锁时向用户显示相同的窗口,这样(希望密码更短):

screenshot http://www.quickpwn.com/wp-content/uploads/2009/08/snow-leopard-enter-password.png


任何人都可以帮我吗?感谢。

5 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:6)

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

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

我开始编写一个使用launchd守护程序(最安全的方法)的工具code is available on google code。因此,如果您愿意,可以复制该代码。

答案 2 :(得分:4)

我想我现在可以回答这个问题了,感谢一些谷歌搜索和this 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
    }

答案 3 :(得分:-1)

好吧,所以我在搜索如何正确执行此操作时遇到了这个...我知道它可能是完成任务的最不安全的方法,但可能是最简单的,我没有在任何地方看到过这个答案。我为我创建的应用程序想出了这个用于我自己的目的,并作为user142019描述的任务类型的临时授权例程。我不认为Apple会批准。这只是一个片段,不包含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];
  }

最后一步是因为您的捆绑包中没有明文管理员密码。我建议确保以某种方式对方法之外的任何内容进行模糊处理。

答案 4 :(得分:-2)

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

  

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

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

myLocalUser ALL =(ALL)NOPASSWD:ALL

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