今天偶尔看到系统里有/etc/passwd- 和/etc/shadow-文件,经测试只要执行过系统的用户操作命令就会产生,如deluser、passwd、chpasswd、adduser等命令,应该是这些命令修改文件前会做备份。

在busybox中,这些命令都会调用以下函数,红色部分为其创建/etc/passwd- 或/etc/shadow-代码:

int FAST_FUNC update_passwd(const char *filename,
const char *name,
const char *new_passwd,
const char *member)
{
#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
#define member NULL
#endif
struct stat sb;
struct flock lock;
FILE *old_fp;
FILE *new_fp;
char *fnamesfx;
char *sfx_char;
char *name_colon;
unsigned user_len;
int old_fd;
int new_fd;
int i;
int changed_lines;
int ret = -1; /* failure */
/* used as a bool: "are we modifying /etc/shadow?" */
#if ENABLE_FEATURE_SHADOWPASSWDS
const char *shadow = strstr(filename, "shadow");
#else
# define shadow NULL
#endif

filename = xmalloc_follow_symlinks(filename);
if (filename == NULL)
return ret;

check_selinux_update_passwd(name);

/* New passwd file, "/etc/passwd+" for now */
fnamesfx = xasprintf("%s+", filename);
sfx_char = &fnamesfx[strlen(fnamesfx)-1];
name_colon = xasprintf("%s:", name);
user_len = strlen(name_colon);

if (shadow)
old_fp = fopen(filename, "r+");
else
old_fp = fopen_or_warn(filename, "r+");
if (!old_fp) {
if (shadow)
ret = 0; /* missing shadow is not an error */
goto free_mem;
}
old_fd = fileno(old_fp);

selinux_preserve_fcontext(old_fd);

/* Try to create "/etc/passwd+". Wait if it exists. */
i = 30;
do {
// FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
new_fd = open(fnamesfx, O_WRONLY|O_CREAT|O_EXCL, 0600);
if (new_fd >= 0) goto created;
if (errno != EEXIST) break;
usleep(100000); /* 0.1 sec */
} while (--i);
bb_perror_msg("can't create '%s'", fnamesfx);
goto close_old_fp;

created:
if (!fstat(old_fd, &sb)) {
fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
fchown(new_fd, sb.st_uid, sb.st_gid);
}
errno = 0;
new_fp = xfdopen_for_write(new_fd);

/* Backup file is "/etc/passwd-" */
*sfx_char = '-';
/* Delete old backup */
i = (unlink(fnamesfx) && errno != ENOENT);
/* Create backup as a hardlink to current */
if (i || link(filename, fnamesfx))
bb_perror_msg("warning: can't create backup copy '%s'",
fnamesfx);
*sfx_char = '+';

/* Lock the password file before updating */
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(old_fd, F_SETLK, &lock) < 0)
bb_perror_msg("warning: can't lock '%s'", filename);
lock.l_type = F_UNLCK;

/* Read current password file, write updated /etc/passwd+ */
changed_lines = 0;
while (1) {
char *cp, *line;

line = xmalloc_fgetline(old_fp);
if (!line) /* EOF/error */
break;
if (strncmp(name_colon, line, user_len) != 0) {
fprintf(new_fp, "%s\n", line);
goto next;
}

/* We have a match with "name:"... */
cp = line + user_len; /* move past name: */

#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
if (member) {
/* It's actually /etc/group+, not /etc/passwd+ */
if (ENABLE_FEATURE_ADDUSER_TO_GROUP
&& applet_name[0] == 'a'
) {
/* Add user to group */
fprintf(new_fp, "%s%s%s\n", line,
last_char_is(line, ':') ? "" : ",",
member);
changed_lines++;
} else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP
/* && applet_name[0] == 'd' */
) {
/* Delete user from group */
char *tmp;
const char *fmt = "%s";

/* find the start of the member list: last ':' */
cp = strrchr(line, ':');
/* cut it */
*cp++ = '\0';
/* write the cut line name:passwd:gid:
* or name:!:: */
fprintf(new_fp, "%s:", line);
/* parse the tokens of the member list */
tmp = cp;
while ((cp = strsep(&tmp, ",")) != NULL) {
if (strcmp(member, cp) != 0) {
fprintf(new_fp, fmt, cp);
fmt = ",%s";
} else {
/* found member, skip it */
changed_lines++;
}
}
fprintf(new_fp, "\n");
}
} else
#endif
if ((ENABLE_PASSWD && applet_name[0] == 'p')
|| (ENABLE_CHPASSWD && applet_name[0] == 'c')
) {
/* Change passwd */
cp = strchrnul(cp, ':'); /* move past old passwd */

if (shadow && *cp == ':') {
/* /etc/shadow's field 3 (passwd change date) needs updating */
/* move past old change date */
cp = strchrnul(cp + 1, ':');
/* "name:" + "new_passwd" + ":" + "change date" + ":rest of line" */
fprintf(new_fp, "%s%s:%u%s\n", name_colon, new_passwd,
(unsigned)(time(NULL)) / (24*60*60), cp);
} else {
/* "name:" + "new_passwd" + ":rest of line" */
fprintf(new_fp, "%s%s%s\n", name_colon, new_passwd, cp);
}
changed_lines++;
} /* else delete user or group: skip the line */
next:
free(line);
}

if (changed_lines == 0) {
#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
if (member) {
if (ENABLE_ADDGROUP && applet_name[0] == 'a')
bb_error_msg("can't find %s in %s", name, filename);
if (ENABLE_DELGROUP && applet_name[0] == 'd')
bb_error_msg("can't find %s in %s", member, filename);
}
#endif
if ((ENABLE_ADDUSER || ENABLE_ADDGROUP)
&& applet_name[0] == 'a' && !member
) {
/* add user or group */
fprintf(new_fp, "%s%s\n", name_colon, new_passwd);
changed_lines++;
}
}

