接前一篇文章:PAM从入门到精通(二十五)
本文参考:
《The Linux-PAM Application Developers' Guide》
先再来重温一下PAM系统架构:
更加形象的形式:
七、PAM-API各函数源码详解
前边的文章讲解了各PAM-API函数以及总体流程,但是也只是从接口层面介绍的,并没有深入到代码层面。从本篇文章开始,将对于各个接口函数从源码级进行讲解,以使大家不但知其然,还要知其所以然。
1. pam_start函数
上回讲到_pam_start_internal函数的第五部分,本文继续往下进行讲解。为了便于理解,再次贴出_pam_start_internal函数源码。在libpam/pam_start.c中,如下所示:
static int _pam_start_internal (const char *service_name,const char *user,const struct pam_conv *pam_conversation,const char *confdir,pam_handle_t **pamh)
{D(("called pam_start: [%s] [%s] [%p] [%p]",service_name, user, pam_conversation, pamh));if (pamh == NULL) {pam_syslog(NULL, LOG_CRIT,"pam_start: invalid argument: pamh == NULL");return (PAM_SYSTEM_ERR);}if (service_name == NULL) {pam_syslog(NULL, LOG_CRIT,"pam_start: invalid argument: service == NULL");return (PAM_SYSTEM_ERR);}if (pam_conversation == NULL) {pam_syslog(NULL, LOG_CRIT,"pam_start: invalid argument: conv == NULL");return (PAM_SYSTEM_ERR);}if ((*pamh = calloc(1, sizeof(**pamh))) == NULL) {pam_syslog(NULL, LOG_CRIT, "pam_start: calloc failed for *pamh");return (PAM_BUF_ERR);}/* All service names should be files below /etc/pam.d and nothingelse. Forbid paths. */if (strrchr(service_name, '/') != NULL)service_name = strrchr(service_name, '/') + 1;/* Mark the caller as the application - permission to do certainthings is limited to a module or an application */__PAM_TO_APP(*pamh);if (((*pamh)->service_name = _pam_strdup(service_name)) == NULL) {pam_syslog(*pamh, LOG_CRIT,"pam_start: _pam_strdup failed for service name");_pam_drop(*pamh);return (PAM_BUF_ERR);} else {char *tmp;for (tmp=(*pamh)->service_name; *tmp; ++tmp)*tmp = tolower(*tmp); /* require lower case */}if (user) {if (((*pamh)->user = _pam_strdup(user)) == NULL) {pam_syslog(*pamh, LOG_CRIT,"pam_start: _pam_strdup failed for user");_pam_drop((*pamh)->service_name);_pam_drop(*pamh);return (PAM_BUF_ERR);}} else(*pamh)->user = NULL;if (confdir) {if (((*pamh)->confdir = _pam_strdup(confdir)) == NULL) {pam_syslog(*pamh, LOG_CRIT,"pam_start: _pam_strdup failed for confdir");_pam_drop((*pamh)->service_name);_pam_drop((*pamh)->user);_pam_drop(*pamh);return (PAM_BUF_ERR);}} else(*pamh)->confdir = NULL;(*pamh)->tty = NULL;(*pamh)->prompt = NULL; /* prompt for pam_get_user() */(*pamh)->ruser = NULL;(*pamh)->rhost = NULL;(*pamh)->authtok = NULL;(*pamh)->oldauthtok = NULL;(*pamh)->fail_delay.delay_fn_ptr = NULL;(*pamh)->former.choice = PAM_NOT_STACKED;(*pamh)->former.substates = NULL;
#ifdef HAVE_LIBAUDIT(*pamh)->audit_state = 0;
#endif(*pamh)->xdisplay = NULL;(*pamh)->authtok_type = NULL;(*pamh)->authtok_verified = 0;memset (&((*pamh)->xauth), 0, sizeof ((*pamh)->xauth));if (((*pamh)->pam_conversation = (struct pam_conv *)malloc(sizeof(struct pam_conv))) == NULL) {pam_syslog(*pamh, LOG_CRIT, "pam_start: malloc failed for pam_conv");_pam_drop((*pamh)->service_name);_pam_drop((*pamh)->user);_pam_drop((*pamh)->confdir);_pam_drop(*pamh);return (PAM_BUF_ERR);} else {memcpy((*pamh)->pam_conversation, pam_conversation,sizeof(struct pam_conv));}(*pamh)->data = NULL;if ( _pam_make_env(*pamh) != PAM_SUCCESS ) {pam_syslog(*pamh,LOG_ERR,"pam_start: failed to initialize environment");_pam_drop((*pamh)->pam_conversation);_pam_drop((*pamh)->service_name);_pam_drop((*pamh)->user);_pam_drop((*pamh)->confdir);_pam_drop(*pamh);return PAM_ABORT;}_pam_reset_timer(*pamh); /* initialize timer support */_pam_start_handlers(*pamh); /* cannot fail *//* According to the SunOS man pages, loading modules and resolving* symbols happens on the first call from the application. */if ( _pam_init_handlers(*pamh) != PAM_SUCCESS ) {pam_syslog(*pamh, LOG_ERR, "pam_start: failed to initialize handlers");_pam_drop_env(*pamh); /* purge the environment */_pam_drop((*pamh)->pam_conversation);_pam_drop((*pamh)->service_name);_pam_drop((*pamh)->user);_pam_drop((*pamh)->confdir);_pam_drop(*pamh);return PAM_ABORT;}D(("exiting pam_start successfully"));return PAM_SUCCESS;
}
接下来来到以下代码片段:
_pam_reset_timer(*pamh); /* initialize timer support */
_pam_reset_timer函数在libpam/pam_delay.c中,代码如下:
/* *********************************************************************** initialize the time as unset, this is set on the return from the* authenticating pair of of the libpam pam_XXX calls.*/void _pam_reset_timer(pam_handle_t *pamh)
{D(("setting pamh->fail_delay.set to FALSE"));pamh->fail_delay.set = PAM_FALSE;
}
函数本身很简单,只有两句代码,还有一句是提示信息,真正的代码只有一句。_pam_reset_timer函数的功能是:将time初始化为unset,这是在libpam的pam_XXX调用的身份验证对返回时设置的。
来看一下pam_handle_t即struct pam_handle中的struct _pam_fail_delay fail_delay成员的定义,在libpam/pam_private.h中,如下:
typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean;struct _pam_fail_delay {_pam_boolean set;unsigned int delay;time_t begin;const void *delay_fn_ptr;
};
其中的成员set实际上是一个布尔型变量,在_pam_reset_timer函数中被设置为了PAM_FALSE。
接下来来到_pam_start_internal函数的以下代码片段:
_pam_start_handlers(*pamh); /* cannot fail */
_pam_start_handlers函数在libpam/pam_handlers.c中,代码如下:
void _pam_start_handlers(pam_handle_t *pamh)
{D(("called."));/* NB. There is no check for a NULL pamh here, since no return* value to communicate the fact! *//* Indicate that handlers are not initialized for this pamh */pamh->handlers.handlers_loaded = 0;pamh->handlers.modules_allocated = 0;pamh->handlers.modules_used = 0;pamh->handlers.module = NULL;/* initialize the .conf and .other entries */pamh->handlers.conf.authenticate = NULL;pamh->handlers.conf.setcred = NULL;pamh->handlers.conf.acct_mgmt = NULL;pamh->handlers.conf.open_session = NULL;pamh->handlers.conf.close_session = NULL;pamh->handlers.conf.chauthtok = NULL;pamh->handlers.other.authenticate = NULL;pamh->handlers.other.setcred = NULL;pamh->handlers.other.acct_mgmt = NULL;pamh->handlers.other.open_session = NULL;pamh->handlers.other.close_session = NULL;pamh->handlers.other.chauthtok = NULL;
}
_pam_start_handlers函数也很好理解,对于(*pamh)->handlers的各成员进行设置,即初始化。
来看一下pam_handle_t即struct pam_handle中的struct service handlers成员的相关定义,在libpam/pam_private.h中,如下:
struct handlers {struct handler *authenticate;struct handler *setcred;struct handler *acct_mgmt;struct handler *open_session;struct handler *close_session;struct handler *chauthtok;
};struct service {struct loaded_module *module; /* Array of modules */int modules_allocated;int modules_used;int handlers_loaded;struct handlers conf; /* the configured handlers */struct handlers other; /* the default handlers */
};
_pam_start_internal函数的其余部分将在后续文章中继续讲解。