2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
23 #include "DLDBListCFPref.h"
24 #include <Security/cssmapple.h>
28 using namespace CssmClient
;
30 static const double kDLDbListCFPrefRevertInterval
= 30.0;
32 #define kKeyGUID CFSTR("GUID")
33 #define kKeySubserviceId CFSTR("SubserviceId")
34 #define kKeySubserviceType CFSTR("SubserviceType")
35 #define kKeyDbName CFSTR("DbName")
36 #define kKeyDbLocation CFSTR("DbLocation")
37 #define kKeyActive CFSTR("Active")
38 #define kKeyMajorVersion CFSTR("MajorVersion")
39 #define kKeyMinorVersion CFSTR("MinorVersion")
40 #define kDefaultDLDbListKey CFSTR("DLDBSearchList")
41 #define kDefaultDomain CFSTR("com.apple.security")
44 //-------------------------------------------------------------------------------------
46 // Lists of DL/DBs, with CFPreferences backing store
48 //-------------------------------------------------------------------------------------
50 DLDbListCFPref::DLDbListCFPref(CFStringRef theDLDbListKey
,CFStringRef prefsDomain
) :
51 mPrefsDomain(prefsDomain
?prefsDomain
:kDefaultDomain
),mDLDbListKey(theDLDbListKey
?theDLDbListKey
:kDefaultDLDbListKey
)
56 DLDbListCFPref::~DLDbListCFPref()
61 void DLDbListCFPref::loadOrCreate()
64 CFRef
<CFArrayRef
> theArray(static_cast<CFArrayRef
>(::CFPreferencesCopyValue(mDLDbListKey
, mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
)));
68 if (::CFGetTypeID(theArray
)!=::CFArrayGetTypeID())
70 ::CFPreferencesSetValue(mDLDbListKey
, NULL
, mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
74 CFIndex top
=::CFArrayGetCount(theArray
);
75 // Each entry is a CFDictionary; peel it off & add it to the array
76 for (CFIndex idx
=0;idx
<top
;idx
++)
78 CFDictionaryRef theDict
=reinterpret_cast<CFDictionaryRef
>(::CFArrayGetValueAtIndex(theArray
,idx
));
79 DLDbIdentifier theDLDbIdentifier
=cfDictionaryRefToDLDbIdentifier(theDict
);
80 push_back(theDLDbIdentifier
);
84 mPrefsTimeStamp
=CFAbsoluteTimeGetCurrent();
89 void DLDbListCFPref::save()
93 // Make a temporary CFArray with the contents of the vector
94 CFRef
<CFMutableArrayRef
> theArray(::CFArrayCreateMutable(kCFAllocatorDefault
,size(),&kCFTypeArrayCallBacks
));
95 for (DLDbList::const_iterator ix
=begin();ix
!=end();ix
++)
97 CFRef
<CFDictionaryRef
> aDict(dlDbIdentifierToCFDictionaryRef(*ix
));
98 ::CFArrayAppendValue(theArray
,aDict
);
101 ::CFPreferencesSetValue(mDLDbListKey
, theArray
, mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
102 ::CFPreferencesSynchronize(mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
107 void DLDbListCFPref::clearDefaultKeychain()
109 ::CFPreferencesSetValue(mDLDbListKey
, NULL
, mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
110 ::CFPreferencesSynchronize(mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
117 //----------------------------------------------------------------------
119 //----------------------------------------------------------------------
121 DLDbIdentifier
DLDbListCFPref::cfDictionaryRefToDLDbIdentifier(CFDictionaryRef theDict
)
123 // We must get individual values from the dictionary and store in basic types
126 CCFValue
vGuid(::CFDictionaryGetValue(theDict
,kKeyGUID
));
127 string guidStr
=vGuid
;
128 const Guid
guid(guidStr
.c_str());
131 CSSM_VERSION theVersion
={0,};
132 CCFValue
vMajor(::CFDictionaryGetValue(theDict
,kKeyMajorVersion
));
133 theVersion
.Major
= vMajor
;
134 CCFValue
vMinor(::CFDictionaryGetValue(theDict
,kKeyMinorVersion
));
135 theVersion
.Minor
= vMinor
;
138 CCFValue
vSsid(::CFDictionaryGetValue(theDict
,kKeySubserviceId
));
139 uint32 subserviceId
=sint32(vSsid
);
142 CSSM_SERVICE_TYPE subserviceType
=CSSM_SERVICE_DL
;
143 CCFValue
vSsType(::CFDictionaryGetValue(theDict
,kKeySubserviceType
));
144 subserviceType
=vSsType
;
146 // Get DbName from dictionary
147 CCFValue
vDbName(::CFDictionaryGetValue(theDict
,kKeyDbName
));
148 string dbName
=vDbName
;
150 // jch Get DbLocation from dictionary
151 CssmNetAddress
*dbLocation
=NULL
;
153 // Create a local CssmSubserviceUid
154 CssmSubserviceUid
ssuid(guid
,&theVersion
,subserviceId
,subserviceType
);
156 return DLDbIdentifier(ssuid
,ExpandTildesInPath(dbName
).c_str(),dbLocation
);
159 string
DLDbListCFPref::HomeDir()
161 const char *home
= getenv("HOME");
164 // If $HOME is unset get the current users home directory from the passwd file.
165 struct passwd
*pw
= getpwuid(getuid());
169 return home
? home
: "";
172 string
DLDbListCFPref::ExpandTildesInPath(const string
&inPath
)
174 if ((short)inPath
.find("~/",0,2) == 0)
175 return HomeDir() + inPath
.substr(1);
180 string
DLDbListCFPref::StripPathStuff(const string
&inPath
)
182 if (inPath
.find("/private/automount/Network/",0,27) == 0)
183 return inPath
.substr(18);
184 if (inPath
.find("/automount/Network/",0,19) == 0)
185 return inPath
.substr(10);
186 if (inPath
.find("/private/Network/",0,17) == 0)
187 return inPath
.substr(8);
191 string
DLDbListCFPref::AbbreviatedPath(const string
&inPath
)
193 string path
= StripPathStuff(inPath
);
194 string home
= StripPathStuff(HomeDir() + "/");
195 size_t homeLen
= home
.length();
197 if (homeLen
> 1 && path
.find(home
.c_str(), 0, homeLen
) == 0)
198 return "~" + path
.substr(homeLen
- 1);
203 CFDictionaryRef
DLDbListCFPref::dlDbIdentifierToCFDictionaryRef(const DLDbIdentifier
& dldbIdentifier
)
205 CFRef
<CFMutableDictionaryRef
> aDict(CFDictionaryCreateMutable(kCFAllocatorDefault
,0,
206 &kCFTypeDictionaryKeyCallBacks
,&kCFTypeDictionaryValueCallBacks
));
208 throw ::std::bad_alloc();
210 // Put SUBSERVICE_UID in dictionary
211 char buffer
[Guid::stringRepLength
+1];
212 const CssmSubserviceUid
& ssuid
=dldbIdentifier
.ssuid();
213 const Guid
&theGuid
= Guid::overlay(ssuid
.Guid
);
214 CFRef
<CFStringRef
> stringGuid(::CFStringCreateWithCString(kCFAllocatorDefault
,
215 theGuid
.toString(buffer
),kCFStringEncodingMacRoman
));
217 ::CFDictionarySetValue(aDict
,kKeyGUID
,stringGuid
);
219 if (ssuid
.SubserviceId
!=0)
221 CFRef
<CFNumberRef
> subserviceId(::CFNumberCreate(kCFAllocatorDefault
,kCFNumberSInt32Type
,&ssuid
.SubserviceId
));
223 ::CFDictionarySetValue(aDict
,kKeySubserviceId
,subserviceId
);
225 if (ssuid
.SubserviceType
!=0)
227 CFRef
<CFNumberRef
> subserviceType(CFNumberCreate(kCFAllocatorDefault
,kCFNumberSInt32Type
,&ssuid
.SubserviceType
));
229 ::CFDictionarySetValue(aDict
,kKeySubserviceType
,subserviceType
);
231 if (ssuid
.Version
.Major
!=0 && ssuid
.Version
.Minor
!=0)
233 CFRef
<CFNumberRef
> majorVersion(::CFNumberCreate(kCFAllocatorDefault
,kCFNumberSInt32Type
,&ssuid
.Version
.Major
));
235 ::CFDictionarySetValue(aDict
,kKeyMajorVersion
,majorVersion
);
236 CFRef
<CFNumberRef
> minorVersion(::CFNumberCreate(kCFAllocatorDefault
,kCFNumberSInt32Type
,&ssuid
.Version
.Minor
));
238 ::CFDictionarySetValue(aDict
,kKeyMinorVersion
,minorVersion
);
241 // Put DbName in dictionary
242 const char *dbName
=dldbIdentifier
.dbName();
245 CFRef
<CFStringRef
> theDbName(::CFStringCreateWithCString(kCFAllocatorDefault
,AbbreviatedPath(dbName
).c_str(),kCFStringEncodingMacRoman
));
246 ::CFDictionarySetValue(aDict
,kKeyDbName
,theDbName
);
248 // Put DbLocation in dictionary
249 const CSSM_NET_ADDRESS
*dbLocation
=dldbIdentifier
.dbLocation();
250 if (dbLocation
!=NULL
&& dbLocation
->AddressType
!=CSSM_ADDR_NONE
)
252 CFRef
<CFDataRef
> theData(::CFDataCreate(kCFAllocatorDefault
,dbLocation
->Address
.Data
,dbLocation
->Address
.Length
));
254 ::CFDictionarySetValue(aDict
,kKeyDbLocation
,theData
);
260 bool DLDbListCFPref::revert(bool force
)
263 // if the prefs have not been refreshed in the last 5 seconds force a reload
264 if (force
|| CFAbsoluteTimeGetCurrent() - mPrefsTimeStamp
> kDLDbListCFPrefRevertInterval
)
267 ::CFPreferencesSynchronize(mPrefsDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
269 return true; // @@@ Be smarter about when something *really* changed