Fix allow/deny groups #816 (#203)

Fixing allow groups, deny groups. (PowerShell/Win32-OpenSSH#816)
Convert users, groups read from sshd_config to lowercase.
This commit is contained in:
bagajjal 2017-09-01 14:53:12 -07:00 committed by Manoj Ampalam
parent e8a303673e
commit ab2aefff6d
8 changed files with 672 additions and 171 deletions

View File

@ -1,6 +1,16 @@
#ifndef COMPAT_GRP_H
#define COMPAT_GRP_H 1
#include <Windows.h>
#include "sys/types.h"
char *group_from_gid(gid_t gid, int nogroup);
typedef enum {
LOCAL_GROUP = 0,
DOMAIN_GROUP = 1,
GLOBAL_UNIVERSAL_GROUP = 2
} group_type;
char ** getusergroups(const char *user, int *numgroups);
void populate_user_groups(char **gr_name, int *group_index, DWORD groupsread, DWORD totalgroups, LPBYTE buf, group_type groupType);
void print_user_groups(const char *user, char **user_groups, int num_user_groups);
#endif

View File

@ -33,6 +33,7 @@
#include <time.h>
#include <Shlwapi.h>
#include <conio.h>
#include <LM.h>
#include "inc\unistd.h"
#include "inc\sys\stat.h"
@ -49,6 +50,7 @@
#include "debug.h"
#include "w32fd.h"
#include "inc\string.h"
#include "inc\grp.h"
static char* s_programdir = NULL;
@ -1046,8 +1048,233 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
return outBuf;
}
void invalid_parameter_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
void
invalid_parameter_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
{
debug3("Invalid parameter in function: %ls. File: %ls Line: %d.", function, file, line);
debug3("Expression: %s", expression);
}
int
get_machine_domain_name(wchar_t *domain, int size)
{
LPWKSTA_INFO_100 pBuf = NULL;
NET_API_STATUS nStatus;
LPWSTR pszServerName = NULL;
nStatus = NetWkstaGetInfo(pszServerName, 100, (LPBYTE *)&pBuf);
if (nStatus != NERR_Success) {
error("Unable to fetch the machine domain, error:%d\n", nStatus);
return 0;
}
debug3("Machine domain:%ls", pBuf->wki100_langroup);
wcscpy_s(domain, size, pBuf->wki100_langroup);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
return 1;
}
/*
* This method will fetch all the groups (listed below) even if the user is indirectly a member.
* - Local machine groups
* - Domain groups
* - global group
* - universal groups
*/
char **
getusergroups(const char *user, int *ngroups)
{
LPGROUP_USERS_INFO_0 local_groups = NULL;
LPGROUP_USERS_INFO_0 domain_groups = NULL;
LPGROUP_USERS_INFO_0 global_universal_groups = NULL;
DWORD num_local_groups_read = 0;
DWORD total_local_groups = 0;
DWORD num_domain_groups_read = 0;
DWORD total_domain_groups = 0;
DWORD num_global_universal_groups_read = 0;
DWORD total_global_universal_groups = 0;
DWORD flags = LG_INCLUDE_INDIRECT;
NET_API_STATUS nStatus;
wchar_t *w_username = NULL;
char *user_domain = NULL;
LPWSTR wszDCName = NULL;
char *user_name = malloc(strlen(user)+1);
if(!user_name) {
error("failed to allocate memory!");
return 0;
}
memcpy(user_name, user, strlen(user)+1);
if (user_domain = strchr(user_name, '@')) {
char *t = user_domain;
user_domain++;
*t='\0';
}
w_username = utf8_to_utf16(user_name);
if (!w_username) {
error("utf8_to_utf16 failed! for %s", user_name);
return NULL;
}
/* Fetch groups on the Local machine */
wchar_t w_machine_domain_name[64] = { 0, };
if (get_machine_domain_name(w_machine_domain_name, 64)) {
if(!machine_domain_name)
machine_domain_name = utf16_to_utf8(w_machine_domain_name);
wchar_t local_user_fmt[256] = { 0, };
if (user_domain) {
wcscpy_s(local_user_fmt, 256, w_machine_domain_name);
wcscat_s(local_user_fmt, 256, L"\\");
}
wcscat_s(local_user_fmt, 256, w_username);
nStatus = NetUserGetLocalGroups(NULL,
local_user_fmt,
0,
flags,
(LPBYTE *)&local_groups,
MAX_PREFERRED_LENGTH,
&num_local_groups_read,
&total_local_groups);
if (NERR_Success != nStatus)
error("Failed to get local groups on this machine, error: %d\n", nStatus);
}
if (user_domain) {
/* Fetch Domain groups */
nStatus = NetGetDCName(NULL, w_machine_domain_name, (LPBYTE *)&wszDCName);
if (NERR_Success == nStatus) {
debug3("domain controller name: %ls", wszDCName);
nStatus = NetUserGetLocalGroups(wszDCName,
w_username,
0,
flags,
(LPBYTE *)&domain_groups,
MAX_PREFERRED_LENGTH,
&num_domain_groups_read,
&total_domain_groups);
if (NERR_Success != nStatus)
error("Failed to get domain groups from DC:%s error: %d\n", wszDCName, nStatus);
}
else
error("Failed to get the domain controller name, error: %d\n", nStatus);
/* Fetch global, universal groups */
nStatus = NetUserGetGroups(wszDCName,
w_username,
0,
(LPBYTE *)&global_universal_groups,
MAX_PREFERRED_LENGTH,
&num_global_universal_groups_read,
&total_global_universal_groups);
if (NERR_Success != nStatus)
error("Failed to get global,universal groups from DC:%ls error: %d\n", wszDCName, nStatus);
}
int total_user_groups = num_local_groups_read + num_domain_groups_read + num_global_universal_groups_read;
/* populate the output */
char **user_groups = NULL;
int num_user_groups = 0;
user_groups = malloc(total_user_groups * sizeof(*user_groups));
populate_user_groups(user_groups, &num_user_groups, num_local_groups_read, total_local_groups, (LPBYTE) local_groups, LOCAL_GROUP);
if (user_domain) {
populate_user_groups(user_groups, &num_user_groups, num_domain_groups_read, total_domain_groups, (LPBYTE)domain_groups, DOMAIN_GROUP);
populate_user_groups(user_groups, &num_user_groups, num_global_universal_groups_read, total_global_universal_groups, (LPBYTE)global_universal_groups, GLOBAL_UNIVERSAL_GROUP);
}
for (int i = 0; i < num_user_groups; i++)
to_lower_case(user_groups[i]);
print_user_groups(user, user_groups, num_user_groups);
if(local_groups)
NetApiBufferFree(local_groups);
if(domain_groups)
NetApiBufferFree(domain_groups);
if(global_universal_groups)
NetApiBufferFree(global_universal_groups);
*ngroups = num_user_groups;
return user_groups;
}
/* This method will return in "group@domain" format */
char *
append_domain_to_groupname(char *groupname)
{
if(!groupname) return NULL;
int len = (int) strlen(machine_domain_name) + (int) strlen(groupname) + 2;
char *groupname_with_domain = malloc(len);
strcpy_s(groupname_with_domain, len, groupname);
strcat_s(groupname_with_domain, len, "@");
strcat_s(groupname_with_domain, len, machine_domain_name);
groupname_with_domain[len-1]= '\0';
return groupname_with_domain;
}
void
populate_user_groups(char **gr_name, int *group_index, DWORD groupsread, DWORD totalgroups, LPBYTE buf, group_type groupType)
{
if(0 == groupsread) return;
if (groupType == GLOBAL_UNIVERSAL_GROUP) {
LPGROUP_USERS_INFO_0 pTmpBuf = (LPGROUP_USERS_INFO_0)buf;
for (DWORD i = 0; (i < groupsread) && pTmpBuf; i++, pTmpBuf++) {
gr_name[*group_index] = append_domain_to_groupname(utf16_to_utf8(pTmpBuf->grui0_name));
if(gr_name[*group_index])
(*group_index)++;
else
error("utf16_to_utf8 failed to convert:%ls", pTmpBuf->grui0_name);
}
} else {
LPLOCALGROUP_USERS_INFO_0 pTmpBuf = (LPLOCALGROUP_USERS_INFO_0)buf;
for (DWORD i = 0; (i < groupsread) && pTmpBuf; i++, pTmpBuf++) {
if(groupType == DOMAIN_GROUP)
gr_name[*group_index] = append_domain_to_groupname(utf16_to_utf8(pTmpBuf->lgrui0_name));
else
gr_name[*group_index] = utf16_to_utf8(pTmpBuf->lgrui0_name);
if (gr_name[*group_index])
(*group_index)++;
else
error("utf16_to_utf8 failed to convert:%ls", pTmpBuf->lgrui0_name);
}
}
if (groupsread < totalgroups)
error("groupsread:%d totalgroups:%d groupType:%d", groupsread, totalgroups, groupType);
}
void
print_user_groups(const char *user, char **user_groups, int num_user_groups)
{
debug3("Group list for user:%s", user);
for(int i=0; i < num_user_groups; i++)
debug3("group name:%s", user_groups[i]);
}
void
to_lower_case(char *s)
{
for (; *s; s++)
*s = tolower((u_char)*s);
}

