Source snapshot from Powershell/openssh-portable:latestw_all

This commit is contained in:
Yanbing Wang 2018-01-19 18:43:54 -08:00
parent 1ad6c956cc
commit c4d0727338
66 changed files with 1946 additions and 1071 deletions

View File

@ -1,4 +1,4 @@
version: 0.0.24.0.{build}
version: 1.0.0.0.{build}
image: Visual Studio 2015
branches:

View File

@ -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, &reg_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
View File

@ -93,9 +93,6 @@ struct Authctxt {
/* Information exposed to session */
struct sshbuf *session_info; /* Auth info for environment */
#ifdef WINDOWS
void *auth_token;
#endif
};
/*

View File

@ -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);

View File

@ -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;

View File

@ -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
}

View File

@ -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') {

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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" />

View File

@ -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" />

View File

@ -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>

View File

@ -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.

View File

@ -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">

View File

@ -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">

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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

View 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);

View File

@ -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 *);

View File

@ -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

View File

@ -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, &sectorsPerCluster, &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;
}

View File

@ -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);

View File

@ -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

View File

@ -358,3 +358,9 @@ setegid(gid_t gid)
{
return 0;
}
void
endpwent(void)
{
return;
}

View File

@ -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--;

View File

@ -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]);
}

View File

@ -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;

View 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;
}

View 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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -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(

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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;
}

View 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,
&quotas,
&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,
&quotas,
&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)

View File

@ -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
View File

@ -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 *

View File

@ -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)
{

View File

@ -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_ */

View File

@ -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;

View File

@ -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."
}
}
}

View File

@ -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" {

View File

@ -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
}
#>
}
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
View File

@ -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));

View File

@ -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 */

View File

@ -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
View File

@ -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
View File

@ -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 */