#!/usr/bin/perl -w
# $Header#

# this script take a passwd file, and a group file.
# it then mundges users according to the passwd file.
# if they don't exist, it creates them. 
# if they're unprivledged, it makes them privledged.
# it also sets stuff based on the GECOS

# because we're dealing with rt through the API, we will need to be
# setgid rt. or be running as root...

use strict;
use Getopt::Long;

# varibles related to command line options, and their defaults
my $verbose = 0;
my $dcm_dir = "/var/local/dcm";
my $passwd_file = "";                # defaults to $dcm_dir/passwd
my $group_file = "";                 # defaults to $dcm_dir/group
#my $rt_location = "/usr/local/rt2";
my $admin_user = "root";

GetOptions (
	    'verbose|v'    => \$verbose,
	    'dcm_dir|d=s'  => \$dcm_dir,
	    'passwd|p=s'   => \$passwd_file,
	    'group|g=s'    => \$group_file,
	    #'rt|r=s'       => \$rt_location,
	    'user|u=s'     => \$admin_user,
	    );

$passwd_file = $dcm_dir . "/passwd";
$group_file = $dcm_dir . "/group";


my $current_user = initialize_rt();

open(PASSWD, "<$passwd_file");
while(<PASSWD>) {
    chomp;
    frob_rt_user($current_user, $_);
}


open(GROUP, "<$group_file");
while(<GROUP>) {
    chomp;
    frob_rt_group($current_user, $_);
}










sub initialize_rt {
    # initialize rt, and get whatever we need for the API

    # I'm not sure why I can't do this by varible. eit.
    #use lib "$rt_location/lib";
    #use lib "$rt_location/etc";
    use lib "/usr/local/rt2/lib";
    use lib "/usr/local/rt2/etc";


    use RT::Interface::CLI  qw(CleanEnv LoadConfig DBConnect 
			       GetCurrentUser GetMessageContent);
    use RT::Group;
    
    #Clean out all the nasties from the environment
    CleanEnv();

    #Load etc/config.pm and drop privs
    LoadConfig();

    #Connect to the database and get RT::SystemUser and RT::Nobody loaded
    DBConnect();

    #Drop setgid permissions
    RT::DropSetGIDPermissions();

    #Get the current user all loaded
    #my $CurrentUser = GetCurrentUser();
    my $CurrentUser = RT::CurrentUser->new();
    $CurrentUser->Load($admin_user);

    
    unless ($CurrentUser->Id) {
        print "Couldn't login to rt as root. yer fucked\n";
        exit(1);
    }
    
    return $CurrentUser;
}


sub frob_rt_group {
    # this takes a /etc/groups style line, and makes an rt group look like that.
    # it does the various user adds and removes.

    # get the RT thingy
    my $CurrentUser = shift;

    my $group_line = shift;
    
    my ($name, $password, $gid, $users) = split (/:/, $group_line);
    my %new_users;
    foreach ( split(/,/, $users) ) {
	chomp;
	my $user_name = $_;
	$user_name = $user_name . '@mit.edu' unless($user_name =~ /\@/);
	$new_users{$user_name} = 1;
    }


    # clean up various bits
    my $group_name = 'moira:' . $name;


    # for now, rt only support 16 character names.
    # we'll truncate so we can get on with testing
    # whoo hoo, fixed.
    #$group_name = sprintf('%.60s', $group_name);


    # let's create an rt group object, and we'll see if the group exists
    my $group_obj = new RT::Group($CurrentUser);
    $group_obj->Load($group_name);

    unless ($group_obj->Id) {
        print "Group $group_name not found, creating\n" if($verbose);
	my ($val, $msg) = $group_obj->Create( Name => $group_name);
        print $msg ."\n" if($verbose);
	

    }

    $group_obj->Load($group_name);
    unless ($group_obj->Id) {
	print "couldn't load $group_name. fucked\n---\n";
	return 1;
    }

    print "CHECKING GROUP $group_name\n" if($verbose);

    # now we know we have a group loaded. let's set it's members 


    # if the user is in the new_users list, remove them from the
    # new_users list, as we've checked them. 
    # if they're supposed to be there, flag it in new_users so we
    # don't check them twice.
    my $existing_members = $group_obj->MembersObj();
    while (my $member = $existing_members->Next()) {
	print "checking existing user " . $member->UserObj->Name(), "\n" if($verbose);
	unless( $new_users{$member->UserObj->Name()} ) {
	    print "   deleting\n" if($verbose);
	    $group_obj->DeleteMember($member->UserObj->Id());
	}
	#else {
	#    $new_users{$member->UserObj->Name()} = 99;
	#}
    }
    
    # now iterate over the various new members, and make sure
    # they're already in the group.
    foreach my $user_name (keys %new_users) {
	print "checking $user_name group $group_name\n" if($verbose);
	
	next if( $new_users{$user_name} eq 99 );
	
	print "    adding\n" if($verbose);
	
	# we need to add members by id, not name.
	my $new_user = new RT::User($CurrentUser);
	$new_user->Load($user_name);
	
	$group_obj->AddMember( $new_user->Id() );
    }
	    



    #use Data::Dumper;
    #print "dumping $group_name\n";
    #print Dumper $existing_members;

}

