1 | /*␊ |
2 | * property_list.cpp␊ |
3 | *␊ |
4 | * Created by Rekursor on 1/17/10.␊ |
5 | *␊ |
6 | */␊ |
7 | ␊ |
8 | #import "BootPropertyList.h"␊ |
9 | #include <string.h>␊ |
10 | #include <sys/stat.h>␊ |
11 | ␊ |
12 | /****************************************************************************/␊ |
13 | /**␊ |
14 | * Simple parsing and splitting args function, does handle env. vars ␊ |
15 | */␊ |
16 | static void parseArgs(const char * args, const char* argv[], int argvlen)␊ |
17 | {␊ |
18 | ␉// Create a list of args fron the space delimited args parameters␊ |
19 | ␉int n=0;␊ |
20 | ␉if (args && *args) ␊ |
21 | ␉{␊ |
22 | ␉␉bool skipSpaces = true;␊ |
23 | ␉␉bool prevCharwasDelim =false;␊ |
24 | ␉␉char * buf = strdup(args);␊ |
25 | ␉␉char lastPriorityDelim=' ';␊ |
26 | ␉␉␊ |
27 | ␉␉printf("Parsing <%s>\n", args);␊ |
28 | ␉␉␊ |
29 | ␉␉int k=0;␊ |
30 | ␉␉for (int i=0; i< strlen(args); i++)␊ |
31 | ␉␉{␊ |
32 | ␉␉␉switch (args[i]) ␊ |
33 | ␉␉␉{␊ |
34 | ␉␉␉␉case ' ': case '\t':␊ |
35 | ␉␉␉␉␉if(!skipSpaces) {␊ |
36 | ␉␉␉␉␉␉buf[k++]=args[i];␊ |
37 | ␉␉␉␉␉}␊ |
38 | ␉␉␉␉␉else {␊ |
39 | ␉␉␉␉␉␉prevCharwasDelim = true; // // keep a track of delim to further split tokens␊ |
40 | ␉␉␉␉␉}␊ |
41 | ␉␉␉␉␉break;␊ |
42 | ␉␉␉␉case '\0':␊ |
43 | ␉␉␉␉case '\'': ␊ |
44 | ␉␉␉␉case '"': ␊ |
45 | ␉␉␉␉␉if (!skipSpaces &&lastPriorityDelim!=args[i])␊ |
46 | ␉␉␉␉␉{ // consider the imbricated delim as a simple char␊ |
47 | ␉␉␉␉␉␉buf[k++]=args[i];␊ |
48 | ␉␉␉␉␉␉break;␊ |
49 | ␉␉␉␉␉}␊ |
50 | ␉␉␉␉␉␊ |
51 | ␉␉␉␉␉if (!skipSpaces) // end of priority substr␊ |
52 | ␉␉␉␉␉{␊ |
53 | ␉␉␉␉␉␉skipSpaces = true;␊ |
54 | ␉␉␉␉␉␉lastPriorityDelim=' ';␊ |
55 | ␉␉␉␉␉␉buf[k]='\0'; ␊ |
56 | ␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the priority substr␊ |
57 | ␉␉␉␉␉␉k=0; // reset the buf index for next token␊ |
58 | ␉␉␉␉␉␉buf[0]='\0';␊ |
59 | ␉␉␉␉␉}␊ |
60 | ␉␉␉␉␉else␊ |
61 | ␉␉␉␉␉{ // start of priority substr␊ |
62 | ␉␉␉␉␉␉skipSpaces=false;␊ |
63 | ␉␉␉␉␉␉lastPriorityDelim=args[i];␊ |
64 | ␉␉␉␉␉␉if(k>0) // previous string to store first␊ |
65 | ␉␉␉␉␉␉{␊ |
66 | ␉␉␉␉␉␉␉buf[k++]='\0'; // finish the substr␊ |
67 | ␉␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the substr␊ |
68 | ␉␉␉␉␉␉␉k=0; // rest the index for next token␊ |
69 | ␉␉␉␉␉␉␉buf[0]='\0';␊ |
70 | ␉␉␉␉␉␉}␊ |
71 | ␉␉␉␉␉␉//if (args[i] !='\0') buf[k++] = args[i]; // start the new priority substr␊ |
72 | ␉␉␉␉␉}␊ |
73 | ␉␉␉␉␉break;␊ |
74 | ␉␉␉␉default: // non delimiters chars␊ |
75 | ␉␉␉␉␉if(skipSpaces && prevCharwasDelim)␊ |
76 | ␉␉␉␉␉{␊ |
77 | ␉␉␉␉␉␉if(k>0) // a previous substr was before the space␊ |
78 | ␉␉␉␉␉␉{ // store previous token␊ |
79 | ␉␉␉␉␉␉␉buf[k++]='\0'; // finish the substr␊ |
80 | ␉␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the substr␊ |
81 | ␉␉␉␉␉␉␉k=0; // rest the index for next token␊ |
82 | ␉␉␉␉␉␉␉buf[0]='\0';␊ |
83 | ␉␉␉␉␉␉}␊ |
84 | ␉␉␉␉␉}␊ |
85 | ␉␉␉␉␉prevCharwasDelim = false;␊ |
86 | ␉␉␉␉␉buf[k++]=args[i];␊ |
87 | ␉␉␉␉␉break;␊ |
88 | ␉␉␉}␊ |
89 | ␉␉}␊ |
90 | ␉␉␊ |
91 | ␉␉if(*buf) ␊ |
92 | ␉␉{␊ |
93 | ␉␉␉buf[k]='\0';␊ |
94 | ␉␉␉argv[n++]=strdup(buf); // copy the last buffer␉␊ |
95 | ␉␉}␊ |
96 | ␉␉free((void*) buf);␊ |
97 | ␉}␊ |
98 | ␉argv[n]=NULL;␊ |
99 | }␊ |
100 | ␊ |
101 | /****************************************************************************/␊ |
102 | bool executePrivilegedCmd(AuthorizationRef auth, ␊ |
103 | ␉␉␉␉␉␉␉␉ const char* pathToTool, ␊ |
104 | ␉␉␉␉␉␉␉␉ const char* args, ␊ |
105 | ␉␉␉␉␉␉␉␉ AuthorizationFlags flags)␊ |
106 | {␊ |
107 | ␉const char * argv[16];␊ |
108 | ␊ |
109 | ␉parseArgs(args, argv, sizeof(argv)/sizeof(const char*));␊ |
110 | ␊ |
111 | ␉// Execute Cmd␊ |
112 | ␉OSStatus status = AuthorizationExecuteWithPrivileges(auth, pathToTool,flags, (char**)argv, NULL);␊ |
113 | ␉␊ |
114 | ␉␊ |
115 | ␉// Cleanup mem␊ |
116 | ␉for (int i=0; argv[i]; i++) free ((void*) argv[i]);␊ |
117 | ␊ |
118 | return status ? false : true;␊ |
119 | }␊ |
120 | ␊ |
121 | ␊ |
122 | /****************************************************************************/␊ |
123 | /**␊ |
124 | * Write a property list from a file␊ |
125 | */␊ |
126 | bool WritePropertyListToFile( CFPropertyListRef propertyList, CFURLRef fileURL )␊ |
127 | {␊ |
128 | ␉CFDataRef xmlData;␊ |
129 | ␉Boolean status;␊ |
130 | ␉SInt32 errorCode;␊ |
131 | ␉␊ |
132 | ␉// Convert the property list into XML data.␊ |
133 | ␉xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList );␊ |
134 | ␉␊ |
135 | ␉// Write the XML data to the file.␊ |
136 | ␉status = CFURLWriteDataAndPropertiesToResource (␊ |
137 | ␉␉␉␉␉␉␉␉␉␉␉␉␉fileURL, // URL to use␊ |
138 | ␉␉␉␉␉␉␉␉␉␉␉␉␉xmlData, // data to write␊ |
139 | ␉␉␉␉␉␉␉␉␉␉␉␉␉NULL,␊ |
140 | ␉␉␉␉␉␉␉␉␉␉␉␉␉&errorCode);␊ |
141 | ␉CFRelease(xmlData);␊ |
142 | ␉␊ |
143 | ␉return status ? true: false;␊ |
144 | }␊ |
145 | ␊ |
146 | /****************************************************************************/␊ |
147 | /**␊ |
148 | * Read a property list from a file␊ |
149 | */␊ |
150 | static CFPropertyListRef CreatePropertyListFromFile( CFURLRef fileURL, CFStringRef * errorString ) {␊ |
151 | ␉CFPropertyListRef propertyList;␊ |
152 | ␉CFDataRef resourceData;␊ |
153 | ␉Boolean status;␊ |
154 | ␉SInt32 errorCode;␊ |
155 | ␉␊ |
156 | ␉// Read the XML file.␊ |
157 | ␉status = CFURLCreateDataAndPropertiesFromResource(␊ |
158 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ kCFAllocatorDefault,␊ |
159 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ fileURL,␊ |
160 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ &resourceData, // place to put file data␊ |
161 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ NULL,␊ |
162 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ NULL,␊ |
163 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ &errorCode);␊ |
164 | ␉if (!status) return NULL;␊ |
165 | ␉␊ |
166 | ␉// Reconstitute the dictionary using the XML data.␊ |
167 | ␉propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,␊ |
168 | ␉␉␉␉␉␉␉␉␉␉␉␉ resourceData,␊ |
169 | ␉␉␉␉␉␉␉␉␉␉␉␉ kCFPropertyListMutableContainersAndLeaves,␊ |
170 | ␉␉␉␉␉␉␉␉␉␉␉␉ errorString);␊ |
171 | ␊ |
172 | ␉␉␉␉␉␉␊ |
173 | ␉CFRelease( resourceData );␊ |
174 | ␉return propertyList;␊ |
175 | }␊ |
176 | ␊ |
177 | /****************************************************************************/␊ |
178 | /*␊ |
179 | * Always return a valid static const string, if the CFSTR is not valid, then we return ""␊ |
180 | */␊ |
181 | static const char * CfsToCs(CFStringRef inRef)␊ |
182 | {␊ |
183 | ␉static char buffer[512]="";␊ |
184 | ␉if(CFStringGetFileSystemRepresentation (inRef, buffer, sizeof(buffer)))␊ |
185 | ␉ return buffer;␊ |
186 | ␉return "";␊ |
187 | }␊ |
188 | ␉␊ |
189 | /****************************************************************************/␊ |
190 | /**␊ |
191 | * Creates a PropertyList Incstance␊ |
192 | */␊ |
193 | PropertyList::~PropertyList()␊ |
194 | {␊ |
195 | ␉if (_CFURLRef) CFRelease(_CFURLRef);␊ |
196 | ␉if (_proplistRef) CFRelease(_proplistRef);␊ |
197 | ␊ |
198 | }␊ |
199 | bool PropertyList::chmodFile(const char * path, const char * chmodMask,␊ |
200 | ␉␉␉␉␉␉␉␉␉ AuthorizationRef auth, AuthorizationFlags flags)␊ |
201 | {␊ |
202 | ␉if (!path || !*path) return false;␊ |
203 | ␉␊ |
204 | ␉if (auth)␊ |
205 | ␉{ // give write temporary write rights to the file␊ |
206 | ␉␉std::string args = chmodMask;␊ |
207 | ␉␉args += ' ';␊ |
208 | ␉␉args += path;␊ |
209 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␉␊ |
210 | ␉␉␉return false;␊ |
211 | ␉}␊ |
212 | ␉return true;␊ |
213 | ␉␊ |
214 | }␊ |
215 | ␊ |
216 | /****************************************************************************/␊ |
217 | /**␊ |
218 | * Open a properlist from a path name␊ |
219 | */␊ |
220 | bool PropertyList::open(const char * path, CFStringRef * errorString, AuthorizationRef auth, AuthorizationFlags flags)␊ |
221 | {␊ |
222 | ␉bool ret = false;␊ |
223 | ␉␊ |
224 | ␉if (!path || !*path) return false;␊ |
225 | ␉struct stat st;␊ |
226 | ␉if(stat(path,&st) != 0) return false; // file does not exist;␊ |
227 | ␊ |
228 | ␉// give write temporary write rights to the file␊ |
229 | ␉if (!chmodFile(path,"0777", auth, flags)) return false;␊ |
230 | ␊ |
231 | ␉_propFilePath = path;␊ |
232 | ␊ |
233 | ␉CFStringRef cfPath = CFStringCreateWithCString (kCFAllocatorDefault, path, kCFStringEncodingUTF8);␊ |
234 | ␉CFURLRef inURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,␊ |
235 | ␉␉␉␉␉␉␉␉␉␉␉cfPath, ␊ |
236 | ␉␉␉␉␉␉␉␉␉␉␉kCFURLPOSIXPathStyle, // interpret as POSIX path␊ |
237 | ␉␉␉␉␉␉␉␉␉␉␉false ); // is it a directory?␊ |
238 | ␉CFRelease(cfPath);␊ |
239 | ␉if (_CFURLRef) CFRelease(_CFURLRef);␊ |
240 | ␉_CFURLRef = inURL;␊ |
241 | ␉␊ |
242 | ␉if (_CFURLRef) ␊ |
243 | ␉{␊ |
244 | ␉␉CFRetain(_CFURLRef);␊ |
245 | ␉␉_proplistRef = CreatePropertyListFromFile(inURL, errorString);␊ |
246 | ␉␉␊ |
247 | ␉␉if (_proplistRef) {␊ |
248 | ␉␉␉CFRetain(_proplistRef);␊ |
249 | ␉␉␉ret= true;␊ |
250 | ␉␉}␊ |
251 | ␉}␊ |
252 | ␉// restore rights␊ |
253 | ␉ret= chmodFile(path,"0644", auth, flags);␊ |
254 | ␉␊ |
255 | ␉return ret;␊ |
256 | }␊ |
257 | ␊ |
258 | /****************************************************************************/␊ |
259 | /**␊ |
260 | * Save the current property list␊ |
261 | */␊ |
262 | bool PropertyList::save(AuthorizationRef auth, AuthorizationFlags flags)␊ |
263 | {␊ |
264 | ␉bool ret=false;␊ |
265 | ␉if (auth)␊ |
266 | ␉{ // give write temporary write rights to the file␊ |
267 | ␉␉std::string args = " 0777 "+ _propFilePath;␊ |
268 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␊ |
269 | ␉␉␉return false;␊ |
270 | ␉}␊ |
271 | ␉if (_proplistRef && _CFURLRef) ␊ |
272 | ␉␉ret= WritePropertyListToFile(_proplistRef,_CFURLRef);␊ |
273 | ␉if (auth)␊ |
274 | ␉{ // give write temporary write rights to the file␊ |
275 | ␉␉std::string args = " 0644 "+ _propFilePath;␊ |
276 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␊ |
277 | ␉␉␉return false;␊ |
278 | ␉}␊ |
279 | ␉return ret;␊ |
280 | }␊ |
281 | ␊ |
282 | /****************************************************************************/␊ |
283 | /**␊ |
284 | * Extract a sring value from a property list key, ␊ |
285 | * value returned is not owned by caller, copy it necessary.␊ |
286 | */␊ |
287 | const char * PropertyList::getStringForKey(const char *key)␊ |
288 | {␊ |
289 | ␉if (!_proplistRef) ␉return NULL;␊ |
290 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
291 | ␉CFStringRef myString;␊ |
292 | ␉␊ |
293 | ␉if (_proplistRef && CFDictionaryGetValueIfPresent((CFMutableDictionaryRef)_proplistRef, ␊ |
294 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ cfKey, (const void **) &myString))␊ |
295 | ␉{␊ |
296 | ␉␉CFRelease(cfKey);␊ |
297 | ␉␉return CfsToCs(myString);␊ |
298 | ␉}␊ |
299 | ␉␊ |
300 | ␉if(cfKey) CFRelease(cfKey);␊ |
301 | ␉return NULL;␊ |
302 | }␊ |
303 | /****************************************************************************/␊ |
304 | /**␊ |
305 | * replace a sring value from a property list key, ␊ |
306 | * value returned is not owned by caller, copy it necessary.␊ |
307 | */␊ |
308 | bool PropertyList::setStringForKey(const char *key, const char * value)␊ |
309 | {␊ |
310 | ␉if (!_proplistRef) ␉return false;␊ |
311 | ␉bool ret = false;␊ |
312 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
313 | ␉CFStringRef myString = CFStringCreateWithCString (kCFAllocatorDefault, value, kCFStringEncodingUTF8);␊ |
314 | ␉CFMutableDictionaryRef myDict = (CFMutableDictionaryRef) _proplistRef;␊ |
315 | ␉␊ |
316 | ␉if (myDict) ␊ |
317 | ␉{␊ |
318 | ␉␉CFDictionarySetValue(myDict, cfKey, myString);␊ |
319 | ␉␉ret=true;␉␊ |
320 | ␉} ␊ |
321 | ␉if(cfKey) CFRelease(cfKey);␊ |
322 | ␉//if(myString) CFRelease(myString);␊ |
323 | ␉return ret;␊ |
324 | }␊ |
325 | ␊ |
326 | /****************************************************************************/␊ |
327 | /**␊ |
328 | * delete a key and its value from the dictionary␊ |
329 | */␊ |
330 | bool PropertyList::removeKeyAndValue(const char *key)␊ |
331 | {␊ |
332 | ␉if (!_proplistRef) ␉return false;␊ |
333 | ␉bool ret = false;␊ |
334 | ␉␊ |
335 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
336 | ␉␊ |
337 | ␉if (_proplistRef) {␊ |
338 | ␉␉CFDictionaryRemoveValue((CFMutableDictionaryRef) _proplistRef, cfKey);␊ |
339 | ␉␉ret=true;␉␊ |
340 | ␉} ␊ |
341 | ␉if(cfKey) CFRelease(cfKey);␊ |
342 | ␉return ret;␊ |
343 | }␊ |
344 | ␊ |
345 | |