etc_changed, passwd & group.

Pierre A. Humblet Pierre.Humblet@ieee.org
Thu Jan 16 06:57:00 GMT 2003


Chris,

Here is the code as it stands. It compiles & runs, and passes
fork tests correctly. Feel free to takeover or at least
have a look. I will continue testing tomorrow evening.

I include only the 5 files that are related to etc_changed,
the 5 others (setuid on Win9X) can wait.

Pierre

P.S. Does GetFileInformationByHandle () work reliably on network drives
(sse MSDN warnings)? If so, in pwdgrp.h read () it could replace 
GetFileSize and GetFileTime and one could also verify that the file hasn't
mutated into a directory.

2003/01/16  Pierre Humblet  <pierre.humblet@ieee.org>

	* cygheap.h (struct init_cygheap): Remove etc_changed_h and 
	etc_changed members. 
	* cygheap.cc (init_cygheap::etc_changed): Delete.
	* pwdgroup.h (class pwdgrp_check): Delete.
	(class pwdgrp_read): Delete.
	(enum etc_changed_bits): Create.
	(struct etc_change): Create.
	(class pwdgrp_file): Create.
	* passwd.cc: Major changes to use class pwdgrp_file instead of classes 
	pwdgrp_check and pwdgrp_read.
	(etc_change::etc_watch): Create.
	(etc_change::etc_changed): Create.
	(grab_int): Replace almost_null by "".
	(read_etc_passwd): On NT, add a line for uid = -1. Use same default uid
	for Win95 and NT. Call cygheap_user::ontherange to initialize HOME. 
	* grp.cc: Major changes to use class pwdgrp_file instead of classes 
	pwdgrp_check and pwdgrp_read.
	(read_etc_group): On NT, add a line for gid = -1. Change name "unknown"
	to "mkgroup". 
	(internal_getgrgid): Do not return default in nontsec case.
	(internal_getgroups): Add argument srchsid and look for it in groups
	if not NULL.
-------------- next part --------------
Index: cygheap.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygheap.h,v
retrieving revision 1.56
diff -u -p -r1.56 cygheap.h
--- cygheap.h	22 Oct 2002 16:18:55 -0000	1.56
+++ cygheap.h	16 Jan 2003 06:47:32 -0000
@@ -216,15 +216,12 @@ struct init_cygheap
   mode_t umask;
   HANDLE shared_h;
   HANDLE console_h;
-  HANDLE etc_changed_h;
   char *cygwin_regname;
   cwdstuff cwd;
   dtable fdtab;
 #ifdef DEBUGGING
   cygheap_debug debug;
 #endif
-
-  bool etc_changed ();
 };

 #define CYGHEAPSIZE (sizeof (init_cygheap) + (16000 * sizeof (fhandler_union)) + (4 * 65536))
Index: cygheap.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygheap.cc,v
retrieving revision 1.75
diff -u -p -r1.75 cygheap.cc
--- cygheap.cc	15 Jan 2003 17:27:20 -0000	1.75
+++ cygheap.cc	16 Jan 2003 06:47:38 -0000
@@ -380,39 +380,6 @@ cstrdup1 (const char *s)
   return p;
 }

