NOTE: This is mostly a program (shell script) I made,
and I know this forum is more a question-answer site than a
programs-introduction one. But I don't have any GitHub (or similar)
account, nor have I had the time to research about the method of
publishing an Open Source program to the community. So, as long as
there is a risk that a working and useful program keeps unnoticed
(even for months) to those who could enjoy it, and it would be sad to
not share an already made program, I am going to publish it here for
now. No problems for me if it the admins decide to remove this thread,
I will understand. I hope to have worded the matter in a
question-answer way enough to make it useful to this forum. If there
are enough interested users, I will do my best to dedicate some time
to continue the project (after all my researchs, I have not found
anything closest to this on Internet, but, well... I don't know if my
script is valuable or it has been a waste of time).
I have programmed a simple Linux shell script that works (until now) on CygWin and helps (I hope) reducing the SUDO for CygWin time-attack interval. The program is named TOUACExt (acronym of "TimeOut and UAC Extension") and acts as a wrapper for SUDO for CygWin (required installed), and is really composed by a set of four .sh
programs.
![Example of TOUACExt execution](../../I/static/images/8add3859b66d9c7a1c8810894983c8fa6a1228f9bcd96180c86ebab3a62f1a5a.png)
Features:
- Comfortable usage: By simulating the original sudo from Linux behavior, the UAC confirmation request prompt only appears once (multiple consecutive
sudo
commands will only generate one UAC request). As long as sudoserver.py keeps running (15 minutes default), there will be no more UAC requests.
- Privileged (Admin) users only get UAC confirmation request (Yes/No) on screen.
- Unprivileged (non-Admin) users get an Administrator account/password input screen.
- sudoserver.py keeps running, then closes automatically after predefined time (15 minutes) from the last sudo command execution.
- sudoserver.py does not close (keeps runing and will check again in 5 minutes) in case of any instance of sudo running.
- Works remotely (tested via SSH):
- Unprivileged users can not start sudoserver.py remotely.
- Creates a (yet simple and not very readable) log at
/var/log/SUDOForCygWin/
.
Requirements (in CygWin):
- SUDO for CygWin.
- pgrep (at
procps
package).
- flock (at
util-linux
package).
- nohup (I think installed by default on CygWin, but not sure).
Assuming:
- The two programs of the SUDO for CygWin project on the path suggested by the author:
/usr/local/bin/sudoserver.py
/usr/local/bin/sudo
TOUACExt have been tested working on Windows 7 SP1 and Windows XP SP3, but I don't know if it makes sense in using it on this last one.
Installation Instructions:
Put this script (suggested name: SUDOServer.cmd
) and create a shortcut (you can personalize its icon if you want) to it named SUDOServer.lnk
(you must enable on this shortcut Advanced Options --> Execute as Administrator
) anywhere on your Windows path, so sudoserver.py
can be directly requested from Windows:
c:\CygWin\bin\python2.7.exe /usr/local/bin/sudoserver.py
Put the four .sh scripts of TOUACExt on the path, for example:
/usr/local/bin/SUDO.sh
/usr/local/bin/SUDOServer.sh
/usr/local/bin/SUDOServerWatchDog.sh
/usr/local/bin/SUDOServerWatchDogScheduler.sh
Rename the original Python script from sudo
to sudo.py
:
mv /usr/local/bin/sudo /usr/local/bin/sudo.py
WARNING: The original "sudo" Python script must not remain anywhere in your path, or it could be executed instead.
Create this alias (for example, manually or by editing your ~/.bashrc
):
alias sudo='SUDO.sh'
Code for SUDO.sh:
#!/bin/bash
# ********** SUDO.sh v0.04a **********
# Variables:
# LockFile (will use a temporal one for now):
#lockfile=sudoserver-running.lck
LockFile=lockfile.lck
# Creating LogFile (if it does not exist):
mkdir /var/log/SUDOForCygWin 2>/dev/null
chmod 777 /var/log/SUDOForCygWin 2>/dev/null
LogFile=/var/log/SUDOForCygWin/$(date +%Y%m%d).log
exec 5>>$LogFile # Redirector 5 will be the log file.
chmod 777 $LogFile >&5 2>&5 # Writable to anyone (for now).
# Start of the program
echo "========== Starting SUDO Server for CygWin ==========" >&5
echo $(date) >&5
# does the lock file exists as locked?
if [ $(flock -n $TMP/$LockFile echo>/dev/null;echo $?) -eq 0 ]
then
# The lock file is not locked.
echo "LockFile not locked. Testing sudo access..." >&5
if [ $(sudo.py vartemp=0>/dev/null 2>/dev/null;printf $?) -eq 0 ]
then
# Wooops. sudoserver.py is running without the lockfile. Better to correct this.
echo "LockFile not locked, but sudoserver.py seems to be running." >&5
printf "Killing sudoserver.py...\n" >&5
sudo.py kill $(sudo.py pgrep.exe -f -l sudoserver.p[y] | grep "pgrep" -v | awk '{print $1}') >&5 2>&5
fi
# Starting SUDOServer.sh
printf "Requesting SUDOServer start...\n" >&5
nohup SUDOServer.sh >&5 2>&1&
# Wait some time delay for UAC Prompt to start
sleep 2
timeout=$((SECONDS+10))
# Has sudoserver.py already started?
while [ $(flock -w 1 $TMP/$LockFile echo>/dev/null;printf $?) -eq 0 ] || [ $(tasklist | grep "consent.exe" -i>/dev/null;printf $?) -eq 0 ]
do
# No. We have to wait.
# Waiting for SUDOServer.py to be running.
printf "."
if [ $SECONDS -ge $timeout ]
then
# sudoserver.py not responding. Aborting with errorlevel=3.
printf "sudoserver.py not responding. Aborting.\n"
exit 3
fi
done
# Yes. sudoserver.py is up and running.
fi
printf "\n"
# Schedule (add) SUDOServer Watch Dog to Task Scheduler:
SUDOServerWatchDogScheduler.sh
# Invoke requested sudo command
sudo.py $@
#printf "ErrorLevel was: "$?
# ErrorLevel Codes:
# 3 --> timeout waiting for sudoserver.py to respond.
Code for SUDOServer.sh:
#!/bin/bash
# ********** SUDOServer.sh v0.04a **********
# Variables:
# LockFile (a temporal one for now):
#lockfile=sudoserver-running.lck
LockFile=lockfile.lck
# Check for other instances of sudoserver.py running
if [ $(flock -n $TMP/$LockFile echo>/dev/null;printf $?) -eq 0 ]
then
printf "Creating lockfile: "$TMP/$LockFile"\n"
flock $TMP/$LockFile -c 'cmd /c SUDOServer'
# The file has been unlocked. Send error level=2.
exit 2
else
printf "The lockfile: "$TMP/$LockFile" is locked by another process.\n"
printf "Exiting SUDOServer.sh"
fi
printf "SUDOServer.sh execution finished. Exiting."
# Exiting with no problems.
exit 0
# ErrorLevel Codes:
# 2 --> SUDOServer.lnk (maybe denial of UAC).
Code for SUDOServerWatchDog.sh:
#!/bin/bash
# ********** SUDOServerWatchDog.sh v0.04a **********
# Variables:
# LockFile (a temporal one for now):
#lockfile=sudoserver-running.lck
LockFile=lockfile.lck
# Redirecting to LogFile:
LogFile=/var/log/SUDOForCygWin/$(date +%Y%m%d).log
exec 5>>$LogFile
if [ $(stat $LogFile -c %a) -ne 777 ]
then
echo "Logfile "$LogFile" has incorrect permissions." >&5
echo "Attemping to change permissions of "$LogFile >&5
chmod 777 $LogFile >&5 2>&5
fi
# Remove Task Scheduler entry, if exists.
if [ $(schtasks.exe /query | grep "SUDOServerWatchDog" -i>/dev/null 2>&5;printf $?) -eq 0 ]
then
sudo.py schtasks.exe /delete /tn "SUDOServerWatchDog" /f >&5 2>&5
fi
# Is sudoserver.py running?
if [ $(flock -n $TMP/$LockFile echo>/dev/null;printf $?) -eq 1 ] || [ $(sudo.py vartemp=0>/dev/null 2>/dev/null;printf $?) -eq 0 ]
then
# Yes. sudoserver.py is running. So...
printf "sudoserver.py detected running...\n" >&5
# Is any instance of sudo running right now?
if [ $(sudo.py pgrep -f -l "/usr/local/bin/sudo.py " | grep -v grep>/dev/null 2>&5;printf $?) -eq 0 ]
then
# Yes. sudo is running right now. So...
printf "There are instances of sudo running.\n" >&5
sudo.py schtasks /create /tn "SUDOServerWatchDog" /tr "SUDOServerWatchDog" /sc minute /mo 5 /sd 10/10/2010 /ru "SYSTEM" >&5 2>&5
printf "Will check again in 5 minutes. Adding Task.\n" >&5
else
# No. sudo is not running right now. So...
# Kill sudoserver.py.
printf "Closing sudoserver.py\n" >&5
sudo.py kill $(sudo.py pgrep.exe -f -l sudoserver.p[y] | grep "pgrep" -v | awk '{print $1}')
fi
else
printf "sudoserver.py not running. Nothing to be done.\n" >&5
fi
Code for SUDOServerWatchDogScheduler.sh:
#!/bin/bash
# ********** SUDOWatchDogScheduler.sh v0.04a **********
# Check if WatchDog is already scheduled
if [ $(schtasks.exe /query | grep "SUDOServerWatchDog">/dev/null 2>&5;printf $?) -eq 0 ]
then
# Yes. Remove it in order to create a new one.
echo "Task SUDOServerWatchDog already existing." >&5
echo "Removing task SUDOServerWatchDog..." >&5
sudo.py schtasks.exe /delete /tn "SUDOServerWatchDog" /f >&5 2>&5
if [ $? -eq 0 ]
then
# Task correctly deleted.
echo "Task correctly removed." >&5
else
# Something failed in task creation. Report.
echo "ERROR on deleting the SUDOServerWatchDog programmed task." >&5
fi
fi
# Schedule new task for deletion.
echo "Adding new SUDOServerWatchDog task to trigger in 15 minutes." >&5
sudo.py schtasks /create /tn "SUDOServerWatchDog" /tr "SUDOServerWatchDog" /sc minute /mo 15 /sd 10/10/2010 /ru "SYSTEM" >&5 2>&5
if [ $? -eq 0 ]
then
# Task correctly scheduled.
echo "Task SUDOServerWatchDog correctly scheduled." >&5
else
# Something failed in task scheduling. Report.
echo "ERROR on scheduling programmed task SUDOServerWatchDog." >&5
fi
Test the program from a CygWin Bash shell:
Luis@Kenobi ~
$ sudo ls -la
<UAC ELEVATION PROMPT APPEARS>
total 49
drwxr-xr-x+ 1 Luis None 0 abr 7 02:23 .
drwxrwxrwt+ 1 Luis- None 0 abr 4 03:27 ..
-rw------- 1 Luis None 13798 abr 14 00:31 .bash_history
-rwxr-xr-x 1 Luis None 1494 mar 3 11:36 .bash_profile
-rwxr-xr-x 1 Luis None 6260 abr 6 05:19 .bashrc
-rwxr-xr-x 1 Luis None 1919 mar 3 11:36 .inputrc
-rw------- 1 Luis None 35 abr 2 01:43 .lesshst
-rwxr-xr-x 1 Luis None 1236 mar 3 11:36 .profile
drwx------+ 1 Luis None 0 mar 8 01:49 .ssh
-rw-r--r-- 1 Luis None 7 mar 4 18:01 d:ppp.txt
-rw-r--r-- 1 Luis None 37 abr 7 02:23 my.log
NOTE2: These scripts are in pre-beta release, so they are still buggy and the code is not very clean. Anyway, in my tests with three different Windows 7 computers they seem to be working (mostly) OK.
Brief explanation of the program:
- Due to the alias, when performing a sudo command the SUDO.sh script is invoked.
- SUDO.sh calls SUDOServer.sh, opening (via
SUDOServer.lnk
) "sudoserver.py" if needed.
- The original sudo command invoked by the user is executed.
- Then SUDO.sh calls SUDOServerWatchDogScheduler.sh, that schedules SUDOServerWatchDog.sh for execution after the given time (15 minutes default) to close
sudoserver.py
.
- After the predefined time, SUDOServerWatchDog.sh closes sudoserver.py. If there are any instance of sudo running, it programs itself for new execution after 5 minutes.
To Do:
- Self installer that creates all the .sh, .cmd and .lnk files automatically.
- Establish lock file to some other (it is at $TMP/lockfile.lck).
- Add a configuration script or .config file (for defaults in timeouts, file locations... etc).
- Add System account behavior (thanks, @Wyatt8740).
- ¿Change "flock" (internal locking SUDO mode) with "fuser" where appropriate?
- Suggestions accepted.
Reported Bugs:
- The bash shell keeps open even after inputing
exit
if sudoserver.py
is running until it closes. Provisional workarounds are welcome.
I hope someone will use the long hours programming I have dedicated to TOUACExt.
Enhancements and corrections accepted.
Suggestions about where should I go publishing the code to stop nagging this forum accepted too ;-) .
Sorry for the long post. I don't have much free time, and this project was about disappear on my closet (maybe for years, who knows?).
@SopalajodeArrierez, it's a great complementary tool you did here. I'm ashamed: there's a long time I came here, tried to set it up, but it never worked as you said and I've never researched enough. Today, I needed sudo again, and well, there I went. I guess you have a very small bug (it could be my system, it's just a guess). I've repeated the steps and continued on not having UAC being requested. I've changed the "flock $TMP/$LockFile -c 'cmd /c SUDOServer'" line to call directly the SUDOServer.lnk you tell us to create. Don't know if you have a customized PATHEXT var, or if it's just me. – Charles Roberto Canato – 2017-04-07T02:03:20.520
1
Thanks, @CharlesRobertoCanato . Maybe you could give me the details at the chat, in order to solve it? Chat Room "TOUACExt - SuDo for Windows" : http://chat.stackexchange.com/rooms/56716/touacext-sudo-for-windows
– Sopalajo de Arrierez – 2017-04-07T12:12:57.377@SopalajodeArrierez, it doesn't seem to me that your SUDOServerWatchDog scheduled task can work. The value after the /tr option should be a path to the task to execute. It seems like to me that you need a .cmd file which can run the SUDOServerWatchDog.sh. I've made some changes to the scripts for this, and to improve the logging (a little), and can send them to you, if you like. – SeeJayBee – 2017-06-23T17:33:33.383
Thanks you, @ChrisJ.Breisch . Lets go to the chat if you want, so you can send me those changes: https://chat.stackexchange.com/rooms/61004/touacext-sudo-for-windows
– Sopalajo de Arrierez – 2017-06-23T22:01:49.1002If you want feedback on your code, post it on codereview.stackexchange.com. (The usage notes and examples are good to have here) – Ben Voigt – 2014-04-14T02:22:29.373
Thanks, @BenVoigt, I didn't know. Please a question: if I do, I think most of the post should be a duplicate of this answer. Will that be considered cross-posting? – Sopalajo de Arrierez – 2014-04-14T09:36:46.317
1Make sure to link them to each other. The harm in crossposting is that people duplicate effort. If they're linked, that's not such a problem – Ben Voigt – 2014-04-14T15:17:18.197
This is a very good solution. If it did not require python, I would use it. I have a personal, deep loathing for python. It is a nice language, but for personal reasons more than anything, I dislike it. Still, since almost no one else hates python, and my hatred is irrational, I upvoted your solution, since it is closer to the real thing than mine. – Wyatt8740 – 2014-04-30T02:26:10.860