代码之家  ›  专栏  ›  技术社区  ›  Form

从Cocoa应用程序获取使用rm删除文件的管理员权限

  •  9
  • Form  · 技术社区  · 14 年前

    我正在制作一个删除日志文件的小应用程序。我正在使用一个运行rm和srm(安全rm)的nstask实例来删除文件。

    我希望能够删除以下位置的文件:

    • 库/日志
    • ~/库/日志

    问题是用户帐户没有权限访问系统库文件夹中的某些文件,例如Adobe Logs子文件夹和其他文件。例如,只有“系统”用户(组?)对Adobe Logs文件夹及其内容具有R/W权限,当前用户甚至在该文件夹的“获取信息”窗口中显示的权限中没有条目。

    我想做的是:

    1. 获取管理员权限。
    2. 将密码存储在钥匙链中,这样应用程序就不必每次都对用户唠叨(存储密码是个坏主意吗?有可能吗?)
    3. 删除文件,无论文件权限是什么。

    我正在使用nstask,因为它提供任务完成通知、从任务本身获取文本输出等。是否需要使用其他功能?如果是这样,在以管理员权限运行RM和SRM时,如何复制NSTASK的完成通知和输出文件句柄?

    我正在寻找最安全的方法来处理这种情况。也就是说,我不希望我的应用程序成为特权升级攻击的入口。

    我看过授权服务编程指南,但我不确定哪种情况适合。起初我以为 AuthorizationExecuteWithPrivileges 这是一个好主意,但是在阅读了更多关于这个主题的内容之后,出于安全原因,似乎不建议使用这种方法。

    一个详细的答案将是非常受欢迎的。我相信你们中的一些人已经做了类似的事情,并且有一些代码和知识要分享。

    事先谢谢!

    更新:

    我现在可以弹出身份验证对话框并获得特权,如下所示:

    OSStatus status;
    AuthorizationRef authRef;
        status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef);
    
    AuthorizationRights authRights;
    AuthorizationItem authItems[1];
    
    authItems[0].name = kAuthorizationRightExecute;
    
    authRights.count = sizeof(authItems) / sizeof(authItems[0]);
    authRights.items = authItems;
    
    AuthorizationFlags authFlags = kAuthorizationFlagDefaults | kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed;
    
    status = AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, authFlags, NULL);
    

    从外观上看,“分解应用程序”方法看起来最合适。问题是,对我来说, RM似乎已经是一个外部助手工具了 . 我不确定是否得到文档中建议的setuid替代方法。我可以在rm上设置setuid位并使用我已经实现的nstask方法运行它吗?这意味着我不需要创建自己的助手工具。有人能详细阐述一下这个问题吗?

    我还研究了betterauthorizationsample,它被建议作为setuid位方法的一个更安全和最新的替代方法,但是发现它对于简单的行为来说非常复杂。有什么暗示吗?

    提前感谢您的帮助!

    2 回复  |  直到 13 年前
        1
  •  4
  •   John Gallagher    14 年前

    几个月前我头痛。我试图让一个shell脚本以管理员权限运行,在某个时间关闭我的计算机。我感觉到你的痛苦。

    我用了BetterAuthorizationSample,这简直是一场噩梦。但我采取了最务实的方法——我不费心去理解正在发生的一切,我只是抓住了代码的勇气。

    我没花那么长时间就把它变成我想要的。我记不清我修改了什么,但欢迎您查看我的代码:

    http://github.com/johngallagher/TurnItOff

    我希望这有助于您寻求一个安全的应用程序!

        2
  •  8
  •   Alex    13 年前

    也许有点晚了,但这可能对其他人的未来参考有用。大部分代码来自 this person .

    基本上,这与Mac上的授权有很大关系。你可以多读一些 here here .

    使用RM工具的代码:

    + (BOOL)removeFileWithElevatedPrivilegesFromLocation:(NSString *)location
    {
        // Create authorization reference
        OSStatus status;
        AuthorizationRef authorizationRef;
    
        // AuthorizationCreate and pass NULL as the initial
        // AuthorizationRights set so that the AuthorizationRef gets created
        // successfully, and then later call AuthorizationCopyRights to
        // determine or extend the allowable rights.
        // http://developer.apple.com/qa/qa2001/qa1172.html
        status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
        if (status != errAuthorizationSuccess)
        {
            NSLog(@"Error Creating Initial Authorization: %d", status);
            return NO;
        }
    
        // kAuthorizationRightExecute == "system.privilege.admin"
        AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
        AuthorizationRights rights = {1, &right};
        AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
                                    kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
    
        // Call AuthorizationCopyRights to determine or extend the allowable rights.
        status = AuthorizationCopyRights(authorizationRef, &rights, NULL, flags, NULL);
        if (status != errAuthorizationSuccess)
        {
            NSLog(@"Copy Rights Unsuccessful: %d", status);
            return NO;
        }
    
        // use rm tool with -rf
        char *tool = "/bin/rm";
        char *args[] = {"-rf", (char *)[location UTF8String], NULL};
        FILE *pipe = NULL;
    
        status = AuthorizationExecuteWithPrivileges(authorizationRef, tool, kAuthorizationFlagDefaults, args, &pipe);
        if (status != errAuthorizationSuccess)
        {
            NSLog(@"Error: %d", status);
            return NO;
        }
    
        // The only way to guarantee that a credential acquired when you
        // request a right is not shared with other authorization instances is
        // to destroy the credential.  To do so, call the AuthorizationFree
        // function with the flag kAuthorizationFlagDestroyRights.
        // http://developer.apple.com/documentation/Security/Conceptual/authorization_concepts/02authconcepts/chapter_2_section_7.html
        status = AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
        return YES;
    }