-bool
-init_cygheap::etc_changed ()
-{
-  bool res = 0;
-
-  if (!etc_changed_h)
-    {
-      path_conv pwd ("/etc");
-      etc_changed_h = FindFirstChangeNotification (pwd, FALSE,
-					      FILE_NOTIFY_CHANGE_LAST_WRITE);
-      if (etc_changed_h == INVALID_HANDLE_VALUE)
-	system_printf ("Can't open /etc for checking, %E", (char *) pwd,
-		       etc_changed_h);
-      else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc,
-				 &etc_changed_h, 0, TRUE,
-				 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
-	{
-	  system_printf ("Can't inherit /etc handle, %E", (char *) pwd,
-			 etc_changed_h);
-	  etc_changed_h = INVALID_HANDLE_VALUE;
-	}
-    }
-
-   if (etc_changed_h != INVALID_HANDLE_VALUE
-       && WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0)
-     {
-       (void) FindNextChangeNotification (etc_changed_h);
-       res = 1;
-     }
-
-  return res;
-}
-
 void
 cygheap_root::set (const char *posix, const char *native)
 {
Index: pwdgrp.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/pwdgrp.h,v
retrieving revision 1.8
diff -u -p -r1.8 pwdgrp.h
--- pwdgrp.h	10 Dec 2002 12:43:49 -0000	1.8
+++ pwdgrp.h	16 Jan 2003 06:47:44 -0000
@@ -19,74 +19,101 @@ extern struct __group32 *internal_getgrs
 extern struct __group32 *internal_getgrgid (__gid32_t gid, BOOL = FALSE);
 extern struct __group32 *internal_getgrnam (const char *, BOOL = FALSE);
 extern struct __group32 *internal_getgrent (int);
-int internal_getgroups (int, __gid32_t *);
+int internal_getgroups (int, __gid32_t *, cygsid * = NULL);
+
+enum etc_changed_bits
+{
+  ETC_PASSWD = 1,
+  ETC_GROUP= 2
+};
+
+struct etc_change
+{
+  HANDLE etc_changed_h;
+  int etc_changed_flags;
+  void etc_watch ();
+  bool etc_changed (etc_changed_bits);
+};

 enum pwdgrp_state {
   uninitialized = 0,
   initializing,
-  loaded
+  stable
 };

-class pwdgrp_check {
-  pwdgrp_state	state;
-  FILETIME	last_modified;
-  char		file_w32[MAX_PATH];
+class pwdgrp_file {
+  path_conv pc;
+  pwdgrp_state	*stateptr; /* state itself is NO_COPY */
+  const char *posix_fname;
+  etc_changed_bits me;
+  HANDLE fh;
+  FILETIME last_modified;
+  char *buf;
+  char *lptr, *eptr;
+  static struct etc_change NO_COPY etc;

 public:
-  pwdgrp_check () : state (uninitialized) {}
-  BOOL isinitializing ()
+  pwdgrp_file (const char *fname, pwdgrp_state * statep, etc_changed_bits who)
+    {
+      posix_fname = fname;
+      stateptr = statep;
+      me = who;
+    }
+  bool setpc ()
     {
-      if (state <= initializing)
-	state = initializing;
-      else if (cygheap->etc_changed ())
+      if (!pc.exists ())
         {
-	  if (!file_w32[0])
-	    state = initializing;
-	  else
+	  pc.check (posix_fname);
+	  if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
 	    {
-	      HANDLE h;
-	      WIN32_FIND_DATA data;
-
-	      if ((h = FindFirstFile (file_w32, &data)) != INVALID_HANDLE_VALUE)
-	        {
-		  if (CompareFileTime (&data.ftLastWriteTime, &last_modified) > 0)
-		    state = initializing;
-		  FindClose (h);
-		}
+	      pc.check ("");
+	      return false;
 	    }
 	}
-      return state == initializing;
+      return true;
     }
-  void operator = (pwdgrp_state nstate)
+  bool iamchanged ()
     {
-      state = nstate;
+      HANDLE h;
+      WIN32_FIND_DATA data;
+      bool ret = false;
+
+      if ((h = FindFirstFile (pc, &data)) != INVALID_HANDLE_VALUE)
+        {
+	  ret = (CompareFileTime (&data.ftLastWriteTime, &last_modified) > 0);
+	  FindClose (h);
+	}
+      return ret;
+    }
+  BOOL isuninitialized ()
+    {
+       if (*stateptr != uninitialized)
+	 return false;
+       /* start watching /etc */
+       etc.etc_watch ();
+       /* buf isn't null when forked with file loaded */
+       if (setpc () && buf && !iamchanged ())
+         {
+	    *stateptr = stable;
+	    return false;
+	 }
+       return true;
     }
-  BOOL isuninitialized () const { return state == uninitialized; }
-  void set_last_modified (HANDLE fh, const char *name)
+  BOOL isinitializing ()
     {
-      if (!file_w32[0])
-	strcpy (file_w32, name);
-      GetFileTime (fh, NULL, NULL, &last_modified);
+      if (*stateptr <= initializing)
+        return true;
+      else if (!etc.etc_changed (me) || !setpc () || !iamchanged ())
+	return false;
+      *stateptr = initializing;
+      return true;
     }
-};
-
-class pwdgrp_read {
-  path_conv pc;
-  HANDLE fh;
-  char *buf;
-  char *lptr, *eptr;
-
-public:
-  bool open (const char *posix_fname)
+  bool read ()
   {
     if (buf)
       free (buf);
     buf = lptr = eptr = NULL;

-    pc.check (posix_fname);
-    if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
-      return false;
-
     fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL, OPEN_EXISTING,
 		     FILE_ATTRIBUTE_NORMAL, 0);
     if (fh != INVALID_HANDLE_VALUE)
@@ -98,14 +125,16 @@ public:
 	    if (buf)
 	      free (buf);
 	    buf = NULL;
-	    CloseHandle (fh);
-	    fh = NULL;
-	    return false;
 	  }
-	buf[read_bytes] = '\0';
-	return true;
+	else
+	  {
+	    buf[read_bytes] = '\0';
+	    GetFileTime (fh, NULL, NULL, &last_modified);
+	  }
+	CloseHandle (fh);
       }
-    return false;
+    *stateptr = stable;
+    return (buf != NULL);
   }
   char *gets ()
   {
@@ -125,13 +154,5 @@ public:
 	*eptr++ = '\0';
       }
     return lptr;
