如何用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文件,这就是文件未更新的直接原因。正确修改逻辑要点
聚焦shadow文件修改
现代Linux系统中,/etc/passwd的pw_passwd字段通常只是占位符(比如x),用户加密密码实际存储在/etc/shadow中。你需要将加密后的密码赋值给struct spwd的sp_pwdp字段,而非passwd结构体的密码字段。文件操作的安全要求
/etc/shadow和/etc/passwd是系统敏感文件,程序必须以root权限运行才能修改。- 禁止直接覆盖原文件,正确流程是:先写入临时副本,验证内容无误后再替换原文件,避免文件损坏导致系统异常。
修正后的代码示例
以下是修改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; }更安全的替代方案
- 使用PAM接口:调用
pam_chauthtok函数,这是符合Linux安全标准的方式,能自动处理密码复杂度、过期策略等系统规则。 - 调用系统命令:通过
popen执行echo -e "newpass\nnewpass" | passwd --stdin username(仅适合信任环境,注意密码泄露风险)。
- 使用PAM接口:调用
内容的提问来源于stack exchange,提问作者blitzmo
相关产品推荐
相关产品推荐

