Why are Administrator privileges required to create a symlink on Windows? - windows

use std::os::windows::fs;
// https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html
use std::io::*;
use std::io::{self, Read, Stdin};
fn input_from() -> io::Result<()> {
let mut buffer = String::new();
let mut stdin = io::stdin(); // We get `Stdin` here.
stdin.read_to_string(&mut buffer)?;
Ok(())
}
fn main() -> std::io::Result<()> {
let mut shortcut_dir = String::from("D:\\winr\\");
println!("Your script path:");
let mut buffer1 = String::new();
let mut stdin = io::stdin();
stdin
.read_line(&mut buffer1)
.expect("error: unable to read user input");
buffer1.pop();
println!("Your shortcut name:");
let mut buffer2 = String::new();
let mut stdin: Stdin = io::stdin();
stdin
.read_line(&mut buffer2)
.expect("error: unable to read user input");
println!("buffer1 is:{:?}", buffer1);
buffer2.pop();
let mut buffer2 = &buffer2[..];
println!("buffer2 is:{:?}", buffer2);
shortcut_dir.push_str(&buffer2);
let mut buffer3 = shortcut_dir;
println!("buffer3 is:{:?}", buffer3);
fs::symlink_file(buffer1, buffer3)?;
Ok(())
}
It complains:
Error: Os { code: 1314, kind: Other, message: "A required privilege is not held by the client" }
error: process didn't exit successfully: `target\debug\ssdkqn.exe` (exit code: 1)
I use Windows. When I run this script in Administrator mode, the problem goes away. Why does it need the Administrator privilege to create a symlink?

This is a requirement of Windows, unless you are running in Developer Mode on Windows 10.
Unix has had symbolic links since 4.2 BSD. Their behavior is well known and well understood and they are widely used. Any Unix programmer knows about symbolic links.
However, when they're available, there are certain sets of security problems that a developer must be aware of. For example, there are time-of-check/time-of-use race conditions where the destination of a symlink can be changed, so it isn't safe to assume that just because you've checked the path that it means the destination won't change. Experienced Unix developers know about these and consider them carefully.
Windows added symlinks relatively late on (Windows Vista for userspace), and as such, developers were not used to using them. There was concern that enabling them would cause older programs or programs written by developers unfamiliar with symbolic links to have security issues, some of which could not be fixed. As such, it was decided to restrict the use of symbolic links to the administrator unless the user has the Create Symbolic Links privilege.
If you are on Windows 10, you can enable Developer Mode and restart, and you will be able to create symbolic links. You can also create symbolic links under WSL without privileges.

If a workaround is acceptable for you, Windows supports hard links and directory junctions, both of which can be created without administrative privileges. Unfortunately symlink_dir() and symlink_file() do not seem to allow junction or hard links.
if source.is_dir() {
std::process::Command::new("cmd")
.arg("/C")
.arg("mklink")
.arg("/J")
.arg(destination)
.arg(source)
.output()?;
} else {
std::process::Command::new("cmd")
.arg("/C")
.arg("mklink")
.arg("/H")
.arg(destination)
.arg(source)
.output()?;
}

Related

building a game on solana

I am trying to build a simple game for testing where you enter sol amount and the program just sends double the amount (not on mainnet, ofc) but I just don't get some stuff about solana.
For now i don't have the code cause I am trying to understand the workflow
Here i brainstormed how my program will look like
I don't know how to create this treasury wallet account? Will it be owned by my program?
Could you also show me a piece of code, like this play function that will allow me to interact with it?
My guess rn is that i will just write the public address, and then write a from/to function in the program to do the transaction. Is it correct?
I will be using anchor btw. Thanks for the help :)
Your treasury wallet, since it's holding SOL, can simply be a PDA derived using your program id, with no data in it. It will still be owned by the system program, but since it's derived from your program, only your program can sign for it. In your program, you'll do something like:
fn transfer_one_token_from_escrow(
program_id: &Pubkey,
accounts: &[AccountInfo],
) -> ProgramResult {
// User supplies the destination
let alice_pubkey = accounts[1].key;
// Iteratively derive the escrow pubkey
let (escrow_pubkey, bump_seed) = Pubkey::find_program_address(&[&["escrow"]], program_id);
// Create the transfer instruction
let instruction = token_instruction::transfer(&escrow_pubkey, alice_pubkey, 1);
// Include the generated bump seed to the list of all seeds
invoke_signed(&instruction, accounts, &[&["escrow", &[bump_seed]]])
}
You'll likely need to do some more research to understand exactly how to implement a lot of these bits. Here are some resources:
Solana Account Model: https://solanacookbook.com/core-concepts/accounts.html#account-model
Using PDAs: https://docs.solana.com/developing/programming-model/calling-between-programs#using-program-addresses
PDAs with Anchor: https://book.anchor-lang.com/chapter_3/PDAs.html

