<commit_before>#!/usr/local/bin/perl
# sshd-lib.pl
# Common functions for the ssh daemon config file

BEGIN { push(@INC, ".."); };
use WebminCore;
&init_config();

# Get version information
if (!&read_file("$module_config_directory/version", \%version)) {
	%version = &get_sshd_version();
	}

# get_sshd_version()
# Returns a hash containing the version type, number and full version
sub get_sshd_version
{
local %version;
local $out = &backquote_command(
	&quote_path($config{'sshd_path'})." -h 2>&1 </dev/null");
if ($config{'sshd_version'}) {
	# Forced version
	$version{'type'} = 'openssh';
	$version{'number'} = $version{'full'} = $config{'sshd_version'};
	}
elsif ($out =~ /(sshd\s+version\s+([0-9\.]+))/i ||
    $out =~ /(ssh\s+secure\s+shell\s+([0-9\.]+))/i) {
	# Classic commercial SSH
	$version{'type'} = 'ssh';
	$version{'number'} = $2;
	$version{'full'} = $1;
	}
elsif ($out =~ /(OpenSSH.([0-9\.]+))/i) {
	# OpenSSH .. assume all versions are supported
	$version{'type'} = 'openssh';
	$version{'number'} = $2;
	$version{'full'} = $1;
	}
elsif ($out =~ /(Sun_SSH_([0-9\.]+))/i) {
	# Solaris 9 SSH is actually OpenSSH 2.x
	$version{'type'} = 'openssh';
	$version{'number'} = 2.0;
	$version{'full'} = $1;
	}
elsif (($out = $config{'sshd_version'}) && ($out =~ /(Sun_SSH_([0-9\.]+))/i)) {
	# Probably Solaris 10 SSHD that didn't display version.  Use it.
	$version{'type'} = 'openssh';
	$version{'number'} = 2.0;
	$version{'full'} = $1;
	}
return %version;
}

# get_sshd_config()
# Returns a reference to an array of SSHD config file options
sub get_sshd_config
{
local @rv = ( { 'dummy' => 1,
		'indent' => 0,
		'file' => $config{'sshd_config'},
		'line' => -1,
		'eline' => -1 } );
local $lnum = 0;
open(CONF, $config{'sshd_config'});
while(<CONF>) {
	s/\r|\n//g;
	s/^\s*#.*$//g;
	local ($name, @values) = split(/\s+/, $_);
	if ($name) {
		local $dir = { 'name' => $name,
			       'values' => \@values,
			       'file' => $config{'sshd_config'},
			       'line' => $lnum };
		push(@rv, $dir);
		}
	$lnum++;
	}
close(CONF);
return \@rv;
}

# find_value(name, &config)
sub find_value
{
foreach $c (@{$_[1]}) {
	if (lc($c->{'name'}) eq lc($_[0])) {
		return wantarray ? @{$c->{'values'}} : $c->{'values'}->[0];
		}
	}
return wantarray ? ( ) : undef;
}

# find(value, &config)
sub find
{
local @rv;
foreach $c (@{$_[1]}) {
	if (lc($c->{'name'}) eq lc($_[0])) {
		push(@rv, $c);
		}
	}
return wantarray ? @rv : $rv[0];
}

# save_directive(name, &config, [value*|&values], [before])
sub save_directive
{
local @o = &find($_[0], $_[1]);
local @n = ref($_[2]) ?
		grep { defined($_) } @{$_[2]} :
		grep { defined($_) } @_[2..@_-1];
local $lref = &read_file_lines($_[1]->[0]->{'file'});
local $id = ("\t" x $_[1]->[0]->{'indent'});
local $i;
local $before = $_[3] && ref($_[2]) ? &find($_[3], $_[1]) : undef;
for($i=0; $i<@o || $i<@n; $i++) {
	if ($o[$i] && $n[$i]) {
		# Replacing a line
		$lref->[$o[$i]->{'line'}] = "$id$_[0] $n[$i]";
		}
	elsif ($o[$i]) {
		# Removing a line
		splice(@$lref, $o[$i]->{'line'}, 1);
		foreach $c (@{$_[1]}) {
			if ($c->{'line'} > $o[$i]->{'line'}) {
				$c->{'line'}--;
				}
			}
		}
	elsif ($n[$i] && !$before) {
		# Adding a line at the end, but before the last Match directive
		local $ll = $_[1]->[@{$_[1]}-1]->{'line'};
		foreach my $m (&find("Match", $_[1])) {
			$ll = $m->{'line'} - 1;
			}
		splice(@$lref, $ll+1, 0, "$id$_[0] $n[$i]");
		}
	elsif ($n[$i] && $before) {<commit_msg>Add new lines before first Match<commit_after>#!/usr/local/bin/perl
# sshd-lib.pl
# Common functions for the ssh daemon config file

BEGIN { push(@INC, ".."); };
use WebminCore;
&init_config();

# Get version information
if (!&read_file("$module_config_directory/version", \%version)) {
	%version = &get_sshd_version();
	}

# get_sshd_version()
# Returns a hash containing the version type, number and full version
sub get_sshd_version
{
local %version;
local $out = &backquote_command(
	&quote_path($config{'sshd_path'})." -h 2>&1 </dev/null");
if ($config{'sshd_version'}) {
	# Forced version
	$version{'type'} = 'openssh';
	$version{'number'} = $version{'full'} = $config{'sshd_version'};
	}
elsif ($out =~ /(sshd\s+version\s+([0-9\.]+))/i ||
    $out =~ /(ssh\s+secure\s+shell\s+([0-9\.]+))/i) {
	# Classic commercial SSH
	$version{'type'} = 'ssh';
	$version{'number'} = $2;
	$version{'full'} = $1;
	}
elsif ($out =~ /(OpenSSH.([0-9\.]+))/i) {
	# OpenSSH .. assume all versions are supported
	$version{'type'} = 'openssh';
	$version{'number'} = $2;
	$version{'full'} = $1;
	}
elsif ($out =~ /(Sun_SSH_([0-9\.]+))/i) {
	# Solaris 9 SSH is actually OpenSSH 2.x
	$version{'type'} = 'openssh';
	$version{'number'} = 2.0;
	$version{'full'} = $1;
	}
elsif (($out = $config{'sshd_version'}) && ($out =~ /(Sun_SSH_([0-9\.]+))/i)) {
	# Probably Solaris 10 SSHD that didn't display version.  Use it.
	$version{'type'} = 'openssh';
	$version{'number'} = 2.0;
	$version{'full'} = $1;
	}
return %version;
}

# get_sshd_config()
# Returns a reference to an array of SSHD config file options
sub get_sshd_config
{
local @rv = ( { 'dummy' => 1,
		'indent' => 0,
		'file' => $config{'sshd_config'},
		'line' => -1,
		'eline' => -1 } );
local $lnum = 0;
open(CONF, $config{'sshd_config'});
while(<CONF>) {
	s/\r|\n//g;
	s/^\s*#.*$//g;
	local ($name, @values) = split(/\s+/, $_);
	if ($name) {
		local $dir = { 'name' => $name,
			       'values' => \@values,
			       'file' => $config{'sshd_config'},
			       'line' => $lnum };
		push(@rv, $dir);
		}
	$lnum++;
	}
close(CONF);
return \@rv;
}

# find_value(name, &config)
sub find_value
{
foreach $c (@{$_[1]}) {
	if (lc($c->{'name'}) eq lc($_[0])) {
		return wantarray ? @{$c->{'values'}} : $c->{'values'}->[0];
		}
	}
return wantarray ? ( ) : undef;
}

# find(value, &config)
sub find
{
local @rv;
foreach $c (@{$_[1]}) {
	if (lc($c->{'name'}) eq lc($_[0])) {
		push(@rv, $c);
		}
	}
return wantarray ? @rv : $rv[0];
}

# save_directive(name, &config, [value*|&values], [before])
sub save_directive
{
local @o = &find($_[0], $_[1]);
local @n = ref($_[2]) ?
		grep { defined($_) } @{$_[2]} :
		grep { defined($_) } @_[2..@_-1];
local $lref = &read_file_lines($_[1]->[0]->{'file'});
local $id = ("\t" x $_[1]->[0]->{'indent'});
local $i;
local $before = $_[3] && ref($_[2]) ? &find($_[3], $_[1]) : undef;
for($i=0; $i<@o || $i<@n; $i++) {
	if ($o[$i] && $n[$i]) {
		# Replacing a line
		$lref->[$o[$i]->{'line'}] = "$id$_[0] $n[$i]";
		}
	elsif ($o[$i]) {
		# Removing a line
		splice(@$lref, $o[$i]->{'line'}, 1);
		foreach $c (@{$_[1]}) {
			if ($c->{'line'} > $o[$i]->{'line'}) {
				$c->{'line'}--;
				}
			}
		}
	elsif ($n[$i] && !$before) {
		# Adding a line at the end, but before the first Match directive
		local $ll = $_[1]->[@{$_[1]}-1]->{'line'};
		foreach my $m (&find("Match", $_[1])) {
			$ll = $m->{'line'} - 1;
			last;
			}
		splice(@$lref, $ll+1, 0, "$id$_[0] $n[$i]");
		}
	elsif ($n[$i] && $before) {
{'fraction_non_alphanumeric': 0.2798491222979835, 'fraction_numerical': 0.01827941389815755, 'mean_word_length': 3.848101265822785, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '183148', 'n_tokens_mistral': 3160, 'n_tokens_neox': 2957, 'n_words': 634}