There's no 'sudo' command in Cygwin

42

15

Because there's no sudo command in Cygwin, scripts that I want to run fail with

./install.sh: line N: sudo: command not found

What's the standard way for getting around this? Editing the scripts to remove sudo? Getting some sudo-like tool for Windows?

Jason Sundram

Posted 2010-03-21T17:45:27.527

Reputation: 2 946

@dotancohen, I hope I picked the right one. – Jason Sundram – 2015-03-30T00:16:43.267

Looks like a good solution to me! Cygwin support has certain gotten better in the past five years! – dotancohen – 2015-03-30T07:35:09.670

@Benj, I wonder why that question didn't get migrated here, too. – Jason Sundram – 2016-08-03T22:25:45.710

@JasonSundram indeed. Let me know if the answer is moved, I'll then update the link. – Benj – 2016-08-04T07:52:42.640

Answers

8

I wrote the (rather simple) TOUACExt for SUDO for CygWin, a pre-beta shell script automation that approaches to the behavior of classical sudo for Linux:

  • Open and closes automatically sudoserver.py when needed.
  • Requests UAC Elevation Prompt.

Installation requires copying the four .sh scripts to some path directory, creating an alias and just a few more steps detailed in the thread.

The results: you type a single sudo YourCommand and you get the output of it, without having to worry about the rest of the process.

Sopalajo de Arrierez

Posted 2010-03-21T17:45:27.527

Reputation: 5 328

35

One way is to create a fake "sudo" command with the following content:

#!/usr/bin/bash

"$@"

This will allow the install.sh to continue, because sudo is found.

This doesn't elevate privileges like real sudo does. If you really need elevated privileges start cygwin shell with from an account with administrative privileges (XP) or r-click on cygwin.bat and "run as administrator" (Vista,Win7)

Peon

Posted 2010-03-21T17:45:27.527

Reputation: 771

5Just out of curiosity from someone who doesn't speak fluent bash: Why does this work? The manpage doesn't say anything about $@ doing anything sudo-like. Instead it's just all arguments to the script. And wouldn't the quotes around it be superfluous in that case? Otherwise if you'd do a sudo foo bar then it tries executing "foo bar" as a single command which probably doesn't exist given that irrational fear of spaces on UNIX-like systems. – Joey – 2010-03-23T10:29:05.037

7@Johannes: "$@" (when double-quoted) works differently from "$*": it expands to a separate word for every positional variable. Example: If $1 == "foo bar" and $2 == "baz", then "$@" is "foo bar" baz - one word for each parameter (unlike "$*", which results in "foo bar baz" as one word). See manual of bash, section Parameters, subsection Special parameters. The end result of Peon's script is that it executes its arguments exactly as they were passed. – user1686 – 2010-03-23T15:22:19.743

1Ah, ok. And where does the sudo part come in? Above snippet doesn't do anything remotely in that direction, right? – Joey – 2010-03-23T15:38:33.407

2@Johannes: In Unix, a real sudo would raise privileges from mortal to root before running the command. In Cygwin, there is no such thing, so Peon's fake script (which you're supposed to name sudo) just runs the command directly without changing its privileges. (This means you may need to run ./install.sh as Administrator.) – user1686 – 2010-03-23T15:49:10.873

1Something really smart would be to write something involving win32security.ImpersonateLoggedInUser(), or at least runas, in order to actually raise privileges to Administrator... however, I'm stuck on XP and don't know if that works with UAC. Peon's solution is much simpler. – user1686 – 2010-03-23T15:51:41.867

2@grawity: runas should work, it doesn't rely on UAC and prompts for a password by itself. I was just confused why the script in the answer apparently didn't do what the name implied which I assumed was the goal. Sorry for my stupidity ;-) – Joey – 2010-03-23T17:12:35.433

1+1. Note though that since the real sudo supports options this can break on occasions. A smarter wrapper script would have knowledge about those and strip them away to avoid breakage on invocations with options, e.g. sudo -n. – Adrian Frühwirth – 2013-09-10T14:53:38.170

Note: newline in that script should be 0x0A. – Nakilon – 2013-12-18T13:57:41.377

22

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:

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

$ PATH=$HOME/bin:$PATH
$ chmod +x ~/bin/sudo
$ sudo elevatedCommand

Tested on 64-bit Windows 8.

dotancohen

Posted 2010-03-21T17:45:27.527

Reputation: 9 798

curiously, this strips out /bin and /usr/bin from the PATH. It does successfully invoke emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1) but then emacs cannot find ls for e.g. M-x dired, even after interactively restoring the PATH using (setenv ...). Is there a trusted paths issue here? – BaseZen – 2018-03-08T18:27:22.777

5The problem with the cygstart method is that it only works for Windows commands/programs. You can not do sudo ls. SUDO for CygWin is neat, but still lacks some good sudo command in it. – Sopalajo de Arrierez – 2014-04-13T20:59:10.297

Thank you, Sopalajode. In what situation have you needed to use sudo ls in Cygwin? – dotancohen – 2014-04-17T10:04:12.440

3

Oh, no, @Dotancohen, it was just an example. You can use sudo for CygWin to run any Windows or CygWin command. It is very useful for me. But the more practical method I have found is this script wrapper for SUDO for CygWin I developed: http://superuser.com/questions/741345/practical-closest-to-the-classical-linux-one-way-to-use-automate-sudo-for-cy (still in Beta, but seems to work ). With it you can comfortably order things like sudo net start vncserver.

– Sopalajo de Arrierez – 2014-04-17T10:22:25.760

