Fixing allow groups, deny groups. (PowerShell/Win32-OpenSSH#816) Convert users, groups read from sshd_config to lowercase.
This commit is contained in:
parent
e8a303673e
commit
ab2aefff6d
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
26
servconf.c
26
servconf.c
|
@ -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 *
|
||||
|
|
Loading…
Reference in New Issue