2 * AuthorizationDBPlist.cpp
5 * Created by Conrad Sauerwald on Tue Mar 18 2003.
6 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
10 #include "AuthorizationDBPlist.h"
12 namespace Authorization
15 //using Authorization::AuthorizationDBPlist;
17 AuthorizationDBPlist::AuthorizationDBPlist(const char *configFile
) : mFileName(configFile
), mLastChecked(DBL_MIN
)
19 memset(&mRulesFileMtimespec
, 0, sizeof(mRulesFileMtimespec
));
22 //AuthorizationDBPlist::~AuthorizationDBPlist()
26 void AuthorizationDBPlist::sync(CFAbsoluteTime now
)
32 // Don't do anything if we checked the timestamp less than 5 seconds ago
33 if (mLastChecked
> now
- 5.0)
37 if (stat(mFileName
.c_str(), &st
))
39 Syslog::error("Stating rules file \"%s\": %s", mFileName
.c_str(), strerror(errno
));
40 /* @@@ No rules file found, use defaults: admin group for everything. */
41 //UnixError::throwMe(errno);
45 // @@@ Make sure this is the right way to compare 2 struct timespec thingies
46 // Technically we should check st_dev and st_ino as well since if either of those change
47 // we are looking at a different file too.
48 if (memcmp(&st
.st_mtimespec
, &mRulesFileMtimespec
, sizeof(mRulesFileMtimespec
)))
56 void AuthorizationDBPlist::save() const
61 StLock
<Mutex
> _(mReadWriteLock
);
64 string tempFile
= mFileName
+ ",";
68 fd
= open(tempFile
.c_str(), O_WRONLY
|O_CREAT
|O_EXCL
, 0644);
73 unlink(tempFile
.c_str());
87 Syslog::error("Saving rules file \"%s\": %s", tempFile
.c_str(), strerror(errno
));
91 // convert config to plist
92 CFDataRef configXML
= CFPropertyListCreateXMLData(NULL
, mConfig
);
98 SInt32 configSize
= CFDataGetLength(configXML
);
99 size_t bytesWritten
= write(fd
, CFDataGetBytePtr(configXML
), configSize
);
100 CFRelease(configXML
);
102 if (bytesWritten
!= uint32_t(configSize
))
104 if (bytesWritten
== static_cast<size_t>(-1))
105 Syslog::error("Writing rules file \"%s\": %s", tempFile
.c_str(), strerror(errno
));
107 Syslog::error("Could only write %lu out of %ld bytes from rules file \"%s\"",
108 bytesWritten
, configSize
, tempFile
.c_str());
111 unlink(tempFile
.c_str());
116 if (rename(tempFile
.c_str(), mFileName
.c_str()))
117 unlink(tempFile
.c_str());
122 void AuthorizationDBPlist::load(CFTimeInterval now
)
124 StLock
<Mutex
> _(mReadWriteLock
);
126 int fd
= open(mFileName
.c_str(), O_RDONLY
, 0);
129 Syslog::error("Opening rules file \"%s\": %s", mFileName
.c_str(), strerror(errno
));
138 UnixError::throwMe(error
);
142 mRulesFileMtimespec
= st
.st_mtimespec
;
144 off_t fileSize
= st
.st_size
;
146 CFMutableDataRef xmlData
= CFDataCreateMutable(NULL
, fileSize
);
147 CFDataSetLength(xmlData
, fileSize
);
148 void *buffer
= CFDataGetMutableBytePtr(xmlData
);
149 size_t bytesRead
= read(fd
, buffer
, fileSize
);
150 if (bytesRead
!= fileSize
)
152 if (bytesRead
== static_cast<size_t>(-1))
154 Syslog::error("Reading rules file \"%s\": %s", mFileName
.c_str(), strerror(errno
));
159 Syslog::error("Could only read %ul out of %ul bytes from rules file \"%s\"",
160 bytesRead
, fileSize
, mFileName
.c_str());
165 CFStringRef errorString
;
166 CFDictionaryRef configPlist
= reinterpret_cast<CFDictionaryRef
>(CFPropertyListCreateFromXMLData(NULL
, xmlData
, kCFPropertyListMutableContainersAndLeaves
, &errorString
));
171 const char *error
= CFStringGetCStringPtr(errorString
, kCFStringEncodingUTF8
);
174 if (CFStringGetCString(errorString
, buffer
, 512, kCFStringEncodingUTF8
))
178 Syslog::error("Parsing rules file \"%s\": %s", mFileName
.c_str(), error
);
180 CFRelease(errorString
);
186 if (CFGetTypeID(configPlist
) != CFDictionaryGetTypeID())
189 Syslog::error("Rules file \"%s\": is not a dictionary", mFileName
.c_str());
192 CFRelease(configPlist
);
197 StLock
<Mutex
> _(mLock
);
198 parseConfig(configPlist
);
202 CFRelease(configPlist
);
210 AuthorizationDBPlist::parseConfig(CFDictionaryRef config
)
212 // grab items from top-level dictionary that we care about
213 CFStringRef rightsKey
= CFSTR("rights");
214 CFStringRef rulesKey
= CFSTR("rules");
215 CFMutableDictionaryRef newRights
= NULL
;
216 CFMutableDictionaryRef newRules
= NULL
;
219 MacOSError::throwMe(errAuthorizationInternal
); // XXX/cs invalid rule file
221 if (CFDictionaryContainsKey(config
, rulesKey
))
223 newRules
= reinterpret_cast<CFMutableDictionaryRef
>(const_cast<void*>(CFDictionaryGetValue(config
, rulesKey
)));
226 if (CFDictionaryContainsKey(config
, rightsKey
))
228 newRights
= reinterpret_cast<CFMutableDictionaryRef
>(const_cast<void*>(CFDictionaryGetValue(config
, rightsKey
)));
233 && (CFDictionaryGetTypeID() == CFGetTypeID(newRules
))
234 && (CFDictionaryGetTypeID() == CFGetTypeID(newRights
)))
237 mConfigRights
= static_cast<CFMutableDictionaryRef
>(newRights
);
238 mConfigRules
= static_cast<CFMutableDictionaryRef
>(newRules
);
242 CFDictionaryApplyFunction(newRights
, parseRule
, this);
246 MacOSError::throwMe(errAuthorizationInternal
); // XXX/cs invalid rule file
250 MacOSError::throwMe(errAuthorizationInternal
); // XXX/cs invalid rule file
253 void AuthorizationDBPlist::parseRule(const void *key
, const void *value
, void *context
)
255 static_cast<AuthorizationDBPlist
*>(context
)->addRight(static_cast<CFStringRef
>(key
), static_cast<CFDictionaryRef
>(value
));
258 void AuthorizationDBPlist::addRight(CFStringRef key
, CFDictionaryRef definition
)
260 string keyString
= cfString(key
);
261 mRules
[keyString
] = Rule(keyString
, definition
, mConfigRules
);
265 AuthorizationDBPlist::validateRule(string inRightName
, CFDictionaryRef inRightDefinition
) const
268 Rule
newRule(inRightName
, inRightDefinition
, mConfigRules
);
269 if (newRule
->name() == inRightName
)
274 secdebug("authrule", "invalid definition for rule %s.\n", inRightName
.c_str());
280 AuthorizationDBPlist::getRuleDefinition(string
&key
)
282 CFStringRef cfKey
= makeCFString(key
);
283 StLock
<Mutex
> _(mLock
);
284 if (CFDictionaryContainsKey(mConfigRights
, cfKey
))
286 CFDictionaryRef definition
= reinterpret_cast<CFMutableDictionaryRef
>(const_cast<void*>(CFDictionaryGetValue(mConfigRights
, cfKey
)));
288 return CFDictionaryCreateCopy(NULL
, definition
);
298 AuthorizationDBPlist::existRule(string
&ruleName
) const
300 map
<string
,Rule
>::const_iterator rule
= mRules
.find(ruleName
);
301 if (rule
!= mRules
.end())
308 AuthorizationDBPlist::getRule(const AuthItemRef
&inRight
) const
310 string
key(inRight
->name());
312 StLock
<Mutex
> _(mLock
);
319 map
<string
,Rule
>::const_iterator rule
= mRules
.find(key
);
321 if (rule
!= mRules
.end())
322 return (*rule
).second
;
327 // any reduction of a combination of two chars is futile
328 if (key
.size() > 2) {
329 // find last dot with exception of possible dot at end
330 string::size_type index
= key
.rfind('.', key
.size() - 2);
331 // cut right after found dot, or make it match default rule
332 key
= key
.substr(0, index
== string::npos
? 0 : index
+ 1);
339 AuthorizationDBPlist::setRule(const char *inRightName
, CFDictionaryRef inRuleDefinition
)
341 if (!inRuleDefinition
|| !mConfigRights
)
342 MacOSError::throwMe(errAuthorizationDenied
); // errInvalidRule
344 CFRef
<CFStringRef
> keyRef(CFStringCreateWithCString(NULL
, inRightName
, kCFStringEncodingASCII
));
348 StLock
<Mutex
> _(mLock
);
350 CFDictionarySetValue(mConfigRights
, keyRef
, inRuleDefinition
);
351 // release modification lock here already?
357 AuthorizationDBPlist::removeRule(const char *inRightName
)
360 MacOSError::throwMe(errAuthorizationDenied
);
362 CFRef
<CFStringRef
> keyRef(CFStringCreateWithCString(NULL
, inRightName
, kCFStringEncodingASCII
));
366 StLock
<Mutex
> _(mLock
);
368 if (CFDictionaryContainsKey(mConfigRights
, keyRef
))
370 CFDictionaryRemoveValue(mConfigRights
, keyRef
);
371 // release modification lock here already?
378 } // end namespace Authorization