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

Viewed 1594
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?

2 Answers

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