about summary refs log tree commit diff
path: root/login
diff options
context:
space:
mode:
Diffstat (limited to 'login')
-rw-r--r--login/Makefile2
-rw-r--r--login/programs/request.c20
-rw-r--r--login/programs/utmpd.c10
-rw-r--r--login/programs/utmpd.h7
-rw-r--r--login/utmp_daemon.c52
-rw-r--r--login/utmp_file.c89
6 files changed, 116 insertions, 64 deletions
diff --git a/login/Makefile b/login/Makefile
index 916dd6c512..e4f9a9e9be 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -27,7 +27,7 @@ headers	:= utmp.h utmpbits.h lastlog.h pty.h
 routines := getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmp_daemon utmpname updwtmp
 
-others = utmpd
+others = utmpd utmpdump
 install-sbin = utmpd
 utmpd-routines := connection database error request xtmp
 extra-objs := $(utmpd-routines:=.o)
diff --git a/login/programs/request.c b/login/programs/request.c
index d2c12e68cf..5e6bfa19cf 100644
--- a/login/programs/request.c
+++ b/login/programs/request.c
@@ -182,12 +182,8 @@ do_setutent (client_connection *connection)
   setutent_request *request;
   setutent_reply reply;
 
+  /* The request size varies, so don't check it.  */
   request = (setutent_request *)connection->read_base;
