// // main.m // kordophone // // Created by James Magahern on 11/12/18. // Copyright © 2018 James Magahern. All rights reserved. // #import #import "MBIMBridge.h" void printUsage() { fprintf(stderr, "Usage: kordophoned [-h] [-s | -c (certificate.p12)] [-a (access control file)\n"); fprintf(stderr, "\t-h \t Show this help message\n"); fprintf(stderr, "\t-s \t Use SSL (requires -c option)\n"); fprintf(stderr, "\t-c \t SSL certificate path encoded as pkcs12\n"); fprintf(stderr, "\t-a \t Optional access control file\n"); fprintf(stderr, "\t-p \t Specify port number (default: 5738)\n"); } BOOL acquireCredentials(bool encrypted, const char *accessFile, NSString **out_username, NSString **out_password) { BOOL success = NO; NSString *asString = nil; NSError *launchError = nil; NSString *accessFilePath = [NSString stringWithUTF8String:accessFile]; if (encrypted) { NSPipe *stdoutPipe = [NSPipe pipe]; NSPipe *stderrPipe = [NSPipe pipe]; NSTask *task = [[NSTask alloc] init]; task.launchPath = @"/usr/local/bin/gpg"; task.arguments = @[ @"-q", @"-d", accessFilePath ]; task.standardOutput = stdoutPipe; task.standardError = stderrPipe; success = [task launchAndReturnError:&launchError]; [task waitUntilExit]; if (success) { NSFileHandle *stdoutFile = stdoutPipe.fileHandleForReading; NSData *data = [stdoutFile readDataToEndOfFile]; // blocks [stdoutFile closeFile]; if ([task terminationStatus] != 0) { NSData *stderrData = [[stderrPipe fileHandleForReading] readDataToEndOfFile]; MBIMLogFatal(@"GPG error when decrypting access file: %@", [[NSString alloc] initWithData:stderrData encoding:NSUTF8StringEncoding]); return NO; } asString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } } else { NSError *fileReadError = nil; asString = [NSString stringWithContentsOfFile:accessFilePath encoding:NSASCIIStringEncoding error:&fileReadError]; if (fileReadError != nil) { MBIMLogFatal(@"File open error when opening access file: %@", fileReadError.localizedDescription); return NO; } success = (asString.length > 0); } if (success) { NSScanner *scanner = [NSScanner scannerWithString:asString]; BOOL scannerSuccess = NO; NSString *username = nil; scannerSuccess = [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&username]; if (!scannerSuccess) { MBIMLogFatal(@"Error parsing username from access file"); return NO; } NSString *password = nil; scannerSuccess = [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&password]; if (!scannerSuccess) { MBIMLogFatal(@"Error parsing password from access file"); return NO; } if ([username length] && [password length]) { *out_username = username; *out_password = password; } else { MBIMLogFatal(@"Error parsing username or password from access file"); return NO; } } else { MBIMLogFatal(@"Unable to launch GPG executable to decrypt access file: %@", [launchError localizedDescription]); return NO; } return YES; } int main(int argc, char *const argv[]) { @autoreleasepool { BOOL usesSSL = NO; BOOL showHelp = NO; BOOL usesAccessControl = NO; long portNumber = -1; const char *certPath = NULL; const char *accessFilePath = NULL; int c = -1; while ( (c = getopt(argc, argv, "hsc:a:p:")) != -1 ) { switch (c) { case 's': usesSSL = YES; break; case 'c': certPath = optarg; break; case 'a': usesAccessControl = YES; accessFilePath = optarg; break; case 'p': portNumber = strtol(optarg, NULL, 10); break; case 'h': showHelp = YES; break; case '?': if (optopt == 'c') { fprintf (stderr, "Option -%c requires an argument.\n", optopt); } else if (isprint(optopt)) { fprintf (stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; } default: abort (); } } if (showHelp) { printUsage(); return 1; } if (usesSSL && certPath == NULL) { fprintf(stderr, "Error: wants SSL (-s) but no ssl certificate path (-c) provided\n"); return 1; } MBIMBridge *bridge = [MBIMBridge sharedInstance]; if (usesAccessControl) { NSString *username = nil; NSString *password = nil; BOOL success = acquireCredentials(false, accessFilePath, &username, &password); if (!success) { MBIMLogInfo( @"Access file must be a GPG encrypted file (encrypted with your private key, to your pub key) " "with the follwing format: \n" "(username)\n" "(password)" ); return 1; } else { const ssize_t ast_len = 55; const unichar asterisks[ast_len] = u"*******************************************************"; NSString *obscuredPassword = [NSString stringWithCharacters:asterisks length:MIN([password length], ast_len)]; MBIMLogNotify(@"Using access control credentials: username(%@) password(%@)", username, obscuredPassword); bridge.usesAccessControl = YES; bridge.authUsername = username; bridge.authPassword = password; } } if (usesSSL && certPath != NULL) { bridge.usesSSL = YES; bridge.sslCertPath = [NSString stringWithCString:certPath encoding:NSASCIIStringEncoding]; } if (portNumber > 0) { bridge.port = portNumber; } [bridge connect]; BOOL running = YES; while (running) { [[NSRunLoop currentRunLoop] run]; } } return 0; }