sub frob_rt_user {
    # this function takes a passwd style line and frobs the rt user
    # if the user doesn't exist, it creates it.
    # if the user is unprivledged, it makes said user privleged
    # it also set's the name and gecos

    my $CurrentUser = shift;

    my $passwd_line = shift;
    my ($login, $pass, $uid, $gid, $gecos, $home, $shell) = split(/:/, $passwd_line);
    my ($name, $nickname, $office, $office_phone, $phone) = split(/,/, $gecos);
    
    # clean up various varibles before we pass them into rt
    my $user_email = $login;
    $user_email = $user_email . '@MIT.EDU' unless($user_email =~ /\@/);
    my $user_name = $login;
    $user_name = $user_name . '@mit.edu' unless($user_name =~ /\@/);

    # set up the attributes array:
    my %user_attributes;
    $user_attributes{'Name'} = $user_name;
    $user_attributes{'Gecos'} = $login;
    $user_attributes{'EmailAddress'} = $user_email;
    $user_attributes{'Privileged'} = 1;
    $user_attributes{'Comments'} = 'frobbed by the dcm';
    $user_attributes{'RealName'} = $name;
    $user_attributes{'NickName'} = $nickname;
    $user_attributes{'HomePhone'} = $phone;
    $user_attributes{'WorkPhone'} = $office_phone;
    
        
    # let's create an rt user object, and we'll see 
    my $user_obj = new RT::User($CurrentUser); 
    $user_obj->Load($user_name);

    # alrighty, create the user, if they don't exist.
    unless ($user_obj->id) {
	print "User '$user_name' not found, creating\n" if($verbose);
        my ($status, $msg) =
	    $user_obj->Create( Name => ($user_attributes{'Name'} || $user_name),
			       Gecos => $user_attributes{'Gecos'},
			       Password => $user_attributes{'Password'},
			       EmailAddress => $user_attributes{'EmailAddress'},
			       Privileged => $user_attributes{'Privileged'},
			       Comments => $user_attributes{'Comments'},
			       Signature => $user_attributes{'Signature'},
			       Organization => $user_attributes{'Organization'},
			       RealName => $user_attributes{'RealName'},
			       NickName => $user_attributes{'NickName'},
			       ExternalContactInfoId => $user_attributes{'ExternalContactInfoId'},
			       ContactInfoSystem => $user_attributes{'ContactInfoSystem'},
			       ExternalAuthId => $user_attributes{'ExternalAuthId'},
			       AuthSystem => $user_attributes{'AuthSystem'},
			       HomePhone => $user_attributes{'HomePhone'},
			       WorkPhone => $user_attributes{'WorkPhone'},
			       MobilePhone => $user_attributes{'MobilePhone'},
			       PagerPhone => $user_attributes{'PagerPhone'},
			       Address1 => $user_attributes{'Address1'},
			       Address2 => $user_attributes{'Address2'},
			       City  => $user_attributes{'City'},
			       State => $user_attributes{'State'},
			       Zip => $user_attributes{'Zip'},
			       FreeformContactInfo => $user_attributes{'FreeformContactInfo'}
			       );
	
        print "$msg\n";
    }
    # if they already exist, let's just frob them...
    else {

	# now that we know we have a user, let's set it's attributes
	# this bit of code lifted from rtadmin
	my @attributes = ('Name', 'Gecos',
			  'EmailAddress', 'Privileged', 'Comments', 'Signature',
			  'Organization', 'RealName', 'NickName',
			  'ExternalContactInfoId', 'ContactInfoSystem',
			  'ExternalAuthId', 'AuthSystem',
			  'HomePhone', 'WorkPhone', 'MobilePhone', 'PagerPhone',
			  'Address1', 'Address2', 'City', 'State', 'Zip',
			  'Country', 'FreeformContactInfo');
	foreach my $attrib (@attributes) {
	    if ( (exists ($user_attributes{"$attrib"})) and
		 ($user_obj->$attrib() ne $user_attributes{"$attrib"})) {
		
		my $method = "Set$attrib";
		my ($val, $msg) = $user_obj->$method($user_attributes{"$attrib"});
		print "User ".$user_obj->Name. " $attrib:  $msg\n" if($verbose);
		
	    }
	}
    }

}
