This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

mkpasswd and mkgroup patch, ntsec documentation, 3rd try


Hi Chris,

Chris Faylor wrote:
> 
> On Mon, May 31, 1999 at 07:56:03PM +0200, Corinna Vinschen wrote:
> >Chris Faylor wrote:
> >> Also, I was thinking that CYGWIN=ntsec should be *on* by default.  That
> >> way it will be tested by more people.  Can you add a check in environ.cc
> >> to turn this on if it's running under NT (assuming you agree)?
> >
> >Done.

It's essential now, to document this in the installation instructions:

   NT users have to create /etc/passwd and /etc/group or they have to
   set CYGWIN=nontsec if they don't want to use NT security.

Michael Hirmke has corrected my ntsec documentation (oh god, my English
is SO bad!) and it's definitely more readable now.
NT security is so complex, that I think, the document should be part of 
winsup. Do you agree?

I have attached patches to mkpasswd.c and mkgroup.c for better working
with ntsec.

mkpasswd and mkgroup both list the correct native name of the
`Everyone' group (SID 0) and mkgroup additionally lists the native
name of the `None' group (SID 513) now.

On a workstation the commands `mkpasswd -l -g' and `mkgroup -l'
result in real complete passwd and group files now. I don't know,
how it looks like in domains. Unfortunately there is no solution for
correct primary group assignment outside of domains as I mention in
the ntsec doc.

Regards,
Corinna

ChangeLog:
==========

Thu Jun 1 14:17:00 1999  Corinna Vinschen  <corinna@vinschen.de>

	* utils/mkpasswd.c: Changed to output native names of
	well known group `Everyone' (SID 0).
	* utils/mkgroup.c: Ditto plus output of native name of
	well known group `None' (SID 513).
Index: mkpasswd.c
===================================================================
RCS file: /src/cvsroot/winsup-990526/utils/mkpasswd.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 mkpasswd.c
--- mkpasswd.c	1999/05/28 19:28:24	1.1.1.1
+++ mkpasswd.c	1999/06/01 12:20:26
@@ -22,6 +22,9 @@
 
 #include <stdio.h>
 
+SID_IDENTIFIER_AUTHORITY sid_world_auth = {SECURITY_WORLD_SID_AUTHORITY};
+SID_IDENTIFIER_AUTHORITY sid_nt_auth = {SECURITY_NT_AUTHORITY};
+
 #ifndef min
 #define min(a,b) (((a)<(b))?(a):(b))
 #endif
@@ -167,9 +170,9 @@ enum_local_groups ()
 	      return 0;
 	    }
 
-	  gid = *GetSidSubAuthority (psid, 1);
+	  gid = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1);
 
-	  printf ("%s::%ld:0:::\n", localgroup_name, gid);
+	  printf ("%s:*:%ld:%ld:::\n", localgroup_name, gid, gid);
 	}
 
       NetApiBufferFree (buffer);
@@ -208,6 +211,11 @@ main (int argc, char **argv)
   int domain_name_specified = 0;
   int i;
 
+  char name[256], dom[256];
+  DWORD len, len2;
+  PSID sid;
+  SID_NAME_USE use;
+
   if (argc == 1)
     usage ();
 
@@ -243,6 +251,23 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  /*
+   * Get `Everyone' group
+  */
+  if (AllocateAndInitializeSid (&sid_world_auth, 1, SECURITY_WORLD_RID,
+                                0, 0, 0, 0, 0, 0, 0, &sid))
+    {
+      if (LookupAccountSid (NULL, sid,
+                            name, (len = 256, &len),
+                            dom, (len2 = 256, &len),
+                            &use))
+        printf ("%s:*:%d:%d:::\n", name, SECURITY_WORLD_RID, SECURITY_WORLD_RID);
+      FreeSid (sid);
+    }
+
+  if (print_local_groups)
+    enum_local_groups ();
+
   if (print_domain)
     {
       if (domain_name_specified)
@@ -262,9 +287,6 @@ main (int argc, char **argv)
 
   if (print_local)
     enum_users (NULL);
-
-  if (print_local_groups)
-    enum_local_groups ();
 
   return 0;
 }