-  }
-  inline HANDLE get_fhandle () { return fh; }
-  inline const char *get_fname () { return pc; }
-  void close ()
-  {
-    if (fh)
-      CloseHandle (fh);
-    fh = NULL;
   }
 };
Index: passwd.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/passwd.cc,v
retrieving revision 1.57
diff -u -p -r1.57 passwd.cc
--- passwd.cc	10 Jan 2003 12:32:46 -0000	1.57
+++ passwd.cc	16 Jan 2003 06:47:49 -0000
@@ -23,14 +23,53 @@ details. */
 #include <sys/termios.h>
 #include "pwdgrp.h"

+/* Per process data */
+struct etc_change NO_COPY pwdgrp_file::etc;
+static pwdgrp_state NO_COPY state;
+
+void
+etc_change::etc_watch ()
+{
+  if (!etc_changed_h)
+    {
+      path_conv pwd ("/etc");
+      etc_changed_h = FindFirstChangeNotification (pwd, FALSE,
+						   FILE_NOTIFY_CHANGE_LAST_WRITE);
+      if (etc_changed_h == INVALID_HANDLE_VALUE)
+	system_printf ("Can't open /etc for checking, %E", (char *) pwd,
+		       etc_changed_h);
+    }
+}
+bool
+etc_change::etc_changed (etc_changed_bits who)
+{
+  bool res = 0;
+
+  if (etc_changed_h != INVALID_HANDLE_VALUE)
+    {
+      if (etc_changed_flags & who)
+        {
+	  etc_changed_flags &= ~who;
+	  res = 1;
+	}
+      else if (WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0)
+        {
+	  (void) FindNextChangeNotification (etc_changed_h);
+	  etc_changed_flags |= ~who;
+	  res = 1;
+	}
+    }
+  return res;
+}
+
+
 /* Read /etc/passwd only once for better performance.  This is done
    on the first call that needs information from it. */

 static struct passwd *passwd_buf;	/* passwd contents in memory */
 static int curr_lines;
 static int max_lines;
-
-static pwdgrp_check passwd_state;
+static pwdgrp_file pwd_file ("/etc/passwd", &state, ETC_PASSWD);


 /* Position in the passwd cache */
@@ -40,7 +79,7 @@ static pwdgrp_check passwd_state;
 static int pw_pos = 0;
 #endif

