2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 * AuthorizationMechEval.cpp
27 #include "AuthorizationMechEval.h"
28 #include <security_utilities/logging.h>
29 #include <bsm/audit_uevents.h>
30 #include <security_utilities/ccaudit.h>
32 namespace Authorization
{
34 AgentMechanismRef::AgentMechanismRef(const AuthHostType type
, Session
&session
) :
35 RefPointer
<QueryInvokeMechanism
>(new QueryInvokeMechanism(type
, session
)) {}
37 // we need the vector<string> of mechanisms
38 AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid
, Session
& session
, const vector
<string
>& inMechanisms
) :
39 mMechanisms(inMechanisms
), mClientUid(uid
), mSession(session
)
45 AgentMechanismEvaluator::run(const AuthValueVector
&inArguments
, const AuthItemSet
&inHints
, const AuthorizationToken
&auth
)
47 const AuthItemSet
&inContext
= const_cast<AuthorizationToken
&>(auth
).infoSet();
49 // add process specifics to context?
51 vector
<std::string
>::const_iterator currentMechanism
= mMechanisms
.begin();
53 AuthorizationResult result
= kAuthorizationResultAllow
;
55 AuthItemSet hints
= inHints
;
56 AuthItemSet context
= inContext
;
57 // add saved-off sticky context values to context for evaluation
58 context
.insert(mStickyContext
.begin(), mStickyContext
.end());
60 while ( (result
== kAuthorizationResultAllow
) &&
61 (currentMechanism
!= mMechanisms
.end()) ) // iterate mechanisms
63 ClientMap::iterator iter
= mClients
.find(*currentMechanism
);
64 if (iter
== mClients
.end())
66 string::size_type extPlugin
= currentMechanism
->find(':');
67 if (extPlugin
!= string::npos
)
69 // no whitespace removal
70 string
pluginIn(currentMechanism
->substr(0, extPlugin
));
71 string mechanismIn
, authhostIn
;
73 string::size_type extMechanism
= currentMechanism
->rfind(',');
74 AuthHostType hostType
= securityAgent
;
76 if (extMechanism
!= string::npos
)
78 if (extMechanism
< extPlugin
)
79 return errAuthorizationInternal
;
81 mechanismIn
= currentMechanism
->substr(extPlugin
+ 1, extMechanism
- extPlugin
- 1);
82 authhostIn
= currentMechanism
->substr(extMechanism
+ 1);
83 if (authhostIn
== "privileged")
84 hostType
= privilegedAuthHost
;
87 mechanismIn
= currentMechanism
->substr(extPlugin
+ 1);
89 secdebug("AuthEvalMech", "external mechanism %s:%s", pluginIn
.c_str(), mechanismIn
.c_str());
91 AgentMechanismRef
client(hostType
, mSession
);
92 client
->initialize(pluginIn
, mechanismIn
, inArguments
);
93 mClients
.insert(ClientMap::value_type(*currentMechanism
, client
));
95 else if (*currentMechanism
== "authinternal")
97 secdebug("AuthEvalMech", "performing authentication");
98 result
= authinternal(context
);
100 AuthItem
*rightItem
= hints
.find(AGENT_HINT_AUTHORIZE_RIGHT
);
101 string right
= (rightItem
== NULL
) ? string("<unknown right>") : rightItem
->stringValue();
102 CommonCriteria::AuditRecord
auditrec(auth
.creatorAuditToken());
103 if (kAuthorizationResultAllow
== result
)
104 auditrec
.submit(AUE_ssauthint
, CommonCriteria::errNone
, right
.c_str());
105 else // kAuthorizationResultDeny
106 auditrec
.submit(AUE_ssauthint
, CommonCriteria::errInvalidCredential
, right
.c_str());
108 else if (*currentMechanism
== "push_hints_to_context")
110 secdebug("AuthEvalMech", "evaluate push_hints_to_context");
111 // doesn't block evaluation, ever
112 result
= kAuthorizationResultAllow
;
116 return errAuthorizationInternal
;
119 iter
= mClients
.find(*currentMechanism
);
120 if (iter
!= mClients
.end())
124 AgentMechanismRef
&client
= iter
->second
;
125 client
->run(inArguments
, hints
, context
, &result
);
127 bool interrupted
= false;
128 while (client
->state() == client
->current
)
130 // check for interruption
131 vector
<std::string
>::const_iterator checkMechanism
= mMechanisms
.begin();
132 while (*checkMechanism
!= *currentMechanism
) {
133 ClientMap::iterator iter2
= mClients
.find(*checkMechanism
);
134 if (iter2
->second
->state() == iter2
->second
->interrupting
)
136 client
->deactivate();
137 // nothing can happen until the client mechanism returns control to us
138 while (client
->state() == client
->deactivating
)
141 secdebug("AuthEvalMech", "evaluate(%s) interrupted by %s.", (iter
->first
).c_str(), (iter2
->first
).c_str());
144 hints
= iter2
->second
->inHints();
145 context
= iter2
->second
->inContext();
146 currentMechanism
= checkMechanism
;
152 if (client
->state() == client
->current
)
158 // clear reason for restart from interrupt
159 uint32_t reason
= SecurityAgent::worldChanged
;
160 AuthItemRef
retryHint(AGENT_HINT_RETRY_REASON
, AuthValueOverlay(sizeof(reason
), &reason
));
161 hints
.erase(retryHint
); hints
.insert(retryHint
); // replace
163 result
= kAuthorizationResultAllow
;
167 secdebug("AuthEvalMech", "evaluate(%s) with result: %lu.", (iter
->first
).c_str(), result
);
170 secdebug("AuthEvalMech", "exception during evaluate(%s).", (iter
->first
).c_str());
171 result
= kAuthorizationResultUndefined
;
175 if (result
== kAuthorizationResultAllow
)
179 if ((result
== kAuthorizationResultUserCanceled
) ||
180 (result
== kAuthorizationResultAllow
))
184 // only make non-sticky context values available externally
185 AuthItemSet::const_iterator end
= context
.end();
186 for (AuthItemSet::const_iterator it
= context
.begin(); it
!= end
; ++it
) {
187 const AuthItemRef
&item
= *it
;
188 if (item
->flags() != kAuthorizationContextFlagSticky
)
189 mContext
.insert(item
);
192 else if (result
== kAuthorizationResultDeny
)
194 // save off sticky values in context
195 mStickyContext
.clear();
196 AuthItemSet::const_iterator end
= context
.end();
197 for (AuthItemSet::const_iterator it
= context
.begin(); it
!= end
; ++it
) {
198 const AuthItemRef
&item
= *it
;
199 if (item
->flags() == kAuthorizationContextFlagSticky
)
200 mStickyContext
.insert(item
);
204 // convert AuthorizationResult to OSStatus
207 case kAuthorizationResultDeny
:
208 return errAuthorizationDenied
;
209 case kAuthorizationResultUserCanceled
:
210 return errAuthorizationCanceled
;
211 case kAuthorizationResultAllow
:
212 return errAuthorizationSuccess
;
214 return errAuthorizationInternal
;
218 AuthorizationResult
AgentMechanismEvaluator::authinternal(AuthItemSet
&context
)
220 secdebug("AuthEvalMech", "evaluate authinternal");
222 AuthItemSet::iterator found
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername
) );
223 if (found
== context
.end())
225 string
username(static_cast<const char *>((*found
)->value().data
), (*found
)->value().length
);
226 secdebug("AuthEvalMech", "found username");
227 found
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword
) );
228 if (found
== context
.end())
230 string
password(static_cast<const char *>((*found
)->value().data
), (*found
)->value().length
);
231 secdebug("AuthEvalMech", "found password");
233 Credential
newCredential(username
, password
, true); // create a new shared credential
234 if (newCredential
->isValid())
235 return kAuthorizationResultAllow
;
239 return kAuthorizationResultDeny
;
244 AgentMechanismEvaluator::commonHints(const AuthorizationToken &auth)
250 } /* namespace Authorization */