mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-22 21:45:09 +02:00
Source snapshot from Powershell/openssh-portable:latestw_all
This commit is contained in:
parent
1ad6c956cc
commit
c4d0727338
@ -1,4 +1,4 @@
|
||||
version: 0.0.24.0.{build}
|
||||
version: 1.0.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
|
||||
branches:
|
||||
|
@ -41,9 +41,6 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#ifdef WINDOWS
|
||||
#include <logonuser.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
@ -59,6 +56,11 @@
|
||||
#include "auth-options.h"
|
||||
#include "authfd.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include "logonuser.h"
|
||||
#include "monitor_wrap.h"
|
||||
#endif
|
||||
|
||||
extern Buffer loginmsg;
|
||||
extern ServerOptions options;
|
||||
|
||||
@ -228,10 +230,53 @@ 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*);
|
||||
|
||||
void
|
||||
sys_auth_passwd_lsa(Authctxt *authctxt, const char *password)
|
||||
{
|
||||
char *lsa_auth_pkg = NULL;
|
||||
wchar_t *lsa_auth_pkg_w = NULL;
|
||||
int domain_len = 0, lsa_auth_pkg_len = 0;
|
||||
HKEY reg_key = 0;
|
||||
REGSAM mask = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY;
|
||||
|
||||
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\OpenSSH", 0, mask, ®_key) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, NULL, &lsa_auth_pkg_len) == ERROR_SUCCESS)) {
|
||||
lsa_auth_pkg_w = (wchar_t *) malloc(lsa_auth_pkg_len); // lsa_auth_pkg_len includes the null terminating character.
|
||||
if (!lsa_auth_pkg_w)
|
||||
fatal("%s: out of memory", __func__);
|
||||
|
||||
memset(lsa_auth_pkg_w, 0, lsa_auth_pkg_len);
|
||||
if (RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, (LPBYTE)lsa_auth_pkg_w, &lsa_auth_pkg_len) == ERROR_SUCCESS) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (lsa_auth_pkg_w)
|
||||
free(lsa_auth_pkg_w);
|
||||
|
||||
if (lsa_auth_pkg)
|
||||
free(lsa_auth_pkg);
|
||||
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticate on Windows - Call LogonUser and retrieve user token
|
||||
* Authenticate on Windows
|
||||
* - Call LogonUser and retrieve user token
|
||||
* - If LogonUser fails, then try the LSA (Local Security Authority) authentication.
|
||||
*/
|
||||
int sys_auth_passwd(Authctxt *authctxt, const char *password)
|
||||
int
|
||||
sys_auth_passwd(Authctxt *authctxt, const char *password)
|
||||
{
|
||||
wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp;
|
||||
HANDLE token = NULL;
|
||||
@ -249,25 +294,33 @@ int sys_auth_passwd(Authctxt *authctxt, const char *password)
|
||||
}
|
||||
|
||||
if (LogonUserExExWHelper(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT,
|
||||
LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL) == FALSE) {
|
||||
if (GetLastError() == ERROR_PASSWORD_MUST_CHANGE)
|
||||
/*
|
||||
* TODO - need to add support to force password change
|
||||
* by sending back SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
|
||||
*/
|
||||
LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL) == TRUE)
|
||||
password_auth_token = token;
|
||||
else {
|
||||
if (GetLastError() == ERROR_PASSWORD_MUST_CHANGE)
|
||||
/*
|
||||
* TODO - need to add support to force password change
|
||||
* by sending back SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
|
||||
*/
|
||||
error("password for user %s has expired", authctxt->pw->pw_name);
|
||||
else
|
||||
debug("failed to logon user: %ls domain: %ls error:%d", user_utf16, udom_utf16, GetLastError());
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
debug("Windows authentication failed for user: %ls domain: %ls error:%d", user_utf16, udom_utf16, GetLastError());
|
||||
|
||||
authctxt->auth_token = (void*)(INT_PTR)token;
|
||||
r = 1;
|
||||
/* If LSA authentication package is configured then it will return the auth_token */
|
||||
sys_auth_passwd_lsa(authctxt, password);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (password_auth_token)
|
||||
r = 1;
|
||||
|
||||
if (user_utf16)
|
||||
free(user_utf16);
|
||||
|
||||
if (pwd_utf16)
|
||||
SecureZeroMemory(pwd_utf16, sizeof(wchar_t) * wcslen(pwd_utf16));
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* WINDOWS */
|
||||
|
3
auth.h
3
auth.h
@ -93,9 +93,6 @@ struct Authctxt {
|
||||
|
||||
/* Information exposed to session */
|
||||
struct sshbuf *session_info; /* Auth info for environment */
|
||||
#ifdef WINDOWS
|
||||
void *auth_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -199,13 +199,8 @@ userauth_pubkey(struct ssh *ssh)
|
||||
authenticated = 0;
|
||||
|
||||
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
|
||||
#ifdef WINDOWS
|
||||
(authctxt->auth_token = mm_auth_pubkey(authctxt->pw->pw_name,
|
||||
key, sig, slen, b)) != NULL) {
|
||||
#else
|
||||
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
|
||||
sshbuf_len(b), ssh->compat)) == 0) {
|
||||
#endif
|
||||
authenticated = 1;
|
||||
}
|
||||
sshbuf_free(b);
|
||||
|
5
authfd.c
5
authfd.c
@ -120,12 +120,7 @@ ssh_get_authentication_socket(int *fdp)
|
||||
}
|
||||
|
||||
/* Communicate with agent: send request and read reply */
|
||||
#ifdef WINDOWS
|
||||
/* for Windows we need to access this function from other places to talk to agent*/
|
||||
int
|
||||
#else /* !WINDOWS */
|
||||
static int
|
||||
#endif /* !WINDOWS */
|
||||
ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
|
||||
{
|
||||
int r;
|
||||
|
@ -5,14 +5,14 @@ If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $
|
||||
Import-Module $PSScriptRoot\OpenSSHUtils -Force
|
||||
|
||||
#check sshd config file
|
||||
$sshdConfigPath = join-path $PSScriptRoot "sshd_config"
|
||||
$sshdConfigPath = join-path $env:ProgramData\ssh "sshd_config"
|
||||
if(Test-Path $sshdConfigPath -PathType Leaf)
|
||||
{
|
||||
Repair-SshdConfigPermission -FilePath $sshdConfigPath @psBoundParameters
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-host "$FilePath does not exist" -ForegroundColor Yellow
|
||||
Write-host "$sshdConfigPath does not exist" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
#check host keys
|
||||
@ -36,7 +36,7 @@ If you choose not to register the keys with ssh-agent, please grant sshd read ac
|
||||
Write-Host " "
|
||||
}#>
|
||||
|
||||
Get-ChildItem $PSScriptRoot\ssh_host_*_key -ErrorAction SilentlyContinue | % {
|
||||
Get-ChildItem $env:ProgramData\ssh\ssh_host_*_key -ErrorAction SilentlyContinue | % {
|
||||
Repair-SshdHostKeyPermission -FilePath $_.FullName @psBoundParameters
|
||||
}
|
||||
|
||||
|
@ -344,8 +344,8 @@ function Start-OpenSSHPackage
|
||||
$buildDir = Join-Path $repositoryRoot ("bin\" + $folderName + "\" + $Configuration)
|
||||
$payload = "sshd.exe", "ssh.exe", "ssh-agent.exe", "ssh-add.exe", "sftp.exe"
|
||||
$payload += "sftp-server.exe", "scp.exe", "ssh-shellhost.exe", "ssh-keygen.exe", "ssh-keyscan.exe"
|
||||
$payload += "sshd_config", "install-sshd.ps1", "uninstall-sshd.ps1"
|
||||
$payload +="FixHostFilePermissions.ps1", "FixUserFilePermissions.ps1", "OpenSSHUtils.psm1", "OpenSSHUtils.psd1", "ssh-add-hostkey.ps1"
|
||||
$payload += "sshd_config_default", "install-sshd.ps1", "uninstall-sshd.ps1"
|
||||
$payload +="FixHostFilePermissions.ps1", "FixUserFilePermissions.ps1", "OpenSSHUtils.psm1", "OpenSSHUtils.psd1"
|
||||
|
||||
$packageName = "OpenSSH-Win64"
|
||||
if ($NativeHostArch -ieq 'x86') {
|
||||
|
@ -13,6 +13,7 @@ $PubKeyUser = "sshtest_pubkeyuser"
|
||||
$PasswdUser = "sshtest_passwduser"
|
||||
$OpenSSHTestAccountsPassword = "P@ssw0rd_1"
|
||||
$OpenSSHTestAccounts = $Script:SSOUser, $Script:PubKeyUser, $Script:PasswdUser
|
||||
$OpenSSHConfigPath = Join-Path $env:ProgramData "ssh"
|
||||
|
||||
$Script:TestDataPath = "$env:SystemDrive\OpenSSHTests"
|
||||
$Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName
|
||||
@ -106,7 +107,7 @@ function Set-OpenSSHTestEnvironment
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if (-not (Test-Path (Join-Path $OpenSSHBinPath ssh.exe) -PathType Leaf))
|
||||
{
|
||||
Throw "Cannot find OpenSSH binaries under $OpenSSHBinPath. Please specify -OpenSSHBinPath to the OpenSSH installed location"
|
||||
@ -162,25 +163,19 @@ WARNING: Following changes will be made to OpenSSH configuration
|
||||
}
|
||||
|
||||
#Backup existing OpenSSH configuration
|
||||
$backupConfigPath = Join-Path $script:OpenSSHBinPath sshd_config.ori
|
||||
$backupConfigPath = Join-Path $OpenSSHConfigPath sshd_config.ori
|
||||
if (-not (Test-Path $backupConfigPath -PathType Leaf)) {
|
||||
Copy-Item (Join-Path $script:OpenSSHBinPath sshd_config) $backupConfigPath -Force
|
||||
Copy-Item (Join-Path $OpenSSHConfigPath sshd_config) $backupConfigPath -Force
|
||||
}
|
||||
$targetsshdConfig = Join-Path $script:OpenSSHBinPath sshd_config
|
||||
$targetsshdConfig = Join-Path $OpenSSHConfigPath sshd_config
|
||||
# copy new sshd_config
|
||||
if($Script:WindowsInBox -and (Test-Path $targetsshdConfig))
|
||||
{
|
||||
$currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
|
||||
Add-PermissionToFileACL -FilePath $targetsshdConfig -User $currentUser -Perm "Read,Write"
|
||||
}
|
||||
|
||||
Copy-Item (Join-Path $Script:E2ETestDirectory sshd_config) $targetsshdConfig -Force
|
||||
|
||||
Start-Service ssh-agent
|
||||
|
||||
#copy sshtest keys
|
||||
Copy-Item "$($Script:E2ETestDirectory)\sshtest*hostkey*" $script:OpenSSHBinPath -Force
|
||||
Get-ChildItem "$($script:OpenSSHBinPath)\sshtest*hostkey*"| % {
|
||||
Copy-Item "$($Script:E2ETestDirectory)\sshtest*hostkey*" $OpenSSHConfigPath -Force
|
||||
Get-ChildItem "$($OpenSSHConfigPath)\sshtest*hostkey*"| % {
|
||||
#workaround for the cariggage new line added by git before copy them
|
||||
$filePath = "$($_.FullName)"
|
||||
$con = (Get-Content $filePath | Out-String).Replace("`r`n","`n")
|
||||
@ -188,16 +183,11 @@ WARNING: Following changes will be made to OpenSSH configuration
|
||||
if (-not ($_.Name.EndsWith(".pub")))
|
||||
{
|
||||
Repair-SshdHostKeyPermission -FilePath $_.FullName -confirm:$false
|
||||
if($psversiontable.BuildVersion.Major -gt 6)
|
||||
{
|
||||
#register private key with agent
|
||||
ssh-add-hostkey.ps1 $_.FullName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#copy ca pubkey to SSHD bin path
|
||||
Copy-Item "$($Script:E2ETestDirectory)\sshtest_ca_userkeys.pub" $script:OpenSSHBinPath -Force
|
||||
#copy ca pubkey to ssh config path
|
||||
Copy-Item "$($Script:E2ETestDirectory)\sshtest_ca_userkeys.pub" $OpenSSHConfigPath -Force
|
||||
|
||||
#copy ca private key to test dir
|
||||
$ca_priv_key = (Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_ca_userkeys)
|
||||
@ -462,11 +452,6 @@ function Clear-OpenSSHTestEnvironment
|
||||
Throw "Cannot find OpenSSH binaries under $script:OpenSSHBinPath. "
|
||||
}
|
||||
|
||||
#unregister test host keys from agent
|
||||
Get-ChildItem "$sshBinPath\sshtest*hostkey*.pub"| % {
|
||||
ssh-add-hostkey.ps1 -Delete_key $_.FullName
|
||||
}
|
||||
|
||||
if($Global:OpenSSHTestInfo["EnableAppVerifier"] -and (Test-path $env:windir\System32\appverif.exe))
|
||||
{
|
||||
# clear all applications in application verifier
|
||||
@ -479,14 +464,14 @@ function Clear-OpenSSHTestEnvironment
|
||||
Remove-ItemProperty "HKLM:Software\Microsoft\Windows NT\CurrentVersion\AeDebug" -Name Auto -ErrorAction SilentlyContinue -Force | Out-Null
|
||||
}
|
||||
|
||||
Remove-Item "$sshBinPath\sshtest*hostkey*" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$sshBinPath\sshtest*ca_userkeys*" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$OpenSSHConfigPath\sshtest*hostkey*" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$OpenSSHConfigPath\sshtest*ca_userkeys*" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
#Restore sshd_config
|
||||
$backupConfigPath = Join-Path $sshBinPath sshd_config.ori
|
||||
$backupConfigPath = Join-Path $OpenSSHConfigPath sshd_config.ori
|
||||
if (Test-Path $backupConfigPath -PathType Leaf) {
|
||||
Copy-Item $backupConfigPath (Join-Path $sshBinPath sshd_config) -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item (Join-Path $sshBinPath sshd_config.ori) -Force -ErrorAction SilentlyContinue
|
||||
Copy-Item $backupConfigPath (Join-Path $OpenSSHConfigPath sshd_config) -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item (Join-Path $OpenSSHConfigPath sshd_config.ori) -Force -ErrorAction SilentlyContinue
|
||||
Restart-Service sshd
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,6 @@ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnown
|
||||
# get the everyone
|
||||
$everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::WorldSid)
|
||||
|
||||
$sshdSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-80-3847866527-469524349-687026318-516638107-1125189541")
|
||||
|
||||
$currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
|
||||
|
||||
#Taken from P/Invoke.NET with minor adjustments.
|
||||
@ -112,7 +110,7 @@ function Repair-SshdConfigPermission
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$FilePath)
|
||||
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid -FullAccessNeeded $systemSid -ReadAccessNeeded $sshdSid @psBoundParameters
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid -FullAccessNeeded $systemSid @psBoundParameters
|
||||
}
|
||||
|
||||
<#
|
||||
@ -134,10 +132,10 @@ function Repair-SshdHostKeyPermission
|
||||
$PSBoundParameters["FilePath"] = $PSBoundParameters["FilePath"].Replace(".pub", "")
|
||||
}
|
||||
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessNeeded $sshdSid @psBoundParameters
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid @psBoundParameters
|
||||
|
||||
$PSBoundParameters["FilePath"] += ".pub"
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessOK $everyoneSid -ReadAccessNeeded $sshdSid @psBoundParameters
|
||||
Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessOK $everyoneSid @psBoundParameters
|
||||
}
|
||||
|
||||
<#
|
||||
@ -175,7 +173,7 @@ function Repair-AuthorizedKeyPermission
|
||||
if($profileItem)
|
||||
{
|
||||
$userSid = $profileItem.PSChildName
|
||||
Repair-FilePermission -Owners $userSid,$adminsSid,$systemSid -AnyAccessOK $userSid -FullAccessNeeded $systemSid -ReadAccessNeeded $sshdSid @psBoundParameters
|
||||
Repair-FilePermission -Owners $userSid,$adminsSid,$systemSid -AnyAccessOK $userSid -FullAccessNeeded $systemSid @psBoundParameters
|
||||
|
||||
}
|
||||
else
|
||||
|
@ -102,7 +102,7 @@
|
||||
|
||||
/* Define if your platform needs to skip post auth
|
||||
file descriptor passing */
|
||||
#define DISABLE_FD_PASSING 1
|
||||
/* #undef DISABLE_FD_PASSING */
|
||||
|
||||
/* Define if you don't want to use lastlog */
|
||||
/* #undef DISABLE_LASTLOG */
|
||||
@ -1691,7 +1691,9 @@
|
||||
|
||||
#define HAVE_MBLEN 1
|
||||
|
||||
#define SSHDIR "."
|
||||
#define _PATH_PRIVSEP_CHROOT_DIR "."
|
||||
#define SSHDIR "__PROGRAMDATA__\\ssh"
|
||||
#define _PATH_SFTP_SERVER "sftp-server.exe"
|
||||
#define _PATH_SSH_PROGRAM "ssh.exe"
|
||||
#define _PATH_LS "dir"
|
||||
#define FORK_NOT_SUPPORTED 1
|
@ -196,8 +196,7 @@
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -229,8 +228,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -262,8 +260,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -295,8 +292,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -332,8 +328,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -369,8 +364,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -406,8 +400,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@ -443,8 +436,7 @@ If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir
|
||||
copy /Y "$(SolutionDir)uninstall-ssh*ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)OpenSSHUtils.ps*1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)Fix*FilePermissions.ps1" "$(OutDir)"
|
||||
copy /Y "$(SolutionDir)ssh-add-hostkey.ps1" "$(OutDir)"
|
||||
If NOT exist "$(OutDir)\sshd_config" (copy "$(SolutionDir)sshd_config" "$(OutDir)")</Command>
|
||||
copy /Y "$(SolutionDir)sshd_config" "$(OutDir)sshd_config_default"</Command>
|
||||
<Message>Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, OpenSSHUtils.psd1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -8,245 +8,8 @@ $scriptdir = Split-Path $scriptpath
|
||||
|
||||
$sshdpath = Join-Path $scriptdir "sshd.exe"
|
||||
$sshagentpath = Join-Path $scriptdir "ssh-agent.exe"
|
||||
$logsdir = Join-Path $scriptdir "logs"
|
||||
|
||||
$sshdAccount = "NT SERVICE\SSHD"
|
||||
$sshdSid = "S-1-5-80-3847866527-469524349-687026318-516638107-1125189541"
|
||||
|
||||
#Idea borrowed from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0
|
||||
$definition = @'
|
||||
using System;
|
||||
|
||||
namespace MyLsaWrapper
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.ComponentModel;
|
||||
using System.Security.Principal;
|
||||
|
||||
using LSA_HANDLE = IntPtr;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct LSA_OBJECT_ATTRIBUTES
|
||||
{
|
||||
internal int Length;
|
||||
internal IntPtr RootDirectory;
|
||||
internal IntPtr ObjectName;
|
||||
internal int Attributes;
|
||||
internal IntPtr SecurityDescriptor;
|
||||
internal IntPtr SecurityQualityOfService;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
struct LSA_UNICODE_STRING
|
||||
{
|
||||
internal ushort Length;
|
||||
internal ushort MaximumLength;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
internal string Buffer;
|
||||
}
|
||||
sealed class Win32Sec
|
||||
{
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaOpenPolicy(
|
||||
LSA_UNICODE_STRING[] SystemName,
|
||||
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
int AccessMask,
|
||||
out IntPtr PolicyHandle
|
||||
);
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaAddAccountRights(
|
||||
LSA_HANDLE PolicyHandle,
|
||||
IntPtr pSID,
|
||||
LSA_UNICODE_STRING[] UserRights,
|
||||
int CountOfRights
|
||||
);
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaRemoveAccountRights(
|
||||
LSA_HANDLE PolicyHandle,
|
||||
IntPtr pSID,
|
||||
bool AllRights,
|
||||
LSA_UNICODE_STRING[] UserRights,
|
||||
int CountOfRights
|
||||
);
|
||||
|
||||
[DllImport("advapi32")]
|
||||
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
|
||||
|
||||
[DllImport("advapi32")]
|
||||
internal static extern int LsaClose(IntPtr PolicyHandle);
|
||||
}
|
||||
|
||||
internal sealed class Sid : IDisposable
|
||||
{
|
||||
public IntPtr pSid = IntPtr.Zero;
|
||||
public System.Security.Principal.SecurityIdentifier sid = null;
|
||||
|
||||
public Sid(string account)
|
||||
{
|
||||
try { sid = new SecurityIdentifier(account); }
|
||||
catch { sid = (SecurityIdentifier)(new NTAccount(account)).Translate(typeof(SecurityIdentifier)); }
|
||||
Byte[] buffer = new Byte[sid.BinaryLength];
|
||||
sid.GetBinaryForm(buffer, 0);
|
||||
|
||||
pSid = Marshal.AllocHGlobal(sid.BinaryLength);
|
||||
Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (pSid != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(pSid);
|
||||
pSid = IntPtr.Zero;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
~Sid() { Dispose(); }
|
||||
}
|
||||
|
||||
public sealed class LsaWrapper : IDisposable
|
||||
{
|
||||
enum Access : int
|
||||
{
|
||||
POLICY_READ = 0x20006,
|
||||
POLICY_ALL_ACCESS = 0x00F0FFF,
|
||||
POLICY_EXECUTE = 0X20801,
|
||||
POLICY_WRITE = 0X207F8
|
||||
}
|
||||
const uint STATUS_ACCESS_DENIED = 0xc0000022;
|
||||
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
|
||||
const uint STATUS_NO_MEMORY = 0xc0000017;
|
||||
const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034;
|
||||
const uint STATUS_NO_MORE_ENTRIES = 0x8000001a;
|
||||
|
||||
IntPtr lsaHandle;
|
||||
|
||||
public LsaWrapper() : this(null) { } // local system if systemName is null
|
||||
public LsaWrapper(string systemName)
|
||||
{
|
||||
LSA_OBJECT_ATTRIBUTES lsaAttr;
|
||||
lsaAttr.RootDirectory = IntPtr.Zero;
|
||||
lsaAttr.ObjectName = IntPtr.Zero;
|
||||
lsaAttr.Attributes = 0;
|
||||
lsaAttr.SecurityDescriptor = IntPtr.Zero;
|
||||
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
|
||||
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
|
||||
lsaHandle = IntPtr.Zero;
|
||||
LSA_UNICODE_STRING[] system = null;
|
||||
if (systemName != null)
|
||||
{
|
||||
system = new LSA_UNICODE_STRING[1];
|
||||
system[0] = InitLsaString(systemName);
|
||||
}
|
||||
|
||||
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr, (int)Access.POLICY_ALL_ACCESS, out lsaHandle);
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void AddPrivilege(string account, string privilege)
|
||||
{
|
||||
uint ret = 0;
|
||||
using (Sid sid = new Sid(account))
|
||||
{
|
||||
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
|
||||
privileges[0] = InitLsaString(privilege);
|
||||
ret = Win32Sec.LsaAddAccountRights(lsaHandle, sid.pSid, privileges, 1);
|
||||
}
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void RemovePrivilege(string account, string privilege)
|
||||
{
|
||||
uint ret = 0;
|
||||
using (Sid sid = new Sid(account))
|
||||
{
|
||||
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
|
||||
privileges[0] = InitLsaString(privilege);
|
||||
ret = Win32Sec.LsaRemoveAccountRights(lsaHandle, sid.pSid, false, privileges, 1);
|
||||
}
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (lsaHandle != IntPtr.Zero)
|
||||
{
|
||||
Win32Sec.LsaClose(lsaHandle);
|
||||
lsaHandle = IntPtr.Zero;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
~LsaWrapper() { Dispose(); }
|
||||
|
||||
// helper functions:
|
||||
static LSA_UNICODE_STRING InitLsaString(string s)
|
||||
{
|
||||
// Unicode strings max. 32KB
|
||||
if (s.Length > 0x7ffe) throw new ArgumentException("String too long");
|
||||
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
|
||||
lus.Buffer = s;
|
||||
lus.Length = (ushort)(s.Length * sizeof(char));
|
||||
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
|
||||
return lus;
|
||||
}
|
||||
}
|
||||
public class LsaWrapperCaller
|
||||
{
|
||||
public static void AddPrivilege(string account, string privilege)
|
||||
{
|
||||
using (LsaWrapper lsaWrapper = new LsaWrapper())
|
||||
{
|
||||
lsaWrapper.AddPrivilege(account, privilege);
|
||||
}
|
||||
}
|
||||
public static void RemovePrivilege(string account, string privilege)
|
||||
{
|
||||
using (LsaWrapper lsaWrapper = new LsaWrapper())
|
||||
{
|
||||
lsaWrapper.RemovePrivilege(account, privilege);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
$references = @("System.Security.Principal.Windows", "Microsoft.Win32.Primitives")
|
||||
try {
|
||||
$null = [MyLsaWrapper.LsaWrapperCaller]
|
||||
}
|
||||
catch {
|
||||
try {
|
||||
$types = Add-Type $definition -ref $references -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
|
||||
}
|
||||
catch {
|
||||
$types = Add-Type $definition -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Add-Privilege
|
||||
{
|
||||
param(
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Account,
|
||||
|
||||
[ValidateSet("SeAssignPrimaryTokenPrivilege", "SeServiceLogonRight")]
|
||||
[string] $Privilege
|
||||
)
|
||||
|
||||
[MyLsaWrapper.LsaWrapperCaller]::AddPrivilege($Account, $Privilege)
|
||||
}
|
||||
|
||||
$sshdir = Join-Path $env:ProgramData "\ssh"
|
||||
$logsdir = Join-Path $sshdir "logs"
|
||||
|
||||
if (-not (Test-Path $sshdpath)) {
|
||||
throw "sshd.exe is not present in script path"
|
||||
@ -267,12 +30,21 @@ if (Get-Service ssh-agent -ErrorAction SilentlyContinue)
|
||||
New-Service -Name ssh-agent -BinaryPathName `"$sshagentpath`" -Description "SSH Agent" -StartupType Manual | Out-Null
|
||||
cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)'
|
||||
|
||||
New-Service -Name sshd -BinaryPathName `"$sshdpath`" -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
|
||||
sc.exe config sshd obj= $sshdAccount
|
||||
sc.exe privs sshd SeAssignPrimaryTokenPrivilege
|
||||
New-Service -Name sshd -BinaryPathName `"$sshdpath`" -Description "SSH Daemon" -StartupType Manual | Out-Null
|
||||
|
||||
Add-Privilege -Account $sshdSid -Privilege SeAssignPrimaryTokenPrivilege
|
||||
Add-Privilege -Account $sshdSid -Privilege SeServiceLogonRight
|
||||
#create the ssh config folder and set its permissions
|
||||
if(-not (test-path $sshdir -PathType Container))
|
||||
{
|
||||
$null = New-Item $sshdir -ItemType Directory -Force -ErrorAction Stop
|
||||
}
|
||||
$acl = Get-Acl -Path $sshdir
|
||||
# following SDDL implies
|
||||
# - owner - built in Administrators
|
||||
# - disabled inheritance
|
||||
# - Full access to System
|
||||
# - Full access to built in Administrators
|
||||
$acl.SetSecurityDescriptorSddlForm("O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;AU)")
|
||||
Set-Acl -Path $sshdir -AclObject $acl
|
||||
|
||||
# create logs folder and set its permissions
|
||||
if(-not (test-path $logsdir -PathType Container))
|
||||
@ -288,15 +60,12 @@ $acl = Get-Acl -Path $logsdir
|
||||
$acl.SetSecurityDescriptorSddlForm("O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)")
|
||||
Set-Acl -Path $logsdir -AclObject $acl
|
||||
|
||||
$agentlog = Join-Path $logsdir "ssh-agent.log"
|
||||
if(-not (test-path $agentlog)){ $null | Set-Content $agentlog }
|
||||
Set-Acl -Path $agentlog -AclObject $acl
|
||||
|
||||
$sshdlog = Join-Path $logsdir "sshd.log"
|
||||
if(-not (test-path $sshdlog)){ $null | Set-Content $sshdlog }
|
||||
$rights = [System.Security.AccessControl.FileSystemRights]"Read, Write"
|
||||
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($sshdAccount, $rights, "None", "None", "Allow")
|
||||
$acl.SetAccessRule($accessRule)
|
||||
Set-Acl -Path $sshdlog -AclObject $acl
|
||||
#copy sshd_config_default to $sshdir\sshd_config
|
||||
$sshdconfigpath = Join-Path $sshdir "sshd_config"
|
||||
$sshddefaultconfigpath = Join-Path $scriptdir "sshd_config_default"
|
||||
if(-not (test-path $sshdconfigpath -PathType Leaf))
|
||||
{
|
||||
$null = Copy-Item $sshddefaultconfigpath -Destination $sshdconfigpath -ErrorAction Stop
|
||||
}
|
||||
|
||||
Write-Host -ForegroundColor Green "sshd and ssh-agent services successfully installed"
|
||||
|
@ -12,7 +12,7 @@
|
||||
<UseOpenSSL>true</UseOpenSSL>
|
||||
<SSLLib>libcrypto.lib;</SSLLib>
|
||||
<WindowsSDKVersion>8.1</WindowsSDKVersion>
|
||||
<AdditionalDependentLibs>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</AdditionalDependentLibs>
|
||||
<AdditionalDependentLibs>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</AdditionalDependentLibs>
|
||||
<MinimalCoreWin>false</MinimalCoreWin>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -382,25 +382,15 @@
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\servconf.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\ssh-pubkey\ssh-pubkeydefs.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\agent-request.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\agent.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)groupaccess.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\auth.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\servconf.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\agent-main.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\agent.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\authagent-request.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\agentconfig.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\connection.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ssh-agent\keyagent-request.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)auth-options.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)auth2-pubkey.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)groupaccess.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\logonuser.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="version.rc" />
|
||||
|
@ -446,8 +446,9 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)sshlogin.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\wmain_sshd.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_monitor_wrap.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\logonuser.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_usertoken_utils.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\spawn-ext.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="version.rc" />
|
||||
|
@ -150,10 +150,13 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_monitor_wrap.c">
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\logonuser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\logonuser.c">
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_usertoken_utils.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\spawn-ext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -1,10 +1,6 @@
|
||||
# $OpenBSD: sshd_config,v 1.84 2011/05/23 03:30:07 djm Exp $
|
||||
|
||||
# This is the sshd server system-wide configuration file. See
|
||||
# sshd_config(5) for more information.
|
||||
|
||||
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# The strategy used for options in the default sshd_config shipped with
|
||||
# OpenSSH is to specify options with their default value where
|
||||
# possible, but leave them commented. Uncommented options override the
|
||||
@ -15,46 +11,38 @@
|
||||
#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 /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
|
||||
|
||||
# Lifetime and size of ephemeral version 1 server key
|
||||
#KeyRegenerationInterval 1h
|
||||
#ServerKeyBits 1024
|
||||
# Ciphers and keying
|
||||
#RekeyLimit default none
|
||||
|
||||
# Logging
|
||||
# obsoletes QuietMode and FascistLogging
|
||||
#SyslogFacility AUTH
|
||||
#LogLevel INFO
|
||||
|
||||
# Authentication:
|
||||
|
||||
#LoginGraceTime 2m
|
||||
#PermitRootLogin yes
|
||||
#PermitRootLogin prohibit-password
|
||||
#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
|
||||
#AuthorizedPrincipalsFile none
|
||||
|
||||
# For this to work you will also need host keys in %windir%/programdata/openssh/config/ssh_known_hosts
|
||||
#HostbasedAuthentication no
|
||||
# Change to yes if you don't trust ~/.ssh/known_hosts for
|
||||
# RhostsRSAAuthentication and HostbasedAuthentication
|
||||
# HostbasedAuthentication
|
||||
#IgnoreUserKnownHosts no
|
||||
# Don't read the user's ~/.rhosts and ~/.shosts files
|
||||
#IgnoreRhosts yes
|
||||
@ -63,50 +51,23 @@ AuthorizedKeysFile .ssh/authorized_keys
|
||||
#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
|
||||
#PermitTTY yes
|
||||
#PrintMotd yes
|
||||
#PrintLastLog yes
|
||||
#TCPKeepAlive yes
|
||||
#UseLogin no
|
||||
#UsePrivilegeSeparation yes
|
||||
#PermitUserEnvironment no
|
||||
#Compression delayed
|
||||
#ClientAliveInterval 0
|
||||
#ClientAliveCountMax 3
|
||||
#UseDNS yes
|
||||
#UseDNS no
|
||||
#PidFile /var/run/sshd.pid
|
||||
#MaxStartups 10
|
||||
#MaxStartups 10:30:100
|
||||
#PermitTunnel no
|
||||
#ChrootDirectory none
|
||||
#VersionAddendum none
|
||||
|
||||
# no default banner path
|
||||
#Banner none
|
||||
@ -116,8 +77,6 @@ Subsystem sftp sftp-server.exe
|
||||
|
||||
# Example of overriding settings on a per-user basis
|
||||
#Match User anoncvs
|
||||
# X11Forwarding no
|
||||
# AllowTcpForwarding no
|
||||
# PermitTTY no
|
||||
# ForceCommand cvs server
|
||||
# PubkeyAcceptedKeyTypes ssh-ed25519*
|
||||
hostkeyagent \\.\pipe\openssh-ssh-agent
|
Binary file not shown.
@ -292,6 +292,7 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\utf.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\spawn.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\w32fd.h" />
|
||||
@ -337,6 +338,7 @@
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\debug.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\console.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\spawn.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -19,6 +19,7 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\utf.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\spawn.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\w32fd.h" />
|
||||
@ -138,6 +139,9 @@
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\debug.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\console.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\spawn.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="inc">
|
||||
|
@ -118,7 +118,8 @@ ConEnterRawMode()
|
||||
dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||
|
||||
char *envValue = NULL;
|
||||
_dupenv_s(&envValue, NULL, "SSH_TERM_CONHOST_PARSER");
|
||||
size_t len = 0;
|
||||
_dupenv_s(&envValue, &len, "SSH_TERM_CONHOST_PARSER");
|
||||
|
||||
if (NULL != envValue) {
|
||||
isConHostParserEnabled = atoi(envValue);
|
||||
|
@ -174,11 +174,12 @@ cleanup:
|
||||
static int pipe_counter = 0;
|
||||
|
||||
/*
|
||||
* pipe() implementation. Creates an inbound named pipe, uses CreateFile to connect
|
||||
* pipe() (unidirectional) and socketpair() (duplex)
|
||||
* implementation. Creates an inbound named pipe, uses CreateFile to connect
|
||||
* to it. These handles are associated with read end and write end of the pipe
|
||||
*/
|
||||
int
|
||||
fileio_pipe(struct w32_io* pio[2])
|
||||
fileio_pipe(struct w32_io* pio[2], int duplex)
|
||||
{
|
||||
HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE;
|
||||
struct w32_io *pio_read = NULL, *pio_write = NULL;
|
||||
@ -205,7 +206,7 @@ fileio_pipe(struct w32_io* pio[2])
|
||||
|
||||
/* create named pipe */
|
||||
write_handle = CreateNamedPipeA(pipe_name,
|
||||
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
|
||||
(duplex ? PIPE_ACCESS_DUPLEX : PIPE_ACCESS_OUTBOUND ) | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
1,
|
||||
4096,
|
||||
@ -220,7 +221,7 @@ fileio_pipe(struct w32_io* pio[2])
|
||||
|
||||
/* connect to named pipe */
|
||||
read_handle = CreateFileA(pipe_name,
|
||||
GENERIC_READ,
|
||||
duplex ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
|
||||
0,
|
||||
&sec_attributes,
|
||||
OPEN_EXISTING,
|
||||
@ -923,14 +924,12 @@ fileio_close(struct w32_io* pio)
|
||||
/* let queued APCs (if any) drain */
|
||||
SleepEx(0, TRUE);
|
||||
CloseHandle(WINHANDLE(pio));
|
||||
/* free up non stdio */
|
||||
if (!IS_STDIO(pio)) {
|
||||
if (pio->read_details.buf)
|
||||
free(pio->read_details.buf);
|
||||
if (pio->write_details.buf)
|
||||
free(pio->write_details.buf);
|
||||
free(pio);
|
||||
}
|
||||
if (pio->read_details.buf)
|
||||
free(pio->read_details.buf);
|
||||
if (pio->write_details.buf)
|
||||
free(pio->write_details.buf);
|
||||
free(pio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ int w32_fcntl(int fd, int cmd, ... /* arg */);
|
||||
int w32_open(const char *pathname, int flags, ... /* arg */);
|
||||
|
||||
void* w32_fd_to_handle(int fd);
|
||||
int w32_allocate_fd_for_handle(HANDLE, BOOL);
|
||||
|
||||
#define O_RDONLY _O_RDONLY
|
||||
#define O_WRONLY _O_WRONLY
|
||||
|
@ -40,6 +40,7 @@ struct passwd *w32_getpwuid(uid_t uid);
|
||||
struct passwd *w32_getpwnam(const char *username);
|
||||
struct passwd* w32_getpwtoken(HANDLE);
|
||||
struct passwd *getpwent(void);
|
||||
void endpwent(void);
|
||||
|
||||
#define getpwuid w32_getpwuid
|
||||
#define getpwnam w32_getpwnam
|
||||
|
77
contrib/win32/win32compat/inc/spawn.h
Normal file
77
contrib/win32/win32compat/inc/spawn.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
|
||||
*
|
||||
* Declarations of POSIX spawn family of functions
|
||||
*/
|
||||
#pragma once
|
||||
#include "sys\types.h"
|
||||
|
||||
#define POSIX_SPAWN_RESETIDS 0x1
|
||||
#define POSIX_SPAWN_SETPGROUP 0x2
|
||||
#define POSIX_SPAWN_SETSIGDEF 0x4
|
||||
#define POSIX_SPAWN_SETSIGMASK 0x8
|
||||
#define POSIX_SPAWN_SETSCHEDPARAM 0x10
|
||||
#define POSIX_SPAWN_SETSCHEDULER 0x20
|
||||
|
||||
#define MAX_INHERITED_FDS 10
|
||||
typedef struct
|
||||
{
|
||||
/* stdio to be redirected*/
|
||||
int stdio_redirect[3];
|
||||
/* number of additinal fds to be duplicated/inherited*/
|
||||
int num_aux_fds;
|
||||
/* additional fds to be duplicated/inherited */
|
||||
struct {
|
||||
int parent_fd[MAX_INHERITED_FDS];
|
||||
int child_fd[MAX_INHERITED_FDS];
|
||||
}aux_fds_info;
|
||||
}posix_spawn_file_actions_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int flags;
|
||||
}posix_spawnattr_t;
|
||||
|
||||
int
|
||||
posix_spawn(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);
|
||||
|
||||
int
|
||||
__posix_spawn_asuser(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], char* user);
|
||||
|
||||
int
|
||||
posix_spawnp(pid_t *pidp, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions);
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int fildes);
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, int fildes, int newfildes);
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *file_actions, int fildes, const char *path, int oflag, mode_t mode);
|
||||
|
||||
int
|
||||
posix_spawnattr_init(posix_spawnattr_t *attr);
|
||||
|
||||
int
|
||||
posix_spawnattr_destroy(posix_spawnattr_t *attr);
|
||||
|
||||
int
|
||||
posix_spawnattr_getflags(const posix_spawnattr_t *attr, short *flags);
|
||||
|
||||
int
|
||||
posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
|
||||
|
||||
int posix_spawnattr_getpgroup(const posix_spawnattr_t * attr, pid_t * pgroup);
|
||||
|
||||
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
|
||||
|
||||
|
||||
|
||||
|
@ -20,3 +20,5 @@ FILE* w32_fdopen(int fd, const char *mode);
|
||||
|
||||
int w32_rename(const char *old_name, const char *new_name);
|
||||
#define rename w32_rename
|
||||
|
||||
int is_absolute_path(char *);
|
@ -7,6 +7,7 @@
|
||||
#include <stddef.h>
|
||||
#include "sys\types.h"
|
||||
#include "fcntl.h"
|
||||
#include "spawn.h"
|
||||
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
@ -79,7 +80,8 @@ int daemon(int nochdir, int noclose);
|
||||
char *crypt(const char *key, const char *salt);
|
||||
int link(const char *oldpath, const char *newpath);
|
||||
int readlink(const char *path, char *link, int linklen);
|
||||
int spawn_child(char*, char**, int, int, int, unsigned long);
|
||||
|
||||
int chroot(const char *path);
|
||||
|
||||
/*
|
||||
* readpassphrase.h definitions
|
||||
|
@ -241,26 +241,29 @@ dlsym(HMODULE handle, const char *symbol)
|
||||
* only r, w, a are supported for now
|
||||
*/
|
||||
FILE *
|
||||
w32_fopen_utf8(const char *path, const char *mode)
|
||||
w32_fopen_utf8(const char *input_path, const char *mode)
|
||||
{
|
||||
wchar_t wpath[PATH_MAX], wmode[5];
|
||||
FILE* f;
|
||||
char utf8_bom[] = { 0xEF,0xBB,0xBF };
|
||||
char first3_bytes[3];
|
||||
int status = 1;
|
||||
errno_t r = 0;
|
||||
errno_t r = 0;
|
||||
char *path = NULL;
|
||||
|
||||
if (mode[1] != '\0') {
|
||||
errno = ENOTSUP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(NULL == path) {
|
||||
if(NULL == input_path) {
|
||||
errno = EINVAL;
|
||||
debug3("fopen - ERROR:%d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = resolved_path(input_path);
|
||||
|
||||
/* if opening null device, point to Windows equivalent */
|
||||
if (0 == strncmp(path, NULL_DEVICE, strlen(NULL_DEVICE)+1)) {
|
||||
if ((r = wcsncpy_s(wpath, PATH_MAX, L"NUL", 3)) != 0) {
|
||||
@ -518,7 +521,7 @@ int
|
||||
w32_chmod(const char *pathname, mode_t mode)
|
||||
{
|
||||
int ret;
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(pathname));
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(pathname));
|
||||
if (resolvedPathName_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
@ -646,7 +649,7 @@ w32_utimes(const char *filename, struct timeval *tvp)
|
||||
{
|
||||
int ret;
|
||||
FILETIME acttime, modtime;
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(filename));
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(filename));
|
||||
if (resolvedPathName_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
@ -680,8 +683,14 @@ link(const char *oldpath, const char *newpath)
|
||||
int
|
||||
w32_rename(const char *old_name, const char *new_name)
|
||||
{
|
||||
wchar_t *resolvedOldPathName_utf16 = utf8_to_utf16(sanitized_path(old_name));
|
||||
wchar_t *resolvedNewPathName_utf16 = utf8_to_utf16(sanitized_path(new_name));
|
||||
char old_name_resolved[PATH_MAX] = {0, };
|
||||
char new_name_resolved[PATH_MAX] = {0, };
|
||||
|
||||
strcpy_s(old_name_resolved, _countof(old_name_resolved), resolved_path(old_name));
|
||||
strcpy_s(new_name_resolved, _countof(new_name_resolved), resolved_path(new_name));
|
||||
|
||||
wchar_t *resolvedOldPathName_utf16 = utf8_to_utf16(old_name_resolved);
|
||||
wchar_t *resolvedNewPathName_utf16 = utf8_to_utf16(new_name_resolved);
|
||||
|
||||
if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
@ -694,17 +703,17 @@ w32_rename(const char *old_name, const char *new_name)
|
||||
* 2) if the new_name is directory and it is empty then delete it so that _wrename will succeed.
|
||||
*/
|
||||
struct _stat64 st;
|
||||
if (fileio_stat(sanitized_path(new_name), &st) != -1) {
|
||||
if (fileio_stat(resolved_path(new_name_resolved), &st) != -1) {
|
||||
if (((st.st_mode & _S_IFMT) == _S_IFREG))
|
||||
w32_unlink(new_name);
|
||||
w32_unlink(new_name_resolved);
|
||||
else {
|
||||
DIR *dirp = opendir(new_name);
|
||||
DIR *dirp = opendir(new_name_resolved);
|
||||
if (NULL != dirp) {
|
||||
struct dirent *dp = readdir(dirp);
|
||||
closedir(dirp);
|
||||
|
||||
if (dp == NULL)
|
||||
w32_rmdir(new_name);
|
||||
w32_rmdir(new_name_resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -719,7 +728,7 @@ w32_rename(const char *old_name, const char *new_name)
|
||||
int
|
||||
w32_unlink(const char *path)
|
||||
{
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(path));
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(path));
|
||||
if (NULL == resolvedPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
@ -734,7 +743,7 @@ w32_unlink(const char *path)
|
||||
int
|
||||
w32_rmdir(const char *path)
|
||||
{
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(path));
|
||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(path));
|
||||
if (NULL == resolvedPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
@ -794,7 +803,7 @@ int
|
||||
w32_mkdir(const char *path_utf8, unsigned short mode)
|
||||
{
|
||||
int curmask;
|
||||
wchar_t *path_utf16 = utf8_to_utf16(sanitized_path(path_utf8));
|
||||
wchar_t *path_utf16 = utf8_to_utf16(resolved_path(path_utf8));
|
||||
if (path_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
@ -816,16 +825,16 @@ w32_mkdir(const char *path_utf8, unsigned short mode)
|
||||
}
|
||||
|
||||
int
|
||||
w32_stat(const char *path, struct w32_stat *buf)
|
||||
w32_stat(const char *input_path, struct w32_stat *buf)
|
||||
{
|
||||
return fileio_stat(sanitized_path(path), (struct _stat64*)buf);
|
||||
return fileio_stat(resolved_path(input_path), (struct _stat64*)buf);
|
||||
}
|
||||
|
||||
/* if file is symbolic link, copy its link into "link" */
|
||||
int
|
||||
readlink(const char *path, char *link, int linklen)
|
||||
{
|
||||
if(strcpy_s(link, linklen, sanitized_path(path)))
|
||||
if(strcpy_s(link, linklen, resolved_path(path)))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@ -909,31 +918,44 @@ realpath(const char *path, char resolved[PATH_MAX])
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/* This function is not thread safe.
|
||||
* TODO - It uses static memory. Is this a good design?
|
||||
*/
|
||||
char*
|
||||
sanitized_path(const char *path)
|
||||
resolved_path(const char *input_path)
|
||||
{
|
||||
if(!path) return NULL;
|
||||
|
||||
static char resolved_path[PATH_MAX] = {0,};
|
||||
static char newPath[PATH_MAX] = { '\0', };
|
||||
errno_t r = 0;
|
||||
|
||||
if (path[0] == '/' && path[1]) {
|
||||
if (path[2] == ':') {
|
||||
if (path[3] == '\0') { /* make "/x:" as "x:\\" */
|
||||
if((r = strncpy_s(newPath, sizeof(newPath), path + 1, strlen(path) - 1)) != 0 ) {
|
||||
debug3("memcpy_s failed with error: %d.", r);
|
||||
return NULL;
|
||||
}
|
||||
newPath[2] = '\\';
|
||||
newPath[3] = '\0';
|
||||
if (!input_path) return NULL;
|
||||
|
||||
return newPath;
|
||||
/* If filename contains __PROGRAMDATA__ then expand it to %programData% and return the resolved path */
|
||||
if ((strlen(input_path) >= strlen(PROGRAM_DATA)) && (memcmp(input_path, PROGRAM_DATA, strlen(PROGRAM_DATA)) == 0)) {
|
||||
resolved_path[0] = '\0';
|
||||
strcat_s(resolved_path, _countof(resolved_path), get_program_data_path());
|
||||
strcat_s(resolved_path, _countof(resolved_path), &input_path[strlen(PROGRAM_DATA)]);
|
||||
|
||||
return resolved_path; /* return here as its doesn't start with "/" */
|
||||
}
|
||||
|
||||
strcpy_s(resolved_path, _countof(resolved_path), input_path);
|
||||
if (resolved_path[0] == '/' && resolved_path[1]) {
|
||||
if (resolved_path[2] == ':') {
|
||||
if (resolved_path[3] == '\0') {
|
||||
/* make "/x:" as "x:\\" */
|
||||
resolved_path[0] = resolved_path[1];
|
||||
resolved_path[1] = resolved_path[2];
|
||||
resolved_path[2] = '\\';
|
||||
resolved_path[3] = '\0';
|
||||
|
||||
return resolved_path;
|
||||
} else
|
||||
return (char *)(path + 1); /* skip the first "/" */
|
||||
return (char *)(resolved_path + 1); /* skip the first "/" */
|
||||
}
|
||||
}
|
||||
|
||||
return (char *)path;
|
||||
return (char *)resolved_path;
|
||||
}
|
||||
|
||||
int
|
||||
@ -944,7 +966,7 @@ statvfs(const char *path, struct statvfs *buf)
|
||||
DWORD freeClusters;
|
||||
DWORD totalClusters;
|
||||
|
||||
wchar_t* path_utf16 = utf8_to_utf16(sanitized_path(path));
|
||||
wchar_t* path_utf16 = utf8_to_utf16(resolved_path(path));
|
||||
if (path_utf16 && (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector,
|
||||
&freeClusters, &totalClusters) == TRUE)) {
|
||||
debug5("path : [%s]", path);
|
||||
@ -1413,3 +1435,34 @@ cleanup:
|
||||
LocalFree(pSD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char*
|
||||
get_program_data_path()
|
||||
{
|
||||
if (ssh_cfg_dir_path) return ssh_cfg_dir_path;
|
||||
|
||||
wchar_t ssh_cfg_dir_path_w[PATH_MAX] = {0, };
|
||||
int return_val = ExpandEnvironmentStringsW(L"%programData%", ssh_cfg_dir_path_w, PATH_MAX);
|
||||
if (return_val > PATH_MAX)
|
||||
fatal("%s, buffer too small to expand:%s", __func__, "%programData%");
|
||||
else if (!return_val)
|
||||
fatal("%s, failed to expand:%s error:%s", __func__, "%programData%", GetLastError());
|
||||
|
||||
ssh_cfg_dir_path = utf16_to_utf8(ssh_cfg_dir_path_w);
|
||||
if(!ssh_cfg_dir_path)
|
||||
fatal("%s utf16_to_utf8 failed", __func__);
|
||||
|
||||
return ssh_cfg_dir_path;
|
||||
}
|
||||
|
||||
/* Windows absolute paths - \abc, /abc, c:\abc, c:/abc, __PROGRAMDATA__\openssh\sshd_config */
|
||||
int
|
||||
is_absolute_path(char *path)
|
||||
{
|
||||
int retVal = 0;
|
||||
if (*path == '/' || *path == '\\' || (*path != '\0' && path[1] == ':') ||
|
||||
((strlen(path) >= strlen(PROGRAM_DATA)) && (memcmp(path, PROGRAM_DATA, strlen(PROGRAM_DATA)) == 0)))
|
||||
retVal = 1;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
@ -2,9 +2,6 @@
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#define PATH_MAX MAX_PATH
|
||||
#define SSH_ASYNC_STDIN "SSH_ASYNC_STDIN"
|
||||
#define SSH_ASYNC_STDOUT "SSH_ASYNC_STDOUT"
|
||||
#define SSH_ASYNC_STDERR "SSH_ASYNC_STDERR"
|
||||
|
||||
#define GOTO_CLEANUP_IF(_cond_,_err_) do { \
|
||||
if ((_cond_)) { \
|
||||
@ -18,25 +15,28 @@
|
||||
|
||||
#define IS_INVALID_HANDLE(h) ( ((NULL == h) || (INVALID_HANDLE_VALUE == h)) ? 1 : 0 )
|
||||
#define IS_VALID_HANDLE(h) (!IS_INVALID_HANDLE(h))
|
||||
#define PROGRAM_DATA "__PROGRAMDATA__"
|
||||
|
||||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||
|
||||
static char *machine_domain_name;
|
||||
static char *ssh_cfg_dir_path = NULL;
|
||||
|
||||
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */
|
||||
char * sanitized_path(const char *);
|
||||
|
||||
char * resolved_path(const char *);
|
||||
void w32posix_initialize();
|
||||
void w32posix_done();
|
||||
|
||||
char* w32_programdir();
|
||||
|
||||
void convertToBackslash(char *str);
|
||||
void convertToBackslashW(wchar_t *str);
|
||||
void convertToForwardslash(char *str);
|
||||
|
||||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||
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);
|
||||
static char *machine_domain_name;
|
||||
void to_lower_case(char *s);
|
||||
int get_machine_domain_name(wchar_t *domain, int size);
|
||||
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);
|
||||
|
@ -93,7 +93,7 @@ innetgr(const char *netgroup, const char *host, const char *user, const char *do
|
||||
int
|
||||
chroot(const char *path)
|
||||
{
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -358,3 +358,9 @@ setegid(gid_t gid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
endpwent(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -690,7 +690,7 @@ SendCharacter(HANDLE hInput, WORD attributes, wchar_t character)
|
||||
|
||||
StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color);
|
||||
|
||||
StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%c", 'm');
|
||||
StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, "%c", 'm');
|
||||
|
||||
if (bUseAnsiEmulation && attributes != pattributes)
|
||||
WriteFile(hInput, formatted_output, (DWORD)(Next - formatted_output), &wr, NULL);
|
||||
@ -1204,7 +1204,7 @@ get_default_shell_path()
|
||||
wchar_t *tmp = malloc(PATH_MAX + 1);
|
||||
|
||||
if (!tmp) {
|
||||
printf_s("get_default_shell_path(), Unable to allocate memory");
|
||||
printf_s("%s: out of memory", __func__);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
@ -1257,6 +1257,9 @@ get_default_shell_path()
|
||||
|
||||
if (tmp)
|
||||
free(tmp);
|
||||
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
|
||||
return default_shell_path;
|
||||
}
|
||||
@ -1586,7 +1589,7 @@ start_withno_pty(wchar_t *command)
|
||||
}
|
||||
|
||||
/* for backspace, we need to send space and another backspace for visual erase */
|
||||
if (buf[i] == '\b') {
|
||||
if (buf[i] == '\b' || buf[i] == '\x7f') {
|
||||
if (in_cmd_len > 0) {
|
||||
GOTO_CLEANUP_ON_FALSE(WriteFile(pipe_out, "\b \b", 3, &wr, NULL));
|
||||
in_cmd_len--;
|
||||
|
@ -174,14 +174,17 @@ w32_raise(int sig)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if set to ignore, nothing to do */
|
||||
if (sig_handlers[sig] == W32_SIG_IGN)
|
||||
/* if set to ignore, handle SIGCHLD since zombies need to be automatically reaped */
|
||||
if (sig_handlers[sig] == W32_SIG_IGN) {
|
||||
if (sig == W32_SIGCHLD)
|
||||
sw_cleanup_child_zombies();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* execute any default handlers */
|
||||
switch (sig) {
|
||||
case W32_SIGCHLD:
|
||||
sw_cleanup_child_zombies();
|
||||
/* do nothing for SIGCHLD */;
|
||||
break;
|
||||
default: /* exit process */
|
||||
exit(0);
|
||||
@ -222,7 +225,8 @@ sw_process_pending_signals()
|
||||
/* sftp client is not expecting it */
|
||||
if (exp[i] != W32_SIGALRM)
|
||||
sig_int = TRUE;
|
||||
}
|
||||
} else if (exp[i] == W32_SIGCHLD) /*if SIGCHLD is SIG_IGN, reap zombies*/
|
||||
sw_cleanup_child_zombies();
|
||||
|
||||
sigdelset(&pending_tmp, exp[i]);
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ CALLBACK WSARecvCompletionRoutine(IN DWORD dwError,
|
||||
|
||||
/* initiates async receive operation*/
|
||||
/* TODO - always return 0, or make this a void func. any error should be put in context*/
|
||||
int
|
||||
socketio_WSARecv(struct w32_io* pio, BOOL* completed)
|
||||
static int
|
||||
socketio_WSARecv(struct w32_io* pio, BOOL* completed, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
WSABUF wsabuf;
|
||||
@ -194,6 +194,9 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed)
|
||||
} else
|
||||
wsabuf.buf = pio->read_details.buf;
|
||||
|
||||
if (len)
|
||||
wsabuf.len = len;
|
||||
|
||||
ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, &WSARecvCompletionRoutine);
|
||||
if (ret == 0) {
|
||||
pio->read_details.pending = TRUE;
|
||||
@ -420,7 +423,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != socketio_WSARecv(pio, &completed))
|
||||
if (0 != socketio_WSARecv(pio, &completed, (int)len))
|
||||
return -1;
|
||||
|
||||
if (completed) {
|
||||
@ -701,6 +704,7 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen)
|
||||
if (pio->read_details.error) {
|
||||
errno = errno_from_WSAError(pio->read_details.error);
|
||||
debug3("accept - ERROR: async io completed with error: %d, io:%p", pio->read_details.error, pio);
|
||||
pio->read_details.error = 0;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
@ -952,7 +956,7 @@ socketio_on_select(struct w32_io* pio, BOOL rd)
|
||||
}
|
||||
} else if(sock_state == SOCK_READY) {
|
||||
/* connected socket - WSARecv if needed */
|
||||
if ((!pio->read_details.pending) && (!socketio_is_io_available(pio, rd)) && (socketio_WSARecv(pio, NULL) != 0))
|
||||
if ((!pio->read_details.pending) && (!socketio_is_io_available(pio, rd)) && (socketio_WSARecv(pio, NULL, 0) != 0))
|
||||
{
|
||||
/* set error, recv() will pick it */
|
||||
pio->read_details.error = errno;
|
||||
|
27
contrib/win32/win32compat/spawn-ext.c
Normal file
27
contrib/win32/win32compat/spawn-ext.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <Windows.h>
|
||||
#include "misc_internal.h"
|
||||
#include "inc\unistd.h"
|
||||
#include "debug.h"
|
||||
|
||||
int posix_spawn_internal(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], HANDLE user_token);
|
||||
|
||||
int
|
||||
__posix_spawn_asuser(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], char* user)
|
||||
{
|
||||
extern HANDLE password_auth_token;
|
||||
int r = -1;
|
||||
/* use token generated from password auth if already present */
|
||||
HANDLE user_token = password_auth_token;
|
||||
|
||||
if (!user_token && (user_token = get_user_token(user)) == NULL) {
|
||||
error("unable to get security token for user %s", user);
|
||||
errno = EOTHER;
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(user, "sshd"))
|
||||
load_user_profile(user_token, user);
|
||||
|
||||
r = posix_spawn_internal(pidp, path, file_actions, attrp, argv, envp, user_token);
|
||||
CloseHandle(user_token);
|
||||
return r;
|
||||
}
|
104
contrib/win32/win32compat/spawn.c
Normal file
104
contrib/win32/win32compat/spawn.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
|
||||
*
|
||||
* Implementation of POSIX spawn family of functions
|
||||
*/
|
||||
#include <Windows.h>
|
||||
#include "inc\spawn.h"
|
||||
#include "inc\unistd.h"
|
||||
|
||||
int
|
||||
posix_spawnp(pid_t *pidp, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[])
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
|
||||
{
|
||||
memset(file_actions, 0, sizeof(posix_spawn_file_actions_t));
|
||||
file_actions->stdio_redirect[0] = 0;
|
||||
file_actions->stdio_redirect[1] = 1;
|
||||
file_actions->stdio_redirect[2] = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int fildes)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, int fildes, int newfildes)
|
||||
{
|
||||
if (newfildes <= STDERR_FILENO) {
|
||||
file_actions->stdio_redirect[newfildes] = fildes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file_actions->num_aux_fds == MAX_INHERITED_FDS) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_actions->aux_fds_info.parent_fd[file_actions->num_aux_fds] = fildes;
|
||||
file_actions->aux_fds_info.child_fd[file_actions->num_aux_fds] = newfildes;
|
||||
file_actions->num_aux_fds++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *file_actions, int fildes, const char *path, int oflag, mode_t mode)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_init(posix_spawnattr_t *attr)
|
||||
{
|
||||
memset(attr, 0, sizeof(posix_spawnattr_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_destroy(posix_spawnattr_t *attr)
|
||||
{
|
||||
memset(attr, 0, sizeof(posix_spawnattr_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_getflags(const posix_spawnattr_t *attr, short *flags)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
|
||||
{
|
||||
if (flags != POSIX_SPAWN_SETPGROUP) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
attr->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getpgroup(const posix_spawnattr_t * attr, pid_t * pgroup) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup) {
|
||||
return 0;
|
||||
}
|
@ -113,14 +113,15 @@ fix_cwd()
|
||||
_wchdir(path);
|
||||
}
|
||||
|
||||
/* TODO - get rid of this dependency */
|
||||
void log_init(char*, int, int, int);
|
||||
|
||||
int
|
||||
wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
_set_invalid_parameter_handler(invalid_parameter_handler);
|
||||
w32posix_initialize();
|
||||
fix_cwd();
|
||||
/* this exits() on failure*/
|
||||
load_config();
|
||||
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
|
||||
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
|
||||
/*
|
||||
@ -146,7 +147,7 @@ wmain(int argc, wchar_t **argv)
|
||||
char* h = 0;
|
||||
h += _wtoi(*(argv + 1));
|
||||
if (h != 0) {
|
||||
log_init("ssh-agent", config_log_level(), 1, 0);
|
||||
log_init("ssh-agent", 3, 1, 0);
|
||||
agent_process_connection(h);
|
||||
return 0;
|
||||
}
|
||||
@ -184,7 +185,7 @@ scm_start_service(DWORD num, LPWSTR* args)
|
||||
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300);
|
||||
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||
log_init("ssh-agent", config_log_level(), 1, 0);
|
||||
log_init("ssh-agent", 3, 1, 0);
|
||||
agent_start(FALSE);
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,6 +16,5 @@ int process_request_identities(struct sshbuf*, struct sshbuf*, struct agent_conn
|
||||
int process_sign_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
|
||||
int process_remove_key(struct sshbuf*, struct sshbuf*, struct agent_connection*);
|
||||
int process_remove_all(struct sshbuf*, struct sshbuf*, struct agent_connection*);
|
||||
int process_privagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
|
||||
|
||||
/* auth */
|
||||
|
@ -168,10 +168,6 @@ agent_cleanup_connection(struct agent_connection* con)
|
||||
{
|
||||
debug("connection %p clean up", con);
|
||||
CloseHandle(con->pipe_handle);
|
||||
if (con->profile_handle)
|
||||
UnloadUserProfile(con->profile_token, con->profile_handle);
|
||||
if (con->profile_token)
|
||||
CloseHandle(con->profile_token);
|
||||
if (con->client_impersonation_token)
|
||||
CloseHandle(con->client_impersonation_token);
|
||||
if (con->client_process_handle)
|
||||
@ -222,7 +218,7 @@ agent_start(BOOL dbg_mode)
|
||||
}
|
||||
|
||||
static char*
|
||||
con_type_to_string(struct agent_connection* con)
|
||||
con_type_to_string(struct agent_connection* con)
|
||||
{
|
||||
switch (con->client_type) {
|
||||
case UNKNOWN:
|
||||
@ -258,16 +254,16 @@ get_con_client_info(struct agent_connection* con)
|
||||
BOOL isMember = FALSE;
|
||||
|
||||
if (GetNamedPipeClientProcessId(con->pipe_handle, &client_pid) == FALSE ||
|
||||
(client_process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL ||
|
||||
OpenProcessToken(client_process_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
|
||||
DuplicateToken(client_primary_token, SecurityImpersonation, &client_impersonation_token) == FALSE) {
|
||||
(client_process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL ||
|
||||
OpenProcessToken(client_process_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
|
||||
DuplicateToken(client_primary_token, SecurityImpersonation, &client_impersonation_token) == FALSE) {
|
||||
error("cannot retrieve client impersonation token");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GetTokenInformation(client_primary_token, TokenUser, NULL, 0, &info_len) == TRUE ||
|
||||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
||||
GetTokenInformation(client_primary_token, TokenUser, info, info_len, &info_len) == FALSE)
|
||||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
||||
GetTokenInformation(client_primary_token, TokenUser, info, info_len, &info_len) == FALSE)
|
||||
goto done;
|
||||
|
||||
/* check if its localsystem */
|
||||
@ -322,7 +318,7 @@ get_con_client_info(struct agent_connection* con)
|
||||
sid_size = SECURITY_MAX_SID_SIZE;
|
||||
if (CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, sid, &sid_size) == FALSE)
|
||||
goto done;
|
||||
if (CheckTokenMembership(client_impersonation_token, sid, &isMember) == FALSE)
|
||||
if (CheckTokenMembership(client_impersonation_token, sid, &isMember) == FALSE)
|
||||
goto done;
|
||||
if (isMember) {
|
||||
con->client_type = ADMIN_USER;
|
||||
@ -355,7 +351,7 @@ done:
|
||||
CloseHandle(client_process_handle);
|
||||
if (client_impersonation_token)
|
||||
CloseHandle(client_impersonation_token);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#define __attribute__(A)
|
||||
#include "log.h"
|
||||
#include "Debug.h"
|
||||
|
||||
#define MAX_MESSAGE_SIZE 256 * 1024
|
||||
|
||||
#define SSH_ROOT L"SOFTWARE\\OpenSSH"
|
||||
@ -37,9 +37,6 @@ struct agent_connection {
|
||||
SYSTEM, /* client is running as System */
|
||||
SERVICE, /* client is running as LS or NS */
|
||||
} client_type;
|
||||
/* user profile related members */
|
||||
HANDLE profile_token;
|
||||
HANDLE profile_handle;
|
||||
};
|
||||
|
||||
void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*);
|
||||
@ -50,6 +47,3 @@ void agent_start(BOOL);
|
||||
void agent_process_connection(HANDLE);
|
||||
void agent_shutdown();
|
||||
void agent_cleanup_connection(struct agent_connection*);
|
||||
|
||||
int load_config();
|
||||
int config_log_level();
|
@ -30,7 +30,6 @@
|
||||
*/
|
||||
#include "agent.h"
|
||||
#include "agent-request.h"
|
||||
#include "..\priv-agent.h"
|
||||
|
||||
#pragma warning(push, 3)
|
||||
|
||||
@ -117,26 +116,6 @@ agent_connection_disconnect(struct agent_connection* con)
|
||||
DisconnectNamedPipe(con->pipe_handle);
|
||||
}
|
||||
|
||||
static char*
|
||||
con_type_to_string(struct agent_connection* con) {
|
||||
switch (con->client_type) {
|
||||
case UNKNOWN:
|
||||
return "unknown";
|
||||
case NONADMIN_USER:
|
||||
return "restricted user";
|
||||
case ADMIN_USER:
|
||||
return "administrator";
|
||||
case SSHD_SERVICE:
|
||||
return "sshd service";
|
||||
case SYSTEM:
|
||||
return "system";
|
||||
case SERVICE:
|
||||
return "service";
|
||||
default:
|
||||
return "unexpected";
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
process_request(struct agent_connection* con)
|
||||
{
|
||||
@ -170,9 +149,6 @@ process_request(struct agent_connection* con)
|
||||
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
|
||||
r = process_remove_all(request, response, con);
|
||||
break;
|
||||
case SSH_PRIV_AGENT_MSG_ID:
|
||||
r = process_privagent_request(request, response, con);
|
||||
break;
|
||||
default:
|
||||
debug("unknown agent request %d", type);
|
||||
r = -1;
|
||||
|
@ -105,16 +105,18 @@ ReadThread(_In_ LPVOID lpParameter)
|
||||
goto done;
|
||||
}
|
||||
|
||||
char *p = NULL;
|
||||
if (p = strstr(pio->read_details.buf, "\r\n"))
|
||||
*p++ = '\n';
|
||||
else if (p = strstr(pio->read_details.buf, "\r"))
|
||||
*p++ = '\n';
|
||||
if (pio->sync_read_status.transferred) {
|
||||
char *p = NULL;
|
||||
if (p = strstr(pio->read_details.buf, "\r\n"))
|
||||
*p++ = '\n';
|
||||
else if (p = strstr(pio->read_details.buf, "\r"))
|
||||
*p++ = '\n';
|
||||
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
pio->read_details.buf_size = (DWORD)strlen(pio->read_details.buf);
|
||||
pio->sync_read_status.transferred = pio->read_details.buf_size;
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
pio->read_details.buf_size = (DWORD)strlen(pio->read_details.buf);
|
||||
pio->sync_read_status.transferred = pio->read_details.buf_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -265,13 +267,10 @@ syncio_close(struct w32_io* pio)
|
||||
/* drain queued APCs */
|
||||
SleepEx(0, TRUE);
|
||||
CloseHandle(WINHANDLE(pio));
|
||||
/* free up if non stdio */
|
||||
if (!IS_STDIO(pio)) {
|
||||
if (pio->read_details.buf)
|
||||
free(pio->read_details.buf);
|
||||
if (pio->write_details.buf)
|
||||
free(pio->write_details.buf);
|
||||
free(pio);
|
||||
}
|
||||
if (pio->read_details.buf)
|
||||
free(pio->read_details.buf);
|
||||
if (pio->write_details.buf)
|
||||
free(pio->write_details.buf);
|
||||
free(pio);
|
||||
return 0;
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen)
|
||||
DWORD nHandle = 1;
|
||||
DWORD dwInput = 0;
|
||||
DWORD dwControlKeyState = 0;
|
||||
DWORD dwAltGrFlags = LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED;
|
||||
DWORD rc = 0;
|
||||
unsigned char octets[20];
|
||||
char aChar = 0;
|
||||
@ -161,6 +162,11 @@ ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen)
|
||||
bShift = (InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED);
|
||||
dwControlKeyState = InputRecord.Event.KeyEvent.dwControlKeyState &
|
||||
~(CAPSLOCK_ON | ENHANCED_KEY | NUMLOCK_ON | SCROLLLOCK_ON);
|
||||
|
||||
/* ignore the AltGr flags*/
|
||||
if ((dwControlKeyState & dwAltGrFlags) == dwAltGrFlags)
|
||||
dwControlKeyState = dwControlKeyState & ~dwAltGrFlags;
|
||||
|
||||
modKey = GetModifierKey(dwControlKeyState);
|
||||
if (InputRecord.Event.KeyEvent.bKeyDown) {
|
||||
int n = WideCharToMultiByte(
|
||||
|
@ -34,8 +34,8 @@
|
||||
#include "inc\pwd.h"
|
||||
#include "sshfileperm.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define SSHD_ACCOUNT L"NT Service\\sshd"
|
||||
#include "misc_internal.h"
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* The function is to check if current user is secure to access to the file.
|
||||
@ -46,10 +46,10 @@
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
int
|
||||
check_secure_file_permission(const char *name, struct passwd * pw)
|
||||
check_secure_file_permission(const char *input_path, struct passwd * pw)
|
||||
{
|
||||
PSECURITY_DESCRIPTOR pSD = NULL;
|
||||
wchar_t * name_utf16 = NULL;
|
||||
wchar_t * path_utf16 = NULL;
|
||||
PSID owner_sid = NULL, user_sid = NULL;
|
||||
PACL dacl = NULL;
|
||||
DWORD error_code = ERROR_SUCCESS;
|
||||
@ -57,6 +57,7 @@ check_secure_file_permission(const char *name, struct passwd * pw)
|
||||
struct passwd * pwd = pw;
|
||||
char *bad_user = NULL;
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
if (pwd == NULL)
|
||||
if ((pwd = getpwuid(0)) == NULL)
|
||||
@ -68,17 +69,19 @@ check_secure_file_permission(const char *name, struct passwd * pw)
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if ((name_utf16 = utf8_to_utf16(name)) == NULL) {
|
||||
|
||||
path = resolved_path(input_path);
|
||||
if ((path_utf16 = utf8_to_utf16(path)) == NULL) {
|
||||
ret = -1;
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*Get the owner sid of the file.*/
|
||||
if ((error_code = GetNamedSecurityInfoW(name_utf16, SE_FILE_OBJECT,
|
||||
if ((error_code = GetNamedSecurityInfoW(path_utf16, SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
&owner_sid, NULL, &dacl, NULL, &pSD)) != ERROR_SUCCESS) {
|
||||
debug3("failed to retrieve the owner sid and dacl of file %s with error code: %d", name, error_code);
|
||||
debug3("failed to retrieve the owner sid and dacl of file %s with error code: %d", path, error_code);
|
||||
errno = EOTHER;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
@ -91,7 +94,7 @@ check_secure_file_permission(const char *name, struct passwd * pw)
|
||||
if (!IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) &&
|
||||
!IsWellKnownSid(owner_sid, WinLocalSystemSid) &&
|
||||
!EqualSid(owner_sid, user_sid)) {
|
||||
debug3("Bad owner on %s", name);
|
||||
debug3("Bad owner on %s", path);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -127,21 +130,13 @@ check_secure_file_permission(const char *name, struct passwd * pw)
|
||||
IsWellKnownSid(current_trustee_sid, WinLocalSystemSid) ||
|
||||
EqualSid(current_trustee_sid, user_sid)) {
|
||||
continue;
|
||||
}
|
||||
else if(is_sshd_account(current_trustee_sid)){
|
||||
if ((current_access_mask & ~FILE_GENERIC_READ) != 0){
|
||||
debug3("Bad permission. %s can only read access to %s", SSHD_ACCOUNT, name);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ret = -1;
|
||||
if (ConvertSidToStringSid(current_trustee_sid, &bad_user) == FALSE) {
|
||||
debug3("ConvertSidToSidString failed with %d. ", GetLastError());
|
||||
break;
|
||||
}
|
||||
debug3("Bad permissions. Try removing permissions for user: %s on file %s.", bad_user, name);
|
||||
debug3("Bad permissions. Try removing permissions for user: %s on file %s.", bad_user, path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -152,31 +147,8 @@ cleanup:
|
||||
LocalFree(pSD);
|
||||
if (user_sid)
|
||||
LocalFree(user_sid);
|
||||
if(name_utf16)
|
||||
free(name_utf16);
|
||||
if(path_utf16)
|
||||
free(path_utf16);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*TODO: optimize to get sshd sid first and then call EqualSid*/
|
||||
static BOOL
|
||||
is_sshd_account(PSID user_sid) {
|
||||
wchar_t user_name[UNCLEN] = { 0 }, full_name[UNCLEN + DNLEN + 2] = { 0 };
|
||||
DWORD name_length = UNCLEN, domain_name_length = 0, full_name_len = UNCLEN + DNLEN + 2;
|
||||
SID_NAME_USE sid_type = SidTypeInvalid;
|
||||
BOOL ret = FALSE;
|
||||
errno_t r = 0;
|
||||
|
||||
if (LookupAccountSidLocalW(user_sid, user_name, &name_length, full_name, &full_name_len, &sid_type) == FALSE)
|
||||
{
|
||||
debug3("LookupAccountSidLocalW() failed with error: %d. ", GetLastError());
|
||||
errno = ENOENT;
|
||||
return FALSE;
|
||||
}
|
||||
domain_name_length = wcsnlen(full_name, _countof(full_name));
|
||||
full_name[domain_name_length] = L'\\';
|
||||
if ((r = wmemcpy_s(full_name + domain_name_length + 1, _countof(full_name) - domain_name_length -1, user_name, wcsnlen_s(user_name, UNCLEN) + 1)) != 0) {
|
||||
debug3("wmemcpy_s failed with error: %d.", r);
|
||||
return FALSE;
|
||||
}
|
||||
return (wcsicmp(full_name, SSHD_ACCOUNT) == 0);
|
||||
}
|
||||
|
@ -60,64 +60,54 @@ struct w32fd_table {
|
||||
/* mapping table*/
|
||||
static struct w32fd_table fd_table;
|
||||
|
||||
/* static table entries representing std in, out and error*/
|
||||
static struct w32_io w32_io_stdin, w32_io_stdout, w32_io_stderr;
|
||||
|
||||
/* main thread handle*/
|
||||
HANDLE main_thread;
|
||||
|
||||
void fd_table_set(struct w32_io* pio, int index);
|
||||
|
||||
void fd_decode_state(char*);
|
||||
#define POSIX_STATE_ENV "c28fc6f98a2c44abbbd89d6a3037d0d9_POSIX_STATE"
|
||||
|
||||
/* initializes mapping table*/
|
||||
static int
|
||||
fd_table_initialize()
|
||||
{
|
||||
char *posix_state;
|
||||
struct w32_io *pio;
|
||||
HANDLE wh;
|
||||
/* table entries representing std in, out and error*/
|
||||
DWORD wh_index[] = { STD_INPUT_HANDLE , STD_OUTPUT_HANDLE , STD_ERROR_HANDLE };
|
||||
int fd_num = 0;
|
||||
|
||||
memset(&fd_table, 0, sizeof(fd_table));
|
||||
memset(&w32_io_stdin, 0, sizeof(w32_io_stdin));
|
||||
w32_io_stdin.std_handle = STD_INPUT_HANDLE;
|
||||
w32_io_stdin.type = NONSOCK_SYNC_FD;
|
||||
|
||||
char *envValue = NULL;
|
||||
_dupenv_s(&envValue, NULL, SSH_ASYNC_STDIN);
|
||||
if (NULL != envValue) {
|
||||
if(strcmp(envValue, "1") == 0)
|
||||
w32_io_stdin.type = NONSOCK_FD;
|
||||
|
||||
free(envValue);
|
||||
/* prepare std io fds */
|
||||
for (fd_num = STDIN_FILENO; fd_num <= STDERR_FILENO; fd_num++) {
|
||||
wh = GetStdHandle(wh_index[fd_num]);
|
||||
if (wh != NULL && wh != INVALID_HANDLE_VALUE) {
|
||||
pio = malloc(sizeof(struct w32_io));
|
||||
if (!pio) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memset(pio, 0, sizeof(struct w32_io));
|
||||
pio->type = NONSOCK_SYNC_FD;
|
||||
pio->handle = wh;
|
||||
fd_table_set(pio, fd_num);
|
||||
}
|
||||
}
|
||||
|
||||
_putenv_s(SSH_ASYNC_STDIN, "");
|
||||
fd_table_set(&w32_io_stdin, STDIN_FILENO);
|
||||
memset(&w32_io_stdout, 0, sizeof(w32_io_stdout));
|
||||
w32_io_stdout.std_handle = STD_OUTPUT_HANDLE;
|
||||
w32_io_stdout.type = NONSOCK_SYNC_FD;
|
||||
|
||||
envValue = NULL;
|
||||
_dupenv_s(&envValue, NULL, SSH_ASYNC_STDOUT);
|
||||
if (NULL != envValue) {
|
||||
if(strcmp(envValue, "1") == 0)
|
||||
w32_io_stdout.type = NONSOCK_FD;
|
||||
_dupenv_s(&posix_state, NULL, POSIX_STATE_ENV);
|
||||
/*TODO - validate parent process - to accomodate these scenarios -
|
||||
* A posix parent process launches a regular process that inturn launches a posix child process
|
||||
* In this case the posix child process may misinterpret POSIX_STATE_ENV set by grand parent
|
||||
*/
|
||||
|
||||
free(envValue);
|
||||
if (NULL != posix_state) {
|
||||
fd_decode_state(posix_state);
|
||||
free(posix_state);
|
||||
_putenv_s(POSIX_STATE_ENV, "");
|
||||
}
|
||||
|
||||
_putenv_s(SSH_ASYNC_STDOUT, "");
|
||||
fd_table_set(&w32_io_stdout, STDOUT_FILENO);
|
||||
memset(&w32_io_stderr, 0, sizeof(w32_io_stderr));
|
||||
w32_io_stderr.std_handle = STD_ERROR_HANDLE;
|
||||
w32_io_stderr.type = NONSOCK_SYNC_FD;
|
||||
|
||||
envValue = NULL;
|
||||
_dupenv_s(&envValue, NULL, SSH_ASYNC_STDERR);
|
||||
if (NULL != envValue) {
|
||||
if(strcmp(envValue, "1") == 0)
|
||||
w32_io_stderr.type = NONSOCK_FD;
|
||||
|
||||
free(envValue);
|
||||
}
|
||||
|
||||
_putenv_s(SSH_ASYNC_STDERR, "");
|
||||
fd_table_set(&w32_io_stderr, STDERR_FILENO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -371,9 +361,34 @@ w32_shutdown(int fd, int how)
|
||||
int
|
||||
w32_socketpair(int domain, int type, int protocol, int sv[2])
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
debug3("socketpair - ERROR not supported");
|
||||
return -1;
|
||||
int p0, p1;
|
||||
struct w32_io* pio[2];
|
||||
|
||||
errno = 0;
|
||||
p0 = fd_table_get_min_index();
|
||||
if (p0 == -1)
|
||||
return -1;
|
||||
|
||||
/*temporarily set occupied bit*/
|
||||
FD_SET(p0, &fd_table.occupied);
|
||||
p1 = fd_table_get_min_index();
|
||||
FD_CLR(p0, &fd_table.occupied);
|
||||
if (p1 == -1)
|
||||
return -1;
|
||||
|
||||
if (-1 == fileio_pipe(pio, 1))
|
||||
return -1;
|
||||
|
||||
pio[0]->type = NONSOCK_FD;
|
||||
pio[1]->type = NONSOCK_FD;
|
||||
fd_table_set(pio[0], p0);
|
||||
fd_table_set(pio[1], p1);
|
||||
sv[0] = p0;
|
||||
sv[1] = p1;
|
||||
debug4("socketpair - r-h:%d,io:%p,fd:%d w-h:%d,io:%p,fd:%d",
|
||||
pio[0]->handle, pio[0], p0, pio[1]->handle, pio[1], p1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -395,7 +410,7 @@ w32_pipe(int *pfds)
|
||||
if (write_index == -1)
|
||||
return -1;
|
||||
|
||||
if (-1 == fileio_pipe(pio))
|
||||
if (-1 == fileio_pipe(pio, 0))
|
||||
return -1;
|
||||
|
||||
pio[0]->type = NONSOCK_FD;
|
||||
@ -427,7 +442,7 @@ w32_open(const char *pathname, int flags, ... /* arg */)
|
||||
va_end(valist);
|
||||
}
|
||||
|
||||
pio = fileio_open(sanitized_path(pathname), flags, mode);
|
||||
pio = fileio_open(resolved_path(pathname), flags, mode);
|
||||
|
||||
if (pio == NULL)
|
||||
return -1;
|
||||
@ -799,95 +814,91 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep
|
||||
return out_ready_fds;
|
||||
}
|
||||
|
||||
int
|
||||
w32_dup(int oldfd)
|
||||
static HANDLE
|
||||
dup_handle(int fd)
|
||||
{
|
||||
int min_index;
|
||||
struct w32_io* pio;
|
||||
HANDLE src, target;
|
||||
CHECK_FD(oldfd);
|
||||
if (oldfd > STDERR_FILENO) {
|
||||
errno = EOPNOTSUPP;
|
||||
debug3("dup - ERROR: supports only std io, fd:%d", oldfd);
|
||||
return -1;
|
||||
HANDLE h = fd_table.w32_ios[fd]->handle;
|
||||
int is_sock = fd_table.w32_ios[fd]->type == SOCK_FD;
|
||||
|
||||
if (is_sock) {
|
||||
SOCKET dup_sock;
|
||||
SOCKET sock = (SOCKET)h;
|
||||
WSAPROTOCOL_INFOW info;
|
||||
if (WSADuplicateSocketW(sock, GetCurrentProcessId(), &info) != 0) {
|
||||
errno = EOTHER;
|
||||
error("WSADuplicateSocket failed, WSALastError: %d", WSAGetLastError());
|
||||
return NULL;
|
||||
}
|
||||
dup_sock = WSASocketW(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, 0);
|
||||
if (dup_sock == INVALID_SOCKET) {
|
||||
errno = EOTHER;
|
||||
error("WSASocketW failed, WSALastError: %d", WSAGetLastError());
|
||||
return NULL;
|
||||
}
|
||||
return (HANDLE)dup_sock;
|
||||
}
|
||||
|
||||
if ((min_index = fd_table_get_min_index()) == -1)
|
||||
return -1;
|
||||
|
||||
src = GetStdHandle(fd_table.w32_ios[oldfd]->std_handle);
|
||||
if (src == INVALID_HANDLE_VALUE) {
|
||||
errno = EINVAL;
|
||||
debug3("dup - ERROR: unable to get underlying handle for std fd:%d", oldfd);
|
||||
return -1;
|
||||
else {
|
||||
HANDLE dup_handle;
|
||||
if (!DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), &dup_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
|
||||
errno = EOTHER;
|
||||
error("dup - ERROR: DuplicatedHandle() :%d", GetLastError());
|
||||
}
|
||||
return dup_handle;
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), &target, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
|
||||
errno = EOTHER;
|
||||
debug3("dup - ERROR: DuplicatedHandle() :%d", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio = (struct w32_io*) malloc(sizeof(struct w32_io));
|
||||
if (pio == NULL) {
|
||||
CloseHandle(target);
|
||||
errno = ENOMEM;
|
||||
debug3("dup - ERROR: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(pio, 0, sizeof(struct w32_io));
|
||||
pio->handle = target;
|
||||
pio->type = fd_table.w32_ios[oldfd]->type;
|
||||
fd_table_set(pio, min_index);
|
||||
return min_index;
|
||||
}
|
||||
|
||||
int
|
||||
w32_dup2(int oldfd, int newfd)
|
||||
{
|
||||
CHECK_FD(oldfd);
|
||||
errno = EOPNOTSUPP;
|
||||
debug3("dup2 - ERROR: not implemented yet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
w32_fd_to_handle(int fd)
|
||||
{
|
||||
HANDLE h = fd_table.w32_ios[fd]->handle;
|
||||
if (fd <= STDERR_FILENO)
|
||||
h = GetStdHandle(fd_table.w32_ios[fd]->std_handle);
|
||||
return h;
|
||||
}
|
||||
|
||||
int
|
||||
w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock)
|
||||
{
|
||||
int min_index = fd_table_get_min_index();
|
||||
struct w32_io* pio;
|
||||
CHECK_FD(oldfd);
|
||||
|
||||
if (min_index == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (fd_table.w32_ios[newfd])
|
||||
w32_close(newfd);
|
||||
|
||||
pio = malloc(sizeof(struct w32_io));
|
||||
if (pio == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(pio, 0, sizeof(struct w32_io));
|
||||
if ((pio->handle = dup_handle(oldfd)) == 0) {
|
||||
free(pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio->type = is_sock ? SOCK_FD : NONSOCK_FD;
|
||||
pio->handle = h;
|
||||
pio->type = fd_table.w32_ios[oldfd]->type;
|
||||
if (pio->type == SOCK_FD)
|
||||
pio->internal.state = SOCK_READY;
|
||||
|
||||
fd_table_set(pio, newfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
w32_dup(int oldfd)
|
||||
{
|
||||
int min_index, r;
|
||||
CHECK_FD(oldfd);
|
||||
|
||||
if ((min_index = fd_table_get_min_index()) == -1)
|
||||
return -1;
|
||||
|
||||
if ((r = w32_dup2(oldfd, min_index)) != 0)
|
||||
return r;
|
||||
|
||||
/* TODO - get socket state and confirm that its connected */
|
||||
pio->internal.state = SOCK_READY;
|
||||
fd_table_set(pio, min_index);
|
||||
return min_index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HANDLE
|
||||
w32_fd_to_handle(int fd)
|
||||
{
|
||||
return fd_table.w32_ios[fd]->handle;
|
||||
}
|
||||
|
||||
int
|
||||
w32_ftruncate(int fd, off_t length)
|
||||
{
|
||||
@ -910,6 +921,11 @@ w32_fsync(int fd)
|
||||
return FlushFileBuffers(w32_fd_to_handle(fd));
|
||||
}
|
||||
|
||||
int fork()
|
||||
{
|
||||
error("fork is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* spawn a child process
|
||||
@ -920,14 +936,18 @@ w32_fsync(int fd)
|
||||
* cmd will be internally decoarated with a set of '"'
|
||||
* to account for any spaces within the commandline
|
||||
* this decoration is done only when additional arguments are passed in argv
|
||||
*
|
||||
* spawned child will run as as_user if its not NULL
|
||||
*/
|
||||
int
|
||||
spawn_child(char* cmd, char** argv, int in, int out, int err, unsigned long flags)
|
||||
|
||||
static int
|
||||
spawn_child_internal(char* cmd, char *const argv[], HANDLE in, HANDLE out, HANDLE err, unsigned long flags, HANDLE* as_user)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOW si;
|
||||
BOOL b;
|
||||
char *cmdline, *t, **t1;
|
||||
char *cmdline, *t;
|
||||
char * const *t1;
|
||||
DWORD cmdline_len = 0;
|
||||
wchar_t * cmdline_utf16 = NULL;
|
||||
int add_module_path = 0, ret = -1;
|
||||
@ -998,22 +1018,17 @@ spawn_child(char* cmd, char** argv, int in, int out, int err, unsigned long flag
|
||||
|
||||
memset(&si, 0, sizeof(STARTUPINFOW));
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.hStdInput = w32_fd_to_handle(in);
|
||||
si.hStdOutput = w32_fd_to_handle(out);
|
||||
si.hStdError = w32_fd_to_handle(err);
|
||||
si.hStdInput = in;
|
||||
si.hStdOutput = out;
|
||||
si.hStdError = err;
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
debug3("spawning %ls", cmdline_utf16);
|
||||
if (fd_table.w32_ios[in]->type != NONSOCK_SYNC_FD)
|
||||
_putenv_s(SSH_ASYNC_STDIN, "1");
|
||||
if (fd_table.w32_ios[out]->type != NONSOCK_SYNC_FD)
|
||||
_putenv_s(SSH_ASYNC_STDOUT, "1");
|
||||
if (fd_table.w32_ios[err]->type != NONSOCK_SYNC_FD)
|
||||
_putenv_s(SSH_ASYNC_STDERR, "1");
|
||||
b = CreateProcessW(NULL, cmdline_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
|
||||
_putenv_s(SSH_ASYNC_STDIN, "");
|
||||
_putenv_s(SSH_ASYNC_STDOUT, "");
|
||||
_putenv_s(SSH_ASYNC_STDERR, "");
|
||||
|
||||
if (as_user)
|
||||
b = CreateProcessAsUserW(as_user, NULL, cmdline_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
|
||||
else
|
||||
b = CreateProcessW(NULL, cmdline_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
|
||||
|
||||
if (b) {
|
||||
if (register_child(pi.hProcess, pi.dwProcessId) == -1) {
|
||||
@ -1037,3 +1052,192 @@ cleanup:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "inc\spawn.h"
|
||||
|
||||
/* structures defining binary layout of fd info to be transmitted between parent and child processes*/
|
||||
struct std_fd_state {
|
||||
int num_inherited;
|
||||
char in_type;
|
||||
char out_type;
|
||||
char err_type;
|
||||
char padding;
|
||||
};
|
||||
|
||||
struct inh_fd_state {
|
||||
int handle;
|
||||
short index;
|
||||
char type;
|
||||
char padding;
|
||||
};
|
||||
|
||||
|
||||
/* encodes the fd info into a base64 encoded binary blob */
|
||||
static char*
|
||||
fd_encode_state(const posix_spawn_file_actions_t *file_actions, HANDLE aux_h[])
|
||||
{
|
||||
char *buf, *encoded;
|
||||
struct std_fd_state *std_fd_state;
|
||||
struct inh_fd_state *c;
|
||||
DWORD len_req;
|
||||
BOOL b;
|
||||
int i;
|
||||
int fd_in = file_actions->stdio_redirect[STDIN_FILENO];
|
||||
int fd_out = file_actions->stdio_redirect[STDOUT_FILENO];
|
||||
int fd_err = file_actions->stdio_redirect[STDERR_FILENO];
|
||||
int num_aux_fds = file_actions->num_aux_fds;
|
||||
const int *parent_aux_fds = file_actions->aux_fds_info.parent_fd;
|
||||
const int *child_aux_fds = file_actions->aux_fds_info.child_fd;
|
||||
|
||||
buf = malloc(8 * (1 + num_aux_fds));
|
||||
if (!buf) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std_fd_state = (struct std_fd_state *)buf;
|
||||
std_fd_state->num_inherited = num_aux_fds;
|
||||
std_fd_state->in_type = fd_table.w32_ios[fd_in]->type;
|
||||
std_fd_state->out_type = fd_table.w32_ios[fd_out]->type;
|
||||
std_fd_state->err_type = fd_table.w32_ios[fd_err]->type;
|
||||
|
||||
c = (struct inh_fd_state*)(buf + 8);
|
||||
for (i = 0; i < num_aux_fds; i++) {
|
||||
c->handle = (int)(intptr_t)aux_h[i];
|
||||
c->index = child_aux_fds[i];
|
||||
c->type = fd_table.w32_ios[parent_aux_fds[i]]->type;
|
||||
c++;
|
||||
}
|
||||
|
||||
b = CryptBinaryToStringA(buf, 8 * (1 + num_aux_fds), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &len_req);
|
||||
encoded = malloc(len_req);
|
||||
if (!encoded) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
b = CryptBinaryToStringA(buf, 8 * (1 + num_aux_fds), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, encoded, &len_req);
|
||||
|
||||
free(buf);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/* decodes fd info from an encoded binary blob */
|
||||
static void
|
||||
fd_decode_state(char* enc_buf)
|
||||
{
|
||||
char* buf;
|
||||
DWORD req, skipped, out_flags;
|
||||
struct std_fd_state *std_fd_state;
|
||||
struct inh_fd_state *c;
|
||||
int num_inherited = 0;
|
||||
|
||||
CryptStringToBinary(enc_buf, 0, CRYPT_STRING_BASE64 | CRYPT_STRING_STRICT, NULL, &req, &skipped, &out_flags);
|
||||
buf = malloc(req);
|
||||
if (!buf)
|
||||
fatal("out of memory");
|
||||
|
||||
CryptStringToBinary(enc_buf, 0, CRYPT_STRING_BASE64 | CRYPT_STRING_STRICT, buf, &req, &skipped, &out_flags);
|
||||
|
||||
std_fd_state = (struct std_fd_state *)buf;
|
||||
fd_table.w32_ios[0]->type = std_fd_state->in_type;
|
||||
if (fd_table.w32_ios[0]->type == SOCK_FD)
|
||||
fd_table.w32_ios[0]->internal.state = SOCK_READY;
|
||||
fd_table.w32_ios[1]->type = std_fd_state->out_type;
|
||||
if (fd_table.w32_ios[1]->type == SOCK_FD)
|
||||
fd_table.w32_ios[1]->internal.state = SOCK_READY;
|
||||
fd_table.w32_ios[2]->type = std_fd_state->err_type;
|
||||
if (fd_table.w32_ios[2]->type == SOCK_FD)
|
||||
fd_table.w32_ios[2]->internal.state = SOCK_READY;
|
||||
num_inherited = std_fd_state->num_inherited;
|
||||
|
||||
c = (struct inh_fd_state*)(buf + 8);
|
||||
while (num_inherited--) {
|
||||
struct w32_io* pio = malloc(sizeof(struct w32_io));
|
||||
if (!pio)
|
||||
fatal("out of memory");
|
||||
ZeroMemory(pio, sizeof(struct w32_io));
|
||||
pio->handle = (void*)(INT_PTR)c->handle;
|
||||
pio->type = c->type;
|
||||
if (pio->type == SOCK_FD)
|
||||
pio->internal.state = SOCK_READY;
|
||||
fd_table_set(pio, c->index);
|
||||
c++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_internal(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], HANDLE user_token)
|
||||
{
|
||||
int i, ret = -1;
|
||||
int sc_flags = 0;
|
||||
char* fd_info = NULL;
|
||||
HANDLE aux_handles[MAX_INHERITED_FDS];
|
||||
HANDLE stdio_handles[STDERR_FILENO + 1];
|
||||
if (file_actions == NULL || envp) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (attrp && attrp->flags == POSIX_SPAWN_SETPGROUP)
|
||||
sc_flags = CREATE_NEW_PROCESS_GROUP;
|
||||
|
||||
/* prepare handles */
|
||||
memset(stdio_handles, 0, sizeof(stdio_handles));
|
||||
memset(aux_handles, 0, sizeof(aux_handles));
|
||||
stdio_handles[STDIN_FILENO] = dup_handle(file_actions->stdio_redirect[STDIN_FILENO]);
|
||||
stdio_handles[STDOUT_FILENO] = dup_handle(file_actions->stdio_redirect[STDOUT_FILENO]);
|
||||
stdio_handles[STDERR_FILENO] = dup_handle(file_actions->stdio_redirect[STDERR_FILENO]);
|
||||
if (!stdio_handles[STDIN_FILENO] || !stdio_handles[STDOUT_FILENO] || !stdio_handles[STDERR_FILENO])
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < file_actions->num_aux_fds; i++) {
|
||||
aux_handles[i] = dup_handle(file_actions->aux_fds_info.parent_fd[i]);
|
||||
if (aux_handles[i] == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set fd info */
|
||||
if ((fd_info = fd_encode_state(file_actions, aux_handles)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (_putenv_s(POSIX_STATE_ENV, fd_info) != 0)
|
||||
goto cleanup;
|
||||
i = spawn_child_internal(argv[0], argv + 1, stdio_handles[STDIN_FILENO], stdio_handles[STDOUT_FILENO], stdio_handles[STDERR_FILENO], sc_flags, user_token);
|
||||
if (i == -1)
|
||||
goto cleanup;
|
||||
if (pidp)
|
||||
*pidp = i;
|
||||
ret = 0;
|
||||
cleanup:
|
||||
_putenv_s(POSIX_STATE_ENV, "");
|
||||
for (i = 0; i <= STDERR_FILENO; i++) {
|
||||
if (stdio_handles[i] != NULL) {
|
||||
if (fd_table.w32_ios[file_actions->stdio_redirect[i]]->type == SOCK_FD)
|
||||
closesocket((SOCKET)stdio_handles[i]);
|
||||
else
|
||||
CloseHandle(stdio_handles[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < file_actions->num_aux_fds; i++) {
|
||||
if (aux_handles[i] != NULL) {
|
||||
if (fd_table.w32_ios[file_actions->aux_fds_info.parent_fd[i]]->type == SOCK_FD)
|
||||
closesocket((SOCKET)aux_handles[i]);
|
||||
else
|
||||
CloseHandle(aux_handles[i]);
|
||||
}
|
||||
}
|
||||
if (fd_info)
|
||||
free(fd_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn(pid_t *pidp, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[])
|
||||
{
|
||||
return posix_spawn_internal(pidp, path, file_actions, attrp, argv, envp, NULL);
|
||||
}
|
||||
|
@ -99,7 +99,6 @@ struct w32_io {
|
||||
union {
|
||||
SOCKET sock;
|
||||
HANDLE handle;
|
||||
DWORD std_handle; /* ex. STD_INPUT_HANDLE */
|
||||
};
|
||||
|
||||
/*internal state used by synchronous io - terminal handles and external
|
||||
@ -122,8 +121,7 @@ struct w32_io {
|
||||
}internal;
|
||||
};
|
||||
|
||||
#define IS_STDIO(pio) ((pio)->table_index <= 2)
|
||||
#define WINHANDLE(pio) (IS_STDIO(pio)? GetStdHandle((pio)->std_handle):(pio)->handle)
|
||||
#define WINHANDLE(pio) ((pio)->handle)
|
||||
#define FILETYPE(pio) (GetFileType(WINHANDLE(pio)))
|
||||
extern HANDLE main_thread;
|
||||
|
||||
@ -155,7 +153,7 @@ int socketio_close(struct w32_io* pio);
|
||||
BOOL fileio_is_io_available(struct w32_io* pio, BOOL rd);
|
||||
void fileio_on_select(struct w32_io* pio, BOOL rd);
|
||||
int fileio_close(struct w32_io* pio);
|
||||
int fileio_pipe(struct w32_io* pio[2]);
|
||||
int fileio_pipe(struct w32_io* pio[2], int);
|
||||
struct w32_io* fileio_afunix_socket();
|
||||
int fileio_connect(struct w32_io*, char*);
|
||||
struct w32_io* fileio_open(const char *pathname, int flags, mode_t mode);
|
||||
|
@ -35,46 +35,48 @@
|
||||
|
||||
#include "inc\syslog.h"
|
||||
#include "misc_internal.h"
|
||||
#include "inc\utf.h"
|
||||
|
||||
#define MSGBUFSIZ 1024
|
||||
static int logfd = -1;
|
||||
|
||||
/*
|
||||
* open a log file using the name of executable under logs folder
|
||||
* Ex. if called from c:\windows\system32\openssh\sshd.exe
|
||||
* logfile - c:\windows\system32\openssh\logs\sshd.log
|
||||
* log file location will be - "%programData%\\openssh\\logs\\<module_name>.log"
|
||||
*/
|
||||
void
|
||||
openlog(char *ident, unsigned int option, int facility)
|
||||
{
|
||||
wchar_t *logs_dir = L"\\logs\\";
|
||||
{
|
||||
if (logfd != -1 || ident == NULL)
|
||||
return;
|
||||
|
||||
wchar_t path[PATH_MAX] = { 0 }, log_file[PATH_MAX + 12] = { 0 };
|
||||
errno_t r = 0;
|
||||
if (GetModuleFileNameW(NULL, path, PATH_MAX) == 0)
|
||||
wchar_t *logs_dir = L"\\logs\\";
|
||||
wchar_t module_path[PATH_MAX] = { 0 }, log_file[PATH_MAX + 12] = { 0 };
|
||||
|
||||
if (GetModuleFileNameW(NULL, module_path, PATH_MAX) == 0)
|
||||
return;
|
||||
|
||||
path[PATH_MAX - 1] = L'\0';
|
||||
|
||||
if (wcsnlen(path, MAX_PATH) > MAX_PATH - wcslen(logs_dir))
|
||||
if (wcsnlen(module_path, MAX_PATH) > MAX_PATH - wcslen(logs_dir))
|
||||
return;
|
||||
|
||||
/* split path root and module */
|
||||
{
|
||||
wchar_t* tail = path + wcsnlen(path, MAX_PATH);
|
||||
while (tail > path && *tail != L'\\' && *tail != L'/')
|
||||
wchar_t* tail = module_path + wcsnlen(module_path, MAX_PATH);
|
||||
while (tail > module_path && *tail != L'\\' && *tail != L'/')
|
||||
tail--;
|
||||
|
||||
char ssh_cfg_path[PATH_MAX] = {0 ,};
|
||||
strcat_s(ssh_cfg_path, _countof(ssh_cfg_path), get_program_data_path()); /* "%programData%" */
|
||||
strcat_s(ssh_cfg_path, _countof(ssh_cfg_path), "\\ssh"); /* "%programData%\\ssh" */
|
||||
|
||||
if (((r = wcsncat_s(log_file, PATH_MAX + 12, path, tail - path)) != 0 ) ||
|
||||
(r = wcsncat_s(log_file, PATH_MAX + 12, logs_dir, 6) != 0 )||
|
||||
(r = wcsncat_s(log_file, PATH_MAX + 12, tail + 1, wcslen(tail + 1) - 3) != 0 ) ||
|
||||
(r = wcsncat_s(log_file, PATH_MAX + 12, L"log", 3) != 0 ))
|
||||
wchar_t* ssh_root_path_w = utf8_to_utf16(ssh_cfg_path); /* "%programData%\\ssh" */
|
||||
|
||||
if ((wcsncat_s(log_file, PATH_MAX + 12, ssh_root_path_w, wcslen(ssh_root_path_w)) != 0) ||
|
||||
(wcsncat_s(log_file, PATH_MAX + 12, logs_dir, 6) != 0) ||
|
||||
(wcsncat_s(log_file, PATH_MAX + 12, tail + 1, wcslen(tail + 1) - 3) != 0 ) ||
|
||||
(wcsncat_s(log_file, PATH_MAX + 12, L"log", 3) != 0))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
errno_t err = _wsopen_s(&logfd, log_file, O_WRONLY | O_CREAT | O_APPEND, SH_DENYNO, S_IREAD | S_IWRITE);
|
||||
|
||||
if (logfd != -1)
|
||||
@ -98,8 +100,8 @@ syslog(int priority, const char *format, const char *formatBuffer)
|
||||
return;
|
||||
|
||||
GetLocalTime(&st);
|
||||
r = _snprintf_s(msgbufTimestamp, sizeof(msgbufTimestamp), _TRUNCATE, "%d %02d:%02d:%02d:%03d %s\n",
|
||||
GetCurrentProcessId(), st.wHour, st.wMinute, st.wSecond,
|
||||
r = _snprintf_s(msgbufTimestamp, sizeof(msgbufTimestamp), _TRUNCATE, "%d %04d-%02d-%02d %02d:%02d:%02d.%03d %s\n",
|
||||
GetCurrentProcessId(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
|
||||
st.wMilliseconds, formatBuffer);
|
||||
if (r == -1) {
|
||||
_write(logfd, "_snprintf_s failed.", 30);
|
||||
@ -107,4 +109,4 @@ syslog(int priority, const char *format, const char *formatBuffer)
|
||||
}
|
||||
msgbufTimestamp[strnlen(msgbufTimestamp, MSGBUFSIZ)] = '\0';
|
||||
_write(logfd, msgbufTimestamp, (unsigned int)strnlen(msgbufTimestamp, MSGBUFSIZ));
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ opendir(const char *name)
|
||||
if (name && strcmp(name, "/") == 0)
|
||||
return openrootdir(name);
|
||||
|
||||
if ((wname = utf8_to_utf16(sanitized_path(name))) == NULL) {
|
||||
if ((wname = utf8_to_utf16(resolved_path(name))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
381
contrib/win32/win32compat/win32_usertoken_utils.c
Normal file
381
contrib/win32/win32compat/win32_usertoken_utils.c
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
|
||||
* Utitilites to generate user tokens
|
||||
*
|
||||
* Copyright (c) 2015 Microsoft Corp.
|
||||
* All rights reserved
|
||||
*
|
||||
* Microsoft openssh win32 port
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define UMDF_USING_NTSTATUS
|
||||
#include <Windows.h>
|
||||
#include <UserEnv.h>
|
||||
#include <Ntsecapi.h>
|
||||
#include <ntstatus.h>
|
||||
#include <Shlobj.h>
|
||||
#include "inc\utf.h"
|
||||
#include "logonuser.h"
|
||||
#include <Ntsecapi.h>
|
||||
#include <ntstatus.h>
|
||||
#include "misc_internal.h"
|
||||
#include "Debug.h"
|
||||
|
||||
#pragma warning(push, 3)
|
||||
|
||||
static void
|
||||
InitLsaString(LSA_STRING *lsa_string, const char *str)
|
||||
{
|
||||
if (!str)
|
||||
memset(lsa_string, 0, sizeof(LSA_STRING));
|
||||
else {
|
||||
lsa_string->Buffer = (char *)str;
|
||||
lsa_string->Length = (USHORT)strlen(str);
|
||||
lsa_string->MaximumLength = lsa_string->Length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EnablePrivilege(const char *privName, int enabled)
|
||||
{
|
||||
TOKEN_PRIVILEGES tp;
|
||||
HANDLE hProcToken = NULL;
|
||||
LUID luid;
|
||||
|
||||
int exitCode = 1;
|
||||
|
||||
if (LookupPrivilegeValueA(NULL, privName, &luid) == FALSE ||
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcToken) == FALSE)
|
||||
goto done;
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = enabled ? SE_PRIVILEGE_ENABLED : 0;
|
||||
|
||||
AdjustTokenPrivileges(hProcToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
|
||||
|
||||
done:
|
||||
if (hProcToken)
|
||||
CloseHandle(hProcToken);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static HANDLE
|
||||
LoadProfile(HANDLE user_token, wchar_t* user, wchar_t* domain) {
|
||||
PROFILEINFOW profileInfo;
|
||||
HANDLE ret = NULL;
|
||||
|
||||
profileInfo.dwFlags = PI_NOUI;
|
||||
profileInfo.lpProfilePath = NULL;
|
||||
profileInfo.lpUserName = user;
|
||||
profileInfo.lpDefaultPath = NULL;
|
||||
profileInfo.lpServerName = domain;
|
||||
profileInfo.lpPolicyPath = NULL;
|
||||
profileInfo.hProfile = NULL;
|
||||
profileInfo.dwSize = sizeof(profileInfo);
|
||||
EnablePrivilege("SeBackupPrivilege", 1);
|
||||
EnablePrivilege("SeRestorePrivilege", 1);
|
||||
if (LoadUserProfileW(user_token, &profileInfo) == FALSE) {
|
||||
debug("Loading user (%ls,%ls) profile failed ERROR: %d", user, domain, GetLastError());
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
ret = profileInfo.hProfile;
|
||||
done:
|
||||
EnablePrivilege("SeBackupPrivilege", 0);
|
||||
EnablePrivilege("SeRestorePrivilege", 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_USER_LEN 64
|
||||
/* https://technet.microsoft.com/en-us/library/active-directory-maximum-limits-scalability(v=ws.10).aspx */
|
||||
#define MAX_FQDN_LEN 64
|
||||
#define MAX_PW_LEN 64
|
||||
|
||||
static HANDLE
|
||||
generate_user_token(wchar_t* user_cpn) {
|
||||
HANDLE lsa_handle = 0, token = 0;
|
||||
LSA_OPERATIONAL_MODE mode;
|
||||
ULONG auth_package_id;
|
||||
NTSTATUS ret, subStatus;
|
||||
void * logon_info = NULL;
|
||||
size_t logon_info_size;
|
||||
LSA_STRING logon_process_name, auth_package_name, originName;
|
||||
TOKEN_SOURCE sourceContext;
|
||||
PKERB_INTERACTIVE_PROFILE pProfile = NULL;
|
||||
LUID logonId;
|
||||
QUOTA_LIMITS quotas;
|
||||
DWORD cbProfile;
|
||||
BOOL domain_user;
|
||||
|
||||
domain_user = wcschr(user_cpn, L'@')? TRUE : FALSE;
|
||||
|
||||
InitLsaString(&logon_process_name, "sshd");
|
||||
if (domain_user)
|
||||
InitLsaString(&auth_package_name, MICROSOFT_KERBEROS_NAME_A);
|
||||
else
|
||||
InitLsaString(&auth_package_name, MSV1_0_PACKAGE_NAME);
|
||||
|
||||
InitLsaString(&originName, "sshd");
|
||||
if (ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode) != STATUS_SUCCESS)
|
||||
goto done;
|
||||
|
||||
if (ret = LsaLookupAuthenticationPackage(lsa_handle, &auth_package_name, &auth_package_id) != STATUS_SUCCESS)
|
||||
goto done;
|
||||
|
||||
if (domain_user) {
|
||||
KERB_S4U_LOGON *s4u_logon;
|
||||
logon_info_size = sizeof(KERB_S4U_LOGON);
|
||||
logon_info_size += (wcslen(user_cpn) * 2 + 2);
|
||||
logon_info = malloc(logon_info_size);
|
||||
if (logon_info == NULL)
|
||||
goto done;
|
||||
s4u_logon = (KERB_S4U_LOGON*)logon_info;
|
||||
s4u_logon->MessageType = KerbS4ULogon;
|
||||
s4u_logon->Flags = 0;
|
||||
s4u_logon->ClientUpn.Length = (USHORT)wcslen(user_cpn) * 2;
|
||||
s4u_logon->ClientUpn.MaximumLength = s4u_logon->ClientUpn.Length;
|
||||
s4u_logon->ClientUpn.Buffer = (WCHAR*)(s4u_logon + 1);
|
||||
if (memcpy_s(s4u_logon->ClientUpn.Buffer, s4u_logon->ClientUpn.Length + 2, user_cpn, s4u_logon->ClientUpn.Length + 2))
|
||||
goto done;
|
||||
s4u_logon->ClientRealm.Length = 0;
|
||||
s4u_logon->ClientRealm.MaximumLength = 0;
|
||||
s4u_logon->ClientRealm.Buffer = 0;
|
||||
} else {
|
||||
MSV1_0_S4U_LOGON *s4u_logon;
|
||||
logon_info_size = sizeof(MSV1_0_S4U_LOGON);
|
||||
/* additional buffer size = size of user_cpn + size of "." and their null terminators */
|
||||
logon_info_size += (wcslen(user_cpn) * 2 + 2) + 4;
|
||||
logon_info = malloc(logon_info_size);
|
||||
if (logon_info == NULL)
|
||||
goto done;
|
||||
s4u_logon = (MSV1_0_S4U_LOGON*)logon_info;
|
||||
s4u_logon->MessageType = MsV1_0S4ULogon;
|
||||
s4u_logon->Flags = 0;
|
||||
s4u_logon->UserPrincipalName.Length = (USHORT)wcslen(user_cpn) * 2;
|
||||
s4u_logon->UserPrincipalName.MaximumLength = s4u_logon->UserPrincipalName.Length;
|
||||
s4u_logon->UserPrincipalName.Buffer = (WCHAR*)(s4u_logon + 1);
|
||||
if(memcpy_s(s4u_logon->UserPrincipalName.Buffer, s4u_logon->UserPrincipalName.Length + 2, user_cpn, s4u_logon->UserPrincipalName.Length + 2))
|
||||
goto done;
|
||||
s4u_logon->DomainName.Length = 2;
|
||||
s4u_logon->DomainName.MaximumLength = 2;
|
||||
s4u_logon->DomainName.Buffer = ((WCHAR*)s4u_logon->UserPrincipalName.Buffer) + wcslen(user_cpn) + 1;
|
||||
if(memcpy_s(s4u_logon->DomainName.Buffer, 4, L".", 4))
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(memcpy_s(sourceContext.SourceName, TOKEN_SOURCE_LENGTH, "sshd", sizeof(sourceContext.SourceName)))
|
||||
goto done;
|
||||
|
||||
if (AllocateLocallyUniqueId(&sourceContext.SourceIdentifier) != TRUE)
|
||||
goto done;
|
||||
|
||||
if (ret = LsaLogonUser(lsa_handle,
|
||||
&originName,
|
||||
Network,
|
||||
auth_package_id,
|
||||
logon_info,
|
||||
(ULONG)logon_info_size,
|
||||
NULL,
|
||||
&sourceContext,
|
||||
(PVOID*)&pProfile,
|
||||
&cbProfile,
|
||||
&logonId,
|
||||
&token,
|
||||
"as,
|
||||
&subStatus) != STATUS_SUCCESS) {
|
||||
debug("LsaLogonUser failed NTSTATUS: %d", ret);
|
||||
goto done;
|
||||
}
|
||||
debug3("LsaLogonUser succeeded");
|
||||
done:
|
||||
if (lsa_handle)
|
||||
LsaDeregisterLogonProcess(lsa_handle);
|
||||
if (logon_info)
|
||||
free(logon_info);
|
||||
if (pProfile)
|
||||
LsaFreeReturnBuffer(pProfile);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
process_custom_lsa_auth(char* user, const char* pwd, char* lsa_pkg)
|
||||
{
|
||||
wchar_t *userw = NULL, *pwdw = NULL, *domw = NULL, *tmp, *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;
|
||||
LSA_STRING logon_process_name, lsa_auth_package_name, originName;
|
||||
TOKEN_SOURCE sourceContext;
|
||||
PVOID pProfile = NULL;
|
||||
LUID logonId;
|
||||
QUOTA_LIMITS quotas;
|
||||
DWORD cbProfile;
|
||||
int retVal = -1;
|
||||
|
||||
debug("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;
|
||||
}
|
||||
|
||||
/* split user and domain */
|
||||
if ((tmp = wcschr(userw, L'@')) != NULL) {
|
||||
domw = tmp + 1;
|
||||
*tmp = L'\0';
|
||||
}
|
||||
|
||||
/* call into LSA provider , get and duplicate token */
|
||||
InitLsaString(&logon_process_name, "sshd");
|
||||
InitLsaString(&lsa_auth_package_name, lsa_pkg);
|
||||
InitLsaString(&originName, "sshd");
|
||||
|
||||
if ((ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode)) != STATUS_SUCCESS) {
|
||||
error("LsaRegisterLogonProcess failed, error:%x", ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ret = LsaLookupAuthenticationPackage(lsa_handle, &lsa_auth_package_name, &auth_package_id)) != STATUS_SUCCESS) {
|
||||
error("LsaLookupAuthenticationPackage failed, lsa auth pkg:%ls error:%x", lsa_pkg, ret);
|
||||
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,
|
||||
NULL,
|
||||
&sourceContext,
|
||||
&pProfile,
|
||||
&cbProfile,
|
||||
&logonId,
|
||||
&token,
|
||||
"as,
|
||||
&subStatus)) != STATUS_SUCCESS) {
|
||||
if(ret == STATUS_ACCOUNT_RESTRICTION)
|
||||
error("LsaLogonUser failed, error:%x subStatus:%ld", ret, subStatus);
|
||||
else
|
||||
error("LsaLogonUser failed error:%x", ret);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
get_user_token(char* user) {
|
||||
HANDLE token = NULL;
|
||||
wchar_t *user_utf16 = NULL;
|
||||
|
||||
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
|
||||
debug("out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((token = generate_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) {
|
||||
error("unable to generate token on 2nd attempt for user %ls", user_utf16);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (user_utf16)
|
||||
free(user_utf16);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
int load_user_profile(HANDLE user_token, char* user) {
|
||||
int r = 0;
|
||||
HANDLE profile_handle = NULL;
|
||||
wchar_t *user_utf16 = NULL, *dom_utf16 = NULL, *tmp;
|
||||
|
||||
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
|
||||
debug("out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* split user and domain */
|
||||
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
|
||||
dom_utf16 = tmp + 1;
|
||||
*tmp = L'\0';
|
||||
}
|
||||
|
||||
if ((profile_handle = LoadProfile(user_token, user_utf16, dom_utf16)) == NULL)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (user_utf16)
|
||||
free(user_utf16);
|
||||
return r;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
@ -34,12 +34,12 @@
|
||||
#define __STDC__ 1
|
||||
#include <Windows.h>
|
||||
#include <wchar.h>
|
||||
#include <Lm.h>
|
||||
#include "inc\utf.h"
|
||||
#include "misc_internal.h"
|
||||
|
||||
int main(int, char **);
|
||||
extern HANDLE main_thread;
|
||||
extern int is_child;
|
||||
|
||||
int scm_start_service(DWORD, LPWSTR*);
|
||||
|
||||
@ -97,6 +97,60 @@ static VOID WINAPI service_handler(DWORD dwControl)
|
||||
ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0);
|
||||
}
|
||||
|
||||
#define SSH_HOSTKEY_GEN_CMDLINE L"ssh-keygen -A"
|
||||
static void
|
||||
prereq_setup()
|
||||
{
|
||||
TOKEN_USER* info = NULL;
|
||||
DWORD info_len = 0, dwError = 0;
|
||||
HANDLE proc_token = NULL;
|
||||
UUID uuid;
|
||||
RPC_CWSTR rpc_str;
|
||||
USER_INFO_1 ui;
|
||||
NET_API_STATUS nStatus;
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
wchar_t cmdline[MAX_PATH];
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &proc_token) == FALSE ||
|
||||
GetTokenInformation(proc_token, TokenUser, NULL, 0, &info_len) == TRUE ||
|
||||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
||||
GetTokenInformation(proc_token, TokenUser, info, info_len, &info_len) == FALSE)
|
||||
goto cleanup;
|
||||
|
||||
if (IsWellKnownSid(info->User.Sid, WinLocalSystemSid)) {
|
||||
/* create sshd account if it does not exist */
|
||||
UuidCreate(&uuid);
|
||||
UuidToStringW(&uuid, (RPC_WSTR*)&rpc_str);
|
||||
ui.usri1_name = L"sshd";
|
||||
ui.usri1_password = (LPWSTR)rpc_str;
|
||||
ui.usri1_priv = USER_PRIV_USER;
|
||||
ui.usri1_home_dir = NULL;
|
||||
ui.usri1_comment = NULL;
|
||||
ui.usri1_flags = UF_SCRIPT;
|
||||
ui.usri1_script_path = NULL;
|
||||
|
||||
NetUserAdd(NULL, 1, (LPBYTE)&ui, &dwError);
|
||||
RpcStringFreeW((RPC_WSTR*)&rpc_str);
|
||||
|
||||
/* create host keys if they dont already exist */
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
memcpy(cmdline, SSH_HOSTKEY_GEN_CMDLINE, wcslen(SSH_HOSTKEY_GEN_CMDLINE) * 2 + 2);
|
||||
if (CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
if (proc_token)
|
||||
CloseHandle(proc_token);
|
||||
if (info)
|
||||
free(info);
|
||||
}
|
||||
|
||||
int sshd_main(int argc, wchar_t **wargv) {
|
||||
char** argv = NULL;
|
||||
int i, r;
|
||||
@ -110,20 +164,26 @@ int sshd_main(int argc, wchar_t **wargv) {
|
||||
}
|
||||
|
||||
w32posix_initialize();
|
||||
if (getenv("SSHD_REMSOC"))
|
||||
is_child = 1;
|
||||
|
||||
/* change current directory to sshd.exe root */
|
||||
wchar_t* path_utf16 = utf8_to_utf16(w32_programdir());
|
||||
_wchdir(path_utf16);
|
||||
free(path_utf16);
|
||||
|
||||
r = main(argc, argv);
|
||||
w32posix_done();
|
||||
return r;
|
||||
}
|
||||
|
||||
int argc_original = 0;
|
||||
wchar_t **wargv_original = NULL;
|
||||
|
||||
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;
|
||||
_wchdir(path_utf16);
|
||||
free(path_utf16);
|
||||
|
||||
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
|
||||
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
|
||||
return sshd_main(argc, wargv); /* sshd running NOT as service*/
|
||||
@ -139,8 +199,9 @@ int scm_start_service(DWORD num, LPWSTR* args) {
|
||||
ZeroMemory(&service_status, sizeof(service_status));
|
||||
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300);
|
||||
prereq_setup();
|
||||
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||
return sshd_main(num, args);
|
||||
return sshd_main(argc_original, wargv_original);
|
||||
}
|
||||
|
||||
|
||||
|
5
misc.c
5
misc.c
@ -1126,10 +1126,6 @@ tun_open(int tun, int mode, char **ifname)
|
||||
void
|
||||
sanitise_stdfd(void)
|
||||
{
|
||||
#ifdef WINDOWS
|
||||
/* nothing to do for Windows*/
|
||||
return;
|
||||
#else /* !WINDOWS */
|
||||
int nullfd, dupfd;
|
||||
|
||||
if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
|
||||
@ -1148,7 +1144,6 @@ sanitise_stdfd(void)
|
||||
}
|
||||
if (nullfd > STDERR_FILENO)
|
||||
close(nullfd);
|
||||
#endif /* !WINDOWS */
|
||||
}
|
||||
|
||||
char *
|
||||
|
37
monitor.c
37
monitor.c
@ -1585,6 +1585,43 @@ mm_answer_audit_command(int socket, Buffer *m)
|
||||
}
|
||||
#endif /* SSH_AUDIT_EVENTS */
|
||||
|
||||
void
|
||||
monitor_send_keystate(struct monitor *pmonitor) {
|
||||
struct sshbuf *m;
|
||||
int r;
|
||||
|
||||
if ((m = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if ((r = sshbuf_put_stringb(m, child_state)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
|
||||
if (ssh_msg_send(pmonitor->m_sendfd, 0, m) == -1)
|
||||
fatal("%s: ssh_msg_send failed", __func__);
|
||||
|
||||
sshbuf_free(m);
|
||||
}
|
||||
|
||||
void
|
||||
monitor_recv_keystate(struct monitor*pmonitor) {
|
||||
Buffer m;
|
||||
char *cp;
|
||||
u_int len;
|
||||
|
||||
buffer_init(&m);
|
||||
|
||||
if (ssh_msg_recv(pmonitor->m_recvfd, &m) == -1)
|
||||
fatal("%s: ssh_msg_recv failed", __func__);
|
||||
if (buffer_get_char(&m) != 0)
|
||||
fatal("%s: recv_keystate version mismatch", __func__);
|
||||
|
||||
cp = buffer_get_string(&m, &len);
|
||||
child_state = sshbuf_new();
|
||||
buffer_append(child_state, cp, len);
|
||||
free(cp);
|
||||
buffer_free(&m);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
monitor_clear_keystate(struct monitor *pmonitor)
|
||||
{
|
||||
|
@ -98,9 +98,4 @@ int mm_bsdauth_respond(void *, u_int, char **);
|
||||
int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
|
||||
int mm_skey_respond(void *, u_int, char **);
|
||||
|
||||
/* Windows specific */
|
||||
void* mm_auth_pubkey(const char*, const struct sshkey *, const u_char *, size_t,
|
||||
struct sshbuf*);
|
||||
int mm_load_profile(const char*, u_int );
|
||||
|
||||
#endif /* _MM_WRAP_H_ */
|
||||
|
34
readpass.c
34
readpass.c
@ -66,14 +66,33 @@ ssh_askpass(char *askpass, const char *msg)
|
||||
return NULL;
|
||||
}
|
||||
osigchld = signal(SIGCHLD, SIG_DFL);
|
||||
#ifdef WINDOWS
|
||||
/* spawd child for Windows */
|
||||
fcntl(p[0], F_SETFD, FD_CLOEXEC);
|
||||
pid = spawn_child(askpass, NULL, p[1], p[1], STDERR_FILENO, 0);
|
||||
if (pid < 0) {
|
||||
#else /* !WINDOWS */
|
||||
if ((pid = fork()) < 0) {
|
||||
#endif /* !WINDOWS */
|
||||
fcntl(p[1], F_SETFD, FD_CLOEXEC);
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
{
|
||||
posix_spawn_file_actions_t actions;
|
||||
pid = -1;
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, p[1], STDOUT_FILENO) != 0 ) {
|
||||
error("posix_spawn initialization failed");
|
||||
signal(SIGCHLD, osigchld);
|
||||
return NULL;
|
||||
} else {
|
||||
char* spawn_argv[2];
|
||||
spawn_argv[0] = askpass;
|
||||
spawn_argv[1] = NULL;
|
||||
if (posix_spawn(&pid, spawn_argv[0], &actions, NULL, spawn_argv, NULL) != 0) {
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
error("ssh_askpass: posix_spawn: %s", strerror(errno));
|
||||
signal(SIGCHLD, osigchld);
|
||||
return NULL;
|
||||
}
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
if ((pid = fork()) < 0) {
|
||||
error("ssh_askpass: fork: %s", strerror(errno));
|
||||
signal(SIGCHLD, osigchld);
|
||||
return NULL;
|
||||
@ -86,6 +105,7 @@ ssh_askpass(char *askpass, const char *msg)
|
||||
execlp(askpass, askpass, msg, (char *)NULL);
|
||||
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
close(p[1]);
|
||||
|
||||
len = 0;
|
||||
|
@ -32,6 +32,27 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
#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++ }
|
||||
@ -91,12 +112,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owners $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
|
||||
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$o | Should Be "1234"
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by local system)" {
|
||||
@ -104,12 +124,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $systemSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
|
||||
|
||||
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$o | Should Be "1234"
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd does not have explict ACE)" {
|
||||
@ -117,12 +137,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
|
||||
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$o | Should Be "1234"
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd have explict ACE)" {
|
||||
@ -130,12 +149,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
Start-SSHD-TestDaemon -Arguments "-d -p $port -o `"AuthorizedKeysFile .testssh/authorized_keys`" -E $logPath"
|
||||
$o = ssh -p $port $ssouser@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$o | Should Be "1234"
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other admin user)" {
|
||||
@ -143,14 +161,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $currentUserSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
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
|
||||
$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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "Authentication refused."
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-negative(other account can access private key file)" {
|
||||
@ -162,14 +177,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Set-FilePermission -FilePath $authorizedkeyPath -User $objPwdUserSid -Perm "Read"
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
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
|
||||
$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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "Authentication refused."
|
||||
}
|
||||
|
||||
It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other non-admin user)" {
|
||||
@ -178,30 +190,11 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objPwdUserSid -FullAccessNeeded $adminsSid,$systemSid,$objPwdUser -confirm:$false
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
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
|
||||
$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-authorized_keys-negative(the running process does not have read access to the authorized_keys)" -skip:$skip {
|
||||
#setup to have ssouser as owner and grant it full control
|
||||
Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objUserSid -FullAccessNeeded $systemSid,$objUserSid -confirm:$false
|
||||
Set-FilePermission -Filepath $authorizedkeyPath -UserSid $adminsSid -Action Delete
|
||||
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
|
||||
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $ssouser@$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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "Authentication refused."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,32 +171,17 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
|
||||
# Executing ssh-agent will start agent service
|
||||
# This is to support typical Unix scenarios where
|
||||
# running ssh-agent will setup the agent for current session
|
||||
It "$tC.$tI - ssh-agent starts agent service and sshd depends on ssh-agent" {
|
||||
It "$tC.$tI - ssh-agent starts agent service" {
|
||||
if ((Get-Service ssh-agent).Status -eq "Running") {
|
||||
Stop-Service ssh-agent -Force
|
||||
}
|
||||
|
||||
(Get-Service ssh-agent).Status | Should Be "Stopped"
|
||||
(Get-Service sshd).Status | Should Be "Stopped"
|
||||
|
||||
ssh-agent
|
||||
WaitForStatus -ServiceName ssh-agent -Status "Running"
|
||||
|
||||
(Get-Service ssh-agent).Status | Should Be "Running"
|
||||
|
||||
Stop-Service ssh-agent -Force
|
||||
|
||||
WaitForStatus -ServiceName ssh-agent -Status "Stopped"
|
||||
|
||||
(Get-Service ssh-agent).Status | Should Be "Stopped"
|
||||
(Get-Service sshd).Status | Should Be "Stopped"
|
||||
|
||||
# this should automatically start both the services
|
||||
Start-Service sshd
|
||||
|
||||
WaitForStatus -ServiceName sshd -Status "Running"
|
||||
(Get-Service ssh-agent).Status | Should Be "Running"
|
||||
(Get-Service sshd).Status | Should Be "Running"
|
||||
}
|
||||
|
||||
It "$tC.$tI - ssh-add - add and remove all key types" {
|
||||
|
@ -27,6 +27,26 @@ Describe "Tests of sshd_config" -Tags "CI" {
|
||||
$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} }
|
||||
}
|
||||
|
||||
function Add-LocalUser
|
||||
{
|
||||
@ -164,7 +184,6 @@ Describe "Tests of sshd_config" -Tags "CI" {
|
||||
$denyGroup3 = "denygroup3"
|
||||
$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
|
||||
@ -173,7 +192,6 @@ Describe "Tests of sshd_config" -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
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
@ -183,162 +201,146 @@ Describe "Tests of sshd_config" -Tags "CI" {
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
Add-UserToLocalGroup -UserName $allowUser1 -Password $password -GroupName $allowGroup1
|
||||
|
||||
$o = ssh -p $port $allowUser1@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
Add-UserToLocalGroup -UserName $allowUser2 -Password $password -GroupName $allowGroup1
|
||||
|
||||
$o = ssh -p $port $allowUser2@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$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 "$tC.$tI-User with ? wildcard" {
|
||||
#Run
|
||||
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
Add-UserToLocalGroup -UserName $allowUser3 -Password $password -GroupName $allowGroup1
|
||||
|
||||
$o = ssh -p $port $allowUser3@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
|
||||
Stop-SSHD-TestDaemon
|
||||
$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 "$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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because not in any group"
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because listed in DenyUsers"
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because listed in DenyUsers"
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because not listed in AllowUsers"
|
||||
|
||||
Remove-UserFromLocalGroup -UserName $denyUser3 -GroupName $allowGroup1
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
$LASTEXITCODE | Should Not Be 0
|
||||
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
|
||||
$matches.Count | Should BeGreaterThan 2
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because a group is listed in DenyGroups"
|
||||
|
||||
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 "$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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
Add-UserToLocalGroup -UserName $localuser2 -Password $password -GroupName $denyGroup2
|
||||
|
||||
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser2@$server echo 1234
|
||||
$LASTEXITCODE | Should Not Be 0
|
||||
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
|
||||
$matches.Count | Should BeGreaterThan 2
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because a group is listed in DenyGroups"
|
||||
|
||||
Remove-UserFromLocalGroup -UserName $localuser2 -GroupName $denyGroup2
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
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
|
||||
Start-SSHD-TestDaemon -Arguments "-d -f $sshdConfigPath -E $logPath"
|
||||
|
||||
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
|
||||
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
|
||||
$matches.Count | Should BeGreaterThan 2
|
||||
Stop-SSHD-TestDaemon
|
||||
$logPath | Should Contain "not allowed because a group is listed in DenyGroups"
|
||||
|
||||
Remove-UserFromLocalGroup -UserName $localuser3 -GroupName $denyGroup3
|
||||
|
||||
#Cleanup
|
||||
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
#>
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ Port 47002
|
||||
# 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
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_rsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_dsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_ecdsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_ed25519
|
||||
|
||||
# Lifetime and size of ephemeral version 1 server key
|
||||
#KeyRegenerationInterval 1h
|
||||
@ -126,5 +126,4 @@ PubkeyAcceptedKeyTypes ssh-ed25519*
|
||||
#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
|
||||
TrustedUserCAKeys sshtest_ca_userkeys.pub
|
||||
TrustedUserCAKeys __PROGRAMDATA__\ssh\sshtest_ca_userkeys.pub
|
||||
|
9
regress/pesterTests/testdata/SSHD_Config
vendored
9
regress/pesterTests/testdata/SSHD_Config
vendored
@ -11,10 +11,10 @@ Port 47003
|
||||
# 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
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_rsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_dsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_ecdsa
|
||||
HostKey __PROGRAMDATA__\ssh\sshtest_hostkey_ed25519
|
||||
|
||||
# Lifetime and size of ephemeral version 1 server key
|
||||
#KeyRegenerationInterval 1h
|
||||
@ -116,4 +116,3 @@ 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
|
||||
|
@ -460,9 +460,6 @@ file_miscellaneous_tests()
|
||||
h = w32_fd_to_handle(STDERR_FILENO);
|
||||
ASSERT_HANDLE(h);
|
||||
|
||||
retValue = w32_allocate_fd_for_handle(h, FALSE);
|
||||
ASSERT_HANDLE(h);
|
||||
|
||||
f = open(tmp_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
ASSERT_INT_NE(f, -1);
|
||||
wchar_t *t = utf8_to_utf16(tmp_filename);
|
||||
|
@ -67,9 +67,9 @@ test_sanitizedpath()
|
||||
char *win32prgdir = w32_programdir();
|
||||
ASSERT_PTR_NE(win32prgdir, NULL);
|
||||
|
||||
ASSERT_PTR_EQ(sanitized_path(NULL), NULL);
|
||||
ASSERT_PTR_EQ(resolved_path(NULL), NULL);
|
||||
|
||||
char *ret = sanitized_path(win32prgdir);
|
||||
char *ret = resolved_path(win32prgdir);
|
||||
retValue = strcmp(win32prgdir, ret);
|
||||
ASSERT_INT_EQ(retValue, 0);
|
||||
|
||||
@ -79,14 +79,14 @@ test_sanitizedpath()
|
||||
strncpy(tmp_path+1, win32prgdir, win32prgdir_len);
|
||||
tmp_path[win32prgdir_len+1] = '\0';
|
||||
|
||||
ret = sanitized_path(tmp_path);
|
||||
ret = resolved_path(tmp_path);
|
||||
retValue = strcmp(win32prgdir, ret);
|
||||
ASSERT_INT_EQ(retValue, 0);
|
||||
|
||||
char *s1 = malloc(4), *s2 = malloc(4);
|
||||
s1[0] = '/', s1[1] = win32prgdir[0], s1[2] = ':', s1[3] = '\0';
|
||||
s2[0] = win32prgdir[0], s2[1] = ':', s2[2] = '\\', s2[3] = '\0';
|
||||
ret = sanitized_path(s1);
|
||||
ret = resolved_path(s1);
|
||||
retValue = strcmp(ret, s2);
|
||||
ASSERT_INT_EQ(retValue, 0);
|
||||
|
||||
|
55
scp.c
55
scp.c
@ -281,6 +281,10 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
fatal("pipe: %s", strerror(errno));
|
||||
if (pipe(pout) < 0)
|
||||
fatal("pipe: %s", strerror(errno));
|
||||
fcntl(pout[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pout[1], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[1], F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* Free the reserved descriptors. */
|
||||
close(reserved[0]);
|
||||
@ -291,9 +295,12 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
signal(SIGTTOU, suspchild);
|
||||
|
||||
/* Fork a child to execute the command on the remote host using ssh. */
|
||||
#ifdef WINDOWS
|
||||
/* generate command line and spawn_child */
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
if (port != -1) {
|
||||
addargs(&args, "-p");
|
||||
addargs(&args, "%d", port);
|
||||
}
|
||||
if (remuser != NULL) {
|
||||
addargs(&args, "-l");
|
||||
addargs(&args, "%s", remuser);
|
||||
@ -302,14 +309,22 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
|
||||
fcntl(pout[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[1], F_SETFD, FD_CLOEXEC);
|
||||
{
|
||||
posix_spawn_file_actions_t actions;
|
||||
do_cmd_pid = -1;
|
||||
|
||||
do_cmd_pid = spawn_child(args.list[0], args.list + 1, pin[0], pout[1], STDERR_FILENO, 0);
|
||||
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(&do_cmd_pid, args.list[0], &actions, NULL, args.list, NULL) != 0)
|
||||
fatal("posix_spawn: %s", strerror(errno));
|
||||
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
|
||||
#else /* !WINDOWS */
|
||||
#else
|
||||
do_cmd_pid = fork();
|
||||
#endif /* !WINDOWS */
|
||||
if (do_cmd_pid == 0) {
|
||||
/* Child. */
|
||||
close(pin[1]);
|
||||
@ -338,6 +353,7 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
} else if (do_cmd_pid == -1) {
|
||||
fatal("fork: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
/* Parent. Close the other side, and return the local side. */
|
||||
close(pin[0]);
|
||||
*fdout = pin[1];
|
||||
@ -370,9 +386,13 @@ do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
|
||||
port = sshport;
|
||||
|
||||
/* Fork a child to execute the command on the remote host using ssh. */
|
||||
#ifdef WINDOWS
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
/* generate command line and spawn_child */
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
if (port != -1) {
|
||||
addargs(&args, "-p");
|
||||
addargs(&args, "%d", port);
|
||||
}
|
||||
if (remuser != NULL) {
|
||||
addargs(&args, "-l");
|
||||
addargs(&args, "%s", remuser);
|
||||
@ -381,11 +401,21 @@ do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
|
||||
pid = spawn_child(args.list[0], args.list + 1, fdin, fdout, STDERR_FILENO, 0);
|
||||
|
||||
#else /* !WINDOWS */
|
||||
{
|
||||
posix_spawn_file_actions_t actions;
|
||||
pid = -1;
|
||||
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, fdin, STDIN_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, fdout, STDOUT_FILENO) != 0 )
|
||||
fatal("posix_spawn initialization failed");
|
||||
else if (posix_spawn(&pid, args.list[0], &actions, NULL, args.list, NULL) != 0)
|
||||
fatal("posix_spawn: %s", strerror(errno));
|
||||
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
#else
|
||||
pid = fork();
|
||||
#endif /* !WINDOWS */
|
||||
if (pid == 0) {
|
||||
dup2(fdin, 0);
|
||||
dup2(fdout, 1);
|
||||
@ -409,6 +439,7 @@ do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
|
||||
} else if (pid == -1) {
|
||||
fatal("fork: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
while (waitpid(pid, &status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
fatal("do_cmd2: waitpid: %s", strerror(errno));
|
||||
|
@ -660,10 +660,8 @@ derelativise_path(const char *path)
|
||||
if (strcasecmp(path, "none") == 0)
|
||||
return xstrdup("none");
|
||||
expanded = tilde_expand_filename(path, getuid());
|
||||
#ifdef WINDOWS
|
||||
/* Windows absolute paths - \abc, /abc, c:\abc, c:/abc*/
|
||||
if (*expanded == '/' || *expanded == '\\' ||
|
||||
(*expanded != '\0' && expanded[1] == ':'))
|
||||
#ifdef WINDOWS
|
||||
if (is_absolute_path(expanded))
|
||||
#else /* !WINDOWS */
|
||||
if (*expanded == '/')
|
||||
#endif /* !WINDOWS */
|
||||
|
28
session.c
28
session.c
@ -518,9 +518,6 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
*cmd = '\0';
|
||||
}
|
||||
|
||||
/* load user profile */
|
||||
mm_load_profile(s->pw->pw_name, ((INT_PTR)s->authctxt->auth_token) & 0xffffffff);
|
||||
|
||||
/* start the process */
|
||||
{
|
||||
memset(&si, 0, sizeof(STARTUPINFO));
|
||||
@ -536,28 +533,13 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
si.hStdError = (HANDLE)w32_fd_to_handle(pipeerr[1]);
|
||||
si.lpDesktop = NULL;
|
||||
|
||||
hToken = s->authctxt->auth_token;
|
||||
|
||||
debug("Executing command: %s", exec_command);
|
||||
UTF8_TO_UTF16_FATAL(exec_command_w, exec_command);
|
||||
|
||||
_putenv_s("SSH_ASYNC_STDIN", "1");
|
||||
_putenv_s("SSH_ASYNC_STDOUT", "1");
|
||||
_putenv_s("SSH_ASYNC_STDERR", "1");
|
||||
|
||||
/* in debug mode launch using sshd.exe user context */
|
||||
if (debug_flag)
|
||||
create_process_ret_val = CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE,
|
||||
DETACHED_PROCESS, NULL, pw_dir_w,
|
||||
&si, &pi);
|
||||
else /* launch as client user context */
|
||||
create_process_ret_val = CreateProcessAsUserW(hToken, NULL, exec_command_w, NULL, NULL, TRUE,
|
||||
DETACHED_PROCESS , NULL, pw_dir_w,
|
||||
&si, &pi);
|
||||
|
||||
_putenv_s("SSH_ASYNC_STDIN", "");
|
||||
_putenv_s("SSH_ASYNC_STDOUT", "");
|
||||
_putenv_s("SSH_ASYNC_STDERR", "");
|
||||
create_process_ret_val = CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE,
|
||||
DETACHED_PROCESS, NULL, pw_dir_w,
|
||||
&si, &pi);
|
||||
|
||||
if (!create_process_ret_val)
|
||||
fatal("ERROR. Cannot create process (%u).\n", GetLastError());
|
||||
@ -2162,7 +2144,11 @@ session_pty_req(struct ssh *ssh, Session *s)
|
||||
|
||||
/* Allocate a pty and open it. */
|
||||
debug("Allocating pty.");
|
||||
#ifdef WINDOWS
|
||||
if (!(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
|
||||
#else
|
||||
if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
|
||||
#endif
|
||||
sizeof(s->tty)))) {
|
||||
free(s->term);
|
||||
s->term = NULL;
|
||||
|
32
sftp.c
32
sftp.c
@ -2309,6 +2309,10 @@ connect_to_server(char *path, char **args, int *in, int *out)
|
||||
*out = pout[1];
|
||||
c_in = pout[0];
|
||||
c_out = pin[1];
|
||||
fcntl(pout[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pout[1], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[1], F_SETFD, FD_CLOEXEC);
|
||||
#else /* USE_PIPES */
|
||||
int inout[2];
|
||||
|
||||
@ -2316,19 +2320,27 @@ connect_to_server(char *path, char **args, int *in, int *out)
|
||||
fatal("socketpair: %s", strerror(errno));
|
||||
*in = *out = inout[0];
|
||||
c_in = c_out = inout[1];
|
||||
fcntl(inout[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(inout[1], F_SETFD, FD_CLOEXEC);
|
||||
#endif /* USE_PIPES */
|
||||
|
||||
#ifdef WINDOWS
|
||||
/* fork replacement on Windows */
|
||||
/* disable inheritance on local pipe ends*/
|
||||
fcntl(pout[1], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(pin[0], F_SETFD, FD_CLOEXEC);
|
||||
|
||||
sshpid = spawn_child(path, args + 1, c_in, c_out, STDERR_FILENO, 0);
|
||||
if (sshpid == -1)
|
||||
#else /* !WINDOWS */
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
{
|
||||
posix_spawn_file_actions_t actions;
|
||||
sshpid = -1;
|
||||
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, c_in, STDIN_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, c_out, STDOUT_FILENO) != 0 )
|
||||
fatal("posix_spawn initialization failed");
|
||||
else if (posix_spawn(&sshpid, path, &actions, NULL, args, NULL) != 0)
|
||||
fatal("posix_spawn: %s", strerror(errno));
|
||||
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
#else
|
||||
if ((sshpid = fork()) == -1)
|
||||
#endif /* !WINDOWS */
|
||||
fatal("fork: %s", strerror(errno));
|
||||
else if (sshpid == 0) {
|
||||
if ((dup2(c_in, STDIN_FILENO) == -1) ||
|
||||
@ -2354,7 +2366,7 @@ connect_to_server(char *path, char **args, int *in, int *out)
|
||||
fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
signal(SIGTERM, killchild);
|
||||
signal(SIGINT, killchild);
|
||||
signal(SIGHUP, killchild);
|
||||
|
458
sshd.c
458
sshd.c
@ -128,6 +128,12 @@
|
||||
#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3)
|
||||
#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4)
|
||||
|
||||
/* Privilege separation related spawn fds */
|
||||
#define PRIVSEP_MONITOR_FD (STDERR_FILENO + 1)
|
||||
#define PRIVSEP_LOG_FD (STDERR_FILENO + 2)
|
||||
#define PRIVSEP_UNAUTH_MIN_FREE_FD (PRIVSEP_LOG_FD + 1)
|
||||
#define PRIVSEP_AUTH_MIN_FREE_FD (PRIVSEP_MONITOR_FD + 1)
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
/* Server configuration options. */
|
||||
@ -167,12 +173,7 @@ int saved_argc;
|
||||
|
||||
/* re-exec */
|
||||
int rexeced_flag = 0;
|
||||
#ifdef WINDOWS
|
||||
/* rexec is not applicable in Windows */
|
||||
int rexec_flag = 0;
|
||||
#else /* !WINDOWS */
|
||||
int rexec_flag = 1;
|
||||
#endif /* !WINDOWS */
|
||||
int rexec_argc = 0;
|
||||
char **rexec_argv;
|
||||
|
||||
@ -195,6 +196,10 @@ char *server_version_string = NULL;
|
||||
int auth_sock = -1;
|
||||
int have_agent = 0;
|
||||
|
||||
int privsep_unauth_child = 0;
|
||||
int privsep_auth_child = 0;
|
||||
int tmp_sock = 0;
|
||||
|
||||
/*
|
||||
* Any really sensitive data in the application is contained in this
|
||||
* structure. The idea is that this structure could be locked into memory so
|
||||
@ -229,20 +234,10 @@ int *startup_pipes = NULL;
|
||||
int startup_pipe; /* in child */
|
||||
|
||||
/* variables used for privilege separation */
|
||||
#ifdef WINDOWS
|
||||
/* Windows does not use Unix privilege separation model */
|
||||
int use_prevsep = 0;
|
||||
#else
|
||||
int use_privsep = -1;
|
||||
#endif
|
||||
struct monitor *pmonitor = NULL;
|
||||
int privsep_is_preauth = 1;
|
||||
#ifdef WINDOWS
|
||||
/* Windows does not use Unix privilege separation model */
|
||||
static int privsep_chroot = 0;
|
||||
#else
|
||||
static int privsep_chroot = 1;
|
||||
#endif
|
||||
|
||||
/* global authentication context */
|
||||
Authctxt *the_authctxt = NULL;
|
||||
@ -256,9 +251,6 @@ Buffer loginmsg;
|
||||
/* Unprivileged user */
|
||||
struct passwd *privsep_pw = NULL;
|
||||
|
||||
/* is child process - used by Windows implementation*/
|
||||
int is_child = 0;
|
||||
|
||||
/* Prototypes for various functions defined later in this file. */
|
||||
void destroy_sensitive_data(void);
|
||||
void demote_sensitive_data(void);
|
||||
@ -542,29 +534,6 @@ reseed_prngs(void)
|
||||
explicit_bzero(rnd, sizeof(rnd));
|
||||
}
|
||||
|
||||
#ifdef WINDOWS
|
||||
/*
|
||||
* No-OP defs for preauth routines for Windows
|
||||
* these should go away once the privilege separation
|
||||
* related code is refactored to be invoked only when applicable
|
||||
*/
|
||||
static void
|
||||
privsep_preauth_child(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
privsep_preauth(Authctxt *authctxt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
privsep_postauth(Authctxt *authctxt) {
|
||||
return;
|
||||
}
|
||||
|
||||
#else /* !WINDOWS */
|
||||
/* Unix privilege separation routines */
|
||||
static void
|
||||
privsep_preauth_child(void)
|
||||
{
|
||||
@ -603,6 +572,162 @@ privsep_preauth_child(void)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
send_rexec_state(int, struct sshbuf *);
|
||||
static void send_config_state(int fd, struct sshbuf *conf)
|
||||
{
|
||||
send_rexec_state(fd, conf);
|
||||
}
|
||||
|
||||
void
|
||||
recv_rexec_state(int, Buffer *);
|
||||
static void recv_config_state(int fd, Buffer *conf)
|
||||
{
|
||||
recv_rexec_state(fd, conf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
send_idexch_state(int fd)
|
||||
{
|
||||
struct sshbuf *m;
|
||||
|
||||
if ((m = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if (sshbuf_put_cstring(m, client_version_string) != 0 ||
|
||||
sshbuf_put_cstring(m, server_version_string) != 0)
|
||||
fatal("%s: buffer error", __func__);
|
||||
|
||||
if (ssh_msg_send(fd, 0, m) == -1)
|
||||
fatal("%s: ssh_msg_send failed", __func__);
|
||||
|
||||
sshbuf_free(m);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_idexch_state(int fd)
|
||||
{
|
||||
Buffer m;
|
||||
char *cp;
|
||||
size_t tmp;
|
||||
|
||||
buffer_init(&m);
|
||||
|
||||
if (ssh_msg_recv(fd, &m) == -1)
|
||||
fatal("%s: ssh_msg_recv failed", __func__);
|
||||
|
||||
if (buffer_get_char(&m) != 0)
|
||||
fatal("%s: recv_idexch_state version mismatch", __func__);
|
||||
|
||||
if (sshbuf_get_cstring(&m, &client_version_string, &tmp) != 0 ||
|
||||
sshbuf_get_cstring(&m, &server_version_string, &tmp) != 0 )
|
||||
fatal("%s: unable to retrieve idexch state", __func__);
|
||||
|
||||
buffer_free(&m);
|
||||
}
|
||||
|
||||
static void
|
||||
send_hostkeys_state(int fd)
|
||||
{
|
||||
struct sshbuf *m;
|
||||
int i;
|
||||
u_char *blob = NULL;
|
||||
size_t blen = 0;
|
||||
|
||||
if ((m = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
|
||||
sshbuf_put_u32(m, options.num_host_key_files);
|
||||
for (i = 0; i < options.num_host_key_files; i++) {
|
||||
if (blob) {
|
||||
free(blob);
|
||||
blob = NULL;
|
||||
}
|
||||
if (sensitive_data.host_pubkeys[i]) {
|
||||
sshkey_to_blob(sensitive_data.host_pubkeys[i], &blob, &blen);
|
||||
sshbuf_put_string(m, blob, blen);
|
||||
}
|
||||
else
|
||||
sshbuf_put_string(m, NULL, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < options.num_host_key_files; i++) {
|
||||
if (blob) {
|
||||
free(blob);
|
||||
blob = NULL;
|
||||
}
|
||||
if (sensitive_data.host_certificates[i]) {
|
||||
sshkey_to_blob(sensitive_data.host_certificates[i], &blob, &blen);
|
||||
sshbuf_put_string(m, blob, blen);
|
||||
}
|
||||
else
|
||||
sshbuf_put_string(m, NULL, 0);
|
||||
}
|
||||
|
||||
if (ssh_msg_send(fd, 0, m) == -1)
|
||||
fatal("%s: ssh_msg_send failed", __func__);
|
||||
|
||||
if (blob)
|
||||
free(blob);
|
||||
sshbuf_free(m);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_hostkeys_state(int fd)
|
||||
{
|
||||
Buffer b, *m = &b;
|
||||
char *cp;
|
||||
struct sshkey *key = NULL;
|
||||
const char *blob;
|
||||
int blen;
|
||||
|
||||
buffer_init(m);
|
||||
|
||||
if (ssh_msg_recv(fd, m) == -1)
|
||||
fatal("%s: ssh_msg_recv failed", __func__);
|
||||
|
||||
if (buffer_get_char(m) != 0)
|
||||
fatal("%s: recv_hostkeys_state version mismatch", __func__);
|
||||
|
||||
int num = buffer_get_int(m);
|
||||
sensitive_data.host_keys = xcalloc(num, sizeof(struct sshkey *));
|
||||
sensitive_data.host_pubkeys = xcalloc(num, sizeof(struct sshkey *));
|
||||
sensitive_data.host_certificates = xcalloc(num, sizeof(struct sshkey *));
|
||||
for (int i = 0; i < num; i++) {
|
||||
blob = buffer_get_string_ptr(m, &blen);
|
||||
sensitive_data.host_pubkeys[i] = NULL;
|
||||
sensitive_data.host_keys[i] = NULL;
|
||||
|
||||
if (blen) {
|
||||
sshkey_from_blob(blob, blen, &key);
|
||||
sensitive_data.host_pubkeys[i] = key;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
blob = buffer_get_string_ptr(m, &blen);
|
||||
sensitive_data.host_certificates[i] = NULL;
|
||||
if (blen) {
|
||||
sshkey_from_blob(blob, blen, &key);
|
||||
sensitive_data.host_certificates[i] = key;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_free(m);
|
||||
}
|
||||
|
||||
static char**
|
||||
privsep_child_cmdline(int authenticated)
|
||||
{
|
||||
char** argv = rexec_argv ? rexec_argv : saved_argv;
|
||||
int argc = rexec_argv ? rexec_argc : saved_argc - 1;
|
||||
if (authenticated)
|
||||
argv[argc] = "-z";
|
||||
else
|
||||
argv[argc] = "-y";
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
static int
|
||||
privsep_preauth(Authctxt *authctxt)
|
||||
{
|
||||
@ -615,6 +740,60 @@ privsep_preauth(Authctxt *authctxt)
|
||||
/* Store a pointer to the kex for later rekeying */
|
||||
pmonitor->m_pkex = &active_state->kex;
|
||||
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
if (privsep_auth_child) {
|
||||
authctxt->pw = w32_getpwuid(1);
|
||||
authctxt->valid = 1;
|
||||
return 1;
|
||||
}
|
||||
else if (privsep_unauth_child) {
|
||||
close(pmonitor->m_sendfd);
|
||||
close(pmonitor->m_log_recvfd);
|
||||
close(pmonitor->m_recvfd);
|
||||
close(pmonitor->m_log_sendfd);
|
||||
|
||||
pmonitor->m_recvfd = PRIVSEP_MONITOR_FD;
|
||||
pmonitor->m_log_sendfd = PRIVSEP_LOG_FD;
|
||||
|
||||
/* Arrange for logging to be sent to the monitor */
|
||||
set_log_handler(mm_log_handler, pmonitor);
|
||||
|
||||
privsep_preauth_child();
|
||||
setproctitle("%s", "[net]");
|
||||
return 0;
|
||||
}
|
||||
else { /* parent */
|
||||
posix_spawn_file_actions_t actions;
|
||||
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, tmp_sock, STDIN_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, tmp_sock, STDOUT_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, pmonitor->m_recvfd, PRIVSEP_MONITOR_FD) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, pmonitor->m_log_sendfd, PRIVSEP_LOG_FD) != 0 )
|
||||
error("posix_spawn initialization failed");
|
||||
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");
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
close(pmonitor->m_recvfd);
|
||||
close(pmonitor->m_log_sendfd);
|
||||
send_config_state(pmonitor->m_sendfd, &cfg);
|
||||
send_hostkeys_state(pmonitor->m_sendfd);
|
||||
send_idexch_state(pmonitor->m_sendfd);
|
||||
monitor_child_preauth(authctxt, pmonitor);
|
||||
while (waitpid(pid, &status, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
pmonitor->m_pid = -1;
|
||||
fatal("%s: waitpid: %s", __func__, strerror(errno));
|
||||
}
|
||||
privsep_is_preauth = 0;
|
||||
pmonitor->m_pid = -1;
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
if (use_privsep == PRIVSEP_ON)
|
||||
box = ssh_sandbox_init(pmonitor);
|
||||
pid = fork();
|
||||
@ -670,6 +849,7 @@ privsep_preauth(Authctxt *authctxt)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -688,6 +868,44 @@ privsep_postauth(Authctxt *authctxt)
|
||||
/* New socket pair */
|
||||
monitor_reinit(pmonitor);
|
||||
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
if (!privsep_auth_child) { /* parent */
|
||||
posix_spawn_file_actions_t actions;
|
||||
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, tmp_sock, STDIN_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, tmp_sock, STDOUT_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, pmonitor->m_recvfd, PRIVSEP_MONITOR_FD) != 0)
|
||||
error("posix_spawn initialization failed");
|
||||
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");
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
}
|
||||
|
||||
send_config_state(pmonitor->m_sendfd, &cfg);
|
||||
send_hostkeys_state(pmonitor->m_sendfd);
|
||||
send_idexch_state(pmonitor->m_sendfd);
|
||||
monitor_send_keystate(pmonitor);
|
||||
monitor_clear_keystate(pmonitor);
|
||||
monitor_child_postauth(pmonitor);
|
||||
/* NEVERREACHED */
|
||||
exit(0);
|
||||
}
|
||||
/* child */
|
||||
close(pmonitor->m_sendfd);
|
||||
close(pmonitor->m_recvfd);
|
||||
|
||||
pmonitor->m_recvfd = PRIVSEP_MONITOR_FD;
|
||||
|
||||
monitor_recv_keystate(pmonitor);
|
||||
monitor_apply_keystate(pmonitor);
|
||||
packet_set_authenticated();
|
||||
skip:
|
||||
return;
|
||||
|
||||
#else
|
||||
pmonitor->m_pid = fork();
|
||||
if (pmonitor->m_pid == -1)
|
||||
fatal("fork of unprivileged child failed");
|
||||
@ -723,10 +941,9 @@ privsep_postauth(Authctxt *authctxt)
|
||||
* this information is not part of the key state.
|
||||
*/
|
||||
packet_set_authenticated();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
static char *
|
||||
list_hostkey_types(void)
|
||||
{
|
||||
@ -1272,6 +1489,11 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
|
||||
close(startup_p[1]);
|
||||
continue;
|
||||
}
|
||||
fcntl(startup_p[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(startup_p[1], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(config_s[0], F_SETFD, FD_CLOEXEC);
|
||||
fcntl(config_s[1], F_SETFD, FD_CLOEXEC);
|
||||
|
||||
|
||||
for (j = 0; j < options.max_startups; j++)
|
||||
if (startup_pipes[j] == -1) {
|
||||
@ -1308,52 +1530,34 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
{
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawnattr_t attributes;
|
||||
if (posix_spawn_file_actions_init(&actions) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, *newsock, STDIN_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, *newsock, STDOUT_FILENO) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, startup_p[1], REEXEC_STARTUP_PIPE_FD) != 0 ||
|
||||
posix_spawn_file_actions_adddup2(&actions, config_s[1], REEXEC_CONFIG_PASS_FD) != 0 ||
|
||||
posix_spawnattr_init(&attributes) != 0 ||
|
||||
posix_spawnattr_setflags(&attributes, POSIX_SPAWN_SETPGROUP) != 0 ||
|
||||
posix_spawnattr_setpgroup(&attributes, 0) != 0)
|
||||
error("posix_spawn initialization failed");
|
||||
else {
|
||||
if (posix_spawn(&pid, rexec_argv[0], &actions, &attributes, rexec_argv, NULL) != 0)
|
||||
error("posix_spawn failed");
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
posix_spawnattr_destroy(&attributes);
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Normal production daemon. Fork, and have
|
||||
* the child process the connection. The
|
||||
* parent continues listening.
|
||||
*/
|
||||
platform_pre_fork();
|
||||
#ifdef WINDOWS
|
||||
/*
|
||||
* fork() repleacement for Windows -
|
||||
* - Put accepted socket in a env varaibale
|
||||
* - disable inheritance on listening socket and startup fds
|
||||
* - Spawn child sshd.exe
|
||||
*/
|
||||
{
|
||||
char* path_utf8 = utf16_to_utf8(GetCommandLineW());
|
||||
/* large enough to hold pointer value in hex */
|
||||
char fd_handle[30];
|
||||
|
||||
if (path_utf8 == NULL)
|
||||
fatal("Failed to alloc memory");
|
||||
|
||||
if (snprintf(fd_handle, sizeof(fd_handle), "%p",
|
||||
w32_fd_to_handle(*newsock)) == -1
|
||||
|| SetEnvironmentVariable("SSHD_REMSOC", fd_handle) == FALSE
|
||||
|| snprintf(fd_handle, sizeof(fd_handle), "%p",
|
||||
w32_fd_to_handle(startup_p[1])) == -1
|
||||
|| SetEnvironmentVariable("SSHD_STARTUPSOC", fd_handle) == FALSE
|
||||
|| fcntl(startup_p[0], F_SETFD, FD_CLOEXEC) == -1) {
|
||||
error("unable to set environment for child");
|
||||
close(*newsock);
|
||||
/*
|
||||
* close child end of startup pipe. parent end will
|
||||
* automatically be cleaned up on next iteration
|
||||
*/
|
||||
close(startup_p[1]);
|
||||
free(path_utf8);
|
||||
continue;
|
||||
}
|
||||
|
||||
pid = spawn_child(path_utf8, NULL, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CREATE_NEW_PROCESS_GROUP);
|
||||
free(path_utf8);
|
||||
close(*newsock);
|
||||
SetEnvironmentVariable("SSHD_REMSOC", NULL);
|
||||
SetEnvironmentVariable("SSHD_STARTUPSOC", NULL);
|
||||
}
|
||||
#else /* !WINDOWS */
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
/*
|
||||
@ -1378,7 +1582,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
|
||||
close(config_s[0]);
|
||||
break;
|
||||
}
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
/* Parent. Stay in the loop. */
|
||||
platform_post_fork_parent(pid);
|
||||
if (pid < 0)
|
||||
@ -1386,6 +1590,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
|
||||
else
|
||||
debug("Forked child %ld.", (long)pid);
|
||||
|
||||
#endif /* fork unsupported */
|
||||
close(startup_p[1]);
|
||||
|
||||
if (rexec_flag) {
|
||||
@ -1552,7 +1757,7 @@ main(int ac, char **av)
|
||||
|
||||
/* Parse command-line arguments. */
|
||||
while ((opt = getopt(ac, av,
|
||||
"C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrt")) != -1) {
|
||||
"C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrtyz")) != -1) {
|
||||
switch (opt) {
|
||||
case '4':
|
||||
options.address_family = AF_INET;
|
||||
@ -1653,6 +1858,18 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
free(line);
|
||||
break;
|
||||
case 'y':
|
||||
privsep_unauth_child = 1;
|
||||
rexec_flag = 0;
|
||||
logfile = NULL;
|
||||
//Sleep(10 * 1000);
|
||||
break;
|
||||
case 'z':
|
||||
privsep_auth_child = 1;
|
||||
rexec_flag = 0;
|
||||
logfile = NULL;
|
||||
//Sleep(10 * 1000);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@ -1661,10 +1878,19 @@ main(int ac, char **av)
|
||||
}
|
||||
if (rexeced_flag || inetd_flag)
|
||||
rexec_flag = 0;
|
||||
if (!test_flag && (rexec_flag && (av[0] == NULL || *av[0] != '/')))
|
||||
if (!test_flag && !debug_flag && rexec_flag &&
|
||||
#ifdef WINDOWS
|
||||
(av[0] == NULL || *av[0] == '\0' || av[0][1] != ':'))
|
||||
#else
|
||||
(av[0] == NULL || *av[0] != '/'))
|
||||
#endif
|
||||
fatal("sshd re-exec requires execution with an absolute path");
|
||||
if (rexeced_flag)
|
||||
closefrom(REEXEC_MIN_FREE_FD);
|
||||
else if (privsep_unauth_child)
|
||||
closefrom(PRIVSEP_UNAUTH_MIN_FREE_FD);
|
||||
else if (privsep_auth_child)
|
||||
closefrom(PRIVSEP_AUTH_MIN_FREE_FD);
|
||||
else
|
||||
closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
|
||||
|
||||
@ -1714,6 +1940,8 @@ main(int ac, char **av)
|
||||
buffer_init(&cfg);
|
||||
if (rexeced_flag)
|
||||
recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg);
|
||||
else if (privsep_unauth_child || privsep_auth_child)
|
||||
recv_config_state(PRIVSEP_MONITOR_FD, &cfg);
|
||||
else if (strcasecmp(config_file_name, "none") != 0)
|
||||
load_server_config(config_file_name, &cfg);
|
||||
|
||||
@ -1725,15 +1953,6 @@ main(int ac, char **av)
|
||||
/* Fill in default values for those options not explicitly set. */
|
||||
fill_default_server_options(&options);
|
||||
|
||||
#ifdef WINDOWS
|
||||
/*
|
||||
* For windows, enable logging right away to capture failures while loading private host keys.
|
||||
* On Unix, logging at configured level is not done until private host keys are loaded. Why??
|
||||
*/
|
||||
if (!debug_flag)
|
||||
log_init(__progname, options.log_level, options.log_facility, log_stderr);
|
||||
#endif // WINDOWS
|
||||
|
||||
/* challenge-response is implemented via keyboard interactive */
|
||||
if (options.challenge_response_authentication)
|
||||
options.kbd_interactive_authentication = 1;
|
||||
@ -1781,7 +2000,6 @@ main(int ac, char **av)
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifndef WINDOWS /* not applicable in Windows */
|
||||
/* Store privilege separation user for later use if required. */
|
||||
privsep_chroot = use_privsep && (getuid() == 0 || geteuid() == 0);
|
||||
if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
|
||||
@ -1796,7 +2014,11 @@ main(int ac, char **av)
|
||||
privsep_pw->pw_passwd = xstrdup("*");
|
||||
}
|
||||
endpwent();
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
if (privsep_auth_child || privsep_unauth_child) {
|
||||
recv_hostkeys_state(PRIVSEP_MONITOR_FD);
|
||||
goto done_loading_hostkeys;
|
||||
}
|
||||
|
||||
/* load host keys */
|
||||
sensitive_data.host_keys = xcalloc(options.num_host_key_files,
|
||||
@ -1818,6 +2040,7 @@ main(int ac, char **av)
|
||||
for (i = 0; i < options.num_host_key_files; i++) {
|
||||
if (options.host_key_files[i] == NULL)
|
||||
continue;
|
||||
if (privsep_unauth_child || privsep_auth_child) key = NULL; else /*TODO - remove this*/
|
||||
key = key_load_private(options.host_key_files[i], "", NULL);
|
||||
pubkey = key_load_public(options.host_key_files[i], NULL);
|
||||
|
||||
@ -1903,7 +2126,7 @@ main(int ac, char **av)
|
||||
debug("host certificate: #%u type %d %s", j, key->type,
|
||||
key_type(key));
|
||||
}
|
||||
|
||||
done_loading_hostkeys:
|
||||
if (privsep_chroot) {
|
||||
struct stat st;
|
||||
|
||||
@ -1996,12 +2219,13 @@ main(int ac, char **av)
|
||||
/* Get a connection, either from inetd or a listening TCP socket */
|
||||
if (inetd_flag) {
|
||||
server_accept_inetd(&sock_in, &sock_out);
|
||||
} else if (privsep_unauth_child || privsep_auth_child) {
|
||||
sock_in = sock_out = dup(STDIN_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
startup_pipe = -1;
|
||||
} else {
|
||||
platform_pre_listen();
|
||||
#ifdef WINDOWS
|
||||
/* For Windows child sshd, skip listener */
|
||||
if (is_child == 0)
|
||||
#endif /* WINDOWS */
|
||||
server_listen();
|
||||
|
||||
signal(SIGHUP, sighup_handler);
|
||||
@ -2025,27 +2249,6 @@ main(int ac, char **av)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WINDOWS
|
||||
/* Windows - for sshd child, pick up the accepted socket*/
|
||||
if (is_child) {
|
||||
char *stopstring;
|
||||
DWORD_PTR handle;
|
||||
|
||||
handle = strtol(getenv("SSHD_REMSOC"), &stopstring, 16);
|
||||
SetEnvironmentVariable("SSHD_REMSOC", NULL);
|
||||
debug("child socket: %d", handle);
|
||||
sock_in = sock_out = newsock = w32_allocate_fd_for_handle((HANDLE)handle, TRUE);
|
||||
fcntl(newsock, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
handle = strtol(getenv("SSHD_STARTUPSOC"), &stopstring, 16);
|
||||
SetEnvironmentVariable("SSHD_STARTUPSOC", NULL);
|
||||
debug("child startup_pipe: %d", handle);
|
||||
startup_pipe = w32_allocate_fd_for_handle((HANDLE)handle, FALSE);
|
||||
fcntl(startup_pipe, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
else /* Windows and Unix sshd parent */
|
||||
#endif /* WINDOWS */
|
||||
|
||||
/* Accept a connection and return in a forked child */
|
||||
server_accept_loop(&sock_in, &sock_out,
|
||||
&newsock, config_s);
|
||||
@ -2069,6 +2272,7 @@ main(int ac, char **av)
|
||||
error("setsid: %.100s", strerror(errno));
|
||||
#endif
|
||||
|
||||
#ifndef FORK_NOT_SUPPORTED
|
||||
if (rexec_flag) {
|
||||
int fd;
|
||||
|
||||
@ -2107,7 +2311,7 @@ main(int ac, char **av)
|
||||
debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d",
|
||||
sock_in, sock_out, newsock, startup_pipe, config_s[0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Executed child processes don't need these. */
|
||||
fcntl(sock_out, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(sock_in, F_SETFD, FD_CLOEXEC);
|
||||
@ -2129,6 +2333,7 @@ main(int ac, char **av)
|
||||
* Register our connection. This turns encryption off because we do
|
||||
* not have a key.
|
||||
*/
|
||||
tmp_sock = sock_in;
|
||||
packet_set_connection(sock_in, sock_out);
|
||||
packet_set_server();
|
||||
ssh = active_state; /* XXX */
|
||||
@ -2166,6 +2371,10 @@ main(int ac, char **av)
|
||||
|
||||
rdomain = ssh_packet_rdomain_in(ssh);
|
||||
|
||||
if (privsep_unauth_child || privsep_auth_child) {
|
||||
recv_idexch_state(PRIVSEP_MONITOR_FD);
|
||||
goto idexch_done;
|
||||
}
|
||||
/* Log the connection. */
|
||||
laddr = get_local_ipaddr(sock_in);
|
||||
verbose("Connection from %s port %d on %s port %d%s%s%s",
|
||||
@ -2188,6 +2397,7 @@ main(int ac, char **av)
|
||||
alarm(options.login_grace_time);
|
||||
|
||||
sshd_exchange_identification(ssh, sock_in, sock_out);
|
||||
idexch_done:
|
||||
packet_set_nonblocking();
|
||||
|
||||
/* allocate authentication context */
|
||||
|
Loading…
x
Reference in New Issue
Block a user