-/* Remove a : teminated string from the buffer, and increment the pointer */
+/* Remove a : terminated string from the buffer, and increment the pointer */
 static char *
 grab_string (char **p)
 {
@@ -65,7 +104,7 @@ grab_int (char **p)
 {
   char *src = *p;
   unsigned int val = strtoul (src, p, 10);
-  *p = (*p == src || **p != ':') ? almost_null : *p + 1;
+  *p = (*p == src || **p != ':') ? (char *) "" : *p + 1;
   return val;
 }

@@ -127,7 +166,6 @@ pthread_mutex_t NO_COPY passwd_lock::mut
 static void
 read_etc_passwd ()
 {
-  static pwdgrp_read pr;

   /* A mutex is ok for speed here - pthreads will use critical sections not
    * mutexes for non-shared mutexes in the future. Also, this function will
@@ -136,34 +174,31 @@ read_etc_passwd ()
   passwd_lock here (cygwin_finished_initializing);

   /* if we got blocked by the mutex, then etc_passwd may have been processed */
-  if (passwd_state.isinitializing ())
+  if (pwd_file.isinitializing ())
     {
       curr_lines = 0;
-      if (pr.open ("/etc/passwd"))
+      if (pwd_file.read ())
 	{
 	  char *line;
-	  while ((line = pr.gets ()) != NULL)
+	  while ((line = pwd_file.gets ()) != NULL)
 	    add_pwd_line (line);

-	  passwd_state.set_last_modified (pr.get_fhandle (), pr.get_fname ());
-	  pr.close ();
 	  debug_printf ("Read /etc/passwd, %d lines", curr_lines);
 	}
-      passwd_state = loaded;

       static char linebuf[1024];
       char strbuf[128] = "";
       BOOL searchentry = TRUE;
-      __uid32_t default_uid = DEFAULT_UID;
       struct passwd *pw;

       if (wincap.has_security ())
 	{
+	  static char pretty_ls[] = "????????:*:-1:-1:";
+	  add_pwd_line (pretty_ls);
 	  cygsid tu = cygheap->user.sid ();
 	  tu.string (strbuf);
-	  if (myself->uid == ILLEGAL_UID
-	      && (searchentry = !internal_getpwsid (tu)))
-	    default_uid = DEFAULT_UID_NT;
+	  if (myself->uid == ILLEGAL_UID)
+	    searchentry = !internal_getpwsid (tu);
 	}
       else if (myself->uid == ILLEGAL_UID)
         searchentry = !internal_getpwuid (DEFAULT_UID);
@@ -173,11 +208,12 @@ read_etc_passwd ()
 	    myself->uid != (__uid32_t) pw->pw_uid  &&
 	    !internal_getpwuid (myself->uid))))
 	{
+	  (void) cygheap->user.ontherange (CH_HOME, NULL);
 	  snprintf (linebuf, sizeof (linebuf), "%s:*:%lu:%lu:,%s:%s:/bin/sh",
 		    cygheap->user.name (),
-		    myself->uid == ILLEGAL_UID ? default_uid : myself->uid,
+		    myself->uid == ILLEGAL_UID ? DEFAULT_UID_NT : myself->uid,
 		    myself->gid,
-		    strbuf, getenv ("HOME") ?: "/");
+		    strbuf, getenv ("HOME") ?: "");
 	  debug_printf ("Completing /etc/passwd: %s", linebuf);
 	  add_pwd_line (linebuf);
 	}
@@ -192,7 +228,7 @@ internal_getpwsid (cygsid &sid)
   char *ptr1, *ptr2, *endptr;
   char sid_string[128] = {0,','};

-  if (passwd_state.isuninitialized ())
+  if (pwd_file.isuninitialized ())
     read_etc_passwd ();

   if (sid.string (sid_string + 2))
