IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management | Open source  >

配置 DB2 Universal Database for UNIX 以使用 OpenSSH

关于配置 DB2 UDB DPF on UNIX 以使用 OpenSSH 的逐步指南

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Liam Finnie (lfinnie@ca.ibm.com), DB2 UDB 软件开发人员, IBM Toronto Lab

2005 年 6 月 23 日

在 IBM® DB2® Universal Database™, Version 8.2.2 (Version 8, FixPack 9)之前,当在远程 DB2 节点上执行命令时,UNIX® 平台上的 DB2 UDB 在具有 Data Partitioning Feature (DPF) 支持的情况下,依赖于 rsh 作为远程 shell 机制。随着新的 DB2 注册变量 DB2RSHCMD 的引入,这一限制已经消除。该变量允许数据库管理员指定 DB2 所要使用的远程 shell 实用程序的完整路径名。OpenSSH 是 secure shell (ssh) 工具套件的开放源代码和免费实现,是 rsh 工具套件的一种安全的替代选择。本文描述如何配置 OpenSSH 3.8p1(其他版本的 ssh 可以使用稍微不同的语法),以便用于 DB2 UDB DPF 实例。

背景

UNIX 上的 DB2 UDB DPF 实例需要一个远程 shell 实用程序来在实例中的远程节点上执行命令。例如,当启动或停止 DPF 实例( db2start/db2stop)时,远程 shell 实用程序被用于发送 startup/shutdown 命令到实例中的每个节点(无论节点是否在相同的主机上)。而且,数据库管理员可以选择使用 db2_all 或 rah 实用程序在 DPF 实例中的远程节点上执行一个特定的命令。这些实用程序还需要一个远程 shell 实用程序。为了使用 OpenSSH 作为 DB2 UDB DPF 实例的远程 shell 实用程序,必须配置 OpenSSH,使得实例中每个主机上的实例所有者用户 ID 能够登录到实例中的每个主机上(以实例所有者用户 ID 的身份),而不会被提示需要附加的验证(例如密码或通行短语)。

本文描述如何为 AIX、Linux™、Solaris 和 HP-UX 操作系统上基于主机和基于公钥的认证配置 OpenSSH。在下面的设置中,我们将假设 DB2 UDB DPF 实例被配置为在两个不同的主机,即 machineA 和 machineB 上运行(每个主机上可以有任意数量的 DB2 节点)。我们还假设这两个机器的全限定名称分别为 machineA.my.domain.com 和 machineB.my.domain.com,为简单起见,它们的 IP 地址分别为 1.1.1.1 和 1.1.1.2。我们还假设 OpenSSH 已经被安装,ssh 守护进程(sshd)被配置为在系统启动时启动,每个机器的公钥和私钥已经生成好了。





回页首


比较基于主机的认证和基于公钥的认证

使用 ssh 的基于主机的认证和基于公钥的认证都比基于 rsh rhost 的认证安全。对于 ssh 基于主机的认证,主机必须建立一个信任关系,然后已配置主机上的所有用户 ID 都将可以凭相同的用户 ID 在任何其他已配置主机上登录。如果有多个 DB2 实例在相同的一组主机上运行,那么这一点可以带来方便。但其负面影响是,一旦任意受信任主机上的任意用户 ID 受到危害,那么在所有受信任主机上的相同用户 ID 都将受到危害,因为那个用户 ID 现在可以登录/ssh 到任何其他受信任的主机上,而不需要密码。(如果在机器上有很多用户,但是其中很少有用户需要在不提示输入密码的情况下登录/ssh 到其他主机,那么需要考虑这一点。)对于基于公钥的认证,只有某个特定的用户被配置为在不提示输入密码的情况下登录/ssh 到其他主机,所以减少了安全漏洞。而且,不需要 root 授权就可以设置基于公钥的认证(部分基于主机的认证需要 root 访问)。由于 DB2 UDB DPF 实例要求实例所有者的主目录在所有主机直接共享,因此基于公钥的认证设置非常简单。虽然这两种认证方法都比基于 rsh rhost 的认证安全,但是您应该选择更符合自身安全需求的方法。





回页首


OpenSSH 中提供的加密方法