@SopalajodeArrierez: That is absolutely terrific! Thank you for the post and the link. – dotancohen – 2014-04-17T12:15:49.733

5

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

alias sudo="cygstart --action=runas"

Works as a charm for external programs (not shell built-ins, though):

sudo chown User:Group <file>

thoni56

Posted 2010-03-21T17:45:27.527

Reputation: 163

3

Sudo (Elevate) for Windows™

I do a lot of work on the command line in Windows™.

In Cygwin itself I believe you can run a root command with su -c /the/cmd as for sudo itself within Windows™ file-system elevating the user's permissions from the command line, If you are an administrator, this will work great for you. Otherwise, use runas and get admin's pass ;).

Now I cannot remember where we got this code but here it is. I hope it helps.

BTW, the package we use to compile this was gcc-mingw32.

$ i586-mingw32msvc-gcc sudo.c -o sudo.exe
# Put sudo.exe in /usr/bin or in your windows path (%homedrive%\windows)
#example:
$ sudo vi /cygdrive/c/windows/system32/drivers/etc/hosts

/**
* (sudo for Windows™)
* @filename sudo.c
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <shellapi.h>
#include <wchar.h>


LPWSTR *mergestrings(LPWSTR *left, LPCWSTR right)
{
    size_t size = ( 1 + lstrlen(*left) + lstrlen(right) ) * sizeof(LPWSTR*);
    if ( *left ) {
        LPWSTR leftcopy = _wcsdup(*left);
        *left = (LPWSTR)realloc(*left, size);
        *left = lstrcpy(*left, leftcopy);
        *left = lstrcat(*left, right);
        free( leftcopy );
    }
    else
        *left = _wcsdup(right);
    return left;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpcommand, int nShowCmd)
{
    DWORD result = 0x2a;
    LPWSTR *argv = NULL;
    int argc = 0;
    if ( argv = CommandLineToArgvW(GetCommandLineW(), &argc) ) {
        if ( argc < 2 ) {
            LPWSTR usagemsg = NULL;
            usagemsg = *mergestrings(&usagemsg, argv[0]);
            usagemsg = *mergestrings(&usagemsg, TEXT(" <command_to_run> [arguments]"));
            MessageBox(NULL, usagemsg, TEXT("Usage:"), MB_OK | MB_ICONEXCLAMATION );
            LocalFree( argv );
            free( usagemsg );
            return ERROR_BAD_ARGUMENTS;
        }
        else {
            LPWSTR command = argv[1];
            LPWSTR arguments = NULL;
            int c;
            for ( c = 2; c < argc; c++ ) {
                arguments = *mergestrings(&arguments, argv[c]);
                arguments = *mergestrings(&arguments, TEXT(" "));
            }
            result = (DWORD)ShellExecute(NULL, TEXT("runas"), command, arguments, NULL, SW_SHOWNORMAL);
            LocalFree( argv );
            if ( arguments )
                free( arguments );
            switch ( result )
            {
                case 0:
                    result = ERROR_OUTOFMEMORY;
                    break;

                case 27:
                case 31:
                    result = ERROR_NO_ASSOCIATION;
                    break;

                case 28:
                case 29:
                case 30:
                    result = ERROR_DDE_FAIL;
                    break;
                case 32:
                    result = ERROR_DLL_NOT_FOUND;
                    break;
                default:
                    if ( result > 32 )
                        result = 0x2a;
            }
        }
    }
    else
        result = GetLastError();

    if (result != 0x2a) {
        LPWSTR errormsg = NULL;
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                      NULL, result, 0, (LPWSTR)&errormsg, 0, NULL);
        MessageBox(NULL, errormsg, TEXT("Error:"), MB_OK | MB_ICONERROR);
        LocalFree( errormsg );
        return result;
    }
    else
        return NO_ERROR;
}

tao

Posted 2010-03-21T17:45:27.527

Reputation: 1 355

@user185282: Good points. I've downvoted the answer. – unforgettableidSupportsMonica – 2017-03-20T03:28:32.470

Dear tao: You wrote, "I cannot remember where we got this code". Did you write this code, or did someone else write it? – unforgettableidSupportsMonica – 2017-03-20T03:28:38.647

5This code is awful. It's full of errors like not checking the return value of realloc() before dereferencing or writing sizeof(LPWSTR) instead of sizeof(LPWSTR) where LPWSTR seems to be a pointer type and one wants to retrieve the size of one character, not the size of the pointer. Furthermore, it's totally unclear why e.g. case 29 leads to ERROR_DDE_FAIL. Can you conclude from the code why? I can't and I guess anybody else can't, too. Please, do not post such code in the future. – None – 2013-01-08T08:59:37.397

4@Mattew: please in the future help the community by posting a cleaned up version of the code snippet you dislike. – Erik Kaplun – 2013-01-20T14:36:33.683

Code shouldn't be on superuser. Put it on codereview.se, and just link it from here. – Ben Voigt – 2014-04-14T02:19:11.847

2

A slight improvement on Peon's fake sudo script:

#!/bin/sh
# Drop any option arguments.
while [[ $# -ge 0 && $1 = -* ]]; do
  shift
done

"$@"

This script silently drops any options passed to sudo and executes the command (without actually elevating the privileges). Dropping the options improves compatibility somewhat. A more complete wrapper script should actually parse options the same way sudo does.

Instead of trying to replace sudo with a wrapper that does cygstart --action=runas "$@", just use this simple fake sudo wrapper and run your install script itself (or whatever you're trying to run that uses sudo) with elevated privileges.

Gene Pavlovsky

Posted 2010-03-21T17:45:27.527

Reputation: 356