PAM应用程序开发笔记记录(二)

一、PAM应用程序开发

任何一个支持PAM的应用程序在进行认证时必须以pam_start()开始进行初始化,最后以pam_end()结束。

1.1 pam_start()函数

#include <security/pam_appl.h>
int pam_start(const char *service_name, const char *user, const struct pam_conv *pam_conversation, pam_handle_t **pamh);

参数讲解

  • service_name

应用的名字,这个名字参数非常重要。当应用程序执行验证操作时,libpam库会在/etc/pam.d/下寻找以service_name命名的配置文件,该配置文件中指定了相关参数,其中包括将要调用哪个动态链接库进行验证。配置文件的格式与前面讲的/etc/pam.conf的格式基本一致,只是去掉了service-name这一项,因为该配置文件的名字就是service-name。

  • user

用户名,即PAM框架所作用的用户的名称。说白了就是你要对哪个用户进行PAM验证,该用户就是此轮验证中(pam_start–pam_end)被操作的对象。

  • pam_conversation

对话函数conv,用于提供PAM与用户或应用程序进程通信的通用方法。对话函数是必需的,因为PAM模块无法了解如何进行通信。通信可以采用 GUI、命令行、智能读卡器或其他设备等方式进行。这个对话函数是一个回调函数,这里只是对它的一个注册,接下来的验证过程中,应用程序和服务模块之间的所有信息交互都要通过它。对话函数需要应用程序的作者自己编写。

  • pamh

PAM句柄 pamh,即 PAM 框架用于存储有关当前操作信息的不透明句柄。成功调用 pam_start() 后将返回此句柄。要研究这个pamh,需要对pam的内部实现机制进行了解,有点复杂,暂时先不说这个。大家把它想成类似于一个socket套接字的东西就行,反正就是一个句柄而已。
返回值
PAM_ABORT 一般性错误
如果收到这个,应用程序应该立即调用pam_end()退出
PAM_BUF_ERR 内存缓冲区错误
PAM_SUCCESS 成功建立验证XX
PAM_SYSTEM_ERR 系统错误,参数中有无效指针

1.2 pam_end()函数

#include <security/pam_appl.h>
int pam_end(pam_handle_t *pamh, int pam_status);

参数讲解
pam_end()函数是整个pam验证过程中,应用程序最后调用的函数。从此以后句柄pamh不再有效,而且所有的占用的内存将被释放。

  • pamh

是pam_start()函数中创建的pamh。

  • pam_status

是应用程序在执行pam_end()函数前所执行的最后一个pam API函数的返回值。

pam_status通常被传递给服务模块的特有的一个回调函数cleanup(),这样服务模块就知道关闭应用程序是否成功,然后继续执行和之前一样的工作,即给其他应用程序提供验证服务。pam_end()释放了pam_set_item()和pam_get_item()申请的所有内存,所有对象的指针在pam_end()执行后也都不在有效。
返回值

1.3 认证管理pam_authenticate()函数

#include <security/pam_appl.h>
int pam_authenticate(pam_handle_t *pamh, int flags);

该函数被用来验证用户的合法性(即令牌认证),这个用户就是在pam_start()参数传递的user。User被要求提供一个密码或者一个简单的数字输入。然后服务模块中对应的pam_sm_authenticate()函数会检测user的输入并验证是否合法。
简单点说就是对用户名/密码进行认证。

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0,或者设置为如下值:
PAM_SILENT
不输出任何信息
PAM_DISALLOW_NULL_AUTHTOK
如果用户没有注册,那么服务模块应该返回PAM_DISALLOW_NULL_AUTHTOK;
返回值
PAM_ABORT 一般性错误
如果收到这个,应用程序应该立即调用pam_end()退出
PAM_AUTH_ERR
user没有被验证
PAM_CRED_INSUFFICIENT
由于一些原因应用程序没有足够的凭证来验证用户
PAM_AUTHINFO_UNVAIL
服务模块不能获取user的验证信息,原因可能是网络或硬件配置错误
PAM_MAXTRIES
服务模块验证用户的次数达到上限,应用程序这边不要再提交验证请求了,也就是说不要再运行pam_ authenticate()了
PAM_SUCCESS
用户成功通过验证
PAM_USER_UNKNOWN
该用户不能够被服务模块识别,我估计要么是用户名格式非法,要么是用户没有注册等其他原因

1.4 账户管理pam_acct_mgmt()函数

#include <security/pam_appl.h>
int pam_acct_mgmt(pam_handle_t *pamh, int flags);