OpenSSH 支持 DSA (Digital Signature Algorithm) 和 RSA (Rivest-Shamir-Adleman) 加密。在 Internet 上有讨论这两种加密优缺点的文献,至于它们哪一个更好,您很可能会发现不同的观点。最后,您应该选择使用符合自身安全需求的加密方式。下面的讨论将描述如何配置 OpenSSH,以使用以下两种形式的加密:

不管使用哪种加密方法,都应确保您使用的是 SSH Version 2 协议(OpenSSH 3.8p1 中的默认协议),因为 Version 2 协议比 Version 1 协议更安全。





回页首


基于主机的认证

使用 ssh 的基于主机的认证允许来自 machineA 的任何用户 ID 使用 ssh 以相同的用户 ID 登录到 machineB 上,这里假设 machineA 上的 ssh 客户机被配置为使用基于主机的认证,machineB 上的 ssh 服务器被配置为允许基于主机的认证。为了让 DB2 UDB DPF 实例使用基于主机的认证,实例中的每个主机必须正确地配置 ssh 客户机和 ssh 服务器。我们先来看 ssh 服务器配置,然后再看 ssh 客户机配置。





回页首


ssh 服务器基于主机的配置

ssh 服务器配置文件是 sshd_config,对于 AIX、Linux 和 Solaris 操作系统,可以在 /etc/ssh 目录中找到该文件。而在 HP-UX 上,sshd_config 位于 /opt/ssh/etc 目录中。为了更新这个文件,并将更新应用于正在运行的 sshd 进程,需要 root 用户身份。使用任意编辑器打开 sshd_config,搜索 # HostbasedAuthentication no 这样一行,然后将该文件作如下更新:


清单 1. sshd_config
        
#   HostbasedAuthentication no
HostbasedAuthentication yes
      

您可以随意删除原始的行,但是,保留配置文件中原始的行会比较有用,这样可以看到原始的配置,并看到对原始配置的改动。

对 sshd_config 的上述更新将允许 ssh 服务器接受来自 ssh 客户机的基于主机的认证请求。然而,基于主机的认证只是在两个受信任的主机之间被允许。这种信任基于两个标准:

  1. ssh 服务器主机在 shosts.equiv 文件中必须有一个对应于客户机主机的条目。对于 AIX 和 Linux,这个文件在 /etc/ssh 目录中,对于 Solaris,这个文件在 /etc 目录中,对于 HP-UX,这个文件在 /opt/ssh/etc 目录中。如果这个文件不存在,那么创建这个文件,并确保它的所有者是 root 用户,只允许用户 read-write 访问和 group/other read 访问(模式 "644")。由于每个主机必须能够与 DB2 UDB DPF 实例中的所有其他主机通信,所以设置 shosts.equiv 文件,使之能够在所有主机上重用。因此,这个文件看上去是这样的:


    清单 2. shosts.equiv
                
    machineA
    machineA.my.domain.com
    machineB
    machineB.my.domain.com
              


  2. ssh 服务器系统上的主机必须能够访问 ssh 客户机主机的公钥。对于基于主机的认证,信任机制在 ssh_known_hosts 文件中寻找公钥,对于 AIX、Linux 和 Solaris,这个文件位于 /etc/ssh 目录,对于 HP-UX,这个文件位于 /opt/ssh/etc 目录。如果这个文件不存在,那么创建这个文件,并确保它的所有者是 root 用户,只允许用户 read-write 访问和 group/other read 访问(模式 "644")。在 ssh 客户机主机上的 /etc/ssh 目录(在 HP-UX 上是 /opt/ssh/etc 目录)中,对于 DSA 加密,查找一个名为 ssh_host_dsa_key.pub 的文件,对于 RSA 加密,查找名为 ssh_host_rsa_key.pub 的文件,并打开该文件。对于 DSA 加密,文件的内容类似于 ssh-dss <key>;对于 RSA 加密,文件的内容类似于 ssh-rsa <key>,其中 <key> 将会是主机的公钥,它通常是一个很长的字符串。现在,打开 ssh 服务器主机的 ssh_known_hosts 文件,添加客户机的主机名(所有适用的版本 -- 未限定主机名、全限定主机名或者 IP 地址,全部以逗号隔开),后面跟上 ssh 客户机主机的公共主机密钥的内容。具体内容如下:


    清单 3. 使用 DSA 加密的 ssh_known_hosts
                
    machineA,machineA.my.domain.com,1.1.1.1 ssh-dss <machineA's public DSA key>
    machineB,machineB.my.domain.com,1.1.1.2 ssh-dss <machineB's public DSA key>
              



    清单 4. 使用 RSA 加密的 ssh_known_hosts
                
    machineA,machineA.my.domain.com,1.1.1.1 ssh-rsa <machineA's public RSA key>
    machineB,machineB.my.domain.com,1.1.1.2 ssh-rsa <machineB's public RSA key>
              

    当添加密钥到 ssh_known_hosts 文件时,应确保密钥没有被分成多个行,并确保主机的条目在一个单独的行上。

    为简化该过程,可以使用 ssh-keyscan 实用程序来取一个主机的公钥。输出可以附加到 ssh_known_hosts 文件后面,如下所示:


    清单 5. 使用 DSA 加密的 ssh_known_hosts
                
    $ cd /etc/ssh # cd /opt/ssh/etc on HP-UX
    $ ssh-keyscan -t dsa machineA,machineA.my.domain.com,1.1.1.1 >>ssh_known_hosts
    $ ssh-keyscan -t dsa machineB,machineB.my.domain.com,1.1.1.2 >>ssh_known_hosts
              



    清单 6. 使用 RSA 加密的 ssh_known_hosts
                
    $ cd /etc/ssh # cd /opt/ssh/etc on HP-UX
    $ ssh-keyscan -t rsa machineA,machineA.my.domain.com,1.1.1.1 >>ssh_known_hosts
    $ ssh-keyscan -t rsa machineB,machineB.my.domain.com,1.1.1.2 >>ssh_known_hosts
              

