* uinfo.cc (uinfo_init): Use more robust method for determining if process was invoked from a non-cygwin process. * sync.h (muto::init): Eliminate "inheritance" parameter. (new_muto): Reflect removal of parameter. * sync.cc (muto::init): Ditto. * cygheap.cc (cygheap_init): Ditto. * debug.cc (threadname_init): Ditto. * exceptions.cc (events_init): Ditto. * malloc.cc (malloc_init): Ditto. * path.cc (cwdstuff::init): Ditto. * sigproc.cc (sigproc_init): Ditto. * grp.cc (group_lock): Use different method for locking with static member. (read_etc_group): REALLY ensure that read lock mutex is released. * passwd.cc (passwd_lock): Use different method for locking with static member. (read_etc_passwd): REALLY ensure that read lock mutex is released. * shared.cc (sec_user): Correct reversed inheritance test.
		
			
				
	
	
		
			374 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* grp.cc
 | 
						|
 | 
						|
   Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
 | 
						|
 | 
						|
   Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
 | 
						|
   First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
 | 
						|
 | 
						|
This file is part of Cygwin.
 | 
						|
 | 
						|
This software is a copyrighted work licensed under the terms of the
 | 
						|
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | 
						|
details. */
 | 
						|
 | 
						|
#include "winsup.h"
 | 
						|
#include <grp.h>
 | 
						|
#include <wininet.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <errno.h>
 | 
						|
#include "sync.h"
 | 
						|
#include "sigproc.h"
 | 
						|
#include "pinfo.h"
 | 
						|
#include "security.h"
 | 
						|
#include "fhandler.h"
 | 
						|
#include "path.h"
 | 
						|
#include "dtable.h"
 | 
						|
#include "cygerrno.h"
 | 
						|
#include "cygheap.h"
 | 
						|
#include "pwdgrp.h"
 | 
						|
 | 
						|
/* Read /etc/group only once for better performance.  This is done
 | 
						|
   on the first call that needs information from it. */
 | 
						|
 | 
						|
static const char *etc_group NO_COPY = "/etc/group";
 | 
						|
static struct __group16 *group_buf;		/* group contents in memory */
 | 
						|
static int curr_lines;
 | 
						|
static int max_lines;
 | 
						|
 | 
						|
/* Position in the group cache */
 | 
						|
#ifdef _MT_SAFE
 | 
						|
#define grp_pos _reent_winsup()->_grp_pos
 | 
						|
#else
 | 
						|
static int grp_pos = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
static pwdgrp_check group_state;
 | 
						|
 | 
						|
static int
 | 
						|
