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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/144859.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像信号处理板设计原理图:2-基于6U VPX的双TMS320C6678+Xilinx FPGA K7 XC7K420T的图像信号处理板

综合图像处理硬件平台包括图像信号处理板2块&#xff0c;视频处理板1块&#xff0c;主控板1块&#xff0c;电源板1块&#xff0c;VPX背板1块。 一、板卡概述 图像信号处理板包括2片TI 多核DSP处理器-TMS320C6678&#xff0c;1片Xilinx FPGA XC7K420T-1FFG1156&#xff0c;1片X…

Linux进程(四)--进程地址空间(一)

前言&#xff1a;在Linux中&#xff0c;每个正在运行的进程都有自己独立的虚拟地址空间&#xff0c;该虚拟地址空间是逻辑上的抽象&#xff0c;用于在进程间提供隔离和保护。它将进程的内存分配和访问从物理内存中分离出来&#xff0c;为每个进程提供了一个独立的地址空间。这究…

零基础搭建个人网站详细流程

最近两天&#xff0c;为了给自己的工具类APP备案&#xff0c;买了阿里云ECS和域名。虽然很想说离线工具APP不用联网&#xff0c;但是现实就很无语。言归正传&#xff0c;既然买了总不能将它们闲置着&#xff0c;就诞生了建站的想法&#xff0c;至少还能放个用户协议和隐私协议。…

FFmpeg和rtsp服务器搭建视频直播流服务

下面使用的是ubuntu的&#xff0c;window系统可以参考&#xff1a; 通过rtsp-simple-server和ffmpeg实现录屏并发布视频直播_rtsp simple server_病毒宇宇的博客-CSDN博客 一、安装rtsp-simple-server &#xff08;1&#xff09;下载rtsp-simple-server 下载地址&#xff1a;R…

二、BurpSuite Intruder暴力破解

一、介绍 解释&#xff1a; Burp Suite Intruder是一款功能强大的网络安全测试工具&#xff0c;它用于执行暴力破解攻击。它是Burp Suite套件的一部分&#xff0c;具有高度可定制的功能&#xff0c;能够自动化和批量化执行各种攻击&#xff0c;如密码破解、参数枚举和身份验证…

时序分解 | Matlab实现CEEMD互补集合经验模态分解时间序列信号分解

时序分解 | Matlab实现CEEMD互补集合经验模态分解时间序列信号分解 目录 时序分解 | Matlab实现CEEMD互补集合经验模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现CEEMD互补集合经验模态分解时间序列信号分解 1.分解效果图 &#xff0…

Linux高性能编程学习-TCP/IP协议族

一、TCP/IP协议族结构与主要协议 分层&#xff1a;数据链路层、网络层、传输层、应用层 1. 数据链路层 功能&#xff1a;实现网卡驱动程序&#xff0c;处理数据在不同物理介质的传输 协议&#xff1a; ARP&#xff1a;将目标机器的IP地址转成MAC地址RARP&#xff1a;将MAC地…

Kubernetes技术与架构-Ingress Controller

Ingress Controller控制器是实现Ingress对象的定义的组件&#xff0c;也即网关&#xff0c;负责Kubernetes集群内流量的分发&#xff0c;Kubernetes可以运行多个Ingress Controller控制器实例&#xff0c;不同的Ingress定义可以使用不同的Ingress Controller控制器实现&#xf…

散列表:Word文档中的单词拼写检查功能是如何实现的?

文章来源于极客时间前google工程师−王争专栏。 一旦我们在Word里输入一个错误的英文单词&#xff0c;它就会用标红的方式提示“编写错误”。Word的这个单词拼写检查功能&#xff0c;虽然很小但却非常实用。这个功能是如何实现的&#xff1f; 散列别&#xff08;Hash Table&am…

[swift刷题模板] 树状数组(BIT/FenwickTree)

[TOC]([swift刷题模板] 树状数组(BIT/FenwickTree) ) 一、 算法&数据结构 1. 描述 [python刷题模板] 树状数组 二、 模板代码 1. 单点赋值(增加)&#xff0c;区间求和(PURQ) 例题: 307. 区域和检索 - 数组可修改 class BIT {var c: [Int]var n: Int init(_ n: Int){c…

【数据结构】【C语言】【环形链表约瑟夫问题】

1.问题描述及背景&#xff1a; 著名的Josephus问题 据说著名犹太 历史学家 Josephus有过以下的故事&#xff1a;在罗⻢⼈占领乔塔帕特后&#xff0c;39 个犹太⼈与 Josephus及他的朋友躲到⼀个洞中&#xff0c;39个犹太⼈决定宁愿死也不要被⼈抓到&#xff0c;于是决定了⼀个⾃…

面试知识储备--打包工具篇(webpack和vite)

1.vite常用配置 常用配置 1.preprocessorOptions 传递给 CSS 预处理器的配置选项 2.PostCSS 也是用来处理 CSS 的&#xff0c;只不过它更像是一个工具箱&#xff0c;可以添加各种插件来处理 CSS 3.resolve.extensions 导入时想要省略的扩展名列表。默认值为 [‘.mjs’, ‘.js’…