Index: mkgroup.c
===================================================================
RCS file: /src/cvsroot/winsup-990526/utils/mkgroup.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 mkgroup.c
--- mkgroup.c	1999/05/28 19:28:24	1.1.1.1
+++ mkgroup.c	1999/06/01 12:19:28
@@ -16,6 +16,8 @@
 #include <lmaccess.h>
 #include <lmapibuf.h>
 
+SID_IDENTIFIER_AUTHORITY sid_world_auth = {SECURITY_WORLD_SID_AUTHORITY};
+
 #ifndef min
 #define min(a,b) (((a)<(b))?(a):(b))
 #endif
@@ -53,6 +55,70 @@ uni2ansi (LPWSTR wcs, char *mbs)
     *mbs = '\0';
 }
 
+int 
+enum_local_groups ()
+{
+  LOCALGROUP_INFO_0 *buffer;
+  DWORD entriesread = 0;
+  DWORD totalentries = 0;
+  DWORD resume_handle = 0;
+
+  do
+    {
+      DWORD i;
+      DWORD rc = NetLocalGroupEnum (NULL, 0, (LPBYTE *) & buffer, 1024,
+			       &entriesread, &totalentries, &resume_handle);
+
+      switch (rc)
+	{
+	case ERROR_ACCESS_DENIED:
+	  fprintf (stderr, "Access denied\n");
+	  exit (1);
+
+	case ERROR_MORE_DATA:
+	case ERROR_SUCCESS:
+	  break;
+
+	default:
+	  fprintf (stderr, "NetUserEnum() failed with %ld\n", rc);
+	  exit (1);
+	}
+
+      for (i = 0; i < entriesread; i++)
+	{
+	  char localgroup_name[100];
+	  char domain_name[100];
+	  DWORD domname_len = 100;
+	  char psid_buffer[1024];
+	  PSID psid = (PSID) psid_buffer;
+	  DWORD sid_length = 1024;
+	  DWORD gid;
+	  SID_NAME_USE acc_type;
+	  uni2ansi (buffer[i].lgrpi0_name, localgroup_name);
+
+	  if (!LookupAccountName (NULL, localgroup_name, psid,
+				  &sid_length, domain_name, &domname_len,
+				  &acc_type))
+	    {
+	      int code = GetLastError ();
+	      fprintf (stderr, "LookupAccountName(%s) failed with %d\n",
+		       localgroup_name, code);
+	      return 0;
+	    }
+
+	  gid = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1);
+
+	  printf ("%s::%ld:\n", localgroup_name, gid);
+	}
+
+      NetApiBufferFree (buffer);
+
+    }
+  while (entriesread < totalentries);
+
+  return 0;
+}
+
 void 
 enum_groups (LPWSTR servername)
 {
@@ -126,6 +192,11 @@ main (int argc, char **argv)
   int domain_specified = 0;
   int i;
 
+  char name[256], dom[256];
+  DWORD len, len2;
+  PSID sid, csid;
+  SID_NAME_USE use;
+
   if (argc == 1)
     usage ();
 
@@ -150,6 +221,51 @@ main (int argc, char **argv)
 	    }
 	}
     }
+
+  /*
+   * Get `Everyone' group
+  */
+  if (AllocateAndInitializeSid (&sid_world_auth, 1, SECURITY_WORLD_RID,
+                                0, 0, 0, 0, 0, 0, 0, &sid))
+    {
+      if (LookupAccountSid (NULL, sid,
+                            name, (len = 256, &len),
+                            dom, (len2 = 256, &len),
+                            &use))
+        printf ("%s::%d:\n", name, SECURITY_WORLD_RID);
+      FreeSid (sid);
+    }
+
+  /*
+   * Get `None' group
+  */
+  GetComputerName (name, (len = 256, &len));
+  csid = (PSID) malloc (1024);
+  LookupAccountName (NULL, name,
+                     csid, (len = 1024, &len),
+                     dom, (len2 = 256, &len),
+                     &use);
+  if (AllocateAndInitializeSid (GetSidIdentifierAuthority (csid),
+                                *GetSidSubAuthorityCount (csid),
+                                *GetSidSubAuthority (csid, 0),
+                                *GetSidSubAuthority (csid, 1),
+                                *GetSidSubAuthority (csid, 2),
+                                *GetSidSubAuthority (csid, 3),
+                                513,
+                                0,
+                                0,
+                                0,
+                                &sid))
+    {
+      if (LookupAccountSid (NULL, sid,
+                            name, (len = 256, &len),
+                            dom, (len2 = 256, &len),
+                            &use))
+        printf ("%s::513:\n", name);
+      FreeSid (sid);
+    }
+  free (csid);
+
   if (print_domain)
     {
       if (domain_specified)
@@ -168,9 +284,7 @@ main (int argc, char **argv)
     }
 
   if (print_local)
