1/* 2 * Copyright (c) 2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#import <Foundation/Foundation.h> 24#import <CrashReporterSupport/CrashReporterSupportPrivate.h> 25#import <sys/utsname.h> 26 27static bool useInternalServer() { 28 struct utsname name; 29 return ((uname(&name) == 0 && strstr(name.version, "DEVELOPMENT") != NULL) 30 && access("/var/db/gkoverride_use_internal", F_OK) == 0); 31} 32 33@interface OverrideClient : NSObject<NSURLConnectionDelegate> { 34 BOOL allow; 35 NSMutableData *buffer; 36 NSURLConnection *connection; 37 int state; 38} 39@property NSString *currentHash; 40@property NSString *opaqueHash; 41@property NSString *bundleID; 42@property NSString *bundleVersion; 43- (NSString *)serverHost; 44- (void)sendQuery; 45- (void)sendReport; 46- (void)abort; 47@end 48 49@implementation OverrideClient 50 51- (NSString *)serverHost { 52 if (useInternalServer()) 53 return @"gkq-stg.siri.apple.com"; 54 else 55 return @"gkq.apple.com"; 56} 57 58- (id)init { 59 self = [super init]; 60 allow = NO; 61 buffer = [NSMutableData new]; 62 return self; 63} 64 65- (void)sendQuery { 66 state = 1; 67 NSMutableURLRequest *request = [NSMutableURLRequest new]; 68 NSString *url = [NSString stringWithFormat:@"https://%@/q/%@/%@", [self serverHost], self.currentHash, self.opaqueHash]; 69 [request setURL:[NSURL URLWithString:url]]; 70 [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; 71 [request setTimeoutInterval:5]; 72 connection = [NSURLConnection connectionWithRequest:request delegate:self]; 73} 74 75- (void)sendReport { 76 state = 2; 77 NSMutableURLRequest *request = [NSMutableURLRequest new]; 78 NSString *body = [NSString stringWithFormat:@"current=%@&bundleid=%@&version=%@", 79 [self.currentHash stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], 80 [self.bundleID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], 81 [self.bundleVersion stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 82 NSString *url = [NSString stringWithFormat:@"https://%@/report", [self serverHost]]; 83 [request setURL:[NSURL URLWithString:url]]; 84 [request setTimeoutInterval:5]; 85 [request setHTTPMethod:@"POST"]; 86 [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]]; 87 connection = [NSURLConnection connectionWithRequest:request delegate:self]; 88} 89 90- (BOOL)connection:(NSURLConnection *)conn canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { 91 SecTrustRef trust = [protectionSpace serverTrust]; 92 // abort if untrusted 93 SecTrustResultType trustResult; 94 SecTrustEvaluate(trust, &trustResult); 95 if (trustResult != kSecTrustResultProceed && trustResult != kSecTrustResultUnspecified) { 96 [conn cancel]; 97 [self abort]; 98 return NO; 99 } 100 // allow if server presented an EV cert 101 NSDictionary *result = CFBridgingRelease(SecTrustCopyResult(trust)); 102 if (result) { 103 NSNumber *ev = [result objectForKey:(__bridge id)kSecTrustExtendedValidation]; 104 if (ev != NULL && [ev boolValue] == YES) { 105 return NO; 106 } 107 } 108 // allow if using internal server (EV not required) 109 if (useInternalServer()) 110 return NO; 111 // otherwise abort 112 [conn cancel]; 113 [self abort]; 114 return NO; 115} 116 117- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 118 [buffer appendData:data]; 119 if ([buffer length] > 100) 120 [self abort]; 121} 122 123- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 124 if (state == 1) { 125 NSString *verdict = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding]; 126 if ([verdict isEqualToString:@"allow"]) { 127 allow = YES; 128 [self abort]; 129 } else if (CRIsAutoSubmitEnabled()) { // "Send diagnostic & usage data to Apple" checked 130 [self sendReport]; 131 } 132 } else { 133 [self abort]; // report sent 134 } 135} 136 137- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 138 [self abort]; 139} 140 141- (void)abort { 142 if (allow) { 143 printf("allow\n"); 144 exit(42); 145 } else { 146 printf("deny\n"); 147 exit(1); 148 } 149} 150 151@end 152 153int main(int argc, const char * argv[]) { 154 if (argc != 5) { 155 fprintf(stderr, "usage: %s <current> <opaque> <bundleid> <version>\n", argv[0]); 156 return 1; 157 } 158 @autoreleasepool { 159 OverrideClient *client = [OverrideClient new]; 160 client.currentHash = [NSString stringWithUTF8String:argv[1]]; 161 client.opaqueHash = [NSString stringWithUTF8String:argv[2]]; 162 client.bundleID = [NSString stringWithUTF8String:argv[3]]; 163 client.bundleVersion = [NSString stringWithUTF8String:argv[4]]; 164 [client sendQuery]; 165 [[NSRunLoop currentRunLoop] run]; 166 } 167 return 0; 168} 169