Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

zeppenwolf

macrumors regular
Original poster
Nov 17, 2009
129
3
Below is the sample code from Apple at the end of "authorizationconcepts.pdf". It should be absolutely identical, except for whitespace.

It works fine, no surprise. However, I'd like it to work for my own tool, which is, at the moment, a toy bash script which attempts nothing other than to 'cp' a file into a protected area. It currently takes the full path of the Info.plist in /App..s/Util..s/Terminal/Contents/ and tries to cp that into the same path but named "Back.plist".

So I change the one line which points to "/usr/bin/id" to point to my bash script instead. But it doesn't work-- the cp command returns "permission denied". One single change, and the thing doesn't work. Nuts!

Obvious and/or silly errors can be ruled out: If I "sudo myBashScript" on the command line, it performs exactly as it should, so there's nothing wrong with the bash script per se. Also, when executed from the compiled SampleCode app, myBashScript executes fine... it is just the cp command which fails...

What am I missing?


Code:
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
//int read(long,StringPtr,int);
//int write(long,StringPtr,int);

#import <Foundation/Foundation.h>

int main( int argc , const char* argv[] ) {

	OSStatus myStatus;
	AuthorizationFlags myFlags = kAuthorizationFlagDefaults; //1
	AuthorizationRef myAuthorizationRef; //2
	myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, myFlags, &myAuthorizationRef); //3
	if (myStatus != errAuthorizationSuccess)
		return myStatus;
	myStatus = AuthorizationCopyPrivilegedReference(&myAuthorizationRef, kAuthorizationFlagDefaults);
	{
		AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0}; //4
		AuthorizationRights myRights = {1, &myItems}; //5
		myFlags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; //6
		myStatus = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL ); //7
	}
	if (myStatus != errAuthorizationSuccess)
		goto DoneWorking;
	{
		char myToolPath[] = "/usr/bin/id";
		char *myArguments[] = { "-un", NULL };
		FILE *myCommunicationsPipe = NULL;
		char myReadBuffer[128];

		myFlags = kAuthorizationFlagDefaults; //8
		myStatus = AuthorizationExecuteWithPrivileges(myAuthorizationRef, myToolPath, myFlags, myArguments, &myCommunicationsPipe); //9

		if (myStatus == errAuthorizationSuccess)
			for(;;) {
				int bytesRead = read(fileno (myCommunicationsPipe), myReadBuffer, sizeof(myReadBuffer));
				if (bytesRead < 1)
					goto DoneWorking;
				write( fileno(stdout), myReadBuffer, bytesRead);
			}
	}

DoneWorking:
	AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults); //10

    return 0;
}
 
Last edited:

briloronmacrumo

macrumors 6502a
Jan 25, 2008
533
341
USA
The cp command returns "permission denied". One single change, and the thing doesn't work. Nuts!

Have you tried the standard flags setting( kAuthorizationFlagDefaults ) instead of bit oring those other constants? Maybe not the punch line but it is where I'd start ( I didn't study your code ). This will require the user to authenticate.... FWIW/btw: Apple deprecated all these Authorization Services calls in OS X 10.7.

Code:
 AuthorizationExecuteWithPrivileges( authRef, tool, kAuthorizationFlagDefaults, args, &pipe );
...
...
AuthorizationFree( authRef, kAuthorizationFlagDestroyRights );
 

chown33

Moderator
Staff member
Aug 9, 2009
10,751
8,423
A sea of green
As I recall, one thing you might be missing is that AEWP only changes the effective uid of the new process. The 'sudo' command, however, changes both the effective and real uid of the process.

You should be able to see this in the output from the 'id' command. Give 'id' no options, and look at the different output.

Any decent discussion of Unix's privilege model will cover the distinction between real and effective uid's, and the role each one plays.

In my experience, some command-line tools have problems when euid and ruid differ. They should behave, but sometimes they don't. It's been a long time since I played around with AEWP, and I don't recall if I ever used it with file-copying commands.
 

zeppenwolf

macrumors regular
Original poster
Nov 17, 2009
129
3
To recap, briefly, Apple's Sample Code works fine when the "helper app" is "usr/bin/id", which is to say, a compiled executable written by some UNIX nerd somewhere.

The same exact code fails if it points to a "helper app" when it is an executable bash script written by moi.

I can't make myself a UNIX nerd anymore than I can change the weather.

But I can substitute a compiled binary for my bash script, so that's what I did, and it works. I used the template for a "command line tool" in XCode 4.0.2; I didn't change a single build setting, and I just added a couple lines to main() to copy the same Info.plist to a Back.plist in a protected area as mentioned previously, and it works fine.

So the clear inference is that AEWP simply will not work if the "helper app" is a bash script instead of a compiled binary. Why this should be I don't understand, and quite likely I still wouldn't understand it even if someone like chown33 tried to explain it. God knows I don't recall any mention of this limitation in the documentation... but I've got my workaround and I'm moving forward.

Thanks everyone. I really hope that someone finds this thread when they have a similar problem. What a messy bowl of chili the whole AEWP thing is...
 

jhiesey

macrumors newbie
Mar 6, 2013
17
16
This is happening because the bash shell is resetting the effective user id back, since it's not the same as the real user id. The manual explains this behavior at the very bottom of this page: https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html

You probably have something like

Code:
#!/bin/bash

at the top of your shell script. Change it to

Code:
#!/bin/bash -p

and it should work! Note though that if you try to run another shell script from inside this one you will have the same problem again, and you'll have to modify that script as well. Most other programs (like cp) should work fine though.
 

zeppenwolf

macrumors regular
Original poster
Nov 17, 2009
129
3
This is happening because the bash shell is resetting the effective user id back, since it's not the same as the real user id.

Well, SHAZAM!!

I *knew* (kinda) that it had something to do with creating a new shell... someway, somehow. Nothing else was logically possible.

The manual explains this behavior at the very bottom of this page:

A curious use of the word "explains", but ok.

You probably have something like
Code:
#!/bin/bash

Not "something like", I had that exactly. And I tried plenty of other things, like eliminating that line entirely, hoping that it would "default through"... but of course it didn't work, which you could guess.

Anyway, I appreciate your explanation and revelation of the Abracadabra, but at this point... I've got my workaround, and I'm wondering whether I shouldn't have gone this route in the first place. Can an external bash script be code signed? I dunno, but it seems doubtful..?

At any rate, with a compiled binary, I feel like I'm more "in control", sorta... For instance, I can more easily compile against complicated error define headers which are also included in the calling app... So I feel inclined right now to stick with the "workaround".

But definitely, thanks for solving the mystery.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.