]> git.saurik.com Git - apple/security.git/blob - SecurityServer/acl_keychain.cpp
Security-28.tar.gz
[apple/security.git] / SecurityServer / acl_keychain.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 // acl_keychain - a subject type for the protected-path
21 // keychain prompt interaction model.
22 //
23 // Arguments in list form:
24 // list[1] = CssmData: Descriptive String (presented to user in protected dialogs)
25 //
26 // Some notes on Acl Update Triggers:
27 // When the user checks the "don't ask me again" checkbox in the access confirmation
28 // dialog, we respond by returning the informational error code
29 // CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT, and setting a count-down trigger
30 // in the connection. The caller is entitled to bypass our dialog (it succeeds
31 // automatically) within the next few (Connection::aclUpdateTriggerLimit == 2)
32 // requests, in order to update the object's ACL as requested. It must then retry
33 // the original access operation (which will presumably pass because of that edit).
34 // These are the rules: for the trigger to apply, the access must be to the same
35 // object, from the same connection, and within the next two accesses.
36 // (Currently, these are for a "get acl" and the "change acl" calls.)
37 // Damage Control Department: The worst this mechanism could do, if subverted, is
38 // to bypass our confirmation dialog (making it appear to succeed to the ACL validation).
39 // But that is exactly what the "don't ask me again" checkbox is meant to do, so any
40 // subversion would be based on a (perhaps intentional) miscommunication between user
41 // and client process as to what the user consents not to be asked about (any more).
42 // The user can always examine the resulting ACL (in Keychain Access or elsewhere), and
43 // edit it to suit her needs.
44 //
45 #ifdef __MWERKS__
46 #define _CPP_ACL_KEYCHAIN
47 #endif
48
49 #include "acl_keychain.h"
50 #include "agentquery.h"
51 #include "acls.h"
52 #include "connection.h"
53 #include "xdatabase.h"
54 #include "server.h"
55 #include <Security/debugging.h>
56 #include <algorithm>
57
58
59 //
60 // Validate a credential set against this subject.
61 //
62 bool KeychainPromptAclSubject::validate(const AclValidationContext &context,
63 const TypedList &sample) const
64 {
65 SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>();
66 if (env) {
67 // check for special ACL-update override
68 if (context.authorization() == CSSM_ACL_AUTHORIZATION_CHANGE_ACL
69 && Server::connection().aclWasSetForUpdateTrigger(env->acl)) {
70 debug("kcacl", "honoring acl update trigger for %p(%s)",
71 &env->acl, description.c_str());
72 return true;
73 }
74
75 // ask the user
76 QueryKeychainUse query;
77 const Database *db = env->database();
78 query((db ? db->dbName() : NULL), description.c_str(), context.authorization());
79 if (query.continueGrantingToCaller) {
80 // mark for special ACL-update override (really soon) later
81 Server::connection().setAclUpdateTrigger(env->acl);
82 debug("kcacl", "setting acl update trigger for %p(%s)",
83 &env->acl, description.c_str());
84 // fail with prejudice (caller will retry)
85 CssmError::throwMe(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT);
86 }
87 return query.allowAccess;
88 }
89 return false; // default to deny without prejudice
90 }
91
92
93 //
94 // Make a copy of this subject in CSSM_LIST form
95 //
96 CssmList KeychainPromptAclSubject::toList(CssmAllocator &alloc) const
97 {
98 return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT,
99 new(alloc) ListElement(alloc, description));
100 }
101
102
103 //
104 // Create a PasswordAclSubject
105 //
106 KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(const TypedList &list) const
107 {
108 ListElement *params[1];
109 crack(list, 1, params, CSSM_LIST_ELEMENT_DATUM);
110 return new KeychainPromptAclSubject(*params[0]);
111 }
112
113 KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(Reader &pub, Reader &) const
114 {
115 const char *description; pub(description);
116 return new KeychainPromptAclSubject(description);
117 }
118
119 KeychainPromptAclSubject::KeychainPromptAclSubject(string descr)
120 : SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT),
121 description(descr)
122 {
123 }
124
125
126 //
127 // Export the subject to a memory blob
128 //
129 void KeychainPromptAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
130 {
131 pub.insert(description.size() + 1);
132 }
133
134 void KeychainPromptAclSubject::exportBlob(Writer &pub, Writer &priv)
135 {
136 pub(description.c_str());
137 }
138
139
140 #ifdef DEBUGDUMP
141
142 void KeychainPromptAclSubject::debugDump() const
143 {
144 Debug::dump("KeychainPrompt:%s", description.c_str());
145 }
146
147 #endif //DEBUGDUMP