本文翻译整理自:Authorization Services Programming Guide(更新日期:2011-10-19
https://developer.apple.com/library/archive/documentation/Security/Conceptual/authorization_concepts/01introduction/introduction.html#//apple_ref/doc/uid/TP30000995
文章目录
- 一、授权服务编程指南简介
- 1、本文件的组织
- 2、另见
- 二、授权概念
- 1、授权书
- 2、认证
- 3、安全服务器
- 4、权利
- 5、政策数据库
- 6、凭据缓存和身份验证对话框
- 7、情景
- 7.1 简单的、自我限制的应用程序
- 7.2 分解应用
- 7.3 安装人员
- 三、授权服务任务
- 1、在简单的、自我限制的应用程序中进行授权
- 1.1 创建没有权限的授权引用
- 1.2 请求授权
- 创建授权权限集
- 指定授权选项
- 授权
- 释放授权项数组
- 1.3 发布授权引用
- 2、在分解应用程序中授权
- 2.1 在分解应用程序中使用授权服务
- 创建授权引用
- 请求预授权
- 创建预授权权限集
- 为预授权指定授权选项
- 预授权
- 创建外部授权引用
- 调用助手工具
- 发布授权引用
- 2.2 在帮助工具中使用授权服务
- 检索授权引用
- 执行授权
- 执行特权操作
- 修复辅助工具
- 将辅助工具称为root
- 设置Setuid位
- 3、调用特权安装程序
- 词汇表
一、授权服务编程指南简介
重要提示:应用沙盒不支持授权服务API,因为它允许权限提升。
授权服务定义了一个编程接口,有助于对特权操作进行精细控制,例如访问操作系统的受限区域和Mac应用程序的自限制部分。
本文档介绍了如何使用授权服务来控制这些特权操作。
授权服务编程指南解释了授权背后的概念,并提供了如何使用授权服务的示例。
从使用授权服务中受益的产品类型包括
- 调用系统受限工具的应用程序
- 限制访问自己工具的软件
- 安装特权工具或需要访问操作系统受限区域的软件安装程序
例如,您可以使用授权服务重新启动后台进程或访问受限目录,例如/Applications
目录。
在这些情况下正确使用授权服务可以大大降低软件无意中损坏操作系统受限区域或允许未经授权的用户访问这些区域的可能性。
如果您的应用程序包含工具或执行您希望只有管理用户有权访问的操作,则它可以从授权服务中受益。
授权服务使用macOS中的身份验证机制。
如果macOS的未来版本支持额外的身份验证机制,现在采用授权服务将使您的应用程序能够利用这些机制,而无需更改代码。
注意:本文档以前的标题为使用授权服务执行特权操作。
1、本文件的组织
授权概念向您介绍macOS中的授权,并描述授权和身份验证之间的区别。
本章探讨使用授权服务的场景。
阅读本章以更好地了解您的软件是否可以从使用授权服务中受益。
授权服务任务详细解释了如何在自限制应用程序、系统限制应用程序和特权安装程序中使用授权服务。
术语表定义了本书中引入的新术语。
2、另见
有关API的详细信息,请参阅授权服务。
二、授权概念
重要提示:应用沙盒不支持授权服务API,因为它允许权限提升。
本章介绍概念,而不是实现或编程细节。
有关在应用程序中使用特定授权服务功能的信息,请参阅授权服务任务。
在阅读本章之前,您应该了解BSD和macOS中权限和所有权的基础知识。
有关这些概念的简要介绍,请参阅 安全概述。
有关术语的定义,请参阅词汇表。
本章包含以下部分:
- 授权提供了macOS使用的基于策略的授权的概念性概述。
- 身份验证描述授权如何使用身份验证。
- 安全服务器描述了如何在应用程序中使用授权服务与安全服务器进行交互。
- 权限描述了如何命名您自己的权限。
- 策略数据库说明安全服务器如何使用策略数据库做出授权决策。
- 凭据缓存和身份验证对话框说明了安全服务器如何确定是否显示身份验证对话框。
- 场景描述了使用授权服务的不同场景。
1、授权书
macOS内核的底层BSD部分提供了一个 user-and-owner-security
模型。
每个文件系统对象,例如文件或目录,都有一个所有者和一组权限或属性,指定所有者、一个组和所有其他人能够对该对象做什么。
在某些情况下,BSD安全模型不适合macOS用户面临的情况。
例如,如果您想创建一个grades-and-transcripts应用程序,您希望教师和学校注册员使用该应用程序,但您可能希望将成绩单的创建限制在注册员。
您可能需要保护用户 不意外地进行底层BSD安全模型 允许的重要更改。
例如,您可能希望只允许管理员更改application-specific首选项。
授权服务还可用于以root身份执行操作(也称为超级用户),例如重新启动守护进程。
在这些情况下,除了BSD权限之外,基于策略的安全模型还为您的应用程序提供了额外的重要功能。
在基于策略的系统中,用户请求授权——授予权利或特权的行为——以执行特权操作。
授权是通过代理执行的,因此用户不必信任应用程序的密码。
代理是用户交互界面——代表安全服务器操作——用于获取用户密码或其他形式的标识,这也确保了应用程序之间的一致性。
安全服务器——macOS中处理授权和身份验证的核心服务守护程序——确定是否没有人、每个人或只有某些用户可以执行特权操作。
授权为您提供了对授予用户权限以执行管理任务和其他特权操作的细粒度控制。
使用授权服务允许您限制应用程序的某些部分,添加额外的安全预防措施,并且仍然满足BSD安全模型。
您应该避免绕过BSD安全模型——例如,不要以root身份运行进程——除非您别无选择,在这种情况下,您应该限制所涉及的代码量。
注意:在基于策略的系统中,您有责任为您的用户请求授权。
您的应用程序应在每次特权操作之前立即授权。
在某些情况下,在您的应用程序实际需要执行这些操作之前,确定用户是否被授权执行特权操作是很有价值的。
例如,当系统偏好设置应用程序被锁定时,它需要用户提供名称和密码,然后才能允许用户更改任何设置。
当非管理员用户单击锁定按钮(参见图1-1)时,系统偏好设置应用程序执行预授权。
在需要授权之前,预授权确定用户的权限。
通过预授权,系统偏好设置可以防止用户为他们无权执行的操作自定义和选择选项。
图1-1未经授权的用户看到的系统偏好设置应用程序示例
图1-2显示了用户在成功预授权后看到的窗口。
但是,系统偏好设置应用程序仍然在执行任何特权操作之前立即执行授权。
图1-2预授权用户看到的系统偏好设置应用程序示例
2、认证
认证是验证用户身份的行为。
一个常见的误解是授权和认证是一回事;然而,认证只是授权过程的一部分。
正如授权中所讨论的,在用户被认证后,授权过程涉及确定用户拥有什么权限或特权。
图1-3显示了系统偏好设置应用程序中的身份验证示例。
图1-3系统偏好设置应用程序中的身份验证示例
为了进行身份验证,根据可用的硬件,用户通常输入用户名和密码,或者扫描指纹寻找触摸识别。
其他身份验证机制可能包括插入智能卡或其他类型的生物识别技术。
当您的应用程序请求用户授权时,您可以设置一个允许安全服务器与用户交互的选项。
这样做会告诉安全服务器根据需要向用户请求身份证明或同意以进行身份验证。
3、安全服务器
您的应用向安全服务器提供授权引用、授权权限集和授权选项。
然后,安全服务器通过以下方式执行身份验证:
- 使用授权引用访问凭据。
- 要求用户提供用于身份验证的用户名和密码。
- 使用授权权限集中的权限在策略数据库中查找规则。
- 使用凭据和授权选项来确定用户是否遵守规则并应被授予授权权限集中请求的权限。
- 返回授予或拒绝授权权限的结果。
要在应用程序和安全服务器之间启动授权会话,您需要创建一个授权引用。
安全服务器使用授权引用访问授权会话。
您将授权引用传递给几乎每个授权服务函数。
当您请求授权时,您以授权选项的形式向安全服务器发送指令。
授权选项告诉安全服务器如何进行授权请求。
例如,您可以指定调用用于授权、部分授权或预授权。
您还可以指定是否要允许安全服务器与用户交互以执行身份验证,或请求同意。
要授权用户,您必须向安全服务器传递一个授权权限集,其中包含用户需要的权限,例如创建副本或重新启动守护程序的权限。
权限是应用程序代表用户请求的命名权限。
凭据是表示经过身份验证的用户的令牌,安全服务器将其存储为授权会话的一部分。
安全服务器使用这些凭据作为真实性证明。
凭据在设定的时间后过期。
您还可以在释放授权引用时强制它们过期。
安全服务器使用包含一组规则的策略数据库。
规则是确定谁应该被授权执行特定操作的一组属性。
安全服务器将规则与用户权限和身份验证凭据进行比较,以确定用户是否被授权执行特权操作。
授予的权限不会存储在授权会话中。
相反,每次执行授权时,安全服务器都会使用凭据——或者重新验证用户,或者如果凭据已过期,则重新请求同意——并查阅策略数据库中的适当规则以重新评估授权。
4、权利
当应用程序请求授权时,您将请求的权限(授权权限集)传递给安全服务器。
安全服务器会将您传递的权限与策略数据库中的密钥进行比较。
找到匹配项时,安全服务器会使用与密钥关联的规则来确定授权。
有关策略数据库的详细信息,请参阅策略数据库。
您必须创建应用程序使用的权限。
权限使用分层命名空间。
权限应以组织的反向域名开头。
然后,权限应指定应用程序的名称并变得更具体——例如,com.myOrganization.myProduct.myRight
。
特定于macOS的权限具有以system
开头的正确名称。
注意:权限区分大小写。
您的权限应该代表对一个或一组目标的单个操作。
例如,权限可能代表重新启动守护程序的单个操作,例如com.myOrganization.myProduct.inetd.restart
以重新启动Internet守护程序,或com.myOrganization.myProduct.daemons.restart
以重新启动一组守护程序。
因为可以为同一用户请求多个权限,所以不需要创建表示操作组合的权限。
例如,在grades-and-transcripts应用程序中,如果您命名一个com.myOrganization.myProduct.transcripts.create
和 另一个com.myOrganization.myProduct.grades.edit
,则不需要单独的权限 com.myOrganization.myProduct.createTranscriptsAndEditGrades
。
您为权限选择的名称应该对用户有意义。
例如,system.finder.trash.empty
比 system.finder.trashDirectory.deleteFiles
可读性更强。
5、政策数据库
策略数据库包含安全服务器用来为用户授权权限的一组规则。
每个规则由一组属性组成。
这些规则在安装macOS时预先配置,但应用程序可能随时更改它们。
因为任何应用程序都可以更改数据库中的权限,所以您的应用程序必须考虑所有可能的情况。
表1-1描述了为规则定义的属性。
Mac应用程序的策略数据库中有一些特定规则。
策略数据库中还有一个通用规则,安全服务器将其用于没有特定规则的任何权限。
规则属性 | 通用规则值 | 描述 |
---|---|---|
key | 该密钥是规则的名称。 密钥使用与权限相同的命名约定。 安全服务器使用规则的密钥将规则与权限匹配。 通配符密钥以“ . ”结尾。 通用规则的键值为空。 与特定规则不匹配的任何权限都使用通用规则。 | |
group | admin | 用户必须是该组的成员。 |
shared | true | 如果设置为true ,则安全服务器将用于获得此权限的凭据标记为共享。 安全服务器可以使用任何共享凭据来授权此权限。 为获得最大安全性,请将共享设置为 false ,以便安全服务器为一个应用程序存储的凭据不能被另一个应用程序使用。 |
timeout | 300 | 此规则使用的凭据在指定的秒数内过期。 对于每次用户都必须进行身份验证或同意的最大安全性,请将超时设置为 0 。 |
除非将新规则添加到策略数据库,否则您的权限始终与通用规则匹配。
使用AuthorizationRightSet
函数在数据库中添加或编辑规则。
使用AuthorizationRightGet
函数读取当前规则。
使用AuthorizationRightRemove
函数删除规则。
要锁定未明确允许的所有特权操作,请通过将超时属性设置为0
来更改通用规则。
要在用户获得授权后允许所有特权操作,请从通用规则中删除超时属性。
要防止应用程序共享权限,请将共享属性设置为false
。
要要求用户以员工组而不是管理组的成员身份进行身份验证,请将组属性设置为staff
。
作为安全服务器如何将权限与策略数据库中的规则匹配的示例,请考虑一个grades-and-transcripts应用程序。
该应用程序请求权限com.myOrganization.myProduct.transcripts.create
。
安全服务器在策略数据库中查找权限。
如果找不到完全匹配,安全服务器会查找通配符密钥设置为com.myOrganization.myProduct.transcripts.
、com.myOrganization.myProduct.
、com.myOrganization.
或com.
-按此顺序-检查最长匹配。
如果没有通配符匹配,则安全服务器使用通用规则。
安全服务器向用户请求身份验证。
用户提供用户名和密码以作为组admin
进行身份验证。
安全服务器根据用户身份验证或同意以及请求的权限创建凭据。
凭据指定其他应用程序可以使用它,安全服务器将过期时间设置为五分钟。
三分钟后,应用程序的子进程启动。
该子进程请求正确的 com.myOrganization.myProduct.transcripts.create
。
安全服务器找到凭证,看到它允许共享,并使用权限。
两分半钟后,同一子进程再次请求正确的 com.myOrganization.myProduct.transcripts.create
,但权限已过期。
安全服务器通过查阅策略数据库并请求用户身份验证或同意,开始创建新凭证的过程。
6、凭据缓存和身份验证对话框
您可能会注意到,当您调用AuthorizationCreate
函数或AuthorizationCopyRights
函数来获取用户权限时,有时会出现一个身份验证对话框,有时会出现一个同意对话框,有时则没有出现任何对话框。
这种行为的原因与策略数据库中的设置以及安全服务器缓存用户凭据的方式有关。
凭据是安全服务器知道的关于特定用户的信息,例如特定用户输入了有效的用户名和密码。
对于每个登录会话,安全服务器维护一个全局凭据缓存和每个授权实例的凭据缓存(即,每次创建新的授权引用时)。
策略数据库中每个权限的规则指示经过身份验证的用户必须属于的组以及凭据被认为有效的时间。
该规则还可能指示要共享凭据。
当授权服务需要凭据来授予用户权限时,安全服务器会尝试从凭据缓存中获取凭据。
它首先查看与授权实例关联的凭据缓存。
如果凭据不在那里并且凭据被共享,它会在全局凭据缓存中查找。
只有当安全服务器在缓存中找不到凭据时,它才会尝试获取凭据,通常是通过显示身份验证或同意对话框。
(在某些情况下,安全服务器可能能够从其他来源(例如智能卡)获取凭据。)
如果安全服务器成功获得新的凭据,它会将其存储在与授权实例关联的凭据缓存中,如果规则指定应共享凭据,则将其存储在全局凭据缓存中。
如果权限的规则有超时属性,其值表示缓存的凭据对该权限适用多长时间(以秒为单位)。
值为0
表示该凭据只能使用一次(即立即超时)。
如果缺少超时属性,只要登录会话持续,凭据就可以用来授予权限,除非该凭据被显式销毁。
例如,当作为管理员组成员的用户登录到系统时,用户的凭据(即他们输入了有效的管理员用户名和密码的事实)将保存在全局凭据缓存中。
然后,当该用户尝试修改系统首选项时,安全服务器会在缓存中找到凭据,并且不会显示身份验证对话框。
另一方面,如果用户使用非管理员用户名和密码登录并尝试修改系统首选项之一,安全服务器将无法从凭据缓存中获取所需的凭据。
因此,它会显示身份验证对话框。
同样的原则适用于任何需要凭证的应用程序:如果用户已通过一个应用程序的身份验证并且凭证已被共享,则另一个应用程序可以使用该凭证。
因此,对AuthorizationCopyRights
的调用是否导致对话框取决于安全服务器是否已经缓存了所需的凭据。
保证请求权限时获得的凭证不与其他授权实例共享的唯一方法是销毁凭证。
为此,请使用标志kAuthorizationFlagDestroyRights
调用AuthorizationFree
函数。
7、情景
涉及授权服务的主要场景有三种:简单的自限制应用程序、分解应用程序和安装程序。
7.1 简单的、自我限制的应用程序
自限制应用程序要求某些功能只能由特定用户组访问。
在简单的自限制应用程序中,这种功能分离是在主应用程序中完成的。
在这种情况下,您使用授权服务,因为这种细粒度限制不能由BSD权限控制。
考虑一个grades-and-transcripts应用程序,它只允许注册人员创建成绩单,而应用程序的其余部分可供教师和注册人员使用。
当用户尝试创建成绩单时,应用程序使用授权服务来决定该用户是否可以执行该操作。
图1-4显示了一个简单的、自我限制的应用程序的流程图。
应用程序创建一个授权引用。
授权引用指的是与安全服务器的授权会话。
在执行任何特权操作(例如创建抄本)之前,应用程序立即代表用户请求授权。
如果需要,安全服务器请求用户的身份验证或同意。
如果授权成功,则执行特权操作。
当不再需要授权引用时,应用程序释放授权引用。
在大多数情况下,将特权操作分离到单独的帮助工具中是有益的。
有关如何将授权服务与帮助工具一起使用的更多信息,请参阅分解应用程序。
如果您只需要授权一次,例如,当您的应用程序首次启动时,您可以在不创建授权引用的情况下执行授权。
为此,您直接使用授权调用的结果。
因为在这种情况下,您没有创建授权引用,所以不必释放它。
授权部分更详细地描述了一次性授权。
图1-4简单、自限制应用程序的流程图
7.2 分解应用
分解应用程序是将特定任务委托给更小的、独立的工具的应用程序。
这些工具有时被称为辅助工具。
在简单的、自限制的应用程序中,特权代码在应用程序本身中,而在分解应用程序中,特权代码在辅助工具中。
您的应用程序执行的操作可能受到BSD安全模型的限制。
此类应用程序是受系统限制的应用程序。
例如,需要重新启动Internet守护程序(inetd
)的应用程序必须具有root权限,但它以启动它的用户的权限运行。
建议您同时考虑自限制应用程序和系统限制应用程序。
考虑您的应用程序有两个好处。
第一个是更容易审计分解应用程序,因为特权操作由帮助工具在单独的进程中执行。
第二个是分解应用程序提供了更多的安全性。
在非分解应用程序中,您不仅必须相信代码中没有安全漏洞,而且您链接到的所有代码中也没有漏洞。
图1-5显示了分解应用程序的应用程序部分的流程图,而辅助工具的流程图如图1-6所示。
图1-5分解应用程序的应用程序部分流程图
应用程序首先创建授权引用,并在调用辅助工具之前立即向安全服务器请求预授权。
应用程序使用预授权的结果来确定用户是否有权在辅助工具中执行特权操作。
执行预授权可确保调用用户无权使用的辅助工具不会浪费资源和时间。
图1-6辅助工具的流程图
应用程序需要将授权引用传递给辅助工具。
因为您不能在两个进程之间传输授权引用本身,所以应用程序使用授权服务创建授权引用的外部、可转移形式以发送到其辅助工具。
助手工具使用授权服务从外部授权引用创建授权引用。
助手工具请求授权并使用结果来决定是否继续特权操作。
您必须将授权引用传递给辅助工具,以便授权对话框可以显示应用程序的路径而不是辅助工具的路径,并允许系统确定授权对话框是否应该具有键盘焦点。
您必须在任何特权操作之前立即执行授权,即使用户已经成功授权。
权限可能会过期,因此作为开发人员,您有责任确保用户使用所有必需的权限。
任何应用程序都可以修改策略数据库以设置权限可用的时间长度(请参阅策略数据库)。
注意:执行特权操作的能力受BSD安全模型控制,而不是授权服务。
权限到期不会阻止具有适当BSD权限的用户执行某些特权操作——您必须通过在特权操作之前立即授权将这种预防构建到您的代码中。
一些系统提供的实用程序使用授权服务。
例如,authopen
实用程序使用授权服务打开特权文件。
如果您调用像authopen
这样的实用程序,那么就没有必要编写自己的帮助工具。
一些特权操作需要特殊权限。
例如,重新启动Internet守护程序的应用程序必须具有root权限。
执行此操作有三种可能的方法,它们都有自己的问题:
- 通过使用特殊的授权服务函数调用自身,使应用程序以root身份运行。
- 设置应用程序的setuid位并将其所有者更改为root,然后使用特殊的授权服务功能。
- 剔除执行特权操作的操作并将其放在单独的setuid工具中-一个设置了setuid位的工具-并将setuid工具的所有者设置为root。
第一个和第二个选项都是等待发生的安全漏洞。
当特权应用程序运行时,它会调用授权服务提供的特殊函数——AuthorizationExecuteWithPrivileges
(有关更多详细信息,请参阅将帮助工具作为根调用)。
调用此函数会执行任何具有根权限的应用程序或工具,而不管应用程序或工具的所有者是谁。
这非常危险,因为应用程序的某些部分很容易被替换。
第二个选项是设置特权应用程序的setuid位,并将其所有者更改为root。
设置setuid位后,运行它的进程可以伪装成另一个用户。
将应用程序的setuid位和所有者设置为不同的用户,例如root,会使替换变得更加困难。
然而,以root身份运行代码非常危险,应该尽可能少地这样做。
在整个应用程序上设置setuid位尤其危险,因为您相信您的整个应用程序以及您的应用程序链接到的代码没有安全漏洞。
第三种情况是目前最好的。
应用程序被分成两个部分:一个控制所有图形用户交互界面元素和非特权操作的应用程序,另一个是只执行重启Internet守护程序所涉及的操作的帮助工具。
帮助工具的setuid位已设置,所有者设置为root。
正确的授权服务功能如前所述使用。
分解和设置setuid位不仅可以最大限度地降低风险,还可以更轻松地审计代码中的安全漏洞。
最后一种情况的一个问题是,当文件被复制时,setuid位设置会丢失。
因此,如果用户复制了您的setuid工具,则不再设置setuid位。
可以在setuid工具本身中重置setuid位。
图1-7显示了修复自己的setuid位的setuid工具的流程图。
您可能不希望用户能够复制应用程序。
如果是这种情况,您无需担心修复setuid位,只需让用户知道他们需要重新安装应用程序即可。
图1-7自修复辅助工具流程图
运行自修复助手工具时,它会检查是否传递了自修复标志。
如果未传递自修复标志,则读取应用程序传递的外部授权引用。
然后,自修复setuid工具检查它是否以root身份运行。
如果它以root身份运行,则执行授权,并根据结果执行特权操作。
如果自修复setuid工具不是以root身份运行,则使用AuthorizationExecuteWithPrivileges
函数调用自身并将自修复标志传递给自己。
当新的自修复setuid工具进程启动时,它会检查是否传递了自修复标志。
如果传递了自修复标志,则自修复setuid工具恢复授权引用并修复setuid位。
自修复setuid工具以root身份运行后,它执行授权并继续作为普通辅助工具。
7.3 安装人员
并非所有安装程序都需要授权-只有那些需要特殊权限才能将文件复制到受限目录、更改受限文件或设置setuid位的安装程序才需要授权。
安装程序是一种特殊情况,因为与其他应用程序不同,安装程序通常只运行一次。
由于使用受限,授权服务提供了一个函数来调用您的安装程序以root权限运行。
由用户来确定安装程序是否来自受信任的来源。
图1-8显示了应用程序使用授权服务调用安装程序的流程图。
在这种情况下,应用程序创建授权引用并执行预授权。
如果用户成功预授权,则调用AuthorizationExecuteWithPrivileges
函数以root权限执行您的安装程序。
图1-8调用特权安装程序的应用程序流程图
图1-9显示了在安装程序本身中执行的授权服务调用的流程图。
授权应该在任何特权操作之前执行。
图1-9安装程序授权服务调用的流程图。
三、授权服务任务
重要提示:应用沙盒不支持授权服务API,因为它允许权限提升。
本章为您可以使用授权服务完成的任务提供说明和代码示例。
您可以在自己的应用程序中调整这些示例
- 限制对您自己的应用程序部分的访问
- 呼叫系统实用程序
- 编辑特权文件
- 安装您的特权工具
一个简单的、自我限制的应用程序需要以最小的安全问题限制用户在应用程序自己的操作中——例如,一个grades-and-transcripts的应用程序可能只允许注册商创建转录本。
阅读在一个简单的、自我限制的应用程序中授权如果你有一个自我限制的应用程序。
如果您有一个分解应用程序-例如,必须以root身份执行操作的应用程序,例如重新启动守护程序-您应该阅读在简单的、自限制的应用程序中授权 和 在分解应用程序中授权。
如果安装程序必须执行特权操作,请阅读调用特权安装程序以查看使用授权服务的安装程序示例。
有关执行系统受限特权操作的示例应用程序,请参阅示例代码>安全性。
1、在简单的、自我限制的应用程序中进行授权
一个简单的自限制应用程序使用授权服务来执行以下部分中描述的任务:
- 创建没有权限的授权引用
- 请求授权
- 发布授权引用
1.1 创建没有权限的授权引用
安全服务器使用授权引用来访问授权会话的状态,其中包括任何存储的凭据。
您的应用程序只需要一个授权引用。
您可以使用AuthorizationCreate
函数为授权引用分配内存。
例2-1中的代码片段显示了对AuthorizationCreate
函数的调用,该函数创建一个没有权限的授权引用。
如果不立即需要权限,则没有权限的授权引用很有用,但需要授权引用,以便它可以在应用程序的不同部分中使用。
例如,在grades-and-transcripts应用程序中,可能会在应用程序启动时创建授权引用,但在用户尝试创建转录本之前不会请求权限。
**注意:**尽管您可以在一次调用中创建授权引用并分配权限,但请记住,如果授权被拒绝,则不会创建该引用,后续使用它的尝试将失败。
因此,通常最好创建没有权限的授权引用,如例2-1所示,然后稍后调用AuthorizationCopyRights
函数来确定或更改权限,如请求授权所示。
例2-1创建没有权限的授权引用
AuthorizationRef myAuthorizationRef;
OSStatus myStatus;
myStatus = AuthorizationCreate (NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults, &myAuthorizationRef);
AuthorizationCreate
函数有四个参数,第一个是一个授权权限集,由于NULL
,此时没有权限被授权。
第二个参数是授权环境,当前没有实现;传递kAuthorizationEmptyEnvironment
。
第三个参数是授权选项,传递常量kAuthorizationFlagDefaults
是因为应用程序没有请求任何权限。
第四个参数是你声明的授权引用的地址。
返回时,授权引用引用当前的授权会话。
如果授权引用创建成功,函数返回errAuthorizationSuccess
。
请求授权 描述了如何使用AuthorizationCopyRights
和AuthorizationCreate
函数来请求授权。
当您的应用程序完成授权引用时,请使用AuthorizationFree
函数,如发布授权引用中所述。
1.2 请求授权
创建授权引用后,您可以请求授权。
您的应用程序应在每个特权操作之前立即执行授权。
在grades-and-transcripts示例中,应用程序在创建副本之前立即请求授权。
当您的应用程序请求授权时,安全服务器可能会请求用户进行身份验证。
授权服务允许您充分利用安全服务器的身份验证插件架构为您处理身份验证。
身份验证可能使用指纹或智能卡,而不是用户名和密码,但您的应用程序代码保持不变。
[图1-3] 显示了安全服务器提供的身份验证对话框。
用户输入管理员用户名和密码,然后单击确定。
安全服务器然后使用用户名和密码对用户进行身份验证和授权。
授权需要创建授权权限集和授权选项,以便在调用函数AuthorizationCopyRights
或AuthorizationCreate
时使用。
在您的应用程序中,通过执行以下部分中描述的任务请求授权:
- 创建授权权限集
- 指定授权选项
- 授权
- 释放授权项数组
创建授权权限集
要为用户授权特定权限,您必须创建一个授权权限集,以通过AuthorizationCopyRights
或AuthorizationCreate
函数传递给安全服务器。
授权权限集由授权项数组和授权项数组中的项目数组成。
授权项数组包含有关应用程序请求的权限的信息。
授权项数组中的每个项由四个信息组成:
- 权利的名称
- 包含与右相关的可选数据的值
value
字段的字节长度- 可选标志
例2-2显示了一个授权项数组的示例。
在大多数情况下,在为权限创建项时,您将value
字段设置为NULL
,将valuelength
和flags
字段设置为0
。
您应该将name
字段设置为您请求的权限的名称。
有关命名您自己的权限的信息,请参阅权限。
例2-2创建授权项数组
AuthorizationItem myItems[2];
myItems[0].name = "com.myOrganization.myProduct.myRight1";
myItems[0].valueLength = 0;
myItems[0].value = NULL;
myItems[0].flags = 0;
myItems[1].name = "com.myOrganization.myProduct.myRight2";
myItems[1].valueLength = 0;
myItems[1].value = NULL;
myItems[1].flags = 0;
例如,grades-and-transcripts应用程序可能请求正确的com.myOrganization.myProduct.transcripts.create
。
valueLength
、value
和flags
字段将不被使用,并分别设置为0
、NULL
和0。
例2-3显示了一个授权权限集的示例,在授权权限集中,count
字段包含授权项数组中的权限数,而items
字段指向您创建的授权项数组。
例2-3创建一组授权权限
AuthorizationRights myRights;
myRights.count = sizeof (myItems) / sizeof (myItems[0]);
myRights.items = myItems;
指定授权选项
您可以使用授权选项来指示安全服务器如何继续AuthorizationCopyRights
和AuthorizationCreate
函数。
通过设置授权选项,您可以使用这些函数
- 授权部分权利
- 授权所有权利
- 预授权权
您可以在这些选项中包含与用户交互的选项。
安全服务器需要用户交互来执行身份验证。
最常见的组合授权所有权限并允许用户交互。
例2-4显示了授权选项的示例。
示例2-4为授权指定授权选项
AuthorizationFlags myFlags;
myFlags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagExtendRights;
kAuthorizationFlagDefaults
常量将位掩码归零。
kAuthorizationFlagExtendRights
常量指示安全服务器授予权限。
如果没有此标志,AuthorizationCopyRights
和AuthorizationCreate
函数将返回相应的错误代码,但不会将权限扩展给用户。
如果您的应用程序不需要授权所有权限,您可以包含kAuthorizationFlagPartialRights
常量来请求部分授权。
然后,您可以根据安全服务器授予的权限确定允许用户执行什么操作。
例2-5显示了为部分授权设置授权选项的示例。
例2-5为部分授权指定授权选项
myFlags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagExtendRights |
kAuthorizationFlagPartialRights;
请参阅请求预授权以了解要为预授权设置哪些授权选项。
授权
在例2-6中的代码片段显示了基于您创建的授权引用和授权权限集以及您指定的授权选项对AuthorizationCopyRights
函数的调用。
在grades-and-transcripts示例中,AuthorizationCopyRights
函数用于授权创建脚本的权限。
例2-6授权权限
myStatus = AuthorizationCopyRights (myAuthorizationRef, &myRights,
kAuthorizationEmptyEnvironment, myFlags, NULL);
第一个参数是在创建无权限授权引用中创建的授权引用。
第二个参数是在创建授权权限集中创建的授权权限集。
第三个参数是授权环境。
授权环境当前未实现,所以传递kAuthorizationEmptyEnvironment
。
第四个参数是在指定授权选项中设置的授权选项。
第五个参数在授权部分权限时很有用,如例2-7所示。
该参数指向您声明的一个空的授权权限集。
返回时,它由安全服务器实际授权的权限组成。
如果您创建一个指向授权权限集的指针,那么您应该按照释放一个授权项数组中的说明释放它。
例2-7授权部分权限
AuthorizationRights *myAuthorizedRights;
myStatus = AuthorizationCopyRights (myAuthorizationRef, &myRights,
kAuthorizationEmptyEnvironment, myFlags,
&myAuthorizedRights);
如果安全服务器授予所有权限,AuthorizationCopyRights
函数将返回errAuthorizationSuccess
。
您可以使用返回状态来确定用户是否可以执行特权操作。
您可以使用授权权限集和授权选项在创建授权引用时请求授权。
**注意:**尽管您可以在一次调用中创建授权引用并分配权限,如例2-8所示,但请记住,如果授权被拒绝,则不会创建该引用,后续使用它的尝试将失败。
因此,通常最好创建没有权限的授权引用,如例2-1所示,然后稍后调用AuthorizationCopyRights
函数来确定或更改权限,如本节前面的代码示例所示。
例2-8显示了一个将授权与AuthorizationCreate
函数相结合的示例。
例2-8创建具有权限的授权引用
myStatus = AuthorizationCreate (&myRights, kAuthorizationEmptyEnvironment,
myFlags, &myAuthorizationRef);
您还可以使用AuthorizationCreate
函数对用户进行一次性特权操作的授权。
如果应用程序在运行时只需要授权一次,那么一次性授权非常有用。
例2-9展示了一个示例,说明如何在不生成授权引用的情况下将授权权限集和授权选项与AuthorizationCreate
函数一起使用。
传递NULL
而不是授权引用。
例2-9一次性授权调用
myStatus = AuthorizationCreate (&myRights, kAuthorizationEmptyEnvironment,
myFlags, NULL);
释放授权项数组
完成例2-7中设置的授权项后,调用AuthorizationFreeItemSet
函数,如例2-10所示,释放它使用的内存。
仅在安全服务器分配的授权项数组上使用此函数,例如AuthorizationCopyRights
和AuthorizationCopyInfo
函数中使用的那些。
例2-10释放授权项数组
myStatus = AuthorizationFreeItemSet (myAuthorizedRights);
1.3 发布授权引用
在退出您的应用程序之前,或者在您希望结束当前授权会话的任何时候,调用AuthorizationFree
函数来释放授权引用。
例如,grades-and-transcripts应用程序会等到用户退出应用程序后再释放授权引用。
每次用户创建抄本时使用相同的授权引用允许安全服务器重用任何尚未过期的共享凭据。
相比之下,用户单击网络首选项窗格中的打开锁定按钮等操作可以触发授权引用的释放,要求用户在单击关闭锁定按钮时重新授权。
例2-11中的代码段显示了使用AuthorizationFree
函数的示例。
您必须传递授权引用和授权选项。
对于授权选项,如果要撤销与当前进程关联的凭据,则传递常量kAuthorizationFlagDefaults
,或者传递常量kAuthorizationFlagDestroyRights
以从所有使用它们的进程释放所有共享凭据。
例2-11发布授权引用
myStatus = AuthorizationFree (myAuthorizationRef,
kAuthorizationFlagDestroyRights);
2、在分解应用程序中授权
分解应用程序,无论是系统限制的还是自限制的,都使用应用程序来控制图形用户交互界面和非特权操作,并使用单独的帮助工具来执行特权操作。
阅读在分解应用程序中使用授权服务,了解在分解应用程序中使用授权服务的说明,在助手工具中使用授权服务,了解在助手工具中使用授权服务的说明。
2.1 在分解应用程序中使用授权服务
您可以在分解应用程序中使用授权服务来执行以下部分中描述的任务:
- 创建授权引用
- 请求预授权
- 创建外部授权引用
- 调用助手工具
- 发布授权引用
分解应用程序的一个示例是重新启动Internet守护程序的应用程序。
当帮助工具重新启动守护程序时,应用程序执行所有非特权操作。
应用程序创建授权引用并预先授权重新启动Internet守护程序的权利。
应用程序使用结果来确定是否启动帮助工具。
应用程序创建授权引用的外部版本并将其传递给帮助工具。
当不再需要授权引用时,应用程序释放它。
创建授权引用
在分解应用程序中创建授权引用与在简单的自限制应用程序中创建授权引用相同。
请参阅创建没有权限的授权引用以了解如何创建授权引用。
请求预授权
在调用辅助工具之前,您应该预先授权权限。
使用预先授权的结果,您可以防止未经授权的用户调用辅助工具。
这样做可以节省启动新进程和使用资源的时间,也可以节省用户准备执行他们没有权限执行的操作的时间。
预授权需要创建授权权限集和授权选项,以便在调用函数AuthorizationCopyRights
或AuthorizationCreate
时使用。
在您的应用程序中,您可以通过执行以下部分中描述的步骤对用户进行预授权:
- 创建预授权权限集
- 为预授权指定授权选项
- 预授权
创建预授权权限集
预授权权限集与创建授权权限集中描述的授权权限集相同。
为预授权指定授权选项
预授权的授权选项类似于指定授权选项中描述的授权和部分授权的授权选项。
预授权和授权之间的唯一区别是,您不是使用结果来确定用户是否可以执行特权操作。
相反,您应该使用结果来确定用户是否可以在以后被授权。
例2-12显示了为预授权设置授权选项的示例。
kAuthorizationFlagDefaults
常量将位掩码清零。
kAuthorizationFlagExtendRights
常量告诉安全服务器扩展授予用户的任何权限。
kAuthorizationFlagInteractionAllowed
常量告诉安全服务器它可以与用户交互以进行身份验证。
kAuthorizationFlagPreAuthorize
常量告诉安全服务器对请求的权限进行预授权。
例2-12为预授权指定授权选项
AuthorizationFlags myFlags;
myFlags = kAuthorizationFlagDefaults |
kAuthorizationFlagExtendRights |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize;
预授权
调用AuthorizationCopyRights
或AuthorizationCreate
函数对于预授权和授权是一样的。
授权部分中的示例参见例2-6。
创建外部授权引用
创建授权引用和预授权权限后,您需要将授权引用传递给您的帮助工具。
共享授权引用允许帮助工具使用作为分解应用程序授权会话一部分的任何凭据。
当您将授权引用传递给帮助工具时,授权对话框可以显示您的应用程序的路径,而不是帮助工具的路径。
它还使系统能够确定授权对话框是否应该具有键盘焦点。
授权引用的一个问题是它不是可以从一个进程转移到另一个进程的形式。
为了解决这个问题,授权服务提供了一个功能,可以将授权引用转换为可以传递给助手工具的外部授权引用。
要创建外部授权引用,声明一个AuthorizationExternalForm
类型的变量,并将其与现有授权引用一起传递给AuthorizationMakeExternalForm
函数。
返回时,该变量包含授权引用的可转移形式。
例2-13显示了创建外部授权引用的示例。
例2-13创建外部授权引用
AuthorizationExternalForm myExternalAuthorizationRef;
myStatus = AuthorizationMakeExternalForm (myAuthorizationRef,
&myExternalAuthorizationRef);
阅读“Retrieving an Authorization Reference”
,了解如何从助手工具中的外部授权引用中检索授权引用。
调用助手工具
当您准备好调用帮助工具时,使用某种形式的进程间通信(例如通信管道)将外部授权引用传递给工具。
发布授权引用
释放分解应用程序中的授权引用与释放授权引用中描述的相同。
2.2 在帮助工具中使用授权服务
您可以在帮助工具中使用授权服务来执行以下部分中描述的任务:
- 检索授权引用
- 执行授权
- 执行特权操作
例如,重新启动Internet守护程序的辅助工具从应用程序传递的外部授权引用中检索授权引用。
然后辅助工具在重新启动Internet守护程序之前立即请求授权。
如果您的辅助工具实际上是一个自我修复辅助工具,您还应该阅读修复一个辅助工具。
检索授权引用
为了共享授权会话,分解应用程序将外部授权引用传递给帮助器工具(请参阅创建外部授权引用)。
在帮助器工具中,您使用AuthorizationCreateFromExternalForm
函数从外部授权引用中检索授权引用。
例2-14显示了一个使用AuthorizationCreateFromExternalForm
函数的示例。
在此示例中,外部授权引用是从辅助工具进程和父进程之间的通信管道中读取的。
然后,您将外部授权引用传递给函数AuthorizationCreateFromExternalForm
。
返回时,myAuthorizationRef
是授权引用。
例2-14检索授权引用
AuthorizationRef myAuthorizationRef;
AuthorizationExternalForm myExternalAuthorizationRef;
OSStatus myStatus;
/* *** You should read in the external authorization reference into
myExternalAuthorizationRef here. *** */
myStatus = AuthorizationCreateFromExternalForm (&myExternalAuthorizationRef,
&myAuthorizationRef);
执行授权
在助手工具中执行授权与简单的自限制应用程序相同。
有关详细信息,请参阅请求授权。
执行特权操作
您应该使用授权的结果来确定是否允许用户执行特权操作。
实际执行特权操作不需要授权服务功能。
修复辅助工具
**重要提示:**有关此处记录的方法的更新和更安全的替代方法,请参阅更好的授权示例(BetterAuthorizationSample)中的示例代码,该代码使用启动守护程序来启动辅助工具,而不是设置setuid位。
如果您的辅助工具需要以root身份运行以执行特权操作,例如重新启动Internet守护程序,那么它应该设置其setuid位。
设置了setuid位的工具(有时称为setuid工具)必须是Mach-O二进制文件,因为CFM二进制文件不支持setuid或setgid(设置组标识符)位。
安装程序时,安装程序应设置辅助工具的setuid位,并将其所有者设置为root。
在OS X 10.1及更早版本中,当用户将setuid工具移动到另一个卷,或将其从一个地方复制到另一个卷时,setuid位会被文件系统重置,并且组和所有者会更改以匹配移动setuid工具的用户。
这样做是为了通过允许任何用户以root身份运行setuid工具来降低setuid工具带来的安全风险。
另一方面,大多数用户期望当他们将应用程序或工具从一个文件夹复制到另一个文件夹时,它仍然可以工作。
因此,setuid位、组和所有者需要重置,而无需编辑终端窗口中的权限。
本节提供代码以允许您的setuid工具在出现此问题时修复其自己的setuid位。
注意:在OS X 10.1中,复制或移动的setuid工具会丢失其setuid位。
所有者和组会更改以匹配执行操作的用户的权限。
在以后的版本中,用户可以移动setuid工具并保留权限集。
所有setuid工具都是潜在的安全问题。
这种情况带来了一个特殊的问题,因为即使用户篡改了setuid工具的代码,该工具也会自我修复其setuid位。
作为额外的安全性,您可能希望在执行此操作时向用户显示警告,以便他们决定继续或取消自我修复操作,或者可能强制用户从安装程序重新安装应用程序。
您可以通过执行以下部分中描述的任务来修复辅助工具上的setuid位:
- 将辅助工具称为root
- 设置Setuid位
将辅助工具称为root
要使辅助工具设置自己的setuid位,该工具必须具有root权限。
这是一个循环问题,因为除非您的辅助工具已经以root身份运行,否则您无法更改辅助工具的权限。
这就是函数AuthorizationExecuteWithPrivileges
发挥作用的地方。
AuthorizationExecuteWithPrivileges
函数通过特殊的安全过程以root身份执行任何应用程序。
例2-15中的代码示例演示了帮助工具如何以root权限递归调用自己,以便修复自己的setuid位。
注意:AuthorizationExecuteWithPrivileges
函数仅将工具的有效用户ID(EUID)设置为root。
工具的真实用户ID(RUID)是调用者的用户ID。
**重要提示:**由于存在安全风险,建议仅在特殊且不经常使用的情况下调用AuthorizationExecuteWithPrivileges
函数,例如修复setuid位和安装应用程序。
在最安全的计算机系统中,此函数请求的权利会立即超时,因此每次调用它时,用户都必须进行身份验证。
例2-15以root权限执行帮助工具
FILE *myCommunicationsPipe = NULL;
char *myArguments[] = {"--self-repair", NULL};
char myPath[MAXPATHLEN];
/* *** You should determine the path of your tool here and put the result in
myPath. *** */
myStatus = AuthorizationExecuteWithPrivileges (myAuthorizationRef,
myPath, kAuthorizationFlagDefaults, myArguments,
&myCommunicationsPipe);
AuthorizationExecuteWithPrivileges
函数期望您传递五个参数。
第一个参数是您检索到的授权引用,如检索授权引用。
授权引用允许辅助工具使用作为分解应用程序授权会话一部分的任何凭据。
第二个参数是正在调用的辅助工具的完整POSIX路径名——在本例中为setuid工具。
第三个参数是授权选项。
在此函数中,此参数未实现,因此目前将其设置为kAuthorizationFlagDefaults
。
第四个参数是被调用工具的以null结尾的参数数组。
您可以使用此参数将所需的任何信息从父进程传递给子进程。
在这种情况下,字符串"--self-repair"
被传递给帮助器工具以指示它应该执行例2-16中的代码。
第五个参数是一个通信管道,因此帮助器工具可以将它从分解应用程序接收到的数据传递给它自己。
**重要提示:**您可能会AuthorizationExecuteWithPrivileges
使用该函数来执行特权操作,而不是创建和调用您自己的setuid工具。
尽管这看起来像是一个简单的解决方案,但使用AuthorizationExecuteWithPrivileges
函数而不使用其余授权服务函数会产生严重的安全漏洞,因为该函数会以root用户身份不加选择地运行任何工具。
Setuid工具也存在安全风险,但它们远没有将该函数用于AuthorizationExecuteWithPrivileges
本文档中描述的目的之外的目的那么严重。
阅读分解应用程序以获取有关创建您自己的助手工具的说明。
设置Setuid位
在例2-15中,helper工具递归调用自身,传递自我修复参数--self-repair
。
因此,在同一个helper工具中,您需要检查自我修复参数,如果找到,则修复setuid位。
有关示例自我修复setuid工具,请参阅More Is Better示例代码(MoreIsBetter)。
**注意:**这里讨论的辅助工具中的自我修复代码的目的是允许工具在用户移动或复制工具后以root身份执行,即使文件系统已经重置了setuid位并更改了所有者和组以匹配执行该操作的用户的权限。
如果setuid位已经被清除,则此自我修复代码(即对AuthorizationExecuteWithPrivileges
函数的调用)有效,无论该工具是由root拥有还是由用户拥有。
如果该工具设置了setuid位并且由root拥有,则不调用自我修复代码。
但是,如果设置了setuid位并且工具归用户所有,则对AuthorizationExecuteWithPrivileges
函数的调用失败,因为在这种情况下尊重setuid位,并且工具以用户权限而不是root权限执行。
如果您希望您的自修复助手工具处理这种不太可能的情况,您需要在调用自修复代码之前添加代码来清除setuid位。
调用AuthorizationExecuteWithPrivileges
函数时,需要一种方法来检索在调用中传递的授权引用。
例2-16显示了使用AuthorizationCopyPrivilegedReference
函数检索授权引用的代码。
使用此函数的唯一时间是检索通过调用AuthorizationExecuteWithPrivileges
传递的授权引用。
调用AuthorizationCopyPrivilegedReference
函数的第一个参数是您声明的空授权引用。
您不应该调用AuthorizationCreate
函数。
返回时,授权引用指向原始授权引用的副本。
第二个参数没有实现,因此将其设置为kAuthorizationFlagDefaults
。
例2-16设置setuid位
myStatus = AuthorizationCopyPrivilegedReference (&myAuthorizationRef,
kAuthorizationFlagDefaults)
3、调用特权安装程序
有时,安装程序必须将文件安装在运行安装程序的用户不拥有的目录中。
这应该是一种罕见的情况,您应该尽可能避免它。
如果无法避免,例2-17中的代码显示了一个使用可选标志-un
运行/usr/bin/id
实用程序的工具。
通过替换实用程序路径并包含您自己的标志,您可以使用此示例代码以root权限调用您的安装程序。
然后,您的安装程序将能够执行它需要的任何特权操作。
例2-17调用特权安装程序
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
int read (long,StringPtr,int);
int write (long,StringPtr,int);
int main() {
OSStatus myStatus;
AuthorizationFlags myFlags = kAuthorizationFlagDefaults; // 1
AuthorizationRef myAuthorizationRef; // 2
myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, // 3
myFlags, &myAuthorizationRef);
if (myStatus != errAuthorizationSuccess)
return myStatus;
{
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, // 4
NULL, 0};
AuthorizationRights myRights = {1, &myItems}; // 5
myFlags = kAuthorizationFlagDefaults | // 6
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
myStatus = AuthorizationCopyRights (myAuthorizationRef, // 7
&myRights, NULL, myFlags, NULL );
}
if (myStatus != errAuthorizationSuccess) goto DoneWorking;
{
char myToolPath[] = "/usr/bin/id";
char *myArguments[] = { "-un", NULL };
FILE *myCommunicationsPipe = NULL;
char myReadBuffer[128];
myFlags = kAuthorizationFlagDefaults; // 8
myStatus = AuthorizationExecuteWithPrivileges // 9
(myAuthorizationRef, myToolPath, myFlags, myArguments,
&myCommunicationsPipe);
if (myStatus == errAuthorizationSuccess)
for(;;)
{
int bytesRead = read (fileno (myCommunicationsPipe),
myReadBuffer, sizeof (myReadBuffer));
if (bytesRead < 1) goto DoneWorking;
write (fileno (stdout), myReadBuffer, bytesRead);
}
}
DoneWorking:
AuthorizationFree (myAuthorizationRef, kAuthorizationFlagDefaults); // 10
if (myStatus) printf("Status: %ld\n", myStatus);
return myStatus;
}
以下是示例2-17中编号代码行的解释:
- 声明一个变量来存储授权选项。
- 声明授权引用。
- 使用
AuthorizationCreate
函数初始化授权引用。
有关详细信息,请参阅创建没有权限的授权引用。 - 创建授权项数组。
用户必须具有执行权限才能使用AuthorizationExecuteWithPrivileges
函数。
要创建执行授权项的权限,请将name
字段设置为kAuthorizationRightExecute
,将value
字段设置为NULL
,将valueLength
和flags
字段设置为0
。
有关详细信息,请参阅创建授权权限集。 - 创建授权权限集。
将count
字段设置为授权项数组中的项目数,并将items
字段设置为指向授权项数组。
有关详细信息,请参阅创建授权权限集。 - 设置授权选项以预授权权限。
有关详细信息,请参阅为预授权指定授权选项。 - 使用
AuthorizationCopyRights
函数预授权以root身份执行安装程序的权限。
在这种情况下,如果用户无法预授权,则没有理由继续。
有关详细信息,请参阅授权。 - 将
AuthorizationExecuteWithPrivileges
函数的授权选项设置为kAuthorizationFlagDefaults
。
其他授权选项,例如kAuthorizationFlagInteractionAllowed
常量指定的选项,是不必要的,因为无论您是否指定该选项,AuthorizationExecuteWithPrivileges
函数都会与用户交互。 - 使用
AuthorizationExecuteWithPrivileges
函数调用您的安装程序。
在第一个参数中传递授权引用。
在第二个参数中传递安装程序的完整POSIX路径名。
在第三个参数中传递默认的授权选项。
在第四个参数中传递安装程序的任何参数。
可以通过第五个参数设置到工具的通信管道。
有关AuthorizationExecuteWithPrivileges
函数的更多信息,请参阅调用辅助工具作为根。 - 使用
AuthorizationFree
函数释放授权引用。
有关详细信息,请参阅释放授权引用。
词汇表
- administrator | 管理员
管理员组中的用户。安装OS X的用户将自动分配到管理员组。管理员的权限少于root用户,但多于普通用户。管理员不能在系统域中创建、删除或移动文件。 - authentication | 身份验证
用用户拥有、知道或正在使用的东西验证身份的行为。例如,用户知道姓名和密码等信息。用户可能有物理的东西,如智能卡。身份可以是用户的东西——指纹或视网膜扫描等物理特征。身份验证可能需要两种或两种以上的身份证明形式。 - authorization | 授权
授予权限的行为。例如,用户请求执行操作的权限。安全服务器在用户满足策略数据库中指定的规则(例如提供凭据或身份验证)后授予授权。 - authorization option | 授权选项
指示安全服务器如何处理请求的参数或字段。选项包括请求预授权、请求部分授权、附加权限以及与用户交互。 - authorization reference | 授权引用
安全服务器使用授权引用访问与进程关联的授权会话。 - Authorization Services| 授权服务
一种API,有助于对特权操作进行精细控制,例如访问操作系统的受限区域和Mac应用程序的自限制部分。安全服务器使用基于策略的决策为用户授权权限。 - biometric identifier | 生物识别器
用于识别的生物物质的测量——例如指纹、视网膜扫描和面部识别。 - credential | 凭据
用户身份验证的证明。由安全服务器使用。当安全服务器对用户进行身份验证时,它会创建一个凭据作为授权会话的一部分。 - factored application | 分解应用程序
使用辅助工具执行特定任务的应用程序。进程间通信机制用于进程之间的通信。在使用授权服务的分解应用程序中,执行特权操作的代码被分解到单独的辅助工具中。 - helper tool | 辅助工具
作为单独进程执行应用程序某些功能的工具。在安全的情况下,辅助工具为应用程序执行特权操作。另请参见setuid工具。 - key
规则的名称。安全服务器使用规则的密钥将权限与规则匹配。 - permissions | 权限
在BSD中,一组控制谁可以读取、写入和执行文件系统中的资源的属性。ls -l
命令的输出将权限表示为九位代码,分为三个二进制三字符子代码;第一个子代码为文件所有者提供权限,第二个子代码为文件所属的组提供权限,最后一个子代码为其他所有人提供权限。例如,-rwsr-xr--
表示文件所有者具有读取、写入、执行权限(rwx);该组具有读取和执行权限(r-x);所有其他只有读取权限。(最左边的位置为一个特殊字符保留,该字符表示这是一个常规文件(-)、一个目录(d)、一个符号链接(l)还是一个特殊的伪文件设备。)执行位对目录有不同的语义,这意味着它们是可搜索的。 - policy-based system | 基于策略的系统
需要授权才能执行特权操作的系统。 - policy database | 策略数据库
包含安全服务器用于确定授权的规则集的数据库。 - preauthorization | 预授权
在执行实际授权之前使用的一种授权形式。预授权用于确定用户以后是否有可能进行授权。 - privileged operation | 特权操作
需要特殊权限或权限的操作。例如,用户以root身份执行的所有操作都具有特权。 - right
命名特权。安全服务器授权用户执行特权操作的权限。 - rule | 规则
用于为应用程序和系统设置安全策略的一组属性。另请参见策略数据库。 - root
(1)具有无限系统权限的用户。也称为超级用户。
(2)BSD样式目录层次结构中的顶部目录。写成斜杠(/),它是每个绝对路径名中的第一个元素。 - Security Server | 安全服务器
OS X中的核心服务应用程序,通过与策略数据库和可插拔身份验证模块(PAM)的交互来处理授权和身份验证。 - self-restricted application | 自限制应用程序
将其部分功能限制为特定用户的应用程序。 - setuid bit
资源权限代码中的第四位。当该位设置为s
时,系统允许运行它的进程伪装成另一个用户。例如,-r-sr-xr-x 1 root wheel traceroute
允许运行traceroute
的进程以root身份运行。 - setuid 工具
设置了setuid位的工具。 - 系统受限应用程序
由于BSD权限系统,其部分功能仅限于特定用户的应用程序。
2024-06-16(日)