/ OSX / libsecurity_keychain / lib / SecKeychain.cpp
SecKeychain.cpp
   1  /*
   2   * Copyright (c) 2000-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/SecKeychain.h>
  25  #include <Security/SecKeychainPriv.h>
  26  #include <security_keychain/KCCursor.h>
  27  #include <security_cdsa_utilities/cssmdata.h>
  28  #include <security_cdsa_client/wrapkey.h>
  29  #include <security_keychain/KCExceptions.h>
  30  #include <securityd_client/ssblob.h>
  31  #include <Security/SecAccess.h>
  32  #include <Security/SecTrustedApplicationPriv.h>
  33  #include "SecBridge.h"
  34  #include "CCallbackMgr.h"
  35  #include <security_cdsa_utilities/Schema.h>
  36  #include <security_cdsa_client/mdsclient.h>
  37  #include <pwd.h>
  38  #include <os/activity.h>
  39  #include <Security/AuthorizationTagsPriv.h>
  40  #include <Security/Authorization.h>
  41  #include "TokenLogin.h"
  42  #include "LegacyAPICounts.h"
  43  
  44  extern "C" {
  45  #include "ctkloginhelper.h"
  46  }
  47  
  48  OSStatus
  49  SecKeychainMDSInstall()
  50  {
  51      BEGIN_SECAPI
  52  
  53  	   os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
  54      os_activity_scope(activity);
  55      os_release(activity);
  56  
  57  	Security::MDSClient::Directory d;
  58  	d.install();
  59  
  60  	END_SECAPI
  61  }
  62  
  63  CFTypeID
  64  SecKeychainGetTypeID(void)
  65  {
  66  	BEGIN_SECAPI
  67  
  68  	return gTypes().KeychainImpl.typeID;
  69  
  70  	END_SECAPI1(_kCFRuntimeNotATypeID)
  71  }
  72  
  73  
  74  OSStatus
  75  SecKeychainGetVersion(UInt32 *returnVers)
  76  {
  77      COUNTLEGACYAPI
  78      if (!returnVers)
  79  		return errSecSuccess;
  80  
  81  	*returnVers = 0x02028000;
  82  	return errSecSuccess;
  83  }
  84  
  85  
  86  OSStatus
  87  SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef)
  88  {
  89      BEGIN_SECAPI
  90  
  91  	   os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
  92      os_activity_scope(activity);
  93      os_release(activity);
  94  
  95  	RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle();
  96  
  97  	END_SECAPI
  98  }
  99  
 100  OSStatus
 101  SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password,
 102  	Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef)
 103  {
 104      BEGIN_SECAPI
 105  
 106  	   os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 107      os_activity_scope(activity);
 108      os_release(activity);
 109      
 110      KCThrowParamErrIf_(!pathName);
 111  	Keychain keychain = globals().storageManager.make(pathName, true, true);
 112  
 113  	// @@@ the call to StorageManager::make above leaves keychain the the cache.
 114  	// If the create below fails we should probably remove it.
 115  	if(promptUser)
 116  		keychain->create();
 117  	else
 118  	{
 119  		KCThrowParamErrIf_(!password);
 120  		keychain->create(passwordLength, password);
 121  	}
 122  
 123  	RequiredParam(keychainRef)=keychain->handle();
 124  
 125  	END_SECAPI
 126  }
 127  
 128  
 129  OSStatus
 130  SecKeychainDelete(SecKeychainRef keychainOrArray)
 131  {
 132      BEGIN_SECAPI
 133  
 134  	   os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 135      os_activity_scope(activity);
 136      os_release(activity);
 137  
 138  	KCThrowIf_(!keychainOrArray, errSecInvalidKeychain);
 139  	StorageManager::KeychainList keychains;
 140  	globals().storageManager.optionalSearchList(keychainOrArray, keychains);
 141  
 142  	globals().storageManager.remove(keychains, true);
 143  
 144  	END_SECAPI
 145  }
 146  
 147  
 148  OSStatus
 149  SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings)
 150  {
 151      BEGIN_SECAPI
 152  
 153  	   os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 154      os_activity_scope(activity);
 155      os_release(activity);
 156  
 157  	Keychain keychain = Keychain::optional(keychainRef);
 158  	if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
 159  	{
 160  		UInt32 lockInterval=newSettings->lockInterval;
 161  		bool lockOnSleep=newSettings->lockOnSleep;
 162  		keychain->setSettings(lockInterval, lockOnSleep);
 163  	}
 164  
 165  	END_SECAPI
 166  }
 167  
 168  
 169  OSStatus
 170  SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings)
 171  {
 172      BEGIN_SECAPI
 173  
 174  	   os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 175      os_activity_scope(activity);
 176      os_release(activity);
 177  
 178  	Keychain keychain = Keychain::optional(keychainRef);
 179  	if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
 180  	{
 181  		uint32 lockInterval;
 182  		bool lockOnSleep;
 183  		
 184  		keychain->getSettings(lockInterval, lockOnSleep);
 185  		outSettings->lockInterval=lockInterval;
 186  		outSettings->lockOnSleep=lockOnSleep;
 187  	}
 188  
 189  	END_SECAPI
 190  }
 191  
 192  
 193  OSStatus
 194  SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword)
 195  {
 196  	BEGIN_SECAPI
 197  
 198  	   os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 199      os_activity_scope(activity);
 200      os_release(activity);
 201  
 202  	Keychain keychain = Keychain::optional(keychainRef);
 203  
 204  	if (usePassword)
 205  		keychain->unlock(CssmData(const_cast<void *>(password), passwordLength));
 206  	else
 207  		keychain->unlock();
 208  
 209  	END_SECAPI
 210  }
 211  
 212  
 213  OSStatus
 214  SecKeychainLock(SecKeychainRef	keychainRef)
 215  {
 216  	BEGIN_SECAPI
 217  
 218  	   os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 219      os_activity_scope(activity);
 220      os_release(activity);
 221  
 222  	Keychain keychain = Keychain::optional(keychainRef);
 223  	keychain->lock();
 224  
 225  	END_SECAPI
 226  }
 227  
 228  
 229  OSStatus
 230  SecKeychainLockAll(void)
 231  {
 232  	BEGIN_SECAPI
 233  
 234  	   os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 235      os_activity_scope(activity);
 236      os_release(activity);
 237  
 238  	globals().storageManager.lockAll();
 239  
 240  	END_SECAPI
 241  }
 242  
 243  
 244  OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList)
 245  {
 246  	BEGIN_SECAPI
 247  
 248  	   os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 249      os_activity_scope(activity);
 250      os_release(activity);
 251          //
 252          // Get the current user (using fallback method if necessary)
 253          //
 254          char* uName = getenv("USER");
 255          string userName = uName ? uName : "";
 256          if ( userName.length() == 0 )
 257          {
 258              uid_t uid = geteuid();
 259              if (!uid) uid = getuid();
 260              struct passwd *pw = getpwuid(uid);	// fallback case...
 261              if (pw)
 262                  userName = pw->pw_name;
 263              endpwent();
 264          }
 265          if ( userName.length() == 0 )	// did we ultimately get one?
 266          {
 267              MacOSError::throwMe(errAuthorizationInternal);
 268          }
 269  
 270          SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData());
 271          secwarning("SecKeychainResetLogin: reset AKS passphrase");
 272  		if (password)
 273  		{
 274  			// Clear the plist and move aside (rename) the existing login.keychain
 275  			globals().storageManager.resetKeychain(resetSearchList);
 276  
 277  			// Create the login keychain without UI
 278  			globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true);
 279  			
 280  			// Set it as the default
 281  			Keychain keychain = globals().storageManager.loginKeychain();
 282  			globals().storageManager.defaultKeychain(keychain);
 283  		}
 284  		else
 285  		{
 286  			// Create the login keychain, prompting for password
 287  			// (implicitly calls resetKeychain, login, and defaultKeychain)
 288  			globals().storageManager.makeLoginAuthUI(NULL, true);
 289  		}
 290          secwarning("SecKeychainResetLogin: reset osx keychain");
 291  
 292  		// Post a "list changed" event after a reset, so apps can refresh their list.
 293  		// Make sure we are not holding mLock when we post this event.
 294  		KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
 295  
 296  
 297  	END_SECAPI
 298  }
 299  
 300  OSStatus
 301  SecKeychainCopyDefault(SecKeychainRef *keychainRef)
 302  {
 303  	BEGIN_SECAPI
 304  
 305  	RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle();
 306  
 307  	END_SECAPI
 308  }
 309  
 310  
 311  OSStatus
 312  SecKeychainSetDefault(SecKeychainRef keychainRef)
 313  {
 314  	BEGIN_SECAPI
 315  
 316  	   os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 317      os_activity_scope(activity);
 318      os_release(activity);
 319  
 320  	globals().storageManager.defaultKeychain(Keychain::optional(keychainRef));
 321  
 322  	END_SECAPI
 323  }
 324  
 325  OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
 326  {
 327  	BEGIN_SECAPI
 328  
 329  	   os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 330      os_activity_scope(activity);
 331      os_release(activity);
 332  
 333  	RequiredParam(searchList);
 334  	StorageManager &smr = globals().storageManager;
 335  	StorageManager::KeychainList keychainList;
 336  	smr.getSearchList(keychainList);
 337  	*searchList = smr.convertFromKeychainList(keychainList);
 338  
 339  	END_SECAPI
 340  }
 341  
 342  OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
 343  {
 344  	BEGIN_SECAPI
 345  
 346  	   os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 347      os_activity_scope(activity);
 348      os_release(activity);
 349  
 350  	RequiredParam(searchList);
 351  	StorageManager &smr = globals().storageManager;
 352  	StorageManager::KeychainList keychainList;
 353  	smr.convertToKeychainList(searchList, keychainList);
 354  	smr.setSearchList(keychainList);
 355  
 356  	END_SECAPI
 357  }
 358  
 359  OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef)
 360  {
 361  	BEGIN_SECAPI
 362  
 363  	   os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 364      os_activity_scope(activity);
 365      os_release(activity);
 366  
 367  	RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle();
 368  
 369  	END_SECAPI
 370  }
 371  
 372  OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef)
 373  {
 374  	BEGIN_SECAPI
 375  
 376  	   os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 377      os_activity_scope(activity);
 378      os_release(activity);
 379  
 380  	globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef));
 381  
 382  	END_SECAPI
 383  }
 384  
 385  OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList)
 386  {
 387  	BEGIN_SECAPI
 388  
 389  	RequiredParam(searchList);
 390  	StorageManager &smr = globals().storageManager;
 391  	StorageManager::KeychainList keychainList;
 392  	smr.getSearchList(domain, keychainList);
 393  	*searchList = smr.convertFromKeychainList(keychainList);
 394  
 395  	END_SECAPI
 396  }
 397  
 398  OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList)
 399  {
 400  	BEGIN_SECAPI
 401  
 402  	   os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 403      os_activity_scope(activity);
 404      os_release(activity);
 405  
 406  	RequiredParam(searchList);
 407  	StorageManager &smr = globals().storageManager;
 408  	StorageManager::KeychainList keychainList;
 409  	smr.convertToKeychainList(searchList, keychainList);
 410  	smr.setSearchList(domain, keychainList);
 411  
 412  	END_SECAPI
 413  }
 414  
 415  OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
 416  {
 417  	BEGIN_SECAPI
 418  
 419  	   os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 420      os_activity_scope(activity);
 421      os_release(activity);
 422  
 423  	globals().storageManager.domain(domain);
 424  
 425  	END_SECAPI
 426  }
 427  
 428  OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain)
 429  {
 430  	BEGIN_SECAPI
 431  
 432  	   os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 433      os_activity_scope(activity);
 434      os_release(activity);
 435  	
 436  	*domain = globals().storageManager.domain();
 437  	
 438  	END_SECAPI
 439  }
 440  
 441  
 442  OSStatus
 443  SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus)
 444  {
 445      BEGIN_SECAPI
 446  
 447  	RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status();
 448  
 449  	END_SECAPI
 450  }
 451  
 452  
 453  OSStatus
 454  SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName)
 455  {
 456      BEGIN_SECAPI
 457  
 458  	RequiredParam(pathName);
 459  	RequiredParam(ioPathLength);
 460  
 461      const char *name = Keychain::optional(keychainRef)->name();
 462  	UInt32 nameLen = (UInt32)strlen(name);
 463  	UInt32 callersLen = *ioPathLength;
 464  	*ioPathLength = nameLen;
 465  	if (nameLen+1 > callersLen)  // if the client's buffer is too small (including null-termination), throw
 466  		return errSecBufferTooSmall;
 467  	strncpy(pathName, name, nameLen);
 468      pathName[nameLen] = 0;
 469  	*ioPathLength = nameLen;   // set the length.
 470      		
 471  	END_SECAPI
 472  }
 473  
 474  OSStatus
 475  SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version)
 476  {
 477      BEGIN_SECAPI
 478  
 479  	   RequiredParam(version);
 480  
 481      *version = Keychain::optional(keychainRef)->database()->dbBlobVersion();
 482  
 483      END_SECAPI
 484  }
 485  
 486  OSStatus
 487  SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename)
 488  {
 489      BEGIN_SECAPI
 490  
 491  	   os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 492      os_activity_scope(activity);
 493      os_release(activity);
 494  
 495      RequiredParam(masterKeyFilename);
 496      Keychain kc = Keychain::optional(keychain);
 497  
 498      SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename);
 499      if(keychainKey.valid()) {
 500          // We've managed to read the key; now, create credentials using it
 501          string path = kc->name();
 502  
 503          CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true);
 504          CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive));
 505  
 506          // Attempt the migrate, using our master key as the ACL override
 507          bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials());
 508          if(!result) {
 509              return errSecBadReq;
 510          }
 511          return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq);
 512      } else {
 513          return errSecBadReq;
 514      }
 515  
 516      END_SECAPI
 517  }
 518  
 519  
 520  // @@@ Deprecated
 521  UInt16
 522  SecKeychainListGetCount(void)
 523  {
 524      BEGIN_SECAPI
 525  
 526  	return globals().storageManager.size();
 527  
 528  	END_SECAPI1(0)
 529  }
 530  
 531  
 532  // @@@ Deprecated
 533  OSStatus
 534  SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef)
 535  {
 536      BEGIN_SECAPI
 537  
 538  	KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager;
 539  	RequiredParam(keychainRef)=smgr[index]->handle();
 540  
 541  	END_SECAPI
 542  }
 543  
 544  
 545  // @@@ Deprecated
 546  OSStatus
 547  SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef)
 548  {
 549      BEGIN_SECAPI
 550  
 551  	Required(keychainRef);
 552  	Keychain keychain = Keychain::optional(*keychainRef);
 553  	StorageManager::KeychainList keychainList;
 554  	keychainList.push_back(keychain);
 555  	globals().storageManager.remove(keychainList);
 556  	*keychainRef = NULL;
 557  
 558  	END_SECAPI
 559  }
 560  
 561  
 562  OSStatus
 563  SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info)
 564  {
 565  	BEGIN_SECAPI
 566  
 567  	Keychain keychain = Keychain::optional(keychainRef);
 568  	keychain->getAttributeInfoForItemID(itemID, info);
 569  
 570  	END_SECAPI
 571  }
 572  
 573  
 574  OSStatus
 575  SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info)
 576  {
 577  	BEGIN_SECAPI
 578  
 579  	KeychainImpl::freeAttributeInfo(info);
 580  
 581  	END_SECAPI
 582  }
 583  
 584  
 585  pascal OSStatus
 586  SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext)
 587  {
 588      BEGIN_SECAPI
 589  
 590  	   os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 591      os_activity_scope(activity);
 592      os_release(activity);
 593  
 594  	RequiredParam(callbackFunction);
 595  	CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext);
 596  
 597  	END_SECAPI
 598  }	
 599  
 600  
 601  OSStatus
 602  SecKeychainRemoveCallback(SecKeychainCallback callbackFunction)
 603  {
 604      BEGIN_SECAPI
 605  
 606  	   os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 607      os_activity_scope(activity);
 608      os_release(activity);
 609  
 610  	RequiredParam(callbackFunction);
 611  	CCallbackMgr::RemoveCallback(callbackFunction);
 612  
 613  	END_SECAPI
 614  }	
 615  
 616  OSStatus
 617  SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 618  {
 619      BEGIN_SECAPI
 620  
 621  	   os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 622      os_activity_scope(activity);
 623      os_release(activity);
 624  
 625  	KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
 626  	// @@@ Get real itemClass
 627  	Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false);
 628  	
 629  	if (serverName && serverNameLength)
 630  	{
 631  		CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength);
 632  		item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server);
 633  		// use server name as default label
 634  		item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server);
 635  	}
 636  		
 637  	if (accountName && accountNameLength)
 638  	{
 639  		CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
 640  		item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
 641  	}
 642  
 643  	if (securityDomain && securityDomainLength)
 644  		item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr),
 645  			CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength));
 646  		
 647  	item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port));
 648  	item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol);
 649  	item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType);
 650  		
 651  	if (path && pathLength)
 652  		item->setAttribute(Schema::attributeInfo(kSecPathItemAttr),
 653  			CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength));
 654  
 655  	Keychain keychain = nil;
 656  	try
 657      {
 658          keychain = Keychain::optional(keychainRef);
 659          if ( !keychain->exists() )
 660          {
 661              MacOSError::throwMe(errSecNoSuchKeychain);	// Might be deleted or not available at this time.
 662          }
 663      }
 664      catch(...)
 665      {
 666          keychain = globals().storageManager.defaultKeychainUI(item);
 667      }
 668  
 669      keychain->add(item);
 670  
 671      if (itemRef)
 672  		*itemRef = item->handle();
 673  
 674      END_SECAPI
 675  }
 676  
 677  
 678  OSStatus
 679  SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef)
 680  												
 681  {
 682      BEGIN_SECAPI
 683  
 684  	   os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 685      os_activity_scope(activity);
 686      os_release(activity);
 687  
 688  	StorageManager::KeychainList keychains;
 689  	globals().storageManager.optionalSearchList(keychainOrArray, keychains);
 690  	KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL);
 691  
 692  	if (serverName && serverNameLength)
 693  	{
 694  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr),
 695  			CssmData(const_cast<char *>(serverName), serverNameLength));
 696  	}
 697  
 698  	if (securityDomain && securityDomainLength)
 699  	{
 700  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr),
 701  			CssmData (const_cast<char*>(securityDomain), securityDomainLength));
 702  	}
 703  
 704  	if (accountName && accountNameLength)
 705  	{
 706  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
 707  			CssmData (const_cast<char*>(accountName), accountNameLength));
 708  	}
 709  
 710  	if (port)
 711  	{
 712  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr),
 713  			UInt32(port));
 714  	}
 715  
 716  	if (protocol)
 717  	{
 718  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr),
 719  			protocol);
 720  	}
 721  
 722  	if (authenticationType)
 723  	{
 724  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr),
 725  			authenticationType);
 726  	}
 727  
 728  	if (path  && pathLength)
 729  	{
 730  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path);
 731  	}
 732  
 733  	Item item;
 734  	if (!cursor->next(item))
 735  		return errSecItemNotFound;
 736  
 737  	// Get its data (only if necessary)
 738  	if (passwordData || passwordLength)
 739  	{
 740  		CssmDataContainer outData;
 741  		item->getData(outData);
 742  		if (passwordLength) {
 743  			*passwordLength=(UInt32)outData.length();
 744  		}
 745  		outData.Length=0;
 746  		if (passwordData) {
 747  			*passwordData=outData.data();
 748  		}
 749  		outData.Data=NULL;
 750  	}
 751  
 752  	if (itemRef)
 753  		*itemRef=item->handle();
 754  
 755      END_SECAPI
 756  }
 757  
 758  
 759  OSStatus
 760  SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 761  {
 762  	BEGIN_SECAPI
 763  
 764  	   os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 765      os_activity_scope(activity);
 766      os_release(activity);
 767  
 768  	KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
 769  	// @@@ Get real itemClass
 770  
 771  	Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false);
 772  
 773  	if (serviceName && serviceNameLength)
 774  	{
 775  		CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength);
 776  		item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
 777          item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
 778  	}
 779  
 780  	if (accountName && accountNameLength)
 781  	{
 782  		CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
 783  		item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
 784  	}
 785  
 786  	Keychain keychain = nil;
 787  	try
 788      {
 789          keychain = Keychain::optional(keychainRef);
 790          if ( !keychain->exists() )
 791          {
 792              MacOSError::throwMe(errSecNoSuchKeychain);	// Might be deleted or not available at this time.
 793          }
 794      }
 795      catch(...)
 796      {
 797          keychain = globals().storageManager.defaultKeychainUI(item);
 798      }
 799  
 800  	keychain->add(item);
 801  	if (itemRef)
 802  		*itemRef = item->handle();
 803  
 804      END_SECAPI
 805  }
 806  
 807  
 808  OSStatus
 809  SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef)
 810  																			   
 811  {
 812      BEGIN_SECAPI
 813  
 814  	   os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 815      os_activity_scope(activity);
 816      os_release(activity);
 817  
 818  	StorageManager::KeychainList keychains;
 819  	globals().storageManager.optionalSearchList(keychainOrArray, keychains);
 820  	KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
 821  
 822  	if (serviceName && serviceNameLength)
 823  	{
 824  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr),
 825  			CssmData(const_cast<char *>(serviceName), serviceNameLength));
 826  	}
 827  
 828  	if (accountName && accountNameLength)
 829  	{
 830  		cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
 831  			CssmData(const_cast<char *>(accountName), accountNameLength));
 832  	}
 833  
 834  	Item item;
 835  	if (!cursor->next(item))
 836  		return errSecItemNotFound;
 837  
 838  	// Get its data (only if necessary)
 839  	if (passwordData || passwordLength)
 840  	{
 841  		CssmDataContainer outData;
 842  		item->getData(outData);
 843  		if (passwordLength) {
 844  			*passwordLength=(UInt32)outData.length();
 845  		}
 846  		outData.Length=0;
 847  		if (passwordData) {
 848  			*passwordData=outData.data();
 849  		}
 850  		outData.Data=NULL;
 851  	}
 852  
 853  	if (itemRef)
 854  		*itemRef=item->handle();
 855  
 856  	END_SECAPI
 857  }
 858  
 859  
 860  OSStatus
 861  SecKeychainSetUserInteractionAllowed(Boolean state) 
 862  {
 863  	BEGIN_SECAPI
 864  
 865  	globals().setUserInteractionAllowed(state);
 866  
 867      END_SECAPI
 868  }
 869  
 870  
 871  OSStatus
 872  SecKeychainGetUserInteractionAllowed(Boolean *state) 
 873  {
 874  	BEGIN_SECAPI
 875  
 876  	Required(state)=globals().getUserInteractionAllowed();
 877  
 878      END_SECAPI
 879  }
 880  
 881  
 882  OSStatus
 883  SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle)
 884  {
 885      BEGIN_SECAPI
 886  
 887  	   os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 888      os_activity_scope(activity);
 889      os_release(activity);
 890  
 891  	RequiredParam(dldbHandle);
 892  	
 893  	Keychain keychain = Keychain::optional(keychainRef);
 894  	*dldbHandle = keychain->database()->handle();
 895  
 896      END_SECAPI
 897  }
 898  
 899  static ModuleNexus<Mutex> gSecReturnedKeychainCSPsMutex;
 900  static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeychainCSPs;
 901  
 902  OSStatus
 903  SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle)
 904  {
 905      BEGIN_SECAPI
 906  
 907  	RequiredParam(cspHandle);
 908  
 909  	Keychain keychain = Keychain::optional(keychainRef);
 910  
 911      // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
 912      // Keep a global pointer to it to force the CSP to stay live forever.
 913      CssmClient::CSP returnedKeychainCSP = keychain->csp();
 914      {
 915          StLock<Mutex> _(gSecReturnedKeychainCSPsMutex());
 916          gSecReturnedKeychainCSPs().insert(returnedKeychainCSP);
 917      }
 918  	*cspHandle = returnedKeychainCSP->handle();
 919  
 920  	END_SECAPI
 921  }
 922  
 923  
 924  OSStatus
 925  SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef)
 926  {
 927  	BEGIN_SECAPI
 928  
 929  	MacOSError::throwMe(errSecUnimplemented);//%%%for now
 930  
 931  	END_SECAPI
 932  }
 933  
 934  
 935  OSStatus
 936  SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef)
 937  {
 938  	BEGIN_SECAPI
 939  
 940  	MacOSError::throwMe(errSecUnimplemented);//%%%for now
 941  
 942  	END_SECAPI
 943  }
 944  
 945  
 946  #pragma mark ---- Private API ----
 947  
 948  
 949  OSStatus
 950  SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword,  UInt32 newPasswordLength, const void *newPassword)
 951  {
 952      BEGIN_SECAPI
 953  
 954  	   os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 955      os_activity_scope(activity);
 956      os_release(activity);
 957  
 958  	Keychain keychain = Keychain::optional(keychainRef);
 959          keychain->changePassphrase (oldPasswordLength, oldPassword,  newPasswordLength, newPassword);
 960  
 961      END_SECAPI
 962  }
 963  
 964  
 965  OSStatus
 966  SecKeychainCopyLogin(SecKeychainRef *keychainRef)
 967  {
 968      BEGIN_SECAPI
 969  
 970  	   os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 971      os_activity_scope(activity);
 972      os_release(activity);
 973  
 974  	RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle();
 975  
 976      END_SECAPI
 977  }
 978  
 979  
 980  OSStatus
 981  SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password)
 982  {
 983      BEGIN_SECAPI
 984  
 985  	   os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
 986      os_activity_scope(activity);
 987      os_release(activity);
 988  
 989  	try
 990  	{
 991  		if (password) {
 992              globals().storageManager.login(nameLength, name,  passwordLength, password, false);
 993          } else {
 994              globals().storageManager.stashLogin();
 995          }
 996  	}
 997  	catch (CommonError &e)
 998  	{
 999          secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not");
1000  		if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
1001  		{
1002  			return errSecAuthFailed;
1003  		}
1004  		else
1005  		{
1006  			return e.osStatus();
1007  		}
1008  	}
1009  
1010      catch (...) {
1011          __secapiresult=errSecInternalComponent;
1012      }
1013      secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not");
1014  
1015      END_SECAPI
1016  }
1017  
1018  OSStatus SecKeychainStash()
1019  {
1020      BEGIN_SECAPI
1021  
1022  	   os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1023      os_activity_scope(activity);
1024      os_release(activity);
1025      
1026  	try
1027  	{
1028  		globals().storageManager.stashKeychain();
1029  	}
1030  	catch (CommonError &e)
1031  	{
1032  		if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
1033  		{
1034  			return errSecAuthFailed;
1035  		}
1036  		else
1037  		{
1038  			return e.osStatus();
1039  		}
1040  	}
1041  	
1042      END_SECAPI
1043  }
1044  
1045  OSStatus
1046  SecKeychainLogout()
1047  {
1048      BEGIN_SECAPI
1049  
1050  	   os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1051      os_activity_scope(activity);
1052      os_release(activity);
1053  
1054  	globals().storageManager.logout();
1055  
1056      END_SECAPI
1057  }
1058  
1059  /* (non-exported C utility routine) 'Makes' a keychain based on a full path
1060  */
1061  static Keychain make(const char *name)
1062  {
1063  	return globals().storageManager.make(name);
1064  }
1065  
1066  /*  'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs.
1067      Note this version doesn't take an accessRef or password.
1068      The "KC" create API takes a keychainRef...
1069  */
1070  OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef)
1071  {
1072      BEGIN_SECAPI
1073  
1074  	RequiredParam(fullPathName);
1075          RequiredParam(keychainRef)=make(fullPathName)->handle();
1076  	END_SECAPI
1077  }
1078  
1079  
1080  /* Determines if the keychainRef is a valid keychain.
1081  */
1082  OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
1083  {
1084      BEGIN_SECAPI
1085  
1086  	*isValid = false;
1087          if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL)
1088              *isValid = true;
1089  	END_SECAPI
1090  }
1091  
1092  /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs.
1093  */
1094  OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
1095  {
1096      BEGIN_SECAPI
1097  
1098  	   os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1099      os_activity_scope(activity);
1100      os_release(activity);
1101          StorageManager::KeychainList singleton;
1102          singleton.push_back(KeychainImpl::required(keychainRef));
1103          globals().storageManager.remove(singleton);
1104  	END_SECAPI
1105  }
1106  
1107  /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs.
1108  */
1109  OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
1110  {
1111      BEGIN_SECAPI
1112  
1113  	   os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1114      os_activity_scope(activity);
1115      os_release(activity);
1116          RequiredParam(inPassword);
1117          KeychainImpl::required(keychainRef)->create(passwordLength, inPassword);
1118  	END_SECAPI
1119  }
1120  
1121  /* Modify a keychain so that it can be synchronized.
1122  */
1123  OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
1124  {
1125  	BEGIN_SECAPI
1126  
1127  	   os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1128      os_activity_scope(activity);
1129      os_release(activity);
1130  
1131  	// do error checking for required parameters
1132  	RequiredParam(dbBlobArray);
1133  	RequiredParam(extraData);
1134  
1135  	const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)),
1136  		CFDataGetLength(extraData));
1137  
1138  	CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray);
1139  	size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle));
1140  	void *dataPtr = (void*)malloc(space);
1141  	if ( !dataPtr )
1142  		return errSecAllocate;
1143  	//
1144  	// Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with.
1145  	//
1146  	uint8* sizePtr = (uint8*)dataPtr;
1147  	*sizePtr = dbBlobArrayCount;
1148  	SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1149  	CFIndex index;
1150  	SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
1151  	for (index=0; index < dbBlobArrayCount; index++)
1152  	{
1153  		CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index);
1154  		const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData));
1155  		//
1156  		// Since it's to a DbHandle that's not on our disk (it came from user's iDisk),
1157  		// it's OK to use the mIdentifier and access credentials of the keychain we're recoding.
1158  		//
1159  		Keychain kc = KeychainImpl::required(keychainRef);
1160  		*currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */
1161  		
1162  		currDbHandle++;
1163  	}
1164  	// do the work
1165  	Keychain keychain = Keychain::optional(keychainRef);
1166  	const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space);
1167  	Boolean recodeFailed = false;
1168  	
1169  	int errCode=errSecSuccess;
1170  	
1171  	try
1172      {
1173  		keychain->recode(data, extraCssmData);
1174  	}
1175  	catch (MacOSError e)
1176  	{
1177  		errCode = e.osStatus();
1178  		recodeFailed = true;
1179  	}
1180  	catch (UnixError ue)
1181  	{
1182  		errCode = ue.unixError();
1183  	}
1184  	
1185  	currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1186  	for (index=0; index < dbBlobArrayCount; index++)
1187  	{
1188  		ss.releaseDb(*currDbHandle);
1189  		currDbHandle++;
1190  	}
1191  	if ( dataPtr )
1192  		free(dataPtr);
1193  	
1194  	if ( recodeFailed )
1195  	{
1196  		return errCode;
1197  	}
1198  	
1199  	END_SECAPI
1200  }
1201  
1202  OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) 
1203  {
1204  	BEGIN_SECAPI
1205  
1206  	   os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1207      os_activity_scope(activity);
1208      os_release(activity);
1209  
1210  	// do error checking for required parameters
1211  	RequiredParam(keychainSignature);
1212  
1213  	// make a keychain object "wrapper" for this keychain ref
1214  	Keychain keychain = Keychain::optional(keychainRef);
1215  	CssmAutoData data(keychain->database()->allocator());
1216  	keychain->copyBlob(data.get());
1217  
1218  	// get the cssmDBBlob
1219  	const SecurityServer::DbBlob *cssmDBBlob =
1220  		data.get().interpretedAs<const SecurityServer::DbBlob>();
1221  
1222  	// convert from CDSA standards to CF standards
1223  	*keychainSignature = CFDataCreate(kCFAllocatorDefault,
1224  		cssmDBBlob->randomSignature.bytes,
1225  		sizeof(SecurityServer::DbBlob::Signature));
1226  
1227  	END_SECAPI
1228  }
1229  
1230  OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
1231  {
1232  	BEGIN_SECAPI
1233  
1234  	   os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1235      os_activity_scope(activity);
1236      os_release(activity);
1237  
1238  	// do error checking for required parameters
1239  	RequiredParam(dbBlob);
1240  
1241  	// make a keychain object "wrapper" for this keychain ref
1242  	Keychain keychain = Keychain::optional(keychainRef);
1243  	CssmAutoData data(keychain->database()->allocator());
1244  	keychain->copyBlob(data.get());
1245  
1246  	// convert from CDSA standards to CF standards
1247  	*dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length());
1248  
1249  	END_SECAPI
1250  }
1251  
1252  // make a new keychain with pre-existing secrets
1253  OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
1254  {
1255  	BEGIN_SECAPI
1256  
1257  	   os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1258      os_activity_scope(activity);
1259      os_release(activity);
1260  	
1261  	KCThrowParamErrIf_(!fullPathName);
1262  	KCThrowParamErrIf_(!dbBlob);
1263  	
1264  	Keychain keychain = globals().storageManager.make(fullPathName);
1265  
1266  	CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob));
1267  
1268  	// @@@ the call to StorageManager::make above leaves keychain the the cache.
1269  	// If the create below fails we should probably remove it.
1270  	keychain->createWithBlob(blob);
1271  
1272  	RequiredParam(kcRef)=keychain->handle();
1273  
1274  	//
1275  
1276  	END_SECAPI
1277  }
1278  
1279  // add a non-file based DB to the keychain list
1280  OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName,
1281  										 const CSSM_GUID *guid, uint32 subServiceType)
1282  {
1283  	BEGIN_SECAPI
1284  
1285  	   os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1286      os_activity_scope(activity);
1287      os_release(activity);
1288  
1289  	RequiredParam(dbName);
1290  	StorageManager &smr = globals().storageManager;
1291  	smr.addToDomainList(domain, dbName, *guid, subServiceType);
1292  
1293  	END_SECAPI
1294  }
1295  
1296  // determine if a non-file based DB is in the keychain list
1297  OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName,
1298  										const CSSM_GUID *guid, uint32 subServiceType)
1299  {
1300  	BEGIN_SECAPI
1301  
1302  	   RequiredParam(dbName);
1303  	StorageManager &smr = globals().storageManager;
1304  	smr.isInDomainList(domain, dbName, *guid, subServiceType);
1305  	END_SECAPI
1306  }
1307  
1308  // remove a non-file based DB from the keychain list
1309  OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName,
1310  											  const CSSM_GUID *guid, uint32 subServiceType)
1311  {
1312  	BEGIN_SECAPI
1313  
1314  	   os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1315      os_activity_scope(activity);
1316      os_release(activity);
1317  	RequiredParam(dbName);
1318  	StorageManager &smr = globals().storageManager;
1319  	smr.removeFromDomainList(domain, dbName, *guid, subServiceType);
1320  	END_SECAPI
1321  }
1322  
1323  
1324  // set server mode -- must be called before any other Sec* etc. call
1325  void SecKeychainSetServerMode()
1326  {
1327  	gServerMode = true;
1328  }
1329  
1330  
1331  
1332  OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
1333  {
1334  	BEGIN_SECAPI
1335  
1336  	   os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1337      os_activity_scope(activity);
1338      os_release(activity);
1339  	RequiredParam(kcRef);
1340  	Keychain keychain = Keychain::optional(kcRef);
1341  	keychain->setBatchMode(mode, rollback);
1342  	END_SECAPI
1343  }
1344  
1345  
1346  
1347  OSStatus SecKeychainCleanupHandles()
1348  {
1349  	BEGIN_SECAPI
1350  
1351  	   END_SECAPI // which causes the handle cache cleanup routine to run
1352  }
1353  
1354  OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
1355  {
1356      BEGIN_SECAPI
1357  
1358  	   os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1359      os_activity_scope(activity);
1360      os_release(activity);
1361      SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
1362      END_SECAPI
1363  }
1364  
1365  OSStatus SecKeychainChangeKeyStorePassphrase()
1366  {
1367      BEGIN_SECAPI
1368  
1369  	   os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1370      os_activity_scope(activity);
1371      os_release(activity);
1372      SecurityServer::ClientSession().changeKeyStorePassphrase();
1373      END_SECAPI
1374  }
1375  
1376  static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
1377  {
1378      BEGIN_SECAPI
1379  
1380  	   os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1381      os_activity_scope(activity);
1382      os_release(activity);
1383  
1384      // make a keychain object "wrapper" for this keychain ref
1385  	Keychain keychain = Keychain::optional(userKeychainRef);
1386  
1387      CssmClient::Db db = keychain->database();
1388  	
1389  	// create the keychain, using appropriate credentials
1390  	Allocator &alloc = db->allocator();
1391  	AutoCredentials cred(alloc);	// will leak, but we're quitting soon :-)
1392  
1393      char passphrase[1024];
1394      CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8);
1395      
1396      // use this passphrase
1397      cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
1398                        new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
1399                        new(alloc) ListElement(StringData(passphrase)));
1400  	db->authenticate(CSSM_DB_ACCESS_READ, &cred);
1401  
1402  	CSSM_DL_DB_HANDLE dlDb = db->handle();
1403  	CssmData dlDbData = CssmData::wrap(dlDb);
1404  	CssmKey refKey;
1405  	KeySpec spec(CSSM_KEYUSE_ANY,
1406                   CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
1407  
1408      DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64);
1409  	derive(&dlDbData, spec, refKey);
1410  	
1411  	// now extract the raw keybits
1412  	CssmKey rawKey;
1413  	WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE);
1414  	wrap(refKey, rawKey);
1415      
1416      *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length());
1417      
1418      END_SECAPI
1419  }
1420  
1421  static const char     *kAutologinPWFilePath = "/etc/kcpassword";
1422  static const uint32_t kObfuscatedPasswordSizeMultiple = 12;
1423  static const uint32_t buffer_size = 512;
1424  static const uint8_t  kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f};
1425  
1426  static void obfuscate(void *buffer, size_t bufferLength)
1427  {
1428  	uint8_t       *pBuf = (uint8_t *) buffer;
1429  	const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey );
1430  
1431  	while (bufferLength--) {
1432  		*pBuf = *pBuf ^ *pKey;
1433  		++pKey;
1434  		++pBuf;
1435  		if (pKey == eKey)
1436  			pKey = kObfuscationKey;
1437  	}
1438  }
1439  
1440  static bool _SASetAutologinPW(CFStringRef inAutologinPW)
1441  {
1442  	bool    result = false;
1443  	struct stat sb;
1444  
1445  	// Delete the kcpassword file if it exists already
1446  	if (stat(kAutologinPWFilePath, &sb) == 0)
1447  		unlink( kAutologinPWFilePath );
1448  
1449      // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off.
1450      if (inAutologinPW != NULL) {
1451  		char buffer[buffer_size];
1452  		const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8);
1453  		if (pwAsUTF8String == NULL) {
1454  			if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer;
1455  		}
1456  
1457  		if (pwAsUTF8String != NULL) {
1458  			size_t pwLength = strlen(pwAsUTF8String) + 1;
1459  			size_t obfuscatedPWLength;
1460  			char *obfuscatedPWBuffer;
1461  
1462  			// The size of the obfuscated password should be the smallest multiple of
1463  			// kObfuscatedPasswordSizeMultiple greater than or equal to pwLength.
1464  			obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple;
1465  			obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength);
1466  
1467  			// Copy the password (including null terminator) to beginning of obfuscatedPWBuffer
1468  			bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength);
1469  
1470  			// Pad remainder of obfuscatedPWBuffer with random bytes
1471  			{
1472  				char *p;
1473  				char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength;
1474  
1475  				for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p)
1476  					*p = random() & 0x000000FF;
1477  			}
1478  
1479  			obfuscate(obfuscatedPWBuffer, obfuscatedPWLength);
1480  
1481  			int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
1482  			if (pwFile >= 0) {
1483  				size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength);
1484  				if (wrote == obfuscatedPWLength)
1485  					result = true;
1486  				close(pwFile);
1487  			}
1488  
1489  			chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR);
1490  			free(obfuscatedPWBuffer);
1491  		}
1492  	}
1493  
1494      return result;
1495  }
1496  
1497  OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
1498  	COUNTLEGACYAPI
1499      SecTrustedApplicationRef itemPath;
1500      SecAccessRef ourAccessRef = NULL;
1501      
1502      OSStatus result = errSecParam;
1503      
1504  	if (userKeychainRef == NULL) {
1505  		// We don't have a specific user keychain, fall back
1506  		if (_SASetAutologinPW(password))
1507  			result = errSecSuccess;
1508  
1509  		return result;
1510  	}
1511  
1512      CFDataRef masterKey = NULL;
1513      result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password);
1514      if (errSecSuccess != result) {
1515          return result;
1516      }
1517      
1518      result = SecKeychainStash();
1519      if (errSecSuccess != result) {
1520          if (masterKey != NULL) CFRelease(masterKey);
1521          return result;
1522      }
1523      
1524      CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1525      if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath)
1526          CFArrayAppendValue(trustedApplications, itemPath);
1527      
1528      if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
1529          if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) {
1530  			SecKeychainRef internalSystemKeychainRef = NULL;
1531              if (NULL == systemKeychainRef) {
1532  				SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef);
1533              } else {
1534                  internalSystemKeychainRef = systemKeychainRef;
1535              }
1536              
1537              const void *queryKeys[] =   { kSecClass,
1538                  kSecAttrService,
1539                  kSecAttrAccount,
1540                  kSecUseKeychain,
1541              };
1542              const void *queryValues[] = { kSecClassGenericPassword,
1543                  CFSTR("com.apple.loginwindow.auto-login"),
1544                  username,
1545  				internalSystemKeychainRef,
1546              };
1547              
1548              const void *updateKeys[] =   { kSecAttrAccess,
1549                  kSecValueData,
1550              };
1551              const void *updateValues[] = { ourAccessRef,
1552                  masterKey,
1553              };
1554              
1555              CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1556              CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1557              
1558              result = SecItemUpdate(query, update);
1559              
1560              if (errSecSuccess != result) {
1561                  const void *addKeys[] =   { kSecClass,
1562                      kSecAttrService,
1563                      kSecAttrAccount,
1564                      kSecUseKeychain,
1565                      kSecAttrAccess,
1566                      kSecValueData,
1567                  };
1568                  const void *addValues[] = { kSecClassGenericPassword,
1569                      CFSTR("com.apple.loginwindow.auto-login"),
1570                      username,
1571  					internalSystemKeychainRef,
1572                      ourAccessRef,
1573                      masterKey,
1574                  };
1575                  
1576                  CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1577                  result = SecItemAdd(add, NULL);
1578                  if (NULL != add) CFRelease(add);
1579              }
1580  
1581              if (NULL != query) CFRelease(query);
1582              if (NULL != update) CFRelease(update);
1583  
1584  			// If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one
1585  			if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef);
1586          }
1587      }
1588  
1589      if (NULL != masterKey) CFRelease(masterKey);
1590      if (NULL != trustedApplications) CFRelease(trustedApplications);
1591      if (NULL != ourAccessRef) CFRelease(ourAccessRef);
1592  
1593      return result;
1594  }
1595  
1596  OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
1597  {
1598      BEGIN_SECAPI
1599  
1600      os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1601      os_activity_scope(activity);
1602      os_release(activity);
1603  
1604      if(attempts) {
1605          SecurityServer::ClientSession().getUserPromptAttempts(*attempts);
1606      }
1607  
1608      END_SECAPI
1609  }
1610  
1611  OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash,
1612                                                   SecKeychainRef userKeychain, CFStringRef password)
1613  {
1614  	COUNTLEGACYAPI
1615  	CFRef<CFStringRef> pwd;
1616  	OSStatus result;
1617  
1618  	if (password == NULL || CFStringGetLength(password) == 0) {
1619  		AuthorizationRef authorizationRef;
1620  		result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
1621  		if (result != errAuthorizationSuccess) {
1622  			secnotice("SecKeychain", "failed to create authorization");
1623  			return result;
1624  		}
1625  
1626  		AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0};
1627  		AuthorizationRights myRights = {1, &myItems};
1628  
1629  		char pathName[PATH_MAX];
1630  		UInt32 pathLength = PATH_MAX;
1631  		result = SecKeychainGetPath(userKeychain, &pathLength, pathName);
1632  		if (result != errSecSuccess) {
1633  			secnotice("SecKeychain", "failed to create authorization");
1634  			return result;
1635  		}
1636  
1637  		Boolean checkPwd = TRUE;
1638  		Boolean ignoreSession = TRUE;
1639  		AuthorizationItem envItems[] = {
1640  			{AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0},
1641  			{AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd},
1642  			{AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession}
1643  		};
1644  
1645  		AuthorizationEnvironment environment  = {3, envItems};
1646  		AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
1647  		result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, NULL);
1648          secnotice("SecKeychain", "Authorization result: %d", (int)result);
1649  
1650  		if (result == errAuthorizationSuccess) {
1651  			AuthorizationItemSet *items;
1652  			result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items);
1653              secnotice("SecKeychain", "Items copy result: %d", (int)result);
1654  			if (result == errAuthorizationSuccess) {
1655                  secnotice("SecKeychain", "Items count: %d", items->count);
1656  				if (items->count > 0) {
1657  					pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8);
1658                      if (pwd) {
1659                          secnotice("SecKeychain", "Got kcpass");
1660                      }
1661  				}
1662  				AuthorizationFreeItemSet(items);
1663  			}
1664  		}
1665  		AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1666  		if (result != errAuthorizationSuccess) {
1667  			secnotice("SecKeychain", "did not get authorization to pair the card");
1668  			return result;
1669  		}
1670  	} else {
1671  		pwd.take(password);
1672  	}
1673  
1674  	if (!pwd) {
1675  		secnotice("SecKeychain", "did not get kcpass");
1676  		return errSecInternalComponent;
1677  	}
1678  
1679  	CFRef<CFDataRef> masterKey;
1680  	result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd);
1681  	if (result != errSecSuccess) {
1682  		secnotice("SecKeychain", "Failed to get master key: %d", (int) result);
1683  		return result;
1684  	}
1685  
1686  	CFRef<CFDataRef> scBlob;
1687  	result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take());
1688  	if (result != errSecSuccess) {
1689  		secnotice("SecKeychain", "Failed to get stash: %d", (int) result);
1690  		return result;
1691  	}
1692  
1693  	result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob);
1694  	if (result != errSecSuccess) {
1695  		secnotice("SecKeychain", "Failed to create login data: %d", (int) result);
1696  		return result;
1697  	}
1698  
1699  	secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result);
1700      
1701      // create SC KEK
1702      // this might fail if KC password is different from user's password
1703      uid_t uid = geteuid();
1704      if (!uid) {
1705          uid = getuid();
1706      }
1707      struct passwd *passwd = getpwuid(uid);
1708      if (passwd) {
1709          CFRef<CFStringRef> username = CFStringCreateWithCString(kCFAllocatorDefault, passwd->pw_name, kCFStringEncodingUTF8);
1710          OSStatus kekRes = TKAddSecureToken(username, pwd, tokenID, wrapPubKeyHash);
1711          if (kekRes != noErr) {
1712              secnotice("SecKeychain", "Failed to register SC token: %d", (int) kekRes); // do not fail because KC functionality be still OK
1713          }
1714      } else {
1715          secnotice("SecKeychain", "Unable to get name for uid %d", uid);
1716      }
1717  	return result;
1718  }
1719  
1720  OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash)
1721  {
1722  	COUNTLEGACYAPI
1723      OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash);
1724      if (result != errSecSuccess) {
1725          secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result);
1726      }
1727      return result;
1728  }