[106042] trunk/dports/security/certsync
landonf at macports.org
landonf at macports.org
Mon May 13 18:20:04 PDT 2013
Revision: 106042
https://trac.macports.org/changeset/106042
Author: landonf at macports.org
Date: 2013-05-13 18:20:04 -0700 (Mon, 13 May 2013)
Log Message:
-----------
Add support for automatically regenerating the output file when the system keychain or trust settings are modified.
Modified Paths:
--------------
trunk/dports/security/certsync/Portfile
trunk/dports/security/certsync/files/certsync.m
Modified: trunk/dports/security/certsync/Portfile
===================================================================
--- trunk/dports/security/certsync/Portfile 2013-05-14 01:06:32 UTC (rev 106041)
+++ trunk/dports/security/certsync/Portfile 2013-05-14 01:20:04 UTC (rev 106042)
@@ -2,8 +2,7 @@
PortSystem 1.0
name certsync
-version 1.0.1
-revision 1
+version 1.0.2
categories security
conflicts curl-ca-bundle
maintainers landonf openmaintainer
@@ -17,11 +16,11 @@
use_configure no
-# TODO: How should we run this automatically? Attempts to use SecKeychainAddCallback()
-# in a blocking daemon haven't been successful; the callback is never called.
-# One possible hack is observing events on /System/Library/Keychains
-#startupitem.create yes
-#startupitem.start "${prefix}/bin/update-ca-certificates"
+# TODO: Ideally this would be run by default, rather than
+# requiring 'port load'. It doesn't run any network services, but rather,
+# simply ensures that the certificate store is always up-to-date.
+startupitem.create yes
+startupitem.start "${prefix}/bin/certsync -s -o '${prefix}/etc/openssl/cert.pem'"
build {
file mkdir "${worksrcpath}"
@@ -31,7 +30,7 @@
-Wall \
${filespath}/certsync.m -o ${worksrcpath}/certsync \
${configure.ldflags} \
- -framework Foundation -framework Security"
+ -framework Foundation -framework Security -framework CoreServices"
file copy "${filespath}/update-ca-certificates" "${worksrcpath}/update-ca-certificates"
reinplace "s|@PREFIX@|${prefix}|g" "${worksrcpath}/update-ca-certificates"
}
Modified: trunk/dports/security/certsync/files/certsync.m
===================================================================
--- trunk/dports/security/certsync/files/certsync.m 2013-05-14 01:06:32 UTC (rev 106041)
+++ trunk/dports/security/certsync/files/certsync.m 2013-05-14 01:20:04 UTC (rev 106042)
@@ -33,6 +33,22 @@
#import <objc/message.h>
+/* A wrapper class that may be used to pass configuration through the
+ * FSEvent callback API */
+ at interface MPCertSyncConfig : NSObject {
+ at public
+ BOOL userAnchors;
+ NSString *outputFile;
+}
+ at end
+
+ at implementation MPCertSyncConfig
+- (void) dealloc {
+ [outputFile release];
+ [super dealloc];
+}
+ at end
+
/**
* Add CoreFoundation object to the current autorelease pool.
*
@@ -56,6 +72,7 @@
NSString *str;
str = (NSString *) CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef) format, args);
retval = fprintf(stream, "%s", [str UTF8String]);
+ [str release];
return retval;
}
@@ -95,6 +112,7 @@
* @return Returns a (possibly empty) array of certificates on success, nil on failure.
*/
static NSArray *certificatesForTrustDomain (SecTrustSettingsDomain domain, NSError **outError) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CFArrayRef certs = nil;
OSStatus err;
@@ -104,12 +122,15 @@
PLCFAutorelease(certs);
} else if (err == errSecNoTrustSettings ) {
/* No data */
+
+ [pool release];
return [NSArray array];
-
} else if (err != errSecSuccess) {
/* Lookup failed */
if (outError != NULL)
*outError = [NSError errorWithDomain: NSOSStatusErrorDomain code: err userInfo:nil];
+
+ [pool release];
return nil;
}
@@ -149,11 +170,15 @@
}
}
}
-
- return results;
+
+ [results retain];
+ [pool release];
+ return [results autorelease];
}
static int exportCertificates (BOOL userAnchors, NSString *outputFile) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
/*
* Fetch all certificates
*/
@@ -169,6 +194,7 @@
[anchors addObjectsFromArray: result];
} else {
nsfprintf(stderr, @"Failed to fetch user anchors: %@\n", error);
+ [pool release];
return EXIT_FAILURE;
}
}
@@ -179,6 +205,7 @@
[anchors addObjectsFromArray: result];
} else {
nsfprintf(stderr, @"Failed to fetch admin anchors: %@\n", error);
+ [pool release];
return EXIT_FAILURE;
}
@@ -188,6 +215,7 @@
[anchors addObjectsFromArray: result];
} else {
nsfprintf(stderr, @"Failed to fetch system anchors: %@\n", error);
+ [pool release];
return EXIT_FAILURE;
}
@@ -207,6 +235,7 @@
if (subject == NULL) {
nsfprintf(stderr, @"Failed to extract certificate description: %@\n", cferror);
+ [pool release];
return EXIT_FAILURE;
} else {
nsfprintf(stderr, @"Extracting %@\n", subject);
@@ -229,9 +258,11 @@
#else
err = SecKeychainItemExport((CFArrayRef) anchors, kSecFormatPEMSequence, kSecItemPemArmour, NULL, &pemData);
#endif
-
+ PLCFAutorelease(pemData);
+
if (err != errSecSuccess) {
nsfprintf(stderr, @"Failed to export certificates: %@\n", [NSError errorWithDomain: NSOSStatusErrorDomain code: err userInfo:nil]);
+ [pool release];
return EXIT_FAILURE;
}
@@ -241,33 +272,50 @@
} else {
if (![(NSData *) pemData writeToFile: outputFile options: NSDataWritingAtomic error: &error]) {
nsfprintf(stderr, @"Failed to write to pem output file: %@\n", error);
+ [pool release];
return EXIT_FAILURE;
}
}
+ [pool release];
return EXIT_SUCCESS;
}
static void usage (const char *progname) {
fprintf(stderr, "Usage: %s [-u] [-o <output file>]\n", progname);
fprintf(stderr, "\t-u\t\t\tInclude the current user's anchor certificates.\n");
+ fprintf(stderr, "\t-s\t\t\tDo not exit; observe the system keychain(s) for changes and update the output file accordingly.");
fprintf(stderr, "\t-o <output file>\tWrite the PEM certificates to the target file, rather than stdout\n");
}
+static void certsync_keychain_cb (ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[])
+{
+ MPCertSyncConfig *config = (MPCertSyncConfig *) clientCallBackInfo;
+
+ int ret;
+ if ((ret = exportCertificates(config->userAnchors, config->outputFile)) != EXIT_SUCCESS)
+ exit(ret);
+}
+
int main (int argc, char * const argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* Parse the command line arguments */
BOOL userAnchors = NO;
+ BOOL runServer = NO;
NSString *outputFile = nil;
int ch;
- while ((ch = getopt(argc, argv, "huo:")) != -1) {
+ while ((ch = getopt(argc, argv, "hsuo:")) != -1) {
switch (ch) {
case 'u':
userAnchors = YES;
break;
+ case 's':
+ runServer = YES;
+ break;
+
case 'o':
outputFile = [NSString stringWithUTF8String: optarg];
break;
@@ -284,11 +332,50 @@
argc -= optind;
argv += optind;
- /* Perform export */
- int ret = exportCertificates(userAnchors, outputFile);
+ /* Perform single-shot export */
+ if (!runServer)
+ return exportCertificates(userAnchors, outputFile);
+
+ /* Formulate the list of directories to observe; We use FSEvents rather than SecKeychainAddCallback(), as during testing the keychain
+ * API never actually fired a callback for the target keychains. */
+ NSSearchPathDomainMask searchPathDomains = NSLocalDomainMask|NSSystemDomainMask;
+ if (userAnchors)
+ searchPathDomains |= NSUserDomainMask;
+ NSArray *libraryDirectories = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, searchPathDomains, YES);
+ NSMutableArray *keychainDirectories = [NSMutableArray arrayWithCapacity: [libraryDirectories count]];
+ for (NSString *dir in libraryDirectories) {
+ [keychainDirectories addObject: [dir stringByAppendingPathComponent: @"Keychains"]];
+ [keychainDirectories addObject: [dir stringByAppendingPathComponent: @"Security/Trust Settings"]];
+ }
+
+ /* Configure the listener */
+ FSEventStreamRef eventStream;
+ MPCertSyncConfig *config = [[[MPCertSyncConfig alloc] init] autorelease];
+ config->userAnchors = userAnchors;
+ config->outputFile = [outputFile retain];
+
+ FSEventStreamContext ctx = {
+ .version = 0,
+ .info = config,
+ .retain = CFRetain,
+ .release = CFRelease,
+ .copyDescription = CFCopyDescription
+ };
+ eventStream = FSEventStreamCreate(NULL, certsync_keychain_cb, &ctx, (CFArrayRef)keychainDirectories, kFSEventStreamEventIdSinceNow, 0.0, kFSEventStreamCreateFlagUseCFTypes);
+ FSEventStreamScheduleWithRunLoop(eventStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ FSEventStreamStart(eventStream);
+
+ /* Perform an initial one-shot export, and then run forever */
+ int ret;
+ if ((ret = exportCertificates(userAnchors, outputFile)) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ CFRunLoopRun();
+
+ FSEventStreamRelease(eventStream);
[pool release];
-
- return ret;
+
+ return EXIT_SUCCESS;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20130513/ace4d88e/attachment-0001.html>
More information about the macports-changes
mailing list