mirror of
https://github.com/sparkle-project/Sparkle.git
synced 2025-11-01 15:34:38 +00:00
* For the Installer and Downloader XPC Services, if these executables are code signed with an Apple issued Team ID, then the connecting client must also be code signed with a matching Team ID. * For the Downloader XPC Service, the request URL must be http/https * For Autoupdate, if stage 1 of installation hasn't been completed yet and this executable is code signed with an Apple issued Team ID, then the connecting client must also be code signed with a matching Team ID. As before, multiple simultaneous connections are still disallowed. * For Autoupdate, if it's not signed with Apple issued certificate, when installing package updates the bundle being updated must be itself and owned by root on disk (as one expects from a PKG installation) * The authorization prompt message in the Installer Service is more computed inside the service so the client can't pass a completely arbitrary message * Add extra nullable checking of parameters coming from XPC endpoints * Add more thread-safe synchronization for Autoupdate installer * Add logs for more failure points
142 lines
4.3 KiB
Objective-C
142 lines
4.3 KiB
Objective-C
//
|
|
// AgentConnection.m
|
|
// Sparkle
|
|
//
|
|
// Created by Mayur Pawashe on 7/17/16.
|
|
// Copyright © 2016 Sparkle Project. All rights reserved.
|
|
//
|
|
|
|
#import "AgentConnection.h"
|
|
#import "SPUMessageTypes.h"
|
|
#import "SPUInstallerAgentProtocol.h"
|
|
#import "SUInstallerAgentInitiationProtocol.h"
|
|
#import "SUCodeSigningVerifier.h"
|
|
#import "SULog.h"
|
|
|
|
|
|
#include "AppKitPrevention.h"
|
|
|
|
@interface AgentConnection () <NSXPCListenerDelegate, SUInstallerAgentInitiationProtocol>
|
|
|
|
@end
|
|
|
|
@implementation AgentConnection
|
|
{
|
|
NSXPCListener *_xpcListener;
|
|
NSXPCConnection *_activeConnection;
|
|
__weak id<AgentConnectionDelegate> _delegate;
|
|
}
|
|
|
|
@synthesize agent = _agent;
|
|
@synthesize connected = _connected;
|
|
@synthesize invalidationError = _invalidationError;
|
|
|
|
- (instancetype)initWithHostBundleIdentifier:(NSString *)bundleIdentifier delegate:(id<AgentConnectionDelegate>)delegate
|
|
{
|
|
self = [super init];
|
|
if (self != nil) {
|
|
// Agents should always be the one that connect to daemons due to how mach bootstraps work
|
|
// For this reason, we are the ones that are creating a listener, not the agent
|
|
_xpcListener = [[NSXPCListener alloc] initWithMachServiceName:SPUProgressAgentServiceNameForBundleIdentifier(bundleIdentifier)];
|
|
_xpcListener.delegate = self;
|
|
_delegate = delegate;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)startListener
|
|
{
|
|
[_xpcListener resume];
|
|
}
|
|
|
|
- (void)invalidate
|
|
{
|
|
_delegate = nil;
|
|
|
|
[_activeConnection invalidate];
|
|
// Don't need to set _activeConnection to nil, we don't expect new connections
|
|
|
|
[_xpcListener invalidate];
|
|
_xpcListener = nil;
|
|
}
|
|
|
|
- (BOOL)listener:(NSXPCListener *)__unused listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
|
|
{
|
|
if (_activeConnection != nil) {
|
|
SULog(SULogLevelError, @"Error: Rejecting new connection for agent due already having an active connection");
|
|
|
|
[newConnection invalidate];
|
|
return NO;
|
|
}
|
|
|
|
// Hardening but not critical for security
|
|
NSError *validationError = nil;
|
|
SUValidateConnectionStatus validationStatus = [SUCodeSigningVerifier validateConnection:newConnection options:SUValidateConnectionOptionDefault error:&validationError];
|
|
switch (validationStatus) {
|
|
case SUValidateConnectionStatusSetCodeSigningRequirementSuccess:
|
|
break;
|
|
case SUValidateConnectionStatusSetNoRequirementSuccess:
|
|
break;
|
|
case SUValidateConnectionStatusAPIFailure:
|
|
case SUValidateConnectionStatusCodeSigningRequirementFailure:
|
|
case SUValidateConectionNoSupportedValidationMethodFailure:
|
|
SULog(SULogLevelError, @"Error: Rejecting new connection for agent due to failing validation of XPC connection with status %lu and error: %@", validationStatus, validationError.localizedDescription);
|
|
|
|
[newConnection invalidate];
|
|
return NO;
|
|
}
|
|
|
|
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SUInstallerAgentInitiationProtocol)];
|
|
newConnection.exportedObject = self;
|
|
|
|
newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SPUInstallerAgentProtocol)];
|
|
|
|
_activeConnection = newConnection;
|
|
|
|
__weak __typeof__(self) weakSelf = self;
|
|
newConnection.interruptionHandler = ^{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
__typeof__(self) strongSelf = weakSelf;
|
|
if (strongSelf != nil) {
|
|
[strongSelf->_activeConnection invalidate];
|
|
}
|
|
});
|
|
};
|
|
|
|
newConnection.invalidationHandler = ^{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
__typeof__(self) strongSelf = weakSelf;
|
|
if (strongSelf != nil) {
|
|
[strongSelf->_delegate agentConnectionDidInvalidate];
|
|
}
|
|
});
|
|
};
|
|
|
|
_agent = newConnection.remoteObjectProxy;
|
|
[newConnection resume];
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (void)connectionDidInitiateWithReply:(void (^)(void))acknowledgement
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self->_connected = YES;
|
|
|
|
[self->_delegate agentConnectionDidInitiate];
|
|
});
|
|
|
|
if (acknowledgement != NULL) {
|
|
acknowledgement();
|
|
}
|
|
}
|
|
|
|
- (void)connectionWillInvalidateWithError:(NSError *)error
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self->_invalidationError = error;
|
|
});
|
|
}
|
|
|
|
@end
|