5 // Created by Claudio on 10/07/07.
6 // Copyright 2007 INFN - National Institute of Nuclear Physics. All rights reserved.
9 #import "AFSMenuExtra.h"
10 #import "AFSMenuExtraView.h"
11 #import "AFSPropertyManager.h"
13 #import "TokenCredentialController.h"
14 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
19 #include <sys/errno.h>
24 @implementation AFSMenuExtra
25 // -------------------------------------------------------------------------------
26 // -(id) initWithBundle
27 // -------------------------------------------------------------------------------
28 - (id) initWithBundle:(NSBundle *)bundle
30 self = [super initWithBundle:bundle];
35 tokensLock = [[NSLock alloc] init];
36 // inizialize the afspath
38 credentialMenuController = nil;
40 theView = [[AFSMenuExtraView alloc] initWithFrame:[[self view] frame]
42 [self setView:theView];
45 // Get the imge for menu
46 //Load image for menu rappresentation
47 hasTokenImage = [self getImageFromBundle:@"hasToken"
50 noTokenImage = [self getImageFromBundle:@"noToken"
53 theMenu = [[NSMenu alloc] initWithTitle: @""];
54 [theMenu setAutoenablesItems: NO];
55 startStopMenu = [theMenu addItemWithTitle: kAfsOff action: @selector(startStopAfs:) keyEquivalent: @""];
56 [startStopMenu setTarget:self];
58 loginMenu = [theMenu addItemWithTitle: kMenuLogin action: @selector(getToken:) keyEquivalent: @""];
59 [loginMenu setTarget:self];
61 unlogMenu = [theMenu addItemWithTitle: kMenuUnlog action: @selector(releaseToken:) keyEquivalent: @""];
62 [unlogMenu setTarget:self];
64 // Register for preference user change
65 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(readPreferenceFile:)
66 name:kAFSMenuExtraID object:kPrefChangeNotification];
68 // Register for afs state change
69 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(afsVolumeMountChange:)
70 name:kAFSMenuExtraID object:kMExtraAFSStateChange];
73 //Register for mount/unmount afs volume
74 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
75 selector:@selector(afsVolumeMountChange:)
76 name:NSWorkspaceDidMountNotification object:nil];
78 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
79 selector:@selector(afsVolumeMountChange:)
80 name:NSWorkspaceDidUnmountNotification object:nil];
81 //Start to read the afs path
82 [self readPreferenceFile:nil];
87 // -------------------------------------------------------------------------------
89 // -------------------------------------------------------------------------------
94 if(hasTokenImage) [hasTokenImage release];
95 if(noTokenImage) [noTokenImage release];
97 // Unregister for preference change
98 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kPrefChangeNotification];
99 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSStateChange];
100 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidMountNotification object:nil];
101 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidUnmountNotification object:nil];
104 [tokensLock release];
107 // -------------------------------------------------------------------------------
109 // -------------------------------------------------------------------------------
111 //start the time for check tokens validity
112 if(timerForCheckTokensList) return;
113 timerForCheckTokensList = [NSTimer scheduledTimerWithTimeInterval:TOKENS_REFRESH_TIME_IN_SEC
115 selector:@selector(updateAfsStatus:)
118 [timerForCheckTokensList fire];
121 // -------------------------------------------------------------------------------
123 // -------------------------------------------------------------------------------
125 if(!timerForCheckTokensList) return;
126 [timerForCheckTokensList invalidate];
127 timerForCheckTokensList = nil;
129 // -------------------------------------------------------------------------------
131 // -------------------------------------------------------------------------------
136 if(afsSysPath) [afsSysPath release];
137 // send notify that menuextra has closed
138 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:afsCommanderID object:kPrefChangeNotification];
142 // -------------------------------------------------------------------------------
144 // -------------------------------------------------------------------------------
151 // -------------------------------------------------------------------------------
152 // -(void) readPreferenceFile
153 // -------------------------------------------------------------------------------
154 - (void) readPreferenceFile:(NSNotification *)notification
156 NSLog(@"Reading preference file");
157 //CFPreferencesSynchronize((CFStringRef)afsCommanderID, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
158 //CFPreferencesSynchronize((CFStringRef)afsCommanderID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
161 [afsSysPath release];
165 afsSysPath = PREFERENCE_AFS_SYS_PAT_STATIC;/*(NSString*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_AFS_SYS_PAT,
166 (CFStringRef)afsCommanderID,
167 kCFPreferencesAnyUser,
168 kCFPreferencesAnyHost);*/
169 //NSLog(@"Path readed %s", (afsSysPath==nil?[afsSysPath UTF8String]:@" no path found "));
171 // read the preference for aklog use
172 useAklogPrefValue = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_USE_AKLOG,
173 (CFStringRef)afsCommanderID,
174 kCFPreferencesCurrentUser,
175 kCFPreferencesAnyHost);
177 //NSLog(@"Preference readed for useAklogPrefValue %d", [useAklogPrefValue intValue]);
179 [self updateAfsStatus:nil];
182 // -------------------------------------------------------------------------------
183 // -(void) readPreferenceFile
184 // -------------------------------------------------------------------------------
185 - (void)startStopAfs:(id)sender
187 NSLog(@"startStopAfs: %s",[afsSysPath UTF8String]);
188 if(!afsSysPath) return;
190 OSStatus status = noErr;
191 NSString *afsdPath = [TaskUtil searchExecutablePath:@"afsd"];
192 NSString *rootHelperApp = nil;
193 BOOL currentAfsState = NO;
196 if(afsdPath == nil) return;
197 AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
198 currentAfsState = [afsMngr checkAfsStatus];
201 rootHelperApp = [[self bundle] pathForResource:@"afshlp" ofType:@""];
203 //[startStopScript setString: resourcePath];
204 //NSLog(@"LAunch repair HelperTool");
206 [self repairHelperTool];
208 // make the parameter to call the root helper app
209 //NSLog(@"Path installazione afs: %s",[afsSysPath UTF8String]);
210 //NSLog(@"Path installazione afsd: %s", [afsdPath UTF8String]);
211 status = [[AuthUtil shared] autorize];
215 //NSLog(@"Shutting down afs");
216 NSMutableString *afsKextPath = [[NSMutableString alloc] initWithCapacity:256];
217 [afsKextPath setString:afsSysPath];
218 [afsKextPath appendString:@"/etc/afs.kext"];
220 //NSLog(@"executeTaskWithAuth");
221 const char *stopAfsArgs[] = {"stop_afs", [afsKextPath UTF8String], [afsdPath UTF8String], 0L};
222 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
226 //NSLog(@"Starting up afs");
227 const char *startAfsArgs[] = {[[[self bundle] pathForResource:@"start_afs" ofType:@"sh"] UTF8String], [afsSysPath UTF8String], [afsdPath UTF8String], 0L};
228 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
234 @catch (NSException * e) {
238 [[AuthUtil shared] deautorize];
239 [self updateAfsStatus:nil];
240 //Send notification to preferencepane
241 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:afsCommanderID object:kMenuExtraEventOccured];
246 // -------------------------------------------------------------------------------
248 // -------------------------------------------------------------------------------
249 - (void)getToken:(id)sender
253 globalRect.origin = [[[self view] window] convertBaseToScreen:[[self view] frame].origin];
254 globalRect.size = [[self view] frame].size;
255 AFSPropertyManager *afsPropMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath ];
256 [afsPropMngr loadConfiguration];
259 if([useAklogPrefValue intValue]==NSOnState ) {
261 [afsPropMngr getTokens:false
264 [self klogUserEven:nil];
267 // register for user event
268 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
269 selector:@selector(klogUserEven:)
271 object:kLogWindowClosed];
273 credentialMenuController = [[AFSMenuCredentialContoller alloc] initWhitRec:globalRect
274 afsPropManager:afsPropMngr];
275 [credentialMenuController showWindow];
278 //Dispose afs manager
279 [afsPropMngr release];
282 // -------------------------------------------------------------------------------
283 // -(void) releaseToken
284 // -------------------------------------------------------------------------------
285 - (void)releaseToken:(id)sender
287 AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
290 [self updateAfsStatus:nil];
294 // -------------------------------------------------------------------------------
295 // -(void) afsVolumeMountChange - Track for mount unmount afs volume
296 // -------------------------------------------------------------------------------
297 - (void) afsVolumeMountChange:(NSNotification *)notification{
298 [self updateAfsStatus:nil];
301 // -------------------------------------------------------------------------------
302 // -(void) updateAfsStatus
303 // -------------------------------------------------------------------------------
304 - (void)updateAfsStatus:(NSTimer*)timer
307 if(![tokensLock tryLock]) return;
309 // check the afs state in esclusive mode
310 AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
311 afsState = [afsMngr checkAfsStatus];
313 NSArray *tokens = [afsMngr getTokenList];
315 gotToken = [tokens count] > 0;
317 // update the menu item title
318 [startStopMenu setTitle:afsState?kAfsButtonShutdown:kAfsButtonStartup];
322 [theView setNeedsDisplay:YES];
328 // -------------------------------------------------------------------------------
329 // -(void) klogUserEven
330 // -------------------------------------------------------------------------------
331 -(void) klogUserEven:(NSNotification *)notification
333 if(credentialMenuController) {
334 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kLogWindowClosed];
335 [credentialMenuController closeWindow];
336 [credentialMenuController release];
337 credentialMenuController = nil;
339 //Send notification to PreferencePane
340 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:afsCommanderID object:kMenuExtraEventOccured];
342 [self updateAfsStatus:nil];
345 // -------------------------------------------------------------------------------
346 // -(void) getImageFromBundle
347 // -------------------------------------------------------------------------------
348 - (NSImage*)getImageFromBundle:(NSString*)fileName fileExt:(NSString*)ext
350 return [[NSImage alloc]initWithContentsOfFile:[[self bundle] pathForResource:fileName
354 // -------------------------------------------------------------------------------
355 // -(void) imageToRender
356 // -------------------------------------------------------------------------------
357 - (NSImage*)imageToRender
360 return hasTokenImage;
367 // -------------------------------------------------------------------------------
368 // -(void) updateMenu
369 // -------------------------------------------------------------------------------
371 [loginMenu setEnabled:afsState];
372 [unlogMenu setEnabled:afsState];
376 // -------------------------------------------------------------------------------
377 // -(void) useAklogPrefValue
378 // -------------------------------------------------------------------------------
379 - (BOOL)useAklogPrefValue
381 if(useAklogPrefValue) return [useAklogPrefValue intValue] == NSOnState;
382 else return NSOffState;
385 // -------------------------------------------------------------------------------
387 // -------------------------------------------------------------------------------
388 - (void) repairHelperTool
393 NSLog(@"repairHelperTool");
394 NSString *afshlpPath = [[self bundle] pathForResource:@"afshlp" ofType:nil];
398 // Open tool exclusively, so nobody can change it while we bless it.
399 fdTool = open([afshlpPath UTF8String], O_NONBLOCK | O_RDONLY | O_EXLOCK, 0);
403 NSLog(@"Exclusive open while repairing tool failed: %d.", errno);
407 if(fstat(fdTool, &st))
409 NSLog(@"fstat failed.");
415 status = [[AuthUtil shared] autorize];
417 fchown(fdTool, 0, st.st_gid);
419 // Disable group and world writability and make setuid root.
420 fchmod(fdTool, (st.st_mode & (~(S_IWGRP | S_IWOTH)))/* | S_ISUID*/);
421 const char *args[] = {"root", [afshlpPath UTF8String],0L};
422 [[AuthUtil shared] execUnixCommand:"/usr/sbin/chown"
425 [[AuthUtil shared] deautorize];
427 } else NSLog(@"st_uid = 0");
433 NSLog(@"Self-repair done.");