为了使 ssh 服务器配置生效,sshd 进程需要重新处理 sshd_config 文件。(这个文件只在 ssh 服务器守护进程第一次启动时被处理)。为了重新处理 sshd_config 文件,发送 SIGHUP 命令到 sshd (ssh 服务器守护)进程。这不会影响当前在主机上运行的 ssh 会话,只会影响将来的会话。


清单 7. 确定 sshd 进程 ID (PID)
        
$ ps -ef | grep sshd
    root  430084  114790   0 19:25:07      -  0:03 /usr/sbin/sshd
    root 3424508 1147104   0 10:39:29  pts/5  0:00 grep sshd
      

第一个条目表明 /usr/sbin/sshd 进程的 PID 是 430084。为了通知 sshd 进程重新读取配置文件,输入:


清单 8. Restart sshd 进程
        
$ kill -HUP 430084
      



清单 9. Linux 上另一种重新启动 sshd 进程的方法
        
$ /etc/init.d/sshd restart
      

这些步骤适用于 DB2 UDB DPF 实例中的所有主机。所以,相同的 ssh 服务器配置应该应用于每个节点。每个节点应该有 sshd_config、shosts.equiv 和 ssh_known_hosts 文件的相同副本。(记住在配置文件被更新后通知每个主机上的 sshd 进程重新读取配置文件。)

完成了上述 ssh 服务器设置后,便完成了 machineA 和 machineB 之间的信任关系。来自 machineA 的任何用户 ID 都可以凭相同的用户 ID ssh 到 machineB(这种形式的基于主机的认证不允许一台机器上的某个用户 ID 以不同的用户 ID 登录到其他机器上)。但是,在将 ssh 客户机也配置成使用基于主机的认证之前,基于主机的认证还没有完成。





回页首


ssh 客户机基于主机的配置

ssh 客户机配置文件名为 ssh_config (ssh 服务器配置文件是 sshd_config),对于 AIX、Linux 和 Solarisand,该文件位于 /etc/ssh 目录中,对于 HP-UX,该文件位于 /opt/ssh/etc 目录中。打开 ssh_config,查找 # HostbasedAuthentication no 这一行,然后将该文件作如下更新:


清单 10. ssh_config
        
#   HostbasedAuthentication no
HostbasedAuthentication yes
      

然后定位到该文件的底端,添加下面一行:


