Question

I´m struggling to learn obj-C and could use some help. I´m writing a "command line tool" to create a encrypted DMG and then safely delete the included files. When hdiutil creates the DMG it asks for a password for the encryption and I´m trying to pipe this password from bin/echo to hdiutil.

The DMG is created as expected but when I try to mount it the password is not accepted. I have tried to mount with both a blank password and with an extra space at the end.

When I NSLog the value from the pipe it looks correct but thats probably because I just read the first 4 characters. I guess there is some extra character added to the password but I can´t figure out why and what.

Two questions 1: How do I pipe the "correct" value as a password from NSTask passwordCmd to NSTask backupCmd?

2: How do I NSLog the exact same value from the pipe as is passed to [backupCmd setStandardInput:pipe]

#import <Foundation/Foundation.h>

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

    @autoreleasepool {
        NSTask *passwordCmd = [NSTask new];
        NSTask *backupCmd = [NSTask new];

        NSPipe *pipe;
        pipe = [NSPipe pipe];

        // Enter password by calling echo with a NStask
        [passwordCmd setLaunchPath:@"/bin/echo"];
        [passwordCmd setStandardOutput:pipe]; // write to pipe
        [passwordCmd setArguments: [NSArray arrayWithObjects: @"test", nil]];
        [passwordCmd launch];
        [passwordCmd waitUntilExit];

        // Log the value of the pipe for debugging 
        NSData *output = [[pipe fileHandleForReading] readDataOfLength:4];
        NSString *string = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
        NSLog(@"'%@'", string);

        // Create a encrypted DMG based on a folder
        [backupCmd setLaunchPath:@"/usr/bin/hdiutil"];
        [backupCmd setCurrentDirectoryPath:@"/Volumes/Macintosh HD/Users/kalle/Desktop/test/"];
        [backupCmd setArguments:[NSArray arrayWithObjects:@"create",@"-format",@"UDZO",@"-srcfolder",@"backup",@"/Volumes/Macintosh HD/Users/kalle/Desktop/backup.dmg",@"-encryption",@"AES-256",@"-stdinpass",@"-quiet",nil]];
        [backupCmd setStandardInput:pipe]; // read from pipe
        [backupCmd launch];
        [backupCmd waitUntilExit];

        // Do some more stuff...

    }
    return 0;
}

any help is much appreciated!

Was it helpful?

Solution

I see two problems in your code:

1) The "hdiutil" documentation states:

-stdinpass
read a null-terminated passphrase from standard input. ... Beware that the password will contain any newlines before the NULL.

But "/bin/echo" always appends a newline to the output. So your password is set to "test\n".

2) If you read the password from the pipe for logging, the data is "gone" and isn't read by the backup task anymore. (EDIT: This has also been posted by Ramy Al Zuhoury while I was writing this answer!)

I would not use a "/bin/echo" task to pipe the password into the backup task. You can better write the necessary data directly to the pipe:

NSString *passwd = @"test\0\n"; // password + NULL character + newline
NSData *passwdData = [passwd dataUsingEncoding:NSUTF8StringEncoding];
[[pipe fileHandleForWriting] writeData:passwdData];
[[pipe fileHandleForWriting] closeFile];

(I am not sure if "hdiutil" really expects a newline after the NULL character. You can also try it without the newline.)

OTHER TIPS

You have already read the characters from the pipe, that are so "consumed" and the next time you read them you won't find them anymore.

You should be able to do it if you remove this line:

NSData *output = [[pipe fileHandleForReading] readDataOfLength:4];

Making so that 4 characters still available in the pipe.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top