Make user verify administrator password with timeout

All,

I’d like to require the user to enter the administrator password such that if they don’t or if they enter incorrectly, then the password to wake is enabled and the screen is locked. I’m currently using this code:

if not CheckPassword() then LockScreen()

on CheckPassword()
	try
		do shell script "echo" with administrator privileges
		return true
	on error
		tell application "System Events" to set require password to wake of security preferences to true
		return false
	end try
end CheckPassword

on LockScreen()
	tell application "System Events" to tell process "SystemUIServer" to click (first menu item of menu 1 of ((click (first menu bar item whose description is "Keychain menu extra")) of menu bar 1) whose title is "Lock Screen")
end LockScreen

This works alright, but I’d like to make it so that if the user doesn’t enter the password within say 15 seconds, then the password request times out and CheckPassword() returns false. I’ve tried using a timeout:

on CheckPassword()
	try
		with timeout of 15 seconds
			tell application "System Events"
				do shell script "echo" with administrator privileges
			end tell
		end timeout
		return true
	on error
		tell application "System Events" to set require password to wake of security preferences to true
		return false
	end try
end CheckPassword

but the timeout does not occur. I guess that the password prompt doesn’t count towards the timeout for System Events to perform the “do shell script” command.

How can I achieve the same method of having the user enter an administrator password with a timeout?

Thanks.

Hello.

If I have been taught right, then do shell script doesn’t per se use any apple events, but, you should be able to fool it.
if your last statement in the do shell script, echoes some text back, which you assign to a variable, then I think you may be able to generate a time out. :wink:

with timeout of 45 seconds
		set probe to do shell script "Important commandlist; echo \"done\" "
end timeout

A do shell script is an “internal” AppleEvent and timeouts doesn’t affect these AppleEvents. Here an small example:

with timeout of 5 seconds
	delay 10 --it doesn't timeout
end timeout

Because do shell scripts aren’t allowed to use as an external AppleEvent (Since Mac OS X 10.6) McUsr example won’t work. Simply put, you can’t use timeout with a do shell script and for the record: It does use an AppleEvent.

Hi,

different solution.
If you’re providing user name and password along with administrator privileges the authentication dialog is not displayed.
Then you can use a standard AppleScript dialog with its time out functionality


checkPassword()

on checkPassword()
	set {text returned:textReturned, gave up:gaveUp} to display dialog "Enter password" default answer "" giving up after 15
	try
		if gaveUp then error
		set shortUserName to short user name of (system info)
		do shell script "echo " user name shortUserName password textReturned with administrator privileges
		return true
	on error
		tell application "System Events" to set require password to wake of security preferences to true
		if system attribute "sys2" > 8 then
			do shell script "pmset displaysleepnow"
		else
			tell application "System Events" to tell process "SystemUIServer" to click (first menu item of menu 1 of ((click (first menu bar item whose description is "Keychain menu extra")) of menu bar 1) whose title is "Lock Screen")
		end if
		return false
	end try
end checkPassword

Apple dropped the Keychain menu extra in Yosemite, the script uses pmset displaysleepnow to lock the screen on Mavericks and later

Its weird, the timeout is even short circuited, even if you add a tell application “Finder” block around the do shell script. Actually, I have found no way of making the timeout “kick in”.

What is the difference between an “internal” apple event, and an “external” one? does the internal one, just stay in the regular context, (script) without any “trampolining”?

Edit

I figured out what you meant by “internal”; that would be the opposite of the events that with timeout can handle, that is events that are addressing the current application, which with timeout doesn’t handle.

I think I got it now, that with timeout, doesn’t care so much about the which tell application context, as to which event is issued, and that the countdown of timeout is started when an event is issued, not when a tell application block is entered.

No It’s not. Since Mac OS X 10.6 scripting addition commands have “Context” (see it’s info.plist). The do shell script has the context “User” which means they are bounced back into the “current application” target if they are used in an another application block. Only commands with the context “Process” are allowed to be loaded into external applications and executed by them, like display dialogs. So wrapping a tell application “Finder” around it has no affect, you will only add one silent error to your script (see event log).

Thanks for the info on the context in the info.plist, hopefully I won’t have to look much into that file to figure out what goes wrong. I realized it worked like you write further down, as “which evebt” matters more than which tell block it appears in. I really should start to the error log more; an error number -10004 did indeed show up in the event log, but if I remember correctly, this just indicates that the do shell script was called in a bad context.

(The MacError utility should really have given more details. it shows the telBadHandleErr, whereas Regulus’s script, shows the errAEPrivilegeError. The script can be found here.)