View File

@ -31,4 +31,7 @@ int errno_from_Win32Error(int);
void unix_time_to_file_time(ULONG, LPFILETIME);
void file_time_to_unix_time(const LPFILETIME, time_t *);
int file_attr_to_st_mode(wchar_t * path, DWORD attributes);
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
static char *machine_domain_name;
void to_lower_case(char *s);
int get_machine_domain_name(wchar_t *domain, int size);

View File

@ -203,6 +203,8 @@ get_passwd(const char *user_utf8, LPWSTR user_sid)
goto done;
}
}
to_lower_case(uname_upn);
pw.pw_name = uname_upn;
uname_upn = NULL;
pw.pw_dir = pw_home_utf8;

View File

@ -54,84 +54,13 @@ int
ga_init(const char *user, gid_t base)
{
#ifdef WINDOWS
#pragma warning(push, 3)
LPLOCALGROUP_USERS_INFO_0 local_groups_info = NULL, tmp_groups_info;
wchar_t *user_utf16 = NULL, *full_name_utf16 = NULL, *udom_utf16 = NULL, *tmp;
char *group_utf8 = NULL;
DWORD i = 0, j = 0;
DWORD entries_read = 0, total_entries = 0, full_name_len = 0, index = 0;
NET_API_STATUS nStatus;
if (ngroups > 0)
ga_free();
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
errno = ENOMEM;
goto done;
}
full_name_len = (DWORD)wcslen(user_utf16) + 1;
if ((full_name_utf16 = malloc(full_name_len * sizeof(wchar_t))) == NULL) {
errno = ENOMEM;
goto done;
}
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
udom_utf16 = tmp + 1;
*tmp = L'\0';
index = (DWORD)wcslen(udom_utf16) + 1;
wmemcpy(full_name_utf16, udom_utf16, index);
full_name_utf16[wcslen(udom_utf16)] = L'\\';
}
wmemcpy(full_name_utf16 + index, user_utf16, wcslen(user_utf16) + 1);
nStatus = NetUserGetLocalGroups(NULL,
full_name_utf16,
0,
LG_INCLUDE_INDIRECT,
(LPBYTE *)&local_groups_info,
MAX_PREFERRED_LENGTH,
&entries_read,
&total_entries);
if (NERR_Success != nStatus) {
error("NetUserGetLocalGroups() failed with error: %u",
nStatus);
errno = ENOENT;
goto done;
}
if (entries_read != total_entries) {
error("NetUserGetLocalGroups(): entries_read (%u) is not equal to "
"total_entries (%u) for user %.100s", entries_read, total_entries, user);
errno = ENOENT;
goto done;
}
if ((tmp_groups_info = local_groups_info) != NULL) {
groups_byname = xcalloc(entries_read, sizeof(*groups_byname));
for (i = 0, j = 0; i < total_entries; i++)
{
if ((group_utf8 = utf16_to_utf8(tmp_groups_info->lgrui0_name)) == NULL) {
errno = ENOMEM;
goto done;
}
groups_byname[j++] = group_utf8;
tmp_groups_info++;
}
}
done:
if(user_utf16 != NULL)
free(user_utf16);
if(full_name_utf16 != NULL)
free(full_name_utf16);
if (local_groups_info != NULL)
NetApiBufferFree(local_groups_info);
#pragma warning(pop)
ngroups = 0;
groups_byname = NULL;
groups_byname = getusergroups(user, &ngroups);
return ngroups;
#else /* !WINDOWS */
gid_t *groups_bygid;
int i, j;
struct group *gr;
@ -153,8 +82,8 @@ done:
if ((gr = getgrgid(groups_bygid[i])) != NULL)
groups_byname[j++] = xstrdup(gr->gr_name);
free(groups_bygid);
#endif /* !WINDOWS */
return (ngroups = j);
#endif /* !WINDOWS */
}
/*

View File

@ -1,17 +1,133 @@
Describe "Tests of sshd_config" -Tags "Scenario" {
If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
$suite = "sshdConfig"
Describe "Tests of sshd_config" -Tags "CI" {
BeforeAll {
$fileName = "test.txt"
$filePath = Join-Path ${TestDrive} $fileName
if($OpenSSHTestInfo -eq $null)
{
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
if( -not (Test-path $testDir -PathType Container))
{
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
[Machine] $client = [Machine]::new([MachineRole]::Client)
[Machine] $server = [Machine]::new([MachineRole]::Server)
$client.SetupClient($server)
$server.SetupServer($client)
$fileName = "test.txt"
$logName = "sshdlog.txt"
$server = $OpenSSHTestInfo["Target"]
$port = 47003
Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction SilentlyContinue
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ContextName = $env:COMPUTERNAME
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new($ContextType, $ContextName)
$IdentityType = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
function Add-LocalUser
{
param([string] $UserName, [string] $Password)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if($user -eq $null)
{
try {
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::new($PrincipalContext,$UserName,$Password, $true)
$user.Save()
}
finally {
$user.Dispose()
}
}
}
function Add-LocalGroup
{
param([string] $groupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
if($group -eq $null)
{
try {
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::new($PrincipalContext,$groupName)
$group.Save()
}
finally {
$group.Dispose()
}
}
}
function Add-UserToLocalGroup
{
param([string]$UserName, [string]$Password, [string]$GroupName)
Add-LocalGroup -groupName $GroupName
Add-LocalUser -UserName $UserName -Password $Password
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if(-not $group.Members.Contains($user))
{
try {
$group.Members.Add($user)
$group.save()
}
finally {
$group.Dispose()
}
}
}
function Remove-UserFromLocalGroup
{
param([string]$UserName, [string]$GroupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if($group.Members.Contains($user))
{
try {
$group.Members.Remove($user)
$group.save()
}
finally {
$group.Dispose()
}
}
}
function Clenaup-LocalGroup
{
param([string]$GroupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
if($group -ne $null)
{
try {
$group.Delete()
}
finally {
$group.Dispose()
}
}
}
$platform = Get-Platform
$skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
#suppress the firewall blocking dialogue on win7
netsh advfirewall firewall add rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any action=allow dir=in
}
}
AfterEach { $tI++ }
AfterAll {
$client.CleanupClient()
$server.CleanupServer()
$PrincipalContext.Dispose()
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
netsh advfirewall firewall delete rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any dir=in
}
}
<#
@ -24,7 +140,6 @@
#>
Context "Tests of AllowGroups, AllowUsers, DenyUsers, DenyGroups" {
BeforeAll {
Remove-Item -Path $filePath -Force -ea silentlycontinue
$password = "Bull_dog1"
$allowUser1 = "allowuser1"
@ -47,113 +162,183 @@
$denyGroup1 = "denygroup1"
$denyGroup2 = "denygroup2"
$denyGroup3 = "denygroup3"
$client.AddPasswordSetting($password)
}
AfterEach {
Remove-Item -Path $filePath -Force -ea SilentlyContinue
$sshdConfigPath = Join-Path $PSScriptRoot testdata\SSHD_Config
$testknownhosts = Join-path $PSScriptRoot testdata\test_known_hosts
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
#add wrong password so ssh does not prompt password if failed with authorized keys
Add-PasswordSetting -Pass $password
$tI=1
}
BeforeEach {
$filePath = Join-Path $testDir "$tC.$tI.$fileName"
$logPath = Join-Path $testDir "$tC.$tI.$logName"
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
AfterAll {
$client.CleanupPasswordSetting()
AfterAll {
Remove-PasswordSetting
$tC++
}
It 'User with full name in the list of AllowUsers' {
$server.AddUserToLocalGroup($allowUser1, $password, $allowGroup1)
It "$tC.$tI-User with full name in the list of AllowUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser1 -Password $password -GroupName $allowGroup1
$o = ssh -p $port $allowUser1@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser1 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with * wildcard" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser2 -Password $password -GroupName $allowGroup1
$client.RunCmd(".\ssh $($allowUser1)@$($server.MachineName) hostname > $filePath")
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser1, $allowGroup1)
$o = ssh -p $port $allowUser2@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser2 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with * wildcard' {
$server.AddUserToLocalGroup($allowUser2, $password, $allowGroup1)
It "$tC.$tI-User with ? wildcard" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser3 -Password $password -GroupName $allowGroup1
$client.RunCmd(".\ssh $($allowUser2)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Be 0
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser2, $allowGroup1)
$o = ssh -p $port $allowUser3@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser3 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with ? wildcard' {
$server.AddUserToLocalGroup($allowUser3, $password, $allowGroup1)
It "$tC.$tI-User with full name in the list of AllowUsers but not in any AllowGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-LocalUser -UserName $allowUser4 -Password $password
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $allowUser4@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with full name in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser1 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $denyUser1 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with * wildcard in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser2 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $denyUser2 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with ? wildcard in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser3 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
$client.RunCmd(".\ssh $($allowUser3)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Be 0
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser3, $allowGroup1)
Remove-UserFromLocalGroup -UserName $denyUser3 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with full name in the list of AllowUsers but not in any AllowGroups' {
$server.AddLocalUser($allowUser4, $password)
It "$tC.$tI-User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $allowGroup1
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $denyGroup1
$client.RunCmd(".\ssh $($allowUser4)@$($server.MachineName) hostname > $filePath")
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $allowGroup1
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $denyGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with full name in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser1, $password, $allowGroup1)
It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard * DenyGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
$client.RunCmd(".\ssh $($denyUser1)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser1, $allowGroup1)
}
It 'User with * wildcard in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser2, $password, $allowGroup1)
$str = ".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath"
$client.RunCmd(".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser2, $allowGroup1)
}
It 'User with ? wildcard in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser3, $password, $allowGroup1)
Add-UserToLocalGroup -UserName $localuser2 -Password $password -GroupName $denyGroup2
$client.RunCmd(".\ssh $($denyUser3)@$($server.MachineName) hostname > $filePath")
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser3, $allowGroup1)
}
It 'User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups' {
$server.AddUserToLocalGroup($localuser1, $password, $allowGroup1)
$server.AddUserToLocalGroup($localuser1, $password, $denyGroup1)
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
$client.RunCmd(".\ssh $($localuser1)@$($server.MachineName) hostname > $filePath")
Remove-UserFromLocalGroup -UserName $localuser2 -GroupName $denyGroup2
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($localuser1, $allowGroup1)
$server.RemoveUserFromLocalGroup($localuser1, $denyGroup1)
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User is listed in the list of AllowUsers but also in a wildcard * DenyGroups' {
$server.AddUserToLocalGroup($localuser2, $password, $denyGroup2)
$client.RunCmd(".\ssh $($localuser2)@$($server.MachineName) hostname > $filePath")
It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $localuser3 -Password $password -GroupName $denyGroup3
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $localuser3 -GroupName $denyGroup3
$server.RemoveUserFromLocalGroup($localuser2, $denyGroup2)
}
It 'User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups' {
$server.AddUserToLocalGroup($localuser3, $password, $denyGroup3)
$client.RunCmd(".\ssh $($localuser3)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($localuser3, $denyGroup3)
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
}
}

119
regress/pesterTests/testdata/SSHD_Config vendored Normal file
View File

@ -0,0 +1,119 @@
# test usage of sshd_config
Port 47003
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
# The default requires explicit activation of protocol 1
#Protocol 2
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
HostKey sshtest_hostkey_rsa
HostKey sshtest_hostkey_dsa
HostKey sshtest_hostkey_ecdsa
HostKey sshtest_hostkey_ed25519
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024
# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
LogLevel DEBUG3
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#RSAAuthentication yes
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM no
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10
#PermitTunnel no
#ChrootDirectory none
# no default banner path
#Banner none
# override default of no subsystems
Subsystem sftp sftp-server.exe -l DEBUG3
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# ForceCommand cvs server
PubkeyAcceptedKeyTypes ssh-ed25519*
DenyUsers denyuser1 deny*2 denyuse?3,
AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin
DenyGroups denygroup1 denygr*p2 deny?rou?3
AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
hostkeyagent \\.\pipe\openssh-ssh-agent

View File

@ -2084,6 +2084,32 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
process_queued_listen_addrs(options);
#ifdef WINDOWS
/* TODO - Refactor this into a platform specific post-read config processing routine.
* TODO - support all forms of username, groupname.
* a) domain\groupname
* b) domain\groupname@hostip
* c) full_domain_name\groupname
* d) full_domain_name\groupname@hostip
* e) user@domain
* f) domain\user
* g) fulldomain\user
* h) user@domain@hostip
*/
/* convert the users, user groups to lower case */
for(int i = 0; i < options->num_allow_users; i++)
lowercase(options->allow_users[i]);
for (int i = 0; i < options->num_deny_users; i++)
lowercase(options->deny_users[i]);
for (int i = 0; i < options->num_allow_groups; i++)
lowercase(options->allow_groups[i]);
for (int i = 0; i < options->num_deny_groups; i++)
lowercase(options->deny_groups[i]);
#endif // WINDOWS
}
static const char *