清单 11. ssh_config
        
EnableSSHKeysign yes
      

最后一行( EnableSSHKeysign)通知 ssh 客户机它应该使用一个单独的 ssh-keysign 实用程序来读取主机的私钥。(私钥的所有者应该是 root,并且只允许用户 read/write 访问。)另一种方法是使 ssh 实用程序本身成为 suid root,但通常更安全的做法是让 ssh-keysign 成为 suid root,因为 ssh 不需要以 root 用户身份运行。在处理之前,检验是否已经正确地安装了 ssh-keysign。在 AIX 上,该文件应该位于 /usr/sbin 目录中,但是也可能被安装到 /usr/bin 目录中。如果出现这种情况,那么将它复制到 /usr/sbin。在 Red Hat Linux 系统上,这个文件应该位于 /usr/libexec/openssh/ 目录中,而在 SUSE Linux 系统上,它应该位于 /usr/lib[64]/ssh/ 目录中。在 Solaris 上,该文件应该位于 /usr/libexec 目录上。在 HP-UX 上,它应该位于 /usr/lbin 中。现在,验证它是否被标记为 suid-root 可执行文件:


清单 12. 确保 ssh-keysign 是 suid-root 可执行文件
        
$ ls -l /usr/sbin/ssh-keysign # use the appropriate path for your platform
  -rws--x--x   1 root     system       285183 Jun 29 2004  ssh-keysign*
      

如果权限和所有者与上面的示例输出不一致,那么修复权限(在 Solaris 和 HP-UX 上,所有者应该是 root:bin,而不是 root:system)。


清单 13. 修复 ssh-keysign 上的许可
        
$ cd /usr/sbin  # replace /usr/sbin with the appropriate path for your platform
$ chown root:system ssh-keysign  # chown root:bin ssh-keysign on Solaris and HP-UX
$ chmod 4755 ssh-keysign
      

ssh 客户机现在已经被配置为允许基于主机的认证。现在可以在 DB2 UDB DPF 实例中的所有其他主机上更新 ssh 客户机配置。完成这些后,就可以进入“ DB2 配置”。





回页首


基于公钥的认证

对于基于公钥的认证,我们将允许单个用户 ID(DB2 UDB DPF 实例所有者用户 ID)在实例中其他主机上以相同的用户 ID 登录,而不会被提示输入密码。由于 DB2 UDB DPF 实例所有者的主目录在所有机器之间共享(DB2 UDB DPF 实例的先决条件),所以可以在一台机器上完成整个设置。在这个例子中,我们将使用 machineA。以 DB2 UDB DPF 实例所有者用户 ID 身份登录到 machineA。如果这个 ID 还没有一个 ~/.ssh 目录,那么创建一个这样的目录。确保 .ssh 目录不允许 group 或other write 访问。与此同时,确保主目录不允许 group 或 other write 访问(ssh 将这一点视为安全漏洞,如果目录权限没有足够的限制,将不允许基于公钥的认证)。从 ~/.ssh 目录,生成一个公钥/私钥对:


清单 14. 生成密钥对
        
$ ssh-keygen -t rsa   # ssh-keygen -t dsa for DSA encryption
      

每当提示需要输入时,按回车键接受默认值。(确保没有输入通行短语,否则 ssh 将质疑每次认证尝试,期望用户给出相同的通行短语。然而,DB2 不允许远程 shell 实用程序提示附加的验证。)这将在 ~/.ssh 目录中生成两个新的文件,对于 RSA 加密就是 id_rsa (私钥)和 id_rsa.pub (公钥),对于 DSA 加密就是 id_dsa (私钥)和 id_dsa.pub (公钥)。为了使这个新的密钥对可以和 ssh 一起使用,遵循以下步骤:


清单 15. 启用密钥对
        
$ mv id_rsa identity                 # use id_dsa for DSA key pair
$ chmod 600 identity
$ cat id_rsa.pub >> authorized_keys  # use id_dsa.pub for DSA key pair
$ chmod 644 authorized_keys
$ rm id_rsa.pub                      # rm id_dsa.pub for DSA key pair
      

