How to give "Everyone" write permissions via C++ MFC on Windows 8? - file

Im struggling with changing permissions.
I need, on Windows 8, to change the permissions of a file to have group "Everyone" write permissions.
How to I do that?
Im trying to edit a file with C++ MFC which already exists with no "Write" (Everyone) checked, thats causing me many problems.

Your Application need to have the rights to change the permissions for the file.
#pragma comment(lib, "Advapi32.lib")
#include "Aclapi.h"
#include "Sddl.h"
#include <io.h>
#include <sys/stat.h>
void AllowEveryone(CString path)
{
PACL pDacl,pNewDACL;
EXPLICIT_ACCESS ExplicitAccess;
PSECURITY_DESCRIPTOR ppSecurityDescriptor;
PSID psid;
LPTSTR lpStr;
CString str = path;
lpStr = str.GetBuffer();
GetNamedSecurityInfo(lpStr, SE_FILE_OBJECT,DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &ppSecurityDescriptor);
ConvertStringSidToSid("S-1-1-0", &psid);
ExplicitAccess.grfAccessMode = SET_ACCESS;
ExplicitAccess.grfAccessPermissions = GENERIC_ALL;
ExplicitAccess.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
ExplicitAccess.Trustee.pMultipleTrustee = NULL;
ExplicitAccess.Trustee.ptstrName = (LPTSTR) psid;
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
SetEntriesInAcl(1, &ExplicitAccess, pDacl, &pNewDACL);
SetNamedSecurityInfo(lpStr,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDACL,NULL);
LocalFree(pNewDACL);
LocalFree(psid);
str.ReleaseBuffer();
}

Related

Program escalates itself from admin to system

