Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com Message-ID: <3753D1F3.4710C353@vinschen.de> Date: Tue, 01 Jun 1999 14:28:35 +0200 From: Corinna Vinschen X-Mailer: Mozilla 4.51 [en] (WinNT; I) X-Accept-Language: de,en MIME-Version: 1.0 To: Chris Faylor , cygwin-developers AT sourceware DOT cygnus DOT com Subject: mkpasswd and mkgroup patch, ntsec documentation, 3rd try References: <19990529184049 DOT C993 AT cygnus DOT com> <375078A4 DOT 5A093F2C AT vinschen DOT de> <19990529193554 DOT A1338 AT cygnus DOT com> <3751397F DOT 19EFD759 AT vinschen DOT de> <19990530124814 DOT A718 AT cygnus DOT com> <37519478 DOT 6BF756F6 AT vinschen DOT de> <19990530210719 DOT A946 AT cygnus DOT com> <375261EA DOT DD9290F1 AT vinschen DOT de> <19990531115344 DOT A1606 AT cygnus DOT com> <3752CD33 DOT C49540D9 AT vinschen DOT de> <19990531200731 DOT A3966 AT cygnus DOT com> Content-Type: multipart/mixed; boundary="------------6AECEE060B6DE79AB1831DAB" This is a multi-part message in MIME format. --------------6AECEE060B6DE79AB1831DAB Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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 * 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). --------------6AECEE060B6DE79AB1831DAB Content-Type: text/plain; charset=us-ascii; name="ntsec-util-patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ntsec-util-patch" 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 +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 #include +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; } --------------6AECEE060B6DE79AB1831DAB Content-Type: text/plain; charset=us-ascii; name="ntsec.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ntsec.txt" 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. --------------6AECEE060B6DE79AB1831DAB--