2 * The Remote User Information Daemon 1.8
4 * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU General Public License. See file COPYING in any of the GNU packages.
16 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
31 time_t last_rec; /* 0=down */
35 static int sock, port;
36 static struct hostrec *first_host;
37 static time_t now, last_local_scan;
39 static void die(char *msg, ...) __attribute__((noreturn));
47 fprintf(stderr, "nwhod: ");
48 vfprintf(stderr, msg, args);
57 struct sockaddr_in sa;
63 if (! (h = gethostbyname(name)))
69 if (! (se = getservbyname("nwho", "udp")))
70 die("Unknown service `nwho/udp'");
72 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
76 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
77 die("setsockopt: %m");
79 sa.sin_family = AF_INET;
80 sa.sin_port = port = se->s_port;
81 sa.sin_addr.s_addr = INADDR_ANY;
82 if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
87 memcpy(&sa.sin_addr.s_addr, h->h_addr, sizeof(sa.sin_addr.s_addr));
88 if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
94 scan_utmp(struct rywho_pkt *p, time_t now)
101 char name[UT_NAMESIZE+10];
105 while ((u = getutent()) && cnt < MAX_USERS)
106 if (u->ut_type == USER_PROCESS && u->ut_user[0])
109 memcpy(name, u->ut_user, UT_NAMESIZE);
111 strcpy(h->name, name);
112 h->login_time = htonl(now - u->ut_time);
115 h->con[0] = u->ut_id[0];
116 h->con[1] = u->ut_id[1];
121 char *z = u->ut_line;
122 if (!strncmp(z, "tty", 3))
124 sprintf(h->con, "%.3s", z);
126 sprintf(device, "/dev/%s", u->ut_line);
127 if (stat(device, &st) < 0)
129 fprintf(stderr, "stat(%s): %m", device);
132 h->mesg_y = !!(S_IWGRP & st.st_mode);
134 if (st.st_mtime > last)
136 if (st.st_ctime > last)
140 h->idle_time = htonl(now - last);
143 p->num_users = htonl(cnt);
147 scan_load(struct rywho_pkt *p)
152 n = open("/proc/uptime", O_RDONLY);
155 if (read(n, buf, sizeof(buf)) <= 0)
158 if (!sscanf(buf, "%d", &i))
160 p->uptime = htonl(i);
162 n = open("/proc/loadavg", O_RDONLY);
165 if (read(n, buf, sizeof(buf)) <= 0)
168 if (sscanf(buf, "%d.%d%d.%d%d.%d", &j[0], &j[1], &j[2], &j[3], &j[4], &j[5]) != 6)
170 p->avl[0] = htonl(j[0]*100 + j[1]);
171 p->avl[1] = htonl(j[2]*100 + j[3]);
172 p->avl[2] = htonl(j[4]*100 + j[5]);
176 make_pkt(struct rywho_pkt *pkt)
178 bzero(pkt, sizeof(pkt));
179 pkt->local_time = htonl(now);
193 while (e = readdir(d))
194 if (e->d_name[0] != '.')
200 save_pkt(char *name, struct rywho_pkt *pkt, int len)
202 int fd = open(name, O_WRONLY | O_CREAT, 0666);
205 syslog(LOG_ERR, "open(%s): %m", name);
208 pkt->server_time = htonl(now);
209 if (write(fd, pkt, len) != len)
210 syslog(LOG_ERR, "write: %m");
215 static inline int /* Validation checks not implemented yet */
225 struct rywho_pkt pkt;
226 struct sockaddr_in sa;
227 int n = sizeof(struct rywho_pkt) - MAX_USERS * sizeof(struct userinfo);
232 alarm(DEFAULT_PRUNE_TIME);
234 r = recvfrom(sock, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa, &al);
241 syslog(LOG_ERR, "recvfrom: %m");
246 if (!is_valid(sa.sin_addr.s_addr) || sa.sin_port != port)
248 syslog(LOG_WARNING, "Received packet from invalid source %s.%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
252 if (r < n || r != n + ntohl(pkt.num_users)*sizeof(struct userinfo))
254 syslog(LOG_WARNING, "Malformed packet from %s", inet_ntoa(sa.sin_addr));
258 for(e=first_host; e; e=e->next)
259 if (e->addr == sa.sin_addr.s_addr)
263 e = malloc(sizeof(struct hostrec));
266 syslog(LOG_ERR, "Out of memory");
269 e->next = first_host;
271 h = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
274 sprintf(e->name, "%.30s", h->h_name);
275 for(c=e->name; *c; c++)
281 else if ((*c < 'A' || *c > 'Z') /* Filter out malicious characters */
282 && (*c < 'a' || *c > 'z')
283 && (*c < '0' || *c > '9')
288 strcpy(e->name, inet_ntoa(sa.sin_addr));
289 e->addr = sa.sin_addr.s_addr;
293 save_pkt(e->name, &pkt, r);
299 struct rywho_pkt pkt;
300 static char hostname[64];
303 if (!hostname[0] && gethostname(hostname, sizeof(hostname)) < 0)
304 die("gethostname: %m");
305 save_pkt(hostname, &pkt, sizeof(pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo));
313 if (last_local_scan + DEFAULT_SEND_TIME <= now)
315 last_local_scan = now;
318 for(e=first_host; e; e=e->next)
319 if (e->last_rec && e->last_rec + DEFAULT_DEAD_TIME < now)
321 if (unlink(e->name) < 0)
322 syslog(LOG_ERR, "unlink(%s): %m", e->name);
332 static struct sigaction sigact = { tick, 0, 0, NULL };
338 if (chdir(YWHO_SPOOL_DIR) < 0)
339 die("chdir(" YWHO_SPOOL_DIR "): %m");
341 sigaction(SIGALRM, &sigact, NULL);
353 struct rywho_pkt pkt;
361 if (send(sock, &pkt, sizeof(pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo), 0) < 0)
362 syslog(LOG_ERR, "sendmsg: %m");
363 sleep(DEFAULT_SEND_TIME);
368 main(int argc, char **argv)
372 if (argc != 1 && argc != 2)
374 fprintf(stderr, "Usage: nwhod [<server>]\n");