const AccessCredentials * KeyItem::getCredentials( CSSM_ACL_AUTHORIZATION_TAG operation, SecCredentialType credentialType) { // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing. //AutoAclEntryInfoList aclInfos; //key()->getAcl(aclInfos); bool smartcard = keychain() != NULL ? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL) : false; AclFactory factory; switch (credentialType) { case kSecCredentialTypeDefault: return smartcard?globals().smartcardItemCredentials():globals().itemCredentials(); case kSecCredentialTypeWithUI: return smartcard?globals().smartcardItemCredentials():factory.promptCred(); case kSecCredentialTypeNoUI: return factory.nullCred(); default: MacOSError::throwMe(paramErr); } }
PrimaryKey ItemImpl::addWithCopyInfo (Keychain &keychain, bool isCopy) { StLock<Mutex>_(mMutex); // If we already have a Keychain we can't be added. if (mKeychain) MacOSError::throwMe(errSecDuplicateItem); // If we don't have any attributes we can't be added. // (this might occur if attempting to add the item twice, since our attributes // and data are set to NULL at the end of this function.) if (!mDbAttributes.get()) MacOSError::throwMe(errSecDuplicateItem); CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType(); // update the creation and update dates on the new item if (!isCopy) { KeychainSchema schema = keychain->keychainSchema(); SInt64 date; GetCurrentMacLongDateTime(date); if (schema->hasAttribute(recordType, kSecCreationDateItemAttr)) { setAttribute(schema->attributeInfoFor(recordType, kSecCreationDateItemAttr), date); } if (schema->hasAttribute(recordType, kSecModDateItemAttr)) { setAttribute(schema->attributeInfoFor(recordType, kSecModDateItemAttr), date); } } // If the label (PrintName) attribute isn't specified, set a default label. if (!mDoNotEncrypt && !mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr))) { // if doNotEncrypt was set all of the attributes are wrapped in the data blob. Don't calculate here. CssmDbAttributeData *label = NULL; switch (recordType) { case CSSM_DL_DB_RECORD_GENERIC_PASSWORD: label = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr)); break; case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD: case CSSM_DL_DB_RECORD_INTERNET_PASSWORD: label = mDbAttributes->find(Schema::attributeInfo(kSecServerItemAttr)); // if AppleShare server name wasn't specified, try the server address if (!label) label = mDbAttributes->find(Schema::attributeInfo(kSecAddressItemAttr)); break; default: break; } // if all else fails, use the account name. if (!label) label = mDbAttributes->find(Schema::attributeInfo(kSecAccountItemAttr)); if (label && label->size()) setAttribute (Schema::attributeInfo(kSecLabelItemAttr), label->at<CssmData>(0)); } // get the attributes that are part of the primary key const CssmAutoDbRecordAttributeInfo &primaryKeyInfos = keychain->primaryKeyInfosFor(recordType); // make sure each primary key element has a value in the item, otherwise // the database will complain. we make a set of the provided attribute infos // to avoid O(N^2) behavior. DbAttributes *attributes = mDbAttributes.get(); typedef set<CssmDbAttributeInfo> InfoSet; InfoSet infoSet; if (!mDoNotEncrypt) { // make a set of all the attributes in the key for (uint32 i = 0; i < attributes->size(); i++) infoSet.insert(attributes->at(i).Info); for (uint32 i = 0; i < primaryKeyInfos.size(); i++) { // check to make sure all required attributes are in the key InfoSet::const_iterator it = infoSet.find(primaryKeyInfos.at(i)); if (it == infoSet.end()) { // not in the key? add the default // we need to add a default value to the item attributes attributes->add(primaryKeyInfos.at(i), defaultAttributeValue(primaryKeyInfos.at(i))); } } } Db db(keychain->database()); if (mDoNotEncrypt) { mUniqueId = db->insertWithoutEncryption (recordType, NULL, mData.get()); } else if (useSecureStorage(db)) { // Add the item to the secure storage db SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*db)); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } SSDb ssDb(impl); TrackingAllocator allocator(Allocator::standard()); // hhs replaced with the new aclFactory class AclFactory aclFactory; const AccessCredentials *nullCred = aclFactory.nullCred(); SecPointer<Access> access = mAccess; if (!access) { // create default access controls for the new item CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr)); string printName = data ? CssmData::overlay(data->Value[0]).toString() : "keychain item"; access = new Access(printName); // special case for "iTools" password - allow anyone to decrypt the item if (recordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD) { CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr)); if (data && data->Value[0].Length == 6 && !memcmp("iTools", data->Value[0].Data, 6)) { typedef vector<SecPointer<ACL> > AclSet; AclSet acls; access->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT, acls); for (AclSet::const_iterator it = acls.begin(); it != acls.end(); it++) (*it)->form(ACL::allowAllForm); } } } // Get the handle of the DL underlying this CSPDL. CSSM_DL_DB_HANDLE dldbh; db->passThrough(CSSM_APPLECSPDL_DB_GET_HANDLE, NULL, reinterpret_cast<void **>(&dldbh)); // Turn off autocommit on the underlying DL and remember the old state. CSSM_BOOL autoCommit = CSSM_TRUE; ObjectImpl::check(CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, 0, reinterpret_cast<void **>(&autoCommit))); try { // Create a new SSGroup with temporary access controls Access::Maker maker; ResourceControlContext prototype; maker.initialOwner(prototype, nullCred); SSGroup ssGroup(ssDb, &prototype); try { // Insert the record using the newly created group. mUniqueId = ssDb->insert(recordType, mDbAttributes.get(), mData.get(), ssGroup, maker.cred()); } catch(...) { ssGroup->deleteKey(nullCred); throw; } // now finalize the access controls on the group access->setAccess(*ssGroup, maker); mAccess = NULL; // use them and lose them if (autoCommit) { // autoCommit was on so commit now that we are done and turn // it back on. ObjectImpl::check(CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_COMMIT, NULL, NULL)); CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, reinterpret_cast<const void *>(autoCommit), NULL); } } catch (...) { if (autoCommit) { // autoCommit was off so rollback since we failed and turn // autoCommit back on. CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL); CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, reinterpret_cast<const void *>(autoCommit), NULL); } throw; } } else { // add the item to the (regular) db mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get()); } mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId); mKeychain = keychain; // Forget our data and attributes. mData = NULL; mDbAttributes.reset(NULL); return mPrimaryKey; }