I wrote a program that needs to be running as SYSTEM. I add the linker option 'UAC Execution Level' to 'requireAdministrator' and it pops the UAC like it should but now I need to escalate from admin to SYSTEM how can I do that?
I thought about opening the program's token and inject it the SYSTEM token but it is not legit way. How can I do it neatly because I know once you admin you can be SYSTEM.
Write a windows service. It will run as SYSTEM user by default.
A simple tutorial is here, but remember that installing a service requires administrator privileges.
Once you're running as administrator, here are some options:
If you know you're not going to be using GUI functions, you can create a scheduled task that runs your same exe as NT AUTHORITY\SYSTEM within a few seconds, and check within your code which account the process is running as.
Copied from a project of mine and slightly modified:
#include <Windows.h>
#include <WinNls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <ObjIdl.h>
#include <ShlGuid.h>
#include <taskschd.h>
#include <comdef.h>
#include <strsafe.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
HRESULT WINAPI CreateSchedTask(WCHAR *wszExePath)
{
ITaskService *pService = NULL;
ITaskFolder *pRoot = NULL;
ITaskDefinition *pTask = NULL;
ITaskSettings *pSettings = NULL;
IRegistrationInfo *pInfo = NULL;
ITriggerCollection *pCollection = NULL;
ITrigger *pTrigger = NULL;
ITimeTrigger *pTime = NULL;
IPrincipal *pPrincipal = NULL;
IActionCollection *pActionCollection = NULL;
IAction *pAction = NULL;
IExecAction *pExecAction = NULL;
IRegisteredTask *pRegTask = NULL;
SYSTEMTIME stNow;
FILETIME ftStart, ftEnd;
ULARGE_INTEGER ulWork;
WCHAR wFmt[100];
VARIANT vBlank = _variant_t();
if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
return E_FAIL;
}
//CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID *) &pService)))
{
return E_FAIL;
}
pService->Connect(vBlank, vBlank, vBlank, vBlank);
pService->GetFolder(SysAllocString(L"\\"), &pRoot);
pService->NewTask(0, &pTask);
pService->Release();
pTask->get_RegistrationInfo(&pInfo);
pInfo->put_Author(SysAllocString(L"TASKNAMEHERE"));
pInfo->Release();
pTask->get_Settings(&pSettings);
pSettings->put_StartWhenAvailable(VARIANT_TRUE);
pSettings->put_Enabled(VARIANT_TRUE);
pSettings->Release();
pTask->get_Triggers(&pCollection);
pCollection->Create(TASK_TRIGGER_TIME, &pTrigger);
pCollection->Release();
pTrigger->QueryInterface(IID_ITimeTrigger, (LPVOID *)&pTime);
GetLocalTime(&stNow);
SystemTimeToFileTime(&stNow, &ftStart);
ulWork.HighPart = ftStart.dwHighDateTime;
ulWork.LowPart = ftStart.dwLowDateTime;
//20000000000
ulWork.QuadPart += 300000000UI64;
ftStart.dwHighDateTime = ulWork.HighPart;
ftStart.dwLowDateTime = ulWork.LowPart;
FileTimeToSystemTime(&ftStart, &stNow);
// Note: replace -07:00 with the appropriate UTC offset for your time zone
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_StartBoundary(SysAllocString(wFmt));
ulWork.QuadPart += 900000000UI64;
ftEnd.dwLowDateTime = ulWork.LowPart;
ftEnd.dwHighDateTime = ulWork.HighPart;
FileTimeToSystemTime(&ftEnd, &stNow);
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_EndBoundary(SysAllocString(wFmt));
pTime->put_Id(SysAllocString(L"TimeTrigger"));
pTime->Release();
pTask->get_Actions(&pActionCollection);
pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
pAction->QueryInterface(IID_IExecAction, (LPVOID *)&pExecAction);
pAction->Release();
pExecAction->put_Path(SysAllocString(wszExePath));
pExecAction->Release();
pTask->get_Principal(&pPrincipal);
pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
pPrincipal->put_LogonType(TASK_LOGON_SERVICE_ACCOUNT);
pTask->put_Principal(pPrincipal);
pPrincipal->Release();
pRoot->RegisterTaskDefinition(
SysAllocString(L"System Elevation"),
pTask, TASK_CREATE_OR_UPDATE,
_variant_t(L"NT AUTHORITY\\SYSTEM"),
_variant_t(), TASK_LOGON_SERVICE_ACCOUNT,
_variant_t(L""), &pRegTask);
pRoot->Release();
pTask->Release();
pRegTask->Release();
CoUninitialize();
return S_OK;
}
INT APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nShowCmd)
{
WCHAR wUsername[100], wExePath[MAX_PATH];
GetEnvironmentVariableW(L"USERNAME", wUsername, 100);
if (!wcschr(wUsername, L'$'))
{
GetModuleFileNameW(hInstance, wExePath, MAX_PATH);
CreateSchedTask(wExePath);
}
else
{
// NOTE: MessageBox and other GUI functions won't work since the process isn't running in winsta0\default
// File I/O instead
HANDLE hLog = CreateFileW(L"C:\\Temp\\Log.txt", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten;
UINT uLen;
CHAR szBuf[100];
SetFilePointer(hLog, 0, NULL, FILE_END);
StringCchPrintfA(szBuf, 100, "Hello from %S\r\n", wUsername);
StringCbLengthA(szBuf, 100, &uLen);
WriteFile(hLog, szBuf, uLen, &dwWritten, NULL);
CloseHandle(hLog);
}
return 0;
}
Use the Windows Process API to elevate to System. I don't have much in the way of example code for this, but you can look at PAExec, an open source alternative to SysInternals PSExec tool, that allows creating new interactive processes as System.
The idiomatic way of doing this on Windows, which is create a Windows service.

winapi create shortcut failed

I want to create shortcut of a file. I found this Microsoft page that describe how to write this, and I copy that in my code to use.
But I have some problems, first it had the following error: "CoInitialize has not been called." I add this CoInitialize(nullptr); to solve the error, but I have error yet.
when I debug it, it has "Information not available, no symbols loaded for windows.storage.dll" error on this line:
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
and after execution when I see the destination path, it creates a shortcut with the name but i can't open it, and it hasn't any content.
What wrong with this?
Does the error make this problem?
I'm using VS 2012.
Code Edited:
// #include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include <iostream>
#include <shlwapi.h>
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
HRESULT CreateLink(LPCWSTR, LPCWSTR, LPCWSTR);
void wmain(int argc, wchar_t* argv[ ], wchar_t* envp[ ])
{
WCHAR lpwSource[MAX_PATH] = {0};
lstrcpyW(lpwSource, (LPCWSTR)argv[1]);
WCHAR lpwDest[MAX_PATH] = {0};
lstrcpyW(lpwDest, (LPCWSTR)argv[2]);
HRESULT hResult = 0;
hResult = CreateLink(lpwSource, lpwDest, NULL);
if (hResult == S_OK) {
printf("Shortcut was created successfully.\n");
} else {
printf("Shortcut creation failed.\n");
}
getchar();
}
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres = 0;
IShellLink* psl;
HRESULT hCoInit = 0;
hCoInit = CoInitialize(nullptr);
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres)) {
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
As I specified in my comment, I've built the code (previous version (Question VERSION #2.) from the one at answer time - which BTW was containing some string conversions that would have most likely failed on non English locales) with VStudio 2013 and ran it on my Win 10 (English) machine. It created a valid shortcut.
So, there was nothing wrong with the code (in the sense that it wouldn't work). The problem was that the output file was also having the .png extension, and when opening it, Win would attempt to use the default image viewer / editor, which would treat the file as PNG (based on its extension). That is obviously wrong, as .lnk files have their own format (as I briefly explained in [SO]: What is the internal structure of a Windows shortcut? (#CristiFati's answer)).
The solution was to properly name the shortcut (let it have the .lnk extension).
Some additional (non critical) notes about the code (current state):
No need for C++ (11) features (nullptr (also check next bullet)):
HRESULT hCoInit = CoInitialize(NULL);
Reorganize the #includes. Use the following list:
#include <windows.h>
#include <shobjidl.h>
#include <shlguid.h>
#include <stdio.h>

