#include <security_ocspd/ocspd.h>
#include <Security/Authorization.h>
#include <Security/AuthorizationDB.h>
#include <security_utilities/threading.h>
#include <security_utilities/globalizer.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <bsm/libbsm.h>
#include <security_ocspd/ocspdDebug.h>
#include <Security/SecBase.h>
#include <Security/SecTrustSettings.h>
#include <Security/TrustSettingsSchema.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include "ocspdServer.h"
#include <membership.h>
static ModuleNexus<Mutex> gTrustSettingsLock;
#define TRUST_SETTINGS_RIGHT_USER "com.apple.trust-settings.user"
#define TRUST_SETTINGS_RIGHT_ADMIN "com.apple.trust-settings.admin"
#define TRUST_SETTINGS_RULE_USER CFSTR("authenticate-session-owner");
#define TRUST_SETTINGS_RULE_ADMIN CFSTR("is-root");
#define TRUST_SETTINGS_PATH_MODE 0755
#define TRUST_SETTINGS_FILES_MODE 0600
#define UUID_STR_LEN ((2 * sizeof(uuid_t)) + 5)
static void uuidString(
uuid_t uuid,
char *cp)
{
unsigned dex;
unsigned char *uuidCp = (unsigned char *)uuid;
for(dex=0; dex<sizeof(uuid_t); dex++) {
sprintf(cp, "%02X", *uuidCp++);
cp += 2;
switch(dex) {
case 3:
case 5:
case 7:
case 9:
*cp++ = '-';
break;
default:
break;
}
}
*cp = '\0';
}
static void trustSettingsPath(
audit_token_t auditToken,
SecTrustSettingsDomain domain,
char *path)
{
switch(domain) {
case kSecTrustSettingsDomainUser:
{
uid_t euid;
uuid_t uuid;
audit_token_to_au32(auditToken, NULL, &euid, NULL, NULL, NULL, NULL, NULL, NULL);
if(!mbr_uid_to_uuid(euid, uuid)) {
char uuidStr[UUID_STR_LEN];
uuidString(uuid, uuidStr);
snprintf(path, MAXPATHLEN + 1, "%s/%s.plist", TRUST_SETTINGS_PATH, uuidStr);
}
else {
snprintf(path, MAXPATHLEN + 1, "%s/%lu.plist", TRUST_SETTINGS_PATH,
(unsigned long)euid);
}
break;
}
case kSecTrustSettingsDomainAdmin:
snprintf(path, MAXPATHLEN + 1, "%s/%s", TRUST_SETTINGS_PATH, ADMIN_TRUST_SETTINGS);
break;
case kSecTrustSettingsDomainSystem:
strcpy(path, SYSTEM_TRUST_SETTINGS_PATH);
break;
default:
break;
}
}
kern_return_t ocsp_server_trustSettingsRead(
mach_port_t serverport,
audit_token_t auditToken,
uint32_t domain,
Data *trustSettings,
mach_msg_type_number_t *trustSettingsCnt,
OSStatus *rcode)
{
StLock<Mutex> _(gTrustSettingsLock());
char path[MAXPATHLEN + 1];
trustSettingsPath(auditToken, domain, path);
unsigned char *fileData = NULL;
unsigned fileDataLen;
if(readFile(path, &fileData, &fileDataLen)) {
ocspdTrustDebug("trustSettingsRead: no file at %s", path);
*rcode = errSecNoTrustSettings;
*trustSettings = NULL;
*trustSettingsCnt = 0;
return 0;
}
CSSM_DATA cdata;
Allocator &alloc = OcspdServer::active().alloc();
cdata.Data = (uint8 *)alloc.malloc(fileDataLen);
cdata.Length = fileDataLen;
memmove(cdata.Data, fileData, fileDataLen);
free(fileData);
passDataToCaller(cdata, trustSettings, trustSettingsCnt);
ocspdTrustDebug("trustSettingsRead: read %lu bytes from %s",
(unsigned long)cdata.Length, path);
*rcode = noErr;
return 0;
}
kern_return_t ocsp_server_trustSettingsWrite(
mach_port_t serverport,
audit_token_t auditToken,
uint32_t domain,
Data authBlob,
mach_msg_type_number_t authBlobCnt,
Data trustSettings,
mach_msg_type_number_t trustSettingsCnt,
OSStatus *rcode)
{
StLock<Mutex> _(gTrustSettingsLock());
const char *authRight = NULL;
CFStringRef authRule = NULL;
char path[MAXPATHLEN + 1];
trustSettingsPath(auditToken, domain, path);
switch(domain) {
case kSecTrustSettingsDomainUser:
authRight = TRUST_SETTINGS_RIGHT_USER;
authRule = TRUST_SETTINGS_RULE_USER;
break;
case kSecTrustSettingsDomainAdmin:
authRight = TRUST_SETTINGS_RIGHT_ADMIN;
authRule = TRUST_SETTINGS_RULE_ADMIN;
break;
case kSecTrustSettingsDomainSystem:
*rcode = errSecDataNotModifiable;
return 0;
}
AuthorizationExternalForm extForm;
if(authBlobCnt > sizeof(extForm)) {
ocspdErrorLog("trustSettingsWrite: authBlob too big\n");
*rcode = paramErr;
return 0;
}
AuthorizationRef authRef;
OSStatus ortn;
if(AuthorizationRightGet(authRight, NULL)) {
ortn = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
0, &authRef);
if(ortn) {
ocspdErrorLog("trustSettingsWrite: AuthorizationCreate failure\n");
*rcode = internalComponentErr;
return 0;
}
ortn = AuthorizationRightSet(authRef, authRight, authRule,
NULL, NULL, NULL);
if(ortn) {
ocspdErrorLog("trustSettingsWrite: AuthorizationRightSet failure\n");
*rcode = internalComponentErr;
return 0;
}
AuthorizationFree(authRef, 0);
}
memmove(&extForm, authBlob, authBlobCnt);
ortn = AuthorizationCreateFromExternalForm(&extForm, &authRef);
if(ortn) {
ocspdErrorLog("trustSettingsWrite: AuthorizationCreateFromExternalForm failure\n");
*rcode = paramErr;
return 0;
}
AuthorizationItem authItem = {authRight, 0, NULL, 0};
AuthorizationRights authRights = { 1, &authItem };
AuthorizationFlags authFlags = kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagExtendRights;
ortn = AuthorizationCopyRights(authRef, &authRights, NULL,
authFlags, NULL);
if(ortn) {
ocspdErrorLog("trustSettingsWrite: AuthorizationCopyRights failure\n");
}
AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
if(ortn) {
*rcode = ortn;
return 0;
}
if(trustSettingsCnt == 0) {
ocspdTrustDebug("trustSettingsWrite: DELETING %s", path);
if(unlink(path)) {
*rcode = errno;
ocspdErrorLog("trustSettingsWrite: unlink error %d\n", errno);
}
else {
*rcode = noErr;
}
return 0;
}
struct stat sb;
if(stat(TRUST_SETTINGS_PATH, &sb)) {
ocspdTrustDebug("trustSettingsWrite: creating %s", TRUST_SETTINGS_PATH);
if(mkdir(TRUST_SETTINGS_PATH, TRUST_SETTINGS_PATH_MODE)) {
ocspdErrorLog("trustSettingsWrite: mkdir() returned %d\n", errno);
*rcode = internalComponentErr;
return 0;
}
chmod(TRUST_SETTINGS_PATH, TRUST_SETTINGS_PATH_MODE);
}
if(writeFile(path, (const unsigned char *)trustSettings, trustSettingsCnt)) {
ocspdErrorLog("trustSettingsWrite: writeFile() error\n");
*rcode = internalComponentErr;
}
else {
ocspdTrustDebug("trustSettingsWrite: wrote %lu bytes to %s",
(unsigned long)trustSettingsCnt, path);
chmod(path, TRUST_SETTINGS_FILES_MODE);
*rcode = noErr;
}
return 0;
}