| 1 |
#import "AgentController.h" |
|---|
| 2 |
#import "TokenController.h" |
|---|
| 3 |
|
|---|
| 4 |
#include <unistd.h> |
|---|
| 5 |
|
|---|
| 6 |
#import "Controller.h" |
|---|
| 7 |
#import "PreferenceController.h" |
|---|
| 8 |
#import "TunnelController.h" |
|---|
| 9 |
|
|---|
| 10 |
#import "Libs/SSHTool.h" |
|---|
| 11 |
|
|---|
| 12 |
#include "SSHKeychain_Prefix.pch" |
|---|
| 13 |
|
|---|
| 14 |
/* This function resides in Controller.m. */ |
|---|
| 15 |
extern NSString *local(NSString *theString); |
|---|
| 16 |
extern int sleep_timestamp; |
|---|
| 17 |
|
|---|
| 18 |
AgentController *sharedAgentController; |
|---|
| 19 |
|
|---|
| 20 |
@implementation AgentController |
|---|
| 21 |
|
|---|
| 22 |
- (id)init |
|---|
| 23 |
{ |
|---|
| 24 |
if(!(self = [super init])) |
|---|
| 25 |
{ |
|---|
| 26 |
return nil; |
|---|
| 27 |
} |
|---|
| 28 |
|
|---|
| 29 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 30 |
selector:@selector(applicationDidFinishLaunching:) |
|---|
| 31 |
name:@"NSApplicationDidFinishLaunchingNotification" object:NSApp]; |
|---|
| 32 |
|
|---|
| 33 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 34 |
selector:@selector(powerChange:) name:@"SKSleep" object:nil]; |
|---|
| 35 |
|
|---|
| 36 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 37 |
selector:@selector(powerChange:) name:@"SKWake" object:nil]; |
|---|
| 38 |
|
|---|
| 39 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 40 |
selector:@selector(appleKeychainNotification:) name:@"AppleKeychainLocked" object:nil]; |
|---|
| 41 |
|
|---|
| 42 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 43 |
selector:@selector(appleKeychainNotification:) name:@"AppleKeychainUnlocked" object:nil]; |
|---|
| 44 |
|
|---|
| 45 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 46 |
selector:@selector(applicationWillTerminate:) |
|---|
| 47 |
name:@"NSApplicationWillTerminateNotification" object:NSApp]; |
|---|
| 48 |
|
|---|
| 49 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 50 |
selector:@selector(keychainChanged:) name:@"KeychainChanged" object:nil]; |
|---|
| 51 |
|
|---|
| 52 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 53 |
selector:@selector(keysOnAgentStatusChange:) name:@"AgentFilled" object:nil]; |
|---|
| 54 |
|
|---|
| 55 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 56 |
selector:@selector(keysOnAgentStatusChange:) name:@"AgentEmptied" object:nil]; |
|---|
| 57 |
|
|---|
| 58 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 59 |
selector:@selector(keysOnAgentStatusChange:) name:@"KeysOnAgentUnknown" object:nil]; |
|---|
| 60 |
|
|---|
| 61 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 62 |
selector:@selector(agentStatusChange:) name:@"AgentStarted" object:nil]; |
|---|
| 63 |
|
|---|
| 64 |
[[NSNotificationCenter defaultCenter] addObserver:self |
|---|
| 65 |
selector:@selector(agentStatusChange:) name:@"AgentStopped" object:nil]; |
|---|
| 66 |
|
|---|
| 67 |
[[NSDistributedNotificationCenter defaultCenter] addObserver:self |
|---|
| 68 |
selector:@selector(onScreenSaver:) name:@"com.apple.screensaver.didstart" object:nil]; |
|---|
| 69 |
|
|---|
| 70 |
allKeysOnAgentLock = [[NSLock alloc] init]; |
|---|
| 71 |
|
|---|
| 72 |
sharedAgentController = self; |
|---|
| 73 |
|
|---|
| 74 |
return self; |
|---|
| 75 |
} |
|---|
| 76 |
|
|---|
| 77 |
+ (AgentController *)sharedController |
|---|
| 78 |
{ |
|---|
| 79 |
if(!sharedAgentController) { |
|---|
| 80 |
return [[AgentController alloc] init]; |
|---|
| 81 |
} |
|---|
| 82 |
|
|---|
| 83 |
return sharedAgentController; |
|---|
| 84 |
} |
|---|
| 85 |
|
|---|
| 86 |
- (void)dealloc |
|---|
| 87 |
{ |
|---|
| 88 |
[allKeysOnAgentLock dealloc]; |
|---|
| 89 |
|
|---|
| 90 |
[super dealloc]; |
|---|
| 91 |
} |
|---|
| 92 |
|
|---|
| 93 |
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification |
|---|
| 94 |
{ |
|---|
| 95 |
NSString *path = [[NSUserDefaults standardUserDefaults] stringForKey:SocketPathString]; |
|---|
| 96 |
|
|---|
| 97 |
NSString *agentPath = [[[NSUserDefaults standardUserDefaults] stringForKey:SSHToolsPathString] stringByAppendingPathComponent:@"ssh-agent"]; |
|---|
| 98 |
|
|---|
| 99 |
SecKeychainStatus status; |
|---|
| 100 |
SecKeychainGetStatus(nil, &status); |
|---|
| 101 |
|
|---|
| 102 |
agent = [SSHAgent currentAgent]; |
|---|
| 103 |
keychain = [SSHKeychain currentKeychain]; |
|---|
| 104 |
|
|---|
| 105 |
[agent setSocketPath:path]; |
|---|
| 106 |
|
|---|
| 107 |
if(![[NSFileManager defaultManager] isExecutableFileAtPath:agentPath]) |
|---|
| 108 |
{ |
|---|
| 109 |
[self warningPanelWithTitle:local(@"StartAgent") andMessage:local(@"AgentNotFound")]; |
|---|
| 110 |
return; |
|---|
| 111 |
} |
|---|
| 112 |
|
|---|
| 113 |
if([self checkSocketPath:path]) |
|---|
| 114 |
{ |
|---|
| 115 |
if([agent start] == NO) |
|---|
| 116 |
{ |
|---|
| 117 |
[self warningPanelWithTitle:local(@"StartAgent") andMessage:local(@"FailedToStartAgent")]; |
|---|
| 118 |
} |
|---|
| 119 |
} |
|---|
| 120 |
|
|---|
| 121 |
else |
|---|
| 122 |
{ |
|---|
| 123 |
[self warningPanelWithTitle:local(@"StartAgent") andMessage:local(@"FailedToStartAgentSocketpathInvalid")]; |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
if((status & 1) |
|---|
| 127 |
&& (([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 3) |
|---|
| 128 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 4)) |
|---|
| 129 |
&& (![keychain addingKeys])) |
|---|
| 130 |
{ |
|---|
| 131 |
|
|---|
| 132 |
[allKeysOnAgentLock lock]; |
|---|
| 133 |
|
|---|
| 134 |
if(allKeysOnAgent) |
|---|
| 135 |
{ |
|---|
| 136 |
[allKeysOnAgentLock unlock]; |
|---|
| 137 |
return; |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
[allKeysOnAgentLock unlock]; |
|---|
| 141 |
|
|---|
| 142 |
SecKeychainGetStatus(nil, &status); |
|---|
| 143 |
|
|---|
| 144 |
if((status & 1) && ([agent isRunning])) |
|---|
| 145 |
{ |
|---|
| 146 |
[keychain addKeysToAgentWithInteraction:NO]; |
|---|
| 147 |
} |
|---|
| 148 |
} |
|---|
| 149 |
|
|---|
| 150 |
[[TunnelController sharedController] launchAfterSleepTunnels]; |
|---|
| 151 |
} |
|---|
| 152 |
|
|---|
| 153 |
- (void)applicationWillTerminate:(NSNotification *)notification |
|---|
| 154 |
{ |
|---|
| 155 |
[agent stop]; |
|---|
| 156 |
} |
|---|
| 157 |
|
|---|
| 158 |
- (void)powerChange:(NSNotification *)notification |
|---|
| 159 |
{ |
|---|
| 160 |
if([[notification name] isEqualToString:@"SKSleep"]) |
|---|
| 161 |
{ |
|---|
| 162 |
[[TunnelController sharedController] closeAllTunnels]; |
|---|
| 163 |
} |
|---|
| 164 |
|
|---|
| 165 |
if([[notification name] isEqualToString:@"SKWake"]) |
|---|
| 166 |
{ |
|---|
| 167 |
[[TunnelController sharedController] closeAllTunnels]; |
|---|
| 168 |
[[TunnelController sharedController] launchAfterSleepTunnels]; |
|---|
| 169 |
} |
|---|
| 170 |
|
|---|
| 171 |
if(([[NSUserDefaults standardUserDefaults] integerForKey:OnSleepString] == 1) && ([[agent keysOnAgent] count] > 0)) |
|---|
| 172 |
{ |
|---|
| 173 |
int minutes = [[NSUserDefaults standardUserDefaults] integerForKey:MinutesOfSleepString]; |
|---|
| 174 |
|
|---|
| 175 |
if([[notification name] isEqualToString:@"SKSleep"]) |
|---|
| 176 |
{ |
|---|
| 177 |
sleep_timestamp = time(nil); |
|---|
| 178 |
} |
|---|
| 179 |
|
|---|
| 180 |
else if(([[notification name] isEqualToString:@"SKWake"]) && (sleep_timestamp != 0)) |
|---|
| 181 |
{ |
|---|
| 182 |
/* |
|---|
| 183 |
* Reduce the output of time() by minutes * 60 (to get the seconds), |
|---|
| 184 |
* if it's more than the timestamp, remove all keys. |
|---|
| 185 |
*/ |
|---|
| 186 |
|
|---|
| 187 |
if((time(nil) - (minutes * 60)) > sleep_timestamp) |
|---|
| 188 |
{ |
|---|
| 189 |
[self removeKeysFromAgent:nil]; |
|---|
| 190 |
} |
|---|
| 191 |
|
|---|
| 192 |
sleep_timestamp = 0; |
|---|
| 193 |
} |
|---|
| 194 |
} |
|---|
| 195 |
} |
|---|
| 196 |
|
|---|
| 197 |
- (void)appleKeychainNotification:(NSNotification *)notification |
|---|
| 198 |
{ |
|---|
| 199 |
if(([[notification name] isEqualToString:@"AppleKeychainLocked"]) |
|---|
| 200 |
&& (([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 2) |
|---|
| 201 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 4))) |
|---|
| 202 |
{ |
|---|
| 203 |
if([[agent keysOnAgent] count] > 0) |
|---|
| 204 |
{ |
|---|
| 205 |
[self removeKeysFromAgent:nil]; |
|---|
| 206 |
} |
|---|
| 207 |
} |
|---|
| 208 |
|
|---|
| 209 |
else if(([[notification name] isEqualToString:@"AppleKeychainUnlocked"]) |
|---|
| 210 |
&& (([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 3) |
|---|
| 211 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 4)) |
|---|
| 212 |
&& (![keychain addingKeys])) |
|---|
| 213 |
{ |
|---|
| 214 |
|
|---|
| 215 |
[allKeysOnAgentLock lock]; |
|---|
| 216 |
|
|---|
| 217 |
if(allKeysOnAgent) |
|---|
| 218 |
{ |
|---|
| 219 |
[allKeysOnAgentLock unlock]; |
|---|
| 220 |
return; |
|---|
| 221 |
} |
|---|
| 222 |
|
|---|
| 223 |
[allKeysOnAgentLock unlock]; |
|---|
| 224 |
|
|---|
| 225 |
[keychain addKeysToAgentWithInteraction:NO]; |
|---|
| 226 |
} |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
- (void)keychainChanged:(NSNotification *)notification |
|---|
| 230 |
{ |
|---|
| 231 |
if([keychain count] > 0) |
|---|
| 232 |
{ |
|---|
| 233 |
[mainMenuAddKeysItem setEnabled:YES]; |
|---|
| 234 |
[dockMenuAddKeysItem setEnabled:YES]; |
|---|
| 235 |
[statusbarMenuAddKeysItem setEnabled:YES]; |
|---|
| 236 |
} |
|---|
| 237 |
|
|---|
| 238 |
else |
|---|
| 239 |
{ |
|---|
| 240 |
[mainMenuAddKeysItem setEnabled:NO]; |
|---|
| 241 |
[dockMenuAddKeysItem setEnabled:NO]; |
|---|
| 242 |
[statusbarMenuAddKeysItem setEnabled:NO]; |
|---|
| 243 |
} |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|
| 246 |
- (void)keysOnAgentStatusChange:(NSNotification *)notification |
|---|
| 247 |
{ |
|---|
| 248 |
if([[notification name] isEqualToString:@"AgentEmptied"]) |
|---|
| 249 |
{ |
|---|
| 250 |
[self updateUI]; |
|---|
| 251 |
|
|---|
| 252 |
[mainMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 253 |
[dockMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 254 |
[statusbarMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 255 |
|
|---|
| 256 |
[mainMenuAddKeysItem setEnabled:YES]; |
|---|
| 257 |
[dockMenuAddKeysItem setEnabled:YES]; |
|---|
| 258 |
[statusbarMenuAddKeysItem setEnabled:YES]; |
|---|
| 259 |
|
|---|
| 260 |
[allKeysOnAgentLock lock]; |
|---|
| 261 |
allKeysOnAgent = NO; |
|---|
| 262 |
[allKeysOnAgentLock unlock]; |
|---|
| 263 |
|
|---|
| 264 |
[[Controller sharedController] setStatus:NO]; |
|---|
| 265 |
} |
|---|
| 266 |
|
|---|
| 267 |
else if([[notification name] isEqualToString:@"AgentFilled"]) |
|---|
| 268 |
{ |
|---|
| 269 |
[self updateUI]; |
|---|
| 270 |
|
|---|
| 271 |
[mainMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 272 |
[dockMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 273 |
[statusbarMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 274 |
|
|---|
| 275 |
[mainMenuAddKeysItem setEnabled:NO]; |
|---|
| 276 |
[dockMenuAddKeysItem setEnabled:NO]; |
|---|
| 277 |
[statusbarMenuAddKeysItem setEnabled:NO]; |
|---|
| 278 |
|
|---|
| 279 |
[allKeysOnAgentLock lock]; |
|---|
| 280 |
allKeysOnAgent = YES; |
|---|
| 281 |
[allKeysOnAgentLock unlock]; |
|---|
| 282 |
|
|---|
| 283 |
if ([[NSUserDefaults standardUserDefaults] integerForKey:KeyTimeoutString] > 0) |
|---|
| 284 |
{ |
|---|
| 285 |
// Self firing timer with reset |
|---|
| 286 |
[[self class] cancelPreviousPerformRequestsWithTarget: self ]; |
|---|
| 287 |
[self performSelector: @selector(removeKeysFromAgent:) |
|---|
| 288 |
withObject: nil |
|---|
| 289 |
afterDelay: [[NSUserDefaults standardUserDefaults] |
|---|
| 290 |
integerForKey:KeyTimeoutString] * 60.00 ]; |
|---|
| 291 |
} |
|---|
| 292 |
|
|---|
| 293 |
[[Controller sharedController] setStatus:YES]; |
|---|
| 294 |
} |
|---|
| 295 |
|
|---|
| 296 |
else if([[notification name] isEqualToString:@"KeysOnAgentUnknown"]) |
|---|
| 297 |
{ |
|---|
| 298 |
[self updateUI]; |
|---|
| 299 |
|
|---|
| 300 |
if([[agent keysOnAgent] count] > 0) |
|---|
| 301 |
{ |
|---|
| 302 |
[mainMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 303 |
[dockMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 304 |
[statusbarMenuRemoveKeysItem setEnabled:YES]; |
|---|
| 305 |
[[Controller sharedController] setStatus:YES]; |
|---|
| 306 |
} else { |
|---|
| 307 |
|
|---|
| 308 |
[mainMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 309 |
[dockMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 310 |
[statusbarMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 311 |
|
|---|
| 312 |
[[Controller sharedController] setStatus:NO]; |
|---|
| 313 |
} |
|---|
| 314 |
} |
|---|
| 315 |
} |
|---|
| 316 |
|
|---|
| 317 |
- (void)agentStatusChange:(NSNotification *)notification |
|---|
| 318 |
{ |
|---|
| 319 |
SecKeychainStatus status; |
|---|
| 320 |
|
|---|
| 321 |
if([[notification name] isEqualToString:@"AgentStarted"]) |
|---|
| 322 |
{ |
|---|
| 323 |
[self updateUI]; |
|---|
| 324 |
|
|---|
| 325 |
[keychain setAgentSocketPath:[agent agentSocketPath]]; |
|---|
| 326 |
|
|---|
| 327 |
[mainMenuAgentItem setTitle:local(@"StopAgent")]; |
|---|
| 328 |
[dockMenuAgentItem setTitle:local(@"StopAgent")]; |
|---|
| 329 |
[statusbarMenuAgentItem setTitle:local(@"StopAgent")]; |
|---|
| 330 |
|
|---|
| 331 |
[mainMenuAddKeysItem setEnabled:YES]; |
|---|
| 332 |
[dockMenuAddKeysItem setEnabled:YES]; |
|---|
| 333 |
[statusbarMenuAddKeysItem setEnabled:YES]; |
|---|
| 334 |
|
|---|
| 335 |
[mainMenuAddKeyItem setEnabled:YES]; |
|---|
| 336 |
[dockMenuAddKeyItem setEnabled:YES]; |
|---|
| 337 |
[statusbarMenuAddKeyItem setEnabled:YES]; |
|---|
| 338 |
|
|---|
| 339 |
[[Controller sharedController] setStatus:NO]; |
|---|
| 340 |
|
|---|
| 341 |
SecKeychainGetStatus(nil, &status); |
|---|
| 342 |
|
|---|
| 343 |
if((([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 3) |
|---|
| 344 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:FollowKeychainString] == 4)) |
|---|
| 345 |
&& (![keychain addingKeys]) && (status & 1) && ([agent isRunning])) |
|---|
| 346 |
{ |
|---|
| 347 |
[keychain addKeysToAgentWithInteraction:NO]; |
|---|
| 348 |
} |
|---|
| 349 |
|
|---|
| 350 |
} |
|---|
| 351 |
|
|---|
| 352 |
else if([[notification name] isEqualToString:@"AgentStopped"]) |
|---|
| 353 |
{ |
|---|
| 354 |
[self updateUI]; |
|---|
| 355 |
|
|---|
| 356 |
[keychain setAgentSocketPath:@""]; |
|---|
| 357 |
|
|---|
| 358 |
[mainMenuAgentItem setTitle:local(@"StartAgent")]; |
|---|
| 359 |
[dockMenuAgentItem setTitle:local(@"StartAgent")]; |
|---|
| 360 |
[statusbarMenuAgentItem setTitle:local(@"StartAgent")]; |
|---|
| 361 |
|
|---|
| 362 |
[mainMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 363 |
[dockMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 364 |
[statusbarMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 365 |
|
|---|
| 366 |
[mainMenuAddKeysItem setEnabled:NO]; |
|---|
| 367 |
[dockMenuAddKeysItem setEnabled:NO]; |
|---|
| 368 |
[statusbarMenuAddKeysItem setEnabled:NO]; |
|---|
| 369 |
|
|---|
| 370 |
[mainMenuAddKeyItem setEnabled:NO]; |
|---|
| 371 |
[dockMenuAddKeyItem setEnabled:NO]; |
|---|
| 372 |
[statusbarMenuAddKeyItem setEnabled:NO]; |
|---|
| 373 |
|
|---|
| 374 |
[[Controller sharedController] setStatus:NO]; |
|---|
| 375 |
|
|---|
| 376 |
[allKeysOnAgentLock lock]; |
|---|
| 377 |
allKeysOnAgent = NO; |
|---|
| 378 |
[allKeysOnAgentLock unlock]; |
|---|
| 379 |
} |
|---|
| 380 |
} |
|---|
| 381 |
|
|---|
| 382 |
- (void)awakeFromNib |
|---|
| 383 |
{ |
|---|
| 384 |
[keyTable setDataSource:self]; |
|---|
| 385 |
|
|---|
| 386 |
[[mainMenuRemoveKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 387 |
[[dockMenuRemoveKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 388 |
[[statusbarMenuRemoveKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 389 |
|
|---|
| 390 |
[[mainMenuAddKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 391 |
[[dockMenuAddKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 392 |
[[statusbarMenuAddKeysItem menu] setAutoenablesItems:NO]; |
|---|
| 393 |
|
|---|
| 394 |
[[mainMenuAddKeyItem menu] setAutoenablesItems:NO]; |
|---|
| 395 |
[[dockMenuAddKeyItem menu] setAutoenablesItems:NO]; |
|---|
| 396 |
[[statusbarMenuAddKeyItem menu] setAutoenablesItems:NO]; |
|---|
| 397 |
|
|---|
| 398 |
[mainMenuAddKeysItem setEnabled:NO]; |
|---|
| 399 |
[dockMenuAddKeysItem setEnabled:NO]; |
|---|
| 400 |
[statusbarMenuAddKeysItem setEnabled:NO]; |
|---|
| 401 |
|
|---|
| 402 |
[mainMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 403 |
[dockMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 404 |
[statusbarMenuRemoveKeysItem setEnabled:NO]; |
|---|
| 405 |
|
|---|
| 406 |
[mainMenuAddKeyItem setEnabled:NO]; |
|---|
| 407 |
[dockMenuAddKeyItem setEnabled:NO]; |
|---|
| 408 |
[statusbarMenuAddKeyItem setEnabled:NO]; |
|---|
| 409 |
|
|---|
| 410 |
if([keychain count] > 0) |
|---|
| 411 |
{ |
|---|
| 412 |
[mainMenuAddKeysItem setEnabled:YES]; |
|---|
| 413 |
[dockMenuAddKeysItem setEnabled:YES]; |
|---|
| 414 |
[statusbarMenuAddKeysItem setEnabled:YES]; |
|---|
| 415 |
} |
|---|
| 416 |
} |
|---|
| 417 |
|
|---|
| 418 |
- (IBAction)toggleAgent:(id)sender |
|---|
| 419 |
{ |
|---|
| 420 |
NSString *path; |
|---|
| 421 |
|
|---|
| 422 |
if([agent isRunning]) |
|---|
| 423 |
{ |
|---|
| 424 |
if([agent stop] == NO) |
|---|
| 425 |
{ |
|---|
| 426 |
[self warningPanelWithTitle:local(@"StopAgent") andMessage:local(@"FailedToStopAgent")]; |
|---|
| 427 |
} |
|---|
| 428 |
} |
|---|
| 429 |
|
|---|
| 430 |
else { |
|---|
| 431 |
path = [[NSUserDefaults standardUserDefaults] stringForKey:SocketPathString]; |
|---|
| 432 |
|
|---|
| 433 |
[agent setSocketPath:path]; |
|---|
| 434 |
|
|---|
| 435 |
if([self checkSocketPath:path]) |
|---|
| 436 |
{ |
|---|
| 437 |
if([agent start] == NO) |
|---|
| 438 |
{ |
|---|
| 439 |
[self warningPanelWithTitle:local(@"StartAgent") andMessage:local(@"FailedToStartAgent")]; |
|---|
| 440 |
} |
|---|
| 441 |
} |
|---|
| 442 |
|
|---|
| 443 |
else |
|---|
| 444 |
{ |
|---|
| 445 |
[self warningPanelWithTitle:local(@"StartAgent") andMessage:local(@"FailedToStartAgentSocketpathInvalid")]; |
|---|
| 446 |
} |
|---|
| 447 |
} |
|---|
| 448 |
} |
|---|
| 449 |
|
|---|
| 450 |
- (IBAction)addKeysToAgent:(id)sender |
|---|
| 451 |
{ |
|---|
| 452 |
if([agent isRunning]) |
|---|
| 453 |
{ |
|---|
| 454 |
[NSThread detachNewThreadSelector:@selector(addKeysToAgentInNewThread) |
|---|
| 455 |
toTarget:self withObject:nil]; |
|---|
| 456 |
} |
|---|
| 457 |
|
|---|
| 458 |
else |
|---|
| 459 |
{ |
|---|
| 460 |
[self warningPanelWithTitle:local(@"AddKeysToAgent") andMessage:local(@"AgentNotRunning")]; |
|---|
| 461 |
} |
|---|
| 462 |
} |
|---|
| 463 |
|
|---|
| 464 |
- (void)addKeysToAgentInNewThread |
|---|
| 465 |
{ |
|---|
| 466 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 467 |
|
|---|
| 468 |
if([keychain addKeysToAgent] == NO) |
|---|
| 469 |
{ |
|---|
| 470 |
|
|---|
| 471 |
[NSApp activateIgnoringOtherApps:YES]; |
|---|
| 472 |
[self warningPanelWithTitle:local(@"AddAllKeysToAgent") andMessage:local(@"AddAllKeysToAgentFailed") |
|---|
| 473 |
inMainThread:YES]; |
|---|
| 474 |
} |
|---|
| 475 |
|
|---|
| 476 |
[pool release]; |
|---|
| 477 |
} |
|---|
| 478 |
|
|---|
| 479 |
/* Add a temporary key to the agent. */ |
|---|
| 480 |
- (IBAction)addSingleKeyToAgent:(id)sender |
|---|
| 481 |
{ |
|---|
| 482 |
if([agent isRunning]) |
|---|
| 483 |
{ |
|---|
| 484 |
[NSThread detachNewThreadSelector:@selector(addSingleKeyToAgentInNewThread) |
|---|
| 485 |
toTarget:self withObject:nil]; |
|---|
| 486 |
} |
|---|
| 487 |
|
|---|
| 488 |
else |
|---|
| 489 |
{ |
|---|
| 490 |
[self warningPanelWithTitle:local(@"AddSingleKeyToAgent") andMessage:local(@"AgentNotRunning")]; |
|---|
| 491 |
} |
|---|
| 492 |
} |
|---|
| 493 |
|
|---|
| 494 |
- (void)addSingleKeyToAgentInNewThread |
|---|
| 495 |
{ |
|---|
| 496 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 497 |
NSOpenPanel *openPanel = [NSOpenPanel openPanel]; |
|---|
| 498 |
NSString *dir = [NSString stringWithString:@"~/.ssh/"]; |
|---|
| 499 |
NSString *path; |
|---|
| 500 |
SSHKey *key; |
|---|
| 501 |
SSHTool *theTool; |
|---|
| 502 |
int returnCode; |
|---|
| 503 |
|
|---|
| 504 |
[openPanel setAllowsMultipleSelection:NO]; |
|---|
| 505 |
[openPanel setCanChooseDirectories:NO]; |
|---|
| 506 |
|
|---|
| 507 |
[NSApp activateIgnoringOtherApps:YES]; |
|---|
| 508 |
|
|---|
| 509 |
returnCode = [openPanel runModalForDirectory:[dir stringByExpandingTildeInPath] file:nil types:nil]; |
|---|
| 510 |
|
|---|
| 511 |
if(returnCode == NSCancelButton) |
|---|
| 512 |
{ |
|---|
| 513 |
return; |
|---|
| 514 |
} |
|---|
| 515 |
|
|---|
| 516 |
/* Get the path of the key we need to add. */ |
|---|
| 517 |
path = [[openPanel filenames] objectAtIndex:0]; |
|---|
| 518 |
|
|---|
| 519 |
/* This shouldn't happen. */ |
|---|
| 520 |
if(!path) |
|---|
| 521 |
{ |
|---|
| 522 |
return; |
|---|
| 523 |
} |
|---|
| 524 |
|
|---|
| 525 |
/* If the key isn't readable, warn the user. */ |
|---|
| 526 |
if([[NSFileManager defaultManager] isReadableFileAtPath:path] == NO) |
|---|
| 527 |
{ |
|---|
| 528 |
[self warningPanelWithTitle:local(@"InvalidKey") andMessage:local(@"ReadPermissionToKeyDenied") |
|---|
| 529 |
inMainThread:YES]; |
|---|
| 530 |
return; |
|---|
| 531 |
} |
|---|
| 532 |
|
|---|
| 533 |
else { |
|---|
| 534 |
key = [SSHKey keyWithPath:path]; |
|---|
| 535 |
int type = [key type]; |
|---|
| 536 |
|
|---|
| 537 |
/* If we can't get a decent type, warn the user. */ |
|---|
| 538 |
if(type == 0) |
|---|
| 539 |
{ |
|---|
| 540 |
[self warningPanelWithTitle:local(@"InvalidKey") andMessage:local(@"InvalidPrivateKey") |
|---|
| 541 |
inMainThread:YES]; |
|---|
| 542 |
return; |
|---|
| 543 |
} |
|---|
| 544 |
} |
|---|
| 545 |
|
|---|
| 546 |
if(!path) |
|---|
| 547 |
{ |
|---|
| 548 |
[pool release]; |
|---|
| 549 |
return; |
|---|
| 550 |
} |
|---|
| 551 |
|
|---|
| 552 |
theTool = [SSHTool toolWithName:@"ssh-add"]; |
|---|
| 553 |
[theTool setArgument:path]; |
|---|
| 554 |
|
|---|
| 555 |
/* Set the SSH_ASKPASS + DISPLAY environment variables, so the tool can ask for a passphrase. */ |
|---|
| 556 |
[theTool setEnvironmentVariable:@"SSH_ASKPASS" withValue: |
|---|
| 557 |
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"PassphraseRequester"]]; |
|---|
| 558 |
|
|---|
| 559 |
[theTool setEnvironmentVariable:@"DISPLAY" withValue:@":0"]; |
|---|
| 560 |
[theTool setEnvironmentVariable:@"INTERACTION" withValue:@"1"]; |
|---|
| 561 |
|
|---|
| 562 |
/* Set the SSH_AUTH_SOCK environment variable. */ |
|---|
| 563 |
[theTool setEnvironmentVariable:@"SSH_AUTH_SOCK" withValue:[agent socketPath]]; |
|---|
| 564 |
|
|---|
| 565 |
/* Set the token and run. */ |
|---|
| 566 |
if(![[TokenController sharedController] generateNewTokenForTool:theTool] || ![theTool launchAndWait]) |
|---|
| 567 |
{ |
|---|
| 568 |
[self warningPanelWithTitle:local(@"AddSingleKeyToAgent") andMessage:local(@"AddSingleKeyToAgentFailed") |
|---|
| 569 |
inMainThread:YES]; |
|---|
| 570 |
} |
|---|
| 571 |
|
|---|
| 572 |
[pool release]; |
|---|
| 573 |
} |
|---|
| 574 |
|
|---|
| 575 |
- (IBAction)removeKeysFromAgent:(id)sender |
|---|
| 576 |
{ |
|---|
| 577 |
if([agent isRunning]) |
|---|
| 578 |
{ |
|---|
| 579 |
[NSThread detachNewThreadSelector:@selector(removeKeysFromAgentInNewThread) |
|---|
| 580 |
toTarget:self withObject:nil]; |
|---|
| 581 |
} |
|---|
| 582 |
} |
|---|
| 583 |
|
|---|
| 584 |
- (void)removeKeysFromAgentInNewThread |
|---|
| 585 |
{ |
|---|
| 586 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 587 |
|
|---|
| 588 |
if([keychain removeKeysFromAgent] == NO) |
|---|
| 589 |
{ |
|---|
| 590 |
[self warningPanelWithTitle:local(@"RemoveAllKeysFromAgent") |
|---|
| 591 |
andMessage:local(@"RemoveAllKeysFromAgentFailed") |
|---|
| 592 |
inMainThread:YES]; |
|---|
| 593 |
} |
|---|
| 594 |
|
|---|
| 595 |
[pool release]; |
|---|
| 596 |
} |
|---|
| 597 |
|
|---|
| 598 |
- (IBAction)showAgentStatusWindow:(id)sender |
|---|
| 599 |
{ |
|---|
| 600 |
[self updateUI]; |
|---|
| 601 |
[NSApp activateIgnoringOtherApps:YES]; |
|---|
| 602 |
[agentStatusWindow makeKeyAndOrderFront:self]; |
|---|
| 603 |
} |
|---|
| 604 |
|
|---|
| 605 |
- (void)updateUI |
|---|
| 606 |
{ |
|---|
| 607 |
[keyTable reloadData]; |
|---|
| 608 |
|
|---|
| 609 |
if([agent isRunning]) |
|---|
| 610 |
{ |
|---|
| 611 |
[agentPID setIntValue:[agent PID]]; |
|---|
| 612 |
[agentGlobalAuthSocket setStringValue:[agent socketPath]]; |
|---|
| 613 |
[agentLocalAuthSocket setStringValue:[agent agentSocketPath]]; |
|---|
| 614 |
} |
|---|
| 615 |
|
|---|
| 616 |
else |
|---|
| 617 |
{ |
|---|
| 618 |
[agentPID setStringValue:@""]; |
|---|
| 619 |
[agentGlobalAuthSocket setStringValue:@""]; |
|---|
| 620 |
[agentLocalAuthSocket setStringValue:@""]; |
|---|
| 621 |
} |
|---|
| 622 |
} |
|---|
| 623 |
|
|---|
| 624 |
- (int)numberOfRowsInTableView:(NSTableView *)theTable |
|---|
| 625 |
{ |
|---|
| 626 |
NSArray *keysOnAgent = [agent keysOnAgent]; |
|---|
| 627 |
|
|---|
| 628 |
if(keysOnAgent) |
|---|
| 629 |
{ |
|---|
| 630 |
return [keysOnAgent count]; |
|---|
| 631 |
} |
|---|
| 632 |
|
|---|
| 633 |
return 0; |
|---|
| 634 |
} |
|---|
| 635 |
|
|---|
| 636 |
- (id)tableView:(NSTableView *)table objectValueForTableColumn:(NSTableColumn *)column row:(int)nr |
|---|
| 637 |
{ |
|---|
| 638 |
NSArray *theArray = [agent keysOnAgent]; |
|---|
| 639 |
|
|---|
| 640 |
if([theArray count] > 0) |
|---|
| 641 |
{ |
|---|
| 642 |
if([[column identifier] isEqualToString:@"name"]) |
|---|
| 643 |
return [[theArray objectAtIndex:nr] objectAtIndex:0]; |
|---|
| 644 |
|
|---|
| 645 |
else if([[column identifier] isEqualToString:@"fingerprint"]) |
|---|
| 646 |
return [[theArray objectAtIndex:nr] objectAtIndex:1]; |
|---|
| 647 |
|
|---|
| 648 |
else if([[column identifier] isEqualToString:@"type"]) |
|---|
| 649 |
return [[theArray objectAtIndex:nr] objectAtIndex:2]; |
|---|
| 650 |
} |
|---|
| 651 |
|
|---|
| 652 |
return nil; |
|---|
| 653 |
} |
|---|
| 654 |
|
|---|
| 655 |
/* Wrapper for warningPanelWithTitle: andMessage: inMainThread: */ |
|---|
| 656 |
- (void)warningPanelWithTitle:(NSString *)title andMessage:(NSString *)message |
|---|
| 657 |
{ |
|---|
| 658 |
[self warningPanelWithTitle:title andMessage:message inMainThread:NO]; |
|---|
| 659 |
} |
|---|
| 660 |
|
|---|
| 661 |
/* This method either displays the warning directly, or asks the main thread to display it.*/ |
|---|
| 662 |
- (void)warningPanelWithTitle:(NSString *)title andMessage:(NSString *)message inMainThread:(BOOL)thread |
|---|
| 663 |
{ |
|---|
| 664 |
if(thread == YES) { |
|---|
| 665 |
id UI = [NSConnection rootProxyForConnectionWithRegisteredName:@"SSHKeychain" host:nil]; |
|---|
| 666 |
|
|---|
| 667 |
if(UI == nil) { |
|---|
| 668 |
NSLog(@"Can't connect to UI to post warning"); |
|---|
| 669 |
} |
|---|
| 670 |
|
|---|
| 671 |
[UI setProtocolForProxy:@protocol(UI)]; |
|---|
| 672 |
[UI warningPanelWithTitle:title andMessage:message]; |
|---|
| 673 |
|
|---|
| 674 |
} else { |
|---|
| 675 |
|
|---|
| 676 |
[NSApp activateIgnoringOtherApps:YES]; |
|---|
| 677 |
NSRunAlertPanel(title, message, nil, nil, nil); |
|---|
| 678 |
} |
|---|
| 679 |
} |
|---|
| 680 |
|
|---|
| 681 |
- (void)onScreenSaver:(NSNotification *)notification |
|---|
| 682 |
{ |
|---|
| 683 |
if((([[NSUserDefaults standardUserDefaults] integerForKey:OnScreensaverString] == 2) |
|---|
| 684 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:OnScreensaverString] == 4)) |
|---|
| 685 |
&& ([[agent keysOnAgent] count] > 0)) |
|---|
| 686 |
{ |
|---|
| 687 |
[self removeKeysFromAgent:nil]; |
|---|
| 688 |
} |
|---|
| 689 |
|
|---|
| 690 |
if(([[NSUserDefaults standardUserDefaults] integerForKey:OnScreensaverString] == 3) |
|---|
| 691 |
|| ([[NSUserDefaults standardUserDefaults] integerForKey:OnScreensaverString] == 4)) |
|---|
| 692 |
{ |
|---|
| 693 |
SecKeychainLockAll(); |
|---|
| 694 |
} |
|---|
| 695 |
} |
|---|
| 696 |
|
|---|
| 697 |
- (BOOL)checkSocketPath:(NSString *)path |
|---|
| 698 |
{ |
|---|
| 699 |
NSString *dir, *errorString; |
|---|
| 700 |
NSDictionary *attributes; |
|---|
| 701 |
BOOL isDirectory; |
|---|
| 702 |
|
|---|
| 703 |
if(path == nil) |
|---|
| 704 |
{ |
|---|
| 705 |
[self warningPanelWithTitle:local(@"AgentNotStarted") andMessage:local(@"InternalInconsistency")]; |
|---|
| 706 |
} |
|---|
| 707 |
|
|---|
| 708 |
dir = [path stringByDeletingLastPathComponent]; |
|---|
| 709 |
|
|---|
| 710 |
attributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0700] |
|---|
| 711 |
forKey:@"NSFilePosixPermissions"]; |
|---|
| 712 |
|
|---|
| 713 |
if(([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) && (isDirectory)) |
|---|
| 714 |
{ |
|---|
| 715 |
errorString = [NSString stringWithFormat:@"%@ (%@). %@", local(@"SocketpathDirectory"), path, local(@"PleaseChangeSocketpath")]; |
|---|
| 716 |
|
|---|
| 717 |
[self warningPanelWithTitle:local(@"AgentNotStarted") andMessage:errorString]; |
|---|
| 718 |
return NO; |
|---|
| 719 |
} |
|---|
| 720 |
|
|---|
| 721 |
else if(([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) && (!isDirectory)) |
|---|
| 722 |
{ |
|---|
| 723 |
if(access([dir fileSystemRepresentation], W_OK) != 0) |
|---|
| 724 |
{ |
|---|
| 725 |
errorString = [NSString stringWithFormat:@"%@ (%@). %@.", local(@"Can'tWriteSocketInDirectory"), dir, local(@"PleaseCheckPermissions")]; |
|---|
| 726 |
|
|---|
| 727 |
[self warningPanelWithTitle:local(@"AgentNotStarted") andMessage:errorString]; |
|---|
| 728 |
return NO; |
|---|
| 729 |
} |
|---|
| 730 |
} |
|---|
| 731 |
|
|---|
| 732 |
else if(![[NSFileManager defaultManager] fileExistsAtPath:dir isDirectory:&isDirectory]) |
|---|
| 733 |
{ |
|---|
| 734 |
if(![[NSFileManager defaultManager] createDirectoryAtPath:dir attributes:attributes]) |
|---|
| 735 |
{ |
|---|
| 736 |
errorString = [NSString stringWithFormat:@"%@ (%@). %@", local(@"Couldn'tCreateSocketDirectory"), dir, local(@"PleaseCreateItManually")]; |
|---|
| 737 |
|
|---|
| 738 |
[self warningPanelWithTitle:local(@"AgentNotStarted") andMessage:errorString]; |
|---|
| 739 |
return NO; |
|---|
| 740 |
} |
|---|
| 741 |
|
|---|
| 742 |
return YES; |
|---|
| 743 |
} |
|---|
| 744 |
|
|---|
| 745 |
else if(isDirectory == NO) |
|---|
| 746 |
{ |
|---|
| 747 |
[[NSFileManager defaultManager] removeFileAtPath:dir handler:nil]; |
|---|
| 748 |
if(![[NSFileManager defaultManager] createDirectoryAtPath:dir attributes:attributes]) |
|---|
| 749 |
{ |
|---|
| 750 |
errorString = [NSString stringWithFormat:@"%@ (%@). %@", local(@"Couldn'tCreateSocketDirectory"), dir, local(@"PleaseCreateItManually")]; |
|---|
| 751 |
|
|---|
| 752 |
[self warningPanelWithTitle:local(@"AgentNotStarted") andMessage:errorString]; |
|---|
| 753 |
return NO; |
|---|
| 754 |
} |
|---|
| 755 |
|
|---|
| 756 |
return YES; |
|---|
| 757 |
} |
|---|
| 758 |
|
|---|
| 759 |
return YES; |
|---|
| 760 |
} |
|---|
| 761 |
|
|---|
| 762 |
@end |
|---|