Changing a user's password within a script doesn't work

7,616

According to: https://stackoverflow.com/questions/714915/using-the-passwd-command-from-within-a-shell-script

echo "$npasswd" | passwd --stdin user

or

echo "user:$npasswd" | chpasswd

will be good for you.

Share:
7,616
confetti
Author by

confetti

Just a bunch of colored sparkles, your average special snowflake. Obsessed with bash. Trying to get the autobiographer badge so adding onto this about me, apparently the first line isn't enough to get the badge but there's not much to tell about myself. I'm like a bag of confetti. For a few minutes it's super pretty and fun but shortly after everyone's just gonna step on you.

Updated on September 18, 2022

Comments

  • confetti
    confetti over 1 year

    For reasons I want to change a user's password to a random one every X minutes using a script. It's a debian machine, the following script is started via @reboot in root's crontab and the script is running. Every X minutes the new password is written to the file specified in the script, however, the password is never changed.

    #!/bin/bash
    # change user's password to a random one on boot and every five minutes
    
    while : ; do
        npasswd=$(pwgen 8 1)
        echo "$npasswd" > /root/current-user-passwd.txt
        usermod --password $(openssl passwd -1 "$npasswd") user
    #   echo "$npasswd" | passwd user
    #   usermod -p $(perl -e "print crypt("$npasswd","Q4")") user
        sleep 300
    done
    

    I have tried each of the three methods (the other two being commented out now), none work. However, when I copy the entire script and just paste it in a terminal to run it, it works perfectly fine. It just doesn't work in a script if it's started by cron.

    Does anyone know what is going on here?
    I've also tried echo -n by the way, same results. I've also tried to set $npasswd in the script to something fixed, just to test it, same results.

    Just to clearify: I'm really looking for an answer that explains why this is working manually, but not in a script, not for an alternative way to change the password. Those methods do work, just not if the script is started by cron.

    Output of the script with set -o errexit -o nounset -o xtrace on top:

    + :
    ++ pwgen 8 1
    + npasswd=eiZeed5u
    + echo eiZeed5u
    ++ openssl passwd -1 eiZeed5u
    + usermod --password '$1$EYRCYJXm$5XkrVNxdrYRzxBmcRwuXm0' user
    + sleep 300
    

    Output of the above when started via cron's @reboot:

    + :
    + pwgen 8 1
    + npasswd=aizof5Ka
    + echo aizof5Ka
    + openssl passwd -1 aizof5Ka
    + usermod --password $1$KFrgibYH$e1dMUeF2AzTtSPExBjbXo1 user
    /root/change-user-passwd.sh: 8: /root/change-user-passwd.sh: usermod: not found
    

    Which makes the issue clear to me now, thanks @l0b0!

    • confetti
      confetti over 5 years
      @l0b0 It's neither. I just needed a temporary password that works only once to login, once the login session ended the password should not work anymore. (Therefore, the every X minutes isn't exactly a requirement, I'd still like to know why this isn't working at all in a script while it does when run manually.)
    • confetti
      confetti over 5 years
      @l0b0 But that wouldn't answer my actual question, that's why I didn't include the information. I'm sure there's another way to create on-time passwords (passwd itself has the --expire option), but I'd really like to know what's causing this particular issue of it working when run manually, but not inside of a script.
    • l0b0
      l0b0 over 5 years
      How are you checking that the password is not changed? Do you have more code to report what the password was changed to in your script?
    • confetti
      confetti over 5 years
      @l0b0 I'm trying to physically log into the machine (lightdm login screen) with the new password, it doesn't work. Logging in via ssh as the user with the changed password doesn't work either. If I manually run those commands, it works. If I run it in the script, nothing's changed (the old password still works).
    • confetti
      confetti over 5 years
      @l0b0 I'm sorry, I've just edited my question. Turns out if I run the script manually it does work. It just doesn't work when cron starts it. The file does get updated, but the password never changed. Do you still want me to do your suggestion?
    • l0b0
      l0b0 over 5 years
      Yes, it should give lots of information about what the problem is.
    • confetti
      confetti over 5 years
      @l0b0 Done, appended the output to my question. If I want to log this information when the script is started by cron, stderr is what I write into a logfile, correct?
    • l0b0
      l0b0 over 5 years
      Did the script work or not when you ran it with those flags set?
    • confetti
      confetti over 5 years
      @l0b0 It worked, when invoked using bash script.sh. I didn't try it using cron yet.
    • confetti
      confetti over 5 years
      @l0b0 There's only the crontabs within that directory, I tried to use &> logfile to redirect it, but now cron doesn't seem to be able to start the script at all. If I run it manually (with the same redirection, same command as in crontab) it works and the output is written to the file, but cron doesn't even start the script now (checked with ps aux, it would always show up before). All I did was add the set line and the redirection. I checked /var/log/syslog - Cron did execute the command. I'm not sure what happened at all.
    • confetti
      confetti over 5 years
      @l0b0 Alright, that was my fault. Cron is using sh instead of bash and &> is a bash thing. Now the issue is clear, thank you so much. I assume the same issue (cron having a different shell and $PATH) is causing usermod not to be found? usermod's binary is indeed not in /usr/bin, but in /usr/sbin. Do you want to leave a full answer so I can accept it? Edit: Confirmed. Supplying full path for usermod within the script fixed it. Everything works as expected now.
  • confetti
    confetti over 5 years
    My passwd doesn't have the --stdin option. The pipe of the second command seems weird to me. Why pipe echo to the command when $npasswd is provided to chpasswd directly? I've tried it on the command-line: chpasswd: line 1: missing new password
  • confetti
    confetti over 5 years
    I think I got it from man chpasswd. I have proposed an edit to your answer of the correct usage for chpasswd, may you please accept it? It works manually, I'll try it in a script now.
  • minish
    minish over 5 years
    Thanks for correction! And I wish helps your problem solve.