/ OSX / libsecurity_cdsa_client / lib / dlclient.cpp
dlclient.cpp
   1  /*
   2   * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
   3   * 
   4   * The contents of this file constitute Original Code as defined in and are
   5   * subject to the Apple Public Source License Version 1.2 (the 'License').
   6   * You may not use this file except in compliance with the License. Please obtain
   7   * a copy of the License at http://www.apple.com/publicsource and read it before
   8   * using this file.
   9   * 
  10   * This Original Code and all software distributed under the License are
  11   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
  12   * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
  13   * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14   * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
  15   * specific language governing rights and limitations under the License.
  16   */
  17  
  18  
  19  //
  20  // dlclient - client interface to CSSM DLs and their operations
  21  //
  22  #include <security_cdsa_client/dlclient.h>
  23  #include <security_cdsa_client/aclclient.h>
  24  #include <Security/cssmapple.h>
  25  #include <Security/cssmapplePriv.h>
  26  #include <Security/SecBase.h>
  27  #include <security_cdsa_utilities/Schema.h>
  28  
  29  using namespace CssmClient;
  30  
  31  #pragma clang diagnostic push
  32  #pragma clang diagnostic ignored "-Wunused-const-variable"
  33  // blob type for blobs created by these classes -- done so that we can change the formats later
  34  const uint32 kBlobType = 0x1;
  35  #pragma clang diagnostic pop
  36  
  37  //
  38  // Abstract classes
  39  //
  40  DbMaker::~DbMaker()
  41  { /* virtual */ }
  42  
  43  DbCursorMaker::~DbCursorMaker()
  44  { /* virtual */ }
  45  
  46  DbUniqueRecordMaker::~DbUniqueRecordMaker()
  47  { /* virtual */ }
  48  
  49  
  50  //
  51  // Manage DL attachments
  52  //
  53  DLImpl::DLImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_DL)
  54  {
  55  }
  56  
  57  DLImpl::DLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_DL)
  58  {
  59  }
  60  
  61  DLImpl::~DLImpl()
  62  {
  63  }
  64  
  65  void
  66  DLImpl::getDbNames(char **)
  67  {
  68  	CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
  69  }
  70  
  71  void
  72  DLImpl::freeNameList(char **)
  73  {
  74  	CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
  75  }
  76  
  77  DbImpl *
  78  DLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
  79  {
  80  	return new DbImpl(DL(this), inDbName, inDbLocation);
  81  }
  82  
  83  
  84  //
  85  // Db (database)
  86  //
  87  DbImpl::DbImpl(const DL &dl, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
  88  	: ObjectImpl(dl), mDbName(inDbName, inDbLocation),
  89  	mUseNameFromHandle(!inDbName), mNameFromHandle(NULL),
  90  	mAccessRequest(CSSM_DB_ACCESS_READ), mAccessCredentials(NULL),
  91  	mDefaultCredentials(NULL), mOpenParameters(NULL), mDbInfo(NULL),
  92  	mResourceControlContext(NULL)
  93  {
  94  }
  95  
  96  DbImpl::~DbImpl()
  97  {
  98  	try
  99  	{
 100  		if (mNameFromHandle)
 101  			allocator().free(mNameFromHandle);
 102  		deactivate();
 103  	}
 104  	catch(...) {}
 105  }
 106  
 107  void
 108  DbImpl::open()
 109  {
 110      {
 111          StLock<Mutex> _(mActivateMutex);
 112          if (!mActive)
 113          {
 114              assert(mDbInfo == nil);
 115              mHandle.DLHandle = dl()->handle();
 116              check(CSSM_DL_DbOpen(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
 117                                      mAccessRequest, mAccessCredentials,
 118                                      mOpenParameters, &mHandle.DBHandle));
 119  
 120              mActive = true;
 121          }
 122  	}
 123  
 124      if (!mAccessCredentials && mDefaultCredentials)
 125          if (const AccessCredentials *creds = mDefaultCredentials->makeCredentials())
 126              CSSM_DL_Authenticate(handle(), mAccessRequest, creds);	// ignore error
 127  }
 128  
 129  void
 130  DbImpl::createWithBlob(CssmData &blob)
 131  {
 132  	if (mActive)
 133  		CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
 134  
 135  	if (mDbInfo == nil) {
 136  		// handle a missing (null) mDbInfo as an all-zero one
 137  		static const CSSM_DBINFO nullDbInfo = { };
 138  		mDbInfo = &nullDbInfo;
 139  	}
 140  
 141  	mHandle.DLHandle = dl()->handle();
 142  
 143  	// create a parameter block for our call to the passthrough
 144  	CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS params;
 145  	
 146  	params.dbName = mDbName.canonicalName ();
 147  	params.dbLocation = dbLocation ();
 148  	params.dbInfo = mDbInfo;
 149  	params.accessRequest = mAccessRequest;
 150  	params.credAndAclEntry = NULL;
 151  	params.openParameters = mOpenParameters;
 152  	params.blob = &blob;
 153  
 154  	check(CSSM_DL_PassThrough (mHandle, CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB, &params, (void**) &mHandle.DBHandle));
 155  }
 156  
 157  void
 158  DbImpl::create()
 159  {
 160      StLock<Mutex> _(mActivateMutex);
 161  	if (mActive)
 162  		CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
 163  
 164  	if (mDbInfo == nil) {
 165  		// handle a missing (null) mDbInfo as an all-zero one
 166  		static const CSSM_DBINFO nullDbInfo = { };
 167  		mDbInfo = &nullDbInfo;
 168  	}
 169  	mHandle.DLHandle = dl()->handle();
 170  	
 171  	if (!mResourceControlContext && mAccessCredentials) {
 172  		AclFactory::AnyResourceContext ctx(mAccessCredentials);
 173  		check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
 174  							mDbInfo, mAccessRequest, &ctx,
 175  							mOpenParameters, &mHandle.DBHandle));
 176  	} else {
 177  		check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
 178  							mDbInfo, mAccessRequest, mResourceControlContext,
 179  							mOpenParameters, &mHandle.DBHandle));
 180  	}
 181  	mActive = true;
 182  }
 183  
 184  void
 185  DbImpl::close()
 186  {
 187      StLock<Mutex> _(mActivateMutex);
 188  	if (mActive)
 189  	{
 190  		check(CSSM_DL_DbClose (mHandle));
 191  		mActive = false;
 192  	}
 193  }
 194  
 195  void
 196  DbImpl::activate()
 197  {
 198      StLock<Mutex> _(mActivateMutex);
 199  	if (!mActive)
 200  	{
 201  		if (mDbInfo)
 202  			create();
 203  		else
 204  			open();
 205  	}
 206  }
 207  
 208  void
 209  DbImpl::deactivate()
 210  {
 211      StLock<Mutex> _(mActivateMutex);
 212  	if (mActive)
 213  	{
 214  		mActive = false;
 215  		close();
 216  	}
 217  }
 218  
 219  void
 220  DbImpl::deleteDb()
 221  {
 222  	// Deactivate so the db gets closed if it was open.
 223  	deactivate();
 224  	// This call does not require the receiver to be active.
 225  	check(CSSM_DL_DbDelete(dl()->handle(), mDbName.canonicalName(), dbLocation(),
 226  						   mAccessCredentials));
 227  }
 228  
 229  void
 230  DbImpl::rename(const char *newName)
 231  {
 232  	// Deactivate so the db gets closed if it was open.
 233  	deactivate();
 234      if (::rename(mDbName.canonicalName(), newName))
 235  		UnixError::throwMe(errno);
 236  
 237  	// Change our DbName to reflect this rename.
 238  	mDbName = DbName(newName, dbLocation());
 239  }
 240  
 241  void
 242  DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
 243  					 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
 244  {
 245  	if (!mActive)
 246  	{
 247  		// XXX Could do the same for create but this would require sticking
 248  		// inAccessCredentials into mResourceControlContext.
 249  		if (!mDbInfo)
 250  		{
 251  			// We were not yet active.  Just do an open.
 252  			accessRequest(inAccessRequest);
 253  			accessCredentials(inAccessCredentials);
 254  			activate();
 255  			return;
 256  		}
 257  	}
 258  
 259  	check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
 260  }
 261  
 262  void
 263  DbImpl::name(char *&outDbName)
 264  {
 265  	check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
 266  }
 267  
 268  const char *
 269  DbImpl::name()
 270  {
 271  	if (mUseNameFromHandle)
 272  	{
 273  		if (mNameFromHandle
 274  		    || !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle))
 275  		{
 276  			return mNameFromHandle;
 277  		}
 278  
 279  		// We failed to get the name from the handle so use the passed
 280  		// in name instead
 281  		mUseNameFromHandle = false;
 282  	}
 283  
 284  	return mDbName.canonicalName();
 285  }
 286  
 287  void
 288  DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
 289  							 const char *inRelationName,
 290  							 uint32 inNumberOfAttributes,
 291  							 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
 292  							 uint32 inNumberOfIndexes,
 293  							 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
 294  {
 295  	check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
 296  								 inNumberOfAttributes, pAttributeInfo,
 297  								 inNumberOfIndexes, pIndexInfo));
 298  }
 299  
 300  void
 301  DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
 302  {
 303  	check(CSSM_DL_DestroyRelation(handle(), inRelationID));
 304  }
 305  
 306  DbUniqueRecord
 307  DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
 308  				 const CSSM_DATA *data)
 309  {
 310  	DbUniqueRecord uniqueId(Db(this));
 311  	check(CSSM_DL_DataInsert(handle(), recordType,
 312  							 attributes,
 313  							 data, uniqueId));
 314  	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
 315  	uniqueId->activate();
 316  	return uniqueId;
 317  }
 318  
 319  
 320  DbUniqueRecord
 321  DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
 322  								CSSM_DATA *data)
 323  {
 324  	DbUniqueRecord uniqueId(Db(this));
 325  
 326  	// fill out the parameters
 327  	CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params;
 328  	params.recordType = recordType;
 329  	params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
 330  	params.data = *data;
 331  
 332  	// for clarity, call the overloaded operator to produce a unique record pointer
 333  	CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = uniqueId;
 334  
 335  	// make the call
 336  	passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION, &params, (void**) uniquePtr);
 337  	
 338  	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
 339  	uniqueId->activate();
 340  	return uniqueId;
 341  }
 342  
 343  
 344  //
 345  // Generic Passthrough interface
 346  //
 347  void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
 348  {
 349  	check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
 350  }
 351  
 352  
 353  //
 354  // Passthrough functions (only implemented by AppleCSPDL).
 355  //
 356  void
 357  DbImpl::lock()
 358  {
 359  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
 360  }
 361  
 362  void
 363  DbImpl::unlock()
 364  {
 365  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
 366  }
 367  
 368  void
 369  DbImpl::unlock(const CSSM_DATA &password)
 370  {
 371  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
 372  }
 373  
 374  void
 375  DbImpl::stash()
 376  {
 377      check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH, NULL, NULL));
 378  }
 379  
 380  void
 381  DbImpl::stashCheck()
 382  {
 383      check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH_CHECK, NULL, NULL));
 384  }
 385  
 386  void
 387  DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
 388  {
 389  	CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
 390  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
 391  							  NULL, reinterpret_cast<void **>(&settings)));
 392  	outIdleTimeout = settings->idleTimeout;
 393  	outLockOnSleep = settings->lockOnSleep;
 394  	allocator().free(settings);
 395  }
 396  
 397  void
 398  DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
 399  {
 400  	CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
 401  	settings.idleTimeout = inIdleTimeout;
 402  	settings.lockOnSleep = inLockOnSleep;
 403  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
 404  }
 405  
 406  bool
 407  DbImpl::isLocked()
 408  {
 409  	CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
 410  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
 411  							  NULL, reinterpret_cast<void **>(&params)));
 412  	bool isLocked = params->isLocked;
 413  	allocator().free(params);
 414  	return isLocked;
 415  }
 416  
 417  void
 418  DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
 419  {
 420  	CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
 421  	params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
 422  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, &params, NULL));
 423  }
 424  
 425  void DbImpl::recode(const CSSM_DATA &data, const CSSM_DATA &extraData)
 426  {
 427  	// setup parameters for the recode call
 428  	CSSM_APPLECSPDL_RECODE_PARAMETERS params;
 429  	params.dbBlob = data;
 430  	params.extraData = extraData;
 431  
 432  	// do the call
 433  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE, &params, NULL));
 434  }
 435  
 436  void DbImpl::copyBlob (CssmData &data)
 437  {
 438  	// do the call
 439  	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB, NULL, (void**) (CSSM_DATA*) &data));
 440  }
 441  
 442  void DbImpl::setBatchMode(Boolean mode, Boolean rollback)
 443  {
 444  	//
 445  	// We need the DL_DB_Handle of the underyling DL in order to use CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
 446  	// 
 447  	CSSM_RETURN result;
 448  	CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL;
 449  	result = CSSM_DL_PassThrough(handle(),
 450  								 CSSM_APPLECSPDL_DB_GET_HANDLE,
 451  								 NULL,
 452  								 (void **)&dldbHandleOfUnderlyingDL);
 453  	//
 454  	// Now, toggle the autocommit...
 455  	//
 456  	if ( result == errSecSuccess )
 457  	{
 458  		CSSM_BOOL modeToUse = !mode;
 459  		if (rollback)
 460  		{
 461  			result = (OSStatus)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
 462  										CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
 463  		}
 464  
 465  		result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
 466  									 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
 467  									 (void *)((size_t) modeToUse),
 468  									 NULL);
 469  		if (!rollback && modeToUse)
 470  			result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
 471  									 CSSM_APPLEFILEDL_COMMIT,
 472  									 NULL,
 473  									 NULL);
 474  	}
 475  }
 476  
 477  uint32 DbImpl::dbBlobVersion() {
 478      uint32 dbBlobVersion = 0;
 479      uint32* dbBlobVersionPtr = &dbBlobVersion;
 480  
 481      // We only have a blob version if we're an apple CSPDL
 482      if(dl()->guid() == gGuidAppleCSPDL) {
 483          check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_BLOB_VERSION, NULL, (void**) &dbBlobVersionPtr));
 484      } else {
 485          secnotice("integrity", "Non-Apple CSPDL keychains don't have keychain versions");
 486      }
 487      return dbBlobVersion;
 488  }
 489  
 490  uint32 DbImpl::recodeDbToVersion(uint32 version) {
 491      uint32 newDbVersion;
 492      uint32* newDbVersionPtr = &newDbVersion;
 493      check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_TO_BLOB_VERSION, &version, (void**) &newDbVersionPtr));
 494      return newDbVersion;
 495  }
 496  
 497  void DbImpl::recodeFinished() {
 498      check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_FINISHED, NULL, NULL));
 499  }
 500  
 501  void DbImpl::takeFileLock() {
 502      passThrough(CSSM_APPLECSPDL_DB_TAKE_FILE_LOCK, NULL, NULL);
 503  }
 504  
 505  void DbImpl::releaseFileLock(bool success) {
 506      passThrough(CSSM_APPLECSPDL_DB_RELEASE_FILE_LOCK, &success, NULL);
 507  }
 508  
 509  void DbImpl::makeBackup() {
 510      passThrough(CSSM_APPLECSPDL_DB_MAKE_BACKUP, NULL, NULL);
 511  }
 512  
 513  void DbImpl::makeCopy(const char* path) {
 514      passThrough(CSSM_APPLECSPDL_DB_MAKE_COPY, path, NULL);
 515  }
 516  
 517  void DbImpl::deleteFile() {
 518      passThrough(CSSM_APPLECSPDL_DB_DELETE_FILE, NULL, NULL);
 519  }
 520  
 521  void DbImpl::transferTo(const DLDbIdentifier& dldbidentifier) {
 522      if (dldbidentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP) {
 523          // if we're an Apple CSPDL, do the fancy transfer:
 524          //  clone the file, clone the db, remove the original file
 525          string oldPath = name();
 526  
 527          CSSM_DB_HANDLE dbhandle;
 528          passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
 529  
 530          mDbName = dldbidentifier.dbName();
 531          mHandle.DBHandle = dbhandle;
 532  
 533          unlink(oldPath.c_str());
 534  
 535          // Don't cache this name
 536          if (mNameFromHandle) {
 537              allocator().free(mNameFromHandle);
 538              mNameFromHandle = NULL;
 539          }
 540      } else {
 541          // if we're not an Apple CSPDL, just call rename
 542          this->rename(dldbidentifier.dbName());
 543      }
 544  }
 545  
 546  
 547  // cloneTo only makes sense if you're on an Apple CSPDL
 548  Db DbImpl::cloneTo(const DLDbIdentifier& dldbidentifier) {
 549      CSSM_DB_HANDLE dbhandle;
 550      passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
 551  
 552      // This is the only reasonable way to make a SSDbImpl at this layer.
 553      CssmClient::Db db(dl(), dldbidentifier.dbName(), dldbidentifier.dbLocation());
 554      db->mHandle.DBHandle = dbhandle;
 555  
 556      return db;
 557  }
 558  
 559  //
 560  // DbCursorMaker
 561  //
 562  DbCursorImpl *
 563  DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
 564  {
 565  	return new DbDbCursorImpl(Db(this), query, allocator);
 566  }
 567  
 568  DbCursorImpl *
 569  DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
 570  {
 571  	return new DbDbCursorImpl(Db(this), capacity, allocator);
 572  }
 573  
 574  
 575  //
 576  // Db adapters for AclBearer
 577  //
 578  void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
 579  {
 580  	aclInfos.allocator(allocator());
 581  	check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
 582  		reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
 583  }
 584  
 585  void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
 586  	const CSSM_ACCESS_CREDENTIALS *accessCred)
 587  {
 588  	check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
 589  }
 590  
 591  void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
 592  {
 593  	owner.allocator(allocator());
 594  	check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
 595  }
 596  
 597  void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
 598  	const CSSM_ACCESS_CREDENTIALS *accessCred)
 599  {
 600  	check(CSSM_DL_ChangeDbOwner(handle(),
 601  		AccessCredentials::needed(accessCred), &newOwner));
 602  }
 603  
 604  void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
 605  {
 606  	mDefaultCredentials = maker;
 607  }
 608  
 609  
 610  //
 611  // Abstract DefaultCredentialsMakers
 612  //
 613  DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
 614  { /* virtual */ }
 615  
 616  
 617  //
 618  // Db adapters for DLAccess
 619  //
 620  CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query,	CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, 
 621  	CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
 622  {
 623  	CSSM_HANDLE result;
 624  	switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
 625  	case CSSM_OK:
 626  		return result;
 627  	case CSSMERR_DL_ENDOFDATA:
 628  		return CSSM_INVALID_HANDLE;
 629  	default:
 630  		CssmError::throwMe(rc);
 631  	}
 632  }
 633  
 634  bool Db::dlGetNext(CSSM_HANDLE query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
 635  	CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
 636  {
 637  	CSSM_RETURN rc = CSSM_DL_DataGetNext(handle(), query, &attributes, data, &id);
 638  	switch (rc) {
 639  	case CSSM_OK:
 640  		return true;
 641  	case CSSMERR_DL_ENDOFDATA:
 642  		return false;
 643  	default:
 644  		CssmError::throwMe(rc);
 645  	}
 646  }
 647  
 648  void Db::dlAbortQuery(CSSM_HANDLE query)
 649  {
 650  	CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
 651  }
 652  
 653  void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
 654  {
 655  	CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
 656  }
 657  
 658  void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
 659  {
 660  	CssmError::check(CSSM_DL_DataDelete(handle(), id));
 661  }
 662  
 663  Allocator &Db::allocator()
 664  {
 665  	return Object::allocator();
 666  }
 667  
 668  
 669  //
 670  // DbUniqueRecordMaker
 671  //
 672  DbUniqueRecordImpl *
 673  DbImpl::newDbUniqueRecord()
 674  {
 675  	return new DbUniqueRecordImpl(Db(this));
 676  }
 677  
 678  
 679  //
 680  // Utility methods
 681  //
 682  DLDbIdentifier
 683  DbImpl::dlDbIdentifier()
 684  {
 685  	// Always use the same dbName and dbLocation that were passed in during
 686  	// construction
 687  	return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
 688  }
 689  
 690  
 691  //
 692  // DbDbCursorImpl
 693  //
 694  DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
 695  : DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
 696  {
 697  }
 698  
 699  DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
 700  : DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
 701  {
 702  }
 703  
 704  DbDbCursorImpl::~DbDbCursorImpl()
 705  {
 706  	try
 707  	{
 708  		deactivate();
 709  	}
 710  	catch(...) {}
 711  }
 712  
 713  bool
 714  DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
 715  {
 716  	if (attributes)
 717  		attributes->deleteValues();
 718  
 719  	if (data)
 720  		data->clear();
 721  
 722  	CSSM_RETURN result;
 723  	Db db(database());
 724  	DbUniqueRecord unique(db);
 725  	if (!mActive)
 726  	{
 727  		// ask the CSP/DL if the requested  record type exists
 728  		CSSM_BOOL boolResult;
 729  		CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
 730  		if (!boolResult)
 731  		{
 732  			if (data != NULL)
 733  			{
 734  				data->invalidate();
 735  			}
 736  			
 737  			return false;
 738  		}
 739  		
 740  		result = CSSM_DL_DataGetFirst(db->handle(),
 741  									  this,
 742  									  &mResultsHandle,
 743  									  attributes,
 744  									  data,
 745  									  unique);
 746  
 747          StLock<Mutex> _(mActivateMutex);
 748  		if (result == CSSM_OK)
 749  			mActive = true;
 750  		else if (data != NULL)
 751  			data->invalidate ();
 752  	}
 753  	else
 754  	{
 755  		result = CSSM_DL_DataGetNext(db->handle(),
 756  									 mResultsHandle,
 757  									 attributes,
 758  									 data,
 759  									 unique);
 760  		
 761  		if (result != CSSM_OK && data != NULL)
 762  		{
 763  			data->invalidate ();
 764  		}
 765  	}
 766  
 767  	if (result != CSSM_OK && attributes != NULL)
 768  	{
 769  		attributes->invalidate();
 770  	}
 771  	
 772  	if (result == CSSMERR_DL_ENDOFDATA)
 773  	{
 774          StLock<Mutex> _(mActivateMutex);
 775  		mActive = false;
 776  		return false;
 777  	}
 778  
 779  	check(result);
 780  
 781  	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
 782  	unique->activate();
 783  	uniqueId = unique;
 784  	return true;
 785  }
 786  
 787  void
 788  DbDbCursorImpl::activate()
 789  {
 790  }
 791  
 792  void
 793  DbDbCursorImpl::deactivate()
 794  {
 795      StLock<Mutex> _(mActivateMutex);
 796  	if (mActive)
 797  	{
 798  		mActive = false;
 799  		check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
 800  	}
 801  }
 802  
 803  
 804  //
 805  // DbCursorImpl
 806  //
 807  DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
 808  ObjectImpl(parent), CssmAutoQuery(query, allocator)
 809  {
 810  }
 811  
 812  DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
 813  ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
 814  {
 815  }
 816  
 817  Allocator &
 818  DbCursorImpl::allocator() const
 819  {
 820  	return ObjectImpl::allocator();
 821  }
 822  
 823  void
 824  DbCursorImpl::allocator(Allocator &alloc)
 825  {
 826  	ObjectImpl::allocator(alloc);
 827  }
 828  
 829  
 830  //
 831  // DbUniqueRecord
 832  //
 833  DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
 834  {
 835  }
 836  
 837  DbUniqueRecordImpl::~DbUniqueRecordImpl()
 838  {
 839  	try
 840  	{
 841  		if (mDestroyID)
 842  		{
 843  			allocator ().free (mUniqueId);
 844  		}
 845  		
 846  		deactivate();
 847  	}
 848  	catch(...) {}
 849  }
 850  
 851  void
 852  DbUniqueRecordImpl::deleteRecord()
 853  {
 854  	check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
 855  }
 856  
 857  void
 858  DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
 859  						   const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
 860  						   const CSSM_DATA *data,
 861  						   CSSM_DB_MODIFY_MODE modifyMode)
 862  {
 863  	check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
 864  							 attributes,
 865  							 data, modifyMode));
 866  }
 867  
 868  void
 869  DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
 870  											const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
 871  											const CSSM_DATA *data,
 872  											CSSM_DB_MODIFY_MODE modifyMode)
 873  {
 874  	// fill out the parameters
 875  	CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
 876  	params.recordType = recordType;
 877  	params.uniqueID = mUniqueId;
 878  	params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
 879  	params.data = (CSSM_DATA*) data;
 880  	params.modifyMode = modifyMode;
 881  	
 882  	// modify the data
 883  	check(CSSM_DL_PassThrough(database()->handle(),
 884  		  CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
 885  		  &params, 
 886  		  NULL));
 887  }
 888  
 889  void
 890  DbUniqueRecordImpl::get(DbAttributes *attributes,
 891  						::CssmDataContainer *data)
 892  {
 893  	if (attributes)
 894  		attributes->deleteValues();
 895  
 896  	if (data)
 897  		data->clear();
 898  
 899  	// @@@ Fix the allocators for attributes and data.
 900  	CSSM_RETURN result;
 901  	result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
 902  											attributes,
 903  											data);
 904  											
 905  	if (result != CSSM_OK)
 906  	{
 907          if (attributes)
 908              attributes->invalidate();
 909  		if (data != NULL) // the data returned is no longer valid
 910  		{
 911  			data->invalidate ();
 912  		}
 913  	}
 914  	
 915  	check(result);
 916  }
 917  
 918  void
 919  DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
 920  										 ::CssmDataContainer *data)
 921  {
 922  	if (attributes)
 923  		attributes->deleteValues();
 924  
 925  	if (data)
 926  		data->clear();
 927  
 928  	// @@@ Fix the allocators for attributes and data.
 929  	CSSM_RETURN result;
 930  	
 931  	// make the parameter block
 932  	CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
 933  	params.uniqueID = mUniqueId;
 934  	params.attributes = attributes;
 935  	
 936  	// get the data
 937  	::CssmDataContainer recordData;
 938  	result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, &params,
 939  								 (void**) data);
 940  	check (result);
 941  }
 942  
 943  void
 944  DbUniqueRecordImpl::activate()
 945  {
 946      StLock<Mutex> _(mActivateMutex);
 947  	mActive = true;
 948  }
 949  
 950  void
 951  DbUniqueRecordImpl::deactivate()
 952  {
 953      StLock<Mutex> _(mActivateMutex);
 954  	if (mActive)
 955  	{
 956  		mActive = false;
 957  		check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
 958  	}
 959  }
 960  
 961  void
 962  DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
 963  {
 964  	check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
 965  		  mUniqueId, (void**) &data));
 966  }
 967  
 968  void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
 969  {
 970  	// clone the record
 971  	mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
 972  	*mUniqueId = *uniquePtr;
 973  	mDestroyID = true;
 974  }
 975  
 976  //
 977  // DbAttributes
 978  //
 979  DbAttributes::DbAttributes()
 980  :  CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
 981  {
 982  }
 983  
 984  DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
 985  :  CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
 986  {
 987  }
 988  
 989  void DbAttributes::updateWithDbAttributes(DbAttributes* newValues) {
 990      if(!newValues) {
 991          return;
 992      }
 993  
 994      canonicalize();
 995      newValues->canonicalize();
 996  
 997      updateWith(newValues);
 998  }
 999  
1000  void
1001  DbAttributes::canonicalize() {
1002      for(int i = 0; i < size(); i++) {
1003          CssmDbAttributeData& data = attributes()[i];
1004          CssmDbAttributeInfo& datainfo = data.info();
1005  
1006          // Calling Schema::attributeInfo is the best way to canonicalize.
1007          // There's no way around the try-catch structure, since it throws if it
1008          // can't find something.
1009  
1010          try {
1011              if(datainfo.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER) {
1012                  data.info() = Security::KeychainCore::Schema::attributeInfo(datainfo.intName());
1013              }
1014          } catch(...) {
1015              // Don't worry about it
1016          }
1017      }
1018  }