Prepare for 64 bit
[MacVim.git] / src / MacVim / AuthorizedShellCommand.m
blob1b90cdb63021e858f04c7b5ed8258a52d31eef8d
1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
2  *
3  * VIM - Vi IMproved            by Bram Moolenaar
4  *                              MacVim GUI port by Bjorn Winckler
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
11  * AuthorizedCommand
12  *
13  * Runs a set of shell commands which may require authorization. Displays a
14  * gui dialog to ask the user for authorized access.
15  */
17 #import "AuthorizedShellCommand.h"
18 #import <Security/AuthorizationTags.h>
21 @implementation AuthorizedShellCommand
23 - (AuthorizedShellCommand *)initWithCommands:(NSArray *)theCommands
25     if (![super init])
26         return nil;
28     commands = [theCommands retain];
29     return self;
32 - (void)dealloc
34     [super dealloc];
35     [commands release]; 
38 - (OSStatus)run
40     OSStatus err;
41     int i;
42     const char** arguments = NULL;
43     AuthorizationFlags flags = kAuthorizationFlagDefaults;
45     err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
46             flags, &authorizationRef);
47     if (err != errAuthorizationSuccess)
48         return err;
50     if ((err = [self askUserForPermission]) != errAuthorizationSuccess) {
51         goto cleanup;
52     }
54     NSEnumerator* myIterator = [commands objectEnumerator];
55     NSDictionary* currCommand;
57     while ((currCommand = [myIterator nextObject])) {
58         /* do something useful with currCommand */
59         FILE *ioPipe = NULL;
60         char junk[256];
62         const char* toolPath = [[currCommand objectForKey:MMCommand] UTF8String];
63         NSArray* argumentStrings = [currCommand objectForKey:MMArguments];
64         arguments = (const char**)malloc(
65                 ([argumentStrings count] + 1) * sizeof(char*));
67         for (i = 0; i < [argumentStrings count]; ++i) {
68             arguments[i] = [[argumentStrings objectAtIndex:i] UTF8String];
69         }
70         arguments[i] = NULL;
72         err = AuthorizationExecuteWithPrivileges (authorizationRef, toolPath,
73                 kAuthorizationFlagDefaults, (char*const*)arguments, &ioPipe);
74         if (err != errAuthorizationSuccess)
75             goto cleanup;
77 #if 0
78         // We use the pipe to signal us when the command has completed
79         char *p;
80         do {
81             p = fgets(junk, sizeof(junk), ioPipe);
82         } while (p);
83 #else
84         for(;;)
85         {
86             int bytesRead = read (fileno (ioPipe),
87                     junk, sizeof (junk));
88             if (bytesRead < 1) break;
89             write (fileno (stdout), junk, bytesRead);
90         }
91 #endif
93         if (arguments != NULL) {
94             free(arguments);
95             arguments = NULL;
96         }
97         fclose(ioPipe);
98     }
102 cleanup:
103     AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
104     authorizationRef = 0;
106     if (arguments != NULL)
107         free(arguments);
109     return err;
112 - (OSStatus)askUserForPermission
114     int i;
116     assert(authorizationRef != 0);
118     // The documentation for AuthorizationItem says that `value` should be
119     // the path to the full posix path for kAuthorizationRightExecute. But
120     // the installer sample "Calling a Privileged Installer" sets it to NULL.
121     // Gotta love Apple's documentation.
122     //
123     // If you don't set `value` correctly, you'll get an
124     // `errAuthorizationToolEnvironmentError` when you try to execute the
125     // command.
126     AuthorizationItem* authItems =
127         malloc([commands count] * sizeof(AuthorizationItem));
128     for (i = 0; i < [commands count]; ++i) {
129         authItems[i].name = kAuthorizationRightExecute;
130         authItems[i].value = (void*)
131             [[[commands objectAtIndex:i] objectForKey:MMCommand] UTF8String];
132         authItems[i].valueLength = strlen(authItems[i].value);
133         authItems[i].flags = 0;
134     }
136     AuthorizationRights rights = {
137         [commands count], authItems
138     };
139     
140     OSStatus err = AuthorizationCopyRights(authorizationRef, &rights, NULL,
141             kAuthorizationFlagInteractionAllowed |
142             kAuthorizationFlagPreAuthorize |
143             kAuthorizationFlagExtendRights
144             , NULL);
146     free(authItems);
148     return err;
151 @end
153 NSString *MMCommand   = @"MMCommand";
154 NSString *MMArguments = @"MMArguments";