/ OSX / libsecurity_keychain / lib / SecACL.cpp
SecACL.cpp
  1  /*
  2   * Copyright (c) 2002-2004,2011-2014 Apple 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  #include <Security/SecACL.h>
 25  #include <security_keychain/ACL.h>
 26  #include <security_keychain/Access.h>
 27  #include <security_keychain/SecAccessPriv.h>
 28  
 29  #include <os/activity.h>
 30  
 31  #include "SecBridge.h"
 32  
 33  #include "LegacyAPICounts.h"
 34  
 35  // Forward reference
 36  /*!
 37  	@function GetACLAuthorizationTagFromString
 38  	@abstract Get the CSSM ACL item from the CFString
 39      @param aclStr The String name of the ACL
 40  	@result The CSSM ACL value
 41  */
 42  sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr);
 43  
 44  CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag);
 45  
 46  //
 47  // Local functions
 48  //
 49  static void setApplications(ACL *acl, CFArrayRef applicationList);
 50  
 51  CFTypeID
 52  SecACLGetTypeID(void)
 53  {
 54  	BEGIN_SECAPI
 55  
 56  	return gTypes().ACL.typeID;
 57  
 58  	END_SECAPI1(_kCFRuntimeNotATypeID)
 59  }
 60  
 61  
 62  /*!
 63   */
 64  OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef,
 65  	CFArrayRef applicationList,
 66  	CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector,
 67  	SecACLRef *newAcl)
 68  {
 69  	BEGIN_SECAPI
 70      os_activity_t activity = os_activity_create("SecACLCreateFromSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 71      os_activity_scope(activity);
 72      os_release(activity);
 73  	SecPointer<Access> access = Access::required(accessRef);
 74  	SecPointer<ACL> acl = new ACL(cfString(description), *promptSelector);
 75  	if (applicationList) {
 76  		// application-list + prompt
 77  		acl->form(ACL::appListForm);
 78  		setApplications(acl, applicationList);
 79  	} else {
 80  		// allow-any
 81  		acl->form(ACL::allowAllForm);
 82  	}
 83  	access->add(acl.get());
 84  	Required(newAcl) = acl->handle();
 85  	END_SECAPI
 86  }
 87  
 88  OSStatus SecACLCreateWithSimpleContents(SecAccessRef access,
 89  										CFArrayRef applicationList,
 90  										CFStringRef description, 
 91  										SecKeychainPromptSelector promptSelector,
 92  										SecACLRef *newAcl)
 93  {
 94  	COUNTLEGACYAPI
 95  	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
 96  	cdsaPromptSelector.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
 97  	cdsaPromptSelector.flags = promptSelector;
 98  	return SecACLCreateFromSimpleContents(access, applicationList, description, &cdsaPromptSelector, newAcl);
 99  }
100  
101  
102  /*!
103   */
104  OSStatus SecACLRemove(SecACLRef aclRef)
105  {
106  	BEGIN_SECAPI
107      os_activity_t activity = os_activity_create("SecACLRemove", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
108      os_activity_scope(activity);
109      os_release(activity);
110  	ACL::required(aclRef)->remove();
111  	END_SECAPI
112  }
113  
114  
115  static SecTrustedApplicationRef
116  convert(const SecPointer<TrustedApplication> &trustedApplication)
117  {
118  	return *trustedApplication;
119  }
120  
121  /*!
122   */
123  OSStatus SecACLCopySimpleContents(SecACLRef aclRef,
124  	CFArrayRef *applicationList,
125  	CFStringRef *promptDescription, CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
126  {
127  	BEGIN_SECAPI
128  	SecPointer<ACL> acl = ACL::required(aclRef);
129  	switch (acl->form()) {
130  	case ACL::allowAllForm:
131  		Required(applicationList) = NULL;
132  		Required(promptDescription) =
133  			acl->promptDescription().empty() ? NULL
134  				: makeCFString(acl->promptDescription());
135  		Required(promptSelector) = acl->promptSelector();
136  		break;
137  	case ACL::appListForm:
138  		Required(applicationList) =
139  			makeCFArrayFrom(convert, acl->applications());
140  		Required(promptDescription) = makeCFString(acl->promptDescription());
141  		Required(promptSelector) = acl->promptSelector();
142  		break;
143      case ACL::integrityForm:
144          Required(applicationList) = NULL;
145          Required(promptDescription) = makeCFString(acl->integrity().toHex());
146  
147          // We don't have a prompt selector. Nullify.
148          Required(promptSelector).version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
149          Required(promptSelector).flags = 0;
150          break;
151  	default:
152  		return errSecACLNotSimple;		// custom or unknown
153  	}
154  	END_SECAPI
155  }
156  
157  OSStatus SecACLCopyContents(SecACLRef acl,
158  							CFArrayRef *applicationList,
159  							CFStringRef *description, 
160  							SecKeychainPromptSelector *promptSelector)
161  {
162  	COUNTLEGACYAPI
163  	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
164  	memset(&cdsaPromptSelector, 0, sizeof(cdsaPromptSelector));
165  	OSStatus err = errSecSuccess;
166  	
167  	err = SecACLCopySimpleContents(acl, applicationList, description, &cdsaPromptSelector);
168  	*promptSelector = cdsaPromptSelector.flags;
169  	return err;	
170  }
171  
172  OSStatus SecACLSetSimpleContents(SecACLRef aclRef,
173  	CFArrayRef applicationList,
174  	CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
175  {
176  	BEGIN_SECAPI
177      os_activity_t activity = os_activity_create("SecACLSetSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
178      os_activity_scope(activity);
179      os_release(activity);
180  	SecPointer<ACL> acl = ACL::required(aclRef);
181      if(acl->form() == ACL::integrityForm) {
182          // If this is an integrity ACL, route the (unhexified) promptDescription into the right place
183          string hex = cfString(description);
184          if(hex.length() %2 == 0) {
185              // might be a valid hex string, try to set
186              CssmAutoData data(Allocator::standard());
187              data.malloc(hex.length() / 2);
188              data.get().fromHex(hex.c_str());
189              acl->setIntegrity(data);
190          }
191      } else {
192          // Otherwise, put it in the promptDescription where it belongs
193          acl->promptDescription() = description ? cfString(description) : "";
194      }
195  	acl->promptSelector() = promptSelector ? *promptSelector : ACL::defaultSelector;
196      if(acl->form() !=  ACL::integrityForm) {
197          if (applicationList) {
198              // application-list + prompt
199              acl->form(ACL::appListForm);
200              setApplications(acl, applicationList);
201          } else {
202              // allow-any
203              acl->form(ACL::allowAllForm);
204          }
205  	}
206  	acl->modify();
207  	END_SECAPI
208  }
209  
210  OSStatus SecACLSetContents(SecACLRef acl,
211  						   CFArrayRef applicationList,
212  						   CFStringRef description, 
213  						   SecKeychainPromptSelector promptSelector)
214  {
215  	COUNTLEGACYAPI
216  	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
217  	cdsaPromptSelector.version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION;
218  	cdsaPromptSelector.flags = promptSelector;
219  	return SecACLSetSimpleContents(acl, applicationList, description, &cdsaPromptSelector);	
220  }
221  
222  //
223  // Stuff a CFArray-of-SecTrustedApplications into an ACL object
224  //
225  static void setApplications(ACL *acl, CFArrayRef applicationList)
226  {
227  	ACL::ApplicationList &appList = acl->applications();
228  	appList.clear();
229  	//@@@ should really use STL iterator overlay on CFArray. By hand...
230  	CFIndex count = CFArrayGetCount(applicationList);
231  	for (CFIndex n = 0; n < count; n++)
232  		appList.push_back(TrustedApplication::required(
233  			SecTrustedApplicationRef(CFArrayGetValueAtIndex(applicationList, n))));
234  }
235  
236  
237  //
238  // Set and get the authorization tags of an ACL entry
239  //
240  OSStatus SecACLGetAuthorizations(SecACLRef acl,
241  	CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 *tagCount)
242  {
243  	BEGIN_SECAPI
244  	AclAuthorizationSet auths = ACL::required(acl)->authorizations();
245  	if (Required(tagCount) < auths.size()) {	// overflow
246  		*tagCount = (uint32)auths.size();				// report size required
247  		CssmError::throwMe(errSecParam);
248  	}
249  	*tagCount = (uint32)auths.size();
250  	copy(auths.begin(), auths.end(), tags);
251  	END_SECAPI
252  }
253  
254  CFArrayRef SecACLCopyAuthorizations(SecACLRef acl)
255  {
256  	COUNTLEGACYAPI
257  	CFArrayRef result = NULL;
258  	if (NULL == acl)
259  	{
260  		return result;
261  	}
262  	
263  	AclAuthorizationSet auths = ACL::required(acl)->authorizations();
264  	uint32 numAuths = (uint32)auths.size();				
265  	
266      CSSM_ACL_AUTHORIZATION_TAG* tags = new CSSM_ACL_AUTHORIZATION_TAG[numAuths];
267      int i;
268      for (i = 0; i < numAuths; ++i)
269      {
270          tags[i] = NULL;
271      }
272  	
273  	OSStatus err = SecACLGetAuthorizations(acl, tags, &numAuths);
274  	if (errSecSuccess != err)
275  	{
276  		
277  		return result;
278  	}
279  	
280  	CFTypeRef* strings = new CFTypeRef[numAuths];
281      for (i = 0; i < numAuths; ++i)
282      {
283          strings[i] = NULL;
284      }
285      
286  	for (size_t iCnt = 0; iCnt < numAuths; iCnt++)
287  	{
288  		strings[iCnt] = (CFTypeRef)GetAuthStringFromACLAuthorizationTag(tags[iCnt]);
289  	}
290  
291  	result = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, numAuths, &kCFTypeArrayCallBacks);
292  
293  	delete[] strings;
294      delete[] tags;
295  
296  	return result;
297  	
298  }
299  
300  OSStatus SecACLSetAuthorizations(SecACLRef aclRef,
301  	CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount)
302  {
303  	BEGIN_SECAPI
304      os_activity_t activity = os_activity_create("SecACLSetAuthorizations", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
305      os_activity_scope(activity);
306      os_release(activity);
307  	SecPointer<ACL> acl = ACL::required(aclRef);
308  	if (acl->isOwner())		// can't change rights of the owner ACL
309  		MacOSError::throwMe(errSecInvalidOwnerEdit);
310  	AclAuthorizationSet &auths = acl->authorizations();
311  	auths.clear();
312  	copy(tags, tags + tagCount, insert_iterator<AclAuthorizationSet>(auths, auths.begin()));
313  	acl->modify();
314  	END_SECAPI
315  }
316  
317  OSStatus SecACLUpdateAuthorizations(SecACLRef acl, CFArrayRef authorizations)
318  {
319  	COUNTLEGACYAPI
320  	if (NULL == acl || NULL == authorizations)
321  	{
322  		return errSecParam;
323  	}
324  	uint32 tagCount = (uint32)CFArrayGetCount(authorizations);
325  	
326  	size_t tagSize = (tagCount * sizeof(CSSM_ACL_AUTHORIZATION_TAG));
327  	
328  	CSSM_ACL_AUTHORIZATION_TAG* tags = (CSSM_ACL_AUTHORIZATION_TAG*)malloc(tagSize);
329  	memset(tags, 0, tagSize);
330  	for (uint32 iCnt = 0; iCnt < tagCount; iCnt++)
331  	{
332  		tags[iCnt] = GetACLAuthorizationTagFromString((CFStringRef)CFArrayGetValueAtIndex(authorizations, iCnt));
333  	}
334  	
335  	OSStatus result = SecACLSetAuthorizations(acl, tags, tagCount);
336  	free(tags);
337  	return result;
338  }