以根用户身份在OSX中以编程方式启动launchctl

6

我正在尝试使用launchctl从OSX应用程序作为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 -> 无效标志。

请问我在这里做错了什么?

2个回答

4
我建议使用STPrivilegedTask - https://github.com/sveinbjornt/STPrivilegedTask
我曾经遇到过类似的问题,并找到了上述精心编写的包装器。它非常简单直接。 如果需要,您可以根据自己的需求进行修改,否则请直接使用它! 这对我起作用了,希望能够帮助到你。
谢谢。
更新(Aug 28, 2014): 执行具有root权限的命令和以root身份执行命令之间存在区别!
在您的特定情况下,您正在尝试加载/卸载守护程序(必须属于root)。 在这种情况下,您必须以root身份执行命令。 如果您尝试仅使用具有root权限来加载/卸载,则会在用户下运行守护进程!- 不好!
现在,您的代码示例和我的参考STPrivilegedTask都使用相同的代码,允许用户使用root权限执行任务,但不是以root身份!为了以root身份执行,您有几种选择。 首先,您可能想查看苹果文档中的推荐方式。 在我的情况下,我不能使用推荐方式,因为我的应用程序没有签名,也不会签名+它需要在旧的OSX上工作。
所以我的解决方案很简单。 制作一个命令实用程序辅助工具,让它承担root并通过参数执行任何传递给它的内容。现在请注意(这不是非常安全的做事方式)。 还要注意,您将使用root权限调用helper tool,并且它将承担根身份。 代码:
 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;
     }
 }

谢谢!我会点赞的,虽然我还没有尝试过。最终我使用了这个:https://dev59.com/oWw15IYBdhLWcg3wFHtZ如果可能的话,我仍然想尝试arri提供的解决方案,以避免使用苹果脚本进行黑客攻击(这会产生自己的密码提示,这是不可取的)。 - Lukas1
谢谢,我正在处理类似的问题,我发现你不能通过上述示例或使用STPriviliegedTask来加载/卸载守护程序。如果你需要解决方案,请告诉我。 - MeIr
上面的例子 - 指问题中的那个。我有一个不需要使用AppleScript的解决方案。如果您想看看,请告诉我。 - MeIr
嗨,感谢更新。代码运行并且没有从NSTask生成错误(这有点奇怪,我本来期望会有什么错误),但它没有启动Samba守护进程。我不明白为什么。我想它可以用于启动其他守护进程,但不适用于Samba...似乎坚持苹果脚本解决方案(对我有效)是我的唯一选择。 - Lukas1
顺便提一下,setuid(0)似乎根本没有起作用。 - Lukas1
显示剩余6条评论

0

文档来看,您的代码似乎缺少kAuthorizationFlagExtendRights标志,当安全服务器授予请求的权限时,该标志是必需的。相关摘录如下:

... kAuthorizationFlagDefaults常量将位掩码设置为零。 kAuthorizationFlagExtendRights常量指示安全服务器授予权限。如果没有此标志,则AuthorizationCopyRightsAuthorizationCreate函数将返回适当的错误代码,但不会向用户授予任何权限 ...

kAuthorizationFlagExtendRights的文档中可以看到:

kAuthorizationFlagExtendRights

如果设置了此掩码指定的位,则安全服务器尝试授予请求的权限 ...

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


然而,正如我所提到的,编写以下代码: flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; 会产生错误代码-60011(无效标志)。我不明白为什么会这样。也许我的AuthorizationCreate调用存在问题?您知道答案吗? - Lukas1
啊,我没有看到任何地方提到 kAuthorizationFlagExtendRights,所以认为这可能是你忽略的东西。 - arri
但完全有可能是我缺少了那些权限,但我不明白为什么会出现无效标志错误代码...这段代码来自苹果文档,所以我期望它能够工作 ;o) - Lukas1

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