Are Windows Services Restricted from Reading from %WINDIR% (C:\Windows)? - windows-7

I've got an application running as a Windows service that wants to read a file specified by a relative path. Since the service is running under C:\Windows\system32 (on Server 2003 and Windows 7), I figure it should be reading the file from there. However, the file read always fails.
I put together some simple test code to try to open a file for reading, using an absolute path. While the service succeeds for files such as C:\Temp\foo.txt, it always fails for files like C:\Windows\foo.txt and C:\Windows\system32\foo.txt . GetLastError() returns 2.
Am I running into an access issue? I couldn't find authoritative documentation on this. Is there any workaround?
Update:
The file test code is generic and straightforward:
std::ofstream out;
//...
std::string fileName("C:\\Windows\\system32\\Foo.txt");
hFile = CreateFile(fileName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
out << "Could not create file handle! (" << GetLastError() << ")" << std::endl;
}
else {
out << "Successfully opened file!" << std::endl;
CloseHandle(hFile);
}

Try running the windows service from Local System account. By default the service may be running from "Network Service" account.
To change the settings, Open Windows Service Manager (Run-> services.msc) and double-click your service. On property window select 2nd Tab "Log On" and change it to run with Local System account.

Error code 2 is ERROR_FILE_NOT_FOUND so it's likelier that the path you give simply does not exist or the file does not exist in that path. Without the relevant flags from CreateFile it's hard to give you a better answer.
But generally - under default conditions - a service would be allowed to read in that folder.
One more thing came to mind. How do you obtain the path (C:\Windows in your case)? The proper means are to use the API (e.g. GetWindowsDirectory) for this and not hardcode it.

Related

Setting NVRAM variable using WinAPI

I'm trying to setup my own NVRAM variable (nv+rt+bs) using WinAPI (SetFirmwareEnvironmentVariable). It fails with my variable and successfully completed with BootOrder. What do I do wrong? Is it possible to setup my own variable using WinAPI?
I'm trying to setup my variable using this code
void setMyNVRAM()
{
// here I setup SE_SYSTEM_ENVIRONMENT_NAME privilege
uint16_t value = 0x5aa5;
if (!SetFirmwareEnvironmentVariable(L"MY_VARIABLE",
L"{12345678-1234-1234-1234-123456789012}", &value, sizeof (value)))
{
std::cout << "error while settin up MY_VARIABLE. Error code: "
<< GetLastError() << std::endl;
}
else
{
std::cout << "success" << std::endl;
}
}
SetFirmwareEnvironmentVariable returns 0 and GetLastError() returns 5 (access denied). I also tried to write into BootOrder variable and it was successfully completed.
According to the instructions on the MSDN.
To write a firmware environment variable, the user account that the
app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME
privilege. A Universal Windows app must be run from an administrator
account and follow the requirements outlined in Access UEFI firmware
variables from a Universal Windows App.
Customizing user privileges for an account in Windows
A similar discussion: How i can set firmware environment variable in UEFI driver

In the Win32 API, given a PID, how can I determine path on disk to the executable?

In Win32, I've obtained a process id for a certain running process. Now I'd like to determine the path on the file system where the executable for the process resides.
eg. if "tasklist" shows the "image name" to be "foobar.exe" and the PID to be 1234. The executable is located in c:\Program Files (x86)\Acme Corp\foobar.exe
Which Win32 API call will accept the PID 1234 and give me the path "c:\Program Files (x86)\Acme Corp\foobar.exe"?
You should open the process using OpenProcess to get a process handle and then use the handle to get path using GetModuleFileNameEx API function.
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, _PID_);
if (hProcess)
{
TCHAR path[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, path, sizeof(path)))
{
MessageBox(0, path, "The path", MB_ICONINFORMATION);
}
CloseHandle(hProcess);
}
If I remember correctly, using "PROCESS_QUERY_INFORMATION | PROCESS_VM_READ" will be enough to get process handle for path retrieve. If it failed, use PROCESS_ALL_ACCESS then.

compiling less to css from classic asp / vbscript

I'm trying to get classic asp / vbscript to run a less compiler (https://github.com/duncansmart/less.js-windows). Running the exact command from a real cmd prompt on the server works fine. So it's going to be one of those permissiony type things. My server is Win2003 x86 / IIS6.
<%
' foo.asp
outpath = "c:\inetpub\wwwroot\site\less"
cmd = "c:\less.js-windows-v1.6.2\lessc.cmd"
Set Shell = server.createobject("WScript.Shell")
nodeCommand = cmd & " " & outPath & "\app.less " & outPath & "\app.css"
errCode = Shell.Run(nodeCommand, 0, True)
' errcode = 1
%>
foo.asp is running somewhere on the web server, anonymously.
cmd.exe has had iusr_server added so that it has read and execute permission.
c:\less.js-windows-v1.6.2 has had iusr_server added with read/execute as well.
I've granted everyone permission to modify files in side c:\inetpub\wwwroot\site\less to make sure it's not a permission thing.
I have tried modifying my command to include CMD /C ahead of the command file name.
Use the following process:
Stop the server
Change relative paths to full paths for all files
Reconfigure the IUSR to be you
Restart the server

Why ptrace doesn't attach to process after setuid?

