Blame winpr/libwinpr/utils/sam.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Security Accounts Manager (SAM)
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/wtypes.h>
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/sam.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
Packit 1fb8d4
#include "../log.h"
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_UNISTD_H
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN32
Packit Service 5a9772
#define WINPR_SAM_FILE "C:\\SAM"
Packit 1fb8d4
#else
Packit Service 5a9772
#define WINPR_SAM_FILE "/etc/winpr/SAM"
Packit 1fb8d4
#endif
Packit 1fb8d4
#define TAG WINPR_TAG("utils")
Packit 1fb8d4
Packit Service 5a9772
struct winpr_sam
Packit Service 5a9772
{
Packit Service 5a9772
	FILE* fp;
Packit Service 5a9772
	char* line;
Packit Service 5a9772
	char* buffer;
Packit Service 5a9772
	char* context;
Packit Service 5a9772
	BOOL readOnly;
Packit Service 5a9772
};
Packit Service 5a9772
Packit 1fb8d4
WINPR_SAM* SamOpen(const char* filename, BOOL readOnly)
Packit 1fb8d4
{
Packit 1fb8d4
	FILE* fp = NULL;
Packit 1fb8d4
	WINPR_SAM* sam = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!filename)
Packit 1fb8d4
		filename = WINPR_SAM_FILE;
Packit 1fb8d4
Packit 1fb8d4
	if (readOnly)
Packit 1fb8d4
		fp = fopen(filename, "r");
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		fp = fopen(filename, "r+");
Packit 1fb8d4
Packit 1fb8d4
		if (!fp)
Packit 1fb8d4
			fp = fopen(filename, "w+");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fp)
Packit 1fb8d4
	{
Packit Service 5a9772
		sam = (WINPR_SAM*)malloc(sizeof(WINPR_SAM));
Packit 1fb8d4
Packit 1fb8d4
		if (!sam)
Packit 1fb8d4
		{
Packit 1fb8d4
			fclose(fp);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sam->readOnly = readOnly;
Packit 1fb8d4
		sam->fp = fp;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Could not open SAM file!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return sam;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL SamLookupStart(WINPR_SAM* sam)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t readSize;
Packit 1fb8d4
	INT64 fileSize;
Packit 1fb8d4
Packit 1fb8d4
	if (!sam || !sam->fp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	_fseeki64(sam->fp, 0, SEEK_END);
Packit 1fb8d4
	fileSize = _ftelli64(sam->fp);
Packit 1fb8d4
	_fseeki64(sam->fp, 0, SEEK_SET);
Packit 1fb8d4
Packit 1fb8d4
	if (fileSize < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	sam->context = NULL;
Packit Service 5a9772
	sam->buffer = (char*)malloc(fileSize + 2);
Packit 1fb8d4
Packit 1fb8d4
	if (!sam->buffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	readSize = fread(sam->buffer, fileSize, 1, sam->fp);
Packit 1fb8d4
Packit 1fb8d4
	if (!readSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!ferror(sam->fp))
Packit 1fb8d4
			readSize = fileSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (readSize < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(sam->buffer);
Packit 1fb8d4
		sam->buffer = NULL;
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	sam->buffer[fileSize] = '\n';
Packit 1fb8d4
	sam->buffer[fileSize + 1] = '\0';
Packit Service 5a9772
	sam->line = strtok_s(sam->buffer, "\n", &sam->context);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void SamLookupFinish(WINPR_SAM* sam)
Packit 1fb8d4
{
Packit 1fb8d4
	free(sam->buffer);
Packit 1fb8d4
	sam->buffer = NULL;
Packit 1fb8d4
	sam->line = NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void HexStrToBin(char* str, BYTE* bin, int length)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	CharUpperBuffA(str, length * 2);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		bin[i] = 0;
Packit 1fb8d4
Packit 1fb8d4
		if ((str[i * 2] >= '0') && (str[i * 2] <= '9'))
Packit 1fb8d4
			bin[i] |= (str[i * 2] - '0') << 4;
Packit 1fb8d4
Packit 1fb8d4
		if ((str[i * 2] >= 'A') && (str[i * 2] <= 'F'))
Packit 1fb8d4
			bin[i] |= (str[i * 2] - 'A' + 10) << 4;
Packit 1fb8d4
Packit 1fb8d4
		if ((str[i * 2 + 1] >= '0') && (str[i * 2 + 1] <= '9'))
Packit 1fb8d4
			bin[i] |= (str[i * 2 + 1] - '0');
Packit 1fb8d4
Packit 1fb8d4
		if ((str[i * 2 + 1] >= 'A') && (str[i * 2 + 1] <= 'F'))
Packit 1fb8d4
			bin[i] |= (str[i * 2 + 1] - 'A' + 10);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
Packit 1fb8d4
{
Packit 1fb8d4
	char* p[5];
Packit 1fb8d4
	size_t LmHashLength;
Packit 1fb8d4
	size_t NtHashLength;
Packit 1fb8d4
	size_t count = 0;
Packit 1fb8d4
	char* cur;
Packit 1fb8d4
Packit 1fb8d4
	if (!sam || !entry || !sam->line)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	cur = sam->line;
Packit 1fb8d4
Packit 1fb8d4
	while ((cur = strchr(cur, ':')) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		count++;
Packit 1fb8d4
		cur++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (count < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	p[0] = sam->line;
Packit 1fb8d4
	p[1] = strchr(p[0], ':') + 1;
Packit 1fb8d4
	p[2] = strchr(p[1], ':') + 1;
Packit 1fb8d4
	p[3] = strchr(p[2], ':') + 1;
Packit 1fb8d4
	p[4] = strchr(p[3], ':') + 1;
Packit 1fb8d4
	LmHashLength = (p[3] - p[2] - 1);
Packit 1fb8d4
	NtHashLength = (p[4] - p[3] - 1);
Packit 1fb8d4
Packit 1fb8d4
	if ((LmHashLength != 0) && (LmHashLength != 32))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if ((NtHashLength != 0) && (NtHashLength != 32))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	entry->UserLength = (UINT32)(p[1] - p[0] - 1);
Packit Service 5a9772
	entry->User = (LPSTR)malloc(entry->UserLength + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!entry->User)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	entry->User[entry->UserLength] = '\0';
Packit 1fb8d4
	entry->DomainLength = (UINT32)(p[2] - p[1] - 1);
Packit 1fb8d4
	memcpy(entry->User, p[0], entry->UserLength);
Packit 1fb8d4
Packit 1fb8d4
	if (entry->DomainLength > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		entry->Domain = (LPSTR)malloc(entry->DomainLength + 1);
Packit 1fb8d4
Packit 1fb8d4
		if (!entry->Domain)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(entry->User);
Packit 1fb8d4
			entry->User = NULL;
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		memcpy(entry->Domain, p[1], entry->DomainLength);
Packit 1fb8d4
		entry->Domain[entry->DomainLength] = '\0';
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		entry->Domain = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (LmHashLength == 32)
Packit Service 5a9772
		HexStrToBin(p[2], (BYTE*)entry->LmHash, 16);
Packit 1fb8d4
Packit 1fb8d4
	if (NtHashLength == 32)
Packit Service 5a9772
		HexStrToBin(p[3], (BYTE*)entry->NtHash, 16);
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void SamFreeEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
Packit 1fb8d4
{
Packit 1fb8d4
	if (entry)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (entry->UserLength > 0)
Packit 1fb8d4
			free(entry->User);
Packit 1fb8d4
Packit 1fb8d4
		if (entry->DomainLength > 0)
Packit 1fb8d4
			free(entry->Domain);
Packit 1fb8d4
Packit 1fb8d4
		free(entry);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void SamResetEntry(WINPR_SAM_ENTRY* entry)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!entry)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (entry->UserLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry->User);
Packit 1fb8d4
		entry->User = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (entry->DomainLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry->Domain);
Packit 1fb8d4
		entry->Domain = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ZeroMemory(entry->LmHash, sizeof(entry->LmHash));
Packit 1fb8d4
	ZeroMemory(entry->NtHash, sizeof(entry->NtHash));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_SAM_ENTRY* SamLookupUserA(WINPR_SAM* sam, LPSTR User, UINT32 UserLength, LPSTR Domain,
Packit 1fb8d4
                                UINT32 DomainLength)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BOOL found = FALSE;
Packit 1fb8d4
	WINPR_SAM_ENTRY* entry;
Packit Service 5a9772
	entry = (WINPR_SAM_ENTRY*)calloc(1, sizeof(WINPR_SAM_ENTRY));
Packit 1fb8d4
Packit 1fb8d4
	if (!entry)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!SamLookupStart(sam))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (sam->line != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		length = strlen(sam->line);
Packit 1fb8d4
Packit 1fb8d4
		if (length > 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (sam->line[0] != '#')
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!SamReadEntry(sam, entry))
Packit 1fb8d4
				{
Packit 1fb8d4
					goto out_fail;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (strcmp(User, entry->User) == 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					found = 1;
Packit 1fb8d4
					break;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		SamResetEntry(entry);
Packit Service 5a9772
		sam->line = strtok_s(NULL, "\n", &sam->context);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	SamLookupFinish(sam);
Packit 1fb8d4
Packit 1fb8d4
	if (!found)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, LPWSTR Domain,
Packit 1fb8d4
                                UINT32 DomainLength)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BOOL Found = FALSE;
Packit 1fb8d4
	BOOL UserMatch;
Packit 1fb8d4
	BOOL DomainMatch;
Packit 1fb8d4
	LPWSTR EntryUser = NULL;
Packit 1fb8d4
	UINT32 EntryUserLength;
Packit 1fb8d4
	LPWSTR EntryDomain = NULL;
Packit 1fb8d4
	UINT32 EntryDomainLength;
Packit 1fb8d4
	WINPR_SAM_ENTRY* entry;
Packit 1fb8d4
Packit Service 5a9772
	if (!(entry = (WINPR_SAM_ENTRY*)calloc(1, sizeof(WINPR_SAM_ENTRY))))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!SamLookupStart(sam))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (sam->line != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		length = strlen(sam->line);
Packit 1fb8d4
Packit 1fb8d4
		if (length > 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (sam->line[0] != '#')
Packit 1fb8d4
			{
Packit 1fb8d4
				DomainMatch = 0;
Packit 1fb8d4
				UserMatch = 0;
Packit 1fb8d4
Packit 1fb8d4
				if (!SamReadEntry(sam, entry))
Packit 1fb8d4
					goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
				if (DomainLength > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (entry->DomainLength > 0)
Packit 1fb8d4
					{
Packit Service 5a9772
						EntryDomainLength = (UINT32)strlen(entry->Domain) * 2;
Packit Service 5a9772
						EntryDomain = (LPWSTR)malloc(EntryDomainLength + 2);
Packit 1fb8d4
Packit 1fb8d4
						if (!EntryDomain)
Packit 1fb8d4
							goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
						MultiByteToWideChar(CP_ACP, 0, entry->Domain, EntryDomainLength / 2,
Packit Service 5a9772
						                    (LPWSTR)EntryDomain, EntryDomainLength / 2);
Packit 1fb8d4
Packit 1fb8d4
						if (DomainLength == EntryDomainLength)
Packit 1fb8d4
						{
Packit 1fb8d4
							if (memcmp(Domain, EntryDomain, DomainLength) == 0)
Packit 1fb8d4
							{
Packit 1fb8d4
								DomainMatch = 1;
Packit 1fb8d4
							}
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						free(EntryDomain);
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
						DomainMatch = 0;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					DomainMatch = 1;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (DomainMatch)
Packit 1fb8d4
				{
Packit Service 5a9772
					EntryUserLength = (UINT32)strlen(entry->User) * 2;
Packit Service 5a9772
					EntryUser = (LPWSTR)malloc(EntryUserLength + 2);
Packit 1fb8d4
Packit 1fb8d4
					if (!EntryUser)
Packit 1fb8d4
						goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
					MultiByteToWideChar(CP_ACP, 0, entry->User, EntryUserLength / 2,
Packit Service 5a9772
					                    (LPWSTR)EntryUser, EntryUserLength / 2);
Packit 1fb8d4
Packit 1fb8d4
					if (UserLength == EntryUserLength)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (memcmp(User, EntryUser, UserLength) == 0)
Packit 1fb8d4
						{
Packit 1fb8d4
							UserMatch = 1;
Packit 1fb8d4
						}
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					free(EntryUser);
Packit 1fb8d4
Packit 1fb8d4
					if (UserMatch)
Packit 1fb8d4
					{
Packit 1fb8d4
						Found = TRUE;
Packit 1fb8d4
						break;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		SamResetEntry(entry);
Packit Service 5a9772
		sam->line = strtok_s(NULL, "\n", &sam->context);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	SamLookupFinish(sam);
Packit 1fb8d4
Packit 1fb8d4
	if (!Found)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(entry);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void SamClose(WINPR_SAM* sam)
Packit 1fb8d4
{
Packit 1fb8d4
	if (sam != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		fclose(sam->fp);
Packit 1fb8d4
		free(sam);
Packit 1fb8d4
	}
Packit 1fb8d4
}