fcntl(old_fd, F_SETLK, &lock);

/* We do want all of them to execute, thus | instead of || */
errno = 0;
if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
|| rename(fnamesfx, filename)
) {
/* At least one of those failed */
bb_perror_nomsg();
goto unlink_new;
}
/* Success: ret >= 0 */
ret = changed_lines;

unlink_new:
if (ret < 0)
unlink(fnamesfx);

close_old_fp:
fclose(old_fp);

free_mem:
free(fnamesfx);
free((char *)filename);
free(name_colon);
return ret;
}

/etc/passwd- 和/etc/shadow-文件的更多相关文章

  1. etc/passwd 和 /etc/shadow 文件内容及其解释

    /etc/passwd 和 /etc/shadow 文件内容及其解释 默认情况下,/etc/passwd 存储有关本地用户的信息 /etc/passwd 采用以下格式: 1)username      ...

  2. linux下/etc/passwd和/etc/shadow文件

    /etc/passwd文件中保存的是用户的账号信息,而/etc/shadow文件中保存的是用户的口令信息. 一 /etc/passwd 一个用户对应着该文件中一行记录,一行记录由若干个字段组成,字段之 ...

  3. linux中/etc/passwd和/etc/shadow文件说明

    /etc/passwd是用来存储登陆用户信息: [root@localhost test]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x ...

  4. linux 系统中 /etc/passwd 和 /etc/shadow文件详解

    链接地址:http://blog.csdn.net/yaofeino1/article/details/54616440

  5. linux用户和组管理,/etc/passwd 、/etc/shadow和/etc/group 文件内容解释

    与用户相关的系统配置文件主要有/etc/passwd 和/etc/shadow,其中/etc/shadow是用户资讯的加密文件,比如用户的密码口令的加密保存等: /etc/passwd 和/etc/s ...

  6. linux 里 /etc/passwd 、/etc/shadow和/etc/group 文件内容解释

    •/etc/passwd文件用于存放用户账户信息,每行代表一个账户,每个账户的各项信息用冒号分割,例如: root:x:::root:/root:/bin/bash username:password ...

  7. linux用户和组管理,/etc/passwd 、/etc/shadow和/etc/group --学习

    一./etc/passwd 和/etc/shadow解释 与用户相关的系统配置文件主要有/etc/passwd 和/etc/shadow,其中/etc/shadow是用户资讯的加密文件,比如用户的密码 ...

  8. /etc/passwd&/etc/shadow文件分析

    /etc/passwd该目录存储的是操作系统用户信息,该文件为所有用户可见.给linux系统添加一个帐号:useradd -g mysql -d /home/test -m test(:新建一个用户t ...

  9. Linux中/etc/passwd文件与/etc/shadow文件解析.

    此文章转载自"慧可",用来学习. 1. /etc/passwd文件 1.1 /etc/passwd文件内容格式 用户名: 密码 : uid  : gid :用户描述:主目录:登陆s ...

  10. /etc/shadow,/etc/passwd,/etc/shadow,/etc/passwd文件的内容解释

    1.1 /etc/passwd文件内容格式           该目录存储的是操作系统用户信息,该文件为所有用户可见 用户名: 密码 : uid  : gid :用户描述:主目录:登陆shell 举个 ...

随机推荐

  1. mysql 5.7 学习

    MySQL5.7 添加用户.删除用户与授权   mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: ...

  2. Python3数字(Number)

    一.数学函数 二.随机数函数 三.三角函数 四.数学常量

  3. OpenResty 最佳实践 1

    建议先搜索<OpenResty最佳实践.pdf> 到网上下载openresty-1.13.6.1-win32 考虑到操作方便性,建议建立个bin目录,放入系统目录中,生成 nginx-st ...

  4. HAVANA 团队简介

    在Ensembl 下载的gtf 文件中,会有一部分来源自 HAVANA havana 的全称叫做 human  and vertebrate analysis and annotation, 是sag ...

  5. Scala学习笔记(四):apply方法说明

    当scala中类或者对象有一个主要用途的时候,apply方法就是一个很好地语法糖.请看下面一个简单的例子: class Foo(foo: String) {} object Foo { def app ...

  6. Android进阶——深入浅出Handler(一)

    Android进阶--深入浅出Handler(一) 在学习Handler之前,首先要学习一些基本概念,这将对之后的学习有所帮助. 主线程:Main Thread,又叫UI线程(UI Thread).A ...

  7. 终端IO(上)

    一.综述 终端IO有两种不同的工作方式: 规范方式输入处理.在这种方式中,终端输入以行为单位进行处理.对于每个读要求,终端驱动程序最多返回一行. 非规范方式输入处理.输入字符不以行为单位进行装配 如果 ...

  8. Android Studio开发第三篇版本管理Git

    创建项目在前一篇讲了,这里就讲一下怎么把创建的新项目关联到远程仓库呢. 在as的菜单栏找到VCS/Import into Verson Control/Create Git Repository 弹出 ...

  9. Installation Guide Ubuntu 16.04

    Beside the installation guide on the main page, here is a guide to install GenieACS off a freshly in ...

  10. 宝塔使用FTP的问题

    我们在使用宝塔FTP面板的时候,会用到FTP工具,但是开的账号在使用 FTP或WinSCP的时候会出现问题,连接不上. 具体解决方式: 参考文档: https://blog.csdn.net/hc11 ...