]> git.saurik.com Git - apple/security.git/blob - securityd/src/tokenacl.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / securityd / src / tokenacl.cpp
1 /*
2 * Copyright (c) 2004-2007,2013 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
25 //
26 // tokenacl - Token-based ACL implementation
27 //
28 #include "tokenacl.h"
29 #include "tokend.h"
30 #include "token.h"
31 #include "tokendatabase.h"
32 #include "agentquery.h"
33 #include <security_utilities/trackingallocator.h>
34 #include <security_cdsa_utilities/cssmbridge.h>
35
36
37 //
38 // A TokenAcl initializes to "invalid, needs update".
39 // Note how our Token will start its ResetGeneration at 1, while we start at zero.
40 //
41 TokenAcl::TokenAcl()
42 : mLastReset(0)
43 {
44 }
45
46
47 //
48 // Instantiate is called (by the ACL machinery core) before this ACL object's
49 // contents are used in any way. Here is where we fetch the ACL data from tokend
50 // (if we haven't got it yet).
51 //
52 void TokenAcl::instantiateAcl()
53 {
54 if (token().resetGeneration(mLastReset))
55 return;
56
57 secinfo("tokenacl", "%p loading ACLs from tokend", this);
58
59 // read owner
60 AclOwnerPrototype *owner = NULL;
61 token().tokend().getOwner(aclKind(), tokenHandle(), owner);
62 assert(owner);
63
64 // read entries
65 uint32 count;
66 AclEntryInfo *infos;
67 token().tokend().getAcl(aclKind(), tokenHandle(), NULL, count, infos);
68
69 // commit to setting the ACL data
70 ObjectAcl::owner(*owner);
71 ObjectAcl::entries(count, infos);
72
73 // and if we actually made it to here...
74 mLastReset = token().resetGeneration();
75 }
76
77
78 //
79 // The ACL machinery core calls this after successfully making changes to our ACL.
80 //
81 void TokenAcl::changedAcl()
82 {
83 }
84
85
86 //
87 // CSSM-layer read gates. This accesses a cached version prepared in our instantiateAcl().
88 //
89 void TokenAcl::getOwner(AclOwnerPrototype &owner)
90 {
91 ObjectAcl::cssmGetOwner(owner);
92 }
93
94 void TokenAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls)
95 {
96 ObjectAcl::cssmGetAcl(tag, count, acls);
97 }
98
99
100 //
101 // CSSM-layer write gates.
102 // This doesn't directly write to the local ObjectAcl at all. The call is relayed to
103 // tokend, and the resulting ACL is being re-read when next needed.
104 //
105 void TokenAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred, Database *db)
106 {
107 // changeAcl from/to a PIN (source) ACL has special UI handling here
108 // @@@ this is an ad-hoc hack; general solution awaits the ACL machinery rebuild later
109 instantiateAcl(); // (redundant except in error cases)
110 if (TokenDatabase *tokenDb = dynamic_cast<TokenDatabase *>(db))
111 if (edit.mode() == CSSM_ACL_EDIT_MODE_REPLACE)
112 if (const AclEntryInput *input = edit.newEntry()) {
113 if (unsigned pin = pinFromAclTag(input->proto().tag())) {
114 // assume this is a PIN change request
115 pinChange(pin, edit.handle(), *tokenDb);
116 invalidateAcl();
117 return;
118 }
119 }
120
121 // hand the request off to tokend to do as it will
122 token().tokend().changeAcl(aclKind(), tokenHandle(), Required(cred), edit);
123 invalidateAcl();
124 }
125
126 void TokenAcl::changeOwner(const AclOwnerPrototype &newOwner,
127 const AccessCredentials *cred, Database *db)
128 {
129 token().tokend().changeOwner(aclKind(), tokenHandle(), Required(cred), newOwner);
130 invalidateAcl();
131 }
132
133
134 //
135 // Ad-hoc PIN change processing.
136 // This cooks a suitable changeAcl call to tokend, ad hoc.
137 // It does NOT complete the originating request; it replaces it completely.
138 // (Completion processing requires not-yet-implemented ACL machine UI coalescing features.)
139 //
140 class QueryNewPin : public QueryNewPassphrase {
141 public:
142 QueryNewPin(unsigned int pinn, CSSM_ACL_HANDLE h, TokenDatabase &db, Reason reason)
143 : QueryNewPassphrase(db, reason), pin(pinn), handle(h) { }
144
145 const unsigned int pin;
146 const CSSM_ACL_HANDLE handle;
147
148 Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase);
149 };
150
151 SecurityAgent::Reason QueryNewPin::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
152 {
153 assert(oldPassphrase); // we don't handle the new-pin case (yet)
154
155 // form a changeAcl query and send it to tokend
156 try {
157 TrackingAllocator alloc(Allocator::standard());
158 AclEntryPrototype proto(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD,
159 new(alloc) ListElement(passphrase)
160 ));
161 proto.authorization() = AuthorizationGroup(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), alloc);
162 char pintag[20]; sprintf(pintag, "PIN%d", pin);
163 proto.tag(pintag);
164 AclEntryInput input(proto);
165 AclEdit edit(CSSM_ACL_EDIT_MODE_REPLACE, handle, &input);
166 AutoCredentials cred(alloc);
167 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
168 new(alloc) ListElement(*oldPassphrase));
169 safer_cast<TokenDatabase &>(database).token().tokend().changeAcl(dbAcl, noDb, cred, edit);
170 return SecurityAgent::noReason;
171 } catch (const CssmError &err) {
172 switch (err.error) {
173 default:
174 return SecurityAgent::unknownReason;
175 }
176 } catch (...) {
177 return SecurityAgent::unknownReason;
178 }
179 }
180
181 void TokenAcl::pinChange(unsigned int pin, CSSM_ACL_HANDLE handle, TokenDatabase &database)
182 {
183 QueryNewPin query(pin, handle, database, SecurityAgent::changePassphrase);
184 query.inferHints(Server::process());
185 CssmAutoData newPin(Allocator::standard(Allocator::sensitive));
186 CssmAutoData oldPin(Allocator::standard(Allocator::sensitive));
187 switch (query(oldPin, newPin)) {
188 case SecurityAgent::noReason: // worked
189 return;
190 default:
191 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
192 }
193 }