Acct-gen.pl

From In The Wings
Jump to navigation Jump to search
#!/usr/bin/perl
#

# Still a little rough, but it does work. Autogenerates the UID given a GID,
# but since we have moved some people group wise this is bound to get
# a little odd looking.

use Net::LDAP;
use Net::LDAP::Util;
use Net::SSH::Perl;
use Mail::Sendmail;
use LWP::Simple;

$userName = $ARGV[0];
$uid = $userName;

if (!$userName) {
    print "Usage: acct-gen.pl <username>\n";
    exit;
}

# Get some data from the user
#
print "Email address: ";
$email = <STDIN>;
print "Name: ";
$name = <STDIN>;

# Go and print the list of groups available
#
print "Available Groups\n";
print "================\n";
&GetGroups;
print "================\n";

print "GID: ";
$gid = <STDIN>;
#print "UID number: ";
#$uidNumber = <STDIN>;
$uidNumber = &getUID($gid);

print "Adding " . $userName . "\n";

print "New uid Number: " . $uidNumber . "\n";

# Organizational Units
print "\n";
print "What Organizational Unit is this user in? (Department)\n";
$OrgUnit = <STDIN>;

# Boilerplate login data
#

$ldapServer     = "ldap1.ufhpc";
$rdn            = "cn=slapman";
$base           = "dc=hpc,dc=ufl,dc=edu";
$bindPasswd     = '';
$searchBase     = "ou=People," . $base;
$dn = "uid=" . $userName . "," . $searchBase;
$BindDn = $rdn . "," . $base;

# Connect and bind to the LDAp server
#
$ldap = Net::LDAP->new( $ldapServer );

$bindDc         = $rdn . "," . $base;
$mesg = $ldap->bind( $BindDn, password => $bindPasswd, version => 3);
if ( $mesg->is_error() ) {
  print "Error: bind failed.\n";
  exit;
}
#
# Generate a new password
$newPassword = &newPass;

# Testing Email
#&notifyMail($userName, $newPassword, $email);
#exit;

# Generate creation and expiration dates for the password
#

$shadowLastChange = int(time / 86400);
$shadowExpire = $shadowLastChange + 180;

# Have to chop these two because they have carriage returns after them.
# This causes havok in the gecos entry if we leave them in there.
chop $name;
chop $email;

# Note that we force uidNumber and gidNumber to be of type int here. This
# is so that ldap doesn't barf.
$result = $ldap->add(dn => $dn, 
                     attr => [ 'uid' => $uid,
                               'cn' => $userName,
                               'userPassword' => $newPassword,
                               'uidNumber' => int($uidNumber),
                               'gidNumber' => int($gid),
                               'gecos' => $name . ", " . $email,
                               'loginShell' => "/bin/bash",
                               'homeDirectory' => "/home/" . $userName,
                               'shadowLastChange' => $shadowLastChange,
                               'shadowMin' => 0,
                               'shadowMax' => 180,
                               'shadowWarning' => 7,
                               'shadowInactive' => 30,
                               'shadowFlag' => 0,
                               'shadowExpire' => $shadowExpire,
                               'ou' => $OrgUnit,
                               'objectClass' => [ 'top',
                                                'account',
                                                'posixAccount',
                                                'shadowAccount'
                                                ]]);

if ($result->is_error()) {
    print "\n";
    print "Creations error: " . $result->error_name . "\n";
    print $result->error_text . "\n";
    print $result->error_desc . "\n";
    print $result->error . "\n";
    exit;
}


print "Account created with password: " . $newPassword . "\n";

# And then we need to add this home directory into autofs
#system("scp racksrv:/opt/cluster/config/auto.home auto.home");
&genAutoHome($userName);

# Now we need to go and create the home directory for this person.
&genHome($userName,$gid,$newPassword);

# Next we send out an email detailing the account.
&notifyMail($userName,$newPassword,$email);

# Subscribe them to Bugzilla
&genBugzilla($email, $name);

# And finally, add them to the gridusers mailing list
&genGridUsers($email);
# Copying over auto.home
#print "Copying over auto.home to racksrv.\n";
#system("scp auto.home racksrv:/opt/cluster/config/auto.home");

print "Account creation completed\n";
exit;

##########################################################################
##########################################################################
## END MAIN PROGRAM END MAIN PROGRAM END MAIN PROGRAM END MAIN PROGRAM ###
##########################################################################
##########################################################################

sub genBugzilla($email, $name) {
    my $name2 = $name;
    $name2 =~ s/ /\%20/g;
    my $url = 'http://bugzilla.hpc.ufl.edu/createaccount.cgi?login=' . 
        $email . '&realname=' . $name2;
    print $url . "\n";
    my $content = get $url;
}

sub genGridUsers($email) {
    $add_members = "/usr/lib/mailman/bin/add_members";
# We have to do it this way because hpc manages the mailing list.
    system("ssh hpc.ufhpc 'echo $email > /tmp/email.txt'");
    system("ssh hpc.ufhpc $add_members -r /tmp/email.txt gridusers");
    system("ssh hpc.ufhpc rm /tmp/email.txt");
    return;
}

