概述
Domino Web服务器应用程序编程接口(DSAPI)是一个C API,它允许您将自己的扩展编写到Domino Web服务器。 在处理http请求期间发生特定事件时,通知DSAPI扩展或过滤器。
DSAPI筛选器允许您在发生特定事件时自定义http请求的处理。 http堆栈通知事件的过滤器。 DSAPI过滤器当前可以捕获13个事件。 根据设计及其实现,过滤器可以支持一个或任意数量的事件。
DSAPI接口的实现依赖于过滤器来指示它支持哪些事件。 过滤器然后只接收它声称支持的事件的通知。
请参考任何本文件中提到的筛选数据结构的详细信息,IBM C API参考 。
入门
DSAPI过滤器必须指定两个入口点:
可选条目点可以为过滤器终止来限定。 此外,可以为线程初始化和终止定义可选的入口点。
初始化
当加载过滤器时,Domino调用Initialization函数。 当Domino HTTP服务器任务启动时或使用Domino控制台命令“tell http restart”重新启动HTTP任务时,将加载过滤器。 初始化函数的原型是:
/ * ---
*过滤器初始化
* /
unsigned int FilterInit(FilterInitData * pFilterInitData);
初始化函数的名称必须为FilterInit,DSAPI图层才能在加载过滤器时找到它。
请参考上FilterInitData结构的进一步信息,IBM C API参考 。
事件通知
事件通知功能负责过滤器的实际工作。 Domino在处理http请求期间发生特定事件时调用事件通知函数。 当Domino调用过滤器的事件通知函数时,它传递有关请求和正在处理的事件的信息。 在每次调用时,过滤器可以决定处理事件,有或没有错误返回,或拒绝处理事件。 事件通知功能的原型是:
/ * ---
*过滤器通知处理
* /
unsigned int HttpFilterProc(FilterContext * pContext,unsigned int eventType,void * pEventData);
事件处理函数的名称必须是HttpFilterProc,以便DSAPI图层在加载过滤器时找到它。
pContext是一个指针FilterContext包含有关该http请求,服务器回调函数指针,和一个指针到过滤器自身的数据的上下文信息。 请参考上FilterContext结构的进一步信息,IBM C API参考 。
EVENTTYPE指示哪个事件正在发生。
pEventData是指向与事件相关联的结构。 每个事件都有不同的事件数据结构。 有关详情,请参阅下面的事件部分。
可选线程初始化和终止
过滤器还可以定义用于线程的初始化和终止的入口点。 http栈将在调用初始化函数FilterInit之后调用函数HttpFilterThreadInit。 HttpFilterThreadInit主要用于初始化任何线程局部变量。 过滤器线程初始化函数的原型是:
unsigned int HttpFilterThreadInit(int threadType);
过滤器线程初始化函数需要过滤器线程终止函数。 当库被卸载时,将调用此函数,以允许过滤器释放由过滤器线程初始化函数分配的任何资源。 过滤器线程终止功能的原型是:
unsigned int HttpFilterThreadTerm(int threadType);
选择终止
过滤器还可以定义终止入口点。 Domino将在过滤器即将卸载时调用此函数 - 当http堆栈进程正在关闭时。 过滤器可以使用此函数来清理它分配的资源。 过滤器必须在调用其初始化例程时释放它分配的所有全局资源。 过滤器终止功能的原型是:
/ * ---
*过滤器终止
* /
unsigned int TerminateFilter(unsigned int reserved);
所有导出的函数都返回一个unsigned int状态代码。 状态代码的可能值如下:
注意,对于函数FilterInit,HttpFilterThreadInit,HttpFilterThreadTerm和TerminateFilter,唯一可能的返回码是kFilterHandledEvent和kFilterError。 函数HttpFilterProc可以在处理事件时返回任何状态代码。
事件
事件按特定顺序发生。 它们反映了http堆栈在每个处理步骤的状态。 事件通知可以被视为过滤器覆盖给定处理步骤的默认实现的机会。 对于每个事件,包含附加信息和在大多数情况下附加的回调函数的结构被传递到过滤器的事件通知处理例程。 过滤器可以调用回调函数以获取其他信息或执行服务。 仅对过滤器注册的那些事件(在过滤器加载和初始化时在FilterInitData结构中传递的那些事件)调用事件通知例程。 事件在其发生的顺序中描述如下。
kFilterStartRequest事件
此事件用于向当前加载的所有过滤器通知已收到http请求,并且将要处理。 在此步骤中,过滤器可以准备处理请求。 通常在此步骤中,过滤器应分配其自己的私有上下文数据,以及处理请求处理所需的必要资源。 不使用参数pEventData,并传递NULL。 支持此事件的任何过滤器都应返回值kFilterHandledEvent。
kFilterRawRequest事件
将通知当前加载并支持此事件的所有过滤器,所有输入的HTTP头都已读入。任何需要预处理输入头的过滤器都可以这样做。 请注意,过滤器可以选择此时完全服务http请求。 参数pEventData是一个指向FilterRawRequest结构的指针。 结构FilterRawRequest如下所述:
当http堆栈已经完成预解析所有http输入头时,使用此事件通知当前加载并支持此事件的所有过滤器。 注意,这反映了与事件kFilterRawRequest中相同的状态,因为http堆栈在开始调用任何过滤器之前预解析http输入头。 任何过滤器都可以选择在此步骤完全处理请求。 pEventData是一个指向结构FilterParsedRequest的指针。 注意,只提供了两个回调函数。 您只能在此步骤中访问http输入标头。 使用kFilterRawRequest,您也有机会更改它们。
当前加载并支持此事件的所有过滤器都有机会更改URL,将请求重定向到其他资源。 如果过滤器成功重写要处理的URL,并且服务器处理新的URL,则DSAPI层停止处理此事件,即,不通知列表中的其他过滤器。 pEventData是指向该结构,FilterMapURL的一个实例。 注意,结构FilterMapURL也用于事件,kFilterTranslateRequest和kFilterPostTranslate。
kFilterAuthenticate事件
当http堆栈处于进程的身份验证阶段时,会发生此事件。 过滤器代码可以查看请求和用户凭证,为http堆栈验证用户,或完全处理请求。 pEventData是指向结构实例的指针。
void(* GetMappedResource)(FilterContext * pContext,
char ** ppBuffer,
unsigned int * pErrID);
kFilterUserNameList事件
当http堆栈即将生成用户的组名称列表时,会发生此事件。 这些是用户所属的组名称。 此事件跟随kFilterAuthenticate事件。 过滤器可以使Domino服务器填充列表,向列表添加或删除组或完全处理事件(完全生成组列表本身)。 函数中的参数HttpEventProc,pEventData是指向结构FilterUserNameList的指针。
kFilterTranslateRequest事件
当http堆栈要将路径URL转换为目标资源时,会发生此事件。 过滤器可以使用自己的翻译和映射规则翻译请求,或完全处理请求。 pEventData指向的结构中,FilterMapURL的一个实例。 结构FilterMapURL如下所述:
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
kFilterPostTranslate事件
此事件在事件kFilterTranslateEvent已处理之后发生。 这是过滤器更改要访问的目标资源的机会。 过滤器可以更改目标资源路径和映射类型。 过滤器还可以选择完全服务请求。 pEventData是一个指向结构FilterMapURL的指针。 结构FilterMapURL如下所述:
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
此事件发生在认证阶段发生之后,并且已经计算了用户的组名称列表。 过滤器可以覆盖授权阶段的默认实现,并授予或拒绝对目标资源的访问。 pEventData是一个指向结构体FilterAuthorize的指针。 它包含有关要提供的目标资源的信息。 请注意,过滤器可以通过使用带有标志kGetAuthenticatedUserInfo的ServerSupport回调的服务来访问经过身份验证的用户信息。 这将允许用户访问用户的已认证的名称以及他/她的组名称列表。
如果过滤器拒绝访问目标资源,则它必须向客户端发送适当的响应,并将FilterAuthorize结构中的字段isAuthorized设置为0.然后它可以返回kFilterHandledRequest或kFilterHandledEvent。 然后,DSAPI层将发信号通知http栈以终止当前请求的处理。
结构FilterAuthorize如下所述:
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
kFilterProcessRequest事件
这是服务http请求的最后一步。 这个事件可以用来覆盖默认实现的请求处理。 在该阶段中,响应数据被计算并发送到客户端。 pEventData是一个指向结构FilterMapURL的指针。 结构FilterMapURL如下所述:
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
此事件用于建议过滤器代码,它是时候清理和释放分配的资源以处理给定的http请求。 在这种情况下,pEventData为NULL。
kFilterAuthUser事件
此事件替换为kFilterAuthenticate事件,但仍支持与以前写入的DSAPI过滤器的兼容性。 在这种情况下,过滤器验证Web用户。 pEventData是结构的一个实例FilterAuthenticate。 在上述kFilterAuthenticate事件中完全描述了该结构。
此事件允许您自定义Web用户的身份验证,这通常是在公司内实施“单点登录”的一部分。 在这种情况下,当Domino验证用户时通知DSAPI过滤器。 然后,DSAPI筛选器可以解析用户名,根据传统大型机系统验证用户名和密码,如果成功,请通知Domino Web服务器它已处理用户的身份验证,并将用户的凭据返回Domino。
这是一个指南,用于设置常用认证方案的输出变量和返回代码,其中eventData指向FilterAuthenticate结构:
当http堆栈要向客户端发送http响应头时,会发生此事件。 这给了过滤器改变发送到客户端的响应的机会。 这在当前版本的DSAPI中未完全实现。 pEventData是一个指向结构FilterResponse的一个实例,下面描述:
typedef struct {
unsigned int responseCode;
char * reasonText;
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,
unsigned int * pErrID);
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
int(* SetHeader)(FilterContext * pContext,
char * pName,
char * pValue,
unsigned int * pErrID);
int(* AddHeader)(FilterContext * pContext,
char * pHeader,
unsigned int * pErrID);
unsigned int reserved;
char * userName;
} FilterResponse;
responseCode -输入参数。 它是HTTP响应状态代码。
reasonText -输入参数。 它是HTTP响应状态文本(如果有)。
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,
unsigned int * pErrID);
此回调函数允许过滤器访问响应http头。
返回包含http响应头的缓冲区的字节计数。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
ppHeaders - 是一个指向位置的指针,DSAPI层将存储指向包含响应http头的缓冲区的指针。
pErrID - 是指向无符号整数的指针,如果成功,则设置为0,否则设置为错误代码。 可能的错误代码是:DSAPI_INVALID_ARGUMENT,DSAPI_MEMORY_ERROR和DSAPI_INTERNAL_ERROR。
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
此回调函数检索单个http响应头值。 提供了http头名称。 如果http头不存在,则在提供的缓冲区中返回一个空字符串。
对于硬故障(传递的错误参数)返回0,如果successfull,则包含结果的缓冲区中的有效字节数,如果缓冲区太小而不包含结果,则返回所需的缓冲区大小。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pName - 是指向包含所需http标头名称的字符串的指针。 这不能等于NULL也不能为空字符串。
pBuffer - 是指向缓冲区的指针,用于存储结果。 此参数不能为NULL。
bufferSize - 是提供的缓冲区的大小。
pErrID - 是指向无符号整数的指针,如果successfull,则设置为0,如果提供的缓冲区太小,不能包含结果,则指向DSAPI_BUFFER_TOO_SMALL。
int(* SetHeader)(FilterContext * pContext,
char * pName,
char * pValue,
unsigned int * pErrID);
此回调函数允许过滤器更改现有响应http标头的值。 注意,如果http头不存在,它被添加到http响应头的列表。
如果successfull,返回TRUE,否则返回FALSE。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pName - 是指向包含要更改的http标头的名称的字符串的指针。 此参数不能为NULL或空字符串。
pValue - 是一个指向包含http头的值的字符串的指针。
pErrID - 指向无符号整数的指针,用于存储状态代码。 如果操作成功,状态码设置为0,否则设置为非零值。
int(* AddHeader)(FilterContext * pContext,
char * pHheader,
unsigned int * pErrID);
此回调函数允许过滤器将http标头添加到响应http标头的列表中。 请注意,如果http头已存在,则其值将更改为反映新值。
如果成功,返回TRUE,否则返回FALSE。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pHeader - 是指向有效http标头的指针。 预期的格式是一样的响应HTTP头的格式,即<headerName:值>。
pErrID - 指向无符号整数的指针,用于存储状态代码。 如果操作成功,状态码设置为0,否则设置为非零值。 在这种情况下,唯一的非零值是DSAPI_INVALID_ARGUMENT,表示检测到所提供头的格式错误。
保留 - 留作将来使用。
kFilterRawWrite事件
当http堆栈要向客户端发送http响应数据时,会发生此事件。 这给了过滤器改变发送到客户端的响应数据的机会。 这在当前版本的DSAPI中未完全实现。 pEventData是一个指向结构FilterRawWrite的一个实例,下面描述:
contentLen -输入/输出参数。 它是输入上提供的缓冲区中的有效字节数,和/或输出上缓冲区中的有效字节数。
保留-留作将来使用。
运行和编程注意事项
DSAPI示例代码
此示例的目的是显示如何扩展Domino Web服务器以启用Unix密码检查。 当通过Web浏览器访问Domino数据库时,Domino可以基于Unix密码(即,存储在标准Unix密码注册表(如/ etc / passwd或NIS)中的密码)对用户进行身份验证。 可以剪切和粘贴这里记录的内容,并将其合并到您自己的样本中。 运行和安装过滤器的步骤如下。
当访问受保护的Web页面时,Domino将提示输入用户名和密码。
此示例允许用户输入Unix密码,并且在可以验证密码的情况下进行Web访问验证。
此示例仅适用于Domino和Unix都知道用户的情况。
该示例假定Unix用户名是用户的Domino“短名称”。 例如:
Domino用户名李四
多米诺简称 JDOE
Unix用户名 JDOE(注:Unix的是大小写敏感的,所以在Domino短名称应当存储为小写字符为获得最佳的互操作性,这个名字应该是超过8个字符。)
1. 安装过滤器
2.运行过滤器
#include <stdlib.h>
#include <stdio.h>
#include <String.h>
/ *特殊dsapi包含文件* /
#include“dsapi.h”
/ * unix认证包括* /
#ifdef AIX
#include <sys / types.h>
#include <pwd.h>
#万一
#ifdef HPUX
#include <pwd.h>
#include <crypt.h>
#include <unistd.h>
#万一
/ * Notes SDK包含文件* /
#include“global.h”
#include“osmem.h”
#include“lookup.h”
/ * ---
*本地过程原型
* /
/ * Notes SDK unix共享库entrypoint * /
状态FAR PASCAL MainEntryPoint(void);
/ *具有由DSAPI接口指定的语法的例程* /
unsigned int Authenticate(FilterContext * context,FilterAuthenticate * authData);
/ *从Notes名称和地址簿检索名称* /
int getUserNames(FilterContext * context,char * userName,char ** pUserFullName,int * pUserFullNameLen,
char ** pUserShortName,
int * pUserShortNameLen);
int getLookupInfo(FilterContext * context,char * pMatch,int itemNumber,char ** pInfo,int * pInfoLen);
/ * unix密码检查程序* /
int unixAuthenticate(char * userName,char * password);
/ * ---
*本地程序如下
* /
状态FAR PASCAL MainEntryPoint(void)
{
/ *
*说明:提供Notes API的主入口点
*初始化此共享库。 我们需要
*这个入口点,因为我们想要能够查找
*用户信息在名称和地址簿中通过
* Notes SDK API。
*:
*输入:无
*输出:无
*返回:NOERROR
* /
return NOERROR;
}}
/ * ---
*过滤器初始化
* /
unsigned int FilterInit(FilterInitData * filterInitData)
{
/ *
*说明:当过滤器执行过滤器初始化
*共享库是动态加载的。
*:
*输入:filterInitData dsapi规范控制格式
* 数据的
*输出:filterInitData填充几个字段
*:
*返回:kFilterHandledEvent
* /
/*需要*/
filterInitData-> appFilterVersion = kInterfaceVersion;
/ *修改以下代码以设置您想要的标志* /
filterInitData-> eventFlags =
kFilterAuthUser;
/ *设置过滤器的简短描述* /
strcpy(filterInitData-> filterDesc,
“Unix Authentication Filter”);
/ *在这里插入任何全局初始化代码... * /
/ *输出发送到stdout和stderr显示在
*服务器控制台,但不会写入服务器日志文件。
* /
printf(“\ nDSAPI Unix Authentication filter initialized \ n”);
return kFilterHandledEvent;
}}
/ * ---
*过滤器终止
* /
unsigned int TerminateFilter(unsigned int reserved)
{
/ *
*说明:过滤器执行过滤器终止
*共享库已卸载。
*:
*输入:保留当前未使用(dsapi规范控制
*数据格式)
*输出:无
*:
*返回:kFilterHandledEvent
* /
/ *在这里插入任何全局清理代码... * /
printf(“\ nDSAPI Unix authentication filter unloaded \ n”);
return kFilterHandledEvent;
}}
/ * ...
*过滤器通知处理
* /
unsigned int HttpFilterProc(FilterContext * context,
unsigned int eventType,void * eventData)
{
/ *
*描述:对所有dsapi过滤器事件调用此例程。
*:
*输入:保留当前未使用(dsapi规范控制
*数据格式)
*输出:无
*:
*返回:kFilterNotHandled对于我们没有自定义的所有事件,
*否则允许我们的过滤器例程提供返回
*值。
* /
/ *只包括我们要处理的事件* /
switch(eventType){
case kFilterAuthUser:
return Authenticate(context,
(FilterAuthenticate *)eventData);
默认:
打破;
}}
return kFilterNotHandled;
}}
/ * ---
*处理用户身份验证
* /
unsigned int Authenticate(FilterContext * context,
FilterAuthenticate * authData)
{
/ *
*说明:此例程在dsapi kFilterAuthUser上调用
*事件。
*:
*输入:上下文dsapi规范控制数据的格式
* authData password字段包含要使用的密码
* authentication userName字段包含名称
*认证foundInCache字段为TRUE如果
*用户已在缓存中找到并可以
*在此基础上进行验证。
*:
*输出:authData authName字段填充用户的
*专有名称authType已填写
*与kNotAuthentic如果我们不能认证
* unix用户kAuthenticBasic如果我们可以
*验证unix用户。
*:
*返回:kFilterNotHandled如果我们不明白输入数据,
*或者如果用户已在缓存中找到,或
*如果我们发现要认证的用户是
* unix不知道。
* kFilterHandledEvent如果用户已知为unix。
* /
/ *如果用户在缓存中找到,那么我们不需要这样做
*任何进一步。
* /
if(!authData || authData-> foundInCache)
return kFilterNotHandled;
/ *尝试验证用户的密码。
* /
if(authData-> userName && authData-> password){
char * fullName = NULL;
int fullNameLen = 0;
char * shortName = NULL;
int shortNameLen = 0;
/ *在名称和地址簿中查找用户。 得到
*用户的短名称(我们期望的是unix
*用户名),并获取用户的全名(我们
*期望将以格式传回
* dsapi)。
* /
if(0 == getUserNames(context,
(char *)authData-> userName,
&全名,
&fullNameLen,
&简称,
&shortNameLen)){
int unixauth;
/ *执行unix身份验证。 的
* unixAuthenticate例程返回:-1 on
*错误,0成功,1如果用户不知道
*到unix。
* /
unixauth = unixAuthenticate(shortName,
(char *)authData-> password);
/ *如果用户不知道unix则返回* /
if(1 == unixauth){
printf(“\ n用户名不在UNIX系统中。\ n”)
return kFilterNotHandled;
}}
/ *复制此用户的规范名称
* dsapi要求。
* /
strncpy((char *)authData-> authName,fullName,
authData-> authNameSize);
/ *填写dsapi的authType返回信息
*要求。
* /
if(unixauth){
/ * unixauthenticate例程
*返回错误:我们不能
*使用输入验证
*密码。
* /
authData-> authType = kNotAuthentic;
} else {
/ *为了调试的目的,写入
* Domino控制台的身份验证
*输入密码成功。
*您可能希望删除此printf。
* /
printf(“DSAPI Filter authenticated%s as%s(unix user%s)\ n”,
(char *)authData-> userName,
authData-> authName,shortName);
authData-> authType = kAuthenticBasic;
}}
return kFilterHandledEvent;
}}
}}
return kFilterNotHandled;
}}
int getUserNames(FilterContext * context,
char * userName,
char ** pUserFullName,
int * pUserFullNameLen,
char ** pUserShortName,
int * pUserShortNameLen){
/ *
*说明:查找用户并返回用户的全名和
* 简称。
*:
*输入:我们将用于分配内存的上下文上下文
* userName要查找的用户的名称
*输出:pUserFullName用户全名的位置
* pUserFullNameLen存储全名的长度的位置
* pUserShortName用户短名称的位置
* pUserShortNameLen存放位置的长度
* 简称
*:
*返回:-1出错,成功0
* /
STATUS error = NOERROR;
HANDLE hLookup = NULLHANDLE;
WORD Matches = 0;
char * pLookup;
char * pName = NULL;
char * pMatch = NULL;
int rc = -1;
if(!userName ||!pUserFullName ||!pUserFullNameLen ||
!pUserShortName || !pUserShortNameLen)
return rc;
/ *初始化输出* /
* pUserFullName = NULL;
* pUserFullNameLen = 0;
* pUserShortName = NULL;
* pUserShortNameLen = 0;
/ *做名称查找
* /
error = NAMELookup(NULL,/ * NULL表示本地查找* /
0,/ * flags * /
1,/ *命名空间数* /
“$ Users”,/ * namespace list * /
1,/ *要查找的名称数* /
userName,/ *要查找的名称列表* /
2,/ *要返回的项目数* /
“FullName \ 0ShortName”,/ *项目列表
* return * /
&hLookup); / *接收句柄的地方
* return buffer * /
if(error ||(NULLHANDLE == hLookup))
goto NoUnlockExit;
pLookup =(char *)OSLockObject(hLookup);
/ *获取指向我们的条目的指针。
* /
pName =(char *)NAMELocateNextName(pLookup,/ * name lookup
* 缓冲 */
NULL,/ *从开头开始
*查找缓冲区* /
&火柴); / *接收号码
*的时间我们
*找到条目
*(应为1)
* /
/ *如果我们没有找到该条目,则退出* /
if((pName == NULL)||(Matches <= 0)){
goto退出;
}}
pMatch =(char *)NAMELocateNextMatch(pLookup,/ * name lookup
* 缓冲 */
pName,/ *我们找到的条目* /
空值); / *无上一个匹配* /
if(NULL == pMatch){
goto退出;
}}
/ *从我们回来的信息获取全名* /
if(getLookupInfo(context,
pMatch,
0,
pUserFullName,
pUserFullNameLen))
goto退出;
/ *从我们回来的信息获取短名称* /
if(getLookupInfo(context,
pMatch,
如图1所示,
pUserShortName,
pUserShortNameLen))
goto退出;
其他
/ *在所有事情上成功* /
rc = 0;
出口:
if(pLookup && hLookup)
OSUnlock(hLookup);
NoUnlockExit:
if(NULLHANDLE!= hLookup)
OSMemFree(hLookup);
return rc;
}}
int getLookupInfo(FilterContext * context,
char * pMatch,
int itemNumber,
char ** pInfo,
int * pInfoLen){
/ *
*说明:从查找缓冲区获取信息
*:
*输入:我们将用于分配内存的上下文上下文
* pMatch查找缓冲区的名称
* itemNumber其中信息存储在查找中
* 缓冲
*输出:信息缓冲区的pInfo位置
* pInfoLen位置来存储信息长度
*:
*返回:-1出错,成功0
* /
unsigned int reserved = 0;
unsigned int errID;
char * ValuePtr = NULL;
WORD ValueLength,DataType;
STATUS错误;
void * newSpace = NULL;
if(!pMatch ||!pInfo ||!pInfoLen ||(itemNumber <0))
return -1;
/ *初始化输出* /
* pInfo = NULL;
* pInfoLen = 0;
/ *检查信息的类型和长度* /
ValuePtr =(char *)NAMELocateItem(pMatch,/ *匹配我们
* found * /
itemNumber,/ * item#
* of item on lookup * /
&DataType,/ * return the datatype
*项目值* /
&ValueLength); / * rtn的大小
* value * /
if(NULL == ValuePtr || ValueLength == 0){
/ *没有信息* /
return -1;
}}
ValueLength - = sizeof(WORD); / *删除数据类型字
*在列表长度
* /
/ *检查值DataType * /
switch(DataType){
case TYPE_TEXT_LIST:
打破;
案例TYPE_TEXT:
打破;
默认:
return -1;
}}
/ *分配信息的空间。 这个内存将被释放
*当线程终止时自动。
* /
newSpace =(context-> AllocMem)(context,ValueLength + 1,
保留,&errID);
* pInfo =(char *)newSpace;
if(NULL == * pInfo){
printf(“Out of memory \ n”);
return -1;
}}
/ *获取信息* /
error = NAMEGetTextItem(pMatch,/ *匹配,我们发现* /
itemNumber,/ * item#按项目顺序
*查找* /
0,/ *成员#文本中的项目
*列表* /
* pInfo,/ *缓冲区复制结果
* into * /
ValueLength + 1); / *缓冲区长度* /
if(!error){
* pInfoLen = ValueLength +1;
return 0;
}}
return -1;
}}
int unixAuthenticate(char * userName,char * password){
/ *
*说明:查看用户是否知道unix,如果是,请检查
*密码可以验证。
*:
*输入:userName unix用户名
*密码unix密码
*:
*返回:-1出错,0成功,1如果用户不知道unix
* /
char缓冲区[1024];
int error = -1;
int success = 0;
int unknown = 1;
#ifdef AIX
struct passwd * result;
#万一
#ifdef HPUX
struct passwd pwd;
size_t buflen = sizeof(buffer);
struct passwd * result;
int err;
#万一
printf(“\ nUserName =%s \ n”,* userName);
if(!userName)
{
printf(“\ nUserName =%s \ n”,* userName);
返回错误;
}}
/ *获取此用户的unix记录* /
#ifdef AIX
result = getpwnam(userName);
if(result && result-> pw_passwd){
/ *加密密码,看看它是否匹配
*来自用户记录的加密密码。
* /
char * thisCrypt = NULL;
thisCrypt =(char *)crypt(password,
result-> pw_passwd);
if(strcmp(result-> pw_passwd,thisCrypt)== 0){
返回成功;
} else {
返回错误;
}}
}}
#万一
#ifdef HPUX
err = getpwnam_r(userName,&pwd,buffer,buflen,&result);
if(0 == err){
/ *加密密码,看看它是否匹配
*来自用户记录的加密密码。
* /
if(strcmp(result-> pw_passwd,
crypt(password,result-> pw_passwd))== 0){
返回成功;
} else {
返回错误;
}}
}}
#万一
返回未知;
}}
/ * ----- end of dsapifilter.c * /
Domino Web服务器应用程序编程接口(DSAPI)是一个C API,它允许您将自己的扩展编写到Domino Web服务器。 在处理http请求期间发生特定事件时,通知DSAPI扩展或过滤器。
DSAPI筛选器允许您在发生特定事件时自定义http请求的处理。 http堆栈通知事件的过滤器。 DSAPI过滤器当前可以捕获13个事件。 根据设计及其实现,过滤器可以支持一个或任意数量的事件。
DSAPI接口的实现依赖于过滤器来指示它支持哪些事件。 过滤器然后只接收它声称支持的事件的通知。
请参考任何本文件中提到的筛选数据结构的详细信息,IBM C API参考 。
入门
DSAPI过滤器必须指定两个入口点:
- 初始化
- 事件通知
可选条目点可以为过滤器终止来限定。 此外,可以为线程初始化和终止定义可选的入口点。
初始化
当加载过滤器时,Domino调用Initialization函数。 当Domino HTTP服务器任务启动时或使用Domino控制台命令“tell http restart”重新启动HTTP任务时,将加载过滤器。 初始化函数的原型是:
/ * ---
*过滤器初始化
* /
unsigned int FilterInit(FilterInitData * pFilterInitData);
初始化函数的名称必须为FilterInit,DSAPI图层才能在加载过滤器时找到它。
请参考上FilterInitData结构的进一步信息,IBM C API参考 。
事件通知
事件通知功能负责过滤器的实际工作。 Domino在处理http请求期间发生特定事件时调用事件通知函数。 当Domino调用过滤器的事件通知函数时,它传递有关请求和正在处理的事件的信息。 在每次调用时,过滤器可以决定处理事件,有或没有错误返回,或拒绝处理事件。 事件通知功能的原型是:
/ * ---
*过滤器通知处理
* /
unsigned int HttpFilterProc(FilterContext * pContext,unsigned int eventType,void * pEventData);
事件处理函数的名称必须是HttpFilterProc,以便DSAPI图层在加载过滤器时找到它。
pContext是一个指针FilterContext包含有关该http请求,服务器回调函数指针,和一个指针到过滤器自身的数据的上下文信息。 请参考上FilterContext结构的进一步信息,IBM C API参考 。
EVENTTYPE指示哪个事件正在发生。
pEventData是指向与事件相关联的结构。 每个事件都有不同的事件数据结构。 有关详情,请参阅下面的事件部分。
可选线程初始化和终止
过滤器还可以定义用于线程的初始化和终止的入口点。 http栈将在调用初始化函数FilterInit之后调用函数HttpFilterThreadInit。 HttpFilterThreadInit主要用于初始化任何线程局部变量。 过滤器线程初始化函数的原型是:
unsigned int HttpFilterThreadInit(int threadType);
过滤器线程初始化函数需要过滤器线程终止函数。 当库被卸载时,将调用此函数,以允许过滤器释放由过滤器线程初始化函数分配的任何资源。 过滤器线程终止功能的原型是:
unsigned int HttpFilterThreadTerm(int threadType);
选择终止
过滤器还可以定义终止入口点。 Domino将在过滤器即将卸载时调用此函数 - 当http堆栈进程正在关闭时。 过滤器可以使用此函数来清理它分配的资源。 过滤器必须在调用其初始化例程时释放它分配的所有全局资源。 过滤器终止功能的原型是:
/ * ---
*过滤器终止
* /
unsigned int TerminateFilter(unsigned int reserved);
所有导出的函数都返回一个unsigned int状态代码。 状态代码的可能值如下:
- kFilterHandledRequest表示http请求已完全处理。 响应已经发送到客户端,并且http栈必须终止请求的处理。
- kFilterHandledEvent表示事件已经被处理,但进行进一步处理以完全服务于http请求。
- kFilterNotHandled信号表明过滤器未处理事件。
- kFilterError表示过滤器在处理事件时遇到错误。 在这种情况下,http堆栈将停止处理请求,并向用户发送适当的错误响应。
注意,对于函数FilterInit,HttpFilterThreadInit,HttpFilterThreadTerm和TerminateFilter,唯一可能的返回码是kFilterHandledEvent和kFilterError。 函数HttpFilterProc可以在处理事件时返回任何状态代码。
事件
事件按特定顺序发生。 它们反映了http堆栈在每个处理步骤的状态。 事件通知可以被视为过滤器覆盖给定处理步骤的默认实现的机会。 对于每个事件,包含附加信息和在大多数情况下附加的回调函数的结构被传递到过滤器的事件通知处理例程。 过滤器可以调用回调函数以获取其他信息或执行服务。 仅对过滤器注册的那些事件(在过滤器加载和初始化时在FilterInitData结构中传递的那些事件)调用事件通知例程。 事件在其发生的顺序中描述如下。
kFilterStartRequest事件
此事件用于向当前加载的所有过滤器通知已收到http请求,并且将要处理。 在此步骤中,过滤器可以准备处理请求。 通常在此步骤中,过滤器应分配其自己的私有上下文数据,以及处理请求处理所需的必要资源。 不使用参数pEventData,并传递NULL。 支持此事件的任何过滤器都应返回值kFilterHandledEvent。
kFilterRawRequest事件
将通知当前加载并支持此事件的所有过滤器,所有输入的HTTP头都已读入。任何需要预处理输入头的过滤器都可以这样做。 请注意,过滤器可以选择此时完全服务http请求。 参数pEventData是一个指向FilterRawRequest结构的指针。 结构FilterRawRequest如下所述:
- typedef struct {
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,
unsigned int * pErrID);
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
int(* SetHeader)(FilterContext * pContext,
char * pName,
char * pValue,
unsigned int * pErrID);
int(* AddHeader)(FilterContext * pContext,
char * pHheader,
unsigned int * pErrID);
unsigned int reserved;
} FilterRawRequest;
requestMethod:是请求方法。 它可以是以下之一:- ·kRequestNone:没有提供HTTP请求方法。
·kRequestHEAD:方法通常用于测试超文本链接的有效性,可访问性和最近的修改。
·kRequestGET:GET方法 - 用于检索Request-URL标识的任何信息(以实体的形式)。
·kRequestPOST:POST方法 - 请求原始服务器接受请求中包含的实体作为请求行中的Request-URL所标识的资源的新从属。
·kRequestPUT:PUT方法 - 请求将所包含的实体存储在提供的Request-URL下。
·kRequestDELETE:DELETE方法 - 请求源服务器删除由Request-URL标识的资源。
·kRequestTRACE:TRACE方法。
·kRequestCONNECT:CONNECT方法。
·kRequestOPTIONS:OPTIONS方法。
·kRequestUNKNOWN:未知请求方法。
·kRequestBAD:请求方法不正确。 错误。
char ** ppHeaders,
unsigned int * pErrID);- 此回调函数允许过滤器访问输入http标头。
返回包含http标头的缓冲区的字节计数。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识与之相关的请求。
ppHeaders是一个指向位置的指针,DSAPI层将存储指向包含输入http头的缓冲区的指针。 http头的格式如下:“<header1> <\ r \ n> <header2> <\ r \ n> .... <headern> <\ r \ n> <\ r \ n>”。
pErrID是指向无符号整数的指针,如果成功则设置为0,否则设置为错误代码。 可能的错误代码是:DSAPI_INVALID_ARGUMENT,DSAPI_MEMORY_ERROR和DSAPI_INTERNAL_ERROR。
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);- 此回调函数检索单个http标头值。
提供了http头名称。
如果http头不存在,则在提供的缓冲区中返回一个空字符串。
对于硬故障(传递的错误参数)返回0,如果成功则包含结果的缓冲区中有效的字节数,或者如果缓冲区太小以至于不包含结果,则返回所需的缓冲区大小。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pName是指向包含所需http标头名称的字符串的指针。 这不能是NULL或空字符串。
pBuffer是指向缓冲区的指针,用于存储结果。 此参数不能为NULL。
bufferSize是提供的缓冲区的大小。
pErrID是指向无符号整数的指针,如果成功则设置为0,如果提供的缓冲区太小,不能包含结果,则为DSAPI_BUFFER_TOO_SMALL,传递的无效参数为DSAPI_INVALID_ARGUMENT。
char * pName,
char * pValue,
unsigned int * pErrID);- 此回调函数允许过滤器更改现有输入http标头的值。
请注意,如果http头不存在,它将添加到输入头的列表中。
成功返回TRUE,否则返回FALSE。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识与之相关的请求。
pName是指向包含要更改的http标头的名称的字符串的指针。 此参数不能为NULL或空字符串。
pValue是一个指向包含http头的值的字符串的指针。
pErrID是指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。
int(* AddHeader)(FilterContext * pContext,
char * pHheader,
unsigned int * pErrID);- 此回调函数允许过滤器将http标头添加到输入http标头的列表中。
请注意,如果http头已存在,则其值将更改为反映新值。
如果成功返回TRUE,否则返回FALSE。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pHeader是指向有效http标头的指针。 预期的格式相同输入HTTP标头的格式,即<headerName:值>。
pErrID 是指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。 在这种情况下,唯一有效的非零状态是DSAPI_INVALID_ARGUMENT,表示检测到所提供头的格式错误。
保留的是为将来使用保留。
- ·kRequestNone:没有提供HTTP请求方法。
当http堆栈已经完成预解析所有http输入头时,使用此事件通知当前加载并支持此事件的所有过滤器。 注意,这反映了与事件kFilterRawRequest中相同的状态,因为http堆栈在开始调用任何过滤器之前预解析http输入头。 任何过滤器都可以选择在此步骤完全处理请求。 pEventData是一个指向结构FilterParsedRequest的指针。 注意,只提供了两个回调函数。 您只能在此步骤中访问http输入标头。 使用kFilterRawRequest,您也有机会更改它们。
- ŧypedef结构{
unsigned int requestMethod;
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,- unsigned int * pErrID);
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
unsigned int reserved;
} FilterParsedRequest;
requestMethod: 是请求方法。 它可以是以下之一:- ·kRequestNone:没有提供HTTP请求方法。
·kRequestHEAD:方法通常用于测试超文本链接的有效性,可访问性和最近的修改。
·kRequestGET:GET方法 - 用于检索Request-URL标识的任何信息(以实体的形式)。
·kRequestPOST:POST方法 - 请求原始服务器接受请求中包含的实体作为请求行中的Request-URL所标识的资源的新从属。
·kRequestPUT:PUT方法 - 请求将所包含的实体存储在提供的Request-URL下。
·kRequestDELETE:DELETE方法 - 请求源服务器删除由Request-URL标识的资源。
·kRequestTRACE:TRACE方法。
·kRequestCONNECT:CONNECT方法。
·kRequestOPTIONS:OPTIONS方法。
·kRequestUNKNOWN:未知请求方法。
·kRequestBAD:请求方法不正确。 错误。
char ** ppHeaders,
unsigned int * pErrID);- 此回调函数允许过滤器访问输入http标头。
返回包含http输入头的缓冲区的字节计数。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
ppHeaders是一个指向位置的指针,DSAPI层将存储指向包含输入http头的缓冲区的指针。 http头的格式如下:“<header1> <\ r \ n> <header2> <\ r \ n> .... <headern> <\ r \ n> <\ r \ n>”。
pErrID是指向无符号整数的指针,如果成功则设置为0,否则设置为错误代码。 可能的错误代码是:DSAPI_INVALID_ARGUMENT,DSAPI_MEMORY_ERROR和DSAPI_INTERNAL_ERROR。
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);- 此回调函数检索单个http标头值。
提供了http头名称。
如果http头不存在,则在提供的缓冲区中返回一个空字符串。
对于硬故障(传递的错误参数)返回0,如果成功则包含结果的缓冲区中有效的字节数,或者如果缓冲区太小以至于不包含结果,则返回所需的缓冲区大小。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pName是指向包含所需http标头名称的字符串的指针。 这不能是NULL或空字符串。
pBuffer是指向缓冲区的指针,用于存储结果。 此参数不能为NULL。
bufferSize是提供的缓冲区的大小。
pErrID是指向无符号整数的指针,如果成功则设置为0,如果提供的缓冲区太小,不能包含结果,则为DSAPI_BUFFER_TOO_SMALL,传递的无效参数为DSAPI_INVALID_ARGUMENT。
- unsigned int * pErrID);
- ŧypedef结构{
当前加载并支持此事件的所有过滤器都有机会更改URL,将请求重定向到其他资源。 如果过滤器成功重写要处理的URL,并且服务器处理新的URL,则DSAPI层停止处理此事件,即,不通知列表中的其他过滤器。 pEventData是指向该结构,FilterMapURL的一个实例。 注意,结构FilterMapURL也用于事件,kFilterTranslateRequest和kFilterPostTranslate。
- typedef struct {
const char * url;
char * pathBuffer;
unsigned int bufferSize;
unsigned int mapType;
} FilterMapURL;
网址:输入参数。 它是一个指向字符串的指针,其值是正在处理的当前URL。
pathBuffer: 输出参数。 它是指向要存储新URL的提供的缓冲区的指针。
BUFFERSIZE:输入参数。 这是要在其中存储新URL的提供的缓冲区的大小。
地图类型:输出参数。 在这种情况下不使用。
- typedef struct {
kFilterAuthenticate事件
当http堆栈处于进程的身份验证阶段时,会发生此事件。 过滤器代码可以查看请求和用户凭证,为http堆栈验证用户,或完全处理请求。 pEventData是指向结构实例的指针。
- typedef struct {
LMBCS * userName;
LMBCS *密码;
unsigned char * clientCert;
unsigned int clientCertLen;
unsigned int authFlags;
unsigned int preAuthenticated;
unsigned int foundInCache;
unsigned int authNameSize;
LMBCS * authName;
unsigned int authType;
int(* GetUserNameList)(FilterContext * pContext,- LMBCS * pBuffer,
unsigned int * pNumNames,
unsigned int reserved,
unsigned int * pErrID);
int(* GetHeader)(FilterContext * pContext,
- typedef struct {
- char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
- char * pBuffer,
void(* GetMappedResource)(FilterContext * pContext,
char ** ppBuffer,
unsigned int * pErrID);
- } FilterAuthenticate;
用户名:输入参数。 来自输入请求的用户的网络名称。 如果没有可用的话,它被设置为NULL。
密码: 输入参数。 来自输入请求的用户的Web密码。 如果没有可用的话,它被设置为NULL。
clientCert: 输入参数。 SSL客户端认证。 如果没有可用的话,它被设置为NULL。
clientCertLen:输入参数。 SSL客户端证书的长度。 它设置为零在没有可用。
authFlags: 输入参数。 为服务器启用的身份验证选项。 它可以是以下的一个或多个“OR”:
- ·kAuthAllowBasic:服务器通过提供用户名和密码允许基本认证。
·kAuthAllowAnonymous:服务器允许匿名访问公共(非保护)文档。
·kAuthAllowSSLCert:服务器允许使用SSL客户端证书进行SSL认证。
·kAuthAllowSSLBasic:
·kAuthAllowSSLAnonymous:服务器允许对公共(非保护)文档进行匿名SSL身份验证。
·kAuthRedirectToSSL:对于受SSL保护的文档,服务器允许重定向到SSL身份验证。
foundInCache:输入参数。 如果用户已在Domino的内部缓存中缓存,并且将在此基础上进行身份验证,则将其设置为TRUE,除非过滤器处理事件。 此成员允许过滤器不重新验证已验证的用户。 过滤器在这种情况下应立即返回kFilterNotHandled。
authNameSize:输入参数。 这是存储已验证用户名的缓冲区大小。
AUTHNAME:输入参数。 它是指向提供的缓冲区的指针,其中必须存储经过身份验证的用户名(规范名称)。
的authType:输出参数。 过滤器(如果它处理事件)必须将此字段设置为由以下值之一描述的授权类型:
- ·kNotAuthentic:用户的凭据认证失败。
http堆栈必须终止请求的处理。
·kAuthenticBasic:用户名和密码已通过身份验证。 认证阶段应该终止,并且请求处理中的下一阶段开始。
·kAuthenticClientCert:使用SSL客户端证书的SSL认证成功。 认证阶段应该终止,并且请求处理中的下一阶段开始。
LMBCS * pBuffer,
unsigned int bufferSize,- unsigned int * pNumNames,
unsigned int * pErrID);- 此回调函数允许过滤器访问用户的组列表。
返回在返回缓冲区中有效的字节数,如果缓冲区太小(缓冲区仍然填充到结束),返回-1。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识与之相关的请求。
pBuffer是指向内存缓冲区的指针,在计算完毕后,返回用户的组列表。 格式是一系列零终止字符串,即“<group1 \ 0group2 \ 0 ... groupn \ 0”。
bufferSize是pBuffer指向的内存块的大小。
pNumNames是一个指针,用于存储用户组名列表中包含的名称数。
保留用于将来使用。 它应该设置为0。
pErrID 是指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。 在这种情况下,唯一有效的非零状态是DSAPI_INVALID_ARGUMENT,表示一个或多个提供的参数无效。
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);- 此回调函数检索单个http标头值。
提供了http头名称。
如果http头不存在,则在提供的缓冲区中返回一个空字符串。
对于硬故障(传递的错误参数)返回0,如果成功则包含结果的缓冲区中有效的字节数,或者如果缓冲区太小而不包含结果,则返回所需的缓冲区大小。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pName 是指向包含所需http标头名称的字符串的指针。 这不能是NULL或空字符串。
pBuffer是指向缓冲区的指针,用于存储结果。 此参数不能为NULL。
bufferSize是提供的缓冲区的大小。
pErrID是指向无符号整数的指针,如果成功则设置为0,如果提供的缓冲区太小,不能包含结果,则为DSAPI_BUFFER_TOO_SMALL,传递的无效参数为DSAPI_INVALID_ARGUMENT。
char ** ppBuffer,
unsigned int * pErrID);- GetMappedResource回调函数检索映射资源值。
对于硬故障(传递的错误参数)返回0,如果成功则包含结果的缓冲区中有效的字节数,或者如果缓冲区太小以致不包含结果,则返回所需的缓冲区大小。
pContext - 指向结构FilterContext的指针,并包含DSAPI层实现所需的所有上下文数据,以识别与之相关的请求。
ppBuffer - 指向缓冲区指针的指针,用于存储结果。 此参数不能为NULL。
pErrID - 指向无符号整数的指针,如果成功,设置为0,如果提供的缓冲区太小,不能包含结果,则设置为DSAPI_BUFFER_TOO_SMALL。
- ·kAuthAllowBasic:服务器通过提供用户名和密码允许基本认证。
- } FilterAuthenticate;
kFilterUserNameList事件
当http堆栈即将生成用户的组名称列表时,会发生此事件。 这些是用户所属的组名称。 此事件跟随kFilterAuthenticate事件。 过滤器可以使Domino服务器填充列表,向列表添加或删除组或完全处理事件(完全生成组列表本身)。 函数中的参数HttpEventProc,pEventData是指向结构FilterUserNameList的指针。
- typedef struct {
const LMBCS * userName;
int(* GetUserNameList)(FilterContext * pContext,
LMBCS * pBuffer,
unsigned int bufferSize,
unsigned int * pNumNames,
unsigned int保留,
unsigned int * pErrID);
int(* PopulateUserNameList)(FilterContext * pContext,
LMBCS * pBuffer,
unsigned int bufferSize,
unsigned int * pNumNames,
unsigned int reserved,
unsigned int * pErrID);
int(* AddGroupsToList)(FilterContext * pCcontext,
LMBCS * pGroupNames,
无符号int numGroupNames,
unsigned int reserved,
unsigned int * pErrID);
int(* RemoveGroupsFromList)(FilterContext * pContext,
unsigned int reserved,
unsigned int * pErrID);
unsigned int reserved;
} FilterUserNameList;
用户名:验证的用户名。
int(* GetUserNameList)(FilterContext * pContext,
LMBCS * pBuffer,
unsigned int bufferSize,
unsigned int * pNumNames,
unsigned int reserved,
unsigned int * pErrID);- 此回调函数允许过滤器访问用户的组列表。
返回在提供的缓冲区中有效的字节数,(-1)如果缓冲区太小(尽管缓冲区填充到结束)。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pBuffer是指向内存缓冲区的指针,在计算完毕后,返回用户的组列表。 格式是零终止字符串的序列,即“<group1 \ 0group2 \ n ... groupn \ 0>”。
bufferSize是pBuffer指向的内存块的大小。
pNumNames是一个指针,用于存储用户组列表中包含的名称数。
保留用于将来使用。 它应该设置为0。
pErrID是指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。 在这种情况下,唯一有效的非零状态是DSAPI_INVALID_ARGUMENT,表示一个或多个提供的参数无效。
int(* PopulateUserNameList)(FilterContext * pContext,
LMBCS * pBuffer,
unsigned int bufferSize,
unsigned int * pNumNames,
unsigned int reserved,
unsigned int * pErrID);- 此回调函数允许过滤器请求计算用户的组列表,并在提供的缓冲区中返回。
返回的pbuffer返回有效的字节数。
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pBuffer是指向内存缓冲区的指针,在计算完毕后,返回用户的组列表。
bufferSize是pBuffer指向的内存块的大小。
pNumNames是一个指针,用于存储用户组列表中包含的名称数。
保留用于将来使用。 它应该设置为0。
pErrID是指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。
int(* AddGroupsToList)(FilterContext * pCcontext,
LMBCS * pGroupNames,
unsigned int numGroupNames,
unsigned int reserved,
unsigned int * pErrID);- 此回调函数允许过滤器动态扩充用户的组。
成功返回TRUE,否则返回FALSE
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识其所属的请求。
pBuffer是一个指向缓冲区的指针,它包含要添加到用户组列表的名称。 格式是一个字符串列表每一个都包含一个组的名称,即,<字符串1字符串2 ... stringn>。 这里的字符串被定义为C字符串,即,以NULL结束的字节序列。
numGroupName是包含在pbuffer的组名的数量。
保留用于将来使用。 它应该设置为0。
pErrID 指向无符号整数的指针,用于存储状态代码。 如果操作成功,则将状态码设置为0,否则设置为非零值。 在这种情况下,它始终设置为0。
int(* RemoveGroupsFromList)(FilterContext * pContext,
unsigned int reserved,
unsigned int * pErrID);- 此回调允许过滤器清除用户的组列表。
结果是一个仅包含用户已知名称的组列表。
返回TRUE
pContext是指向结构FilterContext的指针,并且包含DSAPI层实现所需的所有上下文数据,以标识与之相关的请求。
保留保留,应始终设置为0。
pErrID是指向无符号整数的指针,用于存储状态代码。 状态代码始终设置为0。
保留:保留用于将来使用。
- 此回调函数允许过滤器访问用户的组列表。
- typedef struct {
kFilterTranslateRequest事件
当http堆栈要将路径URL转换为目标资源时,会发生此事件。 过滤器可以使用自己的翻译和映射规则翻译请求,或完全处理请求。 pEventData指向的结构中,FilterMapURL的一个实例。 结构FilterMapURL如下所述:
- typedef struct {
const char * url;
char * pathBuffer;
unsigned int bufferSize;
unsigned int mapType;
} FilterMapURL;
网址:输入参数。 它是一个指向字符串的指针,其值是正在处理的当前URL。
pathBuffer:输出参数。 它是指向所提供的缓冲区的指针,其中存储所得到的目标资源路径。
BUFFERSIZE:输入参数。 这是要在其中存储目标资源路径的提供的缓冲区的大小。
地图类型:输出参数。 它是以下之一:
- typedef struct {
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
- ·kURLMapUnknown:未知的映射类型。
·kURLMapPass:文件系统映射规则
·kURLMapExec:CGI映射规则
·kURLMapRedirect:重定向映射规则
·kURLMapService:Obsolete。 不再使用。
·kURLMapDomino:Domino映射规则
- ·kURLMapUnknown:未知的映射类型。
kFilterPostTranslate事件
此事件在事件kFilterTranslateEvent已处理之后发生。 这是过滤器更改要访问的目标资源的机会。 过滤器可以更改目标资源路径和映射类型。 过滤器还可以选择完全服务请求。 pEventData是一个指向结构FilterMapURL的指针。 结构FilterMapURL如下所述:
- typedef struct {
const char * url;
char * pathBuffer;
unsigned int bufferSize;
unsigned int mapType;
} FilterMapURL;
网址:输入参数。 它是一个指向字符串的指针,其值是正在处理的当前URL。
pathBuffer:输入/输出参数。 它是指向包含已计算的目标资源路径的已提供缓冲区的指针。 新的目标资源路径将被存储在该缓冲器中。
BUFFERSIZE:输入参数。 这是要在其中存储目标资源路径的提供的缓冲区的大小。
地图类型:输入/输出参数。 它是以下之一:
- typedef struct {
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
- ·kURLMapUnknown:未知的映射类型。
·kURLMapPass:文件系统映射规则
·kURLMapExec:CGI映射规则
·kURLMapRedirect:重定向映射规则
·kURLMapService:Obsolete。 不再使用。
·kURLMapDomino:Domino映射规则
- ·kURLMapUnknown:未知的映射类型。
此事件发生在认证阶段发生之后,并且已经计算了用户的组名称列表。 过滤器可以覆盖授权阶段的默认实现,并授予或拒绝对目标资源的访问。 pEventData是一个指向结构体FilterAuthorize的指针。 它包含有关要提供的目标资源的信息。 请注意,过滤器可以通过使用带有标志kGetAuthenticatedUserInfo的ServerSupport回调的服务来访问经过身份验证的用户信息。 这将允许用户访问用户的已认证的名称以及他/她的组名称列表。
如果过滤器拒绝访问目标资源,则它必须向客户端发送适当的响应,并将FilterAuthorize结构中的字段isAuthorized设置为0.然后它可以返回kFilterHandledRequest或kFilterHandledEvent。 然后,DSAPI层将发信号通知http栈以终止当前请求的处理。
结构FilterAuthorize如下所述:
- typedef struct _FilterAuthorize {
const char * pURL;
char * pBuffer;
unsigned int bufferSize;
unsigned int mapType;
unsigned int isAuthorized;
} FilterAuthorize;
的pURL:输入参数。 它是http请求URL。
pBuffer: 输入参数。 此缓冲区包含目标资源的路径。
bufferSize: 输入参数。 这是提供的缓冲区的总大小(以字节为单位)。
地图类型:输入参数。 它是以下之一:- ·typedef枚举{
- typedef struct _FilterAuthorize {
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
- ·kURLMapUnknown:未知的映射类型。
·kURLMapPass:文件系统映射规则
·kURLMapExec:CGI映射规则
·kURLMapRedirect:重定向映射规则
·kURLMapService:Obsolete。 不再使用。
·kURLMapDomino:Domino映射规则
- ·kURLMapUnknown:未知的映射类型。
kFilterProcessRequest事件
这是服务http请求的最后一步。 这个事件可以用来覆盖默认实现的请求处理。 在该阶段中,响应数据被计算并发送到客户端。 pEventData是一个指向结构FilterMapURL的指针。 结构FilterMapURL如下所述:
- typedef struct {
const char * url;
char * pathBuffer;
unsigned int bufferSize;
unsigned int mapType;
} FilterMapURL;
网址:输入参数。 它是一个指向字符串的指针,其值是正在处理的当前URL。
pathBuffer:输入参数。 它是指向包含已计算的目标资源路径的已提供缓冲区的指针。
BUFFERSIZE:输入参数。 这是要在其中存储目标资源路径的提供的缓冲区的大小。
地图类型:输入参数。 它是以下之一:
- typedef struct {
kURLMapUnknown = 0,
kURLMapPass = 1,
kURLMapExec = 2,
kURLMapRedirect = 3,
kURLMapService = 4,
kURLMapDomino = 5
} FilterURLMapTypes;
哪里
- ·kURLMapUnknown:未知的映射类型。
·kURLMapPass:文件系统映射规则
·kURLMapExec:CGI映射规则
·kURLMapRedirect:重定向映射规则
·kURLMapService:Obsolete。 不再使用。
·kURLMapDomino:Domino映射规则
- ·kURLMapUnknown:未知的映射类型。
此事件用于建议过滤器代码,它是时候清理和释放分配的资源以处理给定的http请求。 在这种情况下,pEventData为NULL。
kFilterAuthUser事件
此事件替换为kFilterAuthenticate事件,但仍支持与以前写入的DSAPI过滤器的兼容性。 在这种情况下,过滤器验证Web用户。 pEventData是结构的一个实例FilterAuthenticate。 在上述kFilterAuthenticate事件中完全描述了该结构。
此事件允许您自定义Web用户的身份验证,这通常是在公司内实施“单点登录”的一部分。 在这种情况下,当Domino验证用户时通知DSAPI过滤器。 然后,DSAPI筛选器可以解析用户名,根据传统大型机系统验证用户名和密码,如果成功,请通知Domino Web服务器它已处理用户的身份验证,并将用户的凭据返回Domino。
这是一个指南,用于设置常用认证方案的输出变量和返回代码,其中eventData指向FilterAuthenticate结构:
- 方案1:该过滤器能够对用户进行认证。
将eventData-> authName设置为规范名称,将eventData-> authType设置为kAuthenticBasic或kAuthenticClientCert,并将返回码设置为kFilterHandledEvent。
- 方案2:过滤器无法对用户进行认证,以及其他过滤器或Domino应该继续并尝试自己的身份验证。
将返回代码设置为kFilterNotHandled。
- 场景3:过滤器无法给用户,以及其他过滤认证或Domino不应试图自己的身份验证。
将eventData-> authType设置为kNotAuthentic,并将返回码设置为kFilterHandledEvent。
当http堆栈要向客户端发送http响应头时,会发生此事件。 这给了过滤器改变发送到客户端的响应的机会。 这在当前版本的DSAPI中未完全实现。 pEventData是一个指向结构FilterResponse的一个实例,下面描述:
typedef struct {
unsigned int responseCode;
char * reasonText;
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,
unsigned int * pErrID);
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
int(* SetHeader)(FilterContext * pContext,
char * pName,
char * pValue,
unsigned int * pErrID);
int(* AddHeader)(FilterContext * pContext,
char * pHeader,
unsigned int * pErrID);
unsigned int reserved;
char * userName;
} FilterResponse;
responseCode -输入参数。 它是HTTP响应状态代码。
reasonText -输入参数。 它是HTTP响应状态文本(如果有)。
int(* GetAllHeaders)(FilterContext * pContext,
char ** ppHeaders,
unsigned int * pErrID);
此回调函数允许过滤器访问响应http头。
返回包含http响应头的缓冲区的字节计数。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
ppHeaders - 是一个指向位置的指针,DSAPI层将存储指向包含响应http头的缓冲区的指针。
pErrID - 是指向无符号整数的指针,如果成功,则设置为0,否则设置为错误代码。 可能的错误代码是:DSAPI_INVALID_ARGUMENT,DSAPI_MEMORY_ERROR和DSAPI_INTERNAL_ERROR。
int(* GetHeader)(FilterContext * pContext,
char * pName,
char * pBuffer,
unsigned int bufferSize,
unsigned int * pErrID);
此回调函数检索单个http响应头值。 提供了http头名称。 如果http头不存在,则在提供的缓冲区中返回一个空字符串。
对于硬故障(传递的错误参数)返回0,如果successfull,则包含结果的缓冲区中的有效字节数,如果缓冲区太小而不包含结果,则返回所需的缓冲区大小。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pName - 是指向包含所需http标头名称的字符串的指针。 这不能等于NULL也不能为空字符串。
pBuffer - 是指向缓冲区的指针,用于存储结果。 此参数不能为NULL。
bufferSize - 是提供的缓冲区的大小。
pErrID - 是指向无符号整数的指针,如果successfull,则设置为0,如果提供的缓冲区太小,不能包含结果,则指向DSAPI_BUFFER_TOO_SMALL。
int(* SetHeader)(FilterContext * pContext,
char * pName,
char * pValue,
unsigned int * pErrID);
此回调函数允许过滤器更改现有响应http标头的值。 注意,如果http头不存在,它被添加到http响应头的列表。
如果successfull,返回TRUE,否则返回FALSE。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pName - 是指向包含要更改的http标头的名称的字符串的指针。 此参数不能为NULL或空字符串。
pValue - 是一个指向包含http头的值的字符串的指针。
pErrID - 指向无符号整数的指针,用于存储状态代码。 如果操作成功,状态码设置为0,否则设置为非零值。
int(* AddHeader)(FilterContext * pContext,
char * pHheader,
unsigned int * pErrID);
此回调函数允许过滤器将http标头添加到响应http标头的列表中。 请注意,如果http头已存在,则其值将更改为反映新值。
如果成功,返回TRUE,否则返回FALSE。
pContext -是一个指向结构FilterContext并包含所有由DSAPI层执行,以确定哪个请求此涉及所需要的上下文数据。
pHeader - 是指向有效http标头的指针。 预期的格式是一样的响应HTTP头的格式,即<headerName:值>。
pErrID - 指向无符号整数的指针,用于存储状态代码。 如果操作成功,状态码设置为0,否则设置为非零值。 在这种情况下,唯一的非零值是DSAPI_INVALID_ARGUMENT,表示检测到所提供头的格式错误。
保留 - 留作将来使用。
kFilterRawWrite事件
当http堆栈要向客户端发送http响应数据时,会发生此事件。 这给了过滤器改变发送到客户端的响应数据的机会。 这在当前版本的DSAPI中未完全实现。 pEventData是一个指向结构FilterRawWrite的一个实例,下面描述:
- typedef struct {
char * content;
unsigned int contentLen;
unsigned int reserved;
} FilterRawWrite;
- typedef struct {
contentLen -输入/输出参数。 它是输入上提供的缓冲区中的有效字节数,和/或输出上缓冲区中的有效字节数。
保留-留作将来使用。
运行和编程注意事项
- DSAPI过滤器构建为UNIX下的共享库和Win32下的DLL。 所有Domino服务器平台都支持DSAPI。 编译和链接共享库的细节因平台而异。 请参考第3章,平台具体情况,对建筑应用的进一步信息在特定的平台。
- 由于过滤器是用C编写的,您可以使用Notes C API访问Domino数据或其他C接口来访问其他系统。
- DSAPI筛选器是服务器扩展,当通过C API访问Domino数据库时,筛选器具有服务器ID的权限。
- 由于可以从不同的服务器线程同时调用过滤器通知函数,所以所有过滤器代码必须是线程安全的。 当Domino服务器线程接收到HTTP请求时,它将分配一个FilterContext结构的新实例。 当线程处理请求时,它将该实例传递给它调用的所有过滤器函数。FilterContext包含一个指针privateContext,您可以使用它来存储您自己的数据结构。 过滤器需要从事件到事件维护的所有线程特定的数据应该存储在privateContext结构中。
- 您应该使用AllocMem回调函数在过滤器中分配动态内存。 当服务器线程完成处理请求时,AllocMem分配的所有内存将自动释放。 这简化了您的过滤器清理,并确保内存释放,即使线程异常终止。
- 通过在“服务器”记录中指定过滤器的名称,在Internet协议 - > HTTP表中的字段DSAPI过滤器文件名中安装过滤器。 如果过滤器文件位于Domino程序或数据目录中,则只能指定过滤器文件的名称; 否则必须指定完全限定路径名。 确保所有过滤器文件通过足够的文件权限和物理安全保护,以防止未经授权的人篡改过滤器。
DSAPI示例代码
此示例的目的是显示如何扩展Domino Web服务器以启用Unix密码检查。 当通过Web浏览器访问Domino数据库时,Domino可以基于Unix密码(即,存储在标准Unix密码注册表(如/ etc / passwd或NIS)中的密码)对用户进行身份验证。 可以剪切和粘贴这里记录的内容,并将其合并到您自己的样本中。 运行和安装过滤器的步骤如下。
示例代码说明。 |
该示例假定Unix用户名是用户的Domino“短名称”。 例如:
Domino用户名李四
多米诺简称 JDOE
Unix用户名 JDOE(注:Unix的是大小写敏感的,所以在Domino短名称应当存储为小写字符为获得最佳的互操作性,这个名字应该是超过8个字符。)
安装和运行过滤器共享库。 |
- 打开Domino名称和地址簿。 切换到服务器视图并打开服务器文档。 编辑服务器文档:
- 单击“Internet协议”选项卡。
- 点击“HTTP”选项卡。
- 编辑字段“DSAPI过滤器文件名”以包含共享库的名称。 (如果共享库安装到Domino可执行文件目录以外的目录,请为该库提供完整路径名)。
- 保存更改。
2.运行过滤器
- 获取对服务器控制台的访问权限。 重新启动Domino服务器http任务(例如,发出命令“tell http quit”,“load http”)。 服务器控制台应在加载共享库时显示初始化消息。
- 从Domino管理客户端注册一个新的Domino用户,确保用户的Domino短名称对应于所需的Unix登录用户名。 或者找到Domino和Unix已知的现有Domino用户。
- 对于将从Web浏览器访问的目标Domino数据库,请编辑数据库访问控制列表以向Domino用户授予访问权限。
- 使用Web浏览器访问目标数据库。 如果示例正常工作,应提示您输入用户名和密码。 输入Unix密码以测试示例。
程序过滤器初始化,过滤器终止和过滤器通知定义。
#include <stdlib.h>
#include <stdio.h>
#include <String.h>
/ *特殊dsapi包含文件* /
#include“dsapi.h”
/ * unix认证包括* /
#ifdef AIX
#include <sys / types.h>
#include <pwd.h>
#万一
#ifdef HPUX
#include <pwd.h>
#include <crypt.h>
#include <unistd.h>
#万一
/ * Notes SDK包含文件* /
#include“global.h”
#include“osmem.h”
#include“lookup.h”
/ * ---
*本地过程原型
* /
/ * Notes SDK unix共享库entrypoint * /
状态FAR PASCAL MainEntryPoint(void);
/ *具有由DSAPI接口指定的语法的例程* /
unsigned int Authenticate(FilterContext * context,FilterAuthenticate * authData);
/ *从Notes名称和地址簿检索名称* /
int getUserNames(FilterContext * context,char * userName,char ** pUserFullName,int * pUserFullNameLen,
char ** pUserShortName,
int * pUserShortNameLen);
int getLookupInfo(FilterContext * context,char * pMatch,int itemNumber,char ** pInfo,int * pInfoLen);
/ * unix密码检查程序* /
int unixAuthenticate(char * userName,char * password);
/ * ---
*本地程序如下
* /
状态FAR PASCAL MainEntryPoint(void)
{
/ *
*说明:提供Notes API的主入口点
*初始化此共享库。 我们需要
*这个入口点,因为我们想要能够查找
*用户信息在名称和地址簿中通过
* Notes SDK API。
*:
*输入:无
*输出:无
*返回:NOERROR
* /
return NOERROR;
}}
/ * ---
*过滤器初始化
* /
unsigned int FilterInit(FilterInitData * filterInitData)
{
/ *
*说明:当过滤器执行过滤器初始化
*共享库是动态加载的。
*:
*输入:filterInitData dsapi规范控制格式
* 数据的
*输出:filterInitData填充几个字段
*:
*返回:kFilterHandledEvent
* /
/*需要*/
filterInitData-> appFilterVersion = kInterfaceVersion;
/ *修改以下代码以设置您想要的标志* /
filterInitData-> eventFlags =
kFilterAuthUser;
/ *设置过滤器的简短描述* /
strcpy(filterInitData-> filterDesc,
“Unix Authentication Filter”);
/ *在这里插入任何全局初始化代码... * /
/ *输出发送到stdout和stderr显示在
*服务器控制台,但不会写入服务器日志文件。
* /
printf(“\ nDSAPI Unix Authentication filter initialized \ n”);
return kFilterHandledEvent;
}}
/ * ---
*过滤器终止
* /
unsigned int TerminateFilter(unsigned int reserved)
{
/ *
*说明:过滤器执行过滤器终止
*共享库已卸载。
*:
*输入:保留当前未使用(dsapi规范控制
*数据格式)
*输出:无
*:
*返回:kFilterHandledEvent
* /
/ *在这里插入任何全局清理代码... * /
printf(“\ nDSAPI Unix authentication filter unloaded \ n”);
return kFilterHandledEvent;
}}
/ * ...
*过滤器通知处理
* /
unsigned int HttpFilterProc(FilterContext * context,
unsigned int eventType,void * eventData)
{
/ *
*描述:对所有dsapi过滤器事件调用此例程。
*:
*输入:保留当前未使用(dsapi规范控制
*数据格式)
*输出:无
*:
*返回:kFilterNotHandled对于我们没有自定义的所有事件,
*否则允许我们的过滤器例程提供返回
*值。
* /
/ *只包括我们要处理的事件* /
switch(eventType){
case kFilterAuthUser:
return Authenticate(context,
(FilterAuthenticate *)eventData);
默认:
打破;
}}
return kFilterNotHandled;
}}
过滤器验证主要功能,控制来自Domino和Unix端的验证。 |
*处理用户身份验证
* /
unsigned int Authenticate(FilterContext * context,
FilterAuthenticate * authData)
{
/ *
*说明:此例程在dsapi kFilterAuthUser上调用
*事件。
*:
*输入:上下文dsapi规范控制数据的格式
* authData password字段包含要使用的密码
* authentication userName字段包含名称
*认证foundInCache字段为TRUE如果
*用户已在缓存中找到并可以
*在此基础上进行验证。
*:
*输出:authData authName字段填充用户的
*专有名称authType已填写
*与kNotAuthentic如果我们不能认证
* unix用户kAuthenticBasic如果我们可以
*验证unix用户。
*:
*返回:kFilterNotHandled如果我们不明白输入数据,
*或者如果用户已在缓存中找到,或
*如果我们发现要认证的用户是
* unix不知道。
* kFilterHandledEvent如果用户已知为unix。
* /
/ *如果用户在缓存中找到,那么我们不需要这样做
*任何进一步。
* /
if(!authData || authData-> foundInCache)
return kFilterNotHandled;
/ *尝试验证用户的密码。
* /
if(authData-> userName && authData-> password){
char * fullName = NULL;
int fullNameLen = 0;
char * shortName = NULL;
int shortNameLen = 0;
/ *在名称和地址簿中查找用户。 得到
*用户的短名称(我们期望的是unix
*用户名),并获取用户的全名(我们
*期望将以格式传回
* dsapi)。
* /
if(0 == getUserNames(context,
(char *)authData-> userName,
&全名,
&fullNameLen,
&简称,
&shortNameLen)){
int unixauth;
/ *执行unix身份验证。 的
* unixAuthenticate例程返回:-1 on
*错误,0成功,1如果用户不知道
*到unix。
* /
unixauth = unixAuthenticate(shortName,
(char *)authData-> password);
/ *如果用户不知道unix则返回* /
if(1 == unixauth){
printf(“\ n用户名不在UNIX系统中。\ n”)
return kFilterNotHandled;
}}
/ *复制此用户的规范名称
* dsapi要求。
* /
strncpy((char *)authData-> authName,fullName,
authData-> authNameSize);
/ *填写dsapi的authType返回信息
*要求。
* /
if(unixauth){
/ * unixauthenticate例程
*返回错误:我们不能
*使用输入验证
*密码。
* /
authData-> authType = kNotAuthentic;
} else {
/ *为了调试的目的,写入
* Domino控制台的身份验证
*输入密码成功。
*您可能希望删除此printf。
* /
printf(“DSAPI Filter authenticated%s as%s(unix user%s)\ n”,
(char *)authData-> userName,
authData-> authName,shortName);
authData-> authType = kAuthenticBasic;
}}
return kFilterHandledEvent;
}}
}}
return kFilterNotHandled;
}}
从Domino端查找用户的实际例程。 每次调用此过滤器的Authenticate例程时,将在Domino名称和地址簿中对用户进行查找(假定在之前的身份验证中未在缓存中找到用户)。 此查找将尝试检索用户的Domino短名称(例如,jdoe)和用户的完整Domino名称。 如果unix用户名不对应于Domino短名称,则需要更改此示例以处理将unix名称映射到Domino名称的方式,反之亦然。 |
char * userName,
char ** pUserFullName,
int * pUserFullNameLen,
char ** pUserShortName,
int * pUserShortNameLen){
/ *
*说明:查找用户并返回用户的全名和
* 简称。
*:
*输入:我们将用于分配内存的上下文上下文
* userName要查找的用户的名称
*输出:pUserFullName用户全名的位置
* pUserFullNameLen存储全名的长度的位置
* pUserShortName用户短名称的位置
* pUserShortNameLen存放位置的长度
* 简称
*:
*返回:-1出错,成功0
* /
STATUS error = NOERROR;
HANDLE hLookup = NULLHANDLE;
WORD Matches = 0;
char * pLookup;
char * pName = NULL;
char * pMatch = NULL;
int rc = -1;
if(!userName ||!pUserFullName ||!pUserFullNameLen ||
!pUserShortName || !pUserShortNameLen)
return rc;
/ *初始化输出* /
* pUserFullName = NULL;
* pUserFullNameLen = 0;
* pUserShortName = NULL;
* pUserShortNameLen = 0;
/ *做名称查找
* /
error = NAMELookup(NULL,/ * NULL表示本地查找* /
0,/ * flags * /
1,/ *命名空间数* /
“$ Users”,/ * namespace list * /
1,/ *要查找的名称数* /
userName,/ *要查找的名称列表* /
2,/ *要返回的项目数* /
“FullName \ 0ShortName”,/ *项目列表
* return * /
&hLookup); / *接收句柄的地方
* return buffer * /
if(error ||(NULLHANDLE == hLookup))
goto NoUnlockExit;
pLookup =(char *)OSLockObject(hLookup);
/ *获取指向我们的条目的指针。
* /
pName =(char *)NAMELocateNextName(pLookup,/ * name lookup
* 缓冲 */
NULL,/ *从开头开始
*查找缓冲区* /
&火柴); / *接收号码
*的时间我们
*找到条目
*(应为1)
* /
/ *如果我们没有找到该条目,则退出* /
if((pName == NULL)||(Matches <= 0)){
goto退出;
}}
pMatch =(char *)NAMELocateNextMatch(pLookup,/ * name lookup
* 缓冲 */
pName,/ *我们找到的条目* /
空值); / *无上一个匹配* /
if(NULL == pMatch){
goto退出;
}}
/ *从我们回来的信息获取全名* /
if(getLookupInfo(context,
pMatch,
0,
pUserFullName,
pUserFullNameLen))
goto退出;
/ *从我们回来的信息获取短名称* /
if(getLookupInfo(context,
pMatch,
如图1所示,
pUserShortName,
pUserShortNameLen))
goto退出;
其他
/ *在所有事情上成功* /
rc = 0;
出口:
if(pLookup && hLookup)
OSUnlock(hLookup);
NoUnlockExit:
if(NULLHANDLE!= hLookup)
OSMemFree(hLookup);
return rc;
}}
int getLookupInfo(FilterContext * context,
char * pMatch,
int itemNumber,
char ** pInfo,
int * pInfoLen){
/ *
*说明:从查找缓冲区获取信息
*:
*输入:我们将用于分配内存的上下文上下文
* pMatch查找缓冲区的名称
* itemNumber其中信息存储在查找中
* 缓冲
*输出:信息缓冲区的pInfo位置
* pInfoLen位置来存储信息长度
*:
*返回:-1出错,成功0
* /
unsigned int reserved = 0;
unsigned int errID;
char * ValuePtr = NULL;
WORD ValueLength,DataType;
STATUS错误;
void * newSpace = NULL;
if(!pMatch ||!pInfo ||!pInfoLen ||(itemNumber <0))
return -1;
/ *初始化输出* /
* pInfo = NULL;
* pInfoLen = 0;
/ *检查信息的类型和长度* /
ValuePtr =(char *)NAMELocateItem(pMatch,/ *匹配我们
* found * /
itemNumber,/ * item#
* of item on lookup * /
&DataType,/ * return the datatype
*项目值* /
&ValueLength); / * rtn的大小
* value * /
if(NULL == ValuePtr || ValueLength == 0){
/ *没有信息* /
return -1;
}}
ValueLength - = sizeof(WORD); / *删除数据类型字
*在列表长度
* /
/ *检查值DataType * /
switch(DataType){
case TYPE_TEXT_LIST:
打破;
案例TYPE_TEXT:
打破;
默认:
return -1;
}}
/ *分配信息的空间。 这个内存将被释放
*当线程终止时自动。
* /
newSpace =(context-> AllocMem)(context,ValueLength + 1,
保留,&errID);
* pInfo =(char *)newSpace;
if(NULL == * pInfo){
printf(“Out of memory \ n”);
return -1;
}}
/ *获取信息* /
error = NAMEGetTextItem(pMatch,/ *匹配,我们发现* /
itemNumber,/ * item#按项目顺序
*查找* /
0,/ *成员#文本中的项目
*列表* /
* pInfo,/ *缓冲区复制结果
* into * /
ValueLength + 1); / *缓冲区长度* /
if(!error){
* pInfoLen = ValueLength +1;
return 0;
}}
return -1;
}}
从Unix端验证用户。 |
int unixAuthenticate(char * userName,char * password){
/ *
*说明:查看用户是否知道unix,如果是,请检查
*密码可以验证。
*:
*输入:userName unix用户名
*密码unix密码
*:
*返回:-1出错,0成功,1如果用户不知道unix
* /
char缓冲区[1024];
int error = -1;
int success = 0;
int unknown = 1;
#ifdef AIX
struct passwd * result;
#万一
#ifdef HPUX
struct passwd pwd;
size_t buflen = sizeof(buffer);
struct passwd * result;
int err;
#万一
printf(“\ nUserName =%s \ n”,* userName);
if(!userName)
{
printf(“\ nUserName =%s \ n”,* userName);
返回错误;
}}
/ *获取此用户的unix记录* /
#ifdef AIX
result = getpwnam(userName);
if(result && result-> pw_passwd){
/ *加密密码,看看它是否匹配
*来自用户记录的加密密码。
* /
char * thisCrypt = NULL;
thisCrypt =(char *)crypt(password,
result-> pw_passwd);
if(strcmp(result-> pw_passwd,thisCrypt)== 0){
返回成功;
} else {
返回错误;
}}
}}
#万一
#ifdef HPUX
err = getpwnam_r(userName,&pwd,buffer,buflen,&result);
if(0 == err){
/ *加密密码,看看它是否匹配
*来自用户记录的加密密码。
* /
if(strcmp(result-> pw_passwd,
crypt(password,result-> pw_passwd))== 0){
返回成功;
} else {
返回错误;
}}
}}
#万一
返回未知;
}}
/ * ----- end of dsapifilter.c * /
-------------------------------------------------- -------------------------------------------------- ------