AuthorizationExecuteWithPrivileges已经被弃用。

38
自从我更新到OSX 10.7 Lion后,Xcode告诉我AuthorizationExecuteWithPrivileges已经被弃用。
有人能建议一种方法让我的应用程序写入一个没有权限的目录吗?
4个回答

37

我知道这听起来很疯狂,但是这个确实有效

NSDictionary *error = [NSDictionary new]; 
NSString *script =  @"do shell script \"whoami > /tmp/me\" with administrator privileges";  
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script]; 
if ([appleScript executeAndReturnError:&error]) {
  NSLog(@"success!"); 
} else {
  NSLog(@"failure!"); 
}

我从Objective C执行一个Applescript。唯一的劣势是你不能用它获得永久的root权限。每次运行此操作时,它都会要求输入密码。


6
看那个,所以你就是“root”?哦等等,我才是。不,等等,是“AppleScript”吗?我的天啊,这确实太疯狂了。唯一更疯狂的事情就是它没有要求你输入密码,哈哈。 - Alex Gray
1
我尝试使用它,但它从未要求我输入密码。相反,它直接跳过并打印“失败!”当我打印错误描述时,我得到了这个:“NSAppleScriptErrorMessage =“管理员用户名或密码不正确。””这是在启用沙盒的应用程序中...有没有人有建议适用于启用沙盒的应用程序? - ArtOfWarfare
1
请注意:如在技术笔记TN2065:AppleScript中的do shell script所述(http://developer.apple.com/library/mac/#technotes/tn2065/_index.html):请按以下方式使用管理员特权、用户名和密码参数:do shell script "command" user name "me" password "mypassword" with administrator privileges - geowar
请注意,线程编程指南中提到NSAppleScript类必须仅从应用程序的主线程中使用。尽管我自己在主线程之外也使用它,但没有任何问题。 - cody
如果您想获得永久的 root 权限,可以采取以下步骤:a)创建一个独立的二进制文件来以 root 身份执行您想要的操作,b)将该二进制文件复制到一个安全可写的位置(例如 /Library/Application Support/xxx),c)设置该二进制文件的 setuid 位,d)将二进制文件的所有者更改为 root,e)适当地更改二进制文件的权限。也许有一天我会在 Github 上创建一个示例项目… - kainjow
显示剩余3条评论

36

实际上,AuthorizationExecuteWithPrivileges() 已经被弃用很长时间了,只是最近头文件才跟上了这个事实。

您可以创建一个特权辅助工具作为应用程序的一部分。您可以使用 ServiceManagement.frameworkSMJobBless() 函数将助手部署到系统的 launchd 上下文中:然后当您需要执行特权任务时,只需向特权助手发送消息即可完成该工作。

有一点隐藏的复杂性,即应用程序和助手必须在 SMJobBless() 之前声明彼此的签名身份,而且您需要让链接器将助手工具的 Info.plist 文件写入二进制文件中。所有这些都由 Apple's Documentation 所涵盖,而 Apple 也提供了 a sample project

编写了一个示例应用程序,使用SMJobBless()来部署其特权助手。


嗨,感谢您的回复。如果AuthorizationExecuteWithPrivileges()已经被弃用很长时间了,它是否仍然应该继续工作?基本上,自从Lion更新以来,这在我的应用程序中就不能再工作了,我认为这是因为它现在被标记为过时了...它实际上是否仍然可以工作,并且我的问题在其他地方?非常感谢。 - Phill
4
你不应该依赖于AuthorizationExecuteWithPrivileges(),它是一个可怕的安全漏洞。实现你想要做的事情的正确方式是使用SMJobBless() - user23743
@GrahamLee 那么在安装程序中使用 AuthorizationExecuteWithPrivileges 呢?参考文档表示“您应该仅将此函数用于允许安装程序作为根运行,并允许 setuid 工具在其 setuid 位丢失时修复其 setuid 位”,并且《Authorization Services Programming Guide》建议使用此函数启动安装程序(尽管它有些过时)。那么在像命令行工具这样的简单应用程序中启动安装程序是否有任何替代方法? - cody
那也过时了。如果您正在使用系统管理,则可以在没有安装程序的情况下部署特权组件。 - user23743
4
@GrahamLee,好的,如果我有一个pkg文件,想要在上面启动“installer” 实用工具,但是不使用已弃用的功能,我该怎么做呢?我能否使用系统实用工具来作为辅助工具?我知道可以使用NSWorkspace类来启动安装程序,但我不需要图形界面安装应用程序,我想要静默安装,并且需要安装过程的退出代码,所以我需要等待它。在这种情况下,你可以提供什么建议? - cody
显示剩余3条评论

18

根据用户950473的发现,我已经将其发现实现为一个方法。我觉得分享这段代码可能会有帮助。

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


    if (!success) // Process failed to run
    {
         // ...look at errorDescription 
    }
    else
    {
         // ...process output
    }

这个方法有些取巧,但在我看来是一个令人满意的解决方案。


1
如果脚本路径中有空格,这种方法就会失败,而如果您想运行包含在应用程序包中的脚本,则很可能会出现这种情况。为了解决这个问题,只需在设置fullScript时更改格式为@"'%@' %@",以便进程路径名称被引用。 - Jim
你好,有没有办法在密码提示中添加应用程序图标以取代空白文件?您有解决方案吗? - Yann86
@Yann86 我不这么认为,因为提示是由Applescript本身提供的。 - Carlos P

7

AuthorizationExecuteWithPrivileges已经被弃用了。
但是,幸运的是,现在有一个新的推荐方法可供使用。

从10.6开始,有了新API,并且建议安装一个帮助程序来执行特权操作。苹果提供了一个代码示例,清楚地演示了如何管理它。

请确保查看他们的readme.txt,因为与其他代码示例相比,还需要做更多的工作,而不仅仅是下载项目并运行它。

来自SMJobBless示例介绍

SMJobBless演示了如何安全地安装执行特权操作的帮助工具,以及如何将该工具与调用它的应用程序相关联。

从Snow Leopard开始,在Mac OS X上管理权限升级的首选方法是使用此方法,而不是以前的方法,如BetterAuthorizationSample或直接调用AuthorizationExecuteWithPrivileges。

SMJobBless使用在Mac OS X v10.6 Snow Leopard中引入的ServiceManagement.framework。

来源:Apple SMJobBless代码示例


你为什么这么说?我今天使用提供的链接和非付费开发者账户,成功下载了示例代码。 - Jean
3
你是否已成功地完成过一个项目?这是在要求使用OSX开发者账户对应用程序进行代码签名。 - Fast Engy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接