1 // ====================================================================== //
2 // BLAuthentication.h //
4 // Last Modified on Tuesday April 24 2001 //
5 // Copyright 2001 Ben Lachman //
7 // Thanks to Brian R. Hill <http://personalpages.tds.net/~brian_hill/> //
8 // ====================================================================== //
10 #import "BLAuthentication.h"
11 #import <Security/AuthorizationTags.h>
13 @implementation BLAuthentication
15 // returns an instace of itself, creating one if needed
17 static id sharedTask = nil;
19 sharedTask = [[BLAuthentication alloc] init];
24 // initializes the super class and sets authorizationRef to NULL
27 authorizationRef = NULL;
31 // deauthenticates the user and deallocates memory
33 [self deauthenticate];
38 //============================================================================
39 // - (BOOL)isAuthenticated:(NSArray *)forCommands
40 //============================================================================
41 // Find outs if the user has the appropriate authorization rights for the
42 // commands listed in (NSArray *)forCommands.
43 // This should be called each time you need to know whether the user
44 // is authorized, since the AuthorizationRef can be invalidated elsewhere, or
45 // may expire after a short period of time.
47 - (BOOL)isAuthenticated:(NSArray *)forCommands {
48 AuthorizationRights rights;
49 AuthorizationRights *authorizedRights;
50 AuthorizationFlags flags;
52 int numItems = [forCommands count];
53 AuthorizationItem *items = malloc( sizeof(AuthorizationItem) * numItems );
54 char paths[20][128]; // only handles upto 20 commands with paths upto 128 characters in length
60 if(authorizationRef==NULL) {
64 flags = kAuthorizationFlagDefaults;
66 err = AuthorizationCreate(&rights, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
73 while( i < numItems && i < 20 ) {
74 [[forCommands objectAtIndex:i] getCString:paths[i]];
76 items[i].name = kAuthorizationRightExecute;
77 items[i].value = paths[i];
78 items[i].valueLength = [[forCommands objectAtIndex:i] cStringLength];
84 rights.count = numItems;
87 flags = kAuthorizationFlagExtendRights;
89 err = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment, flags, &authorizedRights);
91 authorized = (errAuthorizationSuccess==err);
94 AuthorizationFreeItemSet(authorizedRights);
101 //============================================================================
102 // - (void)deauthenticate
103 //============================================================================
104 // Deauthenticates the user by freeing their authorization.
106 - (void)deauthenticate {
107 if(authorizationRef) {
108 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
109 authorizationRef = NULL;
110 [[NSNotificationCenter defaultCenter]postNotificationName:BLDeauthenticatedNotification object:self];
114 //============================================================================
115 // - (BOOL)fetchPassword:(NSArray *)forCommands
116 //============================================================================
117 // Adds rights for commands specified in (NSArray *)forCommands.
118 // Commands should be passed as a NSString comtaining the path to the executable.
119 // Returns YES if rights were gained
121 - (BOOL)fetchPassword:(NSArray *)forCommands {
122 AuthorizationRights rights;
123 AuthorizationRights *authorizedRights;
124 AuthorizationFlags flags;
126 int numItems = [forCommands count];
127 AuthorizationItem *items = malloc( sizeof(AuthorizationItem) * numItems );
131 BOOL authorized = NO;
137 while( i < numItems && i < 20 ) {
138 [[forCommands objectAtIndex:i] getCString:paths[i]];
140 items[i].name = kAuthorizationRightExecute;
141 items[i].value = paths[i];
142 items[i].valueLength = [[forCommands objectAtIndex:i] cStringLength];
148 rights.count = numItems;
149 rights.items = items;
151 flags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
153 err = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment, flags, &authorizedRights);
155 authorized = (errAuthorizationSuccess == err);
158 AuthorizationFreeItemSet(authorizedRights);
159 [[NSNotificationCenter defaultCenter] postNotificationName:BLAuthenticatedNotification object:self];
167 //============================================================================
168 // - (BOOL)authenticate:(NSArray *)forCommands
169 //============================================================================
170 // Authenticates the commands in the array (NSArray *)forCommands by calling
173 - (BOOL)authenticate:(NSArray *)forCommands {
174 if( ![self isAuthenticated:forCommands] ) {
175 [self fetchPassword:forCommands];
178 return [self isAuthenticated:forCommands];
182 //============================================================================
183 // - (int)getPID:(NSString *)forProcess
184 //============================================================================
185 // Retrieves the PID (process ID) for the process specified in
186 // (NSString *)forProcess.
187 // The more specific forProcess is the better your accuracy will be, esp. when
188 // multiple versions of the process exist.
190 - (int)getPID:(NSString *)forProcess {
191 FILE* outpipe = NULL;
192 NSMutableData* outputData = [NSMutableData data];
193 NSMutableData* tempData = [[NSMutableData alloc] initWithLength:512];
194 NSString *commandOutput = nil;
195 NSString *scannerOutput = nil;
196 NSString *popenArgs = [[NSString alloc] initWithFormat:@"/bin/ps -axwwopid,command | grep \"%@\"",forProcess];
197 NSScanner *outputScanner = nil;
198 NSScanner *intScanner = nil;
202 outpipe = popen([popenArgs cString],"r");
207 NSLog(@"Error opening pipe: %@",forProcess);
213 [tempData setLength:512];
214 len = fread([tempData mutableBytes],1,512,outpipe);
216 [tempData setLength:len];
217 [outputData appendData:tempData];
225 commandOutput = [[NSString alloc] initWithData:outputData encoding:NSASCIIStringEncoding];
227 if( [commandOutput length] > 0 ) {
228 outputScanner = [NSScanner scannerWithString:commandOutput];
230 [commandOutput release];
232 [outputScanner setCharactersToBeSkipped:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
234 [outputScanner scanUpToString:forProcess intoString:&scannerOutput];
236 if( [scannerOutput rangeOfString:@"grep"].length != 0 ) {
240 intScanner = [NSScanner scannerWithString:scannerOutput];
242 [intScanner scanInt:&pid];
252 [commandOutput release];
259 //============================================================================
260 // -(void)executeCommand:(NSString *)pathToCommand withArgs:(NSArray *)arguments
261 //============================================================================
262 // Executes command in (NSString *)pathToCommand with the arguments listed in
263 // (NSArray *)arguments as root.
264 // pathToCommand should be a string contain the path to the command
265 // (eg., /usr/bin/more), arguments should be an array of strings each containing
266 // a single argument.
268 -(BOOL)executeCommand:(NSString *)pathToCommand withArgs:(NSArray *)arguments {
269 char* args[30]; // can only handle 30 arguments to a given command
273 if(![self authenticate:[NSArray arrayWithObject:pathToCommand]])
276 if( arguments == nil || [arguments count] < 1 ) {
277 err = AuthorizationExecuteWithPrivileges(authorizationRef, [pathToCommand cString], 0, NULL, NULL);
280 while( i < [arguments count] && i < 19) {
281 args[i] = (char*)[[arguments objectAtIndex:i] cString];
286 err = AuthorizationExecuteWithPrivileges(authorizationRef,
287 [pathToCommand cString],
293 NSLog(@"Error %d in AuthorizationExecuteWithPrivileges",err);
302 //============================================================================
303 // - (void)killProcess:(NSString *)commandFromPS
304 //============================================================================
305 // Finds and kills the process specified in (NSString *)commandFromPS using ps
306 // and kill. (by pid)
307 // The more specific (ie., closer to matching the actual listing in ps)
308 // commandFromPS is the better your accuracy will be, esp. when multiple
309 // versions of the process exist.
311 - (BOOL)killProcess:(NSString *)commandFromPS {
314 if( ![self isAuthenticated:[NSArray arrayWithObject:commandFromPS]] ) {
315 [self authenticate:[NSArray arrayWithObject:commandFromPS]];
318 pid = [NSString stringWithFormat:@"%d",[self getPID:commandFromPS]];
320 if( [pid intValue] > 0 ) {
321 [self executeCommand:@"/bin/kill" withArgs:[NSArray arrayWithObject:pid]];
326 NSLog(@"Error killing process %@, invalid PID.",pid);
332 // BLAuthentication sends these notifications are sent when the user
333 // becomes authenticated or deauthenticated.
334 NSString* BLAuthenticatedNotification = @"BLAuthenticatedNotification";
335 NSString* BLDeauthenticatedNotification = @"BLDeauthenticatedNotification";
337 // Sample notification observer:
339 [[NSNotificationCenter defaultCenter] addObserver:self
340 selector:@selector(userAuthenticated:)
341 name:BLAuthenticatedNotification
342 object:[BLAuthentication sharedInstance]];
343 [[NSNotificationCenter defaultCenter] addObserver:self
344 selector:@selector(userDeauthenticated:)
345 name:BLDeauthenticatedNotification
346 object:[BLAuthentication sharedInstance]];