CSDN博客

img VincintCao

Policy Tool — 策略文件创建和管理工具

发表于2003/3/8 14:55:00  1851人阅读

Policy Tool —

策略文件创建和管理工具

创建和修改外部策略配置文件,该文件定义了安装的 Java 安全策略。

目录

简介

权限和策略文件概述
权限
缺省策略文件及其位置
策略文件内容


Policy Tool 用法
启动 Policy Tool
创建新的策略文件
打开另一策略文件
指定密钥仓库
添加新策略项
添加新权限
编辑权限
删除权限
完成策略项的添加
编辑策略项
删除策略项
保存策略文件
退出 Policy Tool
查看警告日志


示例
启动用户策略文件的创建
添加策略项
指定密钥仓库
添加具有 SignedBy 别名的策略项
保存用户策略文件
退出 Policy Tool


另请参阅

简介

Java 运行环境的策略指定了来自各种来源的代码可以获得何种权限,由 Policy 对象表示。缺省 Policy 实现从静态 ASCII 策略配置文件获得其信息。

可借助于纯文本编辑器或者借助于本文档所描述的图形化 Policy Tool 实用程序来撰写策略文件。使用 Policy Tool 可节省键入时间,并且使得用户不必知道策略文件所需语法,从而减少了错误的发生。

本文档中的权限和策略文件概述一节描述了权限是什么,并且提供了有关策略文件内容和缺省策略文件的信息。该节还提供了到这些主题的详细讨论的链接。

Policy Tool 用法一节描述了如何使用 Policy Tool 来创建和修改策略文件。

示例一节提供了 Policy Tool 用法的详细示例。

另请参阅一节提供了到相关文档的链接。

权限和策略文件概述

本节简要地描述了权限是什么,并且提供了有关策略文件内容和缺省策略文件的信息。

权限

权限代表对系统资源的访问。为了让 applet(或与安全管理器一起运行的应用程序)能够进行资源访问,必须将相应的权限明确地授予试图进行访问的代码。

权限通常具有一个名称(常称为“目标名”),而且在某些情况下,还具有一个由逗号分隔开的一个或多个动作的序列。例如,如果要创建权限来读 /tmp/ 目录中名为“abc”的文件,则需要用目标名“/tmp/abc”和动作字符串“read”来创建 File Permission(其术语为 java.io.FilePermission 权限)。

在缺省策略实现中,必须用策略配置文件中的“策略项”(有时称为“授权项”)来将指定权限授予试图读该文件的代码。可以使用 Policy Tool 在这样的文件中创建这样的项。

JDK 1.2 中的权限文档所含的一些表格描述了内置 JDK 1.2 权限类型并且讨论了授予各种权限的危险程度。该文档中所含的另外一些表格显示了需要权限生效才能成功工作的 JDK 1.2 方法,并且对应于每一种方法都列出了所需权限。

缺省策略文件及其位置

缺省情况下只有一个全系统策略文件,以及一个可选的用户策略文件。

系统策略文件的缺省位置为

    java.home/lib/security/java.policy

其中,java.home 表示 JDK 的安装目录。

用户策略文件的缺省位置位于

    user.home/.java.policy

其中,user.home 表示用户的宿主目录。

当策略初始化时,首先加载系统策略,然后再添加用户策略。如果既没有系统策略又没有用户策略,则使用内置策略。这种内置策略与最初的沙箱策略相同。

策略文件位置是在安全属性文件中指定的,该文件位于

    java.home/lib/security/java.security

将策略文件位置作为属性的值来指定,其名称具有以下形式:

    policy.url.n

其中,n 表示数字。用户可以在以下形式的语句行中指定每个属性值:

policy.url.n=URL

其中,URL是 URL 说明。例如,缺省策略文件(有时又分别称为“系统”和“用户”策略文件)在安全属性文件中的定义分别为

policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

注意: 当在策略文件或安全属性文件中出现象

    ${some.property}

这样的字符串时,它将被扩展为指定系统属性的值。例如:

    ${java.home}

表示的是指定 JDK 安装目录的 java.home 属性的值

安全属性文件中的“policy.expandProperties”属性值控制是否允许属性扩展。如果该属性值为 true(缺省值),则允许扩展。