I have a problem with my Linux daemon program. It starts with root privileges, does some configuration, then permanently drops privileges by switching to some user and group and continues working. The switch to the non-privileged user is done like this:
void switch_to_user_group(std::string const& username, std::string const& groupname)
{
// Switch to user/group
gid_t gid = getgid();
if (!groupname.empty())
{
gid = get_group_id(groupname);
if (0 != setgid(gid))
{
std::cout << "Failed to switch to group " << gid << std::endl;
std::abort();
}
}
if (!username.empty())
{
uid_t uid = get_user_id(username);
if (initgroups(username.c_str(), gid) != 0)
{
std::cout << "initgroups failed" << std::endl;
std::abort();
}
if (0 != setuid(uid))
{
std::cout << "Failed to switch to user " << uid << std::endl;
std::abort();
}
}
}
The switch performs correctly, I can see the process in ps and top running under my user. The problem is that I can't attach to this process from gdb, even after it has dropped the privileges. The output is:
Attaching to process 15716
Could not attach to process. If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
I'm running gdb under the same user the process switched to, and I am able to attach to other processes that were initially started under under that user. I tried this on Kubuntu 13.10 (YAMA is disabled), Debian 6 and 7 with the same result.
So my questions are:
Why can't ptrace attach to a process that has the same effective and real UID as gdb?
Is it possible to drop privileges of my program in a way so that I can attach to it from the unprivileged gdb? How?
Thanks.
I found the solution on my own.
There is a 'dumpable' flag in the kernel for every process. When the process performs setuid or setgid (at least, in my case, when the process drops privileges) this flag gets cleared and normal users can't attach to this process with a debugger, and the process crashes also do not produce a crash dump. This is done for security reasons to protect any sensitive data obtained with elevated privileges that may be in the process memory.
To solve the problem the process can explicitly allow debugging by setting the 'dumpable' flag to 1.
prctl(PR_SET_DUMPABLE, 1);
This has to be done after the setgid/setuid calls.

Why is the read-only attribute set (sometimes) for files created by my service?

NOTE: This is a complete re-write of this question. I'd previously conflated some ACL issues with the problem I'm hunting, which is probably why there were no answers.
I have a windows service that uses the standard open/close/write routines to write a log file (it reads stuff from a pipe and stuffs it into the log). A new log file is opened each day at midnight. The system is Windows XP Embedded.
The service runs as the Local System service (CreateService with NULL for the user).
When the service initially starts up, it creates a log file and writes to it with no problems. At this point everything is OK, and you can restart the service (or the computer) with no issues.
However, at midnight (when the day changes), the service creates a new log file and writes to it. The funny thing is, this new log file has the 'read only' flag set. That's a problem because if the service (or the computer) restarts, the service can no longer open the file for writing.
Here's the relevant information from the system with the problem having already happened:
Directory of C:\bbbaudit
09/16/2009 12:00 AM <DIR> .
09/16/2009 12:00 AM <DIR> ..
09/16/2009 12:00 AM 437 AU090915.ADX
09/16/2009 12:00 AM 62 AU090916.ADX
attrib c:\bbbaudit\*
A C:\bbbaudit\AU090915.ADX <-- old log file (before midnight)
A R C:\bbbaudit\AU090916.ADX <-- new log file (after midnight)
cacls output:
C:\ BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CREATOR OWNER:(OI)(CI)(IO)F
BUILTIN\Users:(OI)(CI)R
BUILTIN\Users:(CI)(special access:)
FILE_APPEND_DATA
BUILTIN\Users:(CI)(IO)(special access:)
FILE_WRITE_DATA
Everyone:R
C:\bbbaudit BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CFN3\Administrator:F
CREATOR OWNER:(OI)(CI)(IO)F
Here's the code I use to open/create the log files:
static int open_or_create_file(char *fname, bool &alreadyExists)
{
int fdes;
// try to create new file, fail if it already exists
alreadyExists = false;
fdes = open(fname, O_WRONLY | O_APPEND | O_CREAT | O_EXCL);
if (fdes < 0)
{
// try to open existing, don't create new file
alreadyExists = true;
fdes = open(fname, O_WRONLY | O_APPEND);
}
return fdes;
}
I'm having real trouble figuring out how the file is getting that read-only flag on it. Anyone who can give me a clue or a direction, I'd greatly appreciate it.
Compiler is VC 6 (Yea, I know, it's so far out of date it isn't funny. Until you realize that we're just now upgraded to XPE from NT 3.51).
The Microsoft implementation of open() has an optional third argument 'pmode', which is required to be present when the second argument 'oflag' includes the O_CREAT flag. The pmode argument specifies the file permission settings, which are set when the new file is closed for the first time. Typically you would pass S_IREAD | S_IWRITE for pmode, resulting in an ordinary read/write file.
In your case you have specified O_CREAT but omitted the third argument, so open() has used whatever value happened to be on the stack at the third argument position. The value of S_IWRITE is 0x0080, so if the value in the third argument position happened to have bit 7 clear, it would result in a read-only file. The fact that you got a read-only file only some of the time, is consistent with stack junk being passed as the third argument.
Below is the link for the Visual Studio 2010 documentation for open(). This aspect of the function's behaviour has not changed since VC 6.
http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx
Well, I have no idea what the underlying problem is with the 'open' APIs in this case. In order to 'fix' the problem, I ended up switching to using the Win32 APIs for file management (CreateFile, WriteFile, CloseHandle).

Resources