]> git.saurik.com Git - apple/security.git/blob - libsecurity_authorization/lib/Authorization.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_authorization / lib / Authorization.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // Authorization.cpp
27 //
28 // This file is the unified implementation of the Authorization and AuthSession APIs.
29 //
30 #include <stdint.h>
31 #include <Security/Authorization.h>
32 #include <Security/AuthorizationPriv.h>
33 #include <Security/AuthorizationDB.h>
34 #include <Security/AuthorizationTagsPriv.h>
35 #include <Security/AuthSession.h>
36 #include <security_utilities/mach++.h>
37 #include <security_utilities/globalizer.h>
38 #include <security_utilities/alloc.h>
39 #include <security_utilities/cfutilities.h>
40 #include <security_cdsa_utilities/cssmbridge.h>
41 #include <security_cdsa_utilities/AuthorizationWalkers.h>
42 #include <security_utilities/ccaudit.h>
43 #include <securityd_client/ssclient.h>
44 #include <CoreFoundation/CFPreferences.h>
45 #include <Carbon/../Frameworks/HIToolbox.framework/Headers/TextInputSources.h>
46
47 #include <security_utilities/logging.h>
48
49 using namespace SecurityServer;
50 using namespace MachPlusPlus;
51
52
53 //
54 // Shared cached client object
55 //
56 class AuthClient : public SecurityServer::ClientSession {
57 public:
58 AuthClient()
59 : SecurityServer::ClientSession(Allocator::standard(), Allocator::standard())
60 { }
61 };
62
63 static ModuleNexus<AuthClient> server;
64
65
66 //
67 // Create an Authorization
68 //
69 OSStatus AuthorizationCreate(const AuthorizationRights *rights,
70 const AuthorizationEnvironment *environment,
71 AuthorizationFlags flags,
72 AuthorizationRef *authorization)
73 {
74 BEGIN_API
75 AuthorizationBlob result;
76 server().authCreate(rights, environment, flags, result);
77 if (authorization)
78 {
79 *authorization =
80 (AuthorizationRef) new(server().returnAllocator) AuthorizationBlob(result);
81 }
82 else
83 {
84 // If no authorizationRef is desired free the one we just created.
85 server().authRelease(result, flags);
86 }
87 END_API(CSSM)
88 }
89
90
91 //
92 // Free an authorization reference
93 //
94 OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
95 {
96 BEGIN_API
97 AuthorizationBlob *auth = (AuthorizationBlob *)authorization;
98 server().authRelease(Required(auth, errAuthorizationInvalidRef), flags);
99 server().returnAllocator.free(auth);
100 END_API(CSSM)
101 }
102
103
104 //
105 // Augment and/or interrogate an authorization
106 //
107 OSStatus AuthorizationCopyRights(AuthorizationRef authorization,
108 const AuthorizationRights *rights,
109 const AuthorizationEnvironment *environment,
110 AuthorizationFlags flags,
111 AuthorizationRights **authorizedRights)
112 {
113 BEGIN_API
114 AuthorizationBlob *auth = (AuthorizationBlob *)authorization;
115 server().authCopyRights(Required(auth, errAuthorizationInvalidRef),
116 rights, environment, flags, authorizedRights);
117 END_API(CSSM)
118 }
119
120
121 //
122 // Augment and/or interrogate an authorization asynchronously
123 //
124 void AuthorizationCopyRightsAsync(AuthorizationRef authorization,
125 const AuthorizationRights *rights,
126 const AuthorizationEnvironment *environment,
127 AuthorizationFlags flags,
128 AuthorizationAsyncCallback callbackBlock)
129 {
130 __block AuthorizationRights *blockAuthorizedRights = NULL;
131
132 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
133 OSStatus status = AuthorizationCopyRights(authorization, rights, environment, flags, &blockAuthorizedRights);
134 callbackBlock(status, blockAuthorizedRights);
135 });
136 }
137
138
139 //
140 // Retrieve side-band information from an authorization
141 //
142 OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
143 AuthorizationString tag,
144 AuthorizationItemSet **info)
145 {
146 BEGIN_API
147 AuthorizationBlob *auth = (AuthorizationBlob *)authorization;
148 server().authCopyInfo(Required(auth, errAuthorizationInvalidRef),
149 tag, Required(info));
150 END_API(CSSM)
151 }
152
153
154 //
155 // Externalize and internalize authorizations
156 //
157 OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
158 AuthorizationExternalForm *extForm)
159 {
160 BEGIN_API
161 AuthorizationBlob *auth = (AuthorizationBlob *)authorization;
162 server().authExternalize(Required(auth, errAuthorizationInvalidRef), *extForm);
163 END_API(CSSM)
164 }
165
166 OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm,
167 AuthorizationRef *authorization)
168 {
169 BEGIN_API
170 AuthorizationBlob result;
171 server().authInternalize(*extForm, result);
172 Required(authorization, errAuthorizationInvalidRef) =
173 (AuthorizationRef) new(server().returnAllocator) AuthorizationBlob(result);
174
175 END_API(CSSM)
176 }
177
178
179 //
180 // Free an ItemSet structure returned from an API call. This is a local operation.
181 // Since we allocate returned ItemSets as compact blobs, this is just a simple
182 // free() call.
183 //
184 OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set)
185 {
186 BEGIN_API
187 server().returnAllocator.free(set);
188 return errAuthorizationSuccess;
189 END_API(CSSM)
190 }
191
192
193 //
194 // This no longer talks to securityd; it is a kernel function.
195 //
196 OSStatus SessionGetInfo(SecuritySessionId requestedSession,
197 SecuritySessionId *sessionId,
198 SessionAttributeBits *attributes)
199 {
200 BEGIN_API
201 CommonCriteria::AuditInfo session;
202 if (requestedSession == callerSecuritySession)
203 session.get();
204 else
205 session.get(requestedSession);
206 if (sessionId)
207 *sessionId = session.sessionId();
208 if (attributes)
209 *attributes = session.flags();
210 END_API(CSSM)
211 }
212
213
214 //
215 // Create a new session.
216 // This no longer talks to securityd; it is a kernel function.
217 // Securityd will pick up the new session when we next talk to it.
218 //
219 OSStatus SessionCreate(SessionCreationFlags flags,
220 SessionAttributeBits attributes)
221 {
222 BEGIN_API
223
224 // we don't support the session creation flags anymore
225 if (flags)
226 Syslog::warning("SessionCreate flags=0x%x unsupported (ignored)", flags);
227 CommonCriteria::AuditInfo session;
228 session.create(attributes);
229
230 // retrieve the (new) session id and set it into the process environment
231 session.get();
232 char idString[80];
233 snprintf(idString, sizeof(idString), "%x", session.sessionId());
234 setenv("SECURITYSESSIONID", idString, 1);
235
236 END_API(CSSM)
237 }
238
239
240 //
241 // Get and set the distinguished uid (optionally) associated with the session.
242 //
243 OSStatus SessionSetDistinguishedUser(SecuritySessionId session, uid_t user)
244 {
245 BEGIN_API
246 CommonCriteria::AuditInfo session;
247 session.get();
248 session.ai_auid = user;
249 session.set();
250 END_API(CSSM)
251 }
252
253
254 OSStatus SessionGetDistinguishedUser(SecuritySessionId session, uid_t *user)
255 {
256 BEGIN_API
257 CommonCriteria::AuditInfo session;
258 session.get();
259 Required(user) = session.uid();
260 END_API(CSSM)
261 }
262
263 OSStatus _SessionSetUserPreferences(SecuritySessionId session);
264
265 void SessionUserPreferencesChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
266 {
267 _SessionSetUserPreferences(uintptr_t(observer));
268 }
269
270 OSStatus _SessionSetUserPreferences(SecuritySessionId session)
271 {
272 BEGIN_API
273 CFStringRef appleLanguagesStr = CFSTR("AppleLanguages");
274 CFStringRef controlTintStr = CFSTR("AppleAquaColorVariant");
275 CFStringRef keyboardUIModeStr = CFSTR("AppleKeyboardUIMode");
276 CFStringRef textDirectionStr = CFSTR("AppleTextDirection");
277 CFStringRef hitoolboxAppIDStr = CFSTR("com.apple.HIToolbox");
278 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
279
280 CFRef<CFMutableDictionaryRef> userPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
281 CFRef<CFMutableDictionaryRef> globalPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
282
283 if (!userPrefsDict || !globalPrefsDict)
284 return errSessionValueNotSet;
285
286 CFRef<CFArrayRef> appleLanguagesArray(static_cast<CFArrayRef>(CFPreferencesCopyAppValue(appleLanguagesStr, kCFPreferencesCurrentApplication)));
287 if (appleLanguagesArray)
288 CFDictionarySetValue(globalPrefsDict, appleLanguagesStr, appleLanguagesArray);
289
290 CFRef<CFNumberRef> controlTintNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(controlTintStr, kCFPreferencesCurrentApplication)));
291 if (controlTintNumber)
292 CFDictionarySetValue(globalPrefsDict, controlTintStr, controlTintNumber);
293
294 CFRef<CFNumberRef> keyboardUIModeNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(keyboardUIModeStr, kCFPreferencesCurrentApplication)));
295 if (keyboardUIModeNumber)
296 CFDictionarySetValue(globalPrefsDict, keyboardUIModeStr, keyboardUIModeNumber);
297
298 CFRef<CFNumberRef> textDirectionNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(textDirectionStr, kCFPreferencesCurrentApplication)));
299 if (textDirectionNumber)
300 CFDictionarySetValue(globalPrefsDict, textDirectionStr, textDirectionNumber);
301
302 if (CFDictionaryGetCount(globalPrefsDict) > 0)
303 CFDictionarySetValue(userPrefsDict, kCFPreferencesAnyApplication, globalPrefsDict);
304
305 CFPreferencesSynchronize(hitoolboxAppIDStr, kCFPreferencesCurrentUser,
306 kCFPreferencesCurrentHost);
307 CFRef<CFDictionaryRef> hitoolboxPrefsDict(static_cast<CFDictionaryRef>(CFPreferencesCopyMultiple(NULL, hitoolboxAppIDStr, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)));
308 if (hitoolboxPrefsDict) {
309 CFDictionarySetValue(userPrefsDict, hitoolboxAppIDStr, hitoolboxPrefsDict);
310 CFNotificationCenterPostNotification(center, CFSTR("com.apple.securityagent.InputPrefsChanged"), CFSTR("com.apple.loginwindow"), hitoolboxPrefsDict, true);
311 }
312
313 CFRef<CFDataRef> userPrefsData(CFPropertyListCreateXMLData(NULL, userPrefsDict));
314 if (!userPrefsData)
315 return errSessionValueNotSet;
316 server().setSessionUserPrefs(session, CFDataGetLength(userPrefsData), CFDataGetBytePtr(userPrefsData));
317
318 END_API(CSSM)
319 }
320
321 OSStatus SessionSetUserPreferences(SecuritySessionId session)
322 {
323 OSStatus status = _SessionSetUserPreferences(session);
324 if (noErr == status) {
325 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
326 // We've succeeded in setting up a static set of prefs, now set up
327 CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifySelectedKeyboardInputSourceChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
328 CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifyEnabledKeyboardInputSourcesChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
329 }
330 return status;
331 }
332
333
334 //
335 // Modify Authorization rules
336 //
337
338 //
339 // AuthorizationRightGet
340 //
341 OSStatus AuthorizationRightGet(const char *rightName, CFDictionaryRef *rightDefinition)
342 {
343 BEGIN_API;
344 Required(rightName);
345 CssmDataContainer definition(server().returnAllocator);
346
347 server().authorizationdbGet(rightName, definition, server().returnAllocator);
348 // convert rightDefinition to dictionary
349
350 if (rightDefinition)
351 {
352 CFRef<CFDataRef> data(CFDataCreate(NULL, static_cast<UInt8 *>(definition.data()), definition.length()));
353 if (!data)
354 CssmError::throwMe(errAuthorizationInternal);
355
356 CFRef<CFDictionaryRef> rightDict(static_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL)));
357 if (!rightDict
358 || CFGetTypeID(rightDict) != CFDictionaryGetTypeID())
359 CssmError::throwMe(errAuthorizationInternal);
360
361 CFRetain(rightDict);
362 *rightDefinition = rightDict;
363 }
364
365 END_API(CSSM);
366 }
367
368 //
369 // AuthorizationRightSet
370 //
371 OSStatus AuthorizationRightSet(AuthorizationRef authRef,
372 const char *rightName, CFTypeRef rightDefinition,
373 CFStringRef descriptionKey, CFBundleRef bundle, CFStringRef tableName)
374 {
375 BEGIN_API;
376 Required(rightName);
377 AuthorizationBlob *auth = (AuthorizationBlob *)authRef;
378
379 CFRef<CFMutableDictionaryRef> rightDefinitionDict;
380 if (rightDefinition && (CFGetTypeID(rightDefinition) == CFStringGetTypeID()))
381 {
382 rightDefinitionDict = CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
383 if (!rightDefinitionDict)
384 CssmError::throwMe(errAuthorizationInternal);
385 CFDictionarySetValue(rightDefinitionDict, CFSTR(kAuthorizationRightRule), rightDefinition);
386 }
387 else
388 if (rightDefinition && (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()))
389 {
390 rightDefinitionDict = CFDictionaryCreateMutableCopy(NULL, 0, static_cast<CFDictionaryRef>(rightDefinition));
391 if (!rightDefinitionDict)
392 CssmError::throwMe(errAuthorizationInternal);
393 }
394 else
395 CssmError::throwMe(errAuthorizationDenied);
396
397 if (rightDefinitionDict)
398 CFRelease(rightDefinitionDict); // we just assigned things that were already retained
399
400 if (descriptionKey)
401 {
402 CFRef<CFMutableDictionaryRef> localizedDescriptions(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
403
404 if (!localizedDescriptions)
405 CssmError::throwMe(errAuthorizationInternal);
406
407 // assigning to perform a retain on either
408 CFRef<CFBundleRef> clientBundle; clientBundle = bundle ? bundle : CFBundleGetMainBundle();
409
410 // looks like a list of CFStrings: English us_en etc.
411 CFRef<CFArrayRef> localizations(CFBundleCopyBundleLocalizations(clientBundle));
412
413 if (localizations)
414 {
415 // for every CFString in localizations do
416 CFIndex locIndex, allLocs = CFArrayGetCount(localizations);
417 for (locIndex = 0; locIndex < allLocs; locIndex++)
418 {
419 CFStringRef oneLocalization = static_cast<CFStringRef>(CFArrayGetValueAtIndex(localizations, locIndex));
420
421 if (!oneLocalization)
422 continue;
423
424 // @@@ no way to get "Localized" and "strings" as constants?
425 CFRef<CFURLRef> locURL(CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization));
426
427 if (!locURL)
428 continue;
429
430 CFDataRef tableData = NULL;
431 SInt32 errCode;
432 CFStringRef errStr;
433 CFPropertyListRef stringTable;
434
435 CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode);
436
437 if (errCode)
438 {
439 if (NULL != tableData) {
440 CFRelease(tableData);
441 }
442 continue;
443 }
444
445 stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr);
446 if (errStr != NULL) {
447 CFRelease(errStr);
448 errStr = NULL;
449 }
450 CFRelease(tableData);
451
452 CFStringRef value = static_cast<CFStringRef>(CFDictionaryGetValue(static_cast<CFDictionaryRef>(stringTable), descriptionKey));
453 if (value == NULL || CFEqual(value, CFSTR(""))) {
454 CFRelease(stringTable);
455 continue;
456 } else {
457 // oneLocalization/value into our dictionary
458 CFDictionarySetValue(localizedDescriptions, oneLocalization, value);
459 CFRelease(stringTable);
460 }
461 }
462 }
463
464 // add the description as the default localization into the dictionary
465 CFDictionarySetValue(localizedDescriptions, CFSTR(""), descriptionKey);
466
467 // stuff localization table into rule definition
468 CFDictionarySetValue(rightDefinitionDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), localizedDescriptions);
469
470 }
471
472 // serialize cfdictionary with data into rightDefinitionXML
473 CFRef<CFDataRef> rightDefinitionXML(CFPropertyListCreateXMLData(NULL, rightDefinitionDict));
474
475 server().authorizationdbSet(Required(auth), rightName, CFDataGetLength(rightDefinitionXML), CFDataGetBytePtr(rightDefinitionXML));
476
477 END_API(CSSM);
478 }
479
480 //
481 // AuthorizationRightRemove
482 //
483 OSStatus AuthorizationRightRemove(AuthorizationRef authRef, const char *rightName)
484 {
485 BEGIN_API;
486 Required(rightName);
487 AuthorizationBlob *auth = (AuthorizationBlob *)authRef;
488 server().authorizationdbRemove(Required(auth), rightName);
489 END_API(CSSM);
490 }
491