-    enum_groups (NULL);
-
-  printf ("Everyone::0:\n");
+    enum_local_groups ();
 
   return 0;
 }
NTSEC Documentation
===================

The design goal of the ntsec patch was to get a more UNIX like
permission structure based upon the security features of Windows NT.
To describe the changes, I will give a short overview of NT security
in chapter one.
Chapter two discusses the changes in ntsec related to privileges on
processes.
Chapter three shows the UNIX like setting of file permissions.

The setting of UNIX like object permissions is controlled by the new
CYGWIN variable setting `[no]ntsec'.

On NT ntsec is now turned on by default.


1. NT security
--------------

The NT security allows a process to allow or deny access of
different kind to `objects'. `Objects' are files, processes,
threads, semaphores, etc.

The central data structure of NT security is the `security descriptor' (SD)
structure. It explains the permissions, that are granted (or denied) to an
object and contains information, that is related to so called
`security identifiers' (SID).

An SID is a unique identifier for users, groups and domains. In the ntsec
patch only user and group SIDs are relevant. SIDs are comparable to
UNIX UIDs and GIDs, but are more complicated.

There is a big difference between UNIX IDs and NT SIDs, the existence of
the so called `well known groups'. For example UNIX has no GID for the
group of `all users'. NT has an SID for them, called `Everyone' in the
english versions.

Now, how are permissions given to objects? A process may assign an SD
to the object. The SD of an object consists of three parts:

  - the SID of the owner
  - the SID of the group
  - a list of SIDs with their permissions, called `access control list' (ACL)

UNIX is able to create three different permissions, the permissions
for the owner, for the group and for the world. In contrast the ACL
has a potentially infinite number of members. Every member is a so called
`access control element' (ACE). An ACE contains three parts:

  - the type of the ACE
  - permissions, described with a DWORD
  - the SID, for which the above mentioned permissions are set

The two important types of ACEs are the `access allowed ACE' and the
`access denied ACE'. The ntsec patch only uses `access allowed ACEs'.

The possible permissions on objects are more complicated than in
UNIX. For example, the permission to delete an object is different
from the write permission.

With the forementioned method NT is able to grant or revoke permissions
to objects in a far more specific way. But what about cygwin? In a POSIX
environment it would be fine to have the security behavior of a POSIX
system. The NT security model is able to reproduce the POSIX model.
The ntsec patch tries to do this in cygwin.

The creation of explicit object security is a bit complicated, so typically
only two simple variations are used:

  - default permissions, computed by the operating system
  - each permission to everyone

For parameters to functions that create or open securable objects another
data structure is used, the `security attributes' (SA). This structure
contains an SD and a flag, that specifies whether the returned handle
to the created or opened object is inherited to child processes or not.
This property is not important for the ntsec patch description, so in
this document SDs and SAs are more or less identical.


2. Process privileges
---------------------

Any process started under control of cygwin has a semaphore attached
to it, that is used for signaling purposes. The creation of this semaphore
can be found in sigproc.cc, function `getsem'. The first parameter to the
function call `CreateSemaphore' is an SA. Without ntsec patch this SA 
assigns default security to the semaphore. There is a simple disadvantage:
Only the owner of the process may send signals to it. Or, in other words,
if the owner of the process is not a member of the administrators' group,
no administrator may kill the process! This is especially annoying, if
processes are started via service manager.

The ntsec patch now assigns an SA to the process control semaphore, that
has each permission set for the user of the process and each permission
set for the administrators' group. The creation of this SA is done by
the function `sec_user', that can be found in `shared.cc'. Each member
of the administrators' group is now allowed to send signals to any
process created in cygwin, regardless of the process owner.