The “silent” class of errors, can also confusing, they aren’t even trapped by a try on error - end try block. (I’d really like to call them “errors that don’t create runtime errors” :slight_smile:

Excactly, that’s why it is called Context in the info.plist as well. However, it would be useful if the dictionary had some information about this as well, now we have to execute an command and try in another context when we see an error occur.

If they throw a normal error, in 10.6 the MacScripter forums would have been flooded with posts as the Apple community. Because the error is obvious, and AppleScript is an language that tries to solve mistakes by the developer their choice is nothing more than expected to me.

errors-that-will-be-fixed-for-you-at-run-time was too long compared to the word “silent” :cool:

Hello.

Wasn’t it abit like that when they introduced the “privelege elevation” with Mountain Lion? Wasn’t it like you got a “hard error” then, but that they have “cut some slack” with Mavericks?

I remember standard additions commands throwing errors inside tell application blocks way back then, except for beep, and maybe delay.

This was interesting, thanks. :slight_smile:

That was solved by the security update 005 for Leopard. 10.5 had it’s own new scripting addition structure and improved event handling and got rid of the 10.4 and earlier routines. 10.6 had again a more secured version of the 10.5 loading mechanism and event handling, but 10.6 is forgiving (at least at my desk here). Mountain Lion was all about sandboxing and how you should use NSUserScriptTasks to run scripts (shell or AppleScript) safely from an sandboxed app but hasn’t had any updates on scripting additions. I think it was 10.7 who stopped supporting the 10.4 style scripting additions for security reasons already.

Thanks. :slight_smile:

And in some cases they are actually silent, at least since Mavericks. Take this script:

tell application "Finder"
	random number
end tell

You can see the error in the log. Now try this version:

use scripting additions
tell application "Finder"
	random number
end tell

No sign of the error, but the command is still being sent to current application.

From the ASLG:

Thanks, I was aware of better optimization for scripting additions since Mavericks (from what I have read in the AppleScript release notes for 10.9) but haven’t noticed this.

Wow, you guys really took off with this one! Makes for a good read :slight_smile:

I should explain my problem a little bit more. I have ControlPlane installed to switch between “safe” and “unsafe” contexts (like being safe at home vs. unsafe at the office). This triggers a bunch of system behavior, including toggling whether a password is required to wake the machine.

The use case is that my computer is happy and safe at home, which implies that it can wake without using a password, and then it is taken away by some evil doer. The evil doer opens the computer, and ControlPlane switches to an unsafe contexts because the home displays and network adapter are no longer available. When this happens, ControlPlane runs a script which, among other things, turns on the password when waking. But the computer was already awake when “require password to wake” was set to true, so the evil doer still have access to my machine!

My goal here was to implement a dialog into which the user must enter an administrator password. If the dialog fails, then the computer locks and a password is required to awaken it. Likewise, if the dialog times out the computer locks.

I’m using the password prompt from

do shell script "whatever" with administrator privileges

because I use KnockApp (http://www.knocktounlock.com), which allows auto entry of your password when a “legitimate” dialog appears asking to enter the administrator password (like when installing an application or unlocking security preferences). If I use an alternative method like

try
	set thepass to text returned of (display dialog "password:" giving up after 15)
	do shell script "whatever" password thepass with administrator privileges
on error
	LockScreen()
end try

then KnockApp won’t be triggered by the dialog and I have to manually enter my password.

So I’m after a “built-in” administrator password dialog with a timeout. Is this something I need ASObjC for or can I find a solution within AS?

And Stefan, I have my computer set to require a password after 5 seconds, so if I use pmset displaysleepnow and then wake the computer immediately a password isn’t required, whereas the keychain menu item requires it immediately like I want.

Edit: Let’s ignore how I’m concerned about security and yet I’m using a program that lets me unlock my computer by tapping on my phone :slight_smile:

FWIW, ASObjC is unlikely to help you.

Does anyone know a way to get a “normal” administrator password dialog with a timeout? Maybe a 3rd party application?

I think it will not, at least using vanilla AppleScript StefanK solution is the closest you’ll get. I think you have to write the 3rd party software yourself in ASObjC, an osax or an scriptable Objective-C background application.

Edited

A brutal approach.

What could have been a good idea, is to get the process id of the running script, which should be possible.

You send this into a do shell script as a paramter, the do shell script runs in the background , that process writes its process id into a file. Then the shell script sleeps for 15 seconds, and then it kills the process that runs the script.

The do shell script with administrator privileges, does in addition to what it should do; kill the process, that is supposed to kill the process that runs the script. It does so, by reading the process id from the filename, and then killing that process.

It is a kluge, and a brutal one, but that way, at least the script is terminated if 15 seconds passes without user interaction.

Hopefully this may spawn som other, and possibly better ideas. :slight_smile:

something like this:

set theScript to "do shell script \"echo 'hello world'\" with administrator privileges"

set PID to do shell script "osascript <<<" & quoted form of theScript & " &>/dev/null &
echo $!"

delay 15

do shell script "kill " & PID

Something like that, or a properly set up Applet, that could be called by a script, when the info.plist, and everything is in order, then I see no problem with using system events to get the process id, and the script could still keep running, and exit in a more proper way than just being killed.

The applet approach would be to send with its process id to the a do shell script before the one with the administrator privilege, then the do shell script with administrator privileges, that is augemented with reading the id of the child process and kill it. Then the handler of the applet would just return an “OK”, to the calling script, or nothing if it was killed by the child process after 15 seconds, because the Applet is hanging on the do shell script with administrator dialogue. :slight_smile: