[Samba] SMB2 CREATE + ACCESS_SYSTEM_SECURITY

Steve Tice stic6021 at gmail.com
Mon Dec 31 09:47:56 MST 2012


Jeremy Allison <jra <at> samba.org> writes:

> 
> On Tue, Dec 18, 2012 at 12:24:04PM -0600, Steve Tice wrote:
> > Can anybody provide the expected response to an SMB2 CREATE request that
> > includes ACCESS_SYSTEM_SECURITY in the DesiredAccess mask? I’m particularly
> > interested in cases where the SMB client is connected as an authenticated
> > user with administrative (superuser) privileges on the share, and has made
> > the request on a directory. Should such a client expect full (read/change)
> > access to the SACL (under any conditions)?
> > 
> > The question above is theoretical in nature. Practically speaking, does any
> > version of the Samba server respond correctly to the request described
> > above? I have a Windows application that makes such a request, and have
> > tested it against Samba server versions 3.5.10-125.el6 and 3.6.7. I keep
> > seeing a response of NT_STATUS_PRIVILEGE_NOT_HELD, and think that's not the
> > correct response when the client has superuser privileges - but perhaps my
> > expectation is wrong. If I make the same request while connected to a share
> > on a Windows server, the response is NT_STATUS_OK.
> > 
> > Is there a Samba server configuration change I could make that would affect
> > the behavior? Is there any setup work to do prior to sending the SMB2
> > CREATE request (for example, adding a privilege)?
> 
> You need to give the connected user the SeSecurity privilege.
> 
> Jeremy

Agreed. The Windows app which reproduces the behavior described above adds the 
following privileges after creating but before attempting to open the new 
directory:

SeSecurityPrivilege
SeBackupPrivilege
SeRestorePrivilege

I just noticed that my description above is incorrect. The unexpected behavior 
occurs when attempting to open (not create) a directory. Here's a copy of the 
Windows application source:
--
// Reproduce-Problem.cpp : Attempt to open a directory with 
ACCESS_SYSTEM_SECURITY
// set in the dwDesiredAccess argument.
//

#include "stdafx.h"
#include <windows.h>


static void Usage(_TCHAR *progName)
{
	wprintf(L"Usage: %s <DirectoryToCreate>\n", progName);
}

static void ReportError(char *msg)
{
	DWORD le = GetLastError();
	printf("***ERROR*** %s; error code: %d\n", msg, le);
}

static BOOL CloseProcessToken(HANDLE pt)
{
	BOOL ptClosed = CloseHandle(pt);
	if (FALSE == ptClosed) {
		printf("  Unable to CloseHandle on ProcessToken.\n");
	}
	return ptClosed;
}

static void PrintCurrentPrivileges(void)
{
	printf("Attempting to print current privileges...\n");

	HANDLE pt;
	BOOL ptOpened = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &pt);
	if (FALSE == ptOpened) {
		ReportError("  Unable to OpenProcessToken.");
		return;
	}

	DWORD rl;
	TOKEN_PRIVILEGES tokenInfo[32];
	BOOL tokenInfoFetched = GetTokenInformation(pt, TokenPrivileges, 
&tokenInfo, sizeof(tokenInfo), &rl);
	if (FALSE == tokenInfoFetched) {
		ReportError("  Unable to GetTokenInformation.");
		printf("  sizeof(tokenInfo): %u; required: %u\n", 
sizeof(tokenInfo), rl);
		CloseProcessToken(pt);
		return;
	}

	for (unsigned int i = 0; i < tokenInfo[0].PrivilegeCount; ++i) {
		TCHAR privName[256];
		DWORD pnSize = 256;
		BOOL lookedUp = LookupPrivilegeName((LPCWSTR) NULL, 
&tokenInfo[0].Privileges[i].Luid, privName, &pnSize);
		if (FALSE == lookedUp) {
			ReportError("  Unable to LookupPrivilegeName.");
			printf("  sizeof(privName): %u; required: %u\n", 
sizeof(privName), pnSize);
			CloseProcessToken(pt);
			return;
		}
		wprintf(L"Privilege %u: LUID = %s, Attributes = 0x%X\n", i, 
privName, tokenInfo[0].Privileges[i].Attributes);
	}

	CloseProcessToken(pt);
	printf("All current privileges have been printed.\n");
}

static BOOL AddPrivilege(const wchar_t *privilege)
{
	HANDLE pt;
	BOOL ptOpened = OpenProcessToken(GetCurrentProcess(), 
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &pt);
	if (FALSE == ptOpened) {
		printf("  Unable to OpenProcessToken.\n");
		return FALSE;
	}

	LUID luid;
	BOOL lookedUp = LookupPrivilegeValue((LPCWSTR) NULL, privilege, &luid);
	if (FALSE == lookedUp) {
		printf("  Unable to LookupPrivilegeValue.\n");
		CloseProcessToken(pt);
		return FALSE;
	}

	TOKEN_PRIVILEGES tp;
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	BOOL privAdjusted = AdjustTokenPrivileges(pt, FALSE, &tp, 
sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL);
	if (FALSE == privAdjusted) {
		printf("  Unable to AdjustTokenPrivileges.\n");
		CloseProcessToken(pt);
		return FALSE;
	}

	if (ERROR_NOT_ALL_ASSIGNED == GetLastError()) {
		wprintf(L"  The token does not have the privilege '%s'.\n", 
privilege);
	} 

	if (FALSE == CloseProcessToken(pt)) {
		return FALSE;
	}

	return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc != 2) {
		Usage(argv[0]);
		return 22;
	}

	printf("Attempting to reproduce failure when opening directory with 
ACCESS_SYSTEM_SECURITY set.\n");
	wprintf(L"Attempting to create directory\n  '%s'.\n", argv[1]);
	BOOL dirCreated = CreateDirectory(argv[1], (LPSECURITY_ATTRIBUTES) 
NULL);
	if (FALSE == dirCreated) {
		ReportError("Unable to create directory");
		return 1;
	}

	BOOL privilegeAdded = AddPrivilege(SE_SECURITY_NAME);
	if (FALSE == privilegeAdded) {
		ReportError("Unable to add privilege SE_SECURITY_NAME");
		return 1;
	}

	privilegeAdded = AddPrivilege(SE_BACKUP_NAME);
	if (FALSE == privilegeAdded) {
		ReportError("Unable to add privilege SE_SECURITY_NAME");
		return 1;
	}

	privilegeAdded = AddPrivilege(SE_RESTORE_NAME);
	if (FALSE == privilegeAdded) {
		ReportError("Unable to add privilege SE_SECURITY_NAME");
		return 1;
	}

	PrintCurrentPrivileges();
	//
	// This is the open directory operation that works with Windows and 
fails with Samba.
	//
	HANDLE rc = CreateFile(argv[1], (GENERIC_READ | GENERIC_WRITE | 
ACCESS_SYSTEM_SECURITY),
                           (DWORD) 0, (LPSECURITY_ATTRIBUTES) NULL, 
OPEN_EXISTING,
						   (FILE_ATTRIBUTE_NORMAL | 
FILE_FLAG_BACKUP_SEMANTICS), (HANDLE) NULL);
	if (INVALID_HANDLE_VALUE == rc) {
		ReportError("Unable to open directory via CreateFile");
		return 1;
	}

	printf("Success. The specified directory was created and opened via 
CreateFile.\n");
	return 0;
}




More information about the samba mailing list