pam_acct_mgmt()通常被用来确认用户账户是否有效。确认的内容可以包括下面的内容:

  • 令牌认证(就是pam_authenticate()实现的功能)
  • 账户是否过期
  • 访问权限
  • 该函数一般在pam_authenticate()成功执行(即用户通过验证)之后被调用执行,所以上面内容中的第一项常可以被省略。

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0,或者设置为如下值:
PAM_SILENT
不输出任何信息
PAM_DISALLOW_NULL_AUTHTOK
如果用户没有注册,那么服务模块应该返回PAM_DISALLOW_NULL_AUTHTOK;
返回值
PAM_ACCT_EXPIRED
用户已经过期失效
PAM_AUTH_ERR
用户令牌认证失败
PAM_NEW_AUTHTOK_REQD
该用户账户是有效的但是认证令牌是过期的,正确的做法是回复该值要求用户执行pam_chauthtok()来更新令牌(密码)在用户获得其他服务之前。
PAM_PERM_DENIED
不允许访问,应该就是所谓的权限控制
PAM_SUCCESS
认证令牌被成功更新,或者是用过通过认证
PAM_USER_UNKNOWN
该用户不能够被服务模块识别

1.5 会话管理pam_open_session()函数

#include <security/pam_appl.h>
int pam_open_session(pam_handle_t *pamh, int flags);

该函数为已经成功通过验证的用户建立一个用户会话,该会话应该在后面被函数pam_close_session()终止。

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0或者下面的值:
PAM_SILENT
不输任何信息
返回值
PAM_ABORT
一般性的失败
PAM_BUF_ERR
内存缓冲区错误
PAM_SESSION_ERR
建立会话失败
PAM_SUCCESS
成功建立会话

1.6 会话管理pam_close_session()函数

#include <security/pam_appl.h>
int pam_close_session(pam_handle_t *pamh, int flags);

该函数被用来关闭pam_open_session()创建的会话。

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0或者下面的值:
PAM_SILENT
不输任何信息
返回值
PAM_ABORT
一般性的失败
PAM_BUF_ERR
内存缓冲区错误
PAM_SESSION_ERR
建立会话失败
PAM_SUCCESS
成功建立会话

1.7 密码管理pam_chauthtok()函数

#include <security/pam_appl.h>
int pam_chauthtok(pam_handle_t *pamh, int flags);

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0或者下面的值:
PAM_SILENT
不输任何信息;
PAM_CHANGE_EXPIRED_AUTHTOK
告诉服务模块只更新过期令牌,如果不设置这个参数,应用程序要求更改所有用户的令牌;
返回值
PAM_AUTHTOK_ERR
服务模块未能获得新的用户令牌
PAM_AUTHTOK_RECOVERY_ERR
服务模块未能获得旧的用户令牌
PAM_AUTHTOK_LOCK_BUSY
又有用户令牌被锁定,服务模块不能对其进行更改
PAM_AUTHTOK_DISABLE_AGING
用户令牌被至少一个服务模块禁用了
PAM_PERM_DENIED
没有权限
PAM_SUCCESS
用户令牌被成功更新
PAM_TRY_AGAIN
并不是所有的服务模块都能够更新用户令牌,遇到这种情况,用户令牌都不能得到更新
PAM_USER_UNKNOWN
该用户不能够被服务模块识别

1.8 认证管理pam_setcred()函数

#include <security/pam_appl.h>
int pam_setcred(pam_handle_t *pamh, int flags);

pam_setcred()函数被用来创建、维持、或删除一个用户的证书。Pam_setcred()应该在user已经通过验证(after pam_authenticate)并且在会话建立之前(before pam_open_ session)被调用。删除user证书的操作必须在会话被关闭之后执行(after pam_close_ session).user证书应该被应用程序创建,而不是被pam库或者服务模块创建。
简单点来说就是用来修改用户的秘密信息。

参数讲解

  • pamh

是pam_start()函数中创建的pamh

  • flags

参数flags可以被设置为0或者下面的值:
PAM_ESTABLISH_CRED
初始化用户证书;
PAM_DELETE_CRED
删除用户证书;
PAM_REINITIALIZE_CRED
完全重置用户证书;
PAM_REFRESH_CRED
延长用户证书的生命周期;
返回值
PAM_BUF_ERR
内存缓冲区错误
PAM_CRED_ERR
设置(创建、维持、重置、回复、删除等)用户证书失败
PAM_CRED_EXPIRED
用户证书过期
PAM_CRED_UNAVAIL
回复用户证书失败
PAM_SUCCESS
数据被成功存储
PAM_SYSTEM_ERR
系统错误,例如无效的指针被传入,函数正在被其他模块调用,或者系统错误等等
PAM_USER_UNKNOWN
该用户不能被够服务模块识别

二、PAM服务模块开发

2.1 认证管理pam_sm_authenticate()接口函数

