本文代码涉及所有文件存放在
https://github.com/ochapman/passwd_demo.git
熟悉linux的人应该用过修改用户密码工具passwd,如下所示:
ochapman@ubuntu14:~/code/pam$ passwd
Changing password for ochapman.
(current) UNIX password:
提示了修改谁的密码,并要求输入当前的密码。
一般情况下,读取当前密码,校验当前密码是否正确,再去更新shadow/passwd文件…
linux下,这类工作主要由PAM承包
PAM能抽象到什么程度呢,本文将用一个简单的例子展示PAM的威力。
下面是一个简单的例子,实现了passwd的基本功能
/*
* passwd_demo
* a simple passwd utility for showing PAM usage
* derived from shadow
*/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdlib.h>
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#define SHADOW_PAM_CONVERSATION misc_conv
static struct pam_conv conv = {
SHADOW_PAM_CONVERSATION,
NULL
};
void do_pam_passwd (const char *user, bool silent, bool change_expired)
{
pam_handle_t *pamh = NULL;
int flags = 0, ret;
if (silent)
flags |= PAM_SILENT;
if (change_expired)
经常阅读后台程序源码的话,会看到在初始化时dup2相关的函数,例如nginx的
fd = open("/dev/null", O_RDWR);
if (fd == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"open(\"/dev/null\") failed");
return NGX_ERROR;
}
if (dup2(fd, STDIN_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
return NGX_ERROR;
}
if (dup2(fd, STDOUT_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
return NGX_ERROR;
}
#if 0
if (dup2(fd, STDERR_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
return NGX_ERROR;
}
#endif
if (fd > STDERR_FILENO) {
if (close(fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
return NGX_ERROR;
}
}
return NGX_OK;
dup2的定义
int dup2(int oldfd, int newfd);
从内核代码fs/file.c,实际在SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, i