/*
- * The Remote User Information Daemon 1.9
+ * The Remote User Information Daemon
*
- * (c) 1997--2001 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * This software may be freely distributed and used according to the terms
- * of the GNU General Public License. See file COPYING in any of the GNU packages.
+ * (c) 1997--2017 Martin Mares <mj@ucw.cz>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdarg.h>
#include <fcntl.h>
+#include <getopt.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <utmp.h>
#include <signal.h>
#include <dirent.h>
-#include <asm/types.h>
#include <errno.h>
-#include "net.h"
+#include "nwho.h"
struct hostrec {
struct hostrec *next;
char name[32];
time_t last_rec; /* 0=down */
- __u32 addr;
+ u32 addr;
};
+static int do_not_daemonize;
static int sock, port;
static struct hostrec *first_host;
static time_t now, last_local_scan;
-
-static void die(char *msg, ...) __attribute__((noreturn));
-
-static void
-die(char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "nwhod: ");
- vfprintf(stderr, msg, args);
- fputc('\n', stderr);
- exit(1);
-}
+static char hostname[64];
static void
net_init(char *name)
if (name)
{
if (! (h = gethostbyname(name)))
- die("%s: %m", name);
+ die("Failed to resolve %s", name);
}
else
h = NULL;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
- die("socket: %m");
+ die("Cannot create socket: %m");
sa.sin_family = AF_INET;
- sa.sin_port = port = NWHO_PORT;
+ sa.sin_port = port = htons(NWHO_PORT);
sa.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
- die("bind: %m");
+ die("Cannot bind to UDP port %d: %m", NWHO_PORT);
if (h)
{
memcpy(&sa.sin_addr.s_addr, h->h_addr, sizeof(sa.sin_addr.s_addr));
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
- die("connect: %m");
+ die("Cannot connect socket: %m");
}
+
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ die("Unable to get my own host name: %m");
}
static void
-scan_utmp(struct rywho_pkt *p, time_t now)
+scan_utmp(struct nwho_pkt *p, time_t now)
{
struct utmp *u;
int cnt = 0;
name[9] = 0;
strcpy(h->name, name);
h->login_time = htonl(now - u->ut_time);
- sprintf(h->con, "%.7s", u->ut_line);
- sprintf(device, "/dev/%s", u->ut_line);
+ snprintf(h->con, sizeof(h->con), "%s", u->ut_line);
+ snprintf(device, sizeof(device), "/dev/%s", u->ut_line);
if (stat(device, &st) < 0)
continue;
h->mesg_y = !!(S_IWGRP & st.st_mode);
last = st.st_atime;
- if (st.st_mtime > last)
- last = st.st_mtime;
- if (st.st_ctime > last)
- last = st.st_ctime;
if (now < last)
last = now;
h->idle_time = htonl(now - last);
}
static void
-scan_load(struct rywho_pkt *p)
+scan_load(struct nwho_pkt *p)
{
int n, i, j[6];
char buf[256];
}
static void
-make_pkt(struct rywho_pkt *pkt)
+make_pkt(struct nwho_pkt *pkt)
{
- bzero(pkt, sizeof(pkt));
+ bzero(pkt, sizeof(*pkt));
pkt->magic = htonl(NWHO_MAGIC);
pkt->local_time = htonl(now);
scan_utmp(pkt, now);
}
static void
-save_pkt(char *name, struct rywho_pkt *pkt, int len)
+save_pkt(char *name, struct nwho_pkt *pkt)
{
+ int len = nwho_pkt_size(pkt);
int fd = open(name, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
{
}
static inline int /* Validation checks not implemented yet */
-is_valid(__u32 ipa)
+is_valid(u32 ipa)
{
return 1;
}
static void
receive(void)
{
- int r, al;
- struct rywho_pkt pkt;
+ int r;
+ struct nwho_pkt pkt;
struct sockaddr_in sa;
- int n = sizeof(struct rywho_pkt) - MAX_USERS * sizeof(struct userinfo);
+ socklen_t al = sizeof(sa);
+ int n = sizeof(struct nwho_pkt) - MAX_USERS * sizeof(struct userinfo);
struct hostrec *e;
struct hostent *h;
char *c;
alarm(DEFAULT_PRUNE_TIME);
- al = sizeof(sa);
r = recvfrom(sock, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa, &al);
alarm(0);
now = time(NULL);
if (!is_valid(sa.sin_addr.s_addr) || sa.sin_port != port)
{
- syslog(LOG_WARNING, "Received packet from invalid source %s.%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
+ syslog(LOG_WARNING, "Received packet from invalid source %s:%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
return;
}
- if (r < n || r != n + ntohl(pkt.num_users)*sizeof(struct userinfo))
+ if (r < n ||
+ pkt.magic != htonl(NWHO_MAGIC) ||
+ ntohl(pkt.num_users) > MAX_USERS ||
+ r < nwho_pkt_size(&pkt))
{
syslog(LOG_WARNING, "Malformed packet from %s", inet_ntoa(sa.sin_addr));
return;
}
- if (pkt.magic != htonl(NWHO_MAGIC))
- {
- syslog(LOG_WARNING, "Received ancient nwho packet from %s", inet_ntoa(sa.sin_addr));
- return;
- }
-
for(e=first_host; e; e=e->next)
if (e->addr == sa.sin_addr.s_addr)
break;
+
if (!e)
{
e = malloc(sizeof(struct hostrec));
h = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
if (h)
{
- sprintf(e->name, "%.30s", h->h_name);
- for(c=e->name; *c; c++)
+ snprintf(e->name, sizeof(e->name), "%s", h->h_name);
+ for (c=e->name; *c; c++)
if (*c == '.')
{
*c = 0;
}
e->last_rec = now;
- save_pkt(e->name, &pkt, r);
+ save_pkt(e->name, &pkt);
}
static void
local_scan(void)
{
- struct rywho_pkt pkt;
- static char hostname[64];
+ struct nwho_pkt pkt;
make_pkt(&pkt);
- if (!hostname[0] && gethostname(hostname, sizeof(hostname)) < 0)
- die("gethostname: %m");
- save_pkt(hostname, &pkt, sizeof(pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo));
+ save_pkt(hostname, &pkt);
}
static void
static void
daemonize(void)
{
+ if (do_not_daemonize)
+ return;
+
+ pid_t pid = fork();
+ if (pid < 0)
+ die("Fork failed: %m");
+ if (pid)
+ exit(0);
+
close(0);
close(1);
close(2);
static void
client(char *serv)
{
- struct rywho_pkt pkt;
+ struct nwho_pkt pkt;
net_init(serv);
utmpname(UTMP_FILE);
{
now = time(NULL);
make_pkt(&pkt);
- if (send(sock, &pkt, sizeof(pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo), 0) < 0)
+ if (send(sock, &pkt, nwho_pkt_size(&pkt), 0) < 0)
syslog(LOG_ERR, "sendmsg: %m");
sleep(DEFAULT_SEND_TIME);
}
}
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: nwhod [-d] [<server>]\n");
+ exit(1);
+}
+
int
main(int argc, char **argv)
{
- int pid;
-
- if (argc != 1 && argc != 2)
+ if (argc == 2 && !strcmp(argv[1], "--version"))
{
- fprintf(stderr, "Usage: nwhod [<server>]\n");
- return 1;
+ printf("nwho " STRINGIFY(VERSION) "\n");
+ return 0;
}
- pid = fork();
- if (pid < 0)
+
+ int opt;
+ while ((opt = getopt(argc, argv, "d")) >= 0)
+ switch (opt)
+ {
+ case 'd':
+ do_not_daemonize = 1;
+ break;
+ default:
+ usage();
+ }
+
+ if (optind == argc-1)
{
- perror("fork");
- return 1;
+ if (argv[optind][0])
+ client(argv[optind]);
+ else
+ server();
}
- if (pid)
- return 0;
- if (argc == 2)
- client(argv[1]);
- else if (argc == 1)
+ else if (optind == argc)
server();
- return 1;
+ else
+ usage();
+ return 0;
}