实际上用户可以在安全属性文件中指定多个 URL(包括“http://”形式的 URL),所有指定的策略文件都将加载。也可以注释掉或更改第二个 URL 以禁止读取缺省用户策略文件。

算法从 policy.url.1 开始,并且不断递增直到找不到 URL 为止。因此,如果您有 policy.url.1 和 policy.url.3,则决不会读取 policy.url.3。

当调用应用程序时,还可以指定附加的或另外的策略文件。这可以借助于“-Djava.security.policy”命令行参数来完成,该命令行参数设置 java.security.policy 属性的值。例如,如果键入以下语句,其中 pURL 是指明策略文件的位置的 URL,则在加载安全属性文件中所指定的所有策略文件以外,还加载该 URL 指定的策略文件。

  java -Djava.security.manager -Djava.security.policy=pURL SomeApp

(“-Djava.security.manager”参数确保了缺省安全管理器的安装,这样就可以对应用程序进行策略检查。如果应用程序 SomeApp 安装了安全管理器,则该参数就不是必需的。)

如果键入的是以下语句(使用的是双重等号),则仅使用指定的策略文件;而其它所有策略文件都将被忽略。

  java -Djava.security.manager -Djava.security.policy==pURL SomeApp

如果您想要将策略文件传递给 appletviewer,则请如下所示再次使用“-Djava.security.policy”参数:

  appletviewer -J-Djava.security.policy=pURL  myApplet

请注意: 如果安全属性文件中的“policy.allowSystemProperty”属性被设置为 false,则将忽略 “-Djava.security.policy”策略文件值(对于 java 和 appletviewer 命令)。缺省值为 true。

策略文件内容

策略配置文件(简称为策略文件)指明来自指定代码源的代码可以获得何种权限。

策略配置文件中包含有许多项。可以包含唯一的“密钥仓库”项,包含零个或多个“策略”(或“授权”)项。

密钥仓库 是私钥及其相关数字证书(例如认证相应公钥的 X.509 证书链)的数据库。使用 keytool 实用程序来创建和管理密钥仓库。策略配置文件中所指定的密钥仓库的作用是查询该文件的授权项所指定的签名人(如果有)的公钥。而公钥的作用则是校验用于对代码进行签名的数字签名。

如果有任何策略项指定了签名人别名,则策略配置文件中必须出现密钥仓库项。

此时,策略文件中只能有一个密钥仓库项。密钥仓库项指定密钥仓库的 URL 位置,有时也指定密钥仓库类型。URL 相对于策略文件的位置。因而,如果在安全属性文件中以如下方式指定策略文件:

  policy.url.1=http://foo.bar.com/blah/some.policy

而且该策略文件含有值为“.keystore”的密钥仓库项,则将从以下位置加载密钥仓库:

  http://foo.bar.com/blah/.keystore

URL 也可以是绝对 URL。

密钥仓库类型定义密钥仓库信息的存储和数据格式,以及用于保护密钥仓库中的私钥和密钥仓库自身完整性的算法。如果您没有指定类型,则假定指定的是安全属性文件中的“keystore.type”属性值所指定的类型。该属性的缺省值为“JKS”,指定 Sun Microsystems 所支持的专用密钥仓库类型。

通常认为执行代码来自于特定的“代码源”。代码源不仅可以包括 applet(或应用程序)所始发自的 CodeBase 位置 (URL),而且还可以包括对一个或多个(符号的)别名的引用,这些别名所来自的密钥仓库指定的密钥仓库项包含与签名该代码的私钥相对应的公钥。

策略文件中的每个策略项都包含以下项目:

  • 可选的 CodeBase 项,指定代码所始发自的 URL 位置,
  • 可选的 SignedBy 项,指定来自密钥仓库的别名,作用是引用其私钥用于对代码进行签名的签名人,以及
  • 一个或多个 权限 项,指定将何种权限授予来自指定 CodeBase 并由指定的 SignedBy 别名所签名的代码。

Policy Tool 用法

启动 Policy Tool

要启动 Policy Tool,仅仅需要在命令行中键入以下命令。

  policytool

这将调出“Policy Tool”窗口。

无论何时启动 Policy Tool,Policy Tool 都将试图用来自有时称为“用户策略文件”的策略信息来填写本窗口。在缺省情况下,用户策略文件是宿主目录下名为 .java.policy 的文件。如果 Policy Tool 没能查找到用户策略文件,则它将报告该情况并且显示空白的“Policy Tool”窗口(即有标题和按钮但是其中没有数据的窗口):

空白的策略工具窗口

然后,您可以继续打开您想要使用的任何策略文件或者创建新策略文件,方法是添加策略项(同时还可指定密钥仓库)和保存文件

第一次运行Policy Tool时,将不会有用户策略文件(除非已经手动创建了一个用户策略文件)。

创建新的策略文件

要创建新的策略文件,选择 File 菜单下的 New 命令即可。该操作将关闭当前打开的策略文件(如果有,必要时会在关闭之前首先提示您保存该文件)并且调出新的Policy Tool窗口,即有标题和按钮但是其中没有数据的窗口。

请注意: 在第一次运行 Policy Tool 时,不必这么做。因为该工具试图打开用户策略文件而用户策略文件还不存在(除非已经手动创建),所以该工具将调出其中没有数据的窗口。

一旦您有了新的 Policy Tool 窗口之后,您就可以创建策略项并且指定密钥仓库(如果有任何策略项指定了密钥仓库别名)。您可以随时保存策略文件

打开另一策略文件

要处理另一策略文件而不是当前处理的文件(如果有),请选择 File 菜单下的 Open 命令。

这将关闭当前打开的策略文件(如果有,必要时会在关闭之前将首先提示是否保存该文件)并且呈现“Open”对话框,您可以使用该对话框来浏览目录结构,直到进入包含要处理的策略文件的目录。选择该文件,然后选择 OK 按钮。

随后,“Policy Tool”窗口中将填写来自策略文件的信息,包括策略文件名、密钥仓库 URL (如果有)以及策略文件中每个策略项的 CodeBase 和 SignedBy 部分。

指定密钥仓库

要为策略项的 SignedBy 部分中所指定的别名指定包含密钥信息的密钥仓库,请选择 Edit 菜单下的 Change Keystore 命令。

这将调出一个对话框,在对话框中可以指定新的密钥仓库 URL,也可指定密钥仓库类型。

例如,要指定 /tests/ 目录中名为 "mykeystore" 的密钥仓库,应将下列 file: URL 键入标签为 "New KeyStore URL" 的文本框。

  file:/tests/mykeystore

要将密钥仓库类型指定为“JKS”(Sun Microsystems 所支持的专用密钥仓库类型),请在标签为“New KeyStore Type”的文本框中键入以下内容。

  JKS

当完成指定密钥仓库 URL 和类型(如果有)时,请选择 OK(或者也可以选择 Cancel 来取消操作)。如果没有取消,则标签为“Keystore:” 的文本框中现在就填上了密钥仓库 URL 和类型。

添加新策略项

要添加新的策略项,请选择主“Policy Tool”窗口中的 Add Policy Entry 按钮。

这将调出“策略项”对话框:

空白的添加项对话框

利用该对话框,您可以指定

  • 可选的 CodeBase 项,指明代码所始发自的 URL 位置。例如,要指明代码是来自于本地 /JavaSoft/TESTS/ 目录,请将以下文件 URL 键入到标签为 CodeBase 的文本框中:
      file:/JavaSoft/TESTS/
    

     

  • 可选的 SignedBy 项,指明来自密钥仓库的别名,作用是引用其私钥用于对代码进行签名的签名人。例如,要指明“duke”别名,只需在标签为 SignedBy 的文本框中键入以下内容:
      duke
    
  • 一个或多个权限项,指明将何种权限授予来自 CodeBase 和 SignedBy 值所指示的代码源的代码(或者如果没有指定这样的值,则指明将何种权限授予其它任何代码)。请参阅添加新权限

SignedBy 值是字符串别名,它被映射到(使用密钥仓库)与签名人相关联的公钥集。这些密钥的作用是校验来自指定代码源的类是否确实由这些签名人签名。

SignedBy 值可以是逗号分隔的字符串,其中可以包含多个签名人的名字,例如 “Adam,Eve,Charles”,这意味着“由 Adam 和 Eve 以及 Charles 签名”(即,其关系是 AND,而不是 OR)。

SignedBy 值是可选的,这是因为:如果忽略该值,则表示“任何签名人”,换句话说,对代码是否进行签名无关紧要。同样,如果没有 CodeBase 项,则表示“任何代码”;代码始发自何处无关紧要。

因此,如果没有 CodeBase 项,则所有由指定别名签名的代码将被授予指定的权限。如果没有 SignedBy 项,则所有来自指定的 CodeBase 的代码将被授予指定的权限,而不管代码是否已经被签名,以及由谁签名。如果没有 CodeBase 项,也没有 SignedBy 项,则所有代码将被授予指定的权限。

注意: CodeBase 值的确切含义取决于结尾处的字符。以“/”结尾的 CodeBase 匹配指定目录中的所有类文件(而不是 JAR 文件)。以“/*”结尾的 CodeBase 匹配该目录中的所有文件(既包括类文件又包括 JAR 文件)。以“/-”结尾的 CodeBase 匹配目录中的所有文件(既包括类文件又包括 JAR 文件),并且递归地匹配该目录所含子目录中的所有文件。

添加新权限

要添加新权限,请选择“Policy Entry”对话框中的 Add Permission 按钮。这将调出“Permissions”对话框:

空白的添加权限对话框

要添加权限:

  1. 请键入或选择权限类型

    “Permission:”下拉列表中包含了内置权限类型的列表。如果您想要其中某种类型,则请从列表中选择,随后完整的权限类型名将出现在下拉列表右边的文本框中。

    如果您想要指定由您本人或其他人所定义的权限类型,请在文本框中键入该权限类型。

  2. 键入或选择权限目标名

    如果您从“Permission:”下拉列表中选择了一种内置权限,而且该类型的权限具有特定的目标名值,则“Target Name:”下拉列表将包含这些值的列表,您可以从中进行选择。

    在某些情况下,目标名的可能取值范围极大但是某些内置目标名规范又具有特殊的含义,这样的目标名将出现在下拉列表中。例如,“<<All Files>>”特殊目标名将出现在“File Permission”列表中。

    要指定下拉列表中没有的目标名,请在“Target Name:”下拉列表右边的文本框中直接键入目标名。例如,要指定 /JavaSoft/ptTest/ 目录中名为 data 的文件,请键入

      /JavaSoft/ptTest/data
    
  3. 键入或选择一个或多个动作(如果动作相关)。

    某些权限只有目标名,但是没有动作。对于这样的权限,保持“Action:”下拉列表右边的文本框为空。(对于该类型的内置权限,它将自动变灰不可用)。

    对于需要指定动作的权限,请在文本框中键入逗号分隔的动作列表,或者从下拉列表中选择操作。例如,要指定对“File Permission”指定的文件的读写访问权限,请首先从列表中选择 read (或 write,其先后顺序无关紧要)。单词“read”将出现在文本框中。然后选择 write,将附加上单词“write”,两单词之间用逗号和空格隔开。

  4. 如有必要,请在“Signed By”标签右边的文本框中键入 SignedBy 别名。权限项的 SignedBy 值是可选的。如果存在 SignedBy 值,则表明是已签名的权限。这就是说,为了授予权限,权限类自身必须由给定别名签名。

当完成权限信息的指定后,请选择 OK 按钮(或 Cancel 按钮来取消操作)。新权限就出现在“Policy Entry”对话框的某行中。

然后,可以依照同样的步骤添加另外的权限。或者也可以编辑现有的权限或删除权限。

编辑权限

要编辑现有权限,请选择“Policy Entry”对话框中该权限所在的行,然后选择 Edit Permission 按钮。另外,也可以简单地双击该权限所在的行。

这将调出与添加新权限时所出现的对话框一样类型的“Permission”对话框,唯一的区别在于此处的对话框中已填写了现有权限信息。要更改该信息,请从下拉列表中重新进行选择或替换文本框中的信息。

完成之后,请选择 OK 按钮(或 Cancel 按钮以取消所作更改)。“Policy Entry”对话框将显示修改后的权限。

删除权限

要删除现有权限,请选择“Policy Entry”对话框中该权限所在的行,然后选择 Remove Permission 按钮。

完成策略项的添加

在完成添加策略项之后,请选择“Policy Entry”对话框中的 Done 按钮,或 Cancel 按钮以取消操作。

如果选择了 Done,则“Policy Tool”窗口中现在就包含了代表该策略项的行。该行只是包含 CodeBase 和 SignedBy 信息(如果有)。如果在“Policy Entry”对话框中没有指定 CodeBase 和 SignedBy ,则只是出现

  CodeBase <ALL>

注意: 如果策略项包含密钥仓库中不存在的 SignedBy 别名,则在关闭该策略项时,会显示一个警告。请选择 OK 并且作记录以创建这样的别名,而如果别名出错,则应编辑策略项以修复别名。

编辑策略项

要编辑现有策略项,请在主“Policy Tool”窗口中选择该项所在的行,然后选择 Edit Policy Entry 按钮。另外,也可以简单地双击该项所在的行。

这将调出与添加新策略项时所出现的对话框一样类型的“Policy Entry”对话框,唯一的区别在于此处的对话框中已填写了现有策略项的信息。要更改该信息,只需重新键入信息(CodeBaseSignedBy 值)或添加删除修改权限。

完成之后,请选择 Done 按钮(或 Cancel 按钮以取消操作)。

删除策略项

要删除策略文件中的策略项,请在主“Policy Tool”窗口中选择该项所在的行,然后选择 Remove Policy Entry 按钮。

随后,就显示出完整的策略项,您可以选择 OK 来删除该项,或选择 Cancel 来保留该策略项。

保存策略文件

要将所作更改保存到现有策略文件,只需选择 File 菜单下的 Save 命令即可。

要保存创建的新策略文件,或者将现有策略文件复制为具有不同名称的新策略文件,请选择 File 菜单下的 Save As 命令。这将调出“Save As”对话框。

浏览目录结构,直到到达要保存该策略文件的目录为止。键入所需的文件名,然后选择 OK 按钮。策略文件即被保存,其名称和路径显示在标签为“Policy File:”的文本框中。

退出 Policy Tool

要退出 Policy Tool,请选择 File 菜单下的 Exit 命令。

查看警告日志

如果 Policy Tool曾经报告说警告已经存入到警告日志中了,则可以通过选择 Edit 菜单下的 View Warning Log 命令来查看日志。

例如,如果策略文件所含有的密钥仓库 URL 指定了并不存在的密钥仓库,则在多种情况下都会得到这样的警告,例如打开文件时。即使存在警告,也仍然可以继续处理策略文件。

示例

以下各例显示了如何

启动用户策略文件的创建

最初,并没有用户策略文件(除非手动创建了一个)。因而,若要创建用户策略文件,请首先在命令行中键入以下命令来启动 Policy Tool。

  policytool

这将调出“Policy Tool”窗口。

无论何时启动 Policy Tool,Policy Tool 都将试图用来自有时称为“用户策略文件”的策略信息来填写本窗口。在缺省情况下,用户策略文件是宿主目录下名为 .java.policy 的文件。如果 Policy Tool 没能查找到用户策略文件,则它将报告该情况并且显示空的“Policy Tool”窗口(即有标题和按钮但是其中没有数据的窗口):

空白的策略工具窗口

现在可以通过添加项目以及保存文件来创建用户策略文件。

添加策略项

假定您想为 Tests/ 目录上的所有类授予读取 /Temp/data/ 目录的 mydata 文件的权限。为此,应首先选择主“Policy Tool”窗口中的 Add Policy Entry 按钮。

这将调出“Policy Entry”对话框:

空白的添加项对话框

利用该对话框在 CodeBase 文本框中键入文件 URL

  file:/tests/

保持 SignedBy 文本框为空,这是因为您不需要将代码签名。

要添加权限,请选择 Add Permission 按钮。这将调出“Permissions”对话框:

空白的添加权限对话框

要添加权限:

  1. 选择“Permission:”下拉列表中的“File Permission”。现在,完整的权限类型名 (java.io.FilePermission) 就出现在下拉列表右边的文本框中。
  2. 在标签为“Target Name:”的列表右边的文本框中键入以下路径:
      /temp/data/mydata
    
  3. 通过选择“Actions:”下拉列表中的“read”以指定读权限。

现在,“Permission”对话框如下所示:

第一个文件权限

当完成指定权限信息之后,请选择 OK 按钮。新权限就出现在“Policy Entry”对话框的某行中。

第一个策略项

现在就完成了对该策略项的指定,因此请选择 Done 按钮。现在,“Policy Tool”窗口中就有了代表该策略项的行。该行中只是包含了 CodeBase 值:

具有一个 CodeBase 的策略工具

指定密钥仓库

假定您还想要将对 /tmp/ 目录中的所有文件的读权限授予来自 URL“http://java.sun.com/”的且由别名“duke”签名的代码。假定您还要赋予这类代码权限以初始化对任何主机发出的套接字连接,则需要完成两件事:

  1. 指定包含别名的密钥仓库,并且
  2. 创建策略项来授予权限。

要为策略项的任何 SignedBy 部分中所指定的别名指定包含密钥信息的密钥仓库,请选择主“Policy Tool“窗口的 Edit 菜单下的 Change Keystore 命令。

这将调出一个对话框,在对话框中可以指定新的密钥仓库 URL,也可指定密钥仓库类型。

例如,要指定 /tests/ 目录中名为 "mykeystore" 的密钥仓库,应将下列 file: URL 键入标有 "New KeyStore URL" 的文本框:

  file:/tests/mykeystore

如果密钥仓库类型是缺省类型,如安全属性文件中的“keystore.type”属性值所指定的,则不必键入“New KeyStore Type”值。该属性的缺省值是“JKS”(Sun Microsystems 所支持的专用密钥仓库类型)。

要指定密钥仓库类型,请将其值键入到标为“New KeyStore Type”的文本框中。例如,要指明密钥仓库类型是“JKS”类型,则请键入

  JKS

其结果是:

密钥仓库

当完成指定密钥仓库 URL 和类型之后,请选择 OK。现在,标为“Keystore:”的文本框中就填写了所指定的 URL 和类型。

下一步,您需要指定策略项:

添加具有 SignedBy 别名的策略项

选择主“Policy Tool”窗口中的 Add Policy Entry 按钮。这将调出“Policy Entry”对话框。将以下路径键入到 CodeBase 文本框中:

  http://java.sun.com/*

其中“*”表明将指定目录中的类文件和 JAR 文件与该 CodeBase 匹配。

现在,将以下别名键入到 SignedBy 文本框中:

  duke

要添加第一个权限,请选择 Add Permission 按钮。这将调出“Permissions”对话框。请进行以下操作

  1. 选择“File Permission”下拉列表中的“File Permission”。现在,完整的权限类型名称 (java.io.FilePermission) 就出现在下拉列表右边的文本框中。
  2. 将以下字符键入到标为“Target Name:”列表的右边的文本框中,以指定 /tmp/ 目录中的所有文件:
      /tmp/*
    
  3. 通过选择“Actions:”下拉列表中的“read”以指定读权限。

现在,“Permissions”对话框如下所示:

第二个文件权限

选择 OK 按钮。新权限就出现在“Policy Entry”对话框的某行中。

现在需要添加其它权限。请选择 Add Permission 按钮。在“Permissions”对话框中,请进行以下操作

  1. 选择“Permission:”下拉列表中的“Socket Permission”。现在,完整的权限类型名称 (java.net.SocketPermission) 就出现在下拉列表右边的文本框中。
  2. 将以下字符键入到标为“Target Name:”列表的右边的文本框中,以指定所有主机:
      *
    
  3. 通过选择“Actions:”下拉列表中的“connect”来指定进行连接的权限。

现在,“Permissions”对话框如下所示:

套接字权限

选择 OK 按钮。新权限就出现在“Policy Entry”对话框的某行中。

具有两个权限的策略项

现在就完成了对该策略项的指定,因此请选择“Policy Entry”对话框中的 Done 按钮。现在,“Policy Tool”窗口就包含了代表该策略项的行,显示了 CodeBase 和 SignedBy 值。

具有两个权限的策略项

保存用户策略文件

假定您想要将创建的策略文件用缺省名称 (.java.policy) 保存在缺省位置(宿主目录)。

要保存用户策略文件,请选择 File 菜单下的 Save As 命令。这将调出“Save As”对话框。

浏览目录结构,直到到达宿主目录。请键入

  .java.policy

(请注意初始阶段)作为文件名,然后选择 OK 按钮。策略文件即被保存,其名称和路径显示在标为“Policy File”的文本框中。

退出 Policy Tool

要退出 Policy Tool,请选择 File 菜单下的 Exit 命令。

另请参阅

0 0

相关博文

我的热门文章

img
取 消
img