0

I've grown tired of the built-in open Mac OS X command, mostly because it runs programs with your actual user ID instead of the effective user ID; this results in the fact sudo open Foo opens Foo with its associated application with your account instead of the root account, and it annoys me. So I decided to make some kind of replacement.

So far I've been successful: I can open any program under the open -a or open -b fashion, and support optionally waiting. I'm using NSTask for that purpose.

However, I'd like to be able to open documents too. As far as I can see, you need to use NSWorkspace for that, but using NSWorkspace to launch programs results in them being launched with your account's credentials instead of your command line program's credentials. Which is precisely what the default open tool does, and precisely what I don't want.

So, how can I have a program request that another program opens a document without using NSWorkspace? From the NSTask object, I can have the process ID, but that's about it.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • What you describe would be an extreme security risk. Running a GUI app as root is not a good idea at all. Why do you want to do this? There is probably a better way. – Rob Keniger Mar 26 '10 at 00:37
  • @Rob Keniger: My goal is to have an `open`-like program that runs programs under `root` if I `sudo open` them, instead of having to do `sudo /full/application/path/Contents/MacOS/program`. I know the risks of running programs as `root`, and I want to do it for myself. There is no redistribution planned nor will be any production environment depending on it. For instance, sometimes I just want information from the Activity Monitor that can only be gathered if it's run as `root` (like open files & ports of daemons). It's not like I want to run the Finder or Safari as `root`. – zneak Mar 26 '10 at 01:06

1 Answers1

1

Hopefully this will do the trick:

- (void)openFile:(NSString *)filePath withTask:(NSTask *)task {
    int pid = [task processIdentifier];
    NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID bytes:&pid length:sizeof(pid)];

    const char *urlUTF8 = [[[NSURL fileURLWithPath:filePath] absoluteString] UTF8String];
    NSAppleEventDescriptor *urlDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeFileURL bytes:urlUTF8 length:strlen(urlUTF8)];

    NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kEventParamAppleEvent eventID:kAEOpen targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
    [event setParamDescriptor:urlDescriptor forKeyword:keyDirectObject];

    OSStatus err = AESendMessage([event aeDesc], NULL, kAENoReply | kAENeverInteract, kAEDefaultTimeout);

    if (err != noErr) {
        // Error handling goes here
    }

    // Activate the application

    event = [NSAppleEventDescriptor appleEventWithEventClass:kAEMiscStandards eventID:kAEActivate targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
    err = AESendMessage([event aeDesc], NULL, kAENoReply | kAENeverInteract, kAEDefaultTimeout); 
}

You may have to launch the application using an NSTask and then send it the appropriate open Apple Event.

Actually, can you launch using an NSTask and then open the file via NSWorkspace once you know it's running? Or does that launch a new instance of the application under your user?

Original reply:

Does

open -a SomeApplication SomeFile

work?

Wevah
  • 28,182
  • 7
  • 83
  • 72
  • I feel you did not quite read the question. :/ `open -a SomeApp SomeFile` will open the desired file in the desired application, but `sudo open -a SomeApp SomeFile` won't run it with the `root` account, which is my grief against the `open` program, and the reason I'm writing a replacement. – zneak Mar 25 '10 at 23:44
  • Oh, under the open -a *fashion*. I misread that part. Let me edit. – Wevah Mar 26 '10 at 00:06
  • Thanks for your edit. Yes, opening the document from NSWorkspace once the application runs with the `root` account will open the document into it; however, there are cases in which it will fail (like if there was another instance of the opened application running under the regular user account). Apple Events might be the way to go; do you have any useful documentation link for that? `initWithEventClass:eventID:targetDescriptor:returnID:transactionID:` scares me. – zneak Mar 26 '10 at 00:19
  • You can get an AE descriptor for your app given the process ID easily enough. I can try to wrangle up some code if you still need it. – Wevah Mar 27 '10 at 22:38
  • (And you're definitely right about the NSWorkspace stuff not working the way you want it to when you have multiple instances open.) – Wevah Mar 27 '10 at 22:38
  • Oh damn! I'm sorry dude, I didn't notice you edited your answer. Don't forget to include @username in your comments if you want people to be notified! I'll try that and accept your answer if it works. Just let me remember what I wanted this for... – zneak Nov 02 '10 at 04:23
  • 1
    Thanks! It works. Though, you need to link against the Carbon framework to get the `kEventParamAppleEvent` constant. – zneak Nov 02 '10 at 04:45
  • Whoops, I forgot about that. +1 – Wevah Nov 03 '10 at 06:20