privPortServer.cpp [plain text]
#include <cstdlib>
#include <unistd.h>
#include <Security/Authorization.h>
#include <Security/unix++.h>
#include <Security/fdmover.h>
#include <Security/debugging.h>
#include "privPort.h"
using namespace UnixPlusPlus;
using namespace IPPlusPlus;
#define DEFAULT_TIMEOUT (2 * 60)
void usage(const char *me);
void serve(FdMover client);
void sigALRM(int signo);
void reply(Socket s, OSStatus error)
{
Reply reply;
reply.status = htonl(error);
s.write(&reply, sizeof(reply));
close(s);
}
int main(int argc, char *argv[])
{
unsigned timeout = DEFAULT_TIMEOUT;
extern int optind;
extern char *optarg;
int arg;
while ((arg = getopt(argc, argv, "t:")) != -1)
switch (arg) {
case 't':
timeout = atoi(optarg);
break;
case '?':
usage(argv[0]);
}
if (optind < argc)
usage(argv[0]);
umask(0111); Socket server(AF_UNIX, SOCK_STREAM);
UNSockAddress serverAddress(kPrivilegedPortBinder);
try {
server.bind(serverAddress);
} catch (const UnixError &error) {
switch (error.error) {
case EADDRINUSE:
unlink(kPrivilegedPortBinder);
server.bind(serverAddress);
break;
default:
throw;
}
}
server.listen(5);
SigSet signals;
signals += SIGALRM;
sigMask(signals, SIG_BLOCK);
if (signal(SIGALRM, sigALRM) == SIG_ERR) {
perror("SIGALRM");
exit(1);
}
for (;;) {
FdMover s;
alarm(timeout);
sigMask(signals, SIG_UNBLOCK);
server.accept(s);
sigMask(signals, SIG_BLOCK);
try {
serve(s);
} catch (const CssmCommonError &error) {
reply(s, error.cssmError());
} catch (...) {
reply(s, -1);
}
}
return 0;
}
void usage(const char *me)
{
fprintf(stderr, "Usage: %s [-t timeout-seconds]\n", me);
exit(2);
}
void sigALRM(int signo)
{
secdebug("portserver", "timeout; quitting");
unlink(kPrivilegedPortBinder);
exit(0);
}
void serve(FdMover client)
{
secdebug("portserver", "processing port request");
Request request;
FdVector fds;
if (client.receive(&request, sizeof(request), fds) != sizeof(request)) {
return reply(client, 11111);
return;
}
if (fds.size() != 1) {
return reply(client, 11111);
return;
}
AuthorizationRef auth;
if (OSStatus err = AuthorizationCreateFromExternalForm(&request.authForm, &auth))
return reply(client, err);
AuthorizationItem rights[] = {
{ CONNECTRIGHT, 0, NULL, 0 },
{ ACCEPTRIGHT, 0, NULL, 0 }
};
AuthorizationRights rightSet = { sizeof(rights) / sizeof(rights[0]), rights };
AuthorizationRights *result;
if (OSStatus err = AuthorizationCopyRights(auth, &rightSet, NULL,
kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
kAuthorizationFlagPartialRights,
&result))
return reply(client, err);
UInt32 count = result ? result->count : 0;
AuthorizationFreeItemSet(result);
if (count == 0)
return reply(client, errAuthorizationDenied);
Socket s; s = fds[0];
s.bind(request.requestedName);
return reply(client, 0);
}