2 * Copyright (c) 2000-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@
26 // process - track a single client process and its belongings
31 #include "tempdatabase.h"
32 #include "authority.h"
33 #include "child.h" // ServerChild (really UnixPlusPlus::Child)::find()
35 #include <security_utilities/logging.h> //@@@ debug only
36 #include "agentquery.h"
40 // Construct a Process object.
42 Process::Process(TaskPort taskPort
, const ClientSetupInfo
*info
, const CommonCriteria::AuditToken
&audit
)
43 : mTaskPort(taskPort
), mByteFlipped(false), mPid(audit
.pid()), mUid(audit
.euid()), mGid(audit
.egid())
46 parent(Session::find(audit
.sessionId(), true));
48 // let's take a look at our wannabe client...
49 if (mTaskPort
.pid() != mPid
) {
50 secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d)",
51 mPid
, mTaskPort
.port(), mTaskPort
.pid());
52 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED
); // you lied!
56 ClientIdentification::setup(this->pid());
58 // NB: ServerChild::find() should only be used to determine
59 // *existence*. Don't use the returned Child object for anything else,
60 // as it is not protected against its underlying process's destruction.
61 if (this->pid() == getpid() // called ourselves (through some API). Do NOT record this as a "dirty" transaction
62 || ServerChild::find
<ServerChild
>(this->pid())) // securityd's child; do not mark this txn dirty
63 VProc::Transaction::deactivate();
65 if (SECURITYD_CLIENT_NEW_ENABLED())
66 SECURITYD_CLIENT_NEW(this, this->pid(), &this->session(),
67 (char *)codePath(this->processCode()).c_str(), taskPort
, mUid
, mGid
, mByteFlipped
);
72 // Screen a process setup request for an existing process.
73 // This means the client has requested intialization even though we remember having
74 // talked to it in the past. This could either be an exec(2), or the client could just
75 // have forgotten all about its securityd client state. Or it could be an attack...
77 void Process::reset(TaskPort taskPort
, const ClientSetupInfo
*info
, const CommonCriteria::AuditToken
&audit
)
79 if (taskPort
!= mTaskPort
) {
80 secdebug("SS", "Process %p(%d) reset mismatch (tp %d-%d)",
81 this, pid(), taskPort
.port(), mTaskPort
.port());
82 //@@@ CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); // liar
85 CFCopyRef
<SecCodeRef
> oldCode
= processCode();
87 ClientIdentification::setup(this->pid()); // re-constructs processCode()
88 if (CFEqual(oldCode
, processCode())) {
89 SECURITYD_CLIENT_RESET_AMNESIA(this);
91 SECURITYD_CLIENT_RESET_FULL(this);
92 CodeSigningHost::reset();
98 // Common set processing
100 void Process::setup(const ClientSetupInfo
*info
)
102 // process setup info
105 if (info
->order
== 0x1234) { // right side up
106 pversion
= info
->version
;
107 mByteFlipped
= false;
108 } else if (info
->order
== 0x34120000) { // flip side up
109 pversion
= flip(info
->version
);
111 } else // non comprende
112 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
114 // check wire protocol version
115 if (pversion
!= SSPROTOVERSION
)
116 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
121 // Clean up a Process object
125 SECURITYD_CLIENT_RELEASE(this, this->pid());
127 // tell all our authorizations that we're gone
128 IFDEBUG(if (!mAuthorizations
.empty())
129 secdebug("SS", "Process %p(%d) clearing %d authorizations",
130 this, mPid
, int(mAuthorizations
.size())));
131 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
132 it
!= mAuthorizations
.end(); ) {
133 AuthorizationToken
*auth
= *it
;
134 while (++it
!= mAuthorizations
.end() && *it
== auth
) ; // Skip duplicates
135 if (auth
->endProcess(*this))
139 // release our name for the process's task port
146 StLock
<Mutex
> _(*this);
148 // release local temp store
151 // standard kill processing
156 Session
& Process::session() const
158 return parent
<Session
>();
162 void Process::checkSession(const audit_token_t
&auditToken
)
164 AuditToken
audit(auditToken
);
165 if (audit
.sessionId() != this->session().sessionId())
166 this->changeSession(audit
.sessionId());
170 LocalDatabase
&Process::localStore()
172 StLock
<Mutex
> _(*this);
174 mLocalStore
= new TempDatabase(*this);
178 Key
*Process::makeTemporaryKey(const CssmKey
&key
, CSSM_KEYATTR_FLAGS moreAttributes
,
179 const AclEntryPrototype
*owner
)
181 return safer_cast
<TempDatabase
&>(localStore()).makeKey(key
, moreAttributes
, owner
);
186 // Change the session of a process.
187 // This is the result of SessionCreate from a known process client.
189 void Process::changeSession(Session::SessionId sessionId
)
192 parent(Session::find(sessionId
, true));
193 SECURITYD_CLIENT_CHANGE_SESSION(this, &this->session());
198 // Authorization set maintainance
200 void Process::addAuthorization(AuthorizationToken
*auth
)
203 StLock
<Mutex
> _(*this);
204 mAuthorizations
.insert(auth
);
205 auth
->addProcess(*this);
208 void Process::checkAuthorization(AuthorizationToken
*auth
)
211 StLock
<Mutex
> _(*this);
212 if (mAuthorizations
.find(auth
) == mAuthorizations
.end())
213 MacOSError::throwMe(errAuthorizationInvalidRef
);
216 bool Process::removeAuthorization(AuthorizationToken
*auth
)
219 StLock
<Mutex
> _(*this);
220 // we do everything with a single set lookup call...
221 typedef AuthorizationSet::iterator Iter
;
222 Iter it
= mAuthorizations
.lower_bound(auth
);
224 if (it
== mAuthorizations
.end() || auth
!= *it
) {
227 Iter next
= it
; ++next
; // following element
228 isLast
= (next
== mAuthorizations
.end()) || auth
!= *next
;
229 mAuthorizations
.erase(it
); // remove first match
232 if (auth
->endProcess(*this)) // ... tell it to remove us,
233 return true; // ... and tell the caller
235 return false; // keep the auth; it's still in use
240 // Debug dump support
242 #if defined(DEBUGDUMP)
244 void Process::dumpNode()
246 PerProcess::dumpNode();
248 Debug::dump(" FLIPPED");
249 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
250 mTaskPort
.port(), mPid
, mUid
, mGid
);
251 CodeSigningHost::dump();
252 ClientIdentification::dump();