September 26, 2007

Automated user management with Expect

Author: Sergio Gonzalez Duran

At the large school in Mexico where I'm employed as a system manager, I proposed (and got) a Linux server to replace an old Windows 2000 file server and domain controller for the alumni. I then was faced with the task of adding 3,000 users to this new CentOS 5 server. I wasn't about to add thousands of users and their passwords one by one to the new Samba primary domain controller (PDC) system. With a little help from Calc, a utility called Expect, and shell scripts, I automated the process.

I previously set up Samba as the PDC, added groups, and configured the firewall -- all the basics -- before I began the task of adding users. I started by creating a Calc worksheet, into which I placed the student ID, full name, and school section, in a format something like this:

1 Student ID Full Name School Section
2 12345 CARDENAS LAZARO primaria
3 12467 JUAREZ BENITO secundaria

The school section is the main group for each student, and they are also members of the domain controller's users and domain_users groups. Using simple concatenation operators (&), I put it all together in the spreadsheet's fourth column (="useradd -s /sbin/nologin -G users,domain_users,"&C2&" -c """&B2&""""&" "&A2). It ends up, for each row, something like this:

useradd -s /sbin/nologin -G users,domain_users,primaria -c "CARDENAS LAZARO" 12345

I use -s /sbin/nologin because no student should be able to talk to the Linux server directly. -G adds the users to their respective supplementary groups -- very important, because they need to be recognized by Samba as part of the domain -- and the school section group is an academic control for the computer teachers.

In addition to the real users, you have to add the machines too as users both for Linux and Samba. This command should do it:

useradd -d /dev/null -g 100 -s /bin/false -c "PC001" -M PC001$; smbpasswd -a -m PC001

The above creates a null acount (without login, home dir, etc.) with the machine name PC001$ as a Linux account, then adds it as a Samba machine account (-m).

After I created the rows in Calc, I copied the resulting column into a text editor and saved it as I changed permissions to make it executable (chmod 700 and ran the script (./

The next part is the tricky one. The students are given their user names -- their student IDs -- and a password they could use to log in from their Windows XP machines, but in Samba, you first need to use the smbpasswd or pdbedit command to add the user, and it then prompts for the password. I needed a tool that allowed me to do that through a shell script and a user/password text file.

Automating with Expect

As its Web site says, with Expect "you will be able to automate tasks that you've never even thought of before." I used it to interactively add a user/password combination from a text file that feeds a smbpasswd script shell.

Since I was not going to use the old accounts, I was creating everything from scratch. Again using Calc, I entered something like this:

2 12345 r h b e 12345 rhbe
3 12467 s e g o 12467 sego

The formula I used in B:E, =CHAR(RANDBETWEEN(97;122)), generates random ASCII characters from a to z. I use only lower-case characters, and actually eight characters for the real passwords. I concatenate everything in the last column, F, then copy it to a text file. I end up with a file with two columns, username and password, and one row for each student. This file, passwords.txt, is the one that feeds the next script, which I call

while read row ; do 
   user=`echo $row | gawk '{ print $1 }'`
   pass=`echo $row | gawk '{ print $2 }'` $user $pass 
done < passwords.txt

As you can see, the script reads the file with the user/password combination and breaks each row into two variables, $user and $pass, using the gawk command. It then passes the two variables as arguments to the next script,, which is the Expect script, the one that does the magic:

#!/usr/bin/expect -f 

  set password [lindex $argv 1] 
  spawn smbpasswd -a [lindex $argv 0] 
  expect { 
        -re "password:" {sleep 1; send "$password\r"; exp_continue} 
        -re "password:" {sleep 1; send "$password\r";} 

The first line indicates that a shell script that uses Expect it is going to be executed. The -f flag prefaces a file from which commands are read. Expect receives the arguments from the first script ($user, $pass) in the argv variable which is invoked through [lindex $argv n]. Next, spawn is an Expect command that creates a new process, in this case running the program smbpasswd with the -a option to create a new Samba user. The argument for this option is the student ID that is cached with $argv 0, or the first argument ($user) passed through the first script.

Next, expect is invoked. It reads (-re) what the smbpasswd -a command send to the terminal; if you had run, for example, smbpasswd -a john, then the next line that pop ups on the screen should include the string password:, because smbpasswd is expecting user input for the password. The next set of commands are all in braces { }. Sleep 1 stops the execution for one second so the terminal is ready for the input. The send command sends the content of the $password variable along with a \r character (an Enter, just like a normal user would do). exp_continue indicates to Expect that the execution is not over, so it goes and does the same for the confirm password line. Now execution finishes, and so does the script. reads the next line from passwords.txt, and the whole process is repeated again -- in my case 3,000 times.

In less than two hours, the whole script was done, and my 3,000 users were ready to log in to the brand new Linux box, although very few students realize what they are connecting to. That is really the beauty of Samba -- let people work smoothly without worrying what tools are working on the background.

I hope and "Expect" that this kind of automation will be useful for you.


  • System Administration
Click Here!