]> git.saurik.com Git - apple/security.git/blob - Keychain/DLDBListCFPref.cpp
f7ee77d1a3b7572c6bd4a2430cd3c736e9d24c54
[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 <memory>
26 #include <pwd.h>
27
28 using namespace CssmClient;
29
30 static const double kDLDbListCFPrefRevertInterval = 30.0;
31
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")
42
43
44 //-------------------------------------------------------------------------------------
45 //
46 // Lists of DL/DBs, with CFPreferences backing store
47 //
48 //-------------------------------------------------------------------------------------
49
50 DLDbListCFPref::DLDbListCFPref(CFStringRef theDLDbListKey,CFStringRef prefsDomain) :
51 mPrefsDomain(prefsDomain?prefsDomain:kDefaultDomain),mDLDbListKey(theDLDbListKey?theDLDbListKey:kDefaultDLDbListKey)
52 {
53 loadOrCreate();
54 }
55
56 DLDbListCFPref::~DLDbListCFPref()
57 {
58 save();
59 }
60
61 void DLDbListCFPref::loadOrCreate()
62 {
63
64 CFRef<CFArrayRef> theArray(static_cast<CFArrayRef>(::CFPreferencesCopyValue(mDLDbListKey, mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost)));
65 if (!theArray)
66 return;
67
68 if (::CFGetTypeID(theArray)!=::CFArrayGetTypeID())
69 {
70 ::CFPreferencesSetValue(mDLDbListKey, NULL, mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
71 return;
72 }
73
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++)
77 {
78 CFDictionaryRef theDict=reinterpret_cast<CFDictionaryRef>(::CFArrayGetValueAtIndex(theArray,idx));
79 DLDbIdentifier theDLDbIdentifier=cfDictionaryRefToDLDbIdentifier(theDict);
80 push_back(theDLDbIdentifier);
81 }
82
83
84 mPrefsTimeStamp=CFAbsoluteTimeGetCurrent();
85
86
87 }
88
89 void DLDbListCFPref::save()
90 {
91 if (!hasChanged())
92 return;
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++)
96 {
97 CFRef<CFDictionaryRef> aDict(dlDbIdentifierToCFDictionaryRef(*ix));
98 ::CFArrayAppendValue(theArray,aDict);
99 }
100
101 ::CFPreferencesSetValue(mDLDbListKey, theArray, mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
102 ::CFPreferencesSynchronize(mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
103
104 changed(false);
105 }
106
107 void DLDbListCFPref::clearDefaultKeychain()
108 {
109 ::CFPreferencesSetValue(mDLDbListKey, NULL, mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
110 ::CFPreferencesSynchronize(mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
111
112 changed(false);
113 }
114
115
116
117 //----------------------------------------------------------------------
118 // Conversions
119 //----------------------------------------------------------------------
120
121 DLDbIdentifier DLDbListCFPref::cfDictionaryRefToDLDbIdentifier(CFDictionaryRef theDict)
122 {
123 // We must get individual values from the dictionary and store in basic types
124
125 // GUID
126 CCFValue vGuid(::CFDictionaryGetValue(theDict,kKeyGUID));
127 string guidStr=vGuid;
128 const Guid guid(guidStr.c_str());
129
130 //CSSM_VERSION
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;
136
137 //subserviceId
138 CCFValue vSsid(::CFDictionaryGetValue(theDict,kKeySubserviceId));
139 uint32 subserviceId=sint32(vSsid);
140
141 //CSSM_SERVICE_TYPE
142 CSSM_SERVICE_TYPE subserviceType=CSSM_SERVICE_DL;
143 CCFValue vSsType(::CFDictionaryGetValue(theDict,kKeySubserviceType));
144 subserviceType=vSsType;
145
146 // Get DbName from dictionary
147 CCFValue vDbName(::CFDictionaryGetValue(theDict,kKeyDbName));
148 string dbName=vDbName;
149
150 // jch Get DbLocation from dictionary
151 CssmNetAddress *dbLocation=NULL;
152
153 // Create a local CssmSubserviceUid
154 CssmSubserviceUid ssuid(guid,&theVersion,subserviceId,subserviceType);
155
156 return DLDbIdentifier(ssuid,ExpandTildesInPath(dbName).c_str(),dbLocation);
157 }
158
159 string DLDbListCFPref::HomeDir()
160 {
161 const char *home = getenv("HOME");
162 if (!home)
163 {
164 // If $HOME is unset get the current users home directory from the passwd file.
165 struct passwd *pw = getpwuid(getuid());
166 if (pw)
167 home = pw->pw_dir;
168 }
169 return home ? home : "";
170 }
171
172 string DLDbListCFPref::ExpandTildesInPath(const string &inPath)
173 {
174 if ((short)inPath.find("~/",0,2) == 0)
175 return HomeDir() + inPath.substr(1);
176 else
177 return inPath;
178 }
179
180 string DLDbListCFPref::StripPathStuff(const string &inPath)
181 {
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);
188 return inPath;
189 }
190
191 string DLDbListCFPref::AbbreviatedPath(const string &inPath)
192 {
193 string path = StripPathStuff(inPath);
194 string home = StripPathStuff(HomeDir() + "/");
195 size_t homeLen = home.length();
196
197 if (homeLen > 1 && path.find(home.c_str(), 0, homeLen) == 0)
198 return "~" + path.substr(homeLen - 1);
199 else
200 return path;
201 }
202
203 CFDictionaryRef DLDbListCFPref::dlDbIdentifierToCFDictionaryRef(const DLDbIdentifier& dldbIdentifier)
204 {
205 CFRef<CFMutableDictionaryRef> aDict(CFDictionaryCreateMutable(kCFAllocatorDefault,0,
206 &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks));
207 if (!aDict)
208 throw ::std::bad_alloc();
209
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));
216 if (stringGuid)
217 ::CFDictionarySetValue(aDict,kKeyGUID,stringGuid);
218
219 if (ssuid.SubserviceId!=0)
220 {
221 CFRef<CFNumberRef> subserviceId(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceId));
222 if (subserviceId)
223 ::CFDictionarySetValue(aDict,kKeySubserviceId,subserviceId);
224 }
225 if (ssuid.SubserviceType!=0)
226 {
227 CFRef<CFNumberRef> subserviceType(CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceType));
228 if (subserviceType)
229 ::CFDictionarySetValue(aDict,kKeySubserviceType,subserviceType);
230 }
231 if (ssuid.Version.Major!=0 && ssuid.Version.Minor!=0)
232 {
233 CFRef<CFNumberRef> majorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Major));
234 if (majorVersion)
235 ::CFDictionarySetValue(aDict,kKeyMajorVersion,majorVersion);
236 CFRef<CFNumberRef> minorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Minor));
237 if (minorVersion)
238 ::CFDictionarySetValue(aDict,kKeyMinorVersion,minorVersion);
239 }
240
241 // Put DbName in dictionary
242 const char *dbName=dldbIdentifier.dbName();
243 if (dbName)
244 {
245 CFRef<CFStringRef> theDbName(::CFStringCreateWithCString(kCFAllocatorDefault,AbbreviatedPath(dbName).c_str(),kCFStringEncodingMacRoman));
246 ::CFDictionarySetValue(aDict,kKeyDbName,theDbName);
247 }
248 // Put DbLocation in dictionary
249 const CSSM_NET_ADDRESS *dbLocation=dldbIdentifier.dbLocation();
250 if (dbLocation!=NULL && dbLocation->AddressType!=CSSM_ADDR_NONE)
251 {
252 CFRef<CFDataRef> theData(::CFDataCreate(kCFAllocatorDefault,dbLocation->Address.Data,dbLocation->Address.Length));
253 if (theData)
254 ::CFDictionarySetValue(aDict,kKeyDbLocation,theData);
255 }
256
257 ::CFRetain(aDict);
258 return aDict;
259 }
260 bool DLDbListCFPref::revert(bool force)
261 {
262
263 // if the prefs have not been refreshed in the last 5 seconds force a reload
264 if (force || CFAbsoluteTimeGetCurrent() - mPrefsTimeStamp > kDLDbListCFPrefRevertInterval)
265 {
266 clear();
267 ::CFPreferencesSynchronize(mPrefsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
268 loadOrCreate();
269 return true; // @@@ Be smarter about when something *really* changed
270 }
271
272 return false;
273 }
274