Resolved Apple's Auth Example Fails Just For Moi

Discussion in 'Mac Programming' started by zeppenwolf, Sep 13, 2014.

  1. zeppenwolf, Sep 13, 2014
    Last edited: Sep 16, 2014

    zeppenwolf macrumors regular


    Nov 17, 2009
    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?

    #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);
    	AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults); //10
        return 0;
  2. briloronmacrumo macrumors 6502


    Jan 25, 2008
    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.

     AuthorizationExecuteWithPrivileges( authRef, tool, kAuthorizationFlagDefaults, args, &pipe );
    AuthorizationFree( authRef, kAuthorizationFlagDestroyRights );
  3. chown33 macrumors 604

    Aug 9, 2009
    Sailing beyond the sunset
    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.
  4. zeppenwolf thread starter macrumors regular


    Nov 17, 2009
    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...
  5. jhiesey macrumors newbie

    Mar 6, 2013
    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:

    You probably have something like

    at the top of your shell script. Change it to

    #!/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.
  6. zeppenwolf thread starter macrumors regular


    Nov 17, 2009
    Well, SHAZAM!!

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

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

    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.

Share This Page