* syscalls.cc: Slightly cleanup all utmp functions.
(login): Use mutex to secure against concurrent access to wtmp file. (logout): Rewrite using POSIX calls. (utmp_fd): Initialized to -1 now. Any value < 0 is treated as closed in subsequent functions. (utmp_readonly): New variable, indicating utmp file open for reading only. (internal_setutent): New function implementing setutent(). (setutent): Call internal_setutent now. (endutent): Reset utmp_readonly. (getutent): Return immediately if utmp file can't be opened. (getutid): Ditto. (getutline): Ditto. (pututline): Ditto. Use mutex to secure against concurrent access to utmp file.
This commit is contained in:
		| @@ -1,3 +1,21 @@ | ||||
| 2003-03-29  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* syscalls.cc: Slightly cleanup all utmp functions. | ||||
| 	(login): Use mutex to secure against concurrent access to wtmp file. | ||||
| 	(logout): Rewrite using POSIX calls. | ||||
| 	(utmp_fd): Initialized to -1 now.  Any value < 0 is treated as closed | ||||
| 	in subsequent functions. | ||||
| 	(utmp_readonly): New variable, indicating utmp file open for reading | ||||
| 	only. | ||||
| 	(internal_setutent): New function implementing setutent(). | ||||
| 	(setutent): Call internal_setutent now. | ||||
| 	(endutent): Reset utmp_readonly. | ||||
| 	(getutent): Return immediately if utmp file can't be opened. | ||||
| 	(getutid): Ditto. | ||||
| 	(getutline): Ditto. | ||||
| 	(pututline): Ditto. Use mutex to secure against concurrent access to | ||||
| 	utmp file. | ||||
|  | ||||
| 2003-03-28  Christopher Faylor  <cgf@redhat.com> | ||||
|  | ||||
| 	* Makefile.in: Remove EXE_LDFLAGS.  Fix fhandler_CFLAGS typo.  Recognize .s suffix. | ||||
|   | ||||
| @@ -2501,98 +2501,113 @@ login (struct utmp *ut) | ||||
|  | ||||
|   pututline (ut); | ||||
|   endutent (); | ||||
|   /* Read/write to utmp must be atomic to prevent overriding data | ||||
|      by concurrent processes. */ | ||||
|   HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("wtmp_mutex", 0)); | ||||
|   if (mutex) | ||||
|     while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED) | ||||
|       ; | ||||
|   if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) | ||||
|     { | ||||
|       (void) write (fd, (char *) ut, sizeof (struct utmp)); | ||||
|       (void) close (fd); | ||||
|       write (fd, ut, sizeof *ut); | ||||
|       close (fd); | ||||
|     } | ||||
|   if (mutex) | ||||
|     { | ||||
|       ReleaseMutex (mutex); | ||||
|       CloseHandle (mutex); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* It isn't possible to use unix-style I/O function in logout code because | ||||
| cygwin's I/O subsystem may be inaccessible at logout () call time. | ||||
| FIXME (cgf): huh? | ||||
| */ | ||||
| extern "C" int | ||||
| logout (char *line) | ||||
| { | ||||
|   sigframe thisframe (mainthread); | ||||
|   int res = 0; | ||||
|   HANDLE ut_fd; | ||||
|   static const char path_utmp[] = _PATH_UTMP; | ||||
|   struct utmp ut_buf, *ut; | ||||
|  | ||||
|   path_conv win32_path (path_utmp); | ||||
|   if (win32_path.error) | ||||
|     return 0; | ||||
|  | ||||
|   ut_fd = CreateFile (win32_path.get_win32 (), | ||||
| 		      GENERIC_READ | GENERIC_WRITE, | ||||
| 		      FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||
| 		      &sec_none_nih, OPEN_EXISTING, | ||||
| 		      FILE_ATTRIBUTE_NORMAL, NULL); | ||||
|   if (ut_fd != INVALID_HANDLE_VALUE) | ||||
|   memset (&ut_buf, 0, sizeof ut_buf); | ||||
|   strncpy (ut_buf.ut_line, line, sizeof ut_buf.ut_line); | ||||
|   setutent (); | ||||
|   ut = getutline (&ut_buf); | ||||
|   if (ut) | ||||
|     { | ||||
|       struct utmp *ut; | ||||
|       struct utmp ut_buf[100]; | ||||
|       /* FIXME: utmp file access is not 64 bit clean for now. */ | ||||
|       __off32_t pos = 0;		/* Position in file */ | ||||
|       DWORD rd; | ||||
|       int fd; | ||||
|  | ||||
|       while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL) | ||||
| 	     && rd != 0) | ||||
|       /* We can't use ut further since it's a pointer to the static utmp_data | ||||
| 	 area (see below) and would get overwritten in pututline().  So we | ||||
| 	 copy it back to the local ut_buf. */ | ||||
|       memcpy (&ut_buf, ut, sizeof ut_buf); | ||||
|       ut_buf.ut_type = DEAD_PROCESS; | ||||
|       memset (ut_buf.ut_user, 0, sizeof ut_buf.ut_user); | ||||
|       time (&ut_buf.ut_time); | ||||
|       /* Read/write to utmp must be atomic to prevent overriding data | ||||
| 	 by concurrent processes. */ | ||||
|       HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("wtmp_mutex", 0)); | ||||
|       if (mutex) | ||||
| 	while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED) | ||||
| 	  ; | ||||
|       if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) | ||||
| 	{ | ||||
| 	  struct utmp *ut_end = (struct utmp *) ((char *) ut_buf + rd); | ||||
|  | ||||
| 	  for (ut = ut_buf; ut < ut_end; ut++, pos += sizeof (*ut)) | ||||
| 	    if (ut->ut_name[0] | ||||
| 		&& strncmp (ut->ut_line, line, sizeof (ut->ut_line)) == 0) | ||||
| 	      /* Found the entry for LINE; mark it as logged out.  */ | ||||
| 	  write (fd, &ut_buf, sizeof ut_buf); | ||||
| 	  close (fd); | ||||
| 	} | ||||
|       if (mutex) | ||||
| 	{ | ||||
| 		/* Zero out entries describing who's logged in.  */ | ||||
| 		memset (ut->ut_name, 0, sizeof (ut->ut_name)); | ||||
| 		memset (ut->ut_host, 0, sizeof (ut->ut_host)); | ||||
| 		time (&ut->ut_time); | ||||
|  | ||||
| 		/* Now seek back to the position in utmp at which UT occured, | ||||
| 		   and write the new version of UT there.  */ | ||||
| 		if ((SetFilePointer (ut_fd, pos, 0, FILE_BEGIN) != 0xFFFFFFFF) | ||||
| 		    && (WriteFile (ut_fd, (char *) ut, sizeof (*ut), | ||||
| 				   &rd, NULL))) | ||||
| 		  { | ||||
| 		    res = 1; | ||||
| 		    break; | ||||
| 	  ReleaseMutex (mutex); | ||||
| 	  CloseHandle (mutex); | ||||
| 	} | ||||
|       memset (ut_buf.ut_line, 0, sizeof ut_buf.ut_line); | ||||
|       ut_buf.ut_time = 0; | ||||
|       pututline (&ut_buf); | ||||
|       endutent (); | ||||
|     } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|       CloseHandle (ut_fd); | ||||
|     } | ||||
|  | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| static int utmp_fd = -2; | ||||
| static int utmp_fd = -1; | ||||
| static bool utmp_readonly = false; | ||||
| static char *utmp_file = (char *) _PATH_UTMP; | ||||
|  | ||||
| static struct utmp utmp_data; | ||||
|  | ||||
| static void | ||||
| internal_setutent (bool force_readwrite) | ||||
| { | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (force_readwrite && utmp_readonly) | ||||
|     endutent (); | ||||
|   if (utmp_fd < 0) | ||||
|     { | ||||
|       utmp_fd = open (utmp_file, O_RDWR | O_BINARY); | ||||
|       /* If open fails, we assume an unprivileged process (who?).  In this | ||||
| 	 case we try again for reading only unless the process calls | ||||
| 	 pututline() (==force_readwrite) in which case opening just fails. */ | ||||
|       if (utmp_fd < 0 && !force_readwrite) | ||||
|         { | ||||
| 	  utmp_fd = open (utmp_file, O_RDONLY | O_BINARY); | ||||
| 	  if (utmp_fd >= 0) | ||||
| 	    utmp_readonly = true; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     lseek (utmp_fd, 0, SEEK_SET); | ||||
| } | ||||
|  | ||||
| extern "C" void | ||||
| setutent () | ||||
| { | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (utmp_fd == -2) | ||||
|     utmp_fd = open (utmp_file, O_RDWR); | ||||
|   else | ||||
|     lseek (utmp_fd, 0, SEEK_SET); | ||||
|   internal_setutent (false); | ||||
| } | ||||
|  | ||||
| extern "C" void | ||||
| endutent () | ||||
| { | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (utmp_fd != -2) | ||||
|   if (utmp_fd >= 0) | ||||
|     { | ||||
|       close (utmp_fd); | ||||
|       utmp_fd = -2; | ||||
|       utmp_fd = -1; | ||||
|       utmp_readonly = false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -2614,9 +2629,13 @@ extern "C" struct utmp * | ||||
| getutent () | ||||
| { | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (utmp_fd == -2) | ||||
|     setutent (); | ||||
|   if (read (utmp_fd, &utmp_data, sizeof (utmp_data)) != sizeof (utmp_data)) | ||||
|   if (utmp_fd < 0) | ||||
|     { | ||||
|       internal_setutent (false); | ||||
|       if (utmp_fd < 0) | ||||
|         return NULL; | ||||
|     } | ||||
|   if (read (utmp_fd, &utmp_data, sizeof utmp_data) != sizeof utmp_data) | ||||
|     return NULL; | ||||
|   return &utmp_data; | ||||
| } | ||||
| @@ -2627,7 +2646,13 @@ getutid (struct utmp *id) | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (check_null_invalid_struct_errno (id)) | ||||
|     return NULL; | ||||
|   while (read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data)) | ||||
|   if (utmp_fd < 0) | ||||
|     { | ||||
|       internal_setutent (false); | ||||
|       if (utmp_fd < 0) | ||||
|         return NULL; | ||||
|     } | ||||
|   while (read (utmp_fd, &utmp_data, sizeof utmp_data) == sizeof utmp_data) | ||||
|     { | ||||
|       switch (id->ut_type) | ||||
| 	{ | ||||
| @@ -2658,12 +2683,18 @@ getutline (struct utmp *line) | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (check_null_invalid_struct_errno (line)) | ||||
|     return NULL; | ||||
|   while (read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data)) | ||||
|   if (utmp_fd < 0) | ||||
|     { | ||||
|       internal_setutent (false); | ||||
|       if (utmp_fd < 0) | ||||
|         return NULL; | ||||
|     } | ||||
|   while (read (utmp_fd, &utmp_data, sizeof utmp_data) == sizeof utmp_data) | ||||
|     { | ||||
|       if ((utmp_data.ut_type == LOGIN_PROCESS || | ||||
| 	   utmp_data.ut_type == USER_PROCESS) && | ||||
| 	  !strncmp (utmp_data.ut_line, line->ut_line, | ||||
| 		    sizeof (utmp_data.ut_line))) | ||||
| 		    sizeof utmp_data.ut_line)) | ||||
| 	return &utmp_data; | ||||
|     } | ||||
|   return NULL; | ||||
| @@ -2675,11 +2706,24 @@ pututline (struct utmp *ut) | ||||
|   sigframe thisframe (mainthread); | ||||
|   if (check_null_invalid_struct (ut)) | ||||
|     return; | ||||
|   setutent (); | ||||
|   internal_setutent (true); | ||||
|   if (utmp_fd < 0) | ||||
|     return; | ||||
|   /* Read/write to utmp must be atomic to prevent overriding data | ||||
|      by concurrent processes. */ | ||||
|   HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("utmp_mutex", 0)); | ||||
|   if (mutex) | ||||
|     while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED) | ||||
|       ; | ||||
|   struct utmp *u; | ||||
|   if ((u = getutid (ut))) | ||||
|     lseek (utmp_fd, -sizeof(struct utmp), SEEK_CUR); | ||||
|     lseek (utmp_fd, -sizeof *ut, SEEK_CUR); | ||||
|   else | ||||
|     lseek (utmp_fd, 0, SEEK_END); | ||||
|   (void) write (utmp_fd, (char *) ut, sizeof (struct utmp)); | ||||
|   write (utmp_fd, ut, sizeof *ut); | ||||
|   if (mutex) | ||||
|     { | ||||
|       ReleaseMutex (mutex); | ||||
|       CloseHandle (mutex); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user