【问题标题】:OSX launchctl programmatically as rootOSX 以 root 身份以编程方式启动
【发布时间】:2014-10-12 08:17:22
【问题描述】:

我正在尝试使用来自 OSX 应用程序的 launchctl 作为 root 启动 samba 服务,但我得到错误状态 -60031。我可以毫无问题地在终端中运行命令:

sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.smbd.plist

在 Objective-c 代码中,我正在使用(我知道它已被弃用,但这不应该是这里的问题)AuthorizationExecuteWithPrivileges 方法。

代码如下:

    NSString *command = @"launchctl";

    // Conversion of NSArray args to char** args here (not relevant part of the code)

    OSStatus authStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &_authRef);
    if (authStatus != errAuthorizationSuccess) {
        NSLog(@"Failed to create application authorization: %d", (int)authStatus);
        return;
    }

    FILE* pipe = NULL;
    AuthorizationFlags flags = kAuthorizationFlagDefaults;
    AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
    AuthorizationRights rights = {1, &right};

    // Call AuthorizationCopyRights to determine or extend the allowable rights.
    OSStatus stat = AuthorizationCopyRights(_authRef, &rights, NULL, flags, NULL);
    if (stat != errAuthorizationSuccess) {
        NSLog(@"Copy Rights Unsuccessful: %d", (int)stat);
        return;
    }

    OSStatus status = AuthorizationExecuteWithPrivileges(_authRef,
                                                         command.UTF8String,
                                                         flags,
                                                         args,
                                                         &pipe);
    if (status != errAuthorizationSuccess) {
        NSLog(@"Error executing command %@ with status %d", command, status);
    } else {
        // some other stuff
    }

我也尝试过使用不同的标志然后是 kAuthorizationFlagDefaults,但这会导致相同的问题或错误代码 -60011 -> 标志无效。

请问我这里做错了什么?

【问题讨论】:

    标签: objective-c macos cocoa shell


    【解决方案1】:

    我建议使用 STPrivilegedTask - https://github.com/sveinbjornt/STPrivilegedTask

    我有类似的问题,我发现上面写得很好的包装器。这是直截了当的,非常简单。 必要时可以根据自己的需要进行修改,否则直接使用!!!

    它对我有用,我希望它也能帮助你。

    谢谢。

    更新(2014 年 8 月 28 日): 以 root 权限执行命令 和以 root 权限执行命令 之间是有区别的!

    在您的特定情况下,您正在尝试加载/卸载守护程序(必须属于 root)。在这种情况下,您必须以 root 身份执行命令。如果您尝试仅使用 root 权限加载/卸载,那么您将在您的用户下运行守护程序! - 不好!

    现在,您的代码示例和我对 STPrivilegedTask 的引用都使用相同的代码并允许用户以 root 权限而不是 作为 root 执行任务!为了以 root 身份执行,您有多种选择。首先,您可能想查看 Apple Docs 以了解推荐的方式。就我而言,我无法采用推荐的方式,因为我的应用程序没有签名也不会被签名+它需要在旧的 OSX 上工作。

    所以我的解决方案很简单。制作一个命令实用程序帮助工具,让它假设 root 并执行您通过参数传递给它的任何内容。现在请记下(这不是很安全的做事方式)。另请注意,您将使用 root 权限调用帮助工具,它将假定为 root 身份。

    代码:

     int main(int argc, const char * argv[])
     {
    
    @autoreleasepool {
    
        if (argc >= 2)
        {
            setuid(0);  // Here is a key - set user id to 0 - meaning become a root and everything below executes as root.
    
            NSMutableArray *arguments = [[NSMutableArray alloc] init];
            NSString *command = [[NSString alloc] initWithFormat:@"%s", argv[1]];
    
            for (int idx = 2; idx < argc; idx++) {
                NSString *tmp = [[NSString alloc] initWithFormat:@"%s", argv[idx]];
                [arguments addObject:tmp];
            }
    
            NSTask *task = [[NSTask alloc] init];
            [task setLaunchPath:command];
            [task setArguments:arguments];
    
            NSPipe * out = [NSPipe pipe];
            [task setStandardOutput:out];
            [task launch];
    
            [task waitUntilExit];
    
            NSFileHandle * read = [out fileHandleForReading];
            NSData * dataRead = [read readDataToEndOfFile];
            NSString * stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];
    
            printf("%s", [stringRead UTF8String]);
    
            }
         return 0;
         }
     }
    

    【讨论】:

    • 谢谢!我要竖起大拇指,虽然我还没有尝试过。我最终使用了这个:stackoverflow.com/questions/6841937/… 我仍然想尝试 arri 提供的解决方案,如果可以避免用苹果脚本破解它(它会产生自己的密码提示,这是不可取的)
    • 谢谢,我正在解决类似的问题,我发现您无法通过上述示例或使用 STPriviliegedTask 加载/卸载守护进程。如果您需要解决方案,请告诉我。
    • “通过上述示例”是什么意思 -> 我作为问题发布的那个,还是我在此评论中发布的 Apple 脚本?因为对我来说,Apple Script 可以工作,但它会产生重复的密码提示,这不是完全可取的;
    • “以上示例” - 表示问题中的一个。我有一个没有 AppleScript 的解决方案。如果你想看,请告诉我。
    • 是的,我想看看,拜托
    【解决方案2】:

    查看the documentation,您的代码似乎缺少kAuthorizationFlagExtendRights标志,这是安全管理服务器授予请求权限时所必需的。相关摘录;

    ...kAuthorizationFlagDefaultsconstant 将位掩码归零。这 kAuthorizationFlagExtendRightsconstant 指示安全服务器 授予权利。 没有这个标志,AuthorizationCopyRights andAuthorizationCreatefunctions 将返回相应的错误 代码,但不会向用户扩展任何权利 ...

    来自kAuthorizationFlagExtendRights的文档:

    kAuthorizationFlagExtendRights

    如果设置了此掩码指定的位,安全管理服务器会尝试 授予所请求的权利 ...

    尝试在调用AuthorizationCopyRights() 之前将此标志添加到您的flags,并且可能还包括kAuthorizationFlagPartialRights 以进一步限制授予的权限。

    【讨论】:

    • 然而,正如我所提到的,写这个:flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; 会产生错误代码 -60011(无效标志)。我不明白为什么它会那样做。也许我的 AuthorizationCreate 调用有问题?请问你知道答案吗?
    • 啊,我没有看到任何地方提到kAuthorizationFlagExtendRights,所以认为这可能是您忽略的内容。
    • 但完全有可能,我错过了这些权利,但我不明白为什么我得到那个无效标志错误代码......代码来自苹果文档,所以我会期待它工作;o)
    猜你喜欢
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 2022-10-16
    • 2013-01-29
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多