sub RANDchar{
    $i = rand();
    $i *= 52;
    $i = int($i);
    return @chars[$i];
}

sub GetGroups{
    $ldapServer = "ldap1.ufhpc";
    $base = "dc=hpc,dc=ufl,dc=edu";
    $searchBase = "ou=Group," . $base;
    
    $ldap = Net::LDAP->new($ldapServer);
    $mesg = $ldap->bind();
    if ($mesg->is_error()) {
        print "Error: bind failed.\n";
        exit;
    }
    $result = $ldap->search(filter=>"(cn=*)",
                            base=>$searchBase,
                            attrs=> ['gidNumber', 'cn'] );
    while( my $entry = $result->shift_entry) {
        foreach my $attr ($entry->attributes) {
            foreach my $value ($entry->get_value($attr)) {
                print $value, " ";
            }
        }
    }
    print "\n";
    $mesg = $ldap->unbind();
}

sub getUID($gid) {
    # Make the uid we are returning at least as high as the gid, so that if
    # this is a new group it will automatically be incremented by one to the
    # gid + 1.
    $highest = $gid; 
    setpwent; # Initialize passwd entry scan
    while (@list = getpwent) { # fetch the next entry
        if ($gid == @list[3]) {
            if (@list[2] > $highest) {
                $highest = @list[2];
            }
        }
    }
    $highest+=1;
    # Check to be sure that we aren't overwriting something here...
    while (getpwuid($highest)) {
#       print "Bad UID (" . $highest . ") Moving to next one!\n";
        $highest+=1;
    }
    return $highest;
}

sub newPass {
# Generate a random password
# Thanks to David Parks for this one
#
    @chars = ("2","3","4","6","7","9","q","w","e","r","t","y","u","i","o",
              "p","a","s","d","f","g","h","j","k","z","x","c","v","b","n",
              "m","Q","W","E","R","T","Y","U","P","A","D","F","G","H","J",
              "K","L","Z","X","C","V","N","M");

    $newPassword = join('', &RANDchar,&RANDchar,&RANDchar,&RANDchar,
                        &RANDchar,&RANDchar,&RANDchar,&RANDchar,&RANDchar,
                        &RANDchar);
    return $newPassword;
}

# Generate a home directory on submit. Right now this uses a script located on
# submit that should really be implanted here.
sub genHome($userName, $gid, $newPassword) {
    $homedir = "/ufhpc/racksrv/home";
    $scmd = "ssh -x submit";
#    system("$scmd mkdir $homedir/$userName");
#    system("$scmd mkdir $homedir/$userName/.ssh");
#    system("$scmd ssh-keygen -t rsa -f $homedir/$userName/.ssh/id_rsa -N \'\'");
#    system("$scmd cp $homedir/$userName/.ssh/id_rsa.pub $homedir/$userName/.ssh/authorized_keys");
#    system("$scmd cp /etc/skel/.[a-z]* $homedir/$userName/");
#    system("$scmd chown -R $userName.$gid $homedir/$userName");
    $stuff = "$scmd /usr/local/bin/acct-gen $homedir/$userName $userName $gid";
    system($stuff);
}

# Generate the autohome entry and get it fired off into ldap.
#
sub genAutoHome($userName) {
    $autohome = "/opt/cluster/config/auto.home";
    $location = "\${HOST}:/ufhpc/racksrv/home/";
    open(AUTOFILE, ">>$autohome") ||
        die "Could not open \$autohome\n";
    printf AUTOFILE "%-17s%s%s\n", $userName, $location, $userName; 
    close(AUTOFILE);
    system("cd /opt/cluster/config; ./mkautomount auto.home");
    system("touch /opt/cluster/config/.auto.home.ts");
}


# Generate and send an email to the new user detailing the account
#     
sub notifyMail($userName, $newPassword, $email) {
    $text = <<END_OF_BODY;
Your account for the HPC cluster has been created. All jobs are to be
submitted using the Torque batch systems.  Links to the Torque documentation 
is located here:

http://wiki.hpc.ufl.edu/index.php/Job_Submission_Queues

Other documentation can also be seen at the wiki pages:

http://wiki.hpc.ufl.edu 

Your login credentials are as follow:

Username: $userName
Password: $newPassword

The machine to use for logins via ssh is submit.hpc.ufl.edu. As a note,
any data that is stored on HPC systems is not backed up, and therefore
there is no guarantee that your data will be protected.

A bugzilla account has also been created, and the password for that account
has been sent to you seperately. 

If you have any questions, please let us know via email or through a bug
report using bugzilla:

http://bugzilla.hpc.ufl.edu/
END_OF_BODY

%mail = (
         from => 'support@hpc.ufl.edu',
         to => $email,
         subject => 'HPC Account'
         );
    $mail{body}=$text;
    
    sendmail(%mail) || print "Error in sending email to user\n";
}