Moreover, each process now has the appropriate security settings, when
it is started via `CreateProcess'. You will find this in function
`spawn_guts' in module `spawn.cc'. The security settings for starting a
process in another user context aren't correct yet, the call to
`CreateProcessAsUser' is not changed. The simple settings of `sec_user'
are not sufficient in this case.


3. File permissions
-------------------

If ntsec is turned on, file permissions are set as in UNIX. An SD is
assigned to the file containing the owner and group and ACEs for the
owner, the group and `Everyone'. If the group of the file is not the
administrators' group, the administrators' group gets each permission.
This has the effect, that the administrators' group has permissions on
files, which are equivalent to root permissions on UNIX systems.

The complete settings of UNIX like permissions can be found in the file
`security.cc'. The two functions `get_nt_attribute' and `set_nt_attribute'
are the main code. The reading and writing of the SDs is done by the
functions `ReadSD' and `WriteSD'. They are using the Backup API functions
`BackupRead' and `BackupWrite', that have the advantage not to crash,
if they are used on non NTFS file systems! These crashes are the default
behavior of the security API, if it's used on, e.g., FAT or SAMBA
file systems :-(

Unfortunately, the settings of NT file security are only available on NTFS.
SAMBA doesn't support them.

If you are creating a file `foo' outside of cygwin, you will see something
like the following on `ls -ln':

If your login is member of the administrators' group:
  rwxrwxrwx 1  544  513  ... foo
if not:
  rwxrwxrwx 1  1000  513  ... foo

Note the user and group IDs. 544 is the UID of the administrators' group.
This is a `feature' :-P of WinNT. If one is a member of the administrators'
group, every file, that he has created is owned by the administrators' group,
instead by him.

The second example shows the UID of the first user, that has been created with
NT's the user adminstration tool. The users and groups are sequentially
numbered, starting with 1000. Users and groups are using the same numbering
scheme, so a user and a group don't share the same ID.

In both examples the GID 513 is of special interest. This GID is a
well known group with the meaning `nobody', named 'None' in the
english, `Kein' in the german, `Aucun' in the french version of NT, etc.
This means, that no group ownership is assigned to the file.
If you give permissions to this group, you will be surprised: Any permission,
that is assigned to this group, has the inverse effect on each other user
and group!!! So: If 'None' is allowed to write a file, in reality nobody is
allowed to write this file. This is very confusing. In function
`set_nt_attribute' a simple check is done to avoid giving any permission
to `None'.

To work correctly the ntsec patch depends on reasoned files /etc/passwd
and /etc/group. The names and the IDs must correspond to the appropriate
NT IDs! The IDs used in cygwin are the last component of the
NT SID. An SID of e.g. the user `corinna' on my NT workstation:

  S-1-5-21-165875785-1005667432-441284377-1000

You see, the SIDs are a little bit complicated. Note the last part:
It's the number 1000, the cygwin's UID.

Unfortunately, workstations and servers outside of domains are not
able to set primary groups! In these cases, where there is no correlation
of users to primary groups, NT returns 513 (None) as primary group,
regardless of the membership to regular groups of these users.

when using `mkpasswd  -l -g' on such systems, you have to change the
primary group by hand if `None' as primary group is not what you want
(and I'm sure, it's not what you want!)

To get help in creating correct passwd and group files, look at
the following examples, that are part of my files. With the exception
of my personal user entry, all entries are well known entries. For a
better understanding, the names are translated to the equivalents of the
English NT version:

/etc/passwd
===========
everyone:*:0:0:::
system:*:18:18:::
administrator::500:544::/home/root:/bin/bash
guest:*:501:546:::
administrators:*:544:544::/home/root:
corinna::1000:547:Corinna Vinschen:/home/corinna:/bin/tcsh

/etc/group
==========
everyone::0:
system::18:
none::513:
administrators::544:
users::545:
guests::546:
powerusers::547:

Groups may be mentioned in the passwd file, too. This has two
advantages:
  - Because NT assignes them to files as owners, a `ls -l' is
    often better readable.
  - Moreover it's possible to assigned them to files as owners with
    cygwin's `chown'.

The group `system' is the owner of processes, that are started through
service manager. The same is true for files, that are created by
processes, which are started through service manager.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]