2 * The Remote User Information Daemon
4 * (c) 1997--2017 Martin Mares <mj@ucw.cz>
13 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
30 time_t last_rec; /* 0=down */
34 static int do_not_daemonize;
35 static int sock, port;
36 static struct hostrec *first_host;
37 static time_t now, last_local_scan;
38 static char hostname[64];
44 struct sockaddr_in sa;
48 if (! (h = gethostbyname(name)))
49 die("Failed to resolve %s", name);
54 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
56 die("Cannot create socket: %m");
58 sa.sin_family = AF_INET;
59 sa.sin_port = port = htons(NWHO_PORT);
60 sa.sin_addr.s_addr = INADDR_ANY;
61 if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
62 die("Cannot bind to UDP port %d: %m", NWHO_PORT);
66 memcpy(&sa.sin_addr.s_addr, h->h_addr, sizeof(sa.sin_addr.s_addr));
67 if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
68 die("Cannot connect socket: %m");
71 if (gethostname(hostname, sizeof(hostname)) < 0)
72 die("Unable to get my own host name: %m");
76 scan_utmp(struct nwho_pkt *p, time_t now)
83 char name[UT_NAMESIZE+10];
87 while ((u = getutent()) && cnt < MAX_USERS)
88 if (u->ut_type == USER_PROCESS && u->ut_user[0])
91 memcpy(name, u->ut_user, UT_NAMESIZE);
93 strcpy(h->name, name);
94 h->login_time = htonl(now - u->ut_time);
95 snprintf(h->con, sizeof(h->con), "%s", u->ut_line);
96 snprintf(device, sizeof(device), "/dev/%s", u->ut_line);
97 if (stat(device, &st) < 0)
99 h->mesg_y = !!(S_IWGRP & st.st_mode);
103 h->idle_time = htonl(now - last);
106 p->num_users = htonl(cnt);
110 scan_load(struct nwho_pkt *p)
115 n = open("/proc/uptime", O_RDONLY);
118 if (read(n, buf, sizeof(buf)) <= 0)
121 if (!sscanf(buf, "%d", &i))
123 p->uptime = htonl(i);
125 n = open("/proc/loadavg", O_RDONLY);
128 if (read(n, buf, sizeof(buf)) <= 0)
131 if (sscanf(buf, "%d.%d%d.%d%d.%d", &j[0], &j[1], &j[2], &j[3], &j[4], &j[5]) != 6)
133 p->avl[0] = htonl(j[0]*100 + j[1]);
134 p->avl[1] = htonl(j[2]*100 + j[3]);
135 p->avl[2] = htonl(j[4]*100 + j[5]);
139 make_pkt(struct nwho_pkt *pkt)
141 bzero(pkt, sizeof(*pkt));
142 pkt->magic = htonl(NWHO_MAGIC);
143 pkt->local_time = htonl(now);
157 while (e = readdir(d))
158 if (e->d_name[0] != '.')
164 save_pkt(char *name, struct nwho_pkt *pkt)
166 int len = nwho_pkt_size(pkt);
167 int fd = open(name, O_WRONLY | O_CREAT, 0666);
170 syslog(LOG_ERR, "open(%s): %m", name);
173 pkt->server_time = htonl(now);
174 if (write(fd, pkt, len) != len)
175 syslog(LOG_ERR, "write: %m");
180 static inline int /* Validation checks not implemented yet */
191 struct sockaddr_in sa;
192 socklen_t al = sizeof(sa);
193 int n = sizeof(struct nwho_pkt) - MAX_USERS * sizeof(struct userinfo);
198 alarm(DEFAULT_PRUNE_TIME);
199 r = recvfrom(sock, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa, &al);
206 syslog(LOG_ERR, "recvfrom: %m");
211 if (!is_valid(sa.sin_addr.s_addr) || sa.sin_port != port)
213 syslog(LOG_WARNING, "Received packet from invalid source %s:%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
218 pkt.magic != htonl(NWHO_MAGIC) ||
219 ntohl(pkt.num_users) > MAX_USERS ||
220 r < nwho_pkt_size(&pkt))
222 syslog(LOG_WARNING, "Malformed packet from %s", inet_ntoa(sa.sin_addr));
226 for(e=first_host; e; e=e->next)
227 if (e->addr == sa.sin_addr.s_addr)
232 e = malloc(sizeof(struct hostrec));
235 syslog(LOG_ERR, "Out of memory");
238 e->next = first_host;
240 h = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
243 snprintf(e->name, sizeof(e->name), "%s", h->h_name);
244 for (c=e->name; *c; c++)
250 else if ((*c < 'A' || *c > 'Z') /* Filter out malicious characters */
251 && (*c < 'a' || *c > 'z')
252 && (*c < '0' || *c > '9')
257 strcpy(e->name, inet_ntoa(sa.sin_addr));
258 e->addr = sa.sin_addr.s_addr;
262 save_pkt(e->name, &pkt);
271 save_pkt(hostname, &pkt);
279 if (last_local_scan + DEFAULT_SEND_TIME <= now)
281 last_local_scan = now;
284 for(e=first_host; e; e=e->next)
285 if (e->last_rec && e->last_rec + DEFAULT_DEAD_TIME < now)
287 if (unlink(e->name) < 0)
288 syslog(LOG_ERR, "unlink(%s): %m", e->name);
296 if (do_not_daemonize)
301 die("Fork failed: %m");
308 open("/dev/null", O_RDONLY);
322 static struct sigaction sigact;
325 if (chdir(NWHO_SPOOL_DIR) < 0)
326 die("chdir(" NWHO_SPOOL_DIR "): %m");
329 bzero(&sigact, sizeof(sigact));
330 sigact.sa_handler = tick;
331 sigaction(SIGALRM, &sigact, NULL);
352 if (send(sock, &pkt, nwho_pkt_size(&pkt), 0) < 0)
353 syslog(LOG_ERR, "sendmsg: %m");
354 sleep(DEFAULT_SEND_TIME);
361 fprintf(stderr, "Usage: nwhod [-d] [<server>]\n");
366 main(int argc, char **argv)
368 if (argc == 2 && !strcmp(argv[1], "--version"))
370 printf("nwho " STRINGIFY(VERSION) "\n");
375 while ((opt = getopt(argc, argv, "d")) >= 0)
379 do_not_daemonize = 1;
385 if (optind == argc-1 && argv[optind][0])
386 client(argv[optind]);
387 else if (optind == argc)