2 * Copyright (c) 2003-2009 Apple 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 "ccaudit_extensions.h"
32 namespace Authorization
{
34 using namespace CommonCriteria::Securityd
;
36 AgentMechanismRef::AgentMechanismRef(const AuthHostType type
, Session
&session
) :
37 RefPointer
<QueryInvokeMechanism
>(new QueryInvokeMechanism(type
, session
)) {}
39 // we need the vector<string> of mechanisms
40 AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid
, Session
& session
, const vector
<string
>& inMechanisms
) :
41 mMechanisms(inMechanisms
), mClientUid(uid
), mSession(session
)
47 AgentMechanismEvaluator::run(const AuthValueVector
&inArguments
, const AuthItemSet
&inHints
, const AuthorizationToken
&auth
)
49 AuthMechLogger
logger(auth
.creatorAuditToken(), AUE_ssauthmech
);
50 string rightName
= "<unknown right>"; // for syslog
52 // as of 10.6, the first item in inArguments should be the name of the
53 // requested right, for auditing
56 AuthorizationValue val
= inArguments
.at(0)->value();
57 string
tmpstr(static_cast<const char *>(val
.data
), val
.length
);
58 logger
.setRight(tmpstr
);
64 const AuthItemSet
&inContext
= const_cast<AuthorizationToken
&>(auth
).infoSet();
66 // add process specifics to context?
68 vector
<std::string
>::const_iterator currentMechanism
= mMechanisms
.begin();
70 AuthorizationResult result
= kAuthorizationResultAllow
;
72 AuthItemSet hints
= inHints
;
73 AuthItemSet context
= inContext
;
74 // add saved-off sticky context values to context for evaluation
75 context
.insert(mStickyContext
.begin(), mStickyContext
.end());
77 while ( (result
== kAuthorizationResultAllow
) &&
78 (currentMechanism
!= mMechanisms
.end()) ) // iterate mechanisms
80 SECURITYD_AUTH_MECH(&auth
, (char *)(*currentMechanism
).c_str());
82 // set up the audit message
83 logger
.setCurrentMechanism(*currentMechanism
);
86 ClientMap::iterator iter
= mClients
.find(*currentMechanism
);
87 if (iter
== mClients
.end())
89 string::size_type extPlugin
= currentMechanism
->find(':');
90 if (extPlugin
!= string::npos
)
92 // no whitespace removal
93 string
pluginIn(currentMechanism
->substr(0, extPlugin
));
94 string mechanismIn
, authhostIn
;
96 string::size_type extMechanism
= currentMechanism
->rfind(',');
97 AuthHostType hostType
= securityAgent
;
99 if (extMechanism
!= string::npos
)
101 if (extMechanism
< extPlugin
)
103 string auditMsg
= "badly formed mechanism name; ending rule evaluation";
104 Syslog::alert("Right '%s', mech '%s': %s", rightName
.c_str(), (*currentMechanism
).c_str(), auditMsg
.c_str());
105 logger
.logFailure(auditMsg
);
106 return errAuthorizationInternal
;
109 mechanismIn
= currentMechanism
->substr(extPlugin
+ 1, extMechanism
- extPlugin
- 1);
110 authhostIn
= currentMechanism
->substr(extMechanism
+ 1);
111 if (authhostIn
== "privileged")
112 hostType
= privilegedAuthHost
;
115 mechanismIn
= currentMechanism
->substr(extPlugin
+ 1);
117 secdebug("AuthEvalMech", "external mechanism %s:%s", pluginIn
.c_str(), mechanismIn
.c_str());
119 AgentMechanismRef
client(hostType
, mSession
);
120 client
->initialize(pluginIn
, mechanismIn
, inArguments
);
121 mClients
.insert(ClientMap::value_type(*currentMechanism
, client
));
123 else if (*currentMechanism
== "authinternal")
125 secdebug("AuthEvalMech", "performing authentication");
126 result
= authinternal(context
);
128 if (kAuthorizationResultAllow
== result
)
132 else // kAuthorizationResultDeny
137 else if (*currentMechanism
== "push_hints_to_context")
139 secdebug("AuthEvalMech", "evaluate push_hints_to_context");
141 // doesn't block evaluation, ever
142 result
= kAuthorizationResultAllow
;
147 string auditMsg
= "unknown mechanism; ending rule evaluation";
148 Syslog::alert("Right '%s', mech '%s': %s", rightName
.c_str(), (*currentMechanism
).c_str(), auditMsg
.c_str());
149 logger
.logFailure(auditMsg
);
150 return errAuthorizationInternal
;
154 iter
= mClients
.find(*currentMechanism
);
155 if (iter
!= mClients
.end())
159 AgentMechanismRef
&client
= iter
->second
;
160 client
->run(inArguments
, hints
, context
, &result
);
162 bool interrupted
= false;
163 while (client
->state() == client
->current
)
165 // check for interruption
166 vector
<std::string
>::const_iterator checkMechanism
= mMechanisms
.begin();
167 while (*checkMechanism
!= *currentMechanism
) {
168 ClientMap::iterator iter2
= mClients
.find(*checkMechanism
);
169 if (iter2
->second
->state() == iter2
->second
->interrupting
)
171 client
->deactivate();
172 // nothing can happen until the client mechanism returns control to us
173 while (client
->state() == client
->deactivating
)
176 string auditMsg
= "evaluation interrupted by ";
177 auditMsg
+= (iter2
->first
).c_str();
178 auditMsg
+= "; restarting evaluation there";
179 secdebug("AuthEvalMech", "%s", auditMsg
.c_str());
180 logger
.logInterrupt(auditMsg
);
183 hints
= iter2
->second
->inHints();
184 context
= iter2
->second
->inContext();
185 currentMechanism
= checkMechanism
;
191 if (client
->state() == client
->current
)
197 // clear reason for restart from interrupt
198 uint32_t reason
= SecurityAgent::worldChanged
;
199 AuthItemRef
retryHint(AGENT_HINT_RETRY_REASON
, AuthValueOverlay(sizeof(reason
), &reason
));
200 hints
.erase(retryHint
); hints
.insert(retryHint
); // replace
202 result
= kAuthorizationResultAllow
;
206 secdebug("AuthEvalMech", "evaluate(%s) with result: %u.", (iter
->first
).c_str(), (uint32_t)result
);
209 string auditMsg
= "exception during evaluation of ";
210 auditMsg
+= (iter
->first
).c_str();
211 secdebug("AuthEvalMech", "%s", auditMsg
.c_str());
212 logger
.logFailure(auditMsg
);
213 result
= kAuthorizationResultUndefined
;
217 if (result
== kAuthorizationResultAllow
)
224 if ((result
== kAuthorizationResultUserCanceled
) ||
225 (result
== kAuthorizationResultAllow
))
229 // only make non-sticky context values available externally
230 AuthItemSet::const_iterator end
= context
.end();
231 for (AuthItemSet::const_iterator it
= context
.begin(); it
!= end
; ++it
) {
232 const AuthItemRef
&item
= *it
;
233 if (item
->flags() != kAuthorizationContextFlagSticky
)
234 mContext
.insert(item
);
236 if (result
== kAuthorizationResultUserCanceled
)
237 logger
.logFailure(NULL
, errAuthorizationCanceled
);
239 else if (result
== kAuthorizationResultDeny
)
241 // save off sticky values in context
242 mStickyContext
.clear();
243 AuthItemSet::const_iterator end
= context
.end();
244 for (AuthItemSet::const_iterator it
= context
.begin(); it
!= end
; ++it
) {
245 const AuthItemRef
&item
= *it
;
246 if (item
->flags() == kAuthorizationContextFlagSticky
)
247 mStickyContext
.insert(item
);
252 // convert AuthorizationResult to OSStatus
255 case kAuthorizationResultDeny
:
256 return errAuthorizationDenied
;
257 case kAuthorizationResultUserCanceled
:
258 return errAuthorizationCanceled
;
259 case kAuthorizationResultAllow
:
260 return errAuthorizationSuccess
;
261 case kAuthorizationResultUndefined
:
262 return errAuthorizationInternal
;
265 Syslog::alert("Right '%s': unexpected error result (%u)", rightName
.c_str(), result
);
266 logger
.logFailure("unexpected error result", result
);
267 return errAuthorizationInternal
;
272 AuthorizationResult
AgentMechanismEvaluator::authinternal(AuthItemSet
&context
)
274 secdebug("AuthEvalMech", "evaluate authinternal");
276 AuthItemSet::iterator found
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername
) );
277 if (found
== context
.end())
279 string
username(static_cast<const char *>((*found
)->value().data
), (*found
)->value().length
);
280 secdebug("AuthEvalMech", "found username");
281 found
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword
) );
282 if (found
== context
.end())
284 string
password(static_cast<const char *>((*found
)->value().data
), (*found
)->value().length
);
285 secdebug("AuthEvalMech", "found password");
287 Credential
newCredential(username
, password
, true); // create a new shared credential
288 if (newCredential
->isValid())
289 return kAuthorizationResultAllow
;
293 return kAuthorizationResultDeny
;
298 AgentMechanismEvaluator::commonHints(const AuthorizationToken &auth)
304 } /* namespace Authorization */