#include <paths.h>
#include <fcntl.h>
#include "authhost.h"
#include "server.h"
#include <grp.h>
#include <pwd.h>
AuthHostInstance::AuthHostInstance(Session &session, AuthHostType host) :
mHostType(host)
{
secdebug("authhost", "authhost born (%p)", this);
referent(session);
session.addReference(*this);
}
AuthHostInstance::~AuthHostInstance()
{
secdebug("authhost", "authhost died (%p)", this);
servicePort ().destroy ();
}
Session &AuthHostInstance::session() const
{
return referent<Session>();
}
void
AuthHostInstance::childAction()
{
unsetenv("USER");
unsetenv("LOGNAME");
unsetenv("HOME");
int maxDescriptors = getdtablesize ();
int i;
int devnull = open(_PATH_DEVNULL, O_RDWR, 0);
if (devnull >= 0) for (i = 0; i < 3; ++i)
{
dup2(devnull, i);
}
for (i = 3; i < maxDescriptors; ++i)
{
close (i);
}
char agentExecutable[PATH_MAX + 1];
const char *path = getenv("SECURITYAGENT");
if (!path)
path = "/System/Library/CoreServices/SecurityAgent.app";
if ((mHostType == userAuthHost) || (mHostType == privilegedAuthHost))
{
snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/Resources/authorizationhost", path);
secdebug("AuthHostInstance", "execl(%s)", agentExecutable);
execl(agentExecutable, agentExecutable, NULL);
}
else
{
snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/MacOS/SecurityAgent", path);
struct group *agentGroup = getgrnam("securityagent");
gid_t agentGID = static_cast<gid_t>(-2);
if (agentGroup)
{
agentGID = agentGroup->gr_gid;
endgrent();
}
struct passwd *agentUser = getpwnam("securityagent");
uid_t agentUID = static_cast<uid_t>(-2);
if (agentUser)
{
agentUID = agentUser->pw_uid;
endpwent();
}
setuid(agentUID);
setgid(agentGID);
CFRef<CFDataRef> userPrefs(session().copyUserPrefs());
FILE *mbox = tmpfile();
if (userPrefs && mbox)
{
if (fwrite(CFDataGetBytePtr(userPrefs), CFDataGetLength(userPrefs), 1, mbox) != 1)
fclose(mbox);
else
{
char mboxFdString[20];
fflush(mbox);
if ((int)sizeof(mboxFdString) > snprintf(mboxFdString, sizeof(mboxFdString), "%d", fileno(mbox)))
setenv("SECURITYAGENT_USERPREFS_FD", mboxFdString, 1);
}
}
secdebug("AuthHostInstance", "execl(%s) as user (%d,%d)", agentExecutable, agentUID, agentGID);
execl(agentExecutable, agentExecutable, NULL);
}
secdebug("AuthHostInstance", "execl failed, errno=%d", errno);
#if 1
_exit(1);
#else
setuid(0);
abort();
#endif
}
Port
AuthHostInstance::activate()
{
StLock<Mutex> _(*this);
if (state() != alive)
{
if (!(session().attributes() & sessionHasGraphicAccess))
CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
Security::MachPlusPlus::StBootstrap bootSaver(session().bootstrapPort());
fork();
switch (ServerChild::state()) {
case Child::alive:
secdebug("AuthHostInstance", "%p (pid %d) has launched", this, pid());
break;
case Child::dead:
secdebug("AuthHostInstance", "%p (pid %d) failed on startup", this, pid());
break;
default:
assert(false);
}
}
if (!ready())
CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
return servicePort();
}