1/*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * ExtendedAttribute.cpp - Extended Keychain Item Attribute class.
26 *
27 * Created 9/6/06 by dmitch.
28 */
29
30#include "ExtendedAttribute.h"
31#include "SecKeychainItemExtendedAttributes.h"
32#include "SecKeychainItemPriv.h"
33#include "cssmdatetime.h"
34#include <security_cdsa_utilities/Schema.h>
35
36using namespace KeychainCore;
37
38/*
39 * Construct new ExtendedAttr from API.
40 */
41ExtendedAttribute::ExtendedAttribute(
42	CSSM_DB_RECORDTYPE recordType,
43	const CssmData &itemID,
44	const CssmData attrName,
45	const CssmData attrValue) :
46		ItemImpl(CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE,
47			reinterpret_cast<SecKeychainAttributeList *>(NULL),
48			0, NULL),
49		mRecordType(recordType),
50		mItemID(Allocator::standard(), itemID.Data, itemID.Length),
51		mAttrName(Allocator::standard(), attrName.Data, attrName.Length),
52		mAttrValue(Allocator::standard(), attrValue.Data, attrValue.Length)
53{
54	setupAttrs();
55}
56
57// db item contstructor
58ExtendedAttribute::ExtendedAttribute(
59	const Keychain &keychain,
60	const PrimaryKey &primaryKey,
61	const CssmClient::DbUniqueRecord &uniqueId) :
62		ItemImpl(keychain, primaryKey, uniqueId),
63		mRecordType(0),
64		mItemID(Allocator::standard()),
65		mAttrName(Allocator::standard()),
66		mAttrValue(Allocator::standard())
67{
68
69}
70
71// PrimaryKey item contstructor
72ExtendedAttribute::ExtendedAttribute(
73	const Keychain &keychain,
74	const PrimaryKey &primaryKey) :
75		ItemImpl(keychain, primaryKey),
76		mRecordType(0),
77		mItemID(Allocator::standard()),
78		mAttrName(Allocator::standard()),
79		mAttrValue(Allocator::standard())
80{
81
82}
83
84ExtendedAttribute* ExtendedAttribute::make(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
85{
86	ExtendedAttribute* ea = new ExtendedAttribute(keychain, primaryKey, uniqueId);
87	keychain->addItem(primaryKey, ea);
88	return ea;
89}
90
91
92
93ExtendedAttribute* ExtendedAttribute::make(const Keychain &keychain, const PrimaryKey &primaryKey)
94{
95	ExtendedAttribute* ea = new ExtendedAttribute(keychain, primaryKey);
96	keychain->addItem(primaryKey, ea);
97	return ea;
98}
99
100
101
102// copy - required due to Item's weird constructor/vendor
103ExtendedAttribute::ExtendedAttribute(
104	ExtendedAttribute &extendedAttr) :
105		ItemImpl(extendedAttr),
106		mRecordType(extendedAttr.mRecordType),
107		mItemID(Allocator::standard()),
108		mAttrName(Allocator::standard()),
109		mAttrValue(Allocator::standard())
110{
111	// CssmData cd = extendedAttr.mItemID;
112	mItemID.copy(extendedAttr.mItemID);
113	// cd = extendedAttr.mAttrName;
114	mAttrName.copy(extendedAttr.mAttrName);
115	// cd = extendedAttr.mAttrValue;
116	mAttrValue.copy(extendedAttr.mAttrValue);
117	setupAttrs();
118}
119
120ExtendedAttribute::~ExtendedAttribute() throw()
121{
122
123}
124
125PrimaryKey
126ExtendedAttribute::add(Keychain &keychain)
127{
128	StLock<Mutex>_(mMutex);
129	// If we already have a Keychain we can't be added.
130	if (mKeychain)
131		MacOSError::throwMe(errSecDuplicateItem);
132
133	SInt64 date;
134	CSSMDateTimeUtils::GetCurrentMacLongDateTime(date);
135	CssmDbAttributeInfo attrInfo(kSecModDateItemAttr, CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE);
136	setAttribute(attrInfo, date);
137
138	Db db(keychain->database());
139	// add the item to the (regular) db
140	try
141	{
142		mUniqueId = db->insert(CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE, mDbAttributes.get(), mData.get());
143	}
144	catch (const CssmError &e)
145	{
146		if (e.osStatus() != CSSMERR_DL_INVALID_RECORDTYPE)
147			throw;
148
149		/*
150		 * First exposure of this keychain to the extended attribute record type.
151		 * Create the relation and try again.
152		 */
153		db->createRelation(CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE,
154			"CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE",
155			Schema::ExtendedAttributeSchemaAttributeCount,
156			Schema::ExtendedAttributeSchemaAttributeList,
157			Schema::ExtendedAttributeSchemaIndexCount,
158			Schema::ExtendedAttributeSchemaIndexList);
159		keychain->keychainSchema()->didCreateRelation(
160			CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE,
161			"CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE",
162			Schema::ExtendedAttributeSchemaAttributeCount,
163			Schema::ExtendedAttributeSchemaAttributeList,
164			Schema::ExtendedAttributeSchemaIndexCount,
165			Schema::ExtendedAttributeSchemaIndexList);
166
167		mUniqueId = db->insert(CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE, mDbAttributes.get(), mData.get());
168	}
169
170	mPrimaryKey = keychain->makePrimaryKey(CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE, mUniqueId);
171    mKeychain = keychain;
172
173	return mPrimaryKey;
174}
175
176/* set up DB attrs based on member vars */
177void ExtendedAttribute::setupAttrs()
178{
179	StLock<Mutex>_(mMutex);
180	CssmDbAttributeInfo attrInfo1(kExtendedAttrRecordTypeAttr, CSSM_DB_ATTRIBUTE_FORMAT_UINT32);
181	setAttribute(attrInfo1, (uint32)mRecordType);
182	CssmData cd = mItemID;
183	CssmDbAttributeInfo attrInfo2(kExtendedAttrItemIDAttr, CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
184	setAttribute(attrInfo2, cd);
185	cd = mAttrName;
186	CssmDbAttributeInfo attrInfo3(kExtendedAttrAttributeNameAttr, CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
187	setAttribute(attrInfo3, cd);
188	cd = mAttrValue;
189	CssmDbAttributeInfo attrInfo4(kExtendedAttrAttributeValueAttr, CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
190	setAttribute(attrInfo4, cd);
191}
192
193
194