简介
认证是当用户或应用程序连接到数据库时验证其身份的过程。赋予用户特权的数据库和服务器首先对每个用户进行正确的认证,这很重要。传统上,Informix® 服务器和客户机只支持简单的认证机制,即使用可信的主机或基于密码文件的认证。现在您有了更广泛的认证选择 — 使用可插入的认证模块(PAM)机制。ESQL/C 的版本 9.53.xC2(与 CSDK 2.82.xC2 一起提供的)开始支持这种新的认证机制。
对于可信的主机,数据库根据连接请求的来源来假定是否可信。如果发送请求的机器是可信的,那么该机器上的用户也是可信的。对于基于密码文件的认证,认证是以安装数据库服务器的机器上的密码和影子(shadow)文件或者与网络信息系统(Network Information System,NIS)的交互为基础的。现有的这些机制的缺陷在于无法使用操作系统可能提供的增强认证。
对于 IBM Informix Dynamic Server® 中的 PAM 实现,所有新旧 ESQL/C 应用程序(通过实现少量更改和重新编译较老的应用程序)现在都可以利用这个新的认证模块,从而改进了客户机与数据库服务器通信和认证的方式。PAM 机制的实现使用户可以在服务器的 sqlhosts 文件中设置额外的标志,以便让用户随心所欲地使用外部认证。需要围绕该认证服务来构建 ESQL/C 应用程序,以处理所有的询问(challenge),并对这些认证询问做出响应。
框架和受支持的平台
为了使用新的 PAM 机制进行认证,首要需求就是您必须拥有最新的 ESQL/C 版本 — 与连接到 Informix Dynamic Server V9.40.UC2 的 CSDK2.81.xC2 一起提供的 9.53.xC2。如果客户机或服务器的版本比这些版本老,则无法使用 PAM 机制。稍后我将在本文中谈论各种客户机-服务器兼容性。
支持 PAM 认证方式背后的主要思想就是能够使用增强的 OS 级别的认证。由于认证是在服务器上进行的,因此 IBM Informix Dynamic Server 应该位于某个支持 PAM 的平台上,这一点很重要。目前,AIX® 32 位、AIX 64 位、HP 32 位、HP 64 位、Solaris 32 位、Solaris 64 位和 Linux 都支持 PAM。如果您正在连接的服务器位于任何其它操作系统上,那么应用程序使用传统的认证方式连接到该服务器。
当然,因为认证是在服务器端进行的,所以客户机(ESQL/C 应用程序)可位于任何平台上。只要注册并编写一个回调函数来处理由服务器抛出的询问,客户机应用程序就与平台无关了。
编写支持 PAM 的 ESQL/C 应用程序
通过编写 ESQL/C 应用程序使用户可以由使用 PAM 的服务器认证,最新 IBM Informix ESQL/C 和 IBM Informix Dynamic Server 的新用户可以快速地使用这个功能,并使认证过程具有更高的可信性。PAM 允许数据库和系统管理员以更大的灵活性并采用可插的模块化体系结构来设置支持 PAM 的应用程序的认证策略。这种认证方式使人们可以对认证过程进行更多的控制。
对于需要使用 PAM 机制的所有应用程序而言,首先需要编写一个认证模块,该模块将在认证过程中“抛出询问”并使响应与询问匹配。例如,如果您登录到某个系统,它通常会要求您输入‘用户名’,如果有必要,它还会提示您输入‘密码’。用户名和密码是由系统抛出的非常简单的询问示例。利用 PAM,您可以更进一步,让您的应用程序成功地与由该模块(为这样的数据库认证而编写的)抛出的更多询问进行通信,并对其作出响应。通常,询问是预先准备好的要向每个用户提出的问题,您必须正确回答它才允许您访问数据库。这些询问的性质因用户而异,这取决于如何编写 PAM 模块。
对于要访问这类支持 PAM 的 Informix Dynamic Server 的 ESQL/C 应用程序而言,应用程序对这类访问的支持至关重要(正如我们将在下面的示例中所展示的那样)。这称为 PAM 服务。对于大多数平台而言,PAM 服务模块驻留在 /usr/lib/security 目录中。开发人员将需要编写一个 PAM 服务模块,并将它放入 IBM Informix Dynamic Server 所在机器的 /usr/lib/security 目录中。IBM Informix Dynamic Server 将装入该库(服务),并使用它来认证客户机。
pam.conf 文件建立服务、库和模块之间的映射。典型的项看起来将如下面这样:
login auth required /usr/lib/security/pam_unix.so.1
pam.conf 文件中的这个项意味着对于“login”服务而言,PAM 库“/usr/lib/libpam”需要使用 pam_unix.so 模块。
类似地,对于 IBM Informix Dynamic Server,要理解用于认证每个连接的 PAM 服务,必须在服务器的 SQLHOSTS 文件中添加一项。对于可以处理这种新认证模块的服务器,其典型的 SQLHOSTS 文件如下所示:
清单 1. 支持 PAM 的服务器的 sqlhosts 样本文件
<servername> <service (ontlitcp/onsoctcp)> <machinename>
<portno>
s=4,pam_serv=<pam servicename>, pamauth=(challenge).
* <servername> — IBM Informix Server 的名称(和 onconfig 文件中出现的一样)
* <service> — 使用哪种服务:ontlitcp、onsoctcp 和 onipcshm 等
* <machinename> — 服务器所在机器的名称
* <portno> — 客户机和服务器之间通信所用的端口号
* pam_serv=<servicename> — PAM 服务模块的名称,该模块是由用户编写的,并放在 IBM Informix Dynamic Server 所在机器的 /usr/lib/security 目录中。这是一个服务,编写后放在 /usr/lib/security 中,它会抛出询问以对用户进行认证。
* pamauth=(challenge) — 指定服务器将使用询问-响应机制来认证连接到该服务器的所有客户机。
一旦编写 PAM 服务模块并将其保存在 /usr/lib/security 目录中,服务器的 sqlhosts 文件中就会设置一个标志(pamauth=challenge),以表明服务器要使用外部认证,并且服务器将引入“challenge”方式,现在我们可以继续编写能够处理服务器所需外部认证的 ESQL/C 应用程序。典型的 PAM 服务模块由几个抛向用户的询问构成,对用户的认证是以对这些询问的响应为基础的。因此,我们需要拥有一个能够处理这些询问,并抛回响应的 ESQL/C 应用程序。
我已经编写了一个典型的样本程序(pamdemo.ec),它是与最新的 ESQL/C 产品一起提供的。它说明了如何编写 ESQL/C 应用程序以使用 PAM 服务。
样本演示程序如下所示,其中带底色的框中包含的几行注释是对程序的说明。该程序说明如何使用 ESQL/C 来与使用 PAM 的 IBM IDS 进行认证。
清单 2. pamdemo.ec
#include <stdio.h>
#define PAM_PROMPT_ECHO_OFF 1 /*Echo off when getting response*/
#define PAM_PROMPT_ECHO_ON 2 /*Echo on when getting response*/
#define PAM_ERROR_MSG 3 /* Error Message */
#define PAM_TEXT_INFO 4 /* Textual Information */
#define PAM_MAX_MSG_SIZE 12 /* max size of each message */
这些定义通常位于支持 PAM 的系统的 /usr/include/security/pam_appl.h 文件中。目前,只有 AIX 32/64 位、HP 32/64 位、Solaris 32/64 位和 Linux 支持这种 PAM 认证。如果服务器打算使用 PAM 认证,那么它必须安装这其中的某个平台上,这一点很重要。而客户机(ESQL/C 应用程序)可以位于任何平台/OS 上。当 PAM 服务返回每个消息时,还会返回消息类型。对于位于非 PAM 系统上的客户机应用程序而言,必须象上面那样显式地定义这些定义。在确定应用程序所要采取的进一步行动时,这些返回类型消息很重要。如果 ESQL/C 应用程序位于支持 PAM 的系统上(AIX 32/64 位、HP 32/64 位、Solaris 32/64 位和 Linux),通过包含如下所示的 /usr/lib/security/pam_appl.h 文件,就可以定义这四个定义了:#define <security/pam_appl.h>
EXEC SQL define FNAME_LEN 15;
EXEC SQL define LNAME_LEN 15;
int callback(char *challenge, char *response, int msg_style);
对于要使用 PAM 的任何 ESQL/C 应用程序而言,它必须包含回调函数。首先必须注册该回调函数。下面,我们定义了这个回调函数。我将更详细地谈论下面这个回调函数。
int main()
{
EXEC SQL BEGIN DECLARE SECTION;
char fname[ FNAME_LEN + 1 ];
char lname[ LNAME_LEN + 1 ];
EXEC SQL END DECLARE SECTION;
int retval = 0;
/* First register the callback. This needs
* to be done before establishing the
* connection as done here.
*/
就象注释说明的,必须注册回调函数。回调函数的主要目的是在应用程序连接到支持 PAM 的 IBM IDS 服务器时能够处理由 PAM 服务抛出的所有询问。回调函数必须能够接受这些来自服务器的询问,并将它们发送给用户(可能是另一个应用程序或用户界面),然后取回对那些询问的响应,并将它们依次传回服务器以用 PAM 服务进行认证。
在首次建立与服务器的连接之前必须注册该函数。每当服务器根据编写的 PAM 模块抛出询问以便应用程序相应地作出响应时,ESQL/C 库都会调用该回调函数。
即使您正在通过单个应用程序连接几个服务器,其中一些能够理解 PAM 模块而另外一些却不能,您仍然需要向那些能够理解 PAM 服务的服务器注册回调函数。连接到非 PAM 服务器时不会有任何问题,即使注册了应用程序也是如此,因为在那些情形中决不会调用回调函数。
printf("Starting PAM demo \\n");
EXEC SQL WHENEVER ERROR STOP;
retval = ifx_pam_callback(callback);
上面就是我们注册回调函数的地方。回调函数的名称是‘callback’。为了在每次 sqli 库接收到来自服务器的询问时能够调用该函数,注册回调函数是很重要的。以下是注册回调函数的出错检查:
if (retval == -1)
{
printf("Error in registering callback\\n");
return (-1);
}
else
{
printf( "Callback function registered.\\n");
EXEC SQL database stores_demo;
printf ("SQLCODE ON CONNECT = %d\\n", SQLCODE);
现在,当客户机建立与服务器的连接时,sqli 库将调用已注册的回调函数。仅当正确注册了回调函数,并且当用户能够对 PAM 服务抛出的询问提供正确响应时,程序才会继续。
程序的余下部分是简单的演示程序(与前面的 ESQL/C 一起提供的 demo1.ec 原本),这段程序的后面是回调函数‘callback’。
EXEC SQL declare pamcursor cursor for
select fname, lname
into :fname, :lname
from customer
where lname < "C";
EXEC SQL open pamcursor;
for (;;)
{
EXEC SQL fetch pamcursor;
if (strncmp(SQLSTATE, "00", 2) != 0)
break;
printf("%s %s\\n",fname, lname);
}
if (strncmp(SQLSTATE, "02", 2) != 0)
printf("SQLSTATE after fetch is %s\\n", SQLSTATE);
EXEC SQL close pamcursor;
EXEC SQL free pamcursor;
EXEC SQL disconnect current;
printf("\\nPAM DEMO run completed successfully\\n");
}
}
/* The callback function which will
* provide responses to the challenges. */
这个回调函数就是先前注册的那个,它是在首次建立与支持 PAM 的 IBM Informix Dynamic Server 的连接之前注册的。编写该函数的方法有多种,这取决于用户希望如何处理由支持 PAM 的服务器抛出的询问。下面的代码显示了一种非常简单的方法。其中的回调函数带有三个参数,返回一个整数。根据消息类型(msg_style),该函数(接着还有 ESQL/C 应用程序)确定需要提供给服务器的响应种类。所有询问都希望有响应。如果有出错消息,或者只是一个不需要响应的消息,那么就在提示符后显示该消息。
询问被抛向用户,并且期望获得对询问的响应,然后将其提供给用户。
非询问响应可以是几种情形之一,例如“authentication successful”,这取决于 PAM 模块(服务)的编写方式。
重申一次,每当建立与数据库服务器的新连接时,就调用该回调函数,并且服务器抛回一个要求更多信息的询问,而不是使用简单的用户名和密码机制进行认证。
int callback(char *challenge, char *response,
int msg_style)
{
switch (msg_style){
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON :
printf("%s: %d:",challenge, msg_style);
scanf("%s:",response);
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
default:
printf("%s: %d\\n",challenge, msg_style);
}
return 0;
}
上述程序可在任何操作系统上编译和运行,既可以与非 PAM 服务器通信,也可以与 PAM 服务器通信。仅当客户机连接到支持 PAM 的服务器时,回调函数才开始起作用,并要求用户输入对由其正在连接的服务器抛出询问的响应。
使用 PAM 模块的客户机-服务器兼容性
PAM 认证功能的开发人员小心地避开了客户机-服务器兼容性问题。用户可以转移到最新的 ESQL/C 客户机(库),而无需过分担心 PAM,即使他们正在连接到最新的 IBM Informix Dynamic Server。迁移或升级到最新的 ESQL/C 版本并不意味着必须提供回调函数,以及必须使用 PAM 功能来连接到服务器。该功能是可选的,而且仅当应用程序连接的服务器处于 PAM 方式时它才起作用。
此外,当您编写新的应用程序时,用户可以继续使用较旧的服务器认证方法。是否使用 PAM 认证方式完全由您自己选择。请记住,同一个应用程序既可以与不具备 PAM 功能的服务器通信,也可以与具备 PAM 功能的服务器通信。要连接到这两种服务器,无需编写不同的应用程序。
到目前为止,在客户机-服务器通信方面尚未发现不兼容性问题。
结束语
可插入的认证模块为数据库管理员提供了更大的灵活性,并使他们能够更好地控制用于 Informix Dynamic Server 数据库的认证策略。为其它应用程序编写的现有 PAM 模块可用于客户机-服务器认证,因而可以将一个公共认证用于各种应用程序,从而降低了维护成本。
过去,您可能需要为每类用户提供单独的认证方案,并且需要为每类用户编写一个程序。现在,PAM 允许 ESQL/C 应用程序开发人员专注于核心程序本身的功能,同时让数据库管理员以及先前编写的 PAM 模块控制认证过程。这种可插入的灵活性确实是客户机-服务器认证的未来,而且事实上,也是需要认证的每个程序的未来。
相关信息
可通过互联网在几个网站上获得有关 PAM 的更多读物和文档。其中值得一读的几篇文章有:
* http://java.sun.com/security/jaas/doc/pam.html/
* http://wwws.sun.com/software/solaris/pam/
* http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/pam_appl.html