#!/usr/bin/perl -w
#
# Copyright (c) 2012 University of Utah and the Flux Group.
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
#
use English;
use Win32;
use Win32API::Net qw(:User);
use Term::ReadKey;

# Turn off line buffering on output
$| = 1;

# Drag in path stuff so we can find emulab stuff.
BEGIN { 
    require "/etc/emulab/paths.pm"; 
    import emulabpaths; 
    $ENV{'PATH'} .= ":/cygdrive/c/Windows/System32:/cygdrive/c/Windows";
}

#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself. 
# 
use libsetup;
use liblocsetup;
use librc;

# Global vars / constants
my $ULEVEL = 1;

sub usage() {
    print "$0 [-p <root_password>]\n".
	"\n(re)hook the Emulab Windows services.\n";
    exit 1;
}

sub modpasswd($$)
{
    my($user, $pswd) = @_;
    my %uh = ();
    my $error;

    if (!UserGetInfo("", $user, $ULEVEL, \%uh)) {
	my $err = Win32::GetLastError();
	warning("UserGetInfo failed for $user: $err\n");
	return 0;
    }

    if ($pswd) {
	$uh{password} = $pswd;
	if (!UserSetInfo("", $user, $ULEVEL, \%uh, \$error)) {
	    my $err = Win32::GetLastError();
	    warning("UserSetInfo failed: $err, $error\n");
	    return 0;
	}
    }

    return 1;
}

sub get_passwd($) {
    my ($user) = @_;
    
    my $passwd = "";
    my $vpasswd = "";
	
    while ($passwd eq "") {
	print "Enter a password for $user: ";
	ReadMode 'noecho';
	$passwd = ReadLine 0;
	chomp $passwd;
	ReadMode 'normal';
	print "\n";
    }
    while ($vpasswd eq "" || $passwd ne $vpasswd) {
	print "Didn't match, try again.\n"
	    if $vpasswd ne "" && $passwd ne $vpasswd;
	print "Re-enter password: ";
	ReadMode 'noecho';
	$vpasswd = ReadLine 0;
	chomp $vpasswd;
	ReadMode 'normal';
	print "\n";
    }

    return $passwd;
}

my $optlist = "p:";
my $rootpwd = "";

# Parse command line.
use Getopt::Std;
if (! getopts($optlist, \%options)) {
    usage();
}
if (defined($options{'p'})) {
    $rootpwd = $options{'p'};
} else {
    $rootpwd = get_passwd("root");
}

#
# Sync Cygwin passwd and group files with Windows
#
if (os_accounts_sync() != 0) {
    print "Error syncing Windows and Cygwin user and group databases!";
    exit 1;
}

# Set the root password to make sure it matches.  We also set this to be
# the Administrator password, to match the sysprep.inf file entry below.
print "\nSetting root password.\n";
modpasswd("root", $rootpwd) or die "Couldn't set root's password!";

#
# Windows stores the password as part of the definition of services that
# run as a real user, such as root, rather than as SYSTEM.  Redefine them
# with the current password.  Otherwise, Windows will refuse to start them
# up at reboot.
#
my $mybash = "/bin/bash";

print "\nRedefining Pubsub service.\n";
my $pubsub = "/usr/local/libexec/pubsubd";
my $pubsublog = "/var/log/pubsub.log";
system("cygrunsrv -R pubsub > /dev/null 2>&1");
# pubsub runs as the 'SYSTEM' user.
system("cygrunsrv.exe -I pubsub -d 'CYGWIN pubsub' -t auto -y tcpip ".
       "-n -p $pubsub -a \"-d -l '$pubsublog'\"");
system("cygrunsrv -VQ pubsub");

my $tbshutdown = "/usr/local/etc/emulab/tbshutdown";
print "\nRedefining EmulabShutdown.\n";
system("cygrunsrv -R EmulabShutdown > /dev/null 2>&1");
system("cygrunsrv -I EmulabShutdown -u root -w '$rootpwd'" .
       " --shutdown --type manual -p $mybash " .
       " -a \"--norc --noprofile -c '$tbshutdown'\"");
system("cygrunsrv -VQ EmulabShutdown");

print "\nRedefining EmulabStartup.\n";
my $bootsetup = "/usr/local/etc/emulab/rc/rc.bootsetup";
my $progrun = "cygrunsrv -S ProgAgent";
my $bootlog = "/var/log/bootsetup.log";
system("cygrunsrv -R EmulabStartup > /dev/null 2>&1");
system("cygrunsrv -I EmulabStartup -u root -w '$rootpwd'" .
       " --dep DHCP --dep iphlpsvc --dep pubsub --dep W32Time" .
       " -p $mybash -a \"--norc --noprofile -c " .
       " '( $bootsetup; $progrun ) >& $bootlog'\"");
system("cygrunsrv -VQ EmulabStartup");
system("sc config EmulabStartup start= delayed-auto");

exit 0;