#define PAM_SM_AUTH
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_authenticate()函数是pam_authenticate()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_ABORT 一般性错误
如果收到这个,应用程序应该立即调用pam_end()退出
PAM_AUTH_ERR
user没有被验证
PAM_CRED_INSUFFICIENT
由于一些原因应用程序没有足够的凭证来验证用户
PAM_AUTHINFO_UNVAIL
服务模块不能获取user的验证信息,原因可能是网络或硬件配置错误
PAM_MAXTRIES
服务模块验证用户的次数达到上限,应用程序这边不要再提交验证请求了,也就是说不要再运行pam_ authenticate()了
PAM_SUCCESS
用户成功通过验证
PAM_USER_UNKNOWN
该用户不能够被服务模块识别,我估计要么是用户名格式非法,要么是用户没有注册等其他原因

2.2 账户管理pam_sm_acct_mgmt()接口函数

#define PAM_SM_ACCOUNT
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_acct_mgmt()函数是pam_acct_mgmt()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_ACCT_EXPIRED
用户已经过期失效
PAM_AUTH_ERR
用户令牌认证失败
PAM_NEW_AUTHTOK_REQD
该用户账户是有效的但是认证令牌是过期的,正确的做法是回复该值要求用户执行pam_chauthtok()来更新令牌(密码)在用户获得其他服务之前。
PAM_PERM_DENIED
不允许访问,应该就是所谓的权限控制
PAM_SUCCESS
认证令牌被成功更新,或者是用过通过认证
PAM_USER_UNKNOWN
该用户不能够被服务模块识别

2.3 会话管理pam_sm_open_session()接口函数

#define PAM_SM_SESSION
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_open_session()函数是pam_open_session()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_ABORT
一般性的失败
PAM_BUF_ERR
内存缓冲区错误
PAM_SESSION_ERR
建立会话失败
PAM_SUCCESS
成功建立会话

2.4 会话管理pam_sm_close_session()接口函数

#define PAM_SM_SESSION
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_close_session()函数是pam_close_session()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_ABORT
一般性的失败
PAM_BUF_ERR
内存缓冲区错误
PAM_SESSION_ERR
建立会话失败
PAM_SUCCESS
成功建立会话

2.5 密码管理pam_sm_chauthtok()接口函数

#define PAM_SM_PASSWORD
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_chauthtok()函数是pam_chauthtok()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_AUTHTOK_ERR
服务模块未能获得新的用户令牌
PAM_AUTHTOK_RECOVERY_ERR
服务模块未能获得旧的用户令牌
PAM_AUTHTOK_LOCK_BUSY
又有用户令牌被锁定,服务模块不能对其进行更改
PAM_AUTHTOK_DISABLE_AGING
用户令牌被至少一个服务模块禁用了
PAM_PERM_DENIED
没有权限
PAM_SUCCESS
用户令牌被成功更新
PAM_TRY_AGAIN
并不是所有的服务模块都能够更新用户令牌,遇到这种情况,用户令牌都不能得到更新
PAM_USER_UNKNOWN
该用户不能够被服务模块识别

2.6 认证管理pam_sm_setcred()接口函数

#define PAM_SM_AUTH
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv);

pam_sm_setcred()函数是pam_setcred()函数在服务模块中的接口

参数讲解
我们永远无法在我们设计的应用程序中直接调用这6个接口函数,也无法在我们自己设计的服务模块中让这6个接口函数相互调用,这6接口函数只能作为回调函数以动态链接库的形式存在,并且只能被PAM库调用。认证请求和认证服务是分离的,应用程序只负责提出认证请求,服务模块负责认证,两者靠PAM库连接起来。
PAM从认证请求函数中获得pamh参数和flags参数,并准备作为参数传递给对应接口函数(分别对应接口函数中pamh和flags)。然后PAM库从配置文件(配置文件的名字在pam_start()函数中指定)中的arguments项中,获取将要传递给接口函数的第四个参数argv,并计算出参数的个数作为接口函数的第三个参数。
返回值
PAM_BUF_ERR
内存缓冲区错误
PAM_CRED_ERR
设置(创建、维持、重置、回复、删除等)用户证书失败
PAM_CRED_EXPIRED
用户证书过期
PAM_CRED_UNAVAIL
回复用户证书失败
PAM_SUCCESS
数据被成功存储
PAM_SYSTEM_ERR
系统错误,例如无效的指针被传入,函数正在被其他模块调用,或者系统错误等等
PAM_USER_UNKNOWN
该用户不能被够服务模块识别

三、PAM配置文件编辑

使用pam_start()函数指定配置文件的文件名后,就应该在/etc/pam.d/目录下创建对应的配置文件。

本次笔记内容来源:http://blog.chinaunix.net/uid-29479952-id-5761564.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值