zoukankan      html  css  js  c++  java
  • /etc/passwd- 和/etc/shadow-文件

    今天偶尔看到系统里有/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 ", 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 ", 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++ = '';
    /* 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, " ");
    }
    } 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 ", name_colon, new_passwd,
    (unsigned)(time(NULL)) / (24*60*60), cp);
    } else {
    /* "name:" + "new_passwd" + ":rest of line" */
    fprintf(new_fp, "%s%s%s ", 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 ", 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;
    }

  • 相关阅读:
    操作系统之进程篇(3)
    指针和数组及内存管理
    进程篇(3: 基本进程控制:进程的退出)--请参照本博客“操作系统”专栏
    Java面向对象程序设计--泛型编程
    进程篇(1: 进程运行环境)--请参照本博客“操作系统”专栏
    操作系统之进程篇(1)
    分类器性能指标之ROC曲线、AUC值
    如何理解似然函数?
    sigmoid函数简介
    Hive分析窗口函数
  • 原文地址:https://www.cnblogs.com/wangliangblog/p/8695690.html
Copyright © 2011-2022 走看看