Lazarus Pascal:使用 SMJobBless() 编写特权帮助工具

Lazarus Pascal: Writing a privileged helper tool with SMJobBless()

我过去在 Lazarus Pascal 中创建了一个应用程序,它执行 "dd" 将图像写入驱动器。为此,显然需要提升权限。

在初始版本中,我使用了 AuthorizationExecuteWithPrivileges() (link),尽管并非完全用于此目的,但它确实运行良好且非常一致。 然而,此功能自 OSX 10.7 以来已被贬低,因为它可能是一个安全问题,并且重定向的命令行语句也无法正常工作(将 zip 的输出重定向为 dd 的输入).

在下一个版本中,我使用了 Lazarus Pascal Wiki (Executing External Programs) 中描述的方法,它基本上启动了我的程序与之通信的 TProcess。使用 sudo -S dd ...,询问并输入用户密码以确保 he/she 具有适当的访问权限。 显然有点肮脏的黑客方法,它表明,某些用户遇到了这个问题。

经过大量阅读,Apple 似乎更喜欢使用名为 SMJobBless() 的辅助工具来完成此操作。不幸的是,在 Objective-C 方面,我不是很有经验,所提供的代码充其量似乎非常少,而且也没有很好的记录。

我想知道是否有人有经验或可以协助 "porting" 这种方法到 Lazarus Pascal ...我完全赞成正确地做。 当然也欢迎使用替代方法!

如有任何帮助,我们将不胜感激。

I'm unfortunately not very experienced when it comes to Objective-C

不要因此而放弃使用 Apple 提供的示例。如果你仔细看SMJobBlessAppController.m中的代码,你会发现除了一行Objective-C代码外,剩下的就是C.

Objective-C行注册辅助应用程序:-

if (![self blessHelperWithLabel:@"com.apple.bsd.SMJobBlessHelper" error:&error])

您将使用自己的 URI,而不是 com.apple.bsd.SMJobBlessHelper。

所有其他相关行都是纯 C 函数。打破这个,你剩下的是:-

// Obtain rights 
AuthorizationCopyRights(self->_authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL)


//Start the helper
SMJobBless(kSMDomainSystemLaunchd, (CFStringRef)label, self->_authRef, &cfError);

我没有检查错误代码,但我希望这表明您需要使用的代码非常少,而且需要的 Objective-C 知识也很少。

因为这花了我很多时间,而且我认为它会对其他人有所帮助,所以这里是我最终的工作解决方案。 https://www.tweaking4all.com/software-development/lazarus-development/macos-smjobbless-elevated-privileges-lazarus-pascal/

您会在那里找到一个示例项目和大量信息。

重现这个的步骤非常广泛,所以在这里做一个简短的回顾:

我一直在使用 CFMessages 向帮助工具发送消息,因为我没有绑定 NSXPCConnection。

Helper Tool 必须基于 Lazarus Pascal 模板 "program" 或 "simple program",不能基于任何 TApplication 类,也不能创建任何踏板。 对于 Helper Tool,需要创建一个 info.plist 和一个 launchd.plist,它们都必须嵌入到二进制文件中。

主要(测试)应用程序可以是任何 Lazarus Pascal 应用程序,但也需要适当的 Info.plist,表明允许帮助工具以提升的权限启动。

Helper Tool 和应用程序应用程序包都需要使用有效的 Apple Developer ID 进行签名。

一些缺失的绑定需要到位:

const  kSMRightBlessPrivilegedHelper = 'com.apple.ServiceManagement.blesshelper';
function SMJobBless(domain:CFStringRef; executableLabel:CFStringRef; auth:AuthorizationRef; outError:CFErrorRef): boolean; external name '_SMJobBless'; mwpascal; 
var kSMDomainSystemLaunchd: CFStringRef; external name '_kSMDomainSystemLaunchd';

并且需要包含适当的框架:

{$linkframework ServiceManagement}
{$linkframework Security}
{$linkframework Foundation}
{$linkframework CoreFoundation}
{$calling mwpascal}

别忘了设置回调函数来处理传入的消息。

我希望这对某人有用...:-)