]> git.saurik.com Git - apple/securityd.git/blob - src/tokenacl.cpp
securityd-26674.tar.gz
[apple/securityd.git] / src / tokenacl.cpp
1 /*
2 * Copyright (c) 2004 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 //
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 secdebug("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 unsigned int pin;
114 if (sscanf(input->proto().s_tag().c_str(), "PIN%d", &pin) == 1) {
115 // assume this is a PIN change request
116 pinChange(pin, edit.handle(), *tokenDb);
117 invalidateAcl();
118 return;
119 }
120 }
121
122 // hand the request off to tokend to do as it will
123 token().tokend().changeAcl(aclKind(), tokenHandle(), Required(cred), edit);
124 invalidateAcl();
125 }
126
127 void TokenAcl::changeOwner(const AclOwnerPrototype &newOwner,
128 const AccessCredentials *cred, Database *db)
129 {
130 token().tokend().changeOwner(aclKind(), tokenHandle(), Required(cred), newOwner);
131 invalidateAcl();
132 }
133
134
135 //
136 // Ad-hoc PIN change processing.
137 // This cooks a suitable changeAcl call to tokend, ad hoc.
138 // It does NOT complete the originating request; it replaces it completely.
139 // (Completion processing requires not-yet-implemented ACL machine UI coalescing features.)
140 //
141 class QueryNewPin : public QueryNewPassphrase {
142 public:
143 QueryNewPin(unsigned int pinn, CSSM_ACL_HANDLE h, TokenDatabase &db, Reason reason)
144 : QueryNewPassphrase(db, reason), pin(pinn), handle(h) { }
145
146 const unsigned int pin;
147 const CSSM_ACL_HANDLE handle;
148
149 Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase);
150 };
151
152 SecurityAgent::Reason QueryNewPin::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
153 {
154 assert(oldPassphrase); // we don't handle the new-pin case (yet)
155
156 // form a changeAcl query and send it to tokend
157 try {
158 TrackingAllocator alloc(Allocator::standard());
159 AclEntryPrototype proto(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD,
160 new(alloc) ListElement(passphrase)
161 ));
162 proto.authorization() = AuthorizationGroup(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), alloc);
163 char pintag[10]; sprintf(pintag, "PIN%d", pin);
164 proto.tag(pintag);
165 AclEntryInput input(proto);
166 AclEdit edit(CSSM_ACL_EDIT_MODE_REPLACE, handle, &input);
167 AutoCredentials cred(alloc);
168 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
169 new(alloc) ListElement(*oldPassphrase));
170 safer_cast<TokenDatabase &>(database).token().tokend().changeAcl(dbAcl, noDb, cred, edit);
171 return SecurityAgent::noReason;
172 } catch (const CssmError &err) {
173 switch (err.error) {
174 default:
175 return SecurityAgent::unknownReason;
176 }
177 } catch (...) {
178 return SecurityAgent::unknownReason;
179 }
180 }
181
182 void TokenAcl::pinChange(unsigned int pin, CSSM_ACL_HANDLE handle, TokenDatabase &database)
183 {
184 QueryNewPin query(pin, handle, database, SecurityAgent::changePassphrase);
185 query.inferHints(Server::process());
186 CssmAutoData newPin(Allocator::standard(Allocator::sensitive));
187 switch (query(newPin)) {
188 case SecurityAgent::noReason: // worked
189 return;
190 default:
191 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
192 }
193 }