You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++程序修改Linux用户密码?现有代码无法生效求指导

问题描述

我想写一个能修改Linux用户密码的C++程序,查了<pwd.h>里的putpwent函数和<shadow.h>里的putspent函数,写了下面的代码:

int main() {
    string username = "user";
    string password = "4321";

    struct passwd *pw = getpwnam(username.c_str());
    struct spwd *sp = getspnam(username.c_str());

    if (pw == NULL || sp == NULL) {
        cerr << "Failed to get user information." << endl;
        return 1;
    }

    char *encrypted_password = crypt(password.c_str(), sp->sp_pwdp);

    pw->pw_passwd = encrypted_password;

    if (putpwent(pw, stdout) != 0) {
        cerr << "Failed to update password." << endl;
        return 1;
    }

    if (putspent(sp, stdout) != 0) {
        cerr << "Failed to update shadow file." << endl;
        return 1;
    }

    return 0;
}

程序能正常运行,但/etc/shadow里的密码没改。程序输出的新密码内容是:

user:$6$jhci4oxH6C4h9off$AwzsRAjJUh21Sf2DY7ktY5KdNbYG3YhsdjTshU8FanJF/pfqRcq8jiR6Jvq/cbubiMbTO50HU7w79Tx2DQnwq/:1001:1001::/home/user:/bin/bash

而/etc/shadow里的旧密码还是:

user:$6$jhci4oxH6C4h9off$.SEwXqgYa1Un5t8rTdVCccicmk3sxLW5NPMqiSdBNcGBNX.pO404Cuic8Wdv7N4IhNVl3KmhtiKunUbjBQq3U0:19515:0:99999:7:::

求实现修改密码功能的指导方案。

解决方案
  • 核心问题:输出方向错误
    你的代码里putpwent和putspent都是把内容输出到stdout(标准输出),而非写入/etc/passwd和/etc/shadow文件,这就是文件未更新的直接原因。

  • 正确修改逻辑要点

    1. 聚焦shadow文件修改
      现代Linux系统中,/etc/passwd的pw_passwd字段通常只是占位符(比如x),用户加密密码实际存储在/etc/shadow中。你需要将加密后的密码赋值给struct spwd的sp_pwdp字段,而非passwd结构体的密码字段。

    2. 文件操作的安全要求

      • /etc/shadow和/etc/passwd是系统敏感文件,程序必须以root权限运行才能修改。
      • 禁止直接覆盖原文件,正确流程是:先写入临时副本,验证内容无误后再替换原文件,避免文件损坏导致系统异常。
    3. 修正后的代码示例
      以下是修改shadow文件的简化实现(需root权限运行):

      #include <iostream>
      #include <string>
      #include <pwd.h>
      #include <shadow.h>
      #include <fstream>
      #include <unistd.h>
      #include <crypt.h>
      
      using namespace std;
      
      int main() {
          string username = "user";
          string password = "4321";
      
          struct spwd *sp = getspnam(username.c_str());
          if (sp == NULL) {
              cerr << "Failed to get shadow information." << endl;
              return 1;
          }
      
          // 生成加密密码
          char *encrypted_password = crypt(password.c_str(), sp->sp_pwdp);
          if (encrypted_password == NULL) {
              cerr << "Crypt failed." << endl;
              return 1;
          }
      
          // 创建临时文件存储修改后的shadow内容
          ofstream temp_shadow("/tmp/shadow.tmp");
          if (!temp_shadow.is_open()) {
              cerr << "Failed to create temp file." << endl;
              return 1;
          }
      
          // 遍历所有shadow条目,替换目标用户的密码
          setspent();
          struct spwd *entry;
          while ((entry = getspent()) != NULL) {
              if (string(entry->sp_namp) == username) {
                  struct spwd new_sp = *entry;
                  new_sp.sp_pwdp = encrypted_password;
                  putspent(&new_sp, temp_shadow.rdbuf());
              } else {
                  putspent(entry, temp_shadow.rdbuf());
              }
          }
          endspent();
          temp_shadow.close();
      
          // 替换原shadow文件
          if (rename("/tmp/shadow.tmp", "/etc/shadow") != 0) {
              cerr << "Failed to replace shadow file." << endl;
              unlink("/tmp/shadow.tmp");
              return 1;
          }
      
          cout << "Password updated successfully." << endl;
          return 0;
      }
      
    4. 更安全的替代方案

      • 使用PAM接口:调用pam_chauthtok函数,这是符合Linux安全标准的方式,能自动处理密码复杂度、过期策略等系统规则。
      • 调用系统命令:通过popen执行echo -e "newpass\nnewpass" | passwd --stdin username(仅适合信任环境,注意密码泄露风险)。

内容的提问来源于stack exchange,提问作者blitzmo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 20:35:00