PAM从入门到精通(二十六)

接前一篇文章: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函数的其余部分将在后续文章中继续讲解。

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

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

相关文章

【AI视野·今日Robot 机器人论文速览 第五十七期】Wed, 18 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Wed, 18 Oct 2023 Totally 17 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers Underwater and Surface Aquatic Locomotion of Soft Biomimetic Robot Based on Bending Rolled Dielectric Elastomer Actua…

No module named ‘cv2’ 解决方法

目录 解决方案1解决方案2 解决方案1 一般情况下的解决方案 在自己的虚拟环境里面安装就行 pip install opencv-python解决方案2 但是我遇到的情况没有这么简单,我使用了pip list | grep open 搜索含有open字样的opencv的包,结果显示已经安装了 我直接进入我的自定义的虚拟…

亚马逊注册账号时老是显示内部错误

最近你们是否遇到注册亚马逊账号时一直遇到"内部错误"的情况?,这可能是由多种原因引起的。以下是一些可能有助于解决这个问题的步骤: 1、清除缓存和Cookie:有时浏览器缓存和Cookie中的问题可能导致网站错误。可以试试清…

如何在Ubuntu下安装RabbitMQ服务并异地远程访问?

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

WeakHashMap 源码解析

目录 一. 前言 二. 源码解析 2.1. 类结构 2.2. 成员变量 2.3. 构造方法 2.4. Entry 2.5. 添加元素 2.6. 扩容 2.7. 删除元素 2.8. 获取元素 一. 前言 WeakHashMap,从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除…

新手投资如何分配股票仓位?诺奖得主的秘诀是什么?| 附代码【邢不行】

2023年6月22日,诺贝尔经济学奖得主哈里.马克维茨于美国去世,享年95岁。 作为现代金融先驱者,马科维茨不仅是将数学引入金融的第一人,更用数学解释了分散投资的重要性。 更令人惊叹的是,过去十几年中如果按他的理论在中…

docker部署prometheus+grafana服务器监控(一)

docker-compose 部署prometheusgrafana Prometheus Prometheus 是有 SoundCloud 开发的开源监控系统和时序数据库,基于 Go 语言开发。通过基于 HTTP 的 pull 方式采集时序数据,通过服务发现或静态配置去获取要采集的目标服务器,支持多节点工…

18.2 使用NPCAP库抓取数据包

NPCAP 库是一种用于在Windows平台上进行网络数据包捕获和分析的库。它是WinPcap库的一个分支,由Nmap开发团队开发,并在Nmap软件中使用。与WinPcap一样,NPCAP库提供了一些API,使开发人员可以轻松地在其应用程序中捕获和处理网络数据…

【Redis系列】在Centos7上安装Redis5.0保姆级教程!

哈喽, 大家好,我是小浪。那么最近也是在忙秋招,很长一段时间没有更新文章啦,最近呢也是秋招闲下来,当然秋招结果也不是很理想,嗯……这里就不多说啦,回归正题,从今天开始我们就开始正…

Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (三)

这是继之前文章: Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (一) Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二&…

配置Sentinel 控制台

1.遇到的问题 服务网关 | RuoYi 最近调试若依的微服务版本需要用到Sentinel这个组件,若依内部继承了这个组件连上即用。 Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面。 在日常开发中,限流功能时常被使用,用…

uni-app配置微信开发者工具

一、配置微信开发者工具路径 工具->设置->运行配置->小程序运行配置->微信开发者工具路径 二、微信开发者工具开启服务端口

YB5302是一款工作于2.7V到6.5V的PFM升压型双节锂电池充电控制集成电路

YB5302 锂电输入升压型双节锂电池充电芯片 概述: YB5302是一款工作于2.7V到6.5V的PFM升压型双节锂电池充电控制集成电路。YB5302采用恒流和准恒压模式(Quasi-CVT™)对电池进行充电管理,内部集成有基准电压源,电感电流检测单元,电池电压检测电…

Remote Local File Inclusion (RFI/LFI)-文件包含漏洞

文件包含是一种功能,在各种开发语言中都提供了内置的文件包含函数。在PHP中,例如,可以使用include()和require()函数来引入另一个文件。这个被引入的文件可以当作PHP代码执行,而忽略其后缀本身。 // if( count( $_GET ) ) if( isset( $file ) )include( $file ); else {he…

易点易动固定资产管理系统:高效盘点海量固定资产的得力助手

固定资产是企业重要的财务资源之一,盘点是保证固定资产准确性和完整性的关键环节。然而,对于拥有海量固定资产的企业来说,传统的手工盘点方式效率低下且容易出错。为了解决这一难题,易点易动固定资产管理系统应运而生。本文将深入…

虹科 | 解决方案 | 非道路移动机械诊断方案

虹科Pico汽车示波器为卡车、拖拉机、叉车、船只、联合收割机、挖掘机开发了专用的测试附件和软件测试菜单,比如 24 V 电池、Bosch Denoxtronic、J1939 通信、发动机和液压传动系统以及部件测试等。我们为从事重型车辆和非道路移动机械的维护与诊断的朋友&#xff0c…

Java New对象分配内存流程

一、流程图 二、流程介绍 1、进行逃逸分析,判断是否能够分配到栈上: Y: 如果能分配到栈上,则进行分配。等方法出栈时,对象内存销毁,可有效减少GC的次数。 N:无法分配到栈上,则判断是…

VMware创建Linux虚拟机之(三)Hadoop安装与配置及搭建集群

Hello,world! 🐒本篇博客使用到的工具有:VMware16 ,Xftp7 若不熟悉操作命令,推荐使用带GUI页面的CentOS7虚拟机 我将使用带GUI页面的虚拟机演示 虚拟机(Virtual Machine) 指通过…

XTU-OJ 1227-Robot

题目描述 假设在一个XOY坐标的平面上,机器人一开始位于原点,面向Y轴正方向。 机器人可以执行向左转,向右转,向后转,前进四个指令。 指令为 LEFT:向左转RIGHT:向右转BACK:向后转FORWORD n:向前走n(1≤n≤100)个单位 现在…

【环境】Linux下Anaconda/ Miniconda安装+百度Paddle环境搭建+Cudnn(3090显卡+CUDA11.8+cudnn8.6.0)

清华源帮助链接:https://mirror.tuna.tsinghua.edu.cn/help/anaconda/ 下载链接:https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/ 其他深度学习环境相关博文:【stable-diffusion】4090显卡下dreambooth、lora、sd模型微调的GUI环境…