PAM从入门到精通(二十)

编程入门 行业动态 更新时间:2024-10-28 11:30:47

PAM从入门到精通(<a href=https://www.elefans.com/category/jswz/34/1766924.html style=二十)"/>

PAM从入门到精通(二十)

接前一篇文章:PAM从入门到精通(十九)

本文参考:

《The Linux-PAM Application Developers' Guide》

先再来重温一下PAM系统架构:

更加形象的形式:

七、PAM-API各函数源码详解

前边的文章讲解了各PAM-API函数以及总体流程,但是也只是从接口层面介绍的,并没有深入到代码层面。从本篇文章开始,将对于各个接口函数从源码级进行讲解,以使大家不但知其然,还要知其所以然。

1. pam_start函数

老规矩,先从pam_start函数开始。先再来看一下pam_start()的说明。

概述:

PAM事务初始化。

函数声明:

#include <security/pam_appl.h>


int pam_start ( service_name , user , pam_conversation , pamh );


const char * service_name ;
const char * user ;
const struct pam_conv * pam_conversation ;
pam_handle_t ** pamh ;

其余函数相关细节说明随着源码一起讲解。

pam_start函数在Linux-PAM-1.5.2源码根目录的libpam/pam_start.c中,代码如下:

int pam_start (const char *service_name,const char *user,const struct pam_conv *pam_conversation,pam_handle_t **pamh)
{return _pam_start_internal(service_name, user, pam_conversation,NULL, pamh);
}

由代码可见,pam_start()只是一层简单的封装,实际的工作完全交给了_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_start_internal函数一开始先给出调试信息,并且进行参数检查。代码片段如下:

    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);}

service_name是由pam_start函数传下来的参数,其作用是:指定要应用的服务的名称,并将作为PAM_SEVICE项存储在新上下文中。服务的策略将从文件/etc/pam.d/service_name中读取,如果该文件不存在,则从/etc/pam.conf中读取。如:passwd(/etc/pam.d/passwd)、useradd(/etc/pam.d/useradd)等。

pamh也是由pam_start函数传下来的参数,其内容是一个句柄,它包含对PAM函数的连续调用的PAM上下文。在错误情况下,pamh的内容未定义。pam_handle_t是一个盲结构,应用程序不应试图直接探测其信息。而是应该通过PAM库提供的函数pam_set_item和pam_get_item。PAM句柄不能同时用于多个身份验证,只要以前没有对其调用pam_end函数。

之前一直没有给出pamh的类型pam_handle_t的定义,在这里必须要弄清楚了。其定义在libpam/pam_private.h中,代码如下:

struct pam_handle {char *authtok;unsigned caller_is;struct pam_conv *pam_conversation;char *oldauthtok;char *prompt;                /* for use by pam_get_user() */char *service_name;char *user;char *rhost;char *ruser;char *tty;char *xdisplay;char *authtok_type;          /* PAM_AUTHTOK_TYPE */struct pam_data *data;struct pam_environ *env;      /* structure to maintain environment list */struct _pam_fail_delay fail_delay;   /* helper function for easy delays */struct pam_xauth_data xauth;        /* auth info for X display */struct service handlers;struct _pam_former_state former;  /* library state - support forevent driven applications */const char *mod_name;	/* Name of the module currently executed */int mod_argc;               /* Number of module arguments */char **mod_argv;            /* module arguments */int choice;			/* Which function we call from the module */#ifdef HAVE_LIBAUDITint audit_state;             /* keep track of reported audit messages */
#endifint authtok_verified;char *confdir;
};

libpam/include/security/_pam_types.h中:

/* This is a blind structure; users aren't allowed to see inside a* pam_handle_t, so we don't define struct pam_handle here.  This is* defined in a file private to the PAM library.  (i.e., it's private* to PAM service modules, too!)  */typedef struct pam_handle pam_handle_t;

pam_conversation也是由pam_start函数传下来的参数,其指向描述要使用的会话函数的结构pam_conv。应用程序必须为加载的模块与应用程序之间的直接通信提供此功能。

struct pam_conv的定义在libpam/include/security/_pam_types.h中,代码如下:

/* The actual conversation structure itself */struct pam_conv {int (*conv)(int num_msg, const struct pam_message **msg,struct pam_response **resp, void *appdata_ptr);void *appdata_ptr;
};

做完第一步参数检查的工作后,下边正式开始进行实际功能实现。欲知后事如何,且看下回分解。

更多推荐

PAM从入门到精通(二十)

本文发布于:2023-12-05 05:10:49,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1663177.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:二十   入门   PAM

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!