]> git.saurik.com Git - apple/security.git/blob - Keychain/DLDBListCFPref.cpp
Security-179.tar.gz
[apple/security.git] / Keychain / DLDBListCFPref.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 DLDBListCFPref.cpp
21 */
22
23 #include "DLDBListCFPref.h"
24 #include <Security/cssmapple.h>
25 #include <Security/debugging.h>
26 #include <syslog.h>
27 #include <memory>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <pwd.h>
33
34 using namespace CssmClient;
35
36 static const double kDLDbListCFPrefRevertInterval = 30.0;
37
38 // normal debug calls, which get stubbed out for deployment builds
39 #define x_debug(str) secdebug("KClogin",(str))
40 #define x_debug1(fmt,arg1) secdebug("KClogin",(fmt),(arg1))
41 #define x_debug2(fmt,arg1,arg2) secdebug("KClogin",(fmt),(arg1),(arg2))
42
43 #define kKeyGUID CFSTR("GUID")
44 #define kKeySubserviceId CFSTR("SubserviceId")
45 #define kKeySubserviceType CFSTR("SubserviceType")
46 #define kKeyDbName CFSTR("DbName")
47 #define kKeyDbLocation CFSTR("DbLocation")
48 #define kKeyActive CFSTR("Active")
49 #define kKeyMajorVersion CFSTR("MajorVersion")
50 #define kKeyMinorVersion CFSTR("MinorVersion")
51 #define kDefaultDLDbListKey CFSTR("DLDBSearchList")
52 #define kDefaultKeychainKey CFSTR("DefaultKeychain")
53 #define kLoginKeychainKey CFSTR("LoginKeychain")
54 #define kUserDefaultPath "~/Library/Preferences/com.apple.security.plist"
55 #define kSystemDefaultPath "/Library/Preferences/com.apple.security.plist"
56 #define kCommonDefaultPath "/Library/Preferences/com.apple.security-common.plist"
57 #define kLoginKeychainPathPrefix "~/Library/Keychains/"
58 #define kUserLoginKeychainPath "~/Library/Keychains/login.keychain"
59 #define kSystemLoginKeychainPath "/Library/Keychains/System.keychain"
60
61
62 // A utility class for managing password database lookups
63
64 const time_t kPasswordCacheExpire = 30; // number of seconds cached password db info is valid
65
66 PasswordDBLookup::PasswordDBLookup () : mValid (false), mCurrent (0), mTime (0)
67 {
68 }
69
70 void PasswordDBLookup::lookupInfoOnUID (uid_t uid)
71 {
72 time_t currentTime = time (NULL);
73
74 if (!mValid || uid != mCurrent || currentTime - mTime >= kPasswordCacheExpire)
75 {
76 struct passwd* pw = getpwuid(uid);
77 if (pw == NULL)
78 {
79 UnixError::throwMe (EPERM);
80 }
81
82 mDirectory = pw->pw_dir;
83 mName = pw->pw_name;
84 mValid = true;
85 mCurrent = uid;
86 mTime = currentTime;
87
88 x_debug2("PasswordDBLookup::lookupInfoOnUID: uid=%d caching home=%s", uid, pw->pw_dir);
89
90 endpwent();
91 }
92 }
93
94 PasswordDBLookup *DLDbListCFPref::mPdbLookup = NULL;
95
96 //-------------------------------------------------------------------------------------
97 //
98 // Lists of DL/DBs, with CFPreferences backing store
99 //
100 //-------------------------------------------------------------------------------------
101
102 DLDbListCFPref::DLDbListCFPref(SecPreferencesDomain domain) : mDomain(domain), mPropertyList(NULL), mChanged(false),
103 mSearchListSet(false), mDefaultDLDbIdentifierSet(false), mLoginDLDbIdentifierSet(false)
104 {
105 x_debug2("New DLDbListCFPref %p for domain %d", this, domain);
106 loadPropertyList(true);
107 }
108
109 void DLDbListCFPref::set(SecPreferencesDomain domain)
110 {
111 save();
112
113 mDomain = domain;
114
115 x_debug2("DLDbListCFPref %p domain set to %d", this, domain);
116
117 if (loadPropertyList(true))
118 resetCachedValues();
119 }
120
121 DLDbListCFPref::~DLDbListCFPref()
122 {
123 save();
124
125 x_debug1("~DLDbListCFPref %p", this);
126
127 if (mPropertyList)
128 CFRelease(mPropertyList);
129 }
130
131 bool
132 DLDbListCFPref::loadPropertyList(bool force)
133 {
134 string prefsPath;
135
136 switch (mDomain)
137 {
138 case kSecPreferencesDomainUser:
139 prefsPath = ExpandTildesInPath(kUserDefaultPath);
140 break;
141 case kSecPreferencesDomainSystem:
142 prefsPath = kSystemDefaultPath;
143 break;
144 case kSecPreferencesDomainCommon:
145 prefsPath = kCommonDefaultPath;
146 break;
147 default:
148 MacOSError::throwMe(errSecInvalidPrefsDomain);
149 }
150
151 x_debug2("DLDbListCFPref::loadPropertyList: force=%s prefsPath=%s", force ? "true" : "false",
152 prefsPath.c_str());
153
154 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
155
156 // If for some reason the prefs file path has changed, blow away the old plist and force an update
157 if (mPrefsPath != prefsPath)
158 {
159 mPrefsPath = prefsPath;
160 if (mPropertyList)
161 {
162 CFRelease(mPropertyList);
163 mPropertyList = NULL;
164 }
165
166 mPrefsTimeStamp = now;
167 }
168 else if (!force)
169 {
170 if (now - mPrefsTimeStamp < kDLDbListCFPrefRevertInterval)
171 return false;
172
173 mPrefsTimeStamp = now;
174 }
175
176 struct stat st;
177 if (stat(mPrefsPath.c_str(), &st))
178 {
179 if (errno == ENOENT)
180 {
181 if (mPropertyList)
182 {
183 if (CFDictionaryGetCount(mPropertyList) == 0)
184 return false;
185 CFRelease(mPropertyList);
186 }
187
188 mPropertyList = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
189 return true;
190 }
191 }
192 else
193 {
194 if (mPropertyList)
195 {
196 if (mTimespec.tv_sec == st.st_mtimespec.tv_sec
197 && mTimespec.tv_nsec == st.st_mtimespec.tv_nsec)
198 return false;
199 }
200
201 mTimespec = st.st_mtimespec;
202 }
203
204 CFMutableDictionaryRef thePropertyList = NULL;
205 CFMutableDataRef xmlData = NULL;
206 CFStringRef errorString = NULL;
207 int fd = -1;
208
209 do
210 {
211 fd = open(mPrefsPath.c_str(), O_RDONLY, 0);
212 if (fd < 0)
213 break;
214
215 off_t theSize = lseek(fd, 0, SEEK_END);
216 if (theSize <= 0)
217 break;
218
219 if (lseek(fd, 0, SEEK_SET))
220 break;
221
222 xmlData = CFDataCreateMutable(NULL, CFIndex(theSize));
223 if (!xmlData)
224 break;
225 CFDataSetLength(xmlData, CFIndex(theSize));
226 void *buffer = reinterpret_cast<void *>(CFDataGetMutableBytePtr(xmlData));
227 if (!buffer)
228 break;
229 ssize_t bytesRead = read(fd, buffer, theSize);
230 if (bytesRead != theSize)
231 break;
232
233 thePropertyList = CFMutableDictionaryRef(CFPropertyListCreateFromXMLData(NULL, xmlData, kCFPropertyListMutableContainers, &errorString));
234 if (!thePropertyList)
235 break;
236
237 if (CFGetTypeID(thePropertyList) != CFDictionaryGetTypeID())
238 {
239 CFRelease(thePropertyList);
240 thePropertyList = NULL;
241 break;
242 }
243 } while (0);
244
245 if (fd >= 0)
246 close(fd);
247 if (xmlData)
248 CFRelease(xmlData);
249 if (errorString)
250 CFRelease(errorString);
251
252 if (!thePropertyList)
253 {
254 thePropertyList = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
255 }
256
257 if (mPropertyList)
258 {
259 if (CFEqual(mPropertyList, thePropertyList))
260 {
261 // The new property list is the same as the old one, so nothing has changed.
262 CFRelease(thePropertyList);
263 return false;
264 }
265 CFRelease(mPropertyList);
266 }
267
268 mPropertyList = thePropertyList;
269 return true;
270 }
271
272 void
273 DLDbListCFPref::writePropertyList()
274 {
275 if (!mPropertyList || CFDictionaryGetCount(mPropertyList) == 0)
276 {
277 // There is nothing in the mPropertyList dictionary,
278 // so we don't need a prefs file.
279 unlink(mPrefsPath.c_str());
280 }
281 else
282 {
283 CFDataRef xmlData = CFPropertyListCreateXMLData(NULL, mPropertyList);
284 if (!xmlData)
285 return; // Bad out of memory or something evil happened let's act like CF and do nothing.
286
287 mode_t mode = 0666;
288 int fd = open(mPrefsPath.c_str(), O_WRONLY|O_CREAT|O_TRUNC, mode);
289 if (fd >= 0)
290 {
291 const void *buffer = CFDataGetBytePtr(xmlData);
292 size_t toWrite = CFDataGetLength(xmlData);
293 /* ssize_t bytesWritten = */ write(fd, buffer, toWrite);
294 // Emulate CFPreferences by not checking for any errors.
295
296 fsync(fd);
297 struct stat st;
298 if (!fstat(fd, &st))
299 mTimespec = st.st_mtimespec;
300
301 close(fd);
302 }
303
304 CFRelease(xmlData);
305 }
306
307 mPrefsTimeStamp = CFAbsoluteTimeGetCurrent();
308 }
309
310 void
311 DLDbListCFPref::resetCachedValues()
312 {
313 // Unset the login and default Keychain.
314 mLoginDLDbIdentifier = mDefaultDLDbIdentifier = DLDbIdentifier();
315
316 // Clear the searchList.
317 mSearchList.clear();
318
319 changed(false);
320
321 // Note that none of our cached values are valid
322 mSearchListSet = mDefaultDLDbIdentifierSet = mLoginDLDbIdentifierSet = false;
323
324 mPrefsTimeStamp = CFAbsoluteTimeGetCurrent();
325 }
326
327 void DLDbListCFPref::save()
328 {
329 if (!hasChanged())
330 return;
331
332 // Resync from disc to make sure we don't clobber anyone elses changes.
333 // @@@ This is probably already done by the next layer up so we don't
334 // really need to do it here again.
335 loadPropertyList(true);
336
337 // Do the searchList first since it might end up invoking defaultDLDbIdentifier() which can set
338 // mLoginDLDbIdentifierSet and mDefaultDLDbIdentifierSet to true.
339 if (mSearchListSet)
340 {
341 // Make a temporary CFArray with the contents of the vector
342 if (mSearchList.size() == 1 && mSearchList[0] == defaultDLDbIdentifier() && mSearchList[0] == LoginDLDbIdentifier())
343 {
344 // The only element in the search list is the default keychain, which is a
345 // post Jaguar style login keychain, so omit the entry from the prefs file.
346 CFDictionaryRemoveValue(mPropertyList, kDefaultDLDbListKey);
347 }
348 else
349 {
350 CFMutableArrayRef searchArray = CFArrayCreateMutable(kCFAllocatorDefault, mSearchList.size(), &kCFTypeArrayCallBacks);
351 for (DLDbList::const_iterator ix=mSearchList.begin();ix!=mSearchList.end();ix++)
352 {
353 CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(*ix);
354 CFArrayAppendValue(searchArray, aDict);
355 CFRelease(aDict);
356 }
357
358 CFDictionarySetValue(mPropertyList, kDefaultDLDbListKey, searchArray);
359 CFRelease(searchArray);
360 }
361 }
362
363 if (mLoginDLDbIdentifierSet)
364 {
365 // Make a temporary CFArray with the login keychain
366 CFArrayRef loginArray = NULL;
367 if (!mLoginDLDbIdentifier)
368 {
369 loginArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks);
370 }
371 else if (!(mLoginDLDbIdentifier == LoginDLDbIdentifier())
372 && !(mLoginDLDbIdentifier == JaguarLoginDLDbIdentifier()))
373 {
374 CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mLoginDLDbIdentifier);
375 const void *value = reinterpret_cast<const void *>(aDict);
376 loginArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks);
377 CFRelease(aDict);
378 }
379
380 if (loginArray)
381 {
382 CFDictionarySetValue(mPropertyList, kLoginKeychainKey, loginArray);
383 CFRelease(loginArray);
384 }
385 else
386 CFDictionaryRemoveValue(mPropertyList, kLoginKeychainKey);
387 }
388
389 if (mDefaultDLDbIdentifierSet)
390 {
391 // Make a temporary CFArray with the default keychain
392 CFArrayRef defaultArray = NULL;
393 if (!mDefaultDLDbIdentifier)
394 {
395 defaultArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks);
396 }
397 else if (!(mDefaultDLDbIdentifier == LoginDLDbIdentifier()))
398 {
399 CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mDefaultDLDbIdentifier);
400 const void *value = reinterpret_cast<const void *>(aDict);
401 defaultArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks);
402 CFRelease(aDict);
403 }
404
405 if (defaultArray)
406 {
407 CFDictionarySetValue(mPropertyList, kDefaultKeychainKey, defaultArray);
408 CFRelease(defaultArray);
409 }
410 else
411 CFDictionaryRemoveValue(mPropertyList, kDefaultKeychainKey);
412 }
413
414 writePropertyList();
415 changed(false);
416 }
417
418
419 //----------------------------------------------------------------------
420 // Conversions
421 //----------------------------------------------------------------------
422
423 DLDbIdentifier DLDbListCFPref::LoginDLDbIdentifier()
424 {
425 CSSM_VERSION theVersion={};
426 CssmSubserviceUid ssuid(gGuidAppleCSPDL,&theVersion,0,CSSM_SERVICE_DL|CSSM_SERVICE_CSP);
427 CssmNetAddress *dbLocation=NULL;
428
429 switch (mDomain) {
430 case kSecPreferencesDomainUser:
431 return DLDbIdentifier(ssuid, ExpandTildesInPath(kUserLoginKeychainPath).c_str(), dbLocation);
432 default:
433 assert(false);
434 case kSecPreferencesDomainSystem:
435 case kSecPreferencesDomainCommon:
436 return DLDbIdentifier(ssuid, kSystemLoginKeychainPath, dbLocation);
437 }
438 }
439
440 DLDbIdentifier DLDbListCFPref::JaguarLoginDLDbIdentifier()
441 {
442 CSSM_VERSION theVersion={};
443 CssmSubserviceUid ssuid(gGuidAppleCSPDL,&theVersion,0,CSSM_SERVICE_DL|CSSM_SERVICE_CSP);
444 CssmNetAddress *dbLocation=NULL;
445
446 switch (mDomain) {
447 case kSecPreferencesDomainUser:
448 {
449 string basepath = ExpandTildesInPath(kLoginKeychainPathPrefix) + getPwInfo(kUsername);
450 return DLDbIdentifier(ssuid,basepath.c_str(),dbLocation);
451 }
452 case kSecPreferencesDomainSystem:
453 case kSecPreferencesDomainCommon:
454 return DLDbIdentifier(ssuid, kSystemLoginKeychainPath, dbLocation);
455 default:
456 assert(false);
457 return DLDbIdentifier();
458 }
459 }
460
461 DLDbIdentifier DLDbListCFPref::cfDictionaryRefToDLDbIdentifier(CFDictionaryRef theDict)
462 {
463 // We must get individual values from the dictionary and store in basic types
464 if (CFGetTypeID(theDict) != CFDictionaryGetTypeID())
465 throw std::logic_error("wrong type in property list");
466
467 // GUID
468 CCFValue vGuid(::CFDictionaryGetValue(theDict,kKeyGUID));
469 string guidStr=vGuid;
470 const Guid guid(guidStr.c_str());
471
472 //CSSM_VERSION
473 CSSM_VERSION theVersion={0,};
474 CCFValue vMajor(::CFDictionaryGetValue(theDict,kKeyMajorVersion));
475 theVersion.Major = vMajor;
476 CCFValue vMinor(::CFDictionaryGetValue(theDict,kKeyMinorVersion));
477 theVersion.Minor = vMinor;
478
479 //subserviceId
480 CCFValue vSsid(::CFDictionaryGetValue(theDict,kKeySubserviceId));
481 uint32 subserviceId=sint32(vSsid);
482
483 //CSSM_SERVICE_TYPE
484 CSSM_SERVICE_TYPE subserviceType=CSSM_SERVICE_DL;
485 CCFValue vSsType(::CFDictionaryGetValue(theDict,kKeySubserviceType));
486 subserviceType=vSsType;
487
488 // Get DbName from dictionary
489 CCFValue vDbName(::CFDictionaryGetValue(theDict,kKeyDbName));
490 string dbName=vDbName;
491
492 // jch Get DbLocation from dictionary
493 CssmNetAddress *dbLocation=NULL;
494
495 // Create a local CssmSubserviceUid
496 CssmSubserviceUid ssuid(guid,&theVersion,subserviceId,subserviceType);
497
498 return DLDbIdentifier(ssuid,ExpandTildesInPath(dbName).c_str(),dbLocation);
499 }
500
501 void DLDbListCFPref::clearPWInfo ()
502 {
503 if (mPdbLookup != NULL)
504 {
505 delete mPdbLookup;
506 mPdbLookup = NULL;
507 }
508 }
509
510 string DLDbListCFPref::getPwInfo(PwInfoType type)
511 {
512 // Get our effective uid
513 uid_t uid = geteuid();
514 // If we are setuid root use the real uid instead
515 if (!uid) uid = getuid();
516
517 // get the password entries
518 if (mPdbLookup == NULL)
519 {
520 mPdbLookup = new PasswordDBLookup ();
521 }
522
523 mPdbLookup->lookupInfoOnUID (uid);
524
525 string result;
526 switch (type)
527 {
528 case kHomeDir:
529 result = mPdbLookup->getDirectory ();
530 break;
531 case kUsername:
532 result = mPdbLookup->getName ();
533 break;
534 }
535
536 return result;
537 }
538
539 string DLDbListCFPref::ExpandTildesInPath(const string &inPath)
540 {
541 if ((short)inPath.find("~/",0,2) == 0)
542 return getPwInfo(kHomeDir) + inPath.substr(1);
543 else
544 return inPath;
545 }
546
547 string DLDbListCFPref::StripPathStuff(const string &inPath)
548 {
549 if (inPath.find("/private/var/automount/Network/",0,31) == 0)
550 return inPath.substr(22);
551 if (inPath.find("/private/automount/Servers/",0,27) == 0)
552 return "/Network" + inPath.substr(18);
553 if (inPath.find("/automount/Servers/",0,19) == 0)
554 return "/Network" + inPath.substr(10);
555 if (inPath.find("/private/automount/Network/",0,27) == 0)
556 return inPath.substr(18);
557 if (inPath.find("/automount/Network/",0,19) == 0)
558 return inPath.substr(10);
559 if (inPath.find("/private/Network/",0,17) == 0)
560 return inPath.substr(8);
561 return inPath;
562 }
563
564 string DLDbListCFPref::AbbreviatedPath(const string &inPath)
565 {
566 string path = StripPathStuff(inPath);
567 string home = StripPathStuff(getPwInfo(kHomeDir) + "/");
568 size_t homeLen = home.length();
569
570 if (homeLen > 1 && path.find(home.c_str(), 0, homeLen) == 0)
571 return "~" + path.substr(homeLen - 1);
572 else
573 return path;
574 }
575
576 CFDictionaryRef DLDbListCFPref::dlDbIdentifierToCFDictionaryRef(const DLDbIdentifier& dldbIdentifier)
577 {
578 CFRef<CFMutableDictionaryRef> aDict(CFDictionaryCreateMutable(kCFAllocatorDefault,0,
579 &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks));
580 if (!aDict)
581 throw ::std::bad_alloc();
582
583 // Put SUBSERVICE_UID in dictionary
584 char buffer[Guid::stringRepLength+1];
585 const CssmSubserviceUid& ssuid=dldbIdentifier.ssuid();
586 const Guid &theGuid = Guid::overlay(ssuid.Guid);
587 CFRef<CFStringRef> stringGuid(::CFStringCreateWithCString(kCFAllocatorDefault,
588 theGuid.toString(buffer),kCFStringEncodingMacRoman));
589 if (stringGuid)
590 ::CFDictionarySetValue(aDict,kKeyGUID,stringGuid);
591
592 if (ssuid.SubserviceId!=0)
593 {
594 CFRef<CFNumberRef> subserviceId(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceId));
595 if (subserviceId)
596 ::CFDictionarySetValue(aDict,kKeySubserviceId,subserviceId);
597 }
598 if (ssuid.SubserviceType!=0)
599 {
600 CFRef<CFNumberRef> subserviceType(CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceType));
601 if (subserviceType)
602 ::CFDictionarySetValue(aDict,kKeySubserviceType,subserviceType);
603 }
604 if (ssuid.Version.Major!=0 && ssuid.Version.Minor!=0)
605 {
606 CFRef<CFNumberRef> majorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Major));
607 if (majorVersion)
608 ::CFDictionarySetValue(aDict,kKeyMajorVersion,majorVersion);
609 CFRef<CFNumberRef> minorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Minor));
610 if (minorVersion)
611 ::CFDictionarySetValue(aDict,kKeyMinorVersion,minorVersion);
612 }
613
614 // Put DbName in dictionary
615 const char *dbName=dldbIdentifier.dbName();
616 if (dbName)
617 {
618 CFRef<CFStringRef> theDbName(::CFStringCreateWithCString(kCFAllocatorDefault,AbbreviatedPath(dbName).c_str(),kCFStringEncodingMacRoman));
619 ::CFDictionarySetValue(aDict,kKeyDbName,theDbName);
620 }
621 // Put DbLocation in dictionary
622 const CSSM_NET_ADDRESS *dbLocation=dldbIdentifier.dbLocation();
623 if (dbLocation!=NULL && dbLocation->AddressType!=CSSM_ADDR_NONE)
624 {
625 CFRef<CFDataRef> theData(::CFDataCreate(kCFAllocatorDefault,dbLocation->Address.Data,dbLocation->Address.Length));
626 if (theData)
627 ::CFDictionarySetValue(aDict,kKeyDbLocation,theData);
628 }
629
630 ::CFRetain(aDict);
631 return aDict;
632 }
633
634 bool DLDbListCFPref::revert(bool force)
635 {
636 // If the prefs have not been refreshed in the last kDLDbListCFPrefRevertInterval
637 // seconds or we are asked to force a reload, then reload.
638 if (!loadPropertyList(force))
639 return false;
640
641 resetCachedValues();
642 return true;
643 }
644
645 void
646 DLDbListCFPref::add(const DLDbIdentifier &dldbIdentifier)
647 {
648 for (vector<DLDbIdentifier>::const_iterator ix = searchList().begin(); ix != mSearchList.end(); ++ix)
649 {
650 if (*ix==dldbIdentifier) // already in list
651 return;
652 }
653
654 mSearchList.push_back(dldbIdentifier);
655 changed(true);
656 }
657
658 void
659 DLDbListCFPref::remove(const DLDbIdentifier &dldbIdentifier)
660 {
661 // Make sure mSearchList is set
662 searchList();
663 for (vector<DLDbIdentifier>::iterator ix = mSearchList.begin(); ix != mSearchList.end(); ++ix)
664 {
665 if (*ix==dldbIdentifier) // found in list
666 {
667 mSearchList.erase(ix);
668 changed(true);
669 break;
670 }
671 }
672 }
673
674 const vector<DLDbIdentifier> &
675 DLDbListCFPref::searchList()
676 {
677 if (!mSearchListSet)
678 {
679 CFArrayRef searchList = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kDefaultDLDbListKey));
680 if (searchList && CFGetTypeID(searchList) != CFArrayGetTypeID())
681 searchList = NULL;
682
683 if (searchList)
684 {
685 CFIndex top = CFArrayGetCount(searchList);
686 // Each entry is a CFDictionary; peel it off & add it to the array
687 for (CFIndex idx = 0; idx < top; ++idx)
688 {
689 CFDictionaryRef theDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(searchList, idx));
690 try
691 {
692 mSearchList.push_back(cfDictionaryRefToDLDbIdentifier(theDict));
693 }
694 catch (...)
695 {
696 // Drop stuff that doesn't parse on the floor.
697 }
698 }
699
700 // If there were entries specified, but they were invalid revert to using the
701 // default keychain in the searchlist.
702 if (top > 0 && mSearchList.size() == 0)
703 searchList = NULL;
704 }
705
706 // The default when no search list is specified is to only search the
707 // default keychain.
708 if (!searchList && static_cast<bool>(defaultDLDbIdentifier()))
709 mSearchList.push_back(mDefaultDLDbIdentifier);
710
711 mSearchListSet = true;
712 }
713
714 return mSearchList;
715 }
716
717 void
718 DLDbListCFPref::searchList(const vector<DLDbIdentifier> &searchList)
719 {
720 vector<DLDbIdentifier> newList(searchList);
721 mSearchList.swap(newList);
722 mSearchListSet = true;
723 changed(true);
724 }
725
726 void
727 DLDbListCFPref::defaultDLDbIdentifier(const DLDbIdentifier &dlDbIdentifier)
728 {
729 if (!(defaultDLDbIdentifier() == dlDbIdentifier))
730 {
731 mDefaultDLDbIdentifier = dlDbIdentifier;
732 changed(true);
733 }
734 }
735
736 const DLDbIdentifier &
737 DLDbListCFPref::defaultDLDbIdentifier()
738 {
739 if (!mDefaultDLDbIdentifierSet)
740 {
741 CFArrayRef defaultArray = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kDefaultKeychainKey));
742 if (defaultArray && CFGetTypeID(defaultArray) != CFArrayGetTypeID())
743 defaultArray = NULL;
744
745 if (defaultArray && CFArrayGetCount(defaultArray) > 0)
746 {
747 CFDictionaryRef defaultDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(defaultArray, 0));
748 try
749 {
750 x_debug("Getting default DLDbIdentifier from defaultDict");
751 mDefaultDLDbIdentifier = cfDictionaryRefToDLDbIdentifier(defaultDict);
752 x_debug1("Now we think the default keychain is %s", (mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : "<NULL>");
753 }
754 catch (...)
755 {
756 // If defaultArray doesn't parse fall back on the default way of getting the default keychain
757 defaultArray = NULL;
758 }
759 }
760
761 if (!defaultArray)
762 {
763 // If the Panther style login keychain actually exists we use that otherwise no
764 // default is set.
765 mDefaultDLDbIdentifier = loginDLDbIdentifier();
766 x_debug1("Now we think the default keychain is %s", (mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : "<NULL>");
767
768 struct stat st;
769 int st_result = stat(mDefaultDLDbIdentifier.dbName(), &st);
770 if (st_result)
771 {
772 x_debug2("stat() of %s returned %d", mDefaultDLDbIdentifier.dbName(), st_result);
773 mDefaultDLDbIdentifier = DLDbIdentifier();
774 x_debug1("After DLDbIdentifier(), we think the default keychain is %s", static_cast<bool>(mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : "<NULL>");
775 }
776 }
777
778 mDefaultDLDbIdentifierSet = true;
779 }
780
781 return mDefaultDLDbIdentifier;
782 }
783
784 void
785 DLDbListCFPref::loginDLDbIdentifier(const DLDbIdentifier &dlDbIdentifier)
786 {
787 if (!(loginDLDbIdentifier() == dlDbIdentifier))
788 {
789 mLoginDLDbIdentifier = dlDbIdentifier;
790 changed(true);
791 }
792 }
793
794 const DLDbIdentifier &
795 DLDbListCFPref::loginDLDbIdentifier()
796 {
797 if (!mLoginDLDbIdentifierSet)
798 {
799 CFArrayRef loginArray = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kLoginKeychainKey));
800 if (loginArray && CFGetTypeID(loginArray) != CFArrayGetTypeID())
801 loginArray = NULL;
802
803 if (loginArray && CFArrayGetCount(loginArray) > 0)
804 {
805 CFDictionaryRef loginDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loginArray, 0));
806 try
807 {
808 x_debug("Getting login DLDbIdentifier from loginDict");
809 mLoginDLDbIdentifier = cfDictionaryRefToDLDbIdentifier(loginDict);
810 x_debug1("We think the login keychain is %s", static_cast<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
811 }
812 catch (...)
813 {
814 // If loginArray doesn't parse fall back on the default way of getting the login keychain.
815 loginArray = NULL;
816 }
817 }
818
819 if (!loginArray)
820 {
821 // If the jaguar login keychain actually exists we use that otherwise no
822 // login keychain is set.
823 x_debug("No loginDict found, calling JaguarLoginDLDbIdentifier()");
824 mLoginDLDbIdentifier = JaguarLoginDLDbIdentifier();
825 x_debug1("After JaguarLoginDLDbIdentifier(), we think the login keychain is %s", static_cast<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
826
827 struct stat st;
828 int st_result = stat(mLoginDLDbIdentifier.dbName(), &st);
829 if (st_result)
830 {
831 // Jaguar login Keychain didn't exist, so assume new style one.
832 x_debug2("stat() of %s returned %d", mLoginDLDbIdentifier.dbName(), st_result);
833 mLoginDLDbIdentifier = LoginDLDbIdentifier();
834 x_debug1("After LoginDLDbIdentifier(), we think the login keychain is %s", static_cast<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
835 }
836 }
837
838 mLoginDLDbIdentifierSet = true;
839 }
840
841 return mLoginDLDbIdentifier;
842 }