Sandbox rwhod(8) receiver process using capability mode and Capsicum

capabilities.

rwhod(8) receiver can now only receive packages, write to /var/rwho/ directory
and log to syslog.

Submitted by:	Mariusz Zaborski <oshogbo@FreeBSD.org>
Sponsored by:	Google Summer of Code 2013
Reviewed by:	pjd
MFC after:	1 month
This commit is contained in:
Pawel Jakub Dawidek 2013-07-03 21:07:02 +00:00
parent 223eee088f
commit 6f691f7ee1

View File

@ -43,6 +43,7 @@ static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/capability.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -220,7 +221,7 @@ main(int argc, char *argv[])
daemon(1, 0); daemon(1, 0);
#endif #endif
(void) signal(SIGHUP, getboottime); (void) signal(SIGHUP, getboottime);
openlog("rwhod", LOG_PID, LOG_DAEMON); openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON);
sp = getservbyname("who", "udp"); sp = getservbyname("who", "udp");
if (sp == NULL) { if (sp == NULL) {
syslog(LOG_ERR, "who/udp: unknown service"); syslog(LOG_ERR, "who/udp: unknown service");
@ -342,12 +343,27 @@ receiver_process(void)
struct sockaddr_in from; struct sockaddr_in from;
struct stat st; struct stat st;
char path[64]; char path[64];
int dirfd;
struct whod wd; struct whod wd;
socklen_t len; socklen_t len;
int cc, whod; int cc, whod;
time_t t; time_t t;
len = sizeof(from); len = sizeof(from);
dirfd = open(".", O_RDONLY | O_DIRECTORY);
if (dirfd < 0) {
syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR);
exit(1);
}
if (cap_rights_limit(dirfd, CAP_CREATE | CAP_WRITE | CAP_FTRUNCATE |
CAP_SEEK | CAP_LOOKUP | CAP_FSTAT) < 0 && errno != ENOSYS) {
syslog(LOG_WARNING, "cap_rights_limit: %m");
exit(1);
}
if (cap_enter() < 0 && errno != ENOSYS) {
syslog(LOG_ERR, "cap_enter: %m");
exit(1);
}
for (;;) { for (;;) {
cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from,
&len); &len);
@ -380,11 +396,16 @@ receiver_process(void)
* Rather than truncating and growing the file each time, * Rather than truncating and growing the file each time,
* use ftruncate if size is less than previous size. * use ftruncate if size is less than previous size.
*/ */
whod = open(path, O_WRONLY | O_CREAT, 0644); whod = openat(dirfd, path, O_WRONLY | O_CREAT, 0644);
if (whod < 0) { if (whod < 0) {
syslog(LOG_WARNING, "%s: %m", path); syslog(LOG_WARNING, "%s: %m", path);
continue; continue;
} }
if (cap_rights_limit(whod, CAP_WRITE | CAP_FTRUNCATE |
CAP_FSTAT) < 0 && errno != ENOSYS) {
syslog(LOG_WARNING, "cap_rights_limit: %m");
exit(1);
}
#if ENDIAN != BIG_ENDIAN #if ENDIAN != BIG_ENDIAN
{ {
struct whoent *we; struct whoent *we;
@ -412,6 +433,7 @@ receiver_process(void)
ftruncate(whod, cc); ftruncate(whod, cc);
(void) close(whod); (void) close(whod);
} }
(void) close(dirfd);
} }
void void