[英]Changing Linux username or password with Python script
I'm writing a Python script that changes the username and password of a Linux account user - it's part of a larger internal web-gui system that queues up password change requests from apache2
(which can't run as root), and then changes the passwords itself. 我正在写一个Python脚本来更改Linux帐户用户的用户名和密码-它是一个较大的内部Web-gui系统的一部分,该系统将
apache2
(不能以root身份运行)中的密码更改请求排队,然后进行更改密码本身。 The python script itself obviously must run as root in order to change passwords. 显然,python脚本本身必须以root用户身份运行才能更改密码。
The password change function is pretty straightforward: 密码更改功能非常简单:
def chpasswd(user, passwd):
if os.getuid() != 0:
syslog.syslog("Error: chpasswd.py must be run as root")
return
proc = Popen(
['/usr/sbin/chpasswd'],
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
print "Changing: " + user + ':' + passwd
out, err = proc.communicate(user + ':' + passwd)
proc.wait()
print out
if proc.returncode != 0:
print "Error: Return code", proc.returncode, ", stderr: ", out, err
if out:
syslog.syslog("stdout: " + out)
if err:
syslog.syslog("stderr: " + err)
The print
statements are just there for temporary debugging. print
语句仅用于临时调试。 This runs fine and doesn't report any errors - there's nothing on out
or err
; 这样可以很好地运行,并且不会报告任何错误-没有任何
out
err
。 but for some reason the actual UNIX password simply isn't changed . 但是由于某些原因,实际的UNIX密码根本没有改变 。
The script which invokes this function is listening on a locally bound TCP socket. 调用此功能的脚本正在本地绑定的TCP套接字上侦听。 When it receives a change password request (in the form of
user:password
- later to be encrypted but for now plaintext) it adds it to a queue and then invokes the chpasswd
function. 当它收到一个更改密码请求时(以
user:password
的形式-稍后将被加密,但现在是纯文本形式),它将其添加到队列中,然后调用chpasswd
函数。
So, typical usage would be: 因此,典型用法是:
# telnet localhost 7001
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
jsmith:mynewpassword
When the server is running in a bash window (not as a daemon) it prints out: 当服务器在bash窗口(而不是作为守护程序)中运行时,它将输出:
# python chpasswd.py
Starting Password Server
New connection from: 127.0.0.1
Changing: jsmith:mynewpassword
The last statement, you can see, is the print
statement in my chpasswd
function. 您可以看到,最后一条语句是
chpasswd
函数中的print
语句。
But after doing the above, when I actually try to login as a user using the new password, I get: 但是完成上述操作后,当我实际上尝试使用新密码以用户身份登录时,我得到:
$ su jsmith
Password:
su: Authentication failure
Is there some obvious thing I'm doing wrong here? 我在这里做错了什么明显的事情吗? My suspicion was that somehow the connection with
Popen
is not actually closing, or perhaps the single line user:password
text is not being transmitted. 我的怀疑是与
Popen
的连接实际上没有关闭,或者单行user:password
文本没有被传输。 So I tried doing something like: 所以我尝试做类似的事情:
out, err = proc.communicate(user + ':' + passwd + '\x04')
Notice the extra \\x04
character at the end, indicating End Of Transmission. 请注意
\\x04
处有额外的\\x04
字符,表示传输结束。 Adding this in still didn't get it to work however - the password remained unchanged. 仍然没有添加它-密码保持不变。
I'm running this on Debian Wheezy, in case it makes any difference. 我正在Debian Wheezy上运行此程序,以防万一。
Update: 更新:
Investigating further, I can see that my chpasswd
function actually is changing the password - if I cat
the /etc/shadow
file before and after connecting to my password server, I see there is a different hash. 进一步调查,我可以看到我的
chpasswd
功能实际上就是更改密码-如果我cat
的/etc/shadow
前,连接到我的密码服务器后的文件,我看到有一个不同的哈希值。
It's just that when I try to authenticate using the plaintext password, it doesn't work. 只是当我尝试使用纯文本密码进行身份验证时,它不起作用。 Therefore, my suspicion is that somehow, the communication with
Popen
is either adding additional characters, or losing characters somehow. 因此,我怀疑与
Popen
的通信是添加其他字符还是丢失字符。 Of course, since /etc/shadow
is a hash, I can't figure out exactly what's going on here. 当然,由于
/etc/shadow
是一个哈希,所以我无法弄清楚这里到底发生了什么。
The problem in this particular instance was that telnet adds "\\r\\n"
after you press return on entering text. 在此特定实例中的问题是,在输入文本时按回车键后,telnet会添加
"\\r\\n"
。 Since your server was not stripping the data of whitespace this was preserved when changing the password. 由于您的服务器没有剥离空白数据,因此在更改密码时将保留该数据。
It is possible to get telnet to not send the carriage return and newline characters by ending a line with the end-of-transmission character (EOT). 通过以传输结束字符(EOT)结束一行,可以使telnet不发送回车符和换行符。 You can do this by pressing Ctrl-D.
您可以通过按Ctrl-D来执行此操作。
eg 例如
$ telnet localhost 7001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
jsmith:mynewpassword^DChanging: jsmith:mynewpassword
Alternatively you can pipe the line into telnet 或者,您可以将线路通过管道连接到telnet
echo -n jsmith:mynewpassword | telnet localhost 7001
Obviously, you'll only want to do this for testing or the new password will end up in your shell history. 显然,您只想这样做进行测试,否则新密码将出现在您的Shell历史记录中。 (The
-n
argument suppresses the printing of newline characters by echo
) (
-n
参数通过echo
抑制换行符的打印)
Or you might want to do away with telnet
altogether and use netcat
instead. 或者,您可能希望完全取消
telnet
并改用netcat
。
echo -n jsmith:mynewpassword | netcat localhost 7001
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.