Win32-OpenSSH/contrib/win32/win32compat/lsalogon.c

475 lines
11 KiB
C

/*
* Author: NoMachine <developers@nomachine.com>
*
* Copyright (c) 2009, 2011 NoMachine
* All rights reserved
*
* Support functions and system calls' replacements needed to let the
* software run on Win32 based operating systems.
*
* 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.
*/
#include "lsalogon.h"
#include "Debug.h"
#include "includes.h"
#include "log.h"
#include "servconf.h"
#define STATUS_LOGON_FAILURE ((NTSTATUS)0xC000006DL) // ntsubauth
#define STATUS_NO_SUCH_PACKAGE ((NTSTATUS)0xC00000FEL)
extern ServerOptions options;
/*
* Allocate new LsaAuth struct and initialize it with given auth data.
* This function is needed becouse:
*
* a) LSA needs one continous memory block on input.
*
* b) We can't send pointers in auth data to LSA 'server', becouse
* LSA package can be 32 or 64 bit and the same to client application.
* Client and Server must be compatible, so all fields must have the
* same size in lsa 'server' and logon client application.
*
* So, we allocate one 'big' LsaAuth struct and copy to it all
* needed auth data.
*
* lsaauth - new allocated LsaAuth struct (OUT)
* user - user name, in UTF-8 (IN)
* pkblob - public key blob (IN)
* blen - pkblob size in bytes (IN)
* sign - signature (IN)
* signSize - signature size in bytes (IN)
* data - ?? We copy it from ssh auth code (IN)
* dataSize - size of data field in bytes (IN)
* dataFellow - ?? We pass global 'datafellow' variable from sshd here (IN)
*
* RETURNS: 0 if OK.
*/
int AllocLsaAuth(LsaAuth **lsaAuth, char *user, char *pkBlob,
int pkBlobSize, char *sign, int signSize,
char *data, int dataSize, int dataFellow)
{
int exitCode = 1;
LPWSTR userUTF16 = NULL;
int i = 0;
int authFileSize = 0;
/*
* Pointers to fields in local allocated LsaAuth struct.
*/
char *userPtr = NULL;
char *signPtr = NULL;
char *dataPtr = NULL;
char *blobPtr = NULL;
char *authPtr = NULL;
char *p = NULL;
/*
* Are arguments ok?
*/
debug3("Checking args...");
FAIL(user == NULL);
FAIL(lsaAuth == NULL);
FAIL(pkBlob == NULL);
FAIL(sign == NULL);
FAIL(signSize == 0);
FAIL(dataSize == 0);
FAIL(pkBlobSize == 0);
*lsaAuth = NULL;
/*
* Compute total size of authorize files list.
* For each files we need : real content + zero terminate word.
*/
for (i = 0; i < options.num_authkeys_files; i++)
{
debug3("Adding authorized file [%s] to LsaAuth...",
options.authorized_keys_files[i]);
int cchLen = MultiByteToWideChar(CP_UTF8, 0,
options.authorized_keys_files[i],
-1, NULL, 0);
authFileSize += (cchLen + 1) * sizeof(wchar_t);
}
/*
* Convert username to UTF-16.
*/
int userSize = MultiByteToWideChar(CP_UTF8, 0, user, -1, NULL, 0);
FAIL(userSize == 0);
userSize = 4 * userSize;
userUTF16 = (LPWSTR) malloc(userSize);
FAIL(userUTF16 == NULL);
FAIL(0 == MultiByteToWideChar(CP_UTF8, 0, user, -1, userUTF16, userSize));
/*
* Compute total size of LsaAuth struct.
*/
debug3("Computing total size of LsaAuth...");
int totalSize = sizeof(LsaAuth) + userSize + signSize +
dataSize + pkBlobSize + authFileSize;
/*
* Allocate new LsaAuth struct.
*/
debug3("Allocating new LsaAuth structure...");
*lsaAuth = (LsaAuth *) malloc(totalSize);
FAIL(*lsaAuth == NULL);
/*
* Store sizes of fields in LsaAuth.
*/
(*lsaAuth) -> totalSize_ = totalSize;
(*lsaAuth) -> userSize_ = userSize;
(*lsaAuth) -> signSize_ = signSize;
(*lsaAuth) -> dataSize_ = dataSize;
(*lsaAuth) -> pkBlobSize_ = pkBlobSize;
/*
* Compute adressess of fields.
*/
userPtr = (char *) &((*lsaAuth) -> buf_);
signPtr = (char *) (userPtr + userSize);
dataPtr = (char *) (signPtr + signSize);
blobPtr = (char *) (dataPtr + dataSize);
authPtr = (char *) (blobPtr + pkBlobSize);
/*
* Copy input buffers into output structure's fields.
*/
debug3("Filling up LsaAuth struct...");
memcpy(userPtr, userUTF16, userSize);
memcpy(signPtr, sign, signSize);
memcpy(dataPtr, data, dataSize);
memcpy(blobPtr, pkBlob, pkBlobSize);
(*lsaAuth) -> dataFellow_ = dataFellow;
/*
* Copy authorized files list into output struct.
*/
(*lsaAuth) -> authFilesCount_ = options.num_authkeys_files;
p = authPtr;
for (i = 0; i < options.num_authkeys_files; i++)
{
char *nextFile = options.authorized_keys_files[i];
int bytesLeft = (char *) (*lsaAuth) + totalSize - p;
/*
* Put next UTF8 string to struct.
*/
debug3("Converting [%s] to UTF8...", nextFile);
int writtenCch = MultiByteToWideChar(CP_UTF8, 0, nextFile, -1,
(wchar_t *) p, bytesLeft);
FAIL(writtenCch <= 0);
p += (writtenCch + 1) * sizeof(wchar_t);
}
exitCode = 0;
fail:
/*
* Clean up if function fails.
*/
if (exitCode)
{
debug("ERROR. Cannot create LsaAuth struct (%u).", GetLastError());
if (lsaAuth && *lsaAuth)
{
free(*lsaAuth);
*lsaAuth = NULL;
}
if (userUTF16)
{
free(userUTF16);
}
}
return exitCode;
}
/*
* Try to logon using SSH-LSA package.
*
* hToken - user token if success (OUT)
* user - user name (IN)
* pkblob - public key blob (IN)
* blen - pkblob size in bytes (IN)
* sign - signature (IN)
* signSize - signature size in bytes (IN)
* data - ?? We copy it from ssh auth code (IN)
* dataSize - size of data field in bytes (IN)
* dataFellow - ?? We copy it from ssh auth code (IN)
*
* RETURNS: 0 if OK.
*/
int LsaLogon(HANDLE *hToken, char homeDir[MAX_PATH], char *user,
char *pkBlob, int pkBlobSize, char *sign, int signSize,
char *data, int dataSize, int dataFellow)
{
int exitCode = 1;
NTSTATUS ntStat = 0;
LSA_STRING logonProcName;
LSA_STRING originName;
LSA_STRING authPckgName;
HANDLE hLsa = NULL;
LSA_OPERATIONAL_MODE securityMode;
/*
* Impersonation, "weak" token returned from network logon.
* We can't create process as other user via this token.
*/
HANDLE hWeakToken = NULL;
/*
* Login data.
*/
LsaAuth *lsaAuth = NULL;
ULONG lsaAuthSize = 0;
ULONG authPckgId = 0;
TOKEN_SOURCE srcToken;
PVOID profile = NULL;
ULONG profileSize;
LUID logonId;
QUOTA_LIMITS quotas;
NTSTATUS loginStat;
debug("-> LsaLogon()...");
/*
* We check only hToken arg, becouse other args are tested in AllocLsaAuth().
*/
debug("Checking args...");
FAIL(hToken == NULL);
/*
* Setup lsa strings.
*/
debug("Setting up LSA Strings...");
FAIL(InitLsaString(&logonProcName, "sshd-logon"));
FAIL(InitLsaString(&originName, "NTLM"));
FAIL(InitLsaString(&authPckgName, "SSH-LSA"));
/*
* Enable needed privilege to current running process.
*/
EnablePrivilege("SeTcbPrivilege", 1);
/*
* Register new logon process.
*/
debug("LsaRegisterLogonProcess()...");
NTFAIL(LsaRegisterLogonProcess(&logonProcName, &hLsa, &securityMode));
/*
* Retrieve Authenticated Package ID.
*/
debug("Retrieving Authentification Package ID...");
NTFAIL(LsaLookupAuthenticationPackage(hLsa, &authPckgName, &authPckgId));
/*
* Allocate LsaAuth struct.
*/
debug("Allocating LsaAuth struct...");
FAIL(AllocLsaAuth(&lsaAuth, user, pkBlob, pkBlobSize,
sign, signSize, data, dataSize, dataFellow));
lsaAuthSize = lsaAuth -> totalSize_;
/*
* Create TOKEN_SOURCE part
*/
debug("Setting up TOKEN_SOURCE...");
FAIL(AllocateLocallyUniqueId(&srcToken.SourceIdentifier) == FALSE);
memcpy(srcToken.SourceName, "**sshd**", 8);
/*
* Try to login using LsaAuth struct.
*/
debug("Login attemp...");
NTFAIL(LsaLogonUser(hLsa, &originName, Network,
authPckgId, lsaAuth, lsaAuthSize, NULL,
&srcToken, &profile, &profileSize,
&logonId, &hWeakToken, &quotas, &loginStat));
debug("login status: %x...", loginStat);
//FAIL(WideCharToMultiByte( CP_UTF8, 0, profile, -1, homeDir, MAX_PATH, NULL, NULL)==0);
//memcpy(homeDir, profile, MAX_PATH*sizeof(wchar_t));
lstrcpyW(homeDir, profile);
debug("homedir = [%ls]", (char *) homeDir);
//strcpy(homeDir, profile);
//PrintToken(hToken);
/*
* Duplicate 'weak' impersonation token into Primary Key token.
* We can create process using duplicated token.
*/
debug("Duplicating token...");
FAIL(DuplicateTokenEx(hWeakToken, MAXIMUM_ALLOWED,
NULL, SecurityImpersonation,
TokenPrimary, hToken) == 0);
exitCode = 0;
fail:
if (exitCode)
{
switch(ntStat)
{
case STATUS_LOGON_FAILURE:
{
debug("SSH-LSA authorization failed. "
"(err = %u, ntStat = %x).", GetLastError(), ntStat);
exitCode = 0;
break;
}
case STATUS_NO_SUCH_PACKAGE:
{
debug("SSH-LSA package not found. "
"(err = %u, ntStat = %x).", GetLastError(), ntStat);
break;
}
default:
{
debug("Cannot logon using LSA package (err = %u, ntStat = %x).",
GetLastError(), ntStat);
}
}
hToken = NULL;
}
else
{
debug("LsaLogon : OK.");
}
/*
* Clean up.
*/
CloseHandle(hWeakToken);
LsaFreeReturnBuffer(profile);
EnablePrivilege("SeTcbPrivilege", 0);
LsaDeregisterLogonProcess(hLsa);
ClearLsaString(&logonProcName);
ClearLsaString(&originName);
ClearLsaString(&authPckgName);
debug("<- LsaLogon()...");
return exitCode;
}