]> mj.ucw.cz Git - nwho.git/blobdiff - nwhod.c
Make the systemd service be ordered after autofs.service, so that it is ordered befor...
[nwho.git] / nwhod.c
diff --git a/nwhod.c b/nwhod.c
index d706fbf257cbc3a78b22e2904e0c5ac9be94aee3..9407f6fa0334af796649741e361cc4b0e30969a8 100644 (file)
--- a/nwhod.c
+++ b/nwhod.c
@@ -1,17 +1,14 @@
 /*
- *     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)
@@ -62,31 +46,34 @@ 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;
@@ -105,16 +92,12 @@ scan_utmp(struct rywho_pkt *p, time_t now)
        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);
@@ -124,7 +107,7 @@ scan_utmp(struct rywho_pkt *p, time_t now)
 }
 
 static void
-scan_load(struct rywho_pkt *p)
+scan_load(struct nwho_pkt *p)
 {
   int n, i, j[6];
   char buf[256];
@@ -153,9 +136,9 @@ scan_load(struct rywho_pkt *p)
 }
 
 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);
@@ -178,8 +161,9 @@ cleanup(void)
 }
 
 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)
     {
@@ -194,7 +178,7 @@ save_pkt(char *name, struct rywho_pkt *pkt, int len)
 }
 
 static inline int                      /* Validation checks not implemented yet */
-is_valid(__u32 ipa)
+is_valid(u32 ipa)
 {
   return 1;
 }
@@ -202,16 +186,16 @@ is_valid(__u32 ipa)
 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);
@@ -226,25 +210,23 @@ receive(void)
 
   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));
@@ -258,8 +240,8 @@ receive(void)
       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;
@@ -277,19 +259,16 @@ receive(void)
     }
 
   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
@@ -314,6 +293,15 @@ do_tick(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);
@@ -352,7 +340,7 @@ server(void)
 static void
 client(char *serv)
 {
-  struct rywho_pkt pkt;
+  struct nwho_pkt pkt;
 
   net_init(serv);
   utmpname(UTMP_FILE);
@@ -361,33 +349,49 @@ client(char *serv)
     {
       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;
 }