How to simulate a TTY while also piping stdio?

I'm looking for a cross-platform solution for simulating a TTY (PTY?) in Rust while also piping stdio.
The frontend is based on web technologies where an interactive terminal is shown. Users can run commands and all their inputs will be sent to the Rust backend, where the commands get executed. Std{in,out,err} are sent back end forth to allow for an interactive experience.
Here's a simplified example (piping only stdout):
let mut child = Command::new(command)
.stdout(Stdio::piped())
.spawn()
.expect("Command failed to start");
loop {
let read = reader.read(&mut chunk);
if let Ok(len) = read {
if len == 0 {
break;
}
let chunk = &chunk[..len];
send_chunk(chunk); // send chunk to frontend
} else {
eprintln!("Err: {}", read.unwrap_err());
}
}
Currently, running the command tty prints: not a tty, but ideally, it should output a file name (e.g /dev/ttys002). And programs, such as atty should return true.
Running only the backend in a terminal, with stdio inherited works, but then I can't send the stdio back to the frontend.
Define "cross platform". As far as PTYs is concerned, those are pseudo devices supported by the kernel, complete with ioctls and everything. As a matter of fact a lot of the things your terminal emulator will have to do, is implementing the receiving end of those ioctls.
As long as you're on a machine with the BSD API (which includes Linux), the best course of action would be to openpty and roll with that. If you want to be portable to non BSD PTY capable systems, you'll have to hook the tty functions in the child process (by preloading a helper library).

How to do non-buffered writes to stdout?

I need 20 'H' characters to appear at 1 second intervals. This program displays nothing till the end
use std::io::Write;
use std::time::Duration;
fn main() {
let ch = 'H' as u8;
for _ in 0..20 {
let buff = vec![ch];
std::io::stdout().write(&buff).unwrap();
std::io::stdout().flush().unwrap();
std::thread::sleep(Duration::from_millis(1000));
}
}
This equivalent C++ program works fine
#include <iostream>
#include <Windows.h>
int main()
{
for(int i = 0; i < 20; i++)
{
std::cout << (char)'H';
std::cout.flush();
Sleep(1000);
}
}
I tried crossterm and could not make that work but it looks really interesting. I tried crossterm_winapi which has direct calls to WriteConsoleW in it, but then I got no output at all.
I am going to answer my own question because I went through a lot of discovery here and I am sure other will find it useful.
BTW - the original question got derailed in the comments section explaining why my c++ equivalent (without flush) worked / didnt work / shouldnt work / might work. Lets ignore that - I added flush.
Firstly Debuggers
vscode and Vs2019 do stuff with stdout in order to try to be helpful. Most of the time it is helpful but not in this case
vscode steals stdout to make it appear in the terminal window. Normally this would be directed to a console window. It also imposes its own buffering regardless of what you do with flushing etc.
The real end for my rust code is a c# gui application calling the rust code as a cdylib. Originally this dll was written in c++. When running a GUI app vs2019 also steals stdout (not the case for console apps, nothing to do with my mini c++ code above) so that it can display it the 'output' window.
Both these behaviors disappear if the app is run outside the debugger of course. But that makes debugging tough.
This of course confused a lot of my investigation because I was not seeing output in various cases because I was looking in the wrong place.
Solution 1
The original code in my question actually works fine if you run it via cargo run from a console window. Excellent. vscode buffers it all up if ran from inside it - so dont do that.
Problem 2, no console window
Windows gui app launch 'knows' that this program doesnt need a console window so stdout is piped to a bitbucket. I had the same issue in the c# -> c++ version. The secret here is to create a console window and reattach stdout to it.
solution 2
Reaches for winapi crate.
unsafe {
let ff = winapi::um::wincon::FreeConsole();
let ret = winapi::um::consoleapi::AllocConsole();
let err = winapi::um::errhandlingapi::GetLastError();
};
FreeConsole just to detach if we are connected to something weird. Then AllocConsole creates a console window and connects the process to it, not wired up to anything yet though. So now wire the new console window to stdout:
let file = OpenOptions::new().write(true).read(true).open("CONOUT$").unwrap();
unsafe{
let err = winapi::um::processenv::SetStdHandle(winapi::um::winbase::STD_OUTPUT_HANDLE, file.as_raw_handle());
}
CONOUT$ is special name for the output buffer of the connected console window. SetStdHandle connects it to stdout.
Now a new window pops up next to the gui and all stdout writes appear there - whoo hoo.
This also works for vscode debugging. A new 'dos' window appears and the stdout appears there. An added bonus
Problem 3 need lower level access
In my original PDP engine in c++ I was not happy still using std::cout, I needed to get as close the the windows console subsystem as possible (I am emulating the behavior of a raw physical device for the PDP). So I decided to use direct windows IO in this new version
Solution 3
So still AllocConsole and open CONOUT$ but call the Console write directly
let buff: [u8; 1] = [ch];
let ptr: *const c_void = buff.as_ptr() as *const _ as *const c_void;
let mut cells_written: u32 = 0;
// write to console
unsafe {
WriteConsoleA(
file.as_raw_handle(),
ptr,
1,
&mut cells_written,
NULL,
) ;
};
file is the handle return by open of CONOUT$
Works nicely. I know I will need to do the same for stdin / CONIN$ at some point

Win32 - Launching a highestAvailable child process as a normal user process

Suppose your Windows user account is in the Admin group, UAC is enabled, and you're running some program A with normal user privileges. A never asks for elevation and never receives it. Now suppose A wants to launch program B, which has highestAvailable in its manifest.
If A calls CreateProcess(B), this will fail with error 740 ("elevation required")
If A calls ShellExecuteEx(B), Windows will display a UAC box asking to run B elevated. The user can say Yes, in which case B will run elevated, or No, in which case the launch will fail.
My question is: is there any way to achieve a third option, where we simply launch B without elevation?
It seems like this should be possible in principle, since "highestAvailable" means that B prefers to run with elevation but is perfectly capable of running in normal user mode. But I can't figure out any way to accomplish it. I've tried all sorts of things with tokens and CreateProcessAsUser(), but it all seems to come down to this: "highestAvailable" seems to unalterably refer to the latent privileges inherent in the user account, not the actual privileges expressed in any explicitly constructed token.
I'm hoping that there actually is some way to use CreateProcessAsUser() to do this, and that I'm just missing the trick for properly constructing the token.
Update - solved: the __COMPAT_LAYER=RunAsInvoker solution below works nicely. One caveat, though. This coerces the subprocess to run "as invoker" unconditionally: it applies even if the exe being invoked specifies "requireAdministrator" in its manifest. I think the original "elevation required" error is generally preferable when the exe specifies "requireAdministrator". The whole reason I wanted the RunAsInvoker behavior for programs marked with "highestAvailable" is that such programs are expressly saying "I can function properly in either mode" - so let's go ahead and run in normal user mode when it's inconvenient to use Admin mode. But "requireAdministrator" is a different matter: such programs are saying "I can't function properly without elevated privileges". It seems better to fail up front for such programs than to force them to run un-elevated, which might make them encounter privilege/access errors that they're not properly programmed to handle. So I think a complete, general-purpose solution here would require checking the application manifest, and only applying the RunAsInvoker coercion if the manifest says "highestAvailable". An even completer solution would be to use one of the techniques discussed elsewhere to give the caller an option to invoke UAC when presented with a "requireAdministrator" program and offer the user a chance to launch it elevated. I can imagine a CreateProcessEx() cover with a couple of new flags for "treat process privileges as highest available privileges" and "invoke UAC if elevation is required". (The other approach described below, hooking NTDLL!RtlQueryElevationFlags() to tell CreateProcess() that UAC is unavailable, has exactly this same caveat with respect to requireAdministrator programs.)
(It's probably telling that the Windows shell doesn't even offer a way to do this... launching B directly from the shell would give you the UAC box that lets you either launch with Admin privs or not launch at all. If there were any way to accomplish it, the UAC box might offer a third button to launch without privileges. But then again that could just be a UX decision that the third option is too confusing for civilians.)
(Note that there are quite a lot of posts on StackOverflow and the Microsoft dev support sites asking about a very similar-seeming scenario that unfortunately doesn't apply here. That scenario is where you have a parent program that's running elevated, and it wants to launch a non-elevated child process. The canonical example is an installer, running elevated as installers tend to do, that wants to launch the program it just installed, at normal user level, just before it exits. There's lots of posted code about how to do that, and I've based my attempts on some of those techniques, but this is really a different scenario and the solutions don't work in my situation. The big difference is that the child program they're attempting to launch in this case isn't marked with highestAvailable - the child is just a normal program that would launch without any UAC involvement under normal circumstances. There's another difference as well, which is that in those scenarios, the parent is already running elevated, whereas in my scenario the parent is running as normal user level; that changes things slightly because the parent process in this other scenario has access to a few privileged operations on tokens that I can't use because A isn't itself elevated. But as far as I can tell those privileged token operations wouldn't help anyway; it's the fact that the child has the highestAvailable flag that's the key element of my scenario.)
Set the __COMPAT_LAYER environment variable to RunAsInvoker in your process. I don't think this is formally documented anywhere but it works all the way back to Vista.
You can also make it permanent by setting the it under the AppCompatFlags\Layers key in the registry.
the possible hack solution call CreateProcess from not elevated admin user (restricted admin) for exe with highestAvailable in manifest (or from any not elevated user for requireAdministrator exe) - this is hook RtlQueryElevationFlags call and set returned flags to 0.
this is currently work, but of course no any grantee that will be work in next versions of windows, if something changed. however as is.
for hook single time api call - we can set hardware breakpoint to function address and VEX handler . demo working code:
NTSTATUS NTAPI hookRtlQueryElevationFlags (DWORD* pFlags)
{
*pFlags = 0;
return 0;
}
PVOID pvRtlQueryElevationFlags;
LONG NTAPI OnVex(::PEXCEPTION_POINTERS ExceptionInfo)
{
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP &&
ExceptionInfo->ExceptionRecord->ExceptionAddress == pvRtlQueryElevationFlags)
{
ExceptionInfo->ContextRecord->
#if defined(_X86_)
Eip
#elif defined (_AMD64_)
Rip
#else
#error not implemented
#endif
= (ULONG_PTR)hookRtlQueryElevationFlags;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
ULONG exec(PCWSTR lpApplicationName)
{
ULONG dwError = NOERROR;
if (pvRtlQueryElevationFlags = GetProcAddress(GetModuleHandle(L"ntdll"), "RtlQueryElevationFlags"))
{
if (PVOID pv = AddVectoredExceptionHandler(TRUE, OnVex))
{
::CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
ctx.Dr7 = 0x404;
ctx.Dr1 = (ULONG_PTR)pvRtlQueryElevationFlags;
if (SetThreadContext(GetCurrentThread(), &ctx))
{
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
if (CreateProcessW(lpApplicationName, 0, 0, 0, 0, 0, 0, 0, &si,&pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
dwError = GetLastError();
}
ctx.Dr7 = 0x400;
ctx.Dr1 = 0;
SetThreadContext(GetCurrentThread(), &ctx);
}
else
{
dwError = GetLastError();
}
RemoveVectoredExceptionHandler(pv);
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
return dwError;
}

Is it possible to open a file allowing another processes to delete this file?

It seems the default os.Open call allows another processes to write the opened file, but not to delete it. Is it possible to enable deletion as well? In .NET this can be done using FileShare.Delete flag, is there any analog in Go?
os.Open will get you a file descriptor with flag O_RDONLY set; that means read only. You can specify your own flag by using os.OpenFile
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
None of these modes, however, will allow you to have multiple writers on a single file. You can share the file descriptor by exec-ing or fork-ing but naively writing to the file from both processes will result in the OS deciding how to synchronise those writes -- which is almost never what you want.
Deleting a file while a process has a FD on it doesn't matter on unix-like systems. I'll go ahead and assume Windows won't like that, though.
Edit given the windows tag and #Not_a_Golfer's excellent observations:
You should be able to pass syscall.FILE_SHARE_DELETE as a flag to os.OpenFile on Windows, if that is what solves your problem.
If you need to combine several flags you can do so by or-ing them together:
syscall.FILE_SHARE_DELETE | syscall.SOME_OTHER_FLAG | syscall.AND_A_THIRD_FLAG
(note, however, that it's up to you to build a coherent flag)

Resources