1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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#include <paths.h> 25#include <fcntl.h> 26#include "authhost.h" 27#include "server.h" 28#include <security_utilities/logging.h> 29#include <security_utilities/debugging.h> 30#include <security_agent_client/sa_request.h> 31#include <security_agent_client/utils.h> 32#include <bsm/audit.h> 33#include <bootstrap_priv.h> 34 35#include <grp.h> 36#include <pwd.h> 37#include <sys/types.h> 38#include <sys/sysctl.h> 39#include <syslog.h> 40#include <pthread.h> 41 42static pthread_once_t agent_cred_init = PTHREAD_ONCE_INIT; 43static gid_t agent_gid = 92; 44static uid_t agent_uid = 92; 45 46void initialize_agent_creds() 47{ 48 struct passwd *agentUser = getpwnam("securityagent"); 49 if (agentUser) 50 { 51 agent_uid = agentUser->pw_uid; 52 agent_gid = agentUser->pw_gid; 53 endpwent(); 54 } 55} 56 57AuthHostInstance::AuthHostInstance(Session &session, AuthHostType host) : 58 mHostType(host) 59{ 60 secdebug("authhost", "authhost born (%p)", this); 61 referent(session); 62 session.addReference(*this); 63 if (host == securityAgent) 64 pthread_once(&agent_cred_init, initialize_agent_creds); 65} 66 67AuthHostInstance::~AuthHostInstance() 68{ 69 secdebug("authhost", "authhost died (%p)", this); 70} 71 72Session &AuthHostInstance::session() const 73{ 74 return referent<Session>(); 75} 76 77bool AuthHostInstance::inDarkWake() 78{ 79 return session().server().inDarkWake(); 80} 81 82void 83AuthHostInstance::childAction() 84{ 85 // switch to desired session 86 CommonCriteria::AuditInfo &audit = this->session().auditInfo(); 87 audit.get(audit.sessionId()); 88 audit.set(); 89 //this->session().auditInfo().set(); 90 91 // Setup the environment for the SecurityAgent 92 unsetenv("USER"); 93 unsetenv("LOGNAME"); 94 unsetenv("HOME"); 95 96 // close down any files that might have been open at this point 97 int maxDescriptors = getdtablesize (); 98 int i; 99 100 int devnull = open(_PATH_DEVNULL, O_RDWR, 0); 101 if (devnull >= 0) for (i = 0; i < 3; ++i) 102 { 103 dup2(devnull, i); 104 } 105 106 for (i = 3; i < maxDescriptors; ++i) 107 { 108 close (i); 109 } 110 111 // construct path to SecurityAgent 112 char agentExecutable[PATH_MAX + 1]; 113 const char *path = getenv("SECURITYAGENT"); 114 if (!path) 115 path = "/System/Library/CoreServices/SecurityAgent.app"; 116 secdebug("adhoc", "hostType = %d", mHostType); 117 118 if ((mHostType == userAuthHost) || (mHostType == privilegedAuthHost)) 119 { 120 snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/Resources/authorizationhost", path); 121 secdebug("AuthHostInstance", "execl(%s)", agentExecutable); 122 execl(agentExecutable, agentExecutable, NULL); 123 } 124 else 125 { 126 snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/MacOS/SecurityAgent", path); 127 128 pid_t pid = getpid(); 129 if ((pid <= 0) || 130 sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &pid, sizeof(pid))) 131 syslog(LOG_ERR, "Failed to set vfs.generic.noremotehang for pid(%d)", pid); 132 133 setgroups(1, &agent_gid); 134 setgid(agent_gid); 135 setuid(agent_uid); 136 137 secdebug("AuthHostInstance", "execl(%s) as user (%d,%d)", agentExecutable, agent_uid, agent_gid); 138 execl(agentExecutable, agentExecutable, NULL); 139 } 140 141 secdebug("AuthHostInstance", "execl failed, errno=%d", errno); 142 // Unconditional suicide follows. 143 _exit(1); 144} 145 146// @@@ these definitions and the logic in lookup() should move into 147// libsecurity_agent 148#define SECURITYAGENT_BOOTSTRAP_NAME_BASE "com.apple.SecurityAgent" 149#define AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE "com.apple.authorizationhost" 150 151mach_port_t 152AuthHostInstance::lookup(SessionId jobId) 153{ 154 StLock<Mutex> _(*this); 155 156 mach_port_t pluginhostPort = MACH_PORT_NULL; 157 kern_return_t result; 158 const char *serviceName; 159 /* PR-7483709 const */ uuid_t instanceId = UUID_INITIALIZER_FROM_SESSIONID(jobId); 160 uuid_string_t s; 161 162 if ((mHostType == securityAgent)) { 163 if (!(session().attributes() & sessionHasGraphicAccess)) 164 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); 165 if (inDarkWake()) 166 CssmError::throwMe(CSSM_ERRCODE_IN_DARK_WAKE); 167 } 168 169 if (mHostType == securityAgent) 170 serviceName = SECURITYAGENT_BOOTSTRAP_NAME_BASE; 171 else 172 serviceName = AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE; 173 174 secdebug("AuthHostInstance", "looking up %s instance %s", serviceName, 175 uuid_to_string(instanceId, s)); // XXX/gh debugging 176 if ((result = bootstrap_look_up3(bootstrap_port, serviceName, 177 &pluginhostPort, 0, instanceId, BOOTSTRAP_SPECIFIC_INSTANCE)) != KERN_SUCCESS) { 178 179 Syslog::error("error %d looking up %s instance %s", result, serviceName, 180 uuid_to_string(instanceId, s)); 181 } else 182 secdebug("AuthHostInstance", "port = %x", (unsigned int)pluginhostPort); 183 184 return pluginhostPort; 185} 186 187Port AuthHostInstance::activate() 188{ 189 StLock<Mutex> _(*this); 190 if (state() != alive) 191 { 192 if ((mHostType == securityAgent)) { 193 if (!(session().attributes() & sessionHasGraphicAccess)) 194 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); 195 if (inDarkWake()) 196 CssmError::throwMe(CSSM_ERRCODE_IN_DARK_WAKE); 197 } 198 199 fork(); 200 switch (ServerChild::state()) { 201 case Child::alive: 202 secdebug("AuthHostInstance", "%p (pid %d) has launched", this, pid()); 203 break; 204 case Child::dead: 205 secdebug("AuthHostInstance", "%p (pid %d) failed on startup", this, pid()); 206 break; 207 default: 208 assert(false); 209 } 210 } 211 212 if (!ready()) 213 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); 214 215 return servicePort(); 216} 217