171

I'm trying to run a bash script in Cygwin.

I get Must run as root, i.e. sudo ./scriptname errors.

chmod 777 scriptname does nothing to help.

I've looked for ways to imitate sudo on Cygwin, to add a root user, since calling "su" renders the error su: user root does not exist, anything useful, and have found nothing.

Anyone have any suggestions?

Ken Bellows
  • 6,711
  • 13
  • 50
  • 78
  • hello KenB, could you give us more detail on `what` script you are trying to run? There is no equivalent to 'sudo' inside a cygwin shell - the rights are the ones from the win user that launched the cygwin shell, so KyleWpppd link is good to avoid errors such as "sudo unknown command". In your case sounds like it's a specific issue with the script you want to execute. – Stefano Feb 04 '11 at 13:02
  • 1
    Honestly, this is an issue long past, and I don't actually remember what the script was. Thanks for the interest, though. – Ken Bellows Feb 15 '11 at 02:14
  • Related question here : http://superuser.com/questions/122418/theres-no-sudo-command-in-cygwin and here : http://stackoverflow.com/questions/22527668/sudo-command-not-found-on-cygwin – Benj Aug 03 '16 at 09:30

18 Answers18

252

I answered this question on SuperUser but only after the OP disregarded the unhelpful answer that was at the time the only answer to the question.

Here is the proper way to elevate permissions in Cygwin, copied from my own answer on SuperUser:

I found the answer on the Cygwin mailing list. To run command with elevated privileges in Cygwin, precede the command with cygstart --action=runas like this:

$ cygstart --action=runas command

This will open a Windows dialogue box asking for the Admin password and run the command if the proper password is entered.

This is easily scripted, so long as ~/bin is in your path. Create a file ~/bin/sudo with the following content:

#!/usr/bin/bash
cygstart --action=runas "$@"

Now make the file executable:

$ chmod +x ~/bin/sudo

Now you can run commands with real elevated privileges:

$ sudo elevatedCommand

You may need to add ~/bin to your path. You can run the following command on the Cygwin CLI, or add it to ~/.bashrc:

$ PATH=$HOME/bin:$PATH

Tested on 64-bit Windows 8.

You could also instead of above steps add an alias for this command to ~/.bashrc:

# alias to simulate sudo
alias sudo='cygstart --action=runas'
Muhammad Usman Bashir
  • 1,441
  • 2
  • 14
  • 43
dotancohen
  • 30,064
  • 36
  • 138
  • 197
  • 13
    Excellent answer. With some tweaks to your bash code (below), I was able to run an elevated command from the command line. Here's the change I needed to make your code work: `cat << 'EOF' > ~/bin/sudo\n #!/usr/bin/bash\n cygstart --action=runas "$@"\n EOF` (I can't figure out how to insert newlines in this comment, so I've added '\n's to the code) The rest from the PATH=... onward is fine. – josmith42 Jan 10 '14 at 14:22
  • @josmith42: Thank you! I don't see the difference between my script and yours. What is the difference? – dotancohen Jan 10 '14 at 14:27
  • It's mainly the first line: I have `cat << 'EOF' > ~/bin/sudo`. And I added `EOF` below the `cygstart` line to close off the here document. – josmith42 Jan 10 '14 at 14:31
  • 3
    Oh, I see! If I'm not mistaken, that is your way of writing the file to disk, instead of opening a text editor. Nice, thank you! I did not know how to use heredocs in Bash! – dotancohen Jan 10 '14 at 15:46
  • $ cat ~/bin/sudo cat: /home/MyName/bin/sudo: No such file or directory What could be the issue there? I have a usr/local/bin and usr/bin in my path – user1530318 Jan 31 '14 at 19:45
  • You need to create that file with the contents that you see. The `cat` command just shows you what I have in the file (i.e. what you need to put in the file). – dotancohen Jan 31 '14 at 23:29
  • Could you reword the answer to make that clear? The answer is very helpful but I, too, was confused by how you presented it. – Michael Scheper May 02 '14 at 04:40
  • I have edited the answer to make things clearer for those unfamiliar with Unix concepts and commands. If anything else is unclear, let me know and I'll try to elucidate. Thanks! – dotancohen May 02 '14 at 06:18
  • This solution doesn't appear to pick up the Cygwin path, only the Windows path, if the command you run is "bash" to get an elevated bash. Luckily you can use the full path still, if you need to e.g., pipe the output of an elevated command through grep, for example. – JeeBee Oct 23 '14 at 10:44
  • Removing the quotes, i.e., `cygstart --action=runas $@` works better for most of my use cases, since I want the command to be able to parse separate arguments. – katriel Oct 21 '15 at 07:20
  • @katriel what is the difference between the quotes version and the no-quotes version? I see it works better for my use cases as well, but I don't understand why. – Olivier Grégoire Feb 04 '16 at 13:07
  • @OlivierGrégoire Everything within quotes is treated as a single token by bash, so I expect (haven't tested) that it will try to treat everything in the quotes as the command name, rather than taking the first token as the command and the rest as arguments. Example: `cygstart --action=runas "ls /bin"` will try to find a command named "ls bin"; `cygstart --action=runas ls /bin` will instead try to find a command named "ls" and pass it the argument "/bin" – Ken Bellows Feb 10 '16 at 14:11
  • @KenB i just tested and I could do for eg `sudo taskkill -f -im iexplore.exe` with the quoted version. So I'm not sure there is any difference. Someone who really knows Bash could say otherwise though – deed02392 Mar 24 '16 at 10:10
  • 10
    The problem with this is that it creates a whole new terminal window (usually conhost). The output isn't inlined into the current terminal. – CMCDragonkai Apr 24 '16 at 07:19
  • 1
    The only way to run things like `ls` is to wrap it in a long running process like mintty or bash or zsh too. But it all appears in a separate terminal. Which at this point, I could have just opened it via the GUI using ConEMU. – CMCDragonkai Apr 24 '16 at 07:32
  • 1
    Without the quotes, even quoted arguments are split in spaces again, @katriel. With the quotes, `"$@"` expands to something like `"$1" "$2" "$3" ...` and without, `$@` expands to `$1 $2 $3...`. – Palec Oct 03 '16 at 10:36
  • 1
    Regarding the `$@` vs `"$@"` debate... The proper bash way is **with** the quotes as otherwise spaces within arguments will cause such to become multiple arguments. `"$@"` is special; see man page. However, it seems that either `cygstart` or `runas` do not do things in the bash way and so no option works completely correctly. To verify, compare `sudo bash -c 'ls;read'` vs `sudo bash -c 'ls; read'` (note space after semicolon). The first works (and pauses waiting for ) while the second fails. The extra space after the semicolon is breaking the passed command. – Brian White Mar 22 '17 at 14:03
  • Note: `command` needs to be replaced with *the actual command you want to run*, and for a noob like me, I missed that... – jjjjjj Jun 25 '17 at 01:10
  • Unfortunately, because of opening into another terminal, piped commands will not work, I wanted to run a `netstat -ab | grep ...` – lcfd Mar 16 '18 at 09:00
  • So, the normal "switch user" (su) program allows one to pick the target user. Is there any way to do that cygwin style using this method? – Erik Bennett Mar 22 '21 at 19:20
  • At present, this seems only able to run Windows executables, not the Unix executables provided in cygwin. E.g., "sudo cpan" and "sudo `which cpan` both produce "Unable to start 'C:\cygwin64\bin\cpan': There is no application associated with the given file name extension." – Phil Goetz Jul 15 '21 at 02:15
51

You probably need to run the cygwin shell as Administrator. You can right click the shortcut and click run as administrator or go into the properties of the shortcut and check it in the compatability section. Just beware.... root permissions can be dangerous.

Matt Williamson
  • 39,165
  • 10
  • 64
  • 72
  • 1
    In the three years since this question has been asked without a good answer as opposed to this workaround, [I've found the correct way to raise permissions for a single command in the extant Cygwin window](http://stackoverflow.com/a/21024592/343302) in the answer below. Thus, it functions exactly like `sudo` in Linux. – dotancohen Jan 09 '14 at 15:44
  • Worked for me on Win10 64. Had to change ownership of files downloaded from a server with rsync. `chown --changes --verbose --recursive [USER] /cygdrive/c/[PATH TO FOLDER]/*`. Without it I could not access the rsynced folders and files. – lowtechsun Sep 17 '18 at 21:18
26

Building on dotancohen's answer I'm using an alias:

alias sudo="cygstart --action=runas"

Works as a charm:

sudo chown User:Group <file>

And if you have SysInternals installed you can even start a command shell as the system user very easily

sudo psexec -i -s -d cmd
thoni56
  • 3,145
  • 3
  • 31
  • 49
9

I found sudo-for-cygwin, maybe this would work, it is a client/server application that uses a python script to spawn a child process in windows (pty) and bridges user's tty and the process I/O.

It requires python in windows and Python modules greenlet, and eventlet in Cygwin.

AdamTheWebMan
  • 99
  • 1
  • 3
  • I'm using this for a while now and it event handles interactive stuff like nano without any problems! – MemphiZ Dec 16 '16 at 17:00
5

It seems that cygstart/runas does not properly handle "$@" and thus commands that have arguments containing spaces (and perhaps other shell meta-characters -- I didn't check) will not work correctly.

I decided to just write a small sudo script that works by writing a temporary script that does the parameters correctly.

#! /bin/bash

# If already admin, just run the command in-line.
# This works on my Win10 machine; dunno about others.
if id -G | grep -q ' 544 '; then
   "$@"
   exit $?
fi

# cygstart/runas doesn't handle arguments with spaces correctly so create
# a script that will do so properly.
tmpfile=$(mktemp /tmp/sudo.XXXXXX)
echo "#! /bin/bash" >>$tmpfile
echo "export PATH=\"$PATH\"" >>$tmpfile
echo "$1 \\" >>$tmpfile
shift
for arg in "$@"; do
  qarg=`echo "$arg" | sed -e "s/'/'\\\\\''/g"`
  echo "  '$qarg' \\" >>$tmpfile
done
echo >>$tmpfile

# cygstart opens a new window which vanishes as soon as the command is complete.
# Give the user a chance to see the output.
echo "echo -ne '\n$0: press <enter> to close window... '" >>$tmpfile
echo "read enter" >>$tmpfile

# Clean up after ourselves.
echo "rm -f $tmpfile" >>$tmpfile

# Do it as Administrator.
cygstart --action=runas /bin/bash $tmpfile
Brian White
  • 8,332
  • 2
  • 43
  • 67
  • 1
    the accepted answer did not work for me on Win7 but this answer worked like a charm. I was able to set up exim-config with elevated privs and then vim-edit the /etc/exim.conf file afterwards. Slick. – nanker Feb 06 '18 at 15:10
4

Or install syswin package, which includes a port of su for cygwin: http://sourceforge.net/p/manufacture/wiki/syswin-su/

Mat Khor
  • 41
  • 1
2

This answer is based off of another answer. First of all, make sure your account is in the Administrators group.

Next, create a generic "runas-admin.bat" file with the following content:

@if (1==1) @if(1==0) @ELSE
@echo off&SETLOCAL ENABLEEXTENSIONS
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"||(
    cscript //E:JScript //nologo "%~f0" %*
    @goto :EOF
)
FOR %%A IN (%*) DO (
    "%%A"
)
@goto :EOF
@end @ELSE
args = WScript.Arguments;
newargs = "";
for (var i = 0; i < args.length; i++) {
    newargs += "\"" + args(i) + "\" ";
}
ShA=new ActiveXObject("Shell.Application");
ShA.ShellExecute("cmd.exe","/c \""+WScript.ScriptFullName+" "+newargs+"\"","","runas",5);
@end

Then execute the batch file like this:

./runas-admin.bat "<command1> [parm1, parm2, ...]" "<command2> [parm1, parm2, ...]"

For exaxmple:

./runas-admin.bat "net localgroup newgroup1 /add" "net localgroup newgroup2 /add"

Just make sure to enclose each separate command in double quotes. You will only get the UAC prompt once using this method and this procedure has been generalized so you could use any kind of command.

Community
  • 1
  • 1
user2618594
  • 355
  • 4
  • 3
2

A new proposal to enhance SUDO for CygWin from GitHub in this thread, named TOUACExt:

  • Automatically opens sudoserver.py.
  • Automatically closes sudoserver.py after timeout (15 minutes default).
  • Request UAC elevation prompt Yes/No style for admin users.
  • Request Admin user/password for non-admin users.
  • Works remotely (SSH) with admin accounts.
  • Creates log.

Still in Pre-Beta, but seems to be working.

Community
  • 1
  • 1
Sopalajo de Arrierez
  • 3,543
  • 4
  • 34
  • 52
1

I landed here through google, and I actually believe I've found a way to gain a fully functioning root promt in cygwin.

Here are my steps.

First you need to rename the Windows Administrator account to "root" Do this by opening start manu and typing "gpedit.msc"

Edit the entry under Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options > Accounts: Rename administrator account

Then you'll have to enable the account if it isn't yet enabled. Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options > Accounts: Administrator account status

Now log out and log into the root account.

Now set an environment variable for cygwin. To do that the easy way: Right Click My Computer > Properties

Click (on the left sidebar) "Advanced system settings"

Near the bottom click the "Enviroment Variables" button

Under "System Variables" click the "New..." button

For the name put "cygwin" without the quotes. For the value, enter in your cygwin root directory. ( Mine was C:\cygwin )

Press OK and close all of that to get back to the desktop.

Open a Cygwin terminal (cygwin.bat)

Edit the file /etc/passwd and change the line

Administrator:unused:500:503:U-MACHINE\Administrator,S-1-5-21-12345678-1234567890-1234567890-500:/home/Administrator:/bin/bash

To this (your numbers, and machine name will be different, just make sure you change the highlighted numbers to 0!)

root:unused:0:0:U-MACHINE\root,S-1-5-21-12345678-1234567890-1234567890-0:/root:/bin/bash

Now that all that is finished, this next bit will make the "su" command work. (Not perfectly, but it will function enough to use. I don't think scripts will function correctly, but hey, you got this far, maybe you can find the way. And please share)

Run this command in cygwin to finalize the deal.

mv /bin/su.exe /bin/_su.exe_backup
cat > /bin/su.bat << "EOF"
@ECHO OFF
RUNAS /savecred /user:root %cygwin%\cygwin.bat
EOF
ln -s /bin/su.bat /bin/su
echo ''
echo 'All finished'

Log out of the root account and back into your normal windows user account.

After all of that, run the new "su.bat" manually by double clicking it in explorer. Enter in your password and go ahead and close the window.

Now try running the su command from cygwin and see if everything worked out alright.

Hydranix
  • 27
  • 2
1

Being unhappy with the available solution, I adopted nu774's script to add security and make it easier to setup and use. The project is available on Github

To use it, just download cygwin-sudo.py and run it via python3 cygwin-sudo.py **yourcommand**.

You can set up an alias for convenience:

alias sudo="python3 /path-to-cygwin-sudo/cygwin-sudo.py"
Chronial
  • 66,706
  • 14
  • 93
  • 99
0

Use this to get an admin window with either bash or cmd running, from any directories context menue. Just right click on a directory name, and select the entry or hit the highlited button.

This is based on the chere tool and the unfortunately not working answer (for me) from link_boy. It works fine for me using Windows 8,

A side effect is the different color in the admin cmd window. To use this on bash, you can change the .bashrc file of the admin user.

I coudln't get the "background" version (right click into an open directory) to run. Feel free to add it.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash]
@="&Bash Prompt Here"
"Icon"="C:\\cygwin\\Cygwin.ico"

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash\command]
@="C:\\cygwin\\bin\\bash -c \"/bin/xhere /bin/bash.exe '%L'\""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash_root]
@="&Root Bash Prompt Here"
"Icon"="C:\\cygwin\\Cygwin.ico"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash_root\command]
@="runas /savecred /user:administrator \"C:\\cygwin\\bin\\bash -c \\\"/bin/xhere /bin/bash.exe '%L'\\\"\""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_cmd]
@="&Command Prompt Here"

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_cmd\command]
@="cmd.exe /k cd %L"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_cmd_root]
@="Roo&t Command Prompt Here"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_cmd_root\command]
@="runas /savecred /user:administrator \"cmd.exe /t:1E /k cd %L\""
0

A very simple way to have a cygwin shell and corresponding subshells to operate with administrator privileges is to change the properties of the link which opens the initial shell.

The following is valid for Windows 7+ (perhaps for previous versions too, but I've not checked)

I usually start the cygwin shell from a cygwin-link in the start button (or desktop). Then, I changed the properties of the cygwin-link in the tabs

/Compatibility/Privilege Level/

and checked the box,

"Run this program as an administrator"

This allows the cygwin shell to open with administrator privileges and the corresponding subshells too.

DMH
  • 1
0

I met this discussion looking for some details on the sudo implementation in different operating systems. Reading it I found that the solution by @brian-white (https://stackoverflow.com/a/42956057/3627676) is useful but can be improved slightly. I avoided creating the temporary file and implemented to execute everything by the single script.

Also I investigated the next step of the improvement to output within the single window/console. Unfortunately, without any success. I tried to use named pipes to capture STDOUT/STDERR and print in the main window. But child process didn't write to named pipes. However writing to a regular file works well.

I dropped any attempts to find the root cause and left the current solution as is. Hope my post can be useful as well.

Improvements:

  • no temporary file
  • no parsing and reconstructing the command line options
  • wait the elevated command
  • use mintty or bash, if the first one not found
  • return the command exit code

    #!/bin/bash

    # Being Administrators, invoke the command directly
    id -G | grep -qw 544 && {
        "$@"
        exit $?
    }

    # The CYG_SUDO variable is used to control the command invocation
    [ -z "$CYG_SUDO" ] && {
        mintty="$( which mintty 2>/dev/null )"
        export CYG_SUDO="$$"
        cygstart --wait --action=runas $mintty /bin/bash "$0" "$@"
        exit $?
    }

    # Now we are able to:
    # -- launch the command
    # -- display the message
    # -- return the exit code
    "$@"
    RETVAL=$?

    echo "$0: Press  to close window..."
    read

    exit $RETVAL

jsxt
  • 1,097
  • 11
  • 28
  • How does `cygstart --wait --action=runas $mintty /bin/bash "$0" "$@"` not break if there are spaces in an argument? It always did for me when passing such through cygstart/runas. – Brian White May 04 '20 at 01:10
0

Based on @mat-khor's answer, I took the syswin su.exe, saved it as manufacture-syswin-su.exe, and wrote this wrapper script. It handles redirection of the command's stdout and stderr, so it can be used in a pipe, etc. Also, the script exits with the status of the given command.

Limitations:

  • The syswin-su options are currently hardcoded to use the current user. Prepending env USERNAME=... to the script invocation overrides it. If other options were needed, the script would have to distinguish between syswin-su and command arguments, e.g. splitting at the first --.
  • If the UAC prompt is cancelled or declined, the script hangs.

.

#!/bin/bash
set -e

# join command $@ into a single string with quoting (required for syswin-su)
cmd=$( ( set -x; set -- "$@"; ) 2>&1 | perl -nle 'print $1 if /\bset -- (.*)/' )

tmpDir=$(mktemp -t -d -- "$(basename "$0")_$(date '+%Y%m%dT%H%M%S')_XXX")
mkfifo -- "$tmpDir/out"
mkfifo -- "$tmpDir/err"

cat >> "$tmpDir/script" <<-SCRIPT
    #!/bin/env bash
    $cmd > '$tmpDir/out' 2> '$tmpDir/err'
    echo \$? > '$tmpDir/status'
SCRIPT

chmod 700 -- "$tmpDir/script"

manufacture-syswin-su -s bash -u "$USERNAME" -m -c "cygstart --showminimized bash -c '$tmpDir/script'" > /dev/null &
cat -- "$tmpDir/err" >&2 &
cat -- "$tmpDir/out"
wait $!
exit $(<"$tmpDir/status")
EndlosSchleife
  • 515
  • 7
  • 19
-1

Can't fully test this myself, I don't have a suitable script to try it out on, and I'm no Linux expert, but you might be able to hack something close enough.

I've tried these steps out, and they 'seem' to work, but don't know if it will suffice for your needs.

To get round the lack of a 'root' user:

  • Create a user on the LOCAL windows machine called 'root', make it a member of the 'Administrators' group
  • Mark the bin/bash.exe as 'Run as administrator' for all users (obviously you will have to turn this on/off as and when you need it)
  • Hold down the left shift button in windows explorer while right clicking on the Cygwin.bat file
  • Select 'Run as a different user'
  • Enter .\root as the username and then your password.

This then runs you as a user called 'root' in cygwin, which coupled with the 'Run as administrator' on the bash.exe file might be enough.

However you still need a sudo.

I faked this (and someone else with more linux knowledge can probably fake it better) by creating a file called 'sudo' in /bin and using this command line to send the command to su instead:

su -c "$*"

The command line 'sudo vim' and others seem to work ok for me, so you might want to try it out.

Be interested to know if this works for your needs or not.

LarryDavid
  • 736
  • 6
  • 16
-1

What I usually do is have a registry "Open Here" helper in order to open a cygwin shell with administrative privileges quite easy from anywhere in my computer.

Be aware you have to have the cygwin "chere" package installed, use "chere -i -m" from an elevated cygwin shell first.

Assuming your cygwin installation is in C:\cygwin...

Here's the registry code:

Windows Registry Editor Version 5.00

[-HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash]

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash]
@="Open Cygwin Here as Root"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\shell\cygwin_bash\command]
@="c:\\cygwin\\bin\\mintty.exe -i /Cygwin-Terminal.ico -e /bin/xhere /bin/bash.exe"

[-HKEY_CLASSES_ROOT\Directory\Background\shell\cygwin_bash]

[HKEY_CLASSES_ROOT\Directory\Background\shell\cygwin_bash]
@="Open Cygwin Here as Root"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\Background\shell\cygwin_bash\command]
@="c:\\cygwin\\bin\\mintty.exe -i /Cygwin-Terminal.ico -e /bin/xhere /bin/bash.exe"

[-HKEY_CLASSES_ROOT\Drive\shell\cygwin_bash]

[HKEY_CLASSES_ROOT\Drive\shell\cygwin_bash]
@="Open Cygwin Here as Root"
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Drive\shell\cygwin_bash\command]
@="c:\\cygwin\\bin\\mintty.exe -i /Cygwin-Terminal.ico -e /bin/xhere /bin/bash.exe"

Hope this helps. Let me know if it works for you. Thanks.

PS: You can grab this code, copy and paste it and save it in a name.reg file to run it... or you can manually add the values.

link_boy
  • 1,025
  • 4
  • 12
  • 23
-1

Just simplifying the accepted answer, copy past the below in a Cygwin terminal and you are done:

cat <<EOF >> /bin/sudo
#!/usr/bin/bash
cygstart --action=runas "\$@"
EOF
chmod +x /bin/sudo
user2576266
  • 2,383
  • 2
  • 16
  • 22
-7

Try:

chmod -R ug+rwx <dir>

where <dir> is the directory on which you want to change permissions.

Blumer
  • 5,005
  • 2
  • 33
  • 47