diff --git a/auth-passwd.c b/auth-passwd.c
index 2c04017..8cd1966 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -231,7 +231,7 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
#elif defined(WINDOWS)
HANDLE password_auth_token = NULL;
-HANDLE process_custom_lsa_auth(char*, const char*, char*);
+HANDLE process_custom_lsa_auth(const char*, const char*, const char*);
void
sys_auth_passwd_lsa(Authctxt *authctxt, const char *password)
@@ -253,8 +253,7 @@ sys_auth_passwd_lsa(Authctxt *authctxt, const char *password)
lsa_auth_pkg = utf16_to_utf8(lsa_auth_pkg_w);
if (!lsa_auth_pkg)
fatal("utf16_to_utf8 failed to convert lsa_auth_pkg_w:%ls", lsa_auth_pkg_w);
-
- debug("Authenticating using LSA Auth Package:%ls", lsa_auth_pkg_w);
+
password_auth_token = process_custom_lsa_auth(authctxt->pw->pw_name, password, lsa_auth_pkg);
}
}
diff --git a/auth.c b/auth.c
index 682136a..9db22bb 100644
--- a/auth.c
+++ b/auth.c
@@ -430,7 +430,7 @@ expand_authorized_keys(const char *filename, struct passwd *pw)
#ifdef WINDOWS
/* Return if the path is absolute. If not, prepend the '%h\\' */
- if ((strlen(file) > 1) && (file[1] == ':'))
+ if(is_absolute_path(file))
return (file);
i = snprintf(ret, sizeof(ret), "%s\\%s", pw->pw_dir, file);
diff --git a/channels.c b/channels.c
index 5a3ee46..539b10a 100644
--- a/channels.c
+++ b/channels.c
@@ -3950,8 +3950,6 @@ channel_disable_adm_local_opens(struct ssh *ssh)
void
channel_clear_permitted_opens(struct ssh *ssh)
{
- if(ssh == NULL)
- return;
struct ssh_channels *sc = ssh->chanctxt;
sc->permitted_opens = xrecallocarray(sc->permitted_opens,
diff --git a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 b/contrib/win32/openssh/OpenSSHBuildHelper.psm1
index 029ef62..f9f5ebc 100644
--- a/contrib/win32/openssh/OpenSSHBuildHelper.psm1
+++ b/contrib/win32/openssh/OpenSSHBuildHelper.psm1
@@ -197,7 +197,8 @@ function Start-OpenSSHBootstrap
Write-BuildMsg -AsVerbose -Message "$gitCmdPath already present in Path environment variable" -Silent:$silent
}
- $nativeMSBuildPath = Get-VS2015BuildToolPath
+ $VS2015Path = Get-VS2015BuildToolPath
+ $VS2017Path = Get-VS2017BuildToolPath
# Update machine environment path
if ($newMachineEnvironmentPath -ne $machinePath)
@@ -206,9 +207,24 @@ function Start-OpenSSHBootstrap
}
$vcVars = "${env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat"
- $sdkPath = "${env:ProgramFiles(x86)}\Windows Kits\8.1\bin\x86\register_app.vbs"
- $packageName = "vcbuildtools"
- If (($nativeMSBuildPath -eq $null) -or (-not (Test-Path $VcVars)) -or (-not (Test-Path $sdkPath))) {
+ $sdkPath = "${env:ProgramFiles(x86)}\Windows Kits\8.1\bin\x86\register_app.vbs"
+ #use vs2017 build tool if exists
+ if($VS2017Path -ne $null)
+ {
+ If (-not (Test-Path $sdkPath))
+ {
+ $packageName = "windows-sdk-8.1"
+ Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName ..."
+ choco install $packageName -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile
+ }
+
+ if(-not (Test-Path $VcVars))
+ {
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "VC++ 2015.3 v140 toolset are not installed."
+ }
+ }
+ elseIf (($VS2015Path -eq $null) -or (-not (Test-Path $VcVars)) -or (-not (Test-Path $sdkPath))) {
+ $packageName = "vcbuildtools"
Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName ..."
choco install $packageName -ia "/InstallSelectableItems VisualCppBuildTools_ATLMFC_SDK;VisualCppBuildTools_NETFX_SDK;Win81SDK_CppBuildSKUV1" -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile
$errorCode = $LASTEXITCODE
@@ -234,9 +250,9 @@ function Start-OpenSSHBootstrap
Write-BuildMsg -AsError -ErrorAction Stop -Message "User choose not to restart the machine to apply the changes."
}
}
- else
+ elseif($errorCode -ne 0)
{
- Write-BuildMsg -AsError -ErrorAction Stop -Message "$packageName installation failed with error code $errorCode"
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "$packageName installation failed with error code $errorCode."
}
}
else
@@ -244,14 +260,11 @@ function Start-OpenSSHBootstrap
Write-BuildMsg -AsVerbose -Message 'VC++ 2015 Build Tools already present.'
}
- if($NativeHostArch.ToLower().Startswith('arm'))
- {
- $nativeMSBuildPath = Get-VS2017BuildToolPath
- If ($nativeMSBuildPath -eq $null)
- {
- #todo, install vs 2017 build tools
- Write-BuildMsg -AsError -ErrorAction Stop -Message "The required msbuild 15.0 is not installed on the machine."
- }
+ if($NativeHostArch.ToLower().Startswith('arm') -and ($VS2017Path -eq $null))
+ {
+
+ #todo, install vs 2017 build tools
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "The required msbuild 15.0 is not installed on the machine."
}
if($OneCore -or ($NativeHostArch.ToLower().Startswith('arm')))
@@ -268,7 +281,7 @@ function Start-OpenSSHBootstrap
# Ensure the VS C toolset is installed
if ($null -eq $env:VS140COMNTOOLS)
{
- Write-BuildMsg -AsError -ErrorAction Stop -Message "Cannot find Visual Studio 2015 Environment variable VS140COMNTOOlS"
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "Cannot find Visual Studio 2015 Environment variable VS140COMNTOOlS."
}
$item = Get-Item(Join-Path -Path $env:VS140COMNTOOLS -ChildPath '../../vc')
@@ -314,7 +327,7 @@ function Copy-LibreSSLSDK
Copy-Item -Container -Path $sourcePath -Destination $PSScriptRoot -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable e
if($e -ne $null)
{
- Write-BuildMsg -AsError -ErrorAction Stop -Message "Copy LibreSSLSDK from $sourcePath to $PSScriptRoot failed"
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "Copy LibreSSLSDK from $sourcePath to $PSScriptRoot failed."
}
}
@@ -330,7 +343,8 @@ function Start-OpenSSHPackage
[string]$Configuration = "Release",
# Copy payload to DestinationPath instead of packaging
- [string]$DestinationPath = ""
+ [string]$DestinationPath = "",
+ [switch]$NoOpenSSL
)
[System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot
@@ -390,7 +404,10 @@ function Start-OpenSSHPackage
#copy libcrypto dll
$libreSSLSDKPath = Join-Path $PSScriptRoot $script:libreSSLSDKStr
- Copy-Item -Path $(Join-Path $libreSSLSDKPath "$NativeHostArch\libcrypto.dll") -Destination $packageDir -Force -ErrorAction Stop
+ if (-not $NoOpenSSL.IsPresent)
+ {
+ Copy-Item -Path $(Join-Path $libreSSLSDKPath "$NativeHostArch\libcrypto.dll") -Destination $packageDir -Force -ErrorAction Stop
+ }
if ($DestinationPath -ne "") {
if (Test-Path $DestinationPath) {
@@ -400,7 +417,7 @@ function Start-OpenSSHPackage
New-Item -ItemType Directory $DestinationPath -Force | Out-Null
}
Copy-Item -Path $packageDir\* -Destination $DestinationPath -Force -Recurse
- Write-BuildMsg -AsInfo -Message "Copied payload to $DestinationPath"
+ Write-BuildMsg -AsInfo -Message "Copied payload to $DestinationPath."
}
else {
Remove-Item ($packageDir + '.zip') -Force -ErrorAction SilentlyContinue
@@ -411,7 +428,7 @@ function Start-OpenSSHPackage
}
else
{
- Write-BuildMsg -AsInfo -Message "Packaged Payload not compressed."
+ Write-BuildMsg -AsInfo -Message "Packaged Payload not compressed."
}
}
Remove-Item $packageDir -Recurse -Force -ErrorAction SilentlyContinue
@@ -470,7 +487,7 @@ function Start-OpenSSHBuild
Remove-Item -Path $script:BuildLogFile -force
}
- Write-BuildMsg -AsInfo -Message "Starting Open SSH build; Build Log: $($script:BuildLogFile)"
+ Write-BuildMsg -AsInfo -Message "Starting Open SSH build; Build Log: $($script:BuildLogFile)."
Start-OpenSSHBootstrap -OneCore:$OneCore
@@ -523,17 +540,25 @@ function Start-OpenSSHBuild
$xml.Project.PropertyGroup.WindowsSDKVersion = $win10SDKVer.ToString()
$xml.Project.PropertyGroup.AdditionalDependentLibs = 'onecore.lib'
$xml.Project.PropertyGroup.MinimalCoreWin = 'true'
+
+ #Use onecore libcrypto binaries
+ $xml.Project.PropertyGroup."LibreSSL-x86-Path" = '$(SolutionDir)\LibreSSLSDK\onecore\x86\'
+ $xml.Project.PropertyGroup."LibreSSL-x64-Path" = '$(SolutionDir)\LibreSSLSDK\onecore\x64\'
+ $xml.Project.PropertyGroup."LibreSSL-arm-Path" = '$(SolutionDir)\LibreSSLSDK\onecore\arm\'
+ $xml.Project.PropertyGroup."LibreSSL-arm64-Path" = '$(SolutionDir)\LibreSSLSDK\onecore\arm64\'
+
$xml.Save($PathTargets)
}
$solutionFile = Get-SolutionFile -root $repositoryRoot.FullName
- $cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/m", "/noconlog", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic")
-
- if($NativeHostArch.ToLower().Startswith('arm'))
+ $cmdMsg = @("${solutionFile}", "/t:Rebuild", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/m", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic")
+ if($silent)
{
- $msbuildCmd = Get-VS2017BuildToolPath
+ $cmdMsg += "/noconlog"
}
- else
+
+ $msbuildCmd = Get-VS2017BuildToolPath
+ if($msbuildCmd -eq $null)
{
$msbuildCmd = Get-VS2015BuildToolPath
}
diff --git a/contrib/win32/openssh/OpenSSHTestHelper.psm1 b/contrib/win32/openssh/OpenSSHTestHelper.psm1
index 1d33594..c0fbdfc 100644
--- a/contrib/win32/openssh/OpenSSHTestHelper.psm1
+++ b/contrib/win32/openssh/OpenSSHTestHelper.psm1
@@ -162,8 +162,14 @@ WARNING: Following changes will be made to OpenSSH configuration
New-Item -ItemType Directory -Path $TestDataPath -Force -ErrorAction SilentlyContinue | out-null
}
- #Backup existing OpenSSH configuration
+
+ if(-not (Test-Path $OpenSSHConfigPath -pathType Container))
+ {
+ #starting the service will create ssh config folder
+ start-service sshd
+ }
$backupConfigPath = Join-Path $OpenSSHConfigPath sshd_config.ori
+ #Backup existing OpenSSH configuration
if (-not (Test-Path $backupConfigPath -PathType Leaf)) {
Copy-Item (Join-Path $OpenSSHConfigPath sshd_config) $backupConfigPath -Force
}
@@ -244,7 +250,7 @@ WARNING: Following changes will be made to OpenSSH configuration
$authorizedKeyPath = Join-Path $ssouserProfile .ssh\authorized_keys
$testPubKeyPath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519.pub
Copy-Item $testPubKeyPath $authorizedKeyPath -Force -ErrorAction SilentlyContinue
- Repair-AuthorizedKeyPermission -FilePath $authorizedKeyPath -confirm:$false
+ Repair-AuthorizedKeyPermission -FilePath $authorizedKeyPath -confirm:$false
copy-item (Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519) $Global:OpenSSHTestInfo["TestDataPath"]
$testPriKeypath = Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_userssokey_ed25519
diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs
index a5e8184..eab416c 100644
--- a/contrib/win32/openssh/config.h.vs
+++ b/contrib/win32/openssh/config.h.vs
@@ -1565,7 +1565,7 @@
#define _PATH_PASSWD_PROG "/usr/bin/passwd"
/* Specify location of ssh.pid */
-#define _PATH_SSH_PIDDIR "."
+/* #undef _PATH_SSH_PIDDIR */
/* Define if we don't have struct __res_state in resolv.h */
#define __res_state state
@@ -1693,6 +1693,7 @@
#define _PATH_PRIVSEP_CHROOT_DIR "."
#define SSHDIR "__PROGRAMDATA__\\ssh"
+#define _PATH_SSH_PIDDIR SSHDIR
#define _PATH_SFTP_SERVER "sftp-server.exe"
#define _PATH_SSH_PROGRAM "ssh.exe"
#define _PATH_LS "dir"
diff --git a/contrib/win32/openssh/paths.targets b/contrib/win32/openssh/paths.targets
index 94f5221..20bea49 100644
--- a/contrib/win32/openssh/paths.targets
+++ b/contrib/win32/openssh/paths.targets
@@ -12,7 +12,7 @@
true
libcrypto.lib;
8.1
- bcrypt.lib;Userenv.lib;Crypt32.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Netapi32.lib;Rpcrt4.lib
+ bcrypt.lib;Userenv.lib;Crypt32.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Netapi32.lib;Rpcrt4.lib;ntdll.lib
false
\ No newline at end of file
diff --git a/contrib/win32/openssh/ssh-add-hostkey.ps1 b/contrib/win32/openssh/ssh-add-hostkey.ps1
deleted file mode 100644
index ab03f27..0000000
--- a/contrib/win32/openssh/ssh-add-hostkey.ps1
+++ /dev/null
@@ -1,96 +0,0 @@
-<#
- Author: manoj.ampalam@microsoft.com
-
- Description: ssh-add.exe like Powershell utility to do host key management.
- Input parameter mimic ssh-add.exe cmdline arguments.
-
- Host keys on Windows need to be registered as SYSTEM (i.e ssh-add.exe would
- need to run as SYSTEM while talking to ssh-agent). This typically requires
- an external utility like psexec.
-
- This script tries to use the Task scheduler option:
- - registers a task scheduler task to run ssh-add.exe operation as SYSTEM
- - actual output of ssh-add.exe is written to file (both stdout and stderr)
- - Dumps the file contents to console
-
-#>
-
-# see https://linux.die.net/man/1/ssh-add for what the arguments mean
-[CmdletBinding(DefaultParameterSetName='Add_key')]
-Param(
- [Parameter(ParameterSetName="List_fingerprints")]
- [switch]$List_fingerprints, #ssh-add -l
- [Parameter(ParameterSetName="List_pubkeys")]
- [switch]$List_pubkeys, #ssh-add -L
- [Parameter(ParameterSetName="Delete_key")]
- [switch]$Delete_key, #ssh-add -d
- [Parameter(ParameterSetName="Delete_all")]
- [switch]$Delete_all, #ssh-add -D
- [Parameter(Mandatory, Position=0, ParameterSetName="Delete_key")]
- [Parameter(Mandatory, Position=0, ParameterSetName="Add_key")]
- [ValidateNotNullOrEmpty()]
- [string]$key
-)
-
-$ssh_add_cmd = get-command ssh-add.exe -ErrorAction Ignore
-if($ssh_add_cmd -eq $null)
-{
- Throw "Cannot find ssh-add.exe."
-}
-
-#create ssh-add cmdlinet
-$ssh_add_cmd_str = $ssh_add_cmd.Path
-if ($List_fingerprints) { $ssh_add_cmd_str += " -l" }
-elseif ($List_pubkeys) { $ssh_add_cmd_str += " -L" }
-elseif ($Delete_key) { $ssh_add_cmd_str += " -d $key" }
-elseif ($Delete_all) { $ssh_add_cmd_str += " -D" }
-else
-{
- if ( ($key.Length -gt 0) -and (-not($key.Contains("host"))) ) {
- Do {
- $input = Read-Host -Prompt "Are you sure the provided key is a host key? [Yes] Y; [No] N (default is `"Y`")"
- if([string]::IsNullOrEmpty($input))
- {
- $input = 'Y'
- }
- } until ($input -match "^(y(es)?|N(o)?)$")
- $result = $Matches[0]
- if (-not($result.ToLower().Startswith('y'))) { exit }
- }
- $ssh_add_cmd_str += " $key"
-}
-
-#globals
-$taskfolder = "\OpenSSHUtils\hostkey_tasks\"
-$taskname = "hostkey_task"
-$ssh_add_output = Join-Path (pwd).Path "ssh-add-hostkey-tmp.txt"
-$task_argument = "/c `"$ssh_add_cmd_str > $ssh_add_output 2>&1 `""
-
-#create TaskScheduler task
-$ac = New-ScheduledTaskAction -Execute "cmd.exe" -Argument $task_argument -WorkingDirectory (pwd).path
-$task = Register-ScheduledTask -TaskName $taskname -User System -Action $ac -TaskPath $taskfolder -Force
-
-#run the task
-if (Test-Path $ssh_add_output) {Remove-Item $ssh_add_output -Force}
-Start-ScheduledTask -TaskPath $taskfolder -TaskName $taskname
-
-#if still running, wait a little while for task to complete
-$num = 0
-while ((Get-ScheduledTask -TaskName $taskname -TaskPath $taskfolder).State -eq "Running")
-{
- sleep 1
- $num++
- if($num -gt 20) { break }
-}
-if (-not(Test-Path $ssh_add_output)) {throw "cannot find task output file. Something went WRONG!!! "}
-
-#dump output to console
-Get-Content $ssh_add_output
-
-#cleanup task and output file
-Remove-Item $ssh_add_output -Force
-Unregister-ScheduledTask -TaskPath $taskfolder -TaskName $taskname -Confirm:$false
-
-
-
-
diff --git a/contrib/win32/openssh/sshd_config b/contrib/win32/openssh/sshd_config
index ccf5113..dfd050b 100644
--- a/contrib/win32/openssh/sshd_config
+++ b/contrib/win32/openssh/sshd_config
@@ -11,10 +11,10 @@
#ListenAddress 0.0.0.0
#ListenAddress ::
-#HostKey /etc/ssh/ssh_host_rsa_key
-#HostKey /etc/ssh/ssh_host_dsa_key
-#HostKey /etc/ssh/ssh_host_ecdsa_key
-#HostKey /etc/ssh/ssh_host_ed25519_key
+#HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key
+#HostKey __PROGRAMDATA__/ssh/ssh_host_dsa_key
+#HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key
+#HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
@@ -39,7 +39,7 @@ AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
-# For this to work you will also need host keys in %windir%/programdata/openssh/config/ssh_known_hosts
+# For this to work you will also need host keys in %programData%/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc
index 4fb3216..e08cf30 100644
Binary files a/contrib/win32/openssh/version.rc and b/contrib/win32/openssh/version.rc differ
diff --git a/contrib/win32/win32compat/lsa_missingdefs.h b/contrib/win32/win32compat/lsa_missingdefs.h
new file mode 100644
index 0000000..87472fc
--- /dev/null
+++ b/contrib/win32/win32compat/lsa_missingdefs.h
@@ -0,0 +1,55 @@
+/*
+* Missing public definitions from Ntsecapi.h
+*/
+
+
+typedef enum _LSA_SID_NAME_MAPPING_OPERATION_TYPE {
+ LsaSidNameMappingOperation_Add,
+ LsaSidNameMappingOperation_Remove,
+ LsaSidNameMappingOperation_AddMultiple,
+} LSA_SID_NAME_MAPPING_OPERATION_TYPE, *PLSA_SID_NAME_MAPPING_OPERATION_TYPE;
+
+typedef enum _LSA_SID_NAME_MAPPING_OPERATION_ERROR {
+ LsaSidNameMappingOperation_Success,
+ LsaSidNameMappingOperation_NonMappingError,
+ LsaSidNameMappingOperation_NameCollision,
+ LsaSidNameMappingOperation_SidCollision,
+ LsaSidNameMappingOperation_DomainNotFound,
+ LsaSidNameMappingOperation_DomainSidPrefixMismatch,
+ LsaSidNameMappingOperation_MappingNotFound,
+} LSA_SID_NAME_MAPPING_OPERATION_ERROR, *PLSA_SID_NAME_MAPPING_OPERATION_ERROR;
+
+typedef struct _LSA_SID_NAME_MAPPING_OPERATION_ADD_INPUT {
+ UNICODE_STRING DomainName;
+ UNICODE_STRING AccountName;
+ PSID Sid;
+ ULONG Flags;
+} LSA_SID_NAME_MAPPING_OPERATION_ADD_INPUT, *PLSA_SID_NAME_MAPPING_OPERATION_ADD_INPUT;
+
+typedef struct _LSA_SID_NAME_MAPPING_OPERATION_REMOVE_INPUT {
+ UNICODE_STRING DomainName;
+ UNICODE_STRING AccountName;
+} LSA_SID_NAME_MAPPING_OPERATION_REMOVE_INPUT, *PLSA_SID_NAME_MAPPING_OPERATION_REMOVE_INPUT;
+
+typedef union _LSA_SID_NAME_MAPPING_OPERATION_INPUT {
+ LSA_SID_NAME_MAPPING_OPERATION_ADD_INPUT AddInput;
+ LSA_SID_NAME_MAPPING_OPERATION_REMOVE_INPUT RemoveInput;
+} LSA_SID_NAME_MAPPING_OPERATION_INPUT, *PLSA_SID_NAME_MAPPING_OPERATION_INPUT;
+
+typedef struct _LSA_SID_NAME_MAPPING_OPERATION_GENERIC_OUTPUT {
+ LSA_SID_NAME_MAPPING_OPERATION_ERROR ErrorCode;
+} LSA_SID_NAME_MAPPING_OPERATION_GENERIC_OUTPUT, *PLSA_SID_NAME_MAPPING_OPERATION_GENERIC_OUTPUT;
+
+typedef LSA_SID_NAME_MAPPING_OPERATION_GENERIC_OUTPUT LSA_SID_NAME_MAPPING_OPERATION_ADD_OUTPUT, *PLSA_SID_NAME_MAPPING_OPERATION_ADD_OUTPUT;
+typedef LSA_SID_NAME_MAPPING_OPERATION_GENERIC_OUTPUT LSA_SID_NAME_MAPPING_OPERATION_REMOVE_OUTPUT, *PLSA_SID_NAME_MAPPING_OPERATION_REMOVE_OUTPUT;
+
+typedef union _LSA_SID_NAME_MAPPING_OPERATION_OUTPUT {
+ LSA_SID_NAME_MAPPING_OPERATION_ADD_OUTPUT AddOutput;
+ LSA_SID_NAME_MAPPING_OPERATION_REMOVE_OUTPUT RemoveOutput;
+} LSA_SID_NAME_MAPPING_OPERATION_OUTPUT, *PLSA_SID_NAME_MAPPING_OPERATION_OUTPUT;
+
+NTSTATUS WINAPI LsaManageSidNameMapping(
+ LSA_SID_NAME_MAPPING_OPERATION_TYPE OpType,
+ PLSA_SID_NAME_MAPPING_OPERATION_INPUT OpInput,
+ PLSA_SID_NAME_MAPPING_OPERATION_OUTPUT *OpOutput
+);
diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c
index 9ce5e87..79eb1b6 100644
--- a/contrib/win32/win32compat/misc.c
+++ b/contrib/win32/win32compat/misc.c
@@ -1460,9 +1460,86 @@ int
is_absolute_path(char *path)
{
int retVal = 0;
- if (*path == '/' || *path == '\\' || (*path != '\0' && path[1] == ':') ||
+ if(*path == '\"') /* skip double quote if path is "c:\abc" */
+ path++;
+
+ if (*path == '/' || *path == '\\' || (*path != '\0' && isalpha(*path) && path[1] == ':') ||
((strlen(path) >= strlen(PROGRAM_DATA)) && (memcmp(path, PROGRAM_DATA, strlen(PROGRAM_DATA)) == 0)))
retVal = 1;
-
+
return retVal;
}
+
+/* return -1 - in case of failure, 0 - success */
+int
+create_directory_withsddl(char *path, char *sddl)
+{
+ struct stat st;
+ if (stat(path, &st) < 0) {
+ PSECURITY_DESCRIPTOR pSD = NULL;
+ SECURITY_ATTRIBUTES sa;
+ memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = FALSE;
+
+ wchar_t *path_w = utf8_to_utf16(path);
+ if (!path_w) {
+ error("%s utf8_to_utf16() has failed to convert string:%s", __func__, path);
+ return -1;
+ }
+
+ wchar_t *sddl_w = utf8_to_utf16(sddl);
+ if (!sddl_w) {
+ error("%s utf8_to_utf16() has failed to convert string:%s", __func__, sddl);
+ return -1;
+ }
+
+ if (ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl_w, SDDL_REVISION, &pSD, NULL) == FALSE) {
+ error("ConvertStringSecurityDescriptorToSecurityDescriptorW failed with error code %d", GetLastError());
+ return -1;
+ }
+
+ if (IsValidSecurityDescriptor(pSD) == FALSE) {
+ error("IsValidSecurityDescriptor return FALSE");
+ return -1;
+ }
+
+ sa.lpSecurityDescriptor = pSD;
+ if (!CreateDirectoryW(path_w, &sa)) {
+ error("Failed to create directory:%ls error:%d", path_w, GetLastError());
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* return -1 - in case of failure, 0 - success */
+int
+copy_file(char *source, char *destination)
+{
+ if (!source || !destination) return 0;
+
+ struct stat st;
+ if ((stat(source, &st) >= 0) && (stat(destination, &st) < 0)) {
+ wchar_t *source_w = utf8_to_utf16(source);
+ if (!source_w) {
+ error("%s utf8_to_utf16() has failed to convert string:%s", __func__, source_w);
+ return -1;
+ }
+
+ wchar_t *destination_w = utf8_to_utf16(destination);
+ if (!destination_w) {
+ error("%s utf8_to_utf16() has failed to convert string:%s", __func__, destination_w);
+ return -1;
+ }
+
+ if (!CopyFileW(source_w, destination_w, FALSE)) {
+ error("Failed to copy %ls to %ls, error:%d", source_w, destination_w, GetLastError());
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/contrib/win32/win32compat/misc_internal.h b/contrib/win32/win32compat/misc_internal.h
index b7d39c8..f66bfff 100644
--- a/contrib/win32/win32compat/misc_internal.h
+++ b/contrib/win32/win32compat/misc_internal.h
@@ -2,7 +2,7 @@
#include
#define PATH_MAX MAX_PATH
-
+#define SSH_REGISTRY_ROOT L"SOFTWARE\\OpenSSH"
#define GOTO_CLEANUP_IF(_cond_,_err_) do { \
if ((_cond_)) { \
hr = _err_; \
@@ -40,3 +40,5 @@ int get_machine_domain_name(wchar_t *domain, int size);
char* get_program_data_path();
HANDLE get_user_token(char* user);
int load_user_profile(HANDLE user_token, char* user);
+int copy_file(char *source, char *destination);
+int create_directory_withsddl(char *path, char *sddl);
\ No newline at end of file
diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c
index f4e3f04..b776449 100644
--- a/contrib/win32/win32compat/pwd.c
+++ b/contrib/win32/win32compat/pwd.c
@@ -111,6 +111,8 @@ get_passwd(const char *user_utf8, LPWSTR user_sid)
int tmp_len = PATH_MAX;
PDOMAIN_CONTROLLER_INFOW pdc = NULL;
DWORD dsStatus, uname_upn_len = 0, uname_len = 0, udom_len = 0;
+ wchar_t wmachine_name[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD wmachine_name_len = MAX_COMPUTERNAME_LENGTH + 1;
errno_t r = 0;
errno = 0;
@@ -135,6 +137,14 @@ get_passwd(const char *user_utf8, LPWSTR user_sid)
udom_utf16 = NULL;
}
+ if (udom_utf16) {
+ /* this should never fail */
+ GetComputerNameW(wmachine_name, &wmachine_name_len);
+ /* If this is a local account (domain part and computer name are the same), strip out domain */
+ if (_wcsicmp(udom_utf16, wmachine_name) == 0)
+ udom_utf16 = NULL;
+ }
+
if (user_sid == NULL) {
NET_API_STATUS status;
if ((status = NetUserGetInfo(udom_utf16, uname_utf16, 23, &user_info)) != NERR_Success) {
diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c
index 31f1619..41847f5 100644
--- a/contrib/win32/win32compat/shell-host.c
+++ b/contrib/win32/win32compat/shell-host.c
@@ -1790,7 +1790,7 @@ wmain(int ac, wchar_t **av)
}
memset(&job_info, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
- job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+ job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK;
if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info)) ||
!AssignProcessToJobObject(job, GetCurrentProcess())) {
diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h
index e5fe79c..d8943c6 100644
--- a/contrib/win32/win32compat/ssh-agent/agent.h
+++ b/contrib/win32/win32compat/ssh-agent/agent.h
@@ -1,11 +1,11 @@
#include
#include
#include "Debug.h"
+#include "misc_internal.h"
#define MAX_MESSAGE_SIZE 256 * 1024
-#define SSH_ROOT L"SOFTWARE\\OpenSSH"
-#define SSH_AGENT_ROOT SSH_ROOT L"\\Agent"
+#define SSH_AGENT_ROOT SSH_REGISTRY_ROOT L"\\Agent"
#define SSH_KEYS_KEY L"Keys"
#define SSH_KEYS_ROOT SSH_AGENT_ROOT L"\\" SSH_KEYS_KEY
diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c
index 93527db..f2e46d1 100644
--- a/contrib/win32/win32compat/w32fd.c
+++ b/contrib/win32/win32compat/w32fd.c
@@ -37,6 +37,7 @@
#include "inc\fcntl.h"
#include "inc\sys\un.h"
#include "inc\utf.h"
+#include "inc\stdio.h"
#include "w32fd.h"
#include "signal_internal.h"
@@ -953,16 +954,14 @@ spawn_child_internal(char* cmd, char *const argv[], HANDLE in, HANDLE out, HANDL
int add_module_path = 0, ret = -1;
/* should module path be added */
- do {
- if (!cmd)
- break;
- t = cmd;
- if (*t == '\"')
- t++;
- if (t[0] == '\0' || t[0] == '\\' || t[0] == '.' || t[1] == ':')
- break;
+ if (!cmd) {
+ error("%s invalid argument cmd:%s", __func__, cmd);
+ return -1;
+ }
+
+ t = cmd;
+ if (!is_absolute_path(t))
add_module_path = 1;
- } while (0);
/* compute total cmdline len*/
if (add_module_path)
@@ -1040,6 +1039,7 @@ spawn_child_internal(char* cmd, char *const argv[], HANDLE in, HANDLE out, HANDL
}
else {
errno = GetLastError();
+ error("%s failed error:%d", (as_user?"CreateProcessAsUserW":"CreateProcessW"), GetLastError());
goto cleanup;
}
diff --git a/contrib/win32/win32compat/win32_usertoken_utils.c b/contrib/win32/win32compat/win32_usertoken_utils.c
index 7cb6fd2..82b16f9 100644
--- a/contrib/win32/win32compat/win32_usertoken_utils.c
+++ b/contrib/win32/win32compat/win32_usertoken_utils.c
@@ -35,11 +35,16 @@
#include
#include
#include
+#include
+
#include "inc\utf.h"
#include "logonuser.h"
#include
+#include
+#include
#include
#include "misc_internal.h"
+#include "lsa_missingdefs.h"
#include "Debug.h"
#pragma warning(push, 3)
@@ -116,7 +121,7 @@ done:
#define MAX_PW_LEN 64
static HANDLE
-generate_user_token(wchar_t* user_cpn) {
+generate_s4u_user_token(wchar_t* user_cpn) {
HANDLE lsa_handle = 0, token = 0;
LSA_OPERATIONAL_MODE mode;
ULONG auth_package_id;
@@ -223,14 +228,14 @@ done:
}
HANDLE
-process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
+process_custom_lsa_auth(const char* user, const char* pwd, const char* lsa_pkg)
{
- wchar_t *userw = NULL, *pwdw = NULL, *domw = NULL, *tmp, *providerw = NULL;
+ wchar_t *providerw = NULL;
HANDLE token = NULL, lsa_handle = NULL;
LSA_OPERATIONAL_MODE mode;
ULONG auth_package_id, logon_info_size = 0;
NTSTATUS ret, subStatus;
- wchar_t *logon_info = NULL;
+ wchar_t *logon_info_w = NULL;
LSA_STRING logon_process_name, lsa_auth_package_name, originName;
TOKEN_SOURCE sourceContext;
PVOID pProfile = NULL;
@@ -238,19 +243,34 @@ process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
QUOTA_LIMITS quotas;
DWORD cbProfile;
int retVal = -1;
+ char *domain = NULL, *logon_info = NULL, user_name[UNLEN] = { 0, }, *tmp = NULL;
- debug("LSA auth request, user:%s lsa_pkg:%s ", user, lsa_pkg);
+ debug3("LSA auth request, user:%s lsa_pkg:%s ", user, lsa_pkg);
- if ((userw = utf8_to_utf16(user)) == NULL ||
- (pwdw = utf8_to_utf16(pwd)) == NULL) {
- debug("out of memory");
- goto done;
+ logon_info_size = (ULONG)(strlen(user) + strlen(pwd) + 2); // 1 - ";", 1 - "\0"
+ strcpy_s(user_name, _countof(user_name), user);
+ if (tmp = strstr(user_name, "@")) {
+ domain = tmp + 1;
+ *tmp = '\0';
+ logon_info_size++; // 1 - ";"
}
- /* split user and domain */
- if ((tmp = wcschr(userw, L'@')) != NULL) {
- domw = tmp + 1;
- *tmp = L'\0';
+ logon_info = malloc(logon_info_size);
+ if(!logon_info)
+ fatal("%s out of memory", __func__);
+
+ strcpy_s(logon_info, logon_info_size, user_name);
+ strcat_s(logon_info, logon_info_size, ";");
+ strcat_s(logon_info, logon_info_size, pwd);
+
+ if (domain) {
+ strcat_s(logon_info, logon_info_size, ";");
+ strcat_s(logon_info, logon_info_size, domain);
+ }
+
+ if (NULL == (logon_info_w = utf8_to_utf16(logon_info))) {
+ error("utf8_to_utf16 failed to convert %s", logon_info);
+ goto done;
}
/* call into LSA provider , get and duplicate token */
@@ -268,30 +288,19 @@ process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
goto done;
}
- logon_info_size = (ULONG)((wcslen(userw) + wcslen(pwdw) + wcslen(domw) + 3) * sizeof(wchar_t));
- logon_info = (wchar_t *)malloc(logon_info_size);
- if (NULL == logon_info)
- fatal("%s:out of memory", __func__);
-
- wcscpy_s(logon_info, logon_info_size, userw);
- wcscat_s(logon_info, logon_info_size, L";");
- wcscat_s(logon_info, logon_info_size, pwdw);
- wcscat_s(logon_info, logon_info_size, L";");
- wcscat_s(logon_info, logon_info_size, domw);
-
memcpy(sourceContext.SourceName, "sshd", sizeof(sourceContext.SourceName));
if (!AllocateLocallyUniqueId(&sourceContext.SourceIdentifier)) {
error("AllocateLocallyUniqueId failed, error:%d", GetLastError());
goto done;
- }
+ }
if ((ret = LsaLogonUser(lsa_handle,
&originName,
Network,
auth_package_id,
- logon_info,
- logon_info_size,
+ logon_info_w,
+ logon_info_size * sizeof(wchar_t),
NULL,
&sourceContext,
&pProfile,
@@ -299,8 +308,8 @@ process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
&logonId,
&token,
"as,
- &subStatus)) != STATUS_SUCCESS) {
- if(ret == STATUS_ACCOUNT_RESTRICTION)
+ &subStatus)) != STATUS_SUCCESS) {
+ if (ret == STATUS_ACCOUNT_RESTRICTION)
error("LsaLogonUser failed, error:%x subStatus:%ld", ret, subStatus);
else
error("LsaLogonUser failed error:%x", ret);
@@ -308,23 +317,23 @@ process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
goto done;
}
+ debug3("LSA auth request is successful for user:%s ", user);
retVal = 0;
done:
- /* delete allocated memory*/
if (lsa_handle)
LsaDeregisterLogonProcess(lsa_handle);
- if (logon_info)
- free(logon_info);
if (pProfile)
LsaFreeReturnBuffer(pProfile);
- if (userw)
- free(userw);
- if (pwdw)
- free(pwdw);
+ if (logon_info)
+ free(logon_info);
+ if (logon_info_w)
+ free(logon_info_w);
return token;
}
+HANDLE generate_sshd_virtual_token();
+
HANDLE
get_user_token(char* user) {
HANDLE token = NULL;
@@ -335,12 +344,18 @@ get_user_token(char* user) {
goto done;
}
- if ((token = generate_user_token(user_utf16)) == 0) {
+ if (wcscmp(user_utf16, L"sshd") == 0) {
+ if ((token = generate_sshd_virtual_token()) != 0)
+ goto done;
+ debug3("unable to generate sshd virtual token, falling back to s4u");
+ }
+
+ if ((token = generate_s4u_user_token(user_utf16)) == 0) {
error("unable to generate token for user %ls", user_utf16);
/* work around for https://github.com/PowerShell/Win32-OpenSSH/issues/727 by doing a fake login */
LogonUserExExWHelper(L"FakeUser", L"FakeDomain", L"FakePasswd",
LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL);
- if ((token = generate_user_token(user_utf16)) == 0) {
+ if ((token = generate_s4u_user_token(user_utf16)) == 0) {
error("unable to generate token on 2nd attempt for user %ls", user_utf16);
goto done;
}
@@ -378,4 +393,209 @@ done:
return r;
}
+
+/* *** virtual account token generation logic ***/
+
+char* LSAMappingErrorDetails[] = {
+ "LsaSidNameMappingOperation_Success",
+ "LsaSidNameMappingOperation_NonMappingError",
+ "LsaSidNameMappingOperation_NameCollision",
+ "LsaSidNameMappingOperation_SidCollision",
+ "LsaSidNameMappingOperation_DomainNotFound",
+ "LsaSidNameMappingOperation_DomainSidPrefixMismatch",
+ "LsaSidNameMappingOperation_MappingNotFound"
+};
+
+#define VIRTUALUSER_DOMAIN L"VIRTUAL USERS"
+#define VIRTUALUSER_GROUP_NAME L"ALL VIRTUAL USERS"
+
+/* returns 0 on success -1 on failure */
+int
+AddSidMappingToLsa(PUNICODE_STRING domain_name,
+ PUNICODE_STRING account_name,
+ PSID sid)
+{
+ LSA_SID_NAME_MAPPING_OPERATION_INPUT input = { 0 };
+ PLSA_SID_NAME_MAPPING_OPERATION_OUTPUT p_output = NULL;
+ LSA_SID_NAME_MAPPING_OPERATION_ERROR op_result =
+ LsaSidNameMappingOperation_NonMappingError;
+ NTSTATUS status = STATUS_SUCCESS;
+ int ret = 0;
+
+ input.AddInput.DomainName = *domain_name;
+ if (account_name)
+ input.AddInput.AccountName = *account_name;
+ input.AddInput.Sid = sid;
+
+ status = LsaManageSidNameMapping(LsaSidNameMappingOperation_Add,
+ &input,
+ &p_output);
+ if (status != STATUS_SUCCESS) {
+ ret = -1;
+ if (p_output) {
+ op_result = p_output->AddOutput.ErrorCode;
+ if (op_result == LsaSidNameMappingOperation_NameCollision || op_result == LsaSidNameMappingOperation_SidCollision)
+ ret = 0; /* OK as it failed due to collision */
+ else
+ error("LsaManageSidNameMapping failed with : %s \n", LSAMappingErrorDetails[op_result]);
+ }
+ else
+ error("LsaManageSidNameMapping failed with ntstatus: %d \n", status);
+ }
+
+ /* TODO - Free p_output */
+ /*if (p_output)
+ LsaFreeMemory(p_output);*/
+
+ return ret;
+}
+
+
+int RemoveVirtualAccountLSAMapping(PUNICODE_STRING domain_name,
+ PUNICODE_STRING account_name)
+{
+ int ret = 0;
+
+ LSA_SID_NAME_MAPPING_OPERATION_INPUT input = { 0 };
+ PLSA_SID_NAME_MAPPING_OPERATION_OUTPUT p_output = NULL;
+ PLSA_SID_NAME_MAPPING_OPERATION_REMOVE_INPUT remove_input = &input.RemoveInput;
+
+ remove_input->DomainName = *domain_name;
+ if (account_name)
+ remove_input->AccountName = *account_name;
+
+ NTSTATUS status = LsaManageSidNameMapping(LsaSidNameMappingOperation_Remove,
+ &input,
+ &p_output);
+ if (status != STATUS_SUCCESS)
+ ret = -1;
+
+ /* TODO - Free p_output */
+ /*if (p_output)
+ LsaFreeMemory(p_output);*/
+
+ return ret;
+}
+
+void
+InitUnicodeString(PUNICODE_STRING dest, PCWSTR source)
+{
+ dest->Buffer = source;
+ dest->Length = wcslen(source) * sizeof(wchar_t);
+ dest->MaximumLength = dest->Length + 2;
+}
+
+HANDLE generate_sshd_virtual_token()
+{
+ SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
+ UNICODE_STRING domain, group, account;
+ WCHAR va_name[32]; /* enough to accomodate sshd_123457890 */
+
+ PSID sid_domain = NULL, sid_group = NULL, sid_user = NULL;
+ HANDLE va_token = 0, va_token_restricted = 0;
+
+ StringCchPrintfW(va_name, 32, L"%s_%d", L"sshd", GetCurrentProcessId());
+
+ InitUnicodeString(&domain, VIRTUALUSER_DOMAIN);
+ InitUnicodeString(&group, VIRTUALUSER_GROUP_NAME);
+ InitUnicodeString(&account, va_name);
+
+ /* Initialize SIDs */
+ /* domain SID - S-1-5-111 */
+ if (!(AllocateAndInitializeSid(&nt_authority,
+ 1,
+ 111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &sid_domain)))
+ goto cleanup;
+
+ /* group SID - S-1-5-111-0 */
+ if (!(AllocateAndInitializeSid(&nt_authority,
+ 2,
+ 111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &sid_group)))
+ goto cleanup;
+
+ /*
+ * account SID
+ * this is derived from higher RIDs in sshd service account SID to ensure there are no conflicts
+ * S-1-5-80-3847866527-469524349-687026318-516638107-1125189541 (Well Known group: NT SERVICE\sshd)
+ * Ex account SID - S-1-5-111-3847866527-469524349-687026318-516638107-1125189541-123
+ */
+ if (!(AllocateAndInitializeSid(&nt_authority,
+ 7,
+ 111,
+ 3847866527,
+ 469524349,
+ 687026318,
+ 516638107,
+ 1125189541,
+ GetCurrentProcessId(),
+ 0,
+ &sid_user)))
+ goto cleanup;
+
+ /* Map the domain SID */
+ if (AddSidMappingToLsa(&domain, NULL, sid_domain) != 0)
+ goto cleanup;
+
+ /* Map the group SID */
+ if (AddSidMappingToLsa(&domain, &group, sid_group) != 0)
+ goto cleanup;
+
+ /* Map the user SID */
+ if (AddSidMappingToLsa(&domain, &account, sid_user) != 0)
+ goto cleanup;
+
+ /* Logon virtual and create token */
+ if (!LogonUserExExWHelper(
+ va_name,
+ VIRTUALUSER_DOMAIN,
+ L"",
+ LOGON32_LOGON_INTERACTIVE,
+ LOGON32_PROVIDER_VIRTUAL,
+ NULL,
+ &va_token,
+ NULL,
+ NULL,
+ NULL,
+ NULL)) {
+ debug3("LogonUserExExW failed with %d \n", GetLastError());
+ goto cleanup;
+ }
+
+ /* remove all privileges */
+ if (!CreateRestrictedToken(va_token, DISABLE_MAX_PRIVILEGE, 0, NULL, 0, NULL, 0, NULL, &va_token_restricted ))
+ debug3("CreateRestrictedToken failed with %d \n", GetLastError());
+
+ CloseHandle(va_token);
+
+cleanup:
+ RemoveVirtualAccountLSAMapping(&domain, &account);
+
+ if (sid_domain)
+ FreeSid(sid_domain);
+ if (sid_user)
+ FreeSid(sid_user);
+ if (sid_group)
+ FreeSid(sid_group);
+
+ return va_token_restricted;
+}
+
+
+
#pragma warning(pop)
\ No newline at end of file
diff --git a/contrib/win32/win32compat/wmain_sshd.c b/contrib/win32/win32compat/wmain_sshd.c
index c98ec5a..1072839 100644
--- a/contrib/win32/win32compat/wmain_sshd.c
+++ b/contrib/win32/win32compat/wmain_sshd.c
@@ -35,6 +35,8 @@
#include
#include
#include
+#include
+
#include "inc\utf.h"
#include "misc_internal.h"
@@ -99,7 +101,7 @@ static VOID WINAPI service_handler(DWORD dwControl)
#define SSH_HOSTKEY_GEN_CMDLINE L"ssh-keygen -A"
static void
-prereq_setup()
+generate_host_keys()
{
TOKEN_USER* info = NULL;
DWORD info_len = 0, dwError = 0;
@@ -127,7 +129,7 @@ prereq_setup()
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_home_dir = NULL;
ui.usri1_comment = NULL;
- ui.usri1_flags = UF_SCRIPT;
+ ui.usri1_flags = UF_SCRIPT | UF_DONT_EXPIRE_PASSWD;
ui.usri1_script_path = NULL;
NetUserAdd(NULL, 1, (LPBYTE)&ui, &dwError);
@@ -151,14 +153,96 @@ cleanup:
free(info);
}
+/*
+* 1) Create %programdata%\ssh - Administrator group(F), system(F), authorized users(RX).
+* 2) Create %programdata%\ssh\logs - Administrator group(F), system(F)
+* 3) copy \sshd_config_default to %programdata%\ssh\sshd_config
+*/
+static void
+create_prgdata_ssh_folder()
+{
+ /* create ssh cfg folder */
+ char ssh_cfg_dir[PATH_MAX] = { 0, };
+ strcpy_s(ssh_cfg_dir, _countof(ssh_cfg_dir), get_program_data_path());
+ strcat_s(ssh_cfg_dir, _countof(ssh_cfg_dir), "\\ssh");
+ if (create_directory_withsddl(ssh_cfg_dir, "O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;AU)") < 0) {
+ printf("failed to create %s", ssh_cfg_dir);
+ exit(255);
+ }
+
+ /* create logs folder */
+ char logs_dir[PATH_MAX] = { 0, };
+ strcat_s(logs_dir, _countof(logs_dir), ssh_cfg_dir);
+ strcat_s(logs_dir, _countof(logs_dir), "\\logs");
+ if (create_directory_withsddl(logs_dir, "O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)") < 0) {
+ printf("failed to create %s", logs_dir);
+ exit(255);
+ }
+
+ /* COPY sshd_config_default to %programData%\openssh\sshd_config */
+ char sshd_config_path[PATH_MAX] = { 0, };
+ strcat_s(sshd_config_path, _countof(sshd_config_path), ssh_cfg_dir);
+ strcat_s(sshd_config_path, _countof(sshd_config_path), "\\sshd_config");
+ struct stat st;
+ if (stat(sshd_config_path, &st) < 0) {
+ char sshd_config_default_path[PATH_MAX] = { 0, };
+ strcat_s(sshd_config_default_path, _countof(sshd_config_default_path), w32_programdir());
+ strcat_s(sshd_config_default_path, _countof(sshd_config_default_path), "\\sshd_config_default");
+
+ if (copy_file(sshd_config_default_path, sshd_config_path) < 0) {
+ printf("Failed to copy %s to %s, error:%d", sshd_config_default_path, sshd_config_path, GetLastError());
+ exit(255);
+ }
+ }
+}
+
+/* Create HKLM\Software\OpenSSH windows registry key */
+static void
+create_openssh_registry_key()
+{
+ HKEY ssh_registry_root = NULL;
+ wchar_t* sddl_str;
+ SECURITY_ATTRIBUTES sa;
+ int r;
+
+ memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+ sa.nLength = sizeof(sa);
+
+ /*
+ * SDDL - FullAcess to System and Builtin/Admins and restricted access to Authenticated users
+ * 0x12019b - FILE_GENERIC_READ/WRITE minus FILE_CREATE_PIPE_INSTANCE
+ */
+ sddl_str = L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x12019b;;;AU)";
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl_str, SDDL_REVISION_1, &sa.lpSecurityDescriptor, &sa.nLength)) {
+ printf("cannot convert sddl ERROR:%d", GetLastError());
+ return;
+ }
+
+ if ((r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_REGISTRY_ROOT, 0, 0, 0, KEY_WRITE, &sa, &ssh_registry_root, 0)) == ERROR_SUCCESS)
+ RegCloseKey(ssh_registry_root);
+ else
+ printf("cannot create ssh root reg key, ERROR:%d", r);
+}
+
+static void
+prereq_setup()
+{
+ create_prgdata_ssh_folder();
+ generate_host_keys();
+ create_openssh_registry_key();
+}
+
int sshd_main(int argc, wchar_t **wargv) {
char** argv = NULL;
int i, r;
_set_invalid_parameter_handler(invalid_parameter_handler);
if (argc) {
- if ((argv = malloc(argc * sizeof(char*))) == NULL)
- fatal("out of memory");
+ if ((argv = malloc(argc * sizeof(char*))) == NULL) {
+ printf("out of memory");
+ exit(255);
+ }
+
for (i = 0; i < argc; i++)
argv[i] = utf16_to_utf8(wargv[i]);
}
@@ -177,7 +261,7 @@ int wmain(int argc, wchar_t **wargv) {
wchar_t* path_utf16;
argc_original = argc;
wargv_original = wargv;
-
+
/* change current directory to sshd.exe root */
if ( (path_utf16 = utf8_to_utf16(w32_programdir())) == NULL)
return -1;
diff --git a/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1 b/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
index 885955f..0734698 100644
--- a/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
+++ b/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
@@ -17,42 +17,22 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
- $fileName = "test.txt"
- $logName = "sshdlog.txt"
+ $sshLogName = "test.txt"
+ $sshdLogName = "sshdlog.txt"
$server = $OpenSSHTestInfo["Target"]
$port = 47003
$ssouser = $OpenSSHTestInfo["SSOUser"]
$PwdUser = $OpenSSHTestInfo["PasswdUser"]
$ssouserProfile = $OpenSSHTestInfo["SSOUserProfile"]
- Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction SilentlyContinue
+ $opensshbinpath = $OpenSSHTestInfo['OpenSSHBinPath']
+ Remove-Item -Path (Join-Path $testDir "*$sshLogName") -Force -ErrorAction SilentlyContinue
$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
- }
-
- $Taskfolder = "\OpenSSHTestTasks\"
- $Taskname = "StartTestDaemon"
-
- function Start-SSHD-TestDaemon
- {
- param([string] $Arguments)
- $opensshbinpath = $OpenSSHTestInfo['OpenSSHBinPath']
-
- $ac = New-ScheduledTaskAction -Execute (join-path $opensshbinpath "sshd") -WorkingDirectory $opensshbinpath -Argument $Arguments
- $task = Register-ScheduledTask -TaskName $Taskname -User system -Action $ac -TaskPath $Taskfolder -Force
- Start-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
- }
-
- function Stop-SSHD-TestDaemon
- {
- Stop-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
- #stop-scheduledTask does not wait for worker process to end. Kill it if still running. Logic below assume sshd service is running
- $svcpid = ((tasklist /svc | select-string -Pattern ".+sshd").ToString() -split "\s+")[1]
- (gps sshd).id | foreach { if ((-not($_ -eq $svcpid))) {Stop-Process $_ -Force} }
- }
+ }
}
AfterEach { $tI++ }
@@ -78,11 +58,13 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$authorizedkeyPath = Join-Path $ssouserProfile .testssh\authorized_keys
$Source = Join-Path $ssouserProfile .ssh\authorized_keys
$testknownhosts = Join-path $PSScriptRoot testdata\test_known_hosts
- Copy-Item $Source $ssouserSSHProfilePath -Force -ErrorAction Stop
-
+ Copy-Item $Source $ssouserSSHProfilePath -Force -ErrorAction Stop
Repair-AuthorizedKeyPermission -Filepath $authorizedkeyPath -confirm:$false
-
- Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
+ if(-not $skip)
+ {
+ Stop-SSHDTestDaemon
+ }
+
#add wrong password so ssh does not prompt password if failed with authorized keys
Add-PasswordSetting -Pass "WrongPass"
$tI=1
@@ -102,73 +84,73 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
}
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
+ $sshlog = Join-Path $testDir "$tC.$tI.$sshLogName"
+ $sshdlog = Join-Path $testDir "$tC.$tI.$sshdLogName"
+ if(-not $skip)
+ {
+ Stop-SSHDTestDaemon
+ }
}
- It "$tC.$tI-authorized_keys-positive(pwd user is the owner and running process can access to the file)" {
+ It "$tC.$tI-authorized_keys-positive(pwd user is the owner and running process can access to the file)" -skip:$skip {
#setup to have ssouser as owner and grant ssouser read and write, admins group, and local system full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owners $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
-
}
- It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by local system)" {
+ It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by local system)" -skip:$skip {
#setup to have system as owner and grant it full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $systemSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
-
}
- It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd does not have explict ACE)" {
+ It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd does not have explict ACE)" -skip:$skip {
#setup to have admin group as owner and grant it full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
-
}
- It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd have explict ACE)" {
+ It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd have explict ACE)" -skip:$skip {
#setup to have admin group as owner and grant it full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
- $o | Should Be "1234"
-
+ Stop-SSHDTestDaemon
+ $o | Should Be "1234"
}
- It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other admin user)" {
+ It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other admin user)" -skip:$skip {
#setup to have current user (admin user) as owner and grant it full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $currentUserSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "Authentication refused."
+ Stop-SSHDTestDaemon
+ $sshlog | Should Contain "Permission denied"
+ $sshdlog | Should Contain "Authentication refused."
}
- It "$tC.$tI-authorized_keys-negative(other account can access private key file)" {
+ It "$tC.$tI-authorized_keys-negative(other account can access private key file)" -skip:$skip {
#setup to have current user as owner and grant it full control
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
@@ -177,24 +159,26 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
Set-FilePermission -FilePath $authorizedkeyPath -User $objPwdUserSid -Perm "Read"
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
- $LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "Authentication refused."
+ Start-SSHDTestDaemon -workDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
+ $LASTEXITCODE | Should Not Be 0
+ Stop-SSHDTestDaemon
+ $sshlog | Should Contain "Permission denied"
+ $sshdlog | Should Contain "Authentication refused."
}
- It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other non-admin user)" {
+ It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other non-admin user)" -skip:$skip {
#setup to have PwdUser as owner and grant it full control
$objPwdUserSid = Get-UserSid -User $PwdUser
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objPwdUserSid -FullAccessNeeded $adminsSid,$systemSid,$objPwdUser -confirm:$false
#Run
- Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
- ssh -p $port -E $FilePath -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $sshdlog"
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $ssouser@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "Authentication refused."
+ Stop-SSHDTestDaemon
+ $sshlog | Should Contain "Permission denied"
+ $sshdlog | Should Contain "Authentication refused."
}
}
}
diff --git a/regress/pesterTests/CommonUtils.psm1 b/regress/pesterTests/CommonUtils.psm1
index ffcd1f8..08911b3 100644
--- a/regress/pesterTests/CommonUtils.psm1
+++ b/regress/pesterTests/CommonUtils.psm1
@@ -105,4 +105,52 @@ function Remove-PasswordSetting
{
if ($env:DISPLAY -eq 1) { Remove-Item env:\DISPLAY }
Remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue
+}
+
+$Taskfolder = "\OpenSSHTestTasks\"
+$Taskname = "StartTestDaemon"
+
+function Start-SSHDTestDaemon
+{
+ param(
+ [string] $Arguments,
+ [string] $Workdir)
+
+ $ac = New-ScheduledTaskAction -Execute (join-path $workdir "sshd") -WorkingDirectory $workdir -Argument $Arguments
+ $task = Register-ScheduledTask -TaskName $Taskname -User system -Action $ac -TaskPath $Taskfolder -Force
+ Start-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
+ $svcpid = ((tasklist /svc | select-string -Pattern ".+sshd").ToString() -split "\s+")[1]
+ #sleep for 1 seconds for process to ready to listener
+ $num = 0
+ while((Get-Process sshd | Where-Object {$_.Id -ne $svcpid}) -eq $null)
+ {
+ start-sleep 1
+ $num++
+ if($num -gt 30) { break }
+ }
+}
+
+function Stop-SSHDTestDaemon
+{
+ $task = Get-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname -ErrorAction SilentlyContinue
+ if($task)
+ {
+ if($task.State -eq "Running")
+ {
+ Stop-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
+ }
+ Unregister-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname -Confirm:$false
+ }
+ #if still running, wait a little while for task to complete
+ #stop-scheduledTask does not wait for worker process to end. Kill it if still running. Logic below assume sshd service is running
+ $svcpid = ((tasklist /svc | select-string -Pattern ".+sshd").ToString() -split "\s+")[1]
+ Get-Process sshd -ErrorAction SilentlyContinue | Where-Object {$_.Id -ne $svcpid} | Stop-Process -Force -ErrorAction SilentlyContinue
+ $num = 0
+ while((Get-Process sshd | Where-Object {$_.Id -ne $svcpid}))
+ {
+ # sshd process is still running; wait 1 more seconds"
+ start-sleep 1
+ $num++
+ if($num -gt 30) { break }
+ }
}
\ No newline at end of file
diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1
index 66bc92c..38534ab 100644
--- a/regress/pesterTests/SSH.Tests.ps1
+++ b/regress/pesterTests/SSH.Tests.ps1
@@ -106,7 +106,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
It "$tC.$tI - test version" {
iex "cmd /c `"ssh -V 2> $stderrFile`""
- $stderrFile | Should Contain "OpenSSH_"
+ $stderrFile | Should Contain "OpenSSH_for_Windows"
}
It "$tC.$tI - test help" {
@@ -147,7 +147,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Be "1234"
}
- It "$tC.$tI - stdin from PS object" {
+ It "$tC.$tI - stdin from PS object" -skip:$skip {
# execute this script that dumps the length of input data, on the remote end
$str = "begin {} process { Write-Output `$input.Length} end { }"
$EncodedText =[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))
@@ -157,7 +157,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Be "8"
}
- It "$tC.$tI - stream file in and out" {
+ It "$tC.$tI - stream file in and out" -skip:$skip {
# prep a file of size > 10KB (https://github.com/PowerShell/Win32-OpenSSH/issues/908 was caught with such file size)
$str = ""
(1..100) | foreach {$str += "1234567890"}
@@ -191,7 +191,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue
}
- It "$tC.$tI - default shell as powershell" {
+ It "$tC.$tI - default shell as powershell" -skip:$skip {
$shell_path = (Get-Command powershell.exe -ErrorAction SilentlyContinue).path
if($shell_path -ne $null) {
ConfigureDefaultShell -default_shell_path $shell_path -default_shell_cmd_option_val "/c"
diff --git a/regress/pesterTests/SSHDConfig.tests.ps1 b/regress/pesterTests/SSHDConfig.tests.ps1
index 6b1c583..3c02e5b 100644
--- a/regress/pesterTests/SSHDConfig.tests.ps1
+++ b/regress/pesterTests/SSHDConfig.tests.ps1
@@ -14,39 +14,20 @@ Describe "Tests of sshd_config" -Tags "CI" {
if( -not (Test-path $testDir -PathType Container))
{
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
- }
+ }
- $fileName = "test.txt"
- $logName = "sshdlog.txt"
+ $sshLogName = "test.txt"
+ $sshdLogName = "sshdlog.txt"
$server = $OpenSSHTestInfo["Target"]
+ $opensshbinpath = $OpenSSHTestInfo['OpenSSHBinPath']
$port = 47003
- Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction SilentlyContinue
+ Remove-Item -Path (Join-Path $testDir "*$sshLogName") -Force -ErrorAction SilentlyContinue
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ContextName = $env:COMPUTERNAME
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$PrincipalContext = new-object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList @($ContextType, $ContextName)
- $IdentityType = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
- $Taskfolder = "\OpenSSHTestTasks\"
- $Taskname = "StartTestDaemon"
-
- function Start-SSHD-TestDaemon
- {
- param([string] $Arguments)
- $opensshbinpath = $OpenSSHTestInfo['OpenSSHBinPath']
-
- $ac = New-ScheduledTaskAction -Execute (join-path $opensshbinpath "sshd") -WorkingDirectory $opensshbinpath -Argument $Arguments
- $task = Register-ScheduledTask -TaskName $Taskname -User system -Action $ac -TaskPath $Taskfolder -Force
- Start-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
- }
-
- function Stop-SSHD-TestDaemon
- {
- Stop-ScheduledTask -TaskPath $Taskfolder -TaskName $Taskname
- #stop-scheduledTask does not wait for worker process to end. Kill it if still running. Logic below assume sshd service is running
- $svcpid = ((tasklist /svc | select-string -Pattern ".+sshd").ToString() -split "\s+")[1]
- (gps sshd).id | foreach { if ((-not($_ -eq $svcpid))) {Stop-Process $_ -Force} }
- }
+ $IdentityType = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
function Add-LocalUser
{
@@ -133,6 +114,10 @@ Describe "Tests of sshd_config" -Tags "CI" {
}
$platform = Get-Platform
$skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
+ if(-not $skip)
+ {
+ Stop-SSHDTestDaemon
+ }
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
#suppress the firewall blocking dialogue on win7
@@ -142,7 +127,7 @@ Describe "Tests of sshd_config" -Tags "CI" {
AfterEach { $tI++ }
- AfterAll {
+ AfterAll {
$PrincipalContext.Dispose()
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
@@ -190,8 +175,12 @@ Describe "Tests of sshd_config" -Tags "CI" {
}
BeforeEach {
- $filePath = Join-Path $testDir "$tC.$tI.$fileName"
- $logPath = Join-Path $testDir "$tC.$tI.$logName"
+ $sshlog = Join-Path $testDir "$tC.$tI.$sshLogName"
+ $sshdlog = Join-Path $testDir "$tC.$tI.$sshdLogName"
+ if(-not $skip)
+ {
+ Stop-SSHDTestDaemon
+ }
}
AfterAll {
@@ -199,148 +188,162 @@ Describe "Tests of sshd_config" -Tags "CI" {
$tC++
}
- It "$tC.$tI-User with full name in the list of AllowUsers" {
+ It "$tC.$tI-User with full name in the list of AllowUsers" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $allowUser1 -Password $password -GroupName $allowGroup1
$o = ssh -p $port $allowUser1@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser1 -GroupName $allowGroup1
}
- It "$tC.$tI-User with * wildcard" {
+ It "$tC.$tI-User with * wildcard" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $allowUser2 -Password $password -GroupName $allowGroup1
$o = ssh -p $port $allowUser2@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser2 -GroupName $allowGroup1
}
- It "$tC.$tI-User with ? wildcard" {
+ It "$tC.$tI-User with ? wildcard" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $allowUser3 -Password $password -GroupName $allowGroup1
$o = ssh -p $port $allowUser3@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
- Stop-SSHD-TestDaemon
+ Stop-SSHDTestDaemon
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser3 -GroupName $allowGroup1
}
- It "$tC.$tI-User with full name in the list of AllowUsers but not in any AllowGroups" {
+ It "$tC.$tI-User with full name in the list of AllowUsers but not in any AllowGroups" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-LocalUser -UserName $allowUser4 -Password $password
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $allowUser4@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $allowUser4@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because not in any group"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because not in any group"
}
- It "$tC.$tI-User with full name in the list of DenyUsers" {
+ It "$tC.$tI-User with full name in the list of DenyUsers" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $denyUser1 -Password $password -GroupName $allowGroup1
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser1@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $denyUser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because listed in DenyUsers"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because listed in DenyUsers"
Remove-UserFromLocalGroup -UserName $denyUser1 -GroupName $allowGroup1
}
- It "$tC.$tI-User with * wildcard in the list of DenyUsers" {
+ It "$tC.$tI-User with * wildcard in the list of DenyUsers" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $denyUser2 -Password $password -GroupName $allowGroup1
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser2@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $denyUser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because listed in DenyUsers"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because listed in DenyUsers"
Remove-UserFromLocalGroup -UserName $denyUser2 -GroupName $allowGroup1
}
- It "$tC.$tI-User with ? wildcard in the list of DenyUsers" {
+ It "$tC.$tI-User with ? wildcard in the list of DenyUsers" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $denyUser3 -Password $password -GroupName $allowGroup1
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser3@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $denyUser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because not listed in AllowUsers"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because not listed in AllowUsers"
Remove-UserFromLocalGroup -UserName $denyUser3 -GroupName $allowGroup1
}
- It "$tC.$tI-User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups" {
+ It "$tC.$tI-User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $allowGroup1
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $denyGroup1
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser1@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $localuser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because a group is listed in DenyGroups"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because a group is listed in DenyGroups"
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $allowGroup1
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $denyGroup1
}
- It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard * DenyGroups" {
+ It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard * DenyGroups" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $localuser2 -Password $password -GroupName $denyGroup2
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser2@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $localuser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because a group is listed in DenyGroups"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because a group is listed in DenyGroups"
Remove-UserFromLocalGroup -UserName $localuser2 -GroupName $denyGroup2
}
- It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups" {
+ It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups" -skip:$skip {
#Run
- Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
Add-UserToLocalGroup -UserName $localuser3 -Password $password -GroupName $denyGroup3
- ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser3@$server echo 1234
+ ssh -p $port -E $sshlog -o "UserKnownHostsFile $testknownhosts" $localuser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
- Stop-SSHD-TestDaemon
- $logPath | Should Contain "not allowed because a group is listed in DenyGroups"
+ Stop-SSHDTestDaemon
+ $sshdlog | Should Contain "not allowed because a group is listed in DenyGroups"
Remove-UserFromLocalGroup -UserName $localuser3 -GroupName $denyGroup3
}
+
+ It "$tC.$tI - Match User block with ForceCommand" -skip:$skip {
+ Start-SSHDTestDaemon -WorkDir $opensshbinpath -Arguments "-d -f $sshdConfigPath -E $sshdlog"
+ $matchuser = "matchuser"
+ Add-UserToLocalGroup -UserName $matchuser -Password $password -GroupName $allowGroup1
+
+ $o = ssh -p $port -T -o "UserKnownHostsFile $testknownhosts" $matchuser@$server randomcommand
+ # Match block's ForceCommand returns output of "whoami & set SSH_ORIGINAL_COMMAND"
+ $o[0].Contains($matchuser) | Should Be $true
+ $o[1].Contains("randomcommand") | Should Be $true
+
+ Stop-SSHDTestDaemon
+ Remove-UserFromLocalGroup -UserName $matchuser -GroupName $allowGroup1
+ }
#>
}
}
diff --git a/regress/pesterTests/testdata/SSHD_Config b/regress/pesterTests/testdata/SSHD_Config
index b50697a..089ce7d 100644
--- a/regress/pesterTests/testdata/SSHD_Config
+++ b/regress/pesterTests/testdata/SSHD_Config
@@ -113,6 +113,9 @@ Subsystem sftp sftp-server.exe -l DEBUG3
PubkeyAcceptedKeyTypes ssh-ed25519*
DenyUsers denyuser1 deny*2 denyuse?3,
-AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin
+AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin matchuser
DenyGroups denygroup1 denygr*p2 deny?rou?3
AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
+
+Match User matchuser
+ ForceCommand cmd.exe /c "whoami & set SSH_ORIGINAL_COMMAND"
diff --git a/sftp.c b/sftp.c
index 22a18a2..47c7ca1 100644
--- a/sftp.c
+++ b/sftp.c
@@ -397,7 +397,7 @@ make_absolute(char *p, const char *pwd)
* Need to follow up with community if this makes sense in common code
*/
char *s1, *s2;
- if (p && p[0] != '/' && (p[0] == '\0' || p[1] != ':')) {
+ if (!is_absolute_path(p)) {
abs_str = path_append(pwd, p);
free(p);
p = abs_str;
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 98e7f14..026cf26 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1544,9 +1544,16 @@ do_change_comment(struct passwd *pw)
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
fatal("Could not save your public key in %s", identity_file);
+#ifdef WINDOWS
+ /* Windows POSIX adpater does not support fdopen() on open(file)*/
+ close(fd);
+ if ((f = fopen(identity_file, "w")) == NULL)
+ fatal("fopen %s failed: %s", identity_file, strerror(errno));
+#else /* !WINDOWS */
f = fdopen(fd, "w");
if (f == NULL)
fatal("fdopen %s failed: %s", identity_file, strerror(errno));
+#endif /* !WINDOWS */
if ((r = sshkey_write(public, f)) != 0)
fatal("write key failed: %s", ssh_err(r));
sshkey_free(public);
diff --git a/sshconnect.c b/sshconnect.c
index c950c4d..cfd6f4e 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -199,10 +199,6 @@ static int
ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
const char *proxy_command)
{
-#ifdef WINDOWS
- fatal("Proxy connect is not supported in Windows yet");
- return 0;
-#else /* !WINDOWS */
char *command_string;
int pin[2], pout[2];
pid_t pid;
@@ -220,6 +216,28 @@ ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
host, port);
debug("Executing proxy command: %.500s", command_string);
+
+#ifdef FORK_NOT_SUPPORTED
+ {
+ posix_spawn_file_actions_t actions;
+ char* spawn_argv[2];
+ /*
+ * expand_proxy_command prefixes cmdline with "exec "
+ */
+ spawn_argv[0] = command_string + 5;
+ spawn_argv[1] = NULL;
+ pid = -1;
+
+ if (posix_spawn_file_actions_init(&actions) != 0 ||
+ posix_spawn_file_actions_adddup2(&actions, pin[0], STDIN_FILENO) != 0 ||
+ posix_spawn_file_actions_adddup2(&actions, pout[1], STDOUT_FILENO) != 0)
+ fatal("posix_spawn initialization failed");
+ else if (posix_spawn(&pid, spawn_argv[0], &actions, NULL, spawn_argv, NULL) != 0)
+ fatal("posix_spawn: %s", strerror(errno));
+
+ posix_spawn_file_actions_destroy(&actions);
+ }
+#else
/* Fork and execute the proxy command. */
if ((pid = fork()) == 0) {
char *argv[10];
@@ -254,6 +272,7 @@ ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
perror(argv[0]);
exit(1);
}
+#endif
/* Parent. */
if (pid < 0)
fatal("fork failed: %.100s", strerror(errno));
@@ -272,7 +291,6 @@ ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
return -1; /* ssh_packet_set_connection logs error */
return 0;
-#endif /* !WINDOWS */
}
void
diff --git a/sshd.c b/sshd.c
index c7061f5..28563f6 100644
--- a/sshd.c
+++ b/sshd.c
@@ -742,7 +742,9 @@ privsep_preauth(Authctxt *authctxt)
#ifdef FORK_NOT_SUPPORTED
if (privsep_auth_child) {
- authctxt->pw = w32_getpwuid(1);
+ struct passwd* me = getpwuid(geteuid());
+ /* this re-does the user specific config */
+ authctxt->pw = getpwnamallow(xstrdup(me->pw_name));
authctxt->valid = 1;
return 1;
}
@@ -774,7 +776,7 @@ privsep_preauth(Authctxt *authctxt)
else {
char** argv = privsep_child_cmdline(0);
if (__posix_spawn_asuser(&pid, argv[0], &actions, NULL, argv, NULL, SSH_PRIVSEP_USER) != 0)
- error("posix_spawn failed");
+ error("%s, posix_spawn failed", __func__);
posix_spawn_file_actions_destroy(&actions);
}
close(pmonitor->m_recvfd);
@@ -880,7 +882,7 @@ privsep_postauth(Authctxt *authctxt)
else {
char** argv = privsep_child_cmdline(1);
if (__posix_spawn_asuser(&pmonitor->m_pid, argv[0], &actions, NULL, argv, NULL, authctxt->pw->pw_name) != 0)
- error("posix_spawn failed");
+ error("%s, posix_spawn failed", __func__);
posix_spawn_file_actions_destroy(&actions);
}
@@ -1545,7 +1547,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
error("posix_spawn initialization failed");
else {
if (posix_spawn(&pid, rexec_argv[0], &actions, &attributes, rexec_argv, NULL) != 0)
- error("posix_spawn failed");
+ error("%s, posix_spawn failed", __func__);
posix_spawn_file_actions_destroy(&actions);
posix_spawnattr_destroy(&attributes);
}
diff --git a/version.h b/version.h
index f87e2ca..9bcbf31 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
/* $OpenBSD: version.h,v 1.80 2017/09/30 22:26:33 djm Exp $ */
-#define SSH_VERSION "OpenSSH_7.6"
+#define SSH_VERSION "OpenSSH_for_Windows_7.6"
#define SSH_PORTABLE "p1"
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE