xref: /original-bsd/usr.sbin/rwhod/rwhod.c (revision f0fd5f8a)
1 #ifndef lint
2 static char sccsid[] = "@(#)rwhod.c	4.6 82/11/15";
3 #endif
4 
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/stat.h>
8 #include <sys/ioctl.h>
9 
10 #include <netinet/in.h>
11 
12 #include <nlist.h>
13 #include <stdio.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <utmp.h>
17 #include <ctype.h>
18 #include <netdb.h>
19 
20 #include "rwhod.h"
21 
22 struct	sockaddr_in sin = { AF_INET };
23 
24 extern	errno;
25 
26 char	*localnet = "localnet";
27 char	*myname = "myname";
28 
29 struct	nlist nl[] = {
30 #define	NL_AVENRUN	0
31 	{ "_avenrun" },
32 #define	NL_BOOTTIME	1
33 	{ "_boottime" },
34 	0
35 };
36 
37 struct	whod mywd;
38 int	s, utmpf, kmemf = -1;
39 
40 int	onalrm();
41 char	*strcpy(), *sprintf();
42 long	lseek();
43 int	getkmem();
44 
45 main()
46 {
47 	struct sockaddr_in from;
48 	char path[64];
49 	int addr;
50 	struct servent *sp;
51 
52 	sp = getservbyname("who", "udp");
53 	if (sp == 0) {
54 		fprintf(stderr, "rwhod: udp/who: unknown service\n");
55 		exit(1);
56 	}
57 	sp->s_port = htons(sp->s_port);
58 #ifndef DEBUG
59 	if (fork())
60 		exit(0);
61 	{ int s;
62 	  for (s = 0; s < 10; s++)
63 		(void) close(s);
64 	  (void) open("/", 0);
65 	  (void) dup2(0, 1);
66 	  (void) dup2(0, 2);
67 	  s = open("/dev/tty", 2);
68 	  if (s >= 0) {
69 		ioctl(s, TIOCNOTTY, 0);
70 		(void) close(s);
71 	  }
72 	}
73 #endif
74 	(void) chdir("/dev");
75 	(void) signal(SIGHUP, getkmem);
76 	if (getuid()) {
77 		fprintf(stderr, "rwhod: not super user\n");
78 		exit(1);
79 	}
80 	addr = rhost(&localnet);
81 	if (addr == -1) {
82 		fprintf(stderr, "rwhod: no localnet\n");
83 		exit(1);
84 	}
85 	sin.sin_addr.s_addr = addr;
86 	if (rhost(&myname) == -1) {
87 		fprintf(stderr, "rwhod: don't know \"myname\"\n");
88 		exit(1);
89 	}
90 	strncpy(mywd.wd_hostname, myname, sizeof (mywd.wd_hostname) - 1);
91 	utmpf = open("/etc/utmp", 0);
92 	if (utmpf < 0) {
93 		(void) close(creat("/etc/utmp", 0644));
94 		utmpf = open("/etc/utmp", 0);
95 	}
96 	if (utmpf < 0) {
97 		perror("rwhod: /etc/utmp");
98 		exit(1);
99 	}
100 	sin.sin_port = sp->s_port;
101 	getkmem();
102 	if ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
103 		perror("rwhod: socket");
104 		exit(1);
105 	}
106 	if (bind(s, &sin, sizeof (sin), 0) < 0) {
107 		perror("rwhod: bind");
108 		exit(1);
109 	}
110 	sigset(SIGALRM, onalrm);
111 	onalrm();
112 	for (;;) {
113 		struct whod wd;
114 		int cc, whod, len=sizeof (from);
115 
116 		cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0, &from, &len);
117 		if (cc <= 0) {
118 			if (cc < 0 && errno != EINTR)
119 				perror("rwhod: recv");
120 			continue;
121 		}
122 		if (from.sin_port != sp->s_port) {
123 			fprintf(stderr, "rwhod: %d: bad from port\n",
124 				ntohs(from.sin_port));
125 			continue;
126 		}
127 #ifdef notdef
128 		if (gethostbyname(wd.wd_hostname) == 0) {
129 			fprintf(stderr, "rwhod: %s: unknown host\n",
130 				wd.wd_hostname);
131 			continue;
132 		}
133 #endif
134 		if (!verify(wd.wd_hostname)) {
135 			fprintf(stderr, "rwhod: malformed host name from %x\n",
136 				from.sin_addr);
137 			continue;
138 		}
139 		(void) sprintf(path, "/etc/whod.%s", wd.wd_hostname);
140 		whod = creat(path, 0666);
141 		if (whod < 0) {
142 			fprintf(stderr, "rwhod: ");
143 			perror(path);
144 			continue;
145 		}
146 		(void) time(&wd.wd_recvtime);
147 		(void) write(whod, (char *)&wd, cc);
148 		(void) close(whod);
149 	}
150 }
151 
152 /*
153  * Check out host name for unprintables
154  * and other funnies before allowing a file
155  * to be created.  Sorry, but blanks aren't allowed.
156  */
157 verify(name)
158 	register char *name;
159 {
160 	register int size = 0;
161 
162 	while (*name) {
163 		if (!isascii(*name) || !isalnum(*name))
164 			return (0);
165 		name++, size++;
166 	}
167 	return (size > 0);
168 }
169 
170 int	utmptime;
171 int	utmpent;
172 struct	utmp utmp[100];
173 int	alarmcount;
174 
175 onalrm()
176 {
177 	register int i;
178 	struct stat stb;
179 	register struct whoent *we = mywd.wd_we, *wlast;
180 	int cc;
181 	double avenrun[3];
182 	time_t now = time(0);
183 
184 	if (alarmcount % 10 == 0)
185 		getkmem();
186 	alarmcount++;
187 	(void) fstat(utmpf, &stb);
188 	if (stb.st_mtime != utmptime) {
189 		(void) lseek(utmpf, (long)0, 0);
190 		cc = read(utmpf, (char *)utmp, sizeof (utmp));
191 		if (cc < 0) {
192 			perror("/etc/utmp");
193 			return;
194 		}
195 		wlast = &mywd.wd_we[(1024 / sizeof (struct whoent)) - 1];
196 		utmpent = cc / sizeof (struct utmp);
197 		for (i = 0; i < utmpent; i++)
198 			if (utmp[i].ut_name[0]) {
199 				we->we_utmp = utmp[i];
200 				if (we >= wlast)
201 					break;
202 				we++;
203 			}
204 		utmpent = we - mywd.wd_we;
205 	}
206 	we = mywd.wd_we;
207 	for (i = 0; i < utmpent; i++) {
208 		if (stat(we->we_utmp.ut_line, &stb) >= 0)
209 			we->we_idle = now - stb.st_atime;
210 		we++;
211 	}
212 	(void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0);
213 	(void) read(kmemf, (char *)avenrun, sizeof (avenrun));
214 	for (i = 0; i < 3; i++)
215 		mywd.wd_loadav[i] = avenrun[i] * 100;
216 	cc = (char *)we - (char *)&mywd;
217 	(void) time(&mywd.wd_sendtime);
218 	(void) sendto(s, (char *)&mywd, cc, 0, &sin, sizeof (sin));
219 	(void) alarm(60);
220 }
221 
222 getkmem()
223 {
224 	struct nlist *nlp;
225 
226 	signal(SIGHUP, getkmem);
227 	if (kmemf >= 0)
228 		(void) close(kmemf);
229 loop:
230 	for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) {
231 		nlp->n_value = 0;
232 		nlp->n_type = 0;
233 	}
234 	nlist("/vmunix", nl);
235 	if (nl[0].n_value == 0) {
236 		fprintf(stderr, "/vmunix namelist botch\n");
237 		sleep(300);
238 		goto loop;
239 	}
240 	kmemf = open("/dev/kmem", 0);
241 	if (kmemf < 0) {
242 		perror("/dev/kmem");
243 		sleep(300);
244 		goto loop;
245 	}
246 	(void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, 0);
247 	(void) read(kmemf, (char *)&mywd.wd_boottime, sizeof (mywd.wd_boottime));
248 }
249