parse_grp (struct __group16 &grp, const char *line)
 | 
						|
{
 | 
						|
  int len = strlen(line);
 | 
						|
  char *newline = (char *) malloc (len + 1);
 | 
						|
  (void) memcpy (newline, line, len + 1);
 | 
						|
 | 
						|
  if (newline[--len] == '\n')
 | 
						|
    newline[len] = '\0';
 | 
						|
 | 
						|
  char *dp = strchr (newline, ':');
 | 
						|
 | 
						|
  if (!dp)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  *dp++ = '\0';
 | 
						|
  grp.gr_name = newline;
 | 
						|
 | 
						|
  grp.gr_passwd = dp;
 | 
						|
  dp = strchr (grp.gr_passwd, ':');
 | 
						|
  if (dp)
 | 
						|
    {
 | 
						|
      *dp++ = '\0';
 | 
						|
      if (!strlen (grp.gr_passwd))
 | 
						|
	grp.gr_passwd = NULL;
 | 
						|
 | 
						|
      grp.gr_gid = strtol (dp, NULL, 10);
 | 
						|
      dp = strchr (dp, ':');
 | 
						|
      if (dp)
 | 
						|
	{
 | 
						|
	  if (*++dp)
 | 
						|
	    {
 | 
						|
	      int i = 0;
 | 
						|
	      char *cp;
 | 
						|
 | 
						|
	      for (cp = dp; (cp = strchr (cp, ',')) != NULL; ++cp)
 | 
						|
		++i;
 | 
						|
	      char **namearray = (char **) calloc (i + 2, sizeof (char *));
 | 
						|
	      if (namearray)
 | 
						|
		{
 | 
						|
		  i = 0;
 | 
						|
		  for (cp = dp; (cp = strchr (dp, ',')) != NULL; dp = cp + 1)
 | 
						|
		    {
 | 
						|
		      *cp = '\0';
 | 
						|
		      namearray[i++] = dp;
 | 
						|
		    }
 | 
						|
		  namearray[i++] = dp;
 | 
						|
		  namearray[i] = NULL;
 | 
						|
		}
 | 
						|
	      grp.gr_mem = namearray;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    grp.gr_mem = (char **) calloc (1, sizeof (char *));
 | 
						|
	  return 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Read one line from /etc/group into the group cache */
 | 
						|
static void
 | 
						|
add_grp_line (const char *line)
 | 
						|
{
 | 
						|
    if (curr_lines == max_lines)
 | 
						|
    {
 | 
						|
	max_lines += 10;
 | 
						|
	group_buf = (struct __group16 *) realloc (group_buf, max_lines * sizeof (struct __group16));
 | 
						|
    }
 | 
						|
    if (parse_grp (group_buf[curr_lines], line))
 | 
						|
      curr_lines++;
 | 
						|
}
 | 
						|
 | 
						|
class group_lock
 | 
						|
{
 | 
						|
  bool armed;
 | 
						|
  static NO_COPY pthread_mutex_t mutex;
 | 
						|
 public:
 | 
						|
  group_lock (bool doit)
 | 
						|
  {
 | 
						|
    if (armed = doit)
 | 
						|
      pthread_mutex_lock (&mutex);
 | 
						|
  }
 | 
						|
  ~group_lock ()
 | 
						|
  {
 | 
						|
    if (armed)
 | 
						|
      pthread_mutex_unlock (&mutex);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
pthread_mutex_t NO_COPY group_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
/* Read in /etc/group and save contents in the group cache */
 | 
						|
/* This sets group_in_memory_p to 1 so functions in this file can
 | 
						|
   tell that /etc/group has been read in */
 | 
						|
/* FIXME: should be static but this is called in uinfo_init outside this
 | 
						|
   file */
 | 
						|
void
 | 
						|
read_etc_group ()
 | 
						|
{
 | 
						|
  char linebuf [200];
 | 
						|
  char group_name [UNLEN + 1];
 | 
						|
  DWORD group_name_len = UNLEN + 1;
 | 
						|
 | 
						|
  strncpy (group_name, "Administrators", sizeof (group_name));
 | 
						|
 | 
						|
  group_lock here (cygwin_finished_initializing);
 | 
						|
 | 
						|
  /* if we got blocked by the mutex, then etc_group may have been processed */
 | 
						|
  if (group_state != uninitialized)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (group_state != initializing)
 | 
						|
    {
 | 
						|
      group_state = initializing;
 | 
						|
      if (max_lines) /* When rereading, free allocated memory first. */
 | 
						|
	{
 | 
						|
	  for (int i = 0; i < curr_lines; ++i)
 | 
						|
	    {
 | 
						|
	      free (group_buf[i].gr_name);
 | 
						|
	      free (group_buf[i].gr_mem);
 | 
						|
	    }
 | 
						|
	  curr_lines = 0;
 | 
						|
	}
 | 
						|
 | 
						|
      FILE *f = fopen (etc_group, "rt");
 | 
						|
 | 
						|
      if (f)
 | 
						|
	{
 | 
						|
	  while (fgets (linebuf, sizeof (linebuf), f) != NULL)
 | 
						|
	    {
 | 
						|
	      if (strlen (linebuf))
 | 
						|
		add_grp_line (linebuf);
 | 
						|
	    }
 | 
						|
 | 
						|
	  group_state.set_last_modified (f);
 | 
						|
	  fclose (f);
 | 
						|
	  group_state = loaded;
 | 
						|
	}
 | 
						|
      else /* /etc/group doesn't exist -- create default one in memory */
 | 
						|
	{
 | 
						|
	  char domain_name [INTERNET_MAX_HOST_NAME_LENGTH + 1];
 | 
						|
	  DWORD domain_name_len = INTERNET_MAX_HOST_NAME_LENGTH + 1;
 | 
						|
	  SID_NAME_USE acType;
 | 
						|
	  debug_printf ("Emulating /etc/group");
 | 
						|
	  if (! LookupAccountSidA (NULL ,
 | 
						|
				    well_known_admins_sid,
 | 
						|
				    group_name,
 | 
						|
				    &group_name_len,
 | 
						|
				    domain_name,
 | 
						|
				    &domain_name_len,
 | 
						|
				    &acType))
 | 
						|
	    {
 | 
						|
	      strcpy (group_name, "unknown");
 | 
						|
	      debug_printf ("Failed to get local admins group name. %E");
 | 
						|
	    }
 | 
						|
 | 
						|
	  snprintf (linebuf, sizeof (linebuf), "%s::%u:\n", group_name, (unsigned) DEFAULT_GID);
 | 
						|
	  add_grp_line (linebuf);
 | 
						|
	  group_state = emulated;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
struct __group16 *
 | 
						|
getgrgid (__gid16_t gid)
 | 
						|
{
 | 
						|
  struct __group16 * default_grp = NULL;
 | 
						|
  if (group_state  <= initializing)
 | 
						|
    read_etc_group();
 | 
						|
 | 
						|
  for (int i = 0; i < curr_lines; i++)
 | 
						|
    {
 | 
						|
      if (group_buf[i].gr_gid == DEFAULT_GID)
 | 
						|
	default_grp = group_buf + i;
 | 
						|
      if (group_buf[i].gr_gid == gid)
 | 
						|
	return group_buf + i;
 | 
						|
    }
 | 
						|
 | 
						|
  return allow_ntsec ? NULL : default_grp;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
struct __group16 *
 | 
						|
getgrnam (const char *name)
 | 
						|
{
 | 
						|
  if (group_state  <= initializing)
 | 
						|
    read_etc_group();
 | 
						|
 | 
						|
  for (int i = 0; i < curr_lines; i++)
 | 
						|
    if (strcasematch (group_buf[i].gr_name, name))
 | 
						|
      return group_buf + i;
 | 
						|
 | 
						|
  /* Didn't find requested group */
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
void
 | 
						|
endgrent()
 | 
						|
{
 | 
						|
  grp_pos = 0;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
struct __group16 *
 | 
						|
getgrent()
 | 
						|
{
 | 
						|
  if (group_state  <= initializing)
 | 
						|
    read_etc_group();
 | 
						|
 | 
						|
  if (grp_pos < curr_lines)
 | 
						|
    return group_buf + grp_pos++;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
void
 | 
						|
setgrent ()
 | 
						|
{
 | 
						|
  grp_pos = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Internal function. ONLY USE THIS INTERNALLY, NEVER `getgrent'!!! */
 | 
						|
struct __group16 *
 | 
						|
internal_getgrent (int pos)
 | 
						|
{
 | 
						|
  if (group_state  <= initializing)
 | 
						|
    read_etc_group();
 | 
						|
 | 
						|
  if (pos < curr_lines)
 | 
						|
    return group_buf + pos;
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
getgroups (int gidsetsize, __gid16_t *grouplist, __gid16_t gid, const char *username)
 | 
						|
{
 | 
						|
  HANDLE hToken = NULL;
 | 
						|
  DWORD size;
 | 
						|
  int cnt = 0;
 | 
						|
  struct __group16 *gr;
 | 
						|
 | 
						|
  if (group_state  <= initializing)
 | 
						|
    read_etc_group();
 | 
						|
 | 
						|
  if (allow_ntsec &&
 | 
						|
      OpenProcessToken (hMainProc, TOKEN_QUERY, &hToken))
 | 
						|
    {
 | 
						|
      if (GetTokenInformation (hToken, TokenGroups, NULL, 0, &size)
 | 
						|
	  || GetLastError () == ERROR_INSUFFICIENT_BUFFER)
 | 
						|
	{
 | 
						|
	  char buf[size];
 | 
						|
	  TOKEN_GROUPS *groups = (TOKEN_GROUPS *) buf;
 | 
						|
 | 
						|
	  if (GetTokenInformation (hToken, TokenGroups, buf, size, &size))
 | 
						|
	    {
 | 
						|
	      cygsid sid;
 | 
						|
 | 
						|
	      for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
 | 
						|
		if (sid.getfromgr (gr))
 | 
						|
		  for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
 | 
						|
		    if (sid == groups->Groups[pg].Sid)
 | 
						|
		      {
 | 
						|
			if (cnt < gidsetsize)
 | 
						|
			  grouplist[cnt] = gr->gr_gid;
 | 
						|
			++cnt;
 | 
						|
			if (gidsetsize && cnt > gidsetsize)
 | 
						|
			  {
 | 
						|
			    CloseHandle (hToken);
 | 
						|
			    goto error;
 | 
						|
			  }
 | 
						|
			break;
 | 
						|
		      }
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	debug_printf ("%d = GetTokenInformation(NULL) %E", size);
 | 
						|
      CloseHandle (hToken);
 | 
						|
      if (cnt)
 | 
						|
	return cnt;
 | 
						|
    }
 | 
						|
 | 
						|
  for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
 | 
						|
    if (gid == gr->gr_gid)
 | 
						|
      {
 | 
						|
	if (cnt < gidsetsize)
 | 
						|
	  grouplist[cnt] = gr->gr_gid;
 | 
						|
	++cnt;
 | 
						|
	if (gidsetsize && cnt > gidsetsize)
 | 
						|
	  goto error;
 | 
						|
      }
 | 
						|
    else if (gr->gr_mem)
 | 
						|
      for (int gi = 0; gr->gr_mem[gi]; ++gi)
 | 
						|
	if (strcasematch (username, gr->gr_mem[gi]))
 | 
						|
	  {
 | 
						|
	    if (cnt < gidsetsize)
 | 
						|
	      grouplist[cnt] = gr->gr_gid;
 | 
						|
	    ++cnt;
 | 
						|
	    if (gidsetsize && cnt > gidsetsize)
 | 
						|
	      goto error;
 | 
						|
	  }
 | 
						|
  return cnt;
 | 
						|
 | 
						|
error:
 | 
						|
  set_errno (EINVAL);
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
int
 | 
						|
getgroups (int gidsetsize, __gid16_t *grouplist)
 | 
						|
{
 | 
						|
  return getgroups (gidsetsize, grouplist, myself->gid, cygheap->user.name ());
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
int
 | 
						|
initgroups (const char *, __gid16_t)
 | 
						|
{
 | 
						|
  return 0;
 | 
						|
}
 |