How to create shortcut with Win32 API and c language

I want to write a program to create a shortcut for a specific file by using win32 API in c. my IDE is visual studio 2010.
I found this page but its sample just not compile and return many errors.
I also find this code but this always create a link with Target: "D:\Desktop\㩣睜湩潤獷湜瑯灥摡攮數" and I don't know why.
can someone tell me why the sample code of Microsoft is not working or the second one return something in Chinese shape language and also with wrong and constant location for any argument?
This is my code for MSDN sample:
#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
void _tmain(int argc, TCHAR *argv[])
{
CreateLink(argv[1],__argv[2],argv[3]);
}
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
and the errors are:
1 error C1083: Cannot open include file: 'stdafx.h' and
2 IntelliSense: cannot open source file "stdafx.h"
CreateLink(argv[1],__argv[2],argv[3]);
This call looks weird. You are using argv[] for two LPCWSTR (const wchar_t *) parameters, but are using __argv[] for an LPCSTR (const char *) parameter. You should change the 2nd parameter to LPCWSTR to match the other parameters, and then use argv[] instead of __argv[].
The TCHAR-based IShellLink works with LP(C)WSTR string parameters, and LP(C)TSTR is LP(C)WSTR when compiling for Unicode. Which you are obviously doing, given that you are passing TCHAR-based argv[] values to LPCWSTR parameters, which will only compile if TCHAR is wchar_t.
IPersistFile::Save() takes only a Unicode string as input, regardless of what TCHAR maps to. You are converting the char* value from __argv[] from ANSI to Unicode, so you may as well just get a Unicode string from argv[] to begin with, and omit the call to MultiByteToWideChar() altogether.
There is no good reason to mix ANSI and Unicode strings like this. This is something the MSDN example is getting wrong.
And since your function parameters are working with Unicode strings, you should use the IShellLinkW interface directly instead of the TCHAR-based IShellLink interface.
Try this:
#include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLinkW* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
void _tmain(int argc, TCHAR *argv[])
{
if (argc > 3)
CreateLink(argv[1], argv[2], argv[3]);
}
Visual Studio generates stdafx.h and stdafx.cpp when you are using new project wizard. If Create empty project checkmark is marked, it will not generate them. These files are used to build a precompiled header file Projname.pch and a precompiled types file Stdafx.obj
For small projects you can eventually remove #include "stdafx.h", but it would be better to create new project with Create empty project unmarked.

Setting a created file permissions

I would like to know how can I set the permissions of a windows file?
Something like chmod(), instead it's a windows.
For example:
Create the file example.exe, and set its permissions in a way that only the owner
of this file can execute it.
I read that there's an ACL API for c somewhere, but I didn't quite get it.
It's a lot more work than chmod!
I have taken the liberty of creating the file AFTER creating the security descriptor - it is safer. If you do things the other way around (create the file first) then there is a short time when the required access is not set.
Try this:
#include <windows.h>
#include <AclAPI.h>
#include <Lmcons.h>
int main()
{
SECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea[1];
PACL pDacl;
SECURITY_ATTRIBUTES sa;
TCHAR UserBuffer[UNLEN+1];
DWORD ulen = UNLEN;
GetUserName(UserBuffer, &ulen);
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
BuildExplicitAccessWithName(&ea[0], UserBuffer, GENERIC_EXECUTE,
SET_ACCESS, NO_INHERITANCE);
SetEntriesInAcl(1, ea, NULL, &pDacl);
SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
CreateFileA("c:\\temp\\example.exe", GENERIC_EXECUTE, 0, &sa,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
return 0;
}

How to retrieve current Windows user login using C?

I'm new to C. How can i retrieve the current user logged into Windows using C?
I know you can do this in C++ by Environment::UserName, but have no idea how to do it in C.
Thanks :)
You can use GetUserName:
#include <windows.h>
#include <Lmcons.h>
TCHAR username[UNLEN+1];
DWORD len = UNLEN+1;
if (GetUserName(username, &len))
{
//do something with username
}

Resources