#!/usr/bin/perl

# Author: Brad Marshall (bmarshal@pisoftware.com)
# Date: 20010803

# This script is released under the GNU GPL.  See http://www.gnu.org/copyleft/gpl.html
# for full licensing details.

# TODO:
# Give pulldown that contains gid options
# Check user doesn't already exist
# Better error checking - is ldap server up, etc
# Better error reporting

use CGI;
use CGI::Carp qw(fatalsToBrowser carpout);
use Net::LDAP; 

# Set to 1 for debugging information
my($debug) = 1;
# Set to your base dn
my($basedn) = "dc=gumby";
# Set to the ip or dns entry of your ldap server
my($ldaphost) = "eta";
# Set to your mail domain
my($maildomain) = "gumby";
# Set to the default group id that you want users to have
my($defaultgid) = 100;
my($adminuser) = "cn=admin,ou=People," . $basedn;
my($adminpasswd) = "admin";

my($query) = new CGI();

if ($query->param('user')) {
    $user = $query->param('user');
    $newpasswd1 = $query->param('newpasswd1');
    $newpasswd2 = $query->param('newpasswd2');
    $givenname = $query->param('givenname');
    $sn = $query->param('sn');
    $shell = $query->param('shell');
    $homedir = $query->param('homedir');
    $uidnumber = $query->param('uidnumber');

    print $query->header(-type=>"text/html"),
        $query->start_html(-title=>'LDAP Add User', -BGCOLOR=>"white"), "\n",
        $query->h1("Adding User");

    $userdn = "uid=$user,ou=People,$basedn";

    print "User is uid=$user,ou=People,$basedn" if $debug;
    print $query->br if $debug;

    my($ldap) = Net::LDAP->new("$ldaphost") or die "Can't bind to $ldaphost: $!\n";

    $mesg = $ldap->bind(
                dn       => $adminuser,
                password => $adminpasswd,
    );

    if ($mesg->code) {
        # Can't bind
        print "Sorry, can't bind to ldap server";
        print $query->br;
    } else {
        print "Bound to ldap server as admin" if $debug;
        print $query->br if $debug;
        if ($newpasswd1 ne $newpasswd2) {
            # passwords don't match, deal with asking for it again
            print "Sorry, new password does not match";
            print $query->br;
        } else {
            # passwords do match
            print "And new passwords match" if $debug;
            print $query->br if $debug;
            $salt = join '', ('.', '/', 0..9, 'A'..'Z','a'..'z')[rand 64, rand 64];
            print "salt = ", $salt if $debug;
            print $query->br if $debug;
            $cryptpass = crypt($newpasswd1,$salt);

            $msg = $ldap->add( dn => $userdn,
                            attr => [
                                'uid' => $user,
                                'cn' => "$givenname $sn",
                                'givenName' => $givenname,
                                'sn' => $sn,
                                'userPassword' => "{crypt}$cryptpass",
                                'loginShell' => $shell,
                                'homeDirectory' => $homedir,
                                'gecos' => "$givenname $sn,,,",
                                'mail' => $user . "\@" . $maildomain,
                                'uidNumber' => $uidnumber,
                                'gidNumber' => $defaultgid,
                                'objectClass' => [ 'person',
                                                    'organizationalPerson',
                                                    'inetOrgPerson',
                                                    'account',
                                                    'posixAccount',
                                                    'top'
                                                 ]
                            ]
                        );

			if ($msg->code) {
				print "Can't add ldap user: $msg->error";
			} else {
				print "Congratulations, you have now added " . $user;
				print $query->br;
			}
        }
    }
} else {
    print $query->header(-type=>"text/html"),
        $query->start_html(-title=>'LDAP Change Password', -BGCOLOR=>"white"), "\n";

    print $query->hr, "\n",
        "<FORM METHOD='post' ACTION='/cgi-bin/ldap/adduser.pl' ENCTYPE='application/x-www-form-urlencoded'>", "\n";

    # Find out the next available uid to use
    $newuid = &find_uid();
    print "New uid = $newuid" if $debug;

    print $query->table({-border=>'0'},
            $query->Tr({-align=>LEFT,-valign=>CENTER},[
                $query->td(["User: ", $query->textfield(-name=>'user',
                                    -default=>'username',
                                    -size=>'10')]),
                $query->td(["Given Name: ", $query->textfield(-name=>'givenname',
                                                -default=>'User',
                                                -size=>'12')]),
                $query->td(["Surname: ", $query->textfield(-name=>'sn',
                                                -default=>'Name',
                                                -size=>'12')]),
                $query->td(["New Password: ", $query->password_field(-name=>'newpasswd1',
                                                        -size=>'10')]),
                $query->td(["Password (again): ", $query->password_field(-name=>'newpasswd2',
                                                             -size=>'10')]),
                $query->td(["Shell: ", $query->popup_menu(-name=>'shell',
                                        -value=>['/bin/sh','/bin/bash','/bin/csh','/bin/ksh'],
                                        -default=>'/bin/bash')]),
                $query->td(["Homedirectory: ", $query->textfield(-name=>'homedir',
                                                 -default=>'/home/username',
                                                 -size=>'20')]),
                $query->td(["UID Number: ", $query->textfield(-name=>'uidnumber',
                                                 -default=>$newuid,
                                                 -size=>'5')]),
             ]
         )
    );

    print $query->br,
        $query->submit,
        $query->end_form,
        $query->hr,
        $query->end_html;

}

sub find_uid {
    # Subroutine to find greatest uid

    my($ldap) = Net::LDAP->new($ldaphost) or die "Can't bind to $ldaphost: $!\n";

    $ldap->bind;

    my($mesg) = $ldap->search( base => $basedn,
                               filter => '(objectclass=posixaccount)',
                               attrs => ['uidNumber']
                             );

    $mesg->code && die "Error doing search: $mesg->error";

    foreach my $entry ($mesg->all_entries) {
        # Deal with uid number
        $uidnum = $entry->get_value('uidNumber');
        print "uidnumbers = $uidnum" if $debug;
        print $query->br if $debug;
        $uid{$uidnum}++;
    }

    my(@uidlist) = sort(keys(%uid));
    print "last uid = $uidlist[$#uidlist]" if $debug;
    my($nextuid) = $uidlist[$#uidlist] + 1;
    print "Next uid = $nextuid" if $debug;

    return $nextuid;
}

