SUMMARY: useradd automation

From: 0000-Admin0000 (
Date: Mon Sep 11 1995 - 17:47:09 CDT


Thanks for the overall helpful response to a probably
commonly asked question. Here is a summary for those who
mailed wanting one:

From: Phillip Plane <>

Here's a perl script I wrote to add groups of users on my Solaris system.
It creates files to append onto passwd and shadow. You could modify it
to do what you want.

# makes a passwd file entry
# input file format is:
# StudentIDnumber,surname,firstname,otherstuff
# as obtained from the registry system.
# ID number is used as the initial password
# This program adds groups of students in an orderley manner.
# - checks to see if this user, or a conflicting user already exists.
# if the user already exists, just puts them in the relevant group.
# - checks to see if a home directory already exists.
# - if it's all OK, creates the passwd and shadow entries,
# with the student ID as the password, a suitable expiry date etc.
# - creates a home directory, copies /usr/local/skel, and sets the perms.
# - gives the user a disk quota.
# - puts the user into the relevant group.
# - adds the student to the mail database
$maxuid = 0;
$passfile = "/etc/passwd";
$shadow = "/etc/shadow";
# number of days since Jan 1 1970
$lastchg = int(time/86400);
$min = 0;
$max = 90;
$warn = 7;
$inactive = "";
$expire = "";
$flag = "";
$gfe = "";
$course = $ARGV[0];
die "usage: makecourse coursefile\n where coursefile is the file from registry for the course,\n with only the lines of student data,\n and the name of the file is the course number. e.g. 57101\n" if !-f $course;
die "/etc/passwd file busy - try again later.\n" if -f 'ptmp';
open(PASSWD,$passfile) || die "Can't open $passfile\n";
while(<PASSWD>) {
  ($login,$passwd,$uid,$gid,$gcos,$home,$shell) = split(/:/);
  if ($uid < 60000){
    if ($uid > $maxuid) {
      $maxuid = $uid;
print "max uid = $maxuid\n";
print "\n\n";
 open(PASS,">addpass") || die "Can't open add addpass\n";
open(SHADOW,">addshadow") || die "Can't open addshadow\n";
open(MAILDB,">new.students") || die "Can't open new.students";
while(<USERS>) {
  # seperate at commas
  ($sid,$sname,$fname,$junk) = split(/,/);
  # remove quotes
  $sid =~ s/\"//g;
  $sname =~ s/\"//g;
  $fname =~ s/\"//g;
  # remove whitespace from surnames like Van der thingy
  $sname =~ s/ //g;
  # remove quotes from O'Brien
  $sname =~ s/'//g;
  # remove hyphens from snobs
  $sname =~ s/-//g;
  # get first character of first name
  $a = substr($fname,0,1);
  #get first 7 characters of surname
  $b = substr($sname,0,7);
  $login = $a . $b ;
  #lower case everything
  $login =~ tr/A-Z/a-z/;
  # check to see if the user already exists.
  if ( grep(/$login/,@lognames) ){
    print "$login is already in $passfile\n"
  else {
    $uid += 1;
    $home = "/home/students/$login";
    $salt = substr($login,0,4);
    $passwd = crypt($sid,salt);
    $gfe .= $login . ",";
    if ( -d $home ){
      print "$login - home directory already exists!!";
    else {
      print PASS "$login:x:$uid:500:$fname $sname:$home:/usr/local/bin/tcsh\n";
      print SHADOW "$login:$passwd:$lastchg:$min:$max:$warn:$inactive:$expire:$f
      print SCRIPT "mkdir $home\n";
      print SCRIPT "chmod 700 $home\n";
      print SCRIPT "cp /etc/skel/.??* $home\n";
      print SCRIPT "chown -R $login $home\n";
      print SCRIPT "edquota -p dummy $login\n";
      print MAILDB "$login $sid\\n";
close USERS;
close SCRIPT;
close PASS;
close SHADOW;
close MAILDB;
open(GROUP,">addgroup") || die "Can't open addgroup\n";
# remove comma from end of line.
$gfe =~ s/\,$/\n/;
print GROUP "$course::$course:$gfe";
close GROUP;

From: Simon Burr <>

We have the same problem here (we're an ISP), and all of the account generation
is done via a single script. So long as your not wanting to descend into the
hell of NIS+, you can easily do the work required.

All you need to do is to have 2 C programs. One which generates the password,
and the other that encrypts it. You just need to kludge the /etc/shadow
entries.... and then add them to the end of /etc/shadow.

To be honest, I've found that doing this, along with a bit of sh that generates
the stuff for /etc/passwd, is the best way to do it. You don't even need to go
*close* to useradd :) I've appended the source for the program to the bottom
of this mail.

You can compile it with a straight cc (or gcc), and it runs as:

accounts@zeus[303]% encpwd test

Where it has encrypted the password "test". Yes, I know it is a security risk
to have the password on the command line (if you're worried about it, combine
the password generation and the encryption into one, and have it return both
the password and the encrypted password on the stdout), but its not that much
of one as the program is quite fast.

Hope this helps.

===== Begin source for encpwd.c

#include <stdio.h>
#include <stdlib.h>
#include <crypt.h>
#include <time.h>
#include <sys/types.h>

#define MAX_RAND 32767

int rand_num(sz)
int sz;
  int res;
  double ran;
  int x;

void set_rand()
  time_t t;
  time_t t2;
  srand((unsigned) t);

char rchar()
  char c=91;

char *salt()
  char *res;
  res=(char *)malloc(sizeof(char)*3);

int main(argc,argv)
int argc;
char **argv;
  int x;
  char *str;

===== End source for encpwd.c

Simon Burr   (       |
Systems Manager and Programmer       |   Total Connectivity Providers Ltd 
          I *don't* speak for my company, my boss does that
                      Is there an LD50 for chocolate ?


From: (Mike Jipping)

We use a "newuser" script for people (and faculty) to request user ids. It generates the password for the user.

I have attached two files. First is "newuser" -- the request script. The second is the "processor script". I use this to transform the one line mail message into a shell script that runs on the server. Note that it's got a lot of NIS+ table additions.

Hope this helps.

------------------------------------------------------------- Mike Jipping | Hope College | (616) 395-7509 Department of Computer Science |

"... Dogs are the leaders of the planet. If you see two life forms, one of them's making a poop, the other's carrying it for him, who would you assume is in charge?" -- Jerry Seinfeld, "SeinLanguage"

---------- X-Sun-Data-Type: default-app X-Sun-Data-Description: default X-Sun-Data-Name: newuser X-Sun-Charset: us-ascii X-Sun-Content-Lines: 167


@saltset = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/'); @alphabet = ('A' .. 'Z', 'a'..'z', '0'..'9'); $oldaccount = $ARGV[0]; shift; $username = $oldaccount; $first_name = ""; $last_name = ""; $address = ""; $phone = ""; $maiden = "";

sub getresp { $response = ""; while (length($response) == 0) { $response = <>; chop($response); if (length($response) == 0) {print(" You need to enter a non-empty response: ");} } return $response; }

sub setupinfo { print("First Name: "); $first_name = &getresp(); if ($first_name eq "quit") {return -1;} print("Last Name: "); $last_name = &getresp(); if ($last_name eq "quit") {return -1;} print("Are you a CS major or taking a CS class? "); $in_CS = &getresp(); if ($in_CS eq "quit") {return -1;} $in_CS =~ y/A-Z/a-z/; $duplicate = 1; while ($duplicate) { $username = substr($last_name,0,8); $username =~ y/A-Z/a-z/; $username =~ s/ //g; $username =~ s/\t//g; print("\nWhat would you like your user name to be?\n"); print("Entering an empty name will give you the user name '$username': "); $un = <>; chop($un); if ($un eq "quit") {return -1;} if (length($un) > 0) { $username = substr($un,0,8); $username =~ y/A-Z/a-z/; $username =~ s/ //g; $username =~ s/\t//g; } # Check passwd $duplicate = 0; $tmpuid = 0; system("niscat passwd.org_dir >/tmp/na1$$"); open(PASSWD, "</tmp/na1$$") || die "ERROR: Can't open passwd file"; while (<PASSWD>) { ($login,$passwd,$uid,$rest) = split(/:/); if (($uid > $tmpuid) && ($uid < 10000)) {$tmpuid = $uid;} if ($login eq $username) { $duplicate = 1; last; } } close PASSWD; unlink("/tmp/na1$$");

if ($duplicate) { print("That name is already taken. Please choose another.\n"); } } return 0; }

sub reviewinfo { print("\n\nHere's a review of your information:\n"); print(" Name is $first_name $last_name\n"); if (substr($in_CS,0,1) eq "y") { print(" You are a CS major or are taking a CS class.\n"); } else { print(" You are neither a CS major nor taking a CS class\n"); } print(" Preferred username is \"$username\"\n");

print("\nIs this correct (answer with y or n)? "); $resp = <>; chop($resp); if ($resp eq "quit") {return -1;} $resp = substr($resp,0,1); $resp =~ y/A-Z/a-z/; if ($resp eq "y") { $ok = 1; } else { print("\nPlease enter new information:\n\n"); $ok = 0; } return 0; }


print " Welcome to Hope College Department of Computer Science Sun Lab.

Your first step in using the lab is to have an account created on our system. Please fill in the following information, and your request information will be forwarded to the system administrator. Most of the time, requests are processed in 24 hours.

IMPORTANT: Pick up and read the handout on lab policies from the lab. A copy will also be sent to you via electronic mail. You will be given a chance to review and re-enter your information if you make any mistakes. We cannot add accounts requested with incomplete data. Enter 'quit' in any field to return to the menu. ";

$ok = 0; while (! $ok) { if (&setupinfo() < 0) {exit(-1);} if (&reviewinfo() < 0) {exit(-1);} }

# select a random password. srand(time); $passwd = ""; $charnum = 1; while ($charnum <= 8) { $passwd = $passwd . $alphabet[int(rand(62))]; $charnum = $charnum + 1; # }

$now = $time; ($pert1, $pert2) = unpack("C2", $username); $week = $now / (60*60*24*7) + $pert1 + $pert2; $nsalt = $saltset[$week % 64] . $saltset[$now % 64]; $cryptpass = crypt($passwd,$nsalt);

$realuid = $tmpuid+1; $passwdline = $username . ":" . $cryptpass . ":". $realuid . ":15:$first_name $last_name:/home/$username:/usr/contrib/bin/tcsh";

print("\nYour password will be \"$passwd\". Make sure you change it often.\n"); # open(WORK, ">/tmp/na$$") || die("ERROR: request processing error!"); print(WORK "*** Request for new ID ***\n\n"); print(WORK "*** Requested by: " . getlogin() . "\n\n"); print(WORK "Name: $first_name $last_name \n"); if (substr($in_CS,0,1) eq "y") { print(WORK "Person is a CS major or is taking a CS class.\n"); } else { print(WORK "Person is not a CS major and is not taking a CS class\n"); } print(WORK "Preferred username is \"$username\"\n\n"); print(WORK $passwdline . ":$passwd\n"); close WORK;

system("/usr/ucb/mail -s \"NEW ID: $username requested\" jipping </tmp/na$$");

unlink("/tmp/na$$"); ---------- X-Sun-Data-Type: default-app X-Sun-Data-Description: default X-Sun-Data-Name: newproc X-Sun-Charset: us-ascii X-Sun-Content-Lines: 28

#!/usr/contrib/bin/perl # $tmpfile = "/home/jipping/NEWUSER$$"; open(tmpfd, ">".$tmpfile) || die "Can't open temp file\n"; while (<>) { chop; ($name,$passwd,$uid,$gid,$gcos,$home,$shell,$rpasswd) = split(/:/,$_); print(tmpfd "nistbladm -a name=$name passwd=\"$passwd\" uid=$uid gid=$gid gcos=\"$gcos\" home=$home shell=$shell shadow=\":0:-1:-1:-1:-1:0\" passwd.org_dir\n"); print(tmpfd "mkdir /home/$name\n"); print(tmpfd "cp /etc/skel/.* /home/$name\n"); print(tmpfd "chown -R $name /home/$name\n"); print(tmpfd "nistbladm -a alias=$name expansion=\"$name@smaug\" mail_aliases.org_dir\n"); print(tmpfd "nistbladm -a key=$name value=smaug:$home auto_home.org_dir\n"); print(tmpfd "nisaddcred -p $uid -P $ LOCAL\n"); print(tmpfd "nisaddcred -p unix.$ -P $ -l $rpasswd DES\n"); print(tmpfd "#\n"); print(tmpfd "mail -s \"READ THIS FIRST: Welcome...\" $name </home/jipping/lab/documents/first-user.txt\n"); print(tmpfd "echo ======== WELCOME TO THE SUN LAB ========= >/tmp/userinfo\n"); print(tmpfd "echo \" \">>/tmp/userinfo\n"); print(tmpfd "echo Your userid is \"$name\".>>/tmp/userinfo\n"); print(tmpfd "echo Your home directory is \"/home/$name\".>>/tmp/userinfo\n"); print(tmpfd "echo Your password is \"$rpasswd\".>>/tmp/userinfo\n"); print(tmpfd "nenscript /tmp/userinfo\n"); }

------------------------------------------------------------------------------ From: Eric Shafto <>

I use a very simple perl script to create users. It would be trivial to modify it to prompt for a password in addition to first and last name, and have it do the passwd as well as the useradd.

------- #!/bin/perl

print "#!/bin/csh\n\n"; while (<>) { chop($_); s/\s(\w)\.//; $mi = $1; /(\w+)\s+(\w+)/; $fname = $1; $finit = substr($fname,0,1); $lname = $2; $trimname = substr($lname,0,7); $uname = "\L${finit}$trimname"; $fullname = "$fname $lname"; system("useradd -s/sbin/tcsh -f180 -gfaculty -m -c \"$fullname\" $uname\n"); } ------- This one is set up to take a file of the form fname [Mi.] lname and create the corresponding users. If you have perl, but don't have the savvy to fix this to meet your needs, let me know and I'll do it for you.

Eric Shafto Dir. Academic Computing, Lake Forest Academy * * * Congress shall make no law regarding the establishment of religion; or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.


Other suggestions were to use expect as it includes some example code of passwd generation, and also to use perl with pwconv. Shout outs to everyone who mailed.


Evan Baer ============================================================= = Evan Baer Network Consultant = = Planet Internet = = = =============================================================

This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:10:33 CDT