1

I've created an application in the past, in Lazarus Pascal, which execute "dd" to write an image to a drive. For this, obviously, elevated rights are needed.

In the initial version I have used AuthorizationExecuteWithPrivileges() (link), even though not exactly intended for this purpose, it did work very well and very consistently. This function however has been depreciated since OSX 10.7, as it can be a security issue, and command line statements that redirect do not work properly either (redirecting output from zip as input for dd).

In the next version I've used a method described in the Lazarus Pascal Wiki (Executing External Programs), which basically starts a TProcess which my program communicates with. Using sudo -S dd ..., the users password is asked and entered to make sure he/she has the proper access rights. Obviously a little bit of a dirty hack method, and it shows, certain users experience issues with this.

After doing a lot of reading, it seems Apple prefers this to be done with a helper tool called SMJobBless(). I'm unfortunately not very experienced when it comes to Objective-C, the presented code seems very minimal at best and not very well documented either.

I was wondering if anyone has experience or could assist in "porting" this method to Lazarus Pascal ... I'm all in favor of doing it right. Alternative methods are most welcome as well of course!

Any help would be greatly appreciated.

Hanzaplastique
  • 564
  • 8
  • 13

2 Answers2

1

I'm unfortunately not very experienced when it comes to Objective-C

Don't let this put you off from using the example provided by Apple. If you look closely at the code in SMJobBlessAppController.m, you'll see that other than one line of Objective-C code, the rest is simply C.

The Objective-C line registers the helper application: -

if (![self blessHelperWithLabel:@"com.apple.bsd.SMJobBlessHelper" error:&error])

You'd use your own URI, instead of com.apple.bsd.SMJobBlessHelper.

All the other relevant lines are plain C functions. Breaking this down, you're left with: -

// Obtain rights 
AuthorizationCopyRights(self->_authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL)


//Start the helper
SMJobBless(kSMDomainSystemLaunchd, (CFStringRef)label, self->_authRef, &cfError);

I've left out checking for error codes, but I hope this has shown just how little code you need to work with and very little Objective-C knowledge is required.

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Thanks for the input Merlin069,... based on your info, I should have probably written: I have no clue how SMJobBless works as I do not quite understand the mechanics of it. :-) – Hanzaplastique Jan 26 '15 at 11:56
  • 1
    You shouldn't need to, but basically the helper is launched by the system, when you call the SMJobBless function, after having registered it with the line [self blesshelperWithLabel:@"com.myuri"]. Responsibility of managing the helper is up to the system and not your program. – TheDarkKnight Jan 26 '15 at 12:00
  • OK, it's slowly starting to make more sense ... say I'd like to execute `sudo dd bs=1m if=path_of_your_image.img of=/dev/rdisk1` ... where "path_of_your_image" and "/dev/rdisk1" are being passed from the main application ... how would I do this? (the most confusing part - and then I'm not even talking about reading the progress of dd) – Hanzaplastique Jan 26 '15 at 12:40
  • Or do I need to create an additional (simple) application/executable that handles just this (call `dd` and add passed parameters)? – Hanzaplastique Jan 26 '15 at 13:01
  • 1
    Referring back to the SMJobBless example, the 'helper' is in the file SMJobBlessHelper.c, which just calls syslog to retrieve the user credentials (uid, gid etc). This is where your dd command would go and you wouldn't need sudo, as the helper should have the necessary elevated rights. Essentially the answer is 'yes', it is an additional executable which is the 'helper'. – TheDarkKnight Jan 26 '15 at 13:09
  • 1
    Thank you Merlin069 for your help - I'll start experimenting with this and see where it gets me ... :-) I've seen many Lazarus Pascal options, and none of them appear to be all that kosher ... I'll post back here when I have a working demo :-) – Hanzaplastique Jan 26 '15 at 13:18
  • Consider that the purpose of the design of the helper app is security and stability, by ensuring applications factor out elevated functionality to separate applications. Apple aim make it easy to use their tools and methods. The downside is that other development systems have to play catch-up and it doesn't always make that easy for their developers. Taking time to learn Apple's way of doing things will reward you in the end. One other option you may have is to look at using Swift, instead of Objective-C. I wouldn't be surprised if that becomes Apple's main development language fairly soon. – TheDarkKnight Jan 26 '15 at 13:27
  • Thanks again Merlin069, ... doing it the Apple way is indeed the preferred way for me as well. However, I prefer to develop with Lazarus Pascal, since other applications can be cross platform compiled. I did briefly look at Swift, XCode 6 offers it. Doesn't look bad, I just prefer to be able to develop for OS X, Windows and Linux, which is something XCode/Swift does not offer. :-( – Hanzaplastique Jan 26 '15 at 16:54
  • I know what you mean. I use Qt for X-platform development, as it allows me to use C, C++ and Objective-C (OS X only) in the same project. – TheDarkKnight Jan 26 '15 at 17:12
  • I'm not a big fan of Qt,... what do you use as IDE? – Hanzaplastique Jan 27 '15 at 08:14
  • Qt Creator, though I have used it with the Visual Studio plugin, in the past. – TheDarkKnight Jan 27 '15 at 08:50
0

Since it took me a lot of work and figured it would be helpful to others, here my final working solution. https://www.tweaking4all.com/software-development/lazarus-development/macos-smjobbless-elevated-privileges-lazarus-pascal/

You'll find there an example project and tons of info.

The steps to reproduce this are quite extensive, so here a short recap:

I've been using CFMessages to send messages to the Helper Tool since I had no bindings for NSXPCConnection.

The Helper Tool has to be based on the Lazarus Pascal template "program" or "simple program", and cannot based on any of the TApplication classes, and cannot create any treads. For the Helper Tool, one needs to create a info.plist and a launchd.plist, which both must be embedded into the binary.

The Main (test) Application can be any Lazarus Pascal application, but needs a proper Info.plist as well, indicating that the Helper Tool is allowed to start with elevated privileges.

The Helper Tool and the application app bundle both need to be signed with a valid Apple Developer ID.

Some missing bindings need to be put in place:

const  kSMRightBlessPrivilegedHelper = 'com.apple.ServiceManagement.blesshelper';
function SMJobBless(domain:CFStringRef; executableLabel:CFStringRef; auth:AuthorizationRef; outError:CFErrorRef): boolean; external name '_SMJobBless'; mwpascal; 
var kSMDomainSystemLaunchd: CFStringRef; external name '_kSMDomainSystemLaunchd';

And the proper frameworks needs to be included:

{$linkframework ServiceManagement}
{$linkframework Security}
{$linkframework Foundation}
{$linkframework CoreFoundation}
{$calling mwpascal}

And let's not forget to set callback function to handle incoming messages.

I hope this is useful to someone ... :-)

Hanzaplastique
  • 564
  • 8
  • 13