简体   繁体   English

使用Python脚本更改Linux用户名或密码

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM