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"
34 #include <security_utilities/logging.h> //@@@ debug only
35 #include "agentquery.h"
39 // Construct a Process object.
41 Process::Process(Port servicePort
, TaskPort taskPort
,
42 const ClientSetupInfo
*info
, const char *identity
, const CommonCriteria::AuditToken
&audit
)
43 : mTaskPort(taskPort
), mByteFlipped(false), mPid(audit
.pid()), mUid(audit
.euid()), mGid(audit
.egid())
46 parent(Session::find(servicePort
));
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) for %s",
51 mPid
, mTaskPort
.port(), mTaskPort
.pid(),
52 (identity
&& identity
[0]) ? identity
: "(unknown)");
53 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED
); // you lied!
57 ClientIdentification::setup(this->pid());
59 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
60 this, mPid
, mUid
, mGid
, &session(),
62 mByteFlipped
? "FLIP " : "",
63 (identity
&& identity
[0]) ? identity
: "(unknown)");
68 // Screen a process setup request for an existing process.
69 // This means the client has requested intialization even though we remember having
70 // talked to it in the past. This could either be an exec(2), or the client could just
71 // have forgotten all about its securityd client state. Or it could be an attack...
73 void Process::reset(Port servicePort
, TaskPort taskPort
,
74 const ClientSetupInfo
*info
, const char *identity
, const CommonCriteria::AuditToken
&audit
)
76 if (servicePort
!= session().servicePort() || taskPort
!= mTaskPort
) {
77 secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s",
78 this, pid(), servicePort
.port(), session().servicePort().port(), taskPort
.port(), mTaskPort
.port(),
79 (identity
&& identity
[0]) ? identity
: "(unknown)");
80 Session
&newSession
= Session::find(servicePort
);
81 Syslog::alert("Process reset %p(%d) session %d(0x%x:0x%x)->%d(0x%x:0x%x) for %s",
83 session().servicePort().port(), &session(), session().attributes(),
84 newSession
.servicePort().port(), &newSession
, newSession
.attributes(),
85 (identity
&& identity
[0]) ? identity
: "(unknown)");
86 //CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); // liar
89 string oldPath
= codePath(processCode());
91 ClientIdentification::setup(this->pid());
92 if (codePath(processCode()) == oldPath
) {
93 secdebug("SS", "process %p(%d) path unchanged; assuming client-side reset", this, mPid
);
95 secdebug("SS", "process %p(%d) path changed; assuming exec with full reset", this, mPid
);
96 CodeSigningHost::reset();
99 secdebug("SS", "process %p(%d) has reset; now %sfor %s",
100 this, mPid
, mByteFlipped
? "FLIP " : "",
101 (identity
&& identity
[0]) ? identity
: "(unknown)");
106 // Common set processing
108 void Process::setup(const ClientSetupInfo
*info
)
110 // process setup info
113 if (info
->order
== 0x1234) { // right side up
114 pversion
= info
->version
;
115 mByteFlipped
= false;
116 } else if (info
->order
== 0x34120000) { // flip side up
117 pversion
= ntohl(info
->version
);
119 } else // non comprende
120 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
122 // check wire protocol version
123 if (pversion
!= SSPROTOVERSION
)
124 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
129 // Clean up a Process object
133 // tell all our authorizations that we're gone
134 IFDEBUG(if (!mAuthorizations
.empty())
135 secdebug("SS", "Process %p(%d) clearing %d authorizations",
136 this, mPid
, int(mAuthorizations
.size())));
137 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
138 it
!= mAuthorizations
.end(); ) {
139 AuthorizationToken
*auth
= *it
;
140 while (++it
!= mAuthorizations
.end() && *it
== auth
) ; // Skip duplicates
141 if (auth
->endProcess(*this))
145 // no need to lock here; the client process has no more active threads
146 secdebug("SS", "Process %p(%d) has died", this, mPid
);
148 // release our name for the process's task port
155 StLock
<Mutex
> _(*this);
157 // release local temp store
160 // standard kill processing
165 Session
& Process::session() const
167 return parent
<Session
>();
171 LocalDatabase
&Process::localStore()
173 StLock
<Mutex
> _(*this);
175 mLocalStore
= new TempDatabase(*this);
179 Key
*Process::makeTemporaryKey(const CssmKey
&key
, CSSM_KEYATTR_FLAGS moreAttributes
,
180 const AclEntryPrototype
*owner
)
182 return safer_cast
<TempDatabase
&>(localStore()).makeKey(key
, moreAttributes
, owner
);
187 // Change the session of a process.
188 // This is the result of SessionCreate from a known process client.
190 void Process::changeSession(Port servicePort
)
193 parent(Session::find(servicePort
));
195 secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
200 // Authorization set maintainance
202 void Process::addAuthorization(AuthorizationToken
*auth
)
205 StLock
<Mutex
> _(*this);
206 mAuthorizations
.insert(auth
);
207 auth
->addProcess(*this);
210 void Process::checkAuthorization(AuthorizationToken
*auth
)
213 StLock
<Mutex
> _(*this);
214 if (mAuthorizations
.find(auth
) == mAuthorizations
.end())
215 MacOSError::throwMe(errAuthorizationInvalidRef
);
218 bool Process::removeAuthorization(AuthorizationToken
*auth
)
221 StLock
<Mutex
> _(*this);
222 // we do everything with a single set lookup call...
223 typedef AuthorizationSet::iterator Iter
;
224 Iter it
= mAuthorizations
.lower_bound(auth
);
226 if (it
== mAuthorizations
.end() || auth
!= *it
) {
229 Iter next
= it
; ++next
; // following element
230 isLast
= (next
== mAuthorizations
.end()) || auth
!= *next
;
231 mAuthorizations
.erase(it
); // remove first match
234 if (auth
->endProcess(*this)) // ... tell it to remove us,
235 return true; // ... and tell the caller
237 return false; // keep the auth; it's still in use
242 // Debug dump support
244 #if defined(DEBUGDUMP)
246 void Process::dumpNode()
248 PerProcess::dumpNode();
250 Debug::dump(" FLIPPED");
251 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
252 mTaskPort
.port(), mPid
, mUid
, mGid
);
253 CodeSigningHost::dump();
254 ClientIdentification::dump();