1/* 2 * Copyright (c) 2000-2009,2012 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// process - track a single client process and its belongings 27// 28#include "process.h" 29#include "server.h" 30#include "session.h" 31#include "tempdatabase.h" 32#include "authority.h" 33#include "child.h" // ServerChild (really UnixPlusPlus::Child)::find() 34 35#include <security_utilities/logging.h> //@@@ debug only 36#include "agentquery.h" 37 38 39// 40// Construct a Process object. 41// 42Process::Process(TaskPort taskPort, const ClientSetupInfo *info, const CommonCriteria::AuditToken &audit) 43 : mTaskPort(taskPort), mByteFlipped(false), mPid(audit.pid()), mUid(audit.euid()), mGid(audit.egid()) 44{ 45 StLock<Mutex> _(*this); 46 47 // set parent session 48 parent(Session::find(audit.sessionId(), true)); 49 50 // let's take a look at our wannabe client... 51 if (mTaskPort.pid() != mPid) { 52 secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d)", 53 mPid, mTaskPort.port(), mTaskPort.pid()); 54 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // you lied! 55 } 56 57 setup(info); 58 ClientIdentification::setup(this->pid()); 59 60 // NB: ServerChild::find() should only be used to determine 61 // *existence*. Don't use the returned Child object for anything else, 62 // as it is not protected against its underlying process's destruction. 63 if (this->pid() == getpid() // called ourselves (through some API). Do NOT record this as a "dirty" transaction 64 || ServerChild::find<ServerChild>(this->pid())) // securityd's child; do not mark this txn dirty 65 VProc::Transaction::deactivate(); 66 67 if (SECURITYD_CLIENT_NEW_ENABLED()) 68 SECURITYD_CLIENT_NEW(this, this->pid(), &this->session(), 69 (char *)codePath(this->processCode()).c_str(), taskPort, mUid, mGid, mByteFlipped); 70} 71 72 73// 74// Screen a process setup request for an existing process. 75// This means the client has requested intialization even though we remember having 76// talked to it in the past. This could either be an exec(2), or the client could just 77// have forgotten all about its securityd client state. Or it could be an attack... 78// 79void Process::reset(TaskPort taskPort, const ClientSetupInfo *info, const CommonCriteria::AuditToken &audit) 80{ 81 StLock<Mutex> _(*this); 82 if (taskPort != mTaskPort) { 83 secdebug("SS", "Process %p(%d) reset mismatch (tp %d-%d)", 84 this, pid(), taskPort.port(), mTaskPort.port()); 85 //@@@ CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); // liar 86 } 87 setup(info); 88 CFCopyRef<SecCodeRef> oldCode = processCode(); 89 90 ClientIdentification::setup(this->pid()); // re-constructs processCode() 91 if (CFEqual(oldCode, processCode())) { 92 SECURITYD_CLIENT_RESET_AMNESIA(this); 93 } else { 94 SECURITYD_CLIENT_RESET_FULL(this); 95 CodeSigningHost::reset(); 96 } 97} 98 99 100// 101// Common set processing 102// 103void Process::setup(const ClientSetupInfo *info) 104{ 105 // process setup info 106 assert(info); 107 uint32 pversion; 108 if (info->order == 0x1234) { // right side up 109 pversion = info->version; 110 mByteFlipped = false; 111 } else if (info->order == 0x34120000) { // flip side up 112 pversion = flip(info->version); 113 mByteFlipped = true; 114 } else // non comprende 115 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); 116 117 // check wire protocol version 118 if (pversion != SSPROTOVERSION) 119 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); 120} 121 122 123// 124// Clean up a Process object 125// 126Process::~Process() 127{ 128 SECURITYD_CLIENT_RELEASE(this, this->pid()); 129 130 // tell all our authorizations that we're gone 131 IFDEBUG(if (!mAuthorizations.empty()) 132 secdebug("SS", "Process %p(%d) clearing %d authorizations", 133 this, mPid, int(mAuthorizations.size()))); 134 for (AuthorizationSet::iterator it = mAuthorizations.begin(); 135 it != mAuthorizations.end(); ) { 136 AuthorizationToken *auth = *it; 137 while (++it != mAuthorizations.end() && *it == auth) ; // Skip duplicates 138 if (auth->endProcess(*this)) 139 delete auth; 140 } 141 142 // release our name for the process's task port 143 if (mTaskPort) 144 mTaskPort.destroy(); 145} 146 147void Process::kill() 148{ 149 StLock<Mutex> _(*this); 150 151 // release local temp store 152 mLocalStore = NULL; 153 154 // standard kill processing 155 PerProcess::kill(); 156} 157 158 159Session& Process::session() const 160{ 161 return parent<Session>(); 162} 163 164 165void Process::checkSession(const audit_token_t &auditToken) 166{ 167 AuditToken audit(auditToken); 168 if (audit.sessionId() != this->session().sessionId()) 169 this->changeSession(audit.sessionId()); 170} 171 172 173LocalDatabase &Process::localStore() 174{ 175 StLock<Mutex> _(*this); 176 if (!mLocalStore) 177 mLocalStore = new TempDatabase(*this); 178 return *mLocalStore; 179} 180 181Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes, 182 const AclEntryPrototype *owner) 183{ 184 return safer_cast<TempDatabase&>(localStore()).makeKey(key, moreAttributes, owner); 185} 186 187 188// 189// Change the session of a process. 190// This is the result of SessionCreate from a known process client. 191// 192void Process::changeSession(Session::SessionId sessionId) 193{ 194 // re-parent 195 parent(Session::find(sessionId, true)); 196 SECURITYD_CLIENT_CHANGE_SESSION(this, &this->session()); 197} 198 199 200// 201// Authorization set maintainance 202// 203void Process::addAuthorization(AuthorizationToken *auth) 204{ 205 assert(auth); 206 StLock<Mutex> _(*this); 207 mAuthorizations.insert(auth); 208 auth->addProcess(*this); 209} 210 211void Process::checkAuthorization(AuthorizationToken *auth) 212{ 213 assert(auth); 214 StLock<Mutex> _(*this); 215 if (mAuthorizations.find(auth) == mAuthorizations.end()) 216 MacOSError::throwMe(errAuthorizationInvalidRef); 217} 218 219bool Process::removeAuthorization(AuthorizationToken *auth) 220{ 221 assert(auth); 222 StLock<Mutex> _(*this); 223 // we do everything with a single set lookup call... 224 typedef AuthorizationSet::iterator Iter; 225 Iter it = mAuthorizations.lower_bound(auth); 226 bool isLast; 227 if (it == mAuthorizations.end() || auth != *it) { 228 isLast = true; 229 } else { 230 Iter next = it; ++next; // following element 231 isLast = (next == mAuthorizations.end()) || auth != *next; 232 mAuthorizations.erase(it); // remove first match 233 } 234 if (isLast) { 235 if (auth->endProcess(*this)) // ... tell it to remove us, 236 return true; // ... and tell the caller 237 } 238 return false; // keep the auth; it's still in use 239} 240 241 242// 243// Debug dump support 244// 245#if defined(DEBUGDUMP) 246 247void Process::dumpNode() 248{ 249 PerProcess::dumpNode(); 250 if (mByteFlipped) 251 Debug::dump(" FLIPPED"); 252 Debug::dump(" task=%d pid=%d uid/gid=%d/%d", 253 mTaskPort.port(), mPid, mUid, mGid); 254 CodeSigningHost::dump(); 255 ClientIdentification::dump(); 256} 257 258#endif //DEBUGDUMP 259