@@ -211,8 +247,8 @@ internal_getpwsid (cygsid &sid)
 struct passwd *
 internal_getpwuid (__uid32_t uid, BOOL check)
 {
-  if (passwd_state.isuninitialized ()
-      || (check && passwd_state.isinitializing ()))
+  if (pwd_file.isuninitialized ()
+      || (check && pwd_file.isinitializing ()))
     read_etc_passwd ();

   for (int i = 0; i < curr_lines; i++)
@@ -224,8 +260,8 @@ internal_getpwuid (__uid32_t uid, BOOL c
 struct passwd *
 internal_getpwnam (const char *name, BOOL check)
 {
-  if (passwd_state.isuninitialized ()
-      || (check && passwd_state.isinitializing ()))
+  if (pwd_file.isuninitialized ()
+      || (check && pwd_file.isinitializing ()))
     read_etc_passwd ();

   for (int i = 0; i < curr_lines; i++)
@@ -347,7 +383,7 @@ getpwnam_r (const char *nam, struct pass
 extern "C" struct passwd *
 getpwent (void)
 {
-  if (passwd_state.isinitializing ())
+  if (pwd_file.isinitializing ())
     read_etc_passwd ();

   if (pw_pos < curr_lines)
@@ -390,7 +426,7 @@ getpass (const char * prompt)
 #endif
   struct termios ti, newti;

-  if (passwd_state.isinitializing ())
+  if (pwd_file.isinitializing ())
     read_etc_passwd ();

   cygheap_fdget fhstdin (0);
Index: grp.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/grp.cc,v
retrieving revision 1.61
diff -u -p -r1.61 grp.cc
--- grp.cc	10 Dec 2002 12:43:49 -0000	1.61
+++ grp.cc	16 Jan 2003 06:47:57 -0000
@@ -29,9 +29,13 @@ details. */
 /* Read /etc/group only once for better performance.  This is done
    on the first call that needs information from it. */

+/* Per process data */
+static pwdgrp_state NO_COPY state;
+
 static struct __group32 *group_buf;		/* group contents in memory */
 static int curr_lines;
 static int max_lines;
+static pwdgrp_file grp_file ("/etc/group", &state, ETC_GROUP);

 /* Position in the group cache */
 #ifdef _MT_SAFE
@@ -40,7 +44,6 @@ static int max_lines;
 static int grp_pos = 0;
 #endif

-static pwdgrp_check group_state;
 static char * NO_COPY null_ptr = NULL;

 static int
@@ -129,35 +132,29 @@ pthread_mutex_t NO_COPY group_lock::mute
 static void
 read_etc_group ()
 {
-  static pwdgrp_read gr;
-
   group_lock here (cygwin_finished_initializing);

   /* if we got blocked by the mutex, then etc_group may have been processed */
-  if (group_state.isinitializing ())
+  if (grp_file.isinitializing ())
     {
       for (int i = 0; i < curr_lines; i++)
 	if ((group_buf + i)->gr_mem != &null_ptr)
 	  free ((group_buf + i)->gr_mem);

       curr_lines = 0;
-      if (gr.open ("/etc/group"))
+      if (grp_file.read ())
 	{
 	  char *line;
-	  while ((line = gr.gets ()) != NULL)
+	  while ((line = grp_file.gets ()) != NULL)
             add_grp_line (line);

-	  group_state.set_last_modified (gr.get_fhandle (), gr.get_fname ());
-	  gr.close ();
 	  debug_printf ("Read /etc/group, %d lines", curr_lines);
 	}
-      group_state = loaded;
-
       /* Complete /etc/group in memory if needed */
       if (!internal_getgrgid (myself->gid))
         {
 	  static char linebuf [200];
-	  char group_name [UNLEN + 1] = "unknown";
+	  char group_name [UNLEN + 1] = "mkgroup";
 	  char strbuf[128] = "";

 	  if (wincap.has_security ())
@@ -173,6 +170,9 @@ read_etc_group ()
 	  debug_printf ("Completing /etc/group: %s", linebuf);
 	  add_grp_line (linebuf);
 	}
+      static char pretty_ls[] = "????????::-1:";
+      if (wincap.has_security ())
+	add_grp_line (pretty_ls);
     }
   return;
 }
@@ -182,7 +182,7 @@ internal_getgrsid (cygsid &sid)
 {
   char sid_string[128];

-  if (group_state.isuninitialized ())
+  if (grp_file.isuninitialized ())
     read_etc_group ();

   if (sid.string (sid_string))
@@ -195,27 +195,21 @@ internal_getgrsid (cygsid &sid)
 struct __group32 *
 internal_getgrgid (__gid32_t gid, BOOL check)
 {
-  struct __group32 * default_grp = NULL;
-
-  if (group_state.isuninitialized ()
-      || (check && group_state.isinitializing ()))
+  if (grp_file.isuninitialized ()
+      || (check && grp_file.isinitializing ()))
     read_etc_group ();

   for (int i = 0; i < curr_lines; i++)
-    {
-      if (group_buf[i].gr_gid == myself->gid)
-	default_grp = group_buf + i;
-      if (group_buf[i].gr_gid == gid)
-	return group_buf + i;
-    }
-  return allow_ntsec || gid != ILLEGAL_GID ? NULL : default_grp;
+    if (group_buf[i].gr_gid == gid)
+      return group_buf + i;
+  return NULL;
 }

 struct __group32 *
 internal_getgrnam (const char *name, BOOL check)
 {
-  if (group_state.isuninitialized ()
-      || (check && group_state.isinitializing ()))
+  if (grp_file.isuninitialized ()
+      || (check && grp_file.isinitializing ()))
     read_etc_group ();

   for (int i = 0; i < curr_lines; i++)
@@ -280,7 +274,7 @@ endgrent ()
 extern "C" struct __group32 *
 getgrent32 ()
 {
-  if (group_state.isinitializing ())
+  if (grp_file.isinitializing ())
     read_etc_group ();

   if (grp_pos < curr_lines)
@@ -307,7 +301,7 @@ setgrent ()
 struct __group32 *
 internal_getgrent (int pos)
 {
-  if (group_state.isuninitialized ())
+  if (grp_file.isuninitialized ())
     read_etc_group ();

   if (pos < curr_lines)
@@ -316,7 +310,7 @@ internal_getgrent (int pos)
 }

 int
-internal_getgroups (int gidsetsize, __gid32_t *grouplist)
+internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygsid * srchsid)
 {
   HANDLE hToken = NULL;
   DWORD size;
@@ -345,6 +339,13 @@ internal_getgroups (int gidsetsize, __gi
 	    {
 	      cygsid sid;

+	      if (srchsid)
+	        {
+		  for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+		    if (*srchsid == groups->Groups[pg].Sid)
+		      return 1;
+		  return 0;
+		}
 	      for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
 		if (sid.getfromgr (gr))
 		  for (DWORD pg = 0; pg < groups->GroupCount; ++pg)


More information about the Cygwin-patches mailing list