2016-12-19 23:46:28 +01:00
|
|
|
/*
|
|
|
|
* Author: NoMachine <developers@nomachine.com>
|
|
|
|
*
|
2018-05-02 08:20:42 +02:00
|
|
|
* Author: Bryan Berns <berns@uwalumni.com>
|
|
|
|
* Normalized and optimized login routines and added support for
|
|
|
|
* internet-linked accounts.
|
|
|
|
*
|
2016-12-19 23:46:28 +01:00
|
|
|
* 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 <Windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <LM.h>
|
|
|
|
#include <sddl.h>
|
|
|
|
#include <DsGetDC.h>
|
|
|
|
#define SECURITY_WIN32
|
|
|
|
#include <security.h>
|
2017-02-09 20:30:40 +01:00
|
|
|
|
2016-12-19 23:46:28 +01:00
|
|
|
#include "inc\pwd.h"
|
|
|
|
#include "inc\grp.h"
|
|
|
|
#include "inc\utf.h"
|
2017-01-15 07:12:19 +01:00
|
|
|
#include "misc_internal.h"
|
2017-03-24 20:35:52 +01:00
|
|
|
#include "debug.h"
|
2016-12-19 23:46:28 +01:00
|
|
|
|
|
|
|
static struct passwd pw;
|
|
|
|
static char* pw_shellpath = NULL;
|
|
|
|
#define SHELL_HOST "\\ssh-shellhost.exe"
|
|
|
|
|
2017-02-09 20:30:40 +01:00
|
|
|
|
2016-12-19 23:46:28 +01:00
|
|
|
int
|
2017-02-09 20:30:40 +01:00
|
|
|
initialize_pw()
|
|
|
|
{
|
2017-07-20 00:28:35 +02:00
|
|
|
errno_t r = 0;
|
|
|
|
char* program_dir = w32_programdir();
|
|
|
|
size_t program_dir_len = strlen(program_dir);
|
|
|
|
size_t shell_host_len = strlen(SHELL_HOST);
|
2017-02-03 08:54:02 +01:00
|
|
|
if (pw_shellpath == NULL) {
|
2017-07-20 00:28:35 +02:00
|
|
|
if ((pw_shellpath = malloc(program_dir_len + shell_host_len + 1)) == NULL)
|
2017-02-03 08:54:02 +01:00
|
|
|
fatal("initialize_pw - out of memory");
|
|
|
|
else {
|
|
|
|
char* head = pw_shellpath;
|
2017-07-20 00:28:35 +02:00
|
|
|
if ((r= memcpy_s(head, program_dir_len + shell_host_len + 1, w32_programdir(), program_dir_len)) != 0) {
|
|
|
|
fatal("memcpy_s failed with error: %d.", r);
|
|
|
|
}
|
|
|
|
head += program_dir_len;
|
|
|
|
if ((r = memcpy_s(head, shell_host_len + 1, SHELL_HOST, shell_host_len)) != 0) {
|
|
|
|
fatal("memcpy_s failed with error: %d.", r);
|
|
|
|
}
|
|
|
|
head += shell_host_len;
|
2017-02-03 08:54:02 +01:00
|
|
|
*head = '\0';
|
|
|
|
}
|
|
|
|
}
|
2017-02-09 20:30:40 +01:00
|
|
|
|
2017-02-03 08:54:02 +01:00
|
|
|
if (pw.pw_shell != pw_shellpath) {
|
|
|
|
memset(&pw, 0, sizeof(pw));
|
|
|
|
pw.pw_shell = pw_shellpath;
|
|
|
|
pw.pw_passwd = "\0";
|
|
|
|
/* pw_uid = 0 for root on Unix and SSH code has specific restrictions for root
|
|
|
|
* that are not applicable in Windows */
|
|
|
|
pw.pw_uid = 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2016-12-19 23:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-02-09 20:30:40 +01:00
|
|
|
reset_pw()
|
|
|
|
{
|
2017-02-03 08:54:02 +01:00
|
|
|
initialize_pw();
|
|
|
|
if (pw.pw_name)
|
|
|
|
free(pw.pw_name);
|
|
|
|
if (pw.pw_dir)
|
|
|
|
free(pw.pw_dir);
|
2017-02-03 21:22:00 +01:00
|
|
|
if (pw.pw_sid)
|
|
|
|
free(pw.pw_sid);
|
|
|
|
pw.pw_name = NULL;
|
|
|
|
pw.pw_dir = NULL;
|
|
|
|
pw.pw_sid = NULL;
|
2016-12-19 23:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct passwd*
|
2018-05-02 08:20:42 +02:00
|
|
|
get_passwd(const wchar_t * user_utf16, PSID sid)
|
2017-02-09 20:30:40 +01:00
|
|
|
{
|
2018-05-02 08:20:42 +02:00
|
|
|
wchar_t user_resolved[DNLEN + 1 + UNLEN + 1];
|
2017-02-03 08:54:02 +01:00
|
|
|
struct passwd *ret = NULL;
|
2018-05-02 08:20:42 +02:00
|
|
|
wchar_t *sid_string = NULL;
|
2017-10-17 21:29:13 +02:00
|
|
|
wchar_t reg_path[PATH_MAX], profile_home[PATH_MAX], profile_home_exp[PATH_MAX];
|
2018-05-02 08:20:42 +02:00
|
|
|
DWORD reg_path_len = PATH_MAX;
|
|
|
|
HKEY reg_key = 0;
|
|
|
|
|
|
|
|
BYTE binary_sid[SECURITY_MAX_SID_SIZE];
|
|
|
|
DWORD sid_size = ARRAYSIZE(binary_sid);
|
|
|
|
WCHAR domain_name[DNLEN + 1] = L"";
|
|
|
|
DWORD domain_name_size = DNLEN + 1;
|
|
|
|
SID_NAME_USE account_type = 0;
|
2017-02-03 08:54:02 +01:00
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
reset_pw();
|
2018-05-02 08:20:42 +02:00
|
|
|
|
|
|
|
/* skip forward lookup on name if sid was passed in */
|
|
|
|
if (sid != NULL)
|
|
|
|
CopySid(sizeof(binary_sid), binary_sid, sid);
|
|
|
|
|
|
|
|
/* attempt to lookup the account; this will verify the account is valid and
|
|
|
|
* is will return its sid and the realm that owns it */
|
|
|
|
else if(LookupAccountNameW(NULL, user_utf16, binary_sid, &sid_size,
|
|
|
|
domain_name, &domain_name_size, &account_type) == 0) {
|
|
|
|
errno = ENOENT;
|
|
|
|
debug("%s: LookupAccountName() failed: %d.", __FUNCTION__, GetLastError());
|
|
|
|
goto cleanup;
|
2017-02-03 08:54:02 +01:00
|
|
|
}
|
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* convert the binary string to a string */
|
|
|
|
if (ConvertSidToStringSidW((PSID) binary_sid, &sid_string) == FALSE) {
|
|
|
|
errno = ENOENT;
|
|
|
|
goto cleanup;
|
2018-02-21 19:09:18 +01:00
|
|
|
}
|
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* lookup the account name from the sid */
|
|
|
|
WCHAR user_name[UNLEN + 1];
|
|
|
|
DWORD user_name_length = ARRAYSIZE(user_name);
|
|
|
|
domain_name_size = DNLEN + 1;
|
|
|
|
if (LookupAccountSidW(NULL, binary_sid, user_name, &user_name_length,
|
|
|
|
domain_name, &domain_name_size, &account_type) == 0) {
|
|
|
|
errno = ENOENT;
|
|
|
|
debug("%s: LookupAccountSid() failed: %d.", __FUNCTION__, GetLastError());
|
|
|
|
goto cleanup;
|
2017-02-03 08:54:02 +01:00
|
|
|
}
|
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* verify passed account is actually a user account */
|
|
|
|
if (account_type != SidTypeUser) {
|
|
|
|
errno = ENOENT;
|
|
|
|
debug3("%s: Invalid account type: %d.", __FUNCTION__, account_type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2017-02-09 20:30:40 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* fetch the computer name so we can determine if the specified user is local or not */
|
|
|
|
wchar_t computer_name[CNLEN + 1];
|
|
|
|
DWORD computer_name_size = ARRAYSIZE(computer_name);
|
|
|
|
if (GetComputerNameW(computer_name, &computer_name_size) == 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2017-02-03 08:54:02 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* if standard local user name, just use name without decoration */
|
|
|
|
if (_wcsicmp(domain_name, computer_name) == 0)
|
|
|
|
wcscpy_s(user_resolved, ARRAYSIZE(user_resolved), user_name);
|
2017-02-09 20:30:40 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* put any other format in sam compatible format */
|
|
|
|
else
|
|
|
|
swprintf_s(user_resolved, ARRAYSIZE(user_resolved), L"%s\\%s", domain_name, user_name);
|
2017-02-03 08:54:02 +01:00
|
|
|
|
|
|
|
/* if one of below fails, set profile path to Windows directory */
|
2018-05-02 08:20:42 +02:00
|
|
|
if (swprintf_s(reg_path, PATH_MAX, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", sid_string) == -1 ||
|
2017-06-13 19:33:47 +02:00
|
|
|
RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®_key) != 0 ||
|
2018-05-02 08:20:42 +02:00
|
|
|
RegQueryValueExW(reg_key, L"ProfileImagePath", 0, NULL, (LPBYTE)profile_home, ®_path_len) != 0 ||
|
|
|
|
ExpandEnvironmentStringsW(profile_home, NULL, 0) > PATH_MAX ||
|
2017-10-17 21:29:13 +02:00
|
|
|
ExpandEnvironmentStringsW(profile_home, profile_home_exp, PATH_MAX) == 0)
|
|
|
|
if (GetWindowsDirectoryW(profile_home_exp, PATH_MAX) == 0) {
|
2017-06-13 19:33:47 +02:00
|
|
|
debug3("GetWindowsDirectoryW failed with %d", GetLastError());
|
|
|
|
errno = EOTHER;
|
2018-05-02 08:20:42 +02:00
|
|
|
goto cleanup;
|
2017-06-13 19:33:47 +02:00
|
|
|
}
|
2017-02-03 08:54:02 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
/* convert to utf8, make name lowercase, and assign to output structure*/
|
|
|
|
_wcslwr_s(user_resolved, wcslen(user_resolved) + 1);
|
|
|
|
if ((pw.pw_name = utf16_to_utf8(user_resolved)) == NULL ||
|
|
|
|
(pw.pw_dir = utf16_to_utf8(profile_home_exp)) == NULL ||
|
|
|
|
(pw.pw_sid = utf16_to_utf8(sid_string)) == NULL) {
|
|
|
|
reset_pw();
|
2017-02-14 22:43:06 +01:00
|
|
|
errno = ENOMEM;
|
2018-05-02 08:20:42 +02:00
|
|
|
goto cleanup;
|
2017-02-14 22:43:06 +01:00
|
|
|
}
|
|
|
|
|
2017-02-03 08:54:02 +01:00
|
|
|
ret = &pw;
|
2017-02-03 00:03:21 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
cleanup:
|
|
|
|
|
|
|
|
if (sid_string)
|
|
|
|
LocalFree(sid_string);
|
2017-02-03 08:54:02 +01:00
|
|
|
if (reg_key)
|
|
|
|
RegCloseKey(reg_key);
|
2018-05-02 08:20:42 +02:00
|
|
|
|
2017-02-03 08:54:02 +01:00
|
|
|
return ret;
|
2016-12-19 23:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct passwd*
|
2017-02-09 20:30:40 +01:00
|
|
|
w32_getpwnam(const char *user_utf8)
|
|
|
|
{
|
2018-05-02 08:20:42 +02:00
|
|
|
wchar_t * user_utf16 = utf8_to_utf16(user_utf8);
|
|
|
|
if (user_utf16 == NULL) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_passwd(user_utf16, NULL);
|
2016-12-19 23:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct passwd*
|
2018-05-02 08:20:42 +02:00
|
|
|
w32_getpwuid(uid_t uid)
|
2017-02-09 20:30:40 +01:00
|
|
|
{
|
2018-05-02 08:20:42 +02:00
|
|
|
struct passwd* ret = NULL;
|
|
|
|
HANDLE token = NULL;
|
2017-02-03 08:54:02 +01:00
|
|
|
TOKEN_USER* info = NULL;
|
2018-05-02 08:20:42 +02:00
|
|
|
DWORD info_len = 0;
|
2017-02-03 08:54:02 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == FALSE ||
|
|
|
|
GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE ||
|
|
|
|
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
|
|
|
GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE)
|
|
|
|
goto cleanup;
|
2017-02-03 08:54:02 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
ret = get_passwd(NULL, info->User.Sid);
|
|
|
|
|
|
|
|
cleanup:
|
2016-12-19 23:46:28 +01:00
|
|
|
|
2018-05-02 08:20:42 +02:00
|
|
|
if (token)
|
|
|
|
CloseHandle(token);
|
2017-02-03 08:54:02 +01:00
|
|
|
if (info)
|
|
|
|
free(info);
|
2016-12-19 23:46:28 +01:00
|
|
|
|
2017-04-28 06:00:12 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2016-12-19 23:46:28 +01:00
|
|
|
|
2017-02-09 20:30:40 +01:00
|
|
|
char *
|
|
|
|
group_from_gid(gid_t gid, int nogroup)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return "-";
|
|
|
|
}
|
|
|
|
|
2017-02-09 20:30:40 +01:00
|
|
|
char *
|
|
|
|
user_from_uid(uid_t uid, int nouser)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return "-";
|
|
|
|
}
|
|
|
|
|
|
|
|
uid_t
|
2017-02-09 20:30:40 +01:00
|
|
|
getuid(void)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gid_t
|
2017-02-09 20:30:40 +01:00
|
|
|
getgid(void)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uid_t
|
2017-02-09 20:30:40 +01:00
|
|
|
geteuid(void)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gid_t
|
2017-02-09 20:30:40 +01:00
|
|
|
getegid(void)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2017-02-09 20:30:40 +01:00
|
|
|
setuid(uid_t uid)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2017-02-09 20:30:40 +01:00
|
|
|
setgid(gid_t gid)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2017-02-09 20:30:40 +01:00
|
|
|
seteuid(uid_t uid)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2017-02-09 20:30:40 +01:00
|
|
|
setegid(gid_t gid)
|
|
|
|
{
|
2016-12-19 23:46:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2018-01-15 22:57:31 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
endpwent(void)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|