这里不需要 ssh 服务器配置,因为在默认情况下,在基于密码的认证之前,ssh 将尝试使用基于公钥的认证。由于还没有形成信任关系,在第一次 ssh 到一个新主机时,您将看到一条提示消息,告诉您不能建立目标主机的认证,并且被询问是否要继续。这是 ssh 采用的额外安全特性,以确保 ssh 通信能到达适当的主机(当有人恶意危害安全时,您的 ssh 通信有可能被路由到一个不同的主机,有时候这也称作“中间人”攻击)。相对于从其他各个主机登录到每个主机,形成信任关系的更容易方法是使用 ssh-keyscan 实用程序收集 DB2 DPF 实例中每个主机的公共主机密钥。


清单 16. 收集 RSA 公共主机密钥
        
$ ssh-keyscan -t rsa machineA,machineA.my.domain.com,1.1.1.1 >>~/.ssh/known_hosts
$ ssh-keyscan -t rsa machineB,machineB.my.domain.com,1.1.1.2 >>~/.ssh/known_hosts
      



清单 17. 收集 DSA 公共主机密钥
        
$ ssh-keyscan -t dsa machineA,machineA.my.domain.com,1.1.1.1 >>~/.ssh/known_hosts
$ ssh-keyscan -t dsa machineB,machineB.my.domain.com,1.1.1.2 >>~/.ssh/known_hosts
      

至此,ssh 基于公钥的认证已经完成,现在可以进入“ DB2 配置”。





回页首


配置 DB2 以使用 ssh 作为远程 shell 实用程序

现在,您已经将 ssh 配置为使用某种形式的认证,这种认证不提示附加的验证,您可以验证该配置是否成功。第一个测试是检查 machineA 是否可以使用 ssh 在 machineB 上运行一个简单的命令。以 DB2 UDB DPF 实例所有者用户 ID 登录到 machineA,并输入:


清单 18. 简单的 ssh 配置测试
        
$ ssh machineB echo hi
      

如果您被提示提供通行短语,那么很可能意味着您在使用公钥认证,并且在生成公钥/私钥对时指定了一个通行短语。返回到 public key authentication instructions,生成一个不需要通行短语的新的公钥/私钥对。如果您被提示输入密码或收到任何其他错误,那么进入“ 故障分析与排除”。如果命令花费超过一两秒钟的时间返回,那么可能是存在网络名称解析配置问题或与特定版本的 ssh 相关的配置问题。不管是哪种情况,搜索 Internet 和网络配置文档,以发现可能的原因及解决办法。否则,就可以通知 DB2 开始使用 ssh 执行远程命令。从 machineA 上的 DB2 UDB DPF 实例所有者用户 ID 输入:


清单 19. 通知 DB2 开始使用 ssh
        
$ db2set DB2RSHCMD=/usr/bin/ssh
      

这将通知 DB2 在远程 DB2 节点上执行内部 DB2 命令(例如使用 db2start 启动一个远程 DB2 节点)时以及在所有 DB2 节点上通过 db2_all 脚本运行命令时使用哪个远程 shell 实用程序。为了测试是否在 DB2 UDB DPF 实例中的所有主机上正确地配置了 ssh,尝试一个简单的命令 -- 使用以下命令让每个 DB2 节点回显一个响应:


清单 20. 在每个 DB2 节点上显示一次 hi
        
$ db2_all echo hi
      

如果命令成功完成,而没有提示附加的验证,那么就可以进入下一步。否则,跳到“ 故障分析与排除”。最后的测试确保 DB2 节点可以 ssh 到其他各个 DB2 节点。还应确保任何 DB2 节点可以 ssh 到任何其他 DB2 节点。所以现在运行最后一个命令修改后的版本:


清单 21. 请求每个节点在其他各个节点上显示 hi
        
$ db2_all db2_all echo hi
      

这一次应该有更多的输出行。只要所有 DB2 节点响应时没有提示附加的验证,DB2 就算是完全配置好了,已经可以使用 ssh 作为远程 shell 实用程序了。您需要停止数据库服务器( db2stop),并重新启动服务器( db2start),以便使新的设置在 DB2 服务器上生效(设置立即对 db2_all 脚本生效)。





回页首


故障分析与排除

基于主机的认证或基于公钥的认证不能工作的原因可能有很多 -- 每种版本的 ssh 似乎总会在这里和或那里做一些小的改动,最终破坏某些配置。本节不详细讨论如何分析和排除所有 ssh 配置问题,但是让您对此有一个初步的了解。在继续之前,请重新阅读前面所有指令,确保遵循了配置的每一步。通常需要检查的两点有:

  1. 确保所有 ssh 服务器配置文件引用客户机的规范名称,也就是服务器所看到的名称。例如,如果 ssh 客户机连接来自 IP 1.1.1.1,那么 ssh 服务器上的 gethostbyname(1.1.1.1) 应该能够将其映射到 machineA (或 machineA.my.domain.com)。请参阅网络配置文档以了解更多细节。

  2. 认真检查权限。私有主机密钥的所有者应该是 root,并且只允许 root 对其进行读写。公共主机密钥应该只允许 root 进行读写,而对于 group/other 访问则是只读的。对于基于公钥的认证,用户的私钥应该由那个用户所有,对于那个用户是可读/可写的,而对于任何其他用户是不可读的。公钥对于其所有者应该是可读/可写的,而对于 group/other 访问是只读的。同样对于基于公钥的认证,DB2 UDB DPF 实例所有者用户 ID 的主目录对于 group/other 应该是不可写的。~/.ssh 目录应该只对于实例所有者 ID 是可读/可写的(不允许 group/other 访问)。

如果一切配置正确,就可以进行 ssh 服务器和 ssh 客户机跟踪,并通过挖掘跟踪来诊断问题。为此,需要采用两个不允许期望形式的认证的主机(在下面的讨论中我们假设是 machineA 和 machineB)。以 root 身份登录到 machineA。在启用额外调试诊断的情况下,在指定端口启动 ssh 服务器,如下所示。(在这个例子中我们将使用端口 5555,任何可用的用户端口都是可行的):


清单 22. 启动一个新的诊断服务器会话
        
$ /usr/sbin/sshd -d -d -d -p 5555 2>&1 | tee sshd.trace # /opt/ssh/sbin/sshd on HP-UX
      

然后,以 DB2 UDB DPF 实例所有者用户 ID 登录到 machineB 上,并启动 ssh 客户机,如下所示:


清单 23. 启动一个新的诊断客户机会话
        
$ ssh -v -v -v -p 5555 machineA echo hi 2>&1 | tee ssh.trace
      

如果看到提示,则输入密码,这个命令将执行到完毕为止。(在最不理想的情况下,ssh 提示您输入密码。当您被提示输入密码时,期望形式的认证已经失败。)现在,有趣的检测工作可以开始了。首先打开客户端跟踪(machineB 上的 ssh.trace),检查消息,看是否存在错误。消息中包含很多信息,所以解释起来要花一些时间。从客户机跟踪应该可以确定是 ssh 客户机还是 ssh 服务器阻碍了期望形式的认证。如果是服务器阻碍了认证,那么打开 ssh 服务器跟踪(machineA 上的 sshd.trace)寻找线索。当您在客户机跟踪或服务器跟踪中发现看上去不正确的或者不能理解的条目时,解释消息的最容易的方法是在 Internet 上对在跟踪中发现的字符串(或字符串的一部分)进行搜索。很可能有人已经碰到了类似的配置问题,他们很可能有您想要的解决办法。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • 了解关于 OpenSSH 项目的更多信息。

  • 要了解更多关于 DB2 的信息,请访问 developerWorks DB2 专区。 您将发现技术性文档、how-to 文章、下载链接、产品信息等等。

  • 从 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 获取评测产品,开始构建应用程序并将它们部署到 IBM 中间件上。选择 Linux™ 或 Windows® 版本的免费 Software Evaluation Kit (SEK)

  • 访问 developerWorks blogs,加入 developerWorks 社区。


关于作者

Author photo

Liam Finnie 在 DB2 UDB Operating System Services 部门担任专职软件开发人员,帮助开发和维护操作系统 API 的抽象层。他擅长的领域是内存管理 -- 在所有受支持的操作系统上,控制 DB2 UDB 如何以一种有效的方式分配和管理私有和共享内存。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款