Ejemplo n.º 1
0
void
receiver_process(void)
{
	struct sockaddr_in from;
	struct stat st;
	cap_rights_t rights;
	char path[64];
	int dirfd;
	struct whod wd;
	socklen_t len;
	int cc, whod;
	time_t t;

	len = sizeof(from);
	dirfd = open(".", O_RDONLY | O_DIRECTORY);
	if (dirfd < 0) {
		syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR);
		exit(1);
	}
	cap_rights_init(&rights, CAP_CREATE, CAP_FSTAT, CAP_FTRUNCATE,
	    CAP_LOOKUP, CAP_SEEK, CAP_WRITE);
	if (caph_rights_limit(dirfd, &rights) < 0) {
		syslog(LOG_WARNING, "cap_rights_limit: %m");
		exit(1);
	}
	if (caph_enter() < 0) {
		syslog(LOG_ERR, "cap_enter: %m");
		exit(1);
	}
	for (;;) {
		cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from,
		    &len);
		if (cc <= 0) {
			if (cc < 0 && errno != EINTR)
				syslog(LOG_WARNING, "recv: %m");
			continue;
		}
		if (from.sin_port != sp->s_port && !insecure_mode) {
			syslog(LOG_WARNING, "%d: bad source port from %s",
			    ntohs(from.sin_port), inet_ntoa(from.sin_addr));
			continue;
		}
		if (cc < WHDRSIZE) {
			syslog(LOG_WARNING, "short packet from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		if (wd.wd_vers != WHODVERSION)
			continue;
		if (wd.wd_type != WHODTYPE_STATUS)
			continue;
		if (!verify(wd.wd_hostname, sizeof(wd.wd_hostname))) {
			syslog(LOG_WARNING, "malformed host name from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		(void) snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname);
		/*
		 * Rather than truncating and growing the file each time,
		 * use ftruncate if size is less than previous size.
		 */
		whod = openat(dirfd, path, O_WRONLY | O_CREAT, 0644);
		if (whod < 0) {
			syslog(LOG_WARNING, "%s: %m", path);
			continue;
		}
		cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_WRITE);
		if (caph_rights_limit(whod, &rights) < 0) {
			syslog(LOG_WARNING, "cap_rights_limit: %m");
			exit(1);
		}
#if ENDIAN != BIG_ENDIAN
		{
			struct whoent *we;
			int i, n;

			n = (cc - WHDRSIZE) / sizeof(struct whoent);
			/* undo header byte swapping before writing to file */
			wd.wd_sendtime = ntohl(wd.wd_sendtime);
			for (i = 0; i < 3; i++)
				wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
			wd.wd_boottime = ntohl(wd.wd_boottime);
			we = wd.wd_we;
			for (i = 0; i < n; i++) {
				we->we_idle = ntohl(we->we_idle);
				we->we_utmp.out_time =
				    ntohl(we->we_utmp.out_time);
				we++;
			}
		}
#endif
		(void) time(&t);
		wd.wd_recvtime = _time_to_int(t);
		(void) write(whod, (char *)&wd, cc);
		if (fstat(whod, &st) < 0 || st.st_size > cc)
			ftruncate(whod, cc);
		(void) close(whod);
	}
	(void) close(dirfd);
}
Ejemplo n.º 2
0
int
main(int argc, char *argv[])
{
	struct sockaddr_in from;
	struct stat st;
	char path[64];
	int on = 1;
	char *cp;
	struct sockaddr_in soin;
	uid_t unpriv_uid;
	gid_t unpriv_gid;

	if (getuid())
		errx(1, "not super user");

	run_as(&unpriv_uid, &unpriv_gid);

	argv++; argc--;
	while (argc > 0 && *argv[0] == '-') {
		if (strcmp(*argv, "-m") == 0) {
			if (argc > 1 && isdigit(*(argv + 1)[0])) {
				argv++, argc--;
				multicast_mode  = SCOPED_MULTICAST;
				multicast_scope = atoi(*argv);
				if (multicast_scope > MAX_MULTICAST_SCOPE)
					errx(1, "ttl must not exceed %u",
					MAX_MULTICAST_SCOPE);
			}
			else multicast_mode = PER_INTERFACE_MULTICAST;
		}
		else if (strcmp(*argv, "-i") == 0)
			insecure_mode = 1;
		else if (strcmp(*argv, "-l") == 0)
			quiet_mode = 1;
		else if (strcmp(*argv, "-p") == 0)
			iff_flag = 0;
		else
			usage();
		argv++, argc--;
	}
	if (argc > 0)
		usage();
#ifndef DEBUG
	daemon(1, 0);
#endif
	(void) signal(SIGHUP, getboottime);
	openlog("rwhod", LOG_PID, LOG_DAEMON);
	sp = getservbyname("who", "udp");
	if (sp == NULL) {
		syslog(LOG_ERR, "who/udp: unknown service");
		exit(1);
	}
	if (chdir(_PATH_RWHODIR) < 0) {
		syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR);
		exit(1);
	}
	/*
	 * Establish host name as returned by system.
	 */
	if (gethostname(myname, sizeof(myname) - 1) < 0) {
		syslog(LOG_ERR, "gethostname: %m");
		exit(1);
	}
	if ((cp = index(myname, '.')) != NULL)
		*cp = '\0';
	strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1);
	mywd.wd_hostname[sizeof(mywd.wd_hostname) - 1] = '\0';
#ifdef __APPLE__
	utmpf = open(_PATH_UTMPX, O_RDONLY|O_CREAT, 0644);
#else
	utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
#endif
	if (utmpf < 0) {
#ifdef __APPLE__
		syslog(LOG_ERR, "%s: %m", _PATH_UTMPX);
#else
		syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
#endif
		exit(1);
	}
	getboottime(0);
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(LOG_ERR, "socket: %m");
		exit(1);
	}
	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
		exit(1);
	}
	memset(&soin, 0, sizeof(soin));
	soin.sin_len = sizeof(soin);
	soin.sin_family = AF_INET;
	soin.sin_port = sp->s_port;
	if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) {
		syslog(LOG_ERR, "bind: %m");
		exit(1);
	}
	setgid(unpriv_gid);
	setgroups(1, &unpriv_gid);	/* XXX BOGUS groups[0] = egid */
	setuid(unpriv_uid);
	if (!configure(s))
		exit(1);
	if (!quiet_mode) {
		signal(SIGALRM, onalrm);
		onalrm(0);
	}
	for (;;) {
		struct whod wd;
		socklen_t len = sizeof(from);
		int cc, whod;
		time_t t;

		cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,
			(struct sockaddr *)&from, &len);
		if (cc <= 0) {
			if (cc < 0 && errno != EINTR)
				syslog(LOG_WARNING, "recv: %m");
			continue;
		}
		if (from.sin_port != sp->s_port && !insecure_mode) {
			syslog(LOG_WARNING, "%d: bad source port from %s",
			    ntohs(from.sin_port), inet_ntoa(from.sin_addr));
			continue;
		}
		if (cc < WHDRSIZE) {
			syslog(LOG_WARNING, "short packet from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		if (wd.wd_vers != WHODVERSION)
			continue;
		if (wd.wd_type != WHODTYPE_STATUS)
			continue;
		if (!verify(wd.wd_hostname, sizeof wd.wd_hostname)) {
			syslog(LOG_WARNING, "malformed host name from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		(void) snprintf(path, sizeof path, "whod.%s", wd.wd_hostname);
		/*
		 * Rather than truncating and growing the file each time,
		 * use ftruncate if size is less than previous size.
		 */
		whod = open(path, O_WRONLY | O_CREAT, 0644);
		if (whod < 0) {
			syslog(LOG_WARNING, "%s: %m", path);
			continue;
		}
#if ENDIAN != BIG_ENDIAN
		{
			int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
			struct whoent *we;

			/* undo header byte swapping before writing to file */
			wd.wd_sendtime = ntohl(wd.wd_sendtime);
			for (i = 0; i < 3; i++)
				wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
			wd.wd_boottime = ntohl(wd.wd_boottime);
			we = wd.wd_we;
			for (i = 0; i < n; i++) {
				we->we_idle = ntohl(we->we_idle);
				we->we_utmp.out_time =
				    ntohl(we->we_utmp.out_time);
				we++;
			}
		}
#endif
		(void) time(&t);
		wd.wd_recvtime = _time_to_int(t);
		(void) write(whod, (char *)&wd, cc);
		if (fstat(whod, &st) < 0 || st.st_size > cc)
			ftruncate(whod, cc);
		(void) close(whod);
	}
}