Wednesday, December 3, 2014


{sysops, scripting, adduser, chfn}

Paul Ford sent out an e-mail to the waitlist pointing at ~pfhawkins’s list of other tildes, so I’m getting signup requests. There are enough that I want to write a script for adding a new user. I’m not determined to be very fancy about this right now; I just want to save some keystrokes.

The first thing I do is google “adduser”. adduser(1) is basically just a front end to useradd(1). (This distinction will never stop being confusing, and should probably be a lesson to anyone considering that naming pattern.) I learn via Wikipedia that the metadata (name, room number, phone, etc.) which adduser prompts for is called the GECOS field, and is a relic of something called the General Electric Comprehensive Operating System, which ran on some machines at Bell Labs.

You can change that info with chfn(1).

What my script needs to do is:

  1. create a user with a given $USERNAME
  2. generate a random password for the user and tell me
  3. do chage -d0 $USERNAME
  4. put a given public key in ~$USERNAME/.ssh/authorized_keys

You can’t log in to with a password, so why go to the trouble of setting a random one and forcing users to change it at their first login? Mostly because users are going to need to know a password for things like changing their shell or in the case that they get operator privileges one day.

This is what I come up with, after a couple of even dumber iterations:



# Complain and exit if we weren't given a path and a property:
if [[ ! $CITIZEN || ! $KEYSTRING ]]; then
  echo "usage: makecitizen <username> <key>"
  exit 64

# this should actually check if a _user_ exists,
# not just the homedir
if [ -d /home/$CITIZEN ]; then
  echo "$CITIZEN already exists - giving up"
  exit 68

PASSWORD=`apg -d -n2`

adduser --disabled-login $CITIZEN
echo "$CITIZEN:$PASSWORD" | chpasswd
chage -d 0 $CITIZEN

echo "$KEYSTRING" >> /home/$CITIZEN/.ssh/authorized_keys  

echo "passwd: $PASSWORD"

exit 0

This is used like so:

root@squiggle:~# ./makecitizen jrandomuser "ssh-rsa ..."

It’ll still do adduser interactively, which is fine for my purposes.

I think this would be improved if it took a fullname and e-mail as input, and then sent that person a message, or at least output the text of one, telling them their password.

It’d probably be improved even more than that if it operated in batch mode, was totally idempotent, and could be driven off some separate file or output containing the set of users.

(Thoughts like this are how systems like Puppet and Chef are born.)