#!/usr/bin/perl

# Copywrite 2008 by Karl Kuehn for Stanford University

# The goal of this script is to take a ssh_known_hosts file in and to spit out the
#	relevant sections for a ssh_config file. Along the way we will also add the items
#	in the remote known_host entries into the on-computer one
# This is to allow people to use GSSAPIDelegateCredentials

# We will be looking for sections in the relevent files brackted by:
#	#<Start edu.stanford.rescomp section>
#	#	This area is controlled by a script, and will be overwriten by that script
#	#<End edu.stanford.rescomp section>

$remoteFileLocation = "/afs/ir.stanford.edu/dev/pubsw/config/ssh/ssh_known_hosts";

# first we pull in the ssh_known_hosts file
#	we are puling in the one from /afs/ir.stanford.edu/dev/pubsw/config/ssh/
if (open(INPUTFILE, $remoteFileLocation)) {
	@inputLines = <INPUTFILE>;
	close(INPUTFILE);
} else {
	 system("/usr/bin/logger 'Could not read the known hosts file. It could be that the afs space is not visible.'");
	 exit 1;
}

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
$todayText = $mday . "-" . ($mon+1) . "-" . ($year+1900);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime( (stat $remoteFileLocation)[9] );
$remoteKnownHostsDateText = $mday . "-" . ($mon+1) . "-" . ($year+1900);

# here we are going to read in the local ssh_known_hosts file and write in the additions

# first we are going to read the file in
my $localKnownHosts;
{
	local $/;
	if (open(LOCALKNONHOSTS, "/etc/ssh_known_hosts")) {
		$localKnownHosts = <LOCALKNONHOSTS>;
		close(LOCALKNONHOSTS);
				
		unless ($localKnownHosts =~ /\#\<Start edu\.stanford\.rescomp section\>.*#\<End edu\.stanford\.rescomp section\>/s) {
			# if the tag line does not already exist, then we need to add it to the end
			$localKnownHosts .= "\n\n#<Start edu.stanford.rescomp section> #<End edu.stanford.rescomp section>\n";
			system("/usr/bin/logger 'The required marked-off area in /etc/ssh_known_hosts was not there, so it was added to the end of the file'");
		}

		# we now know that it has the section we are looking for
		#	so we need to plug things in
		
		$replacementText = "#<Start edu.stanford.rescomp section>\n#\tThis area is controlled by a script, and will be overwriten by that script.\n#\tThis was last rewritten on $todayText based on the ssh_known_hosts file last changed on $remoteKnownHostsDateText\n\n" . join("", @inputLines) . "\n#<End edu.stanford.rescomp section>";
		$localKnownHosts =~ s/\#\<Start edu\.stanford\.rescomp section\>.*#\<End edu\.stanford\.rescomp section\>/$replacementText/s;
					
		# now we are ready to write this file back out
		if (open(LOCALKNONHOSTS, ">", "/etc/ssh_known_hosts")) {
			print LOCALKNONHOSTS $localKnownHosts;
			close LOCALKNONHOSTS;
		} else {
			# we are unable to write out the known host files
			system("/usr/bin/logger 'Unable to write back changes to the /etc/ssh_known_hosts file'");
		}
		
	} else {
		# here we have failed to open the known_hosts file, so should provide some warning
		system("/usr/bin/logger 'Unable to open /etc/ssh_known_hosts for reading, so no changes have been made'");
	}
}

# now to work on the ssh_config file
{
	$outputBuffer = "";
	$inCommentBlock = "yep";
	my $lastHostNames; # since there are multiple key types for each group of servers, we only need one line
	# now to iterate through the lines and create the entries
	#	it would be nice if we could put this all on one line, but that seems to not be the case
	foreach $line (@inputLines) {
		
		if ($line =~ /^\#/) {
			# we are going to bring allong the comment lines, just for fun
			# since they designate differnt sections, lets append a line return to them.
			$outputBuffer .= ($inCommentBlock eq "yep" ? "" : "\n") . $line;
			$inCommentBlock = "yep";
		} else {
			# we need to check to make sure that the line looks aobut right:
			($hostNames, $typeOrLength, ) = $line =~ /^(\S+) (\S+)/;
			if ($typeOrLength =~ /^ssh-/ || $typeOrLength =~ /^\d+$/) {
				$inCommentBlock = "nope";
				
				if ($lastHostNames ne $hostNames) {
					my @hostNamesList = split(",", $hostNames);
					foreach $thisHostName (@hostNamesList) {
						# since it seems you can't have 
						$outputBuffer .= "Host $thisHostName\n\tGSSAPIDelegateCredentials yes\n";
					}
				}
				
				$lastHostNames = $hostNames;
			} else {
				# placeholder for troubleshooting
			}
		}
	}
	
	# at this point we should have a block of text ready to inset into the ssh_config file
	
	local $/;
	
	# so we will first read in the file as a template
	if (open(LOCALSSHCONFIG, "/etc/ssh_config")) {
		$localSshConfig = <LOCALSSHCONFIG>;
		close(LOCALSSHCONFIG);
		
		unless ($localSshConfig =~ /\#\<Start edu\.stanford\.rescomp section\>.*#\<End edu\.stanford\.rescomp section\>/s) {
			# if the tag line does not already exist, then we need to add it to the end
			$localSshConfig .= "\n\n#<Start edu.stanford.rescomp section> #<End edu.stanford.rescomp section>\n";
			system("/usr/bin/logger 'The required marked-off area in /etc/ssh_config was not there, so it was added to the end of the file'");
		}
		
		# here we know that it has the section we are looking for
		#	so we need to plug things in
		
		$replacementText = "\n#<Start edu.stanford.rescomp section>\n#\tThis area is controlled by a script, and will be overwriten by that script.\n#\tThis was last rewritten on $todayText based on the ssh_known_hosts file last changed on $remoteKnownHostsDateText\n\n" . $outputBuffer . "\n#<End edu.stanford.rescomp section>\n";
		$localSshConfig =~ s/\n\#\<Start edu\.stanford\.rescomp section\>.*#\<End edu\.stanford\.rescomp section\>\n/$replacementText/s;
					
		# now we are ready to write this file back out
		if (open(LOCALSSHCONFIG, ">", "/etc/ssh_config")) {
			print LOCALSSHCONFIG $localSshConfig;
			close LOCALSSHCONFIG;
		} else {
			# we are unable to write out the known host files
			system("/usr/bin/logger 'Unable to write back changes to the /etc/ssh_config file'");
		}
		
		
	} else {
		system("/usr/bin/logger 'Unable to open /etc/ssh_config for reading, so no changes have been made'");
	}
}

exit;