-  if (request->header.size != sizeof (setutent_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
 
   /* Initialize reply.  */
   reply.header.version = UTMPD_VERSION;
@@ -195,7 +191,8 @@ do_setutent (client_connection *connection)
   reply.header.type = UTMPD_REQ_SETUTENT;
 
   /* Select database.  */
-  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
+  if (!strncmp (request->file, _PATH_UTMP,
+		request->header.size - sizeof (setutent_request)))
     connection->database = utmp_db;
   else
     {
@@ -450,7 +447,7 @@ do_pututline (client_connection *connection)
       goto return_error;
     }
 
-  if (connection->database == NULL || connection->position == -1)
+  if (connection->database == NULL)
     {
       errno = ESRCH;
       goto return_error;
@@ -520,12 +517,8 @@ do_updwtmp (client_connection *connection)
   updwtmp_reply reply;
   utmp_database *database;
 
+  /* The request size varies, so don't check it.  */
   request = (updwtmp_request *)connection->read_base;
-  if (request->header.size != sizeof (updwtmp_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
 
   /* Initialize reply.  */
   reply.header.version = UTMPD_VERSION;
@@ -539,7 +532,8 @@ do_updwtmp (client_connection *connection)
     }
 
   /* Select database.  */
-  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
+  if (!strncmp (request->file, _PATH_UTMP,
+		request->header.size - sizeof (updwtmp_request)))
     database = utmp_db;
   else
     {
diff --git a/login/programs/utmpd.c b/login/programs/utmpd.c
index ca310a21de..3c8d626a84 100644
--- a/login/programs/utmpd.c
+++ b/login/programs/utmpd.c
@@ -134,8 +134,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
     usage (EXIT_SUCCESS);
 
   signal (SIGINT, termination_handler);
+  signal (SIGQUIT, termination_handler);
   signal (SIGTERM, termination_handler);
-
+  
   /* Check if we are already running.  */
   if (check_pid (_PATH_UTMPDPID))
     error (EXIT_FAILURE, 0, "already running");
@@ -168,8 +169,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
 
       if (write_pid (_PATH_UTMPDPID) < 0)
 	warning (errno, "%s", _PATH_UTMPDPID);
-    }
 
+      /* Ignore job control signals.  */
+      signal (SIGTTOU, SIG_IGN);
+      signal (SIGTTIN, SIG_IGN);
+      signal (SIGTSTP, SIG_IGN);
+    }
+  
   /* Drop priviliges.  */
   drop_priviliges ();
   
diff --git a/login/programs/utmpd.h b/login/programs/utmpd.h
index 8fbc33c923..ef92a1490b 100644
--- a/login/programs/utmpd.h
+++ b/login/programs/utmpd.h
@@ -22,7 +22,6 @@
 
 /* This is an *internal* header.  */
 
-#include <limits.h>
 #include <stddef.h>
 #include <utmp.h>
 
@@ -68,7 +67,7 @@ typedef struct
 {
   request_header header;
   /* File to use.  */
-  char file[_POSIX_PATH_MAX + 1];
+  char file[0];
 } setutent_request;
 
 typedef struct
@@ -100,10 +99,10 @@ typedef struct
 typedef struct
 {
   request_header header;
-  /* File to use.  */
-  char file[_POSIX_PATH_MAX + 1];
   /* Entry to write.  */
   struct utmp utmp;
+  /* File to use.  */
+  char file[0];
 } updwtmp_request;
 
 
diff --git a/login/utmp_daemon.c b/login/utmp_daemon.c
index 705c8b3de9..e0a20e9a9f 100644
--- a/login/utmp_daemon.c
+++ b/login/utmp_daemon.c
@@ -227,24 +227,35 @@ updwtmp_daemon (const char *file, const struct utmp *utmp)
 static int
 do_setutent (int sock)
 {
-  setutent_request request;
+  setutent_request *request;
   setutent_reply reply;
+  size_t size;
 
-  request.header.version = UTMPD_VERSION;
-  request.header.size = sizeof (setutent_request);
-  request.header.type = UTMPD_REQ_SETUTENT;
-  strncpy (request.file, __libc_utmp_file_name, sizeof request.file);
+  size = sizeof (setutent_request) + strlen (__libc_utmp_file_name) + 1;
+  
+  request = malloc (size);
+  if (request == NULL)
+    return -1;
+  
+  request->header.version = UTMPD_VERSION;
+  request->header.size = size;
+  request->header.type = UTMPD_REQ_SETUTENT;
+  strcpy (request->file, __libc_utmp_file_name);
 
   reply.header.version = UTMPD_VERSION;
   reply.header.size = sizeof (setutent_reply);
   reply.header.type = UTMPD_REQ_SETUTENT;
 
-  if (send_request (sock, &request.header, &reply.header) < 0)
-    return -1;
+  if (send_request (sock, &request->header, &reply.header) < 0)
+    {
+      free (request);
+      return -1;
+    }
 
   if (reply.result < 0)
     __set_errno (reply.errnum);
 
+  free (request);
   return reply.result;
 }
 
@@ -375,25 +386,36 @@ do_pututline (int sock, const struct utmp *utmp)
 static int
 do_updwtmp (int sock, const char *file, const struct utmp *utmp)
 {
-  updwtmp_request request;
+  updwtmp_request *request;
   updwtmp_reply reply;
+  size_t size;
 
-  request.header.version = UTMPD_VERSION;
-  request.header.size = sizeof (updwtmp_request);
-  request.header.type = UTMPD_REQ_UPDWTMP;
-  strncpy (request.file, file, sizeof request.file);
-  memcpy (&request.utmp, utmp, sizeof (struct utmp));
+  size = sizeof (updwtmp_request) + strlen (file) + 1;
+  
+  request = malloc (size);
+  if (request == NULL)
+    return -1;
+  
+  request->header.version = UTMPD_VERSION;
+  request->header.size = size;
+  request->header.type = UTMPD_REQ_UPDWTMP;
+  memcpy (&request->utmp, utmp, sizeof (struct utmp));
+  strcpy (request->file, file);
 
   reply.header.version = UTMPD_VERSION;
   reply.header.size = sizeof (updwtmp_reply);
   reply.header.type = UTMPD_REQ_UPDWTMP;
 
-  if (send_request (sock, &request.header, &reply.header) < 0)
-    return -1;
+  if (send_request (sock, &request->header, &reply.header) < 0)
+    {
+      free (request);
+      return -1;
+    }
 
   if (reply.result < 0)
     __set_errno (reply.errnum);
 
+  free (request);
   return reply.result;
 }
 
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 2026070f14..51b33226e0 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -24,10 +24,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <utmp.h>
-#include <sys/file.h>
-#include <sys/stat.h>
 
 #include "utmp-private.h"
 
@@ -116,7 +115,7 @@ endutent_file (void)
 static int
 getutent_r_file (struct utmp *buffer, struct utmp **result)
 {
-  int nbytes;
+  ssize_t nbytes;
   struct flock fl;			/* Information struct for locking.  */
 
   /* Open utmp file if not already done.  */
@@ -136,7 +135,7 @@ getutent_r_file (struct utmp *buffer, struct utmp **result)
 
   /* Try to get the lock.  */
   memset (&fl, '\0', sizeof (struct flock));
-  fl.l_type = F_WRLCK;
+  fl.l_type = F_RDLCK;
   fl.l_whence = SEEK_SET;
   fcntl (file_fd, F_SETLKW, &fl);
 
@@ -170,12 +169,20 @@ static int
 getutline_r_file (const struct utmp *line, struct utmp *buffer,
 		  struct utmp **result)
 {
+  struct flock fl;
+  
   if (file_fd < 0 || file_offset == -1l)
     {
       *result = NULL;
       return -1;
     }
 
+  /* Try to get the lock.  */
+  memset (&fl, '\0', sizeof (struct flock));
+  fl.l_type = F_RDLCK;
+  fl.l_whence = SEEK_SET;
+  fcntl (file_fd, F_SETLKW, &fl);
+
   while (1)
     {
       /* Read the next entry.  */
@@ -185,7 +192,7 @@ getutline_r_file (const struct utmp *line, struct utmp *buffer,
 	  __set_errno (ESRCH);
 	  file_offset = -1l;
 	  *result = NULL;
-	  return -1;
+	  goto unlock_return;
 	}
       file_offset += sizeof (struct utmp);
 
@@ -203,7 +210,12 @@ getutline_r_file (const struct utmp *line, struct utmp *buffer,
   memcpy (buffer, &last_entry, sizeof (struct utmp));
   *result = buffer;
 
-  return 0;
+unlock_return:
+  /* And unlock the file.  */
+  fl.l_type = F_UNLCK;
+  fcntl (file_fd, F_SETLKW, &fl);
+
+  return ((result == NULL) ? -1 : 0);
 }
 
 
@@ -237,6 +249,15 @@ proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
 static int
 internal_getut_r (const struct utmp *id, struct utmp *buffer)
 {
+  int result = -1;
+  struct flock fl;
+  
+  /* Try to get the lock.  */
+  memset (&fl, '\0', sizeof (struct flock));
+  fl.l_type = F_RDLCK;
+  fl.l_whence = SEEK_SET;
+  fcntl (file_fd, F_SETLKW, &fl);
+
 #if _HAVE_UT_TYPE - 0
   if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
       || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
@@ -252,7 +273,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer)
 	    {
 	      __set_errno (ESRCH);
 	      file_offset = -1l;
-	      return -1;
+	      goto unlock_return;
 	    }
 	  file_offset += sizeof (struct utmp);
 
@@ -274,7 +295,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer)
 	    {
 	      __set_errno (ESRCH);
 	      file_offset = -1l;
-	      return -1;
+	      goto unlock_return;
 	    }
 	  file_offset += sizeof (struct utmp);
 
@@ -283,7 +304,14 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer)
 	}
     }
 
-  return 0;
+  result = 0;
+
+unlock_return:
+  /* And unlock the file.  */
+  fl.l_type = F_UNLCK;
+  fcntl (file_fd, F_SETLKW, &fl);
+
+  return result;
 }
 
 
@@ -401,47 +429,50 @@ static int
 updwtmp_file (const char *file, const struct utmp *utmp)
 {
   int result = -1;
-  struct stat st;
-  ssize_t nbytes;
+  struct flock fl;
+  off_t offset;
   int fd;
   
   /* Open WTMP file.  */
-  fd = __open (file, O_WRONLY | O_APPEND);
+  fd = open (file, O_WRONLY);
   if (fd < 0)
     return -1;
 
-  /* Try to lock the file.  */
-  if (__flock (fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS)
+  /* Try to get the lock.  */
+  memset (&fl, '\0', sizeof (struct flock));
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fcntl (fd, F_SETLKW, &fl);
+  
+  /* Remember original size of log file.  */
+  offset = lseek (fd, 0, SEEK_END);
+  if (offset % sizeof (struct utmp) != 0)
     {
-      /* Oh, oh.  The file is already locked.  Wait a bit and try again.  */
-      sleep (1);
+      offset -= offset % sizeof (struct utmp);
+      ftruncate (fd, offset);
 
-      /*  This time we ignore the error.  */
-      __flock (fd, LOCK_EX | LOCK_NB);
+      if (lseek (fd, 0, SEEK_END) < 0)
+	goto unlock_return;
     }
 
-  /* Remember original size of log file.  */
-  if (__fstat (fd, &st) < 0)
-    goto fail;
-
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  nbytes = __write (fd, utmp, sizeof (struct utmp));
-  if (nbytes != sizeof (struct utmp))
+  if (write (fd, utmp, sizeof (struct utmp)) != sizeof (struct utmp))
     {
-      ftruncate (fd, st.st_size);
-      goto fail;
+      ftruncate (fd, offset);
+      goto unlock_return;
     }
 
   result = 0;
   
-fail:
+unlock_return:
   /* And unlock the file.  */
-  __flock (fd, LOCK_UN);
+  fl.l_type = F_UNLCK;
+  fcntl (fd, F_SETLKW, &fl);
 
   /* Close WTMP file.  */
-  __close (fd);
+  close (fd);
 
   return result;
 }