--- security.h.orig 2002-11-12 22:07:16.000000000 -0500 +++ security.h 2002-11-15 19:15:34.000000000 -0500 @@ -11,7 +11,8 @@ details. */ #include #define DEFAULT_UID DOMAIN_USER_RID_ADMIN -#define DEFAULT_GID DOMAIN_ALIAS_RID_ADMINS +#define DEFAULT_UID_NT 400 /* Non conflicting number */ +#define DEFAULT_GID 401 #define MAX_SID_LEN 40 #define MAX_DACL_LEN(n) (sizeof (ACL) \ @@ -208,6 +209,8 @@ extern BOOL allow_smbntsec; I didn't find a better place to declare them. */ extern struct passwd *internal_getpwent (int); extern struct __group32 *internal_getgrent (int); +extern struct passwd *getpwsid (cygsid &); +extern struct __group32 *getgrsid (cygsid &); /* File manipulation */ int __stdcall set_process_privileges (); --- passwd.cc.orig 2002-10-24 01:08:58.000000000 -0400 +++ passwd.cc 2002-11-16 13:30:12.000000000 -0500 @@ -27,7 +27,7 @@ details. */ on the first call that needs information from it. */ static struct passwd *passwd_buf; /* passwd contents in memory */ -static int curr_lines; +static int curr_lines = -1; static int max_lines; static pwdgrp_check passwd_state; @@ -74,7 +74,7 @@ grab_int (char **p) } /* Parse /etc/passwd line into passwd structure. */ -void +static int parse_pwd (struct passwd &res, char *buf) { /* Allocate enough room for the passwd struct and all the strings @@ -82,6 +82,8 @@ parse_pwd (struct passwd &res, char *buf size_t len = strlen (buf); if (buf[--len] == '\r') buf[len] = '\0'; + if (len < 6) + return 0; res.pw_name = grab_string (&buf); res.pw_passwd = grab_string (&buf); @@ -91,6 +93,7 @@ parse_pwd (struct passwd &res, char *buf res.pw_gecos = grab_string (&buf); res.pw_dir = grab_string (&buf); res.pw_shell = grab_string (&buf); + return 1; } /* Add one line from /etc/passwd into the password cache */ @@ -102,7 +105,8 @@ add_pwd_line (char *line) max_lines += 10; passwd_buf = (struct passwd *) realloc (passwd_buf, max_lines * sizeof (struct passwd)); } - parse_pwd (passwd_buf[curr_lines++], line); + if (parse_pwd (passwd_buf[curr_lines], line)) + curr_lines++; } class passwd_lock @@ -125,10 +129,32 @@ class passwd_lock pthread_mutex_t NO_COPY passwd_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; +/* Cygwin internal */ +/* If this ever becomes non-reentrant, update all the getpw*_r functions */ +static struct passwd * +search_for (__uid32_t uid, const char *name) +{ + struct passwd *res = 0; + + for (int i = 0; i < curr_lines; i++) + { + res = passwd_buf + i; + /* on Windows NT user names are case-insensitive */ + if (name) + { + if (strcasematch (name, res->pw_name)) + return res; + } + else if (uid == (__uid32_t) res->pw_uid) + return res; + } + return NULL; +} + /* Read in /etc/passwd and save contents in the password cache. This sets passwd_state to loaded or emulated so functions in this file can tell that /etc/passwd has been read in or will be emulated. */ -void +static void read_etc_passwd () { static pwdgrp_read pr; @@ -146,97 +172,71 @@ read_etc_passwd () if (passwd_state != initializing) { passwd_state = initializing; + curr_lines = 0; if (pr.open ("/etc/passwd")) { char *line; while ((line = pr.gets ()) != NULL) - if (strlen (line)) - add_pwd_line (line); + add_pwd_line (line); passwd_state.set_last_modified (pr.get_fhandle (), pr.get_fname ()); - passwd_state = loaded; pr.close (); debug_printf ("Read /etc/passwd, %d lines", curr_lines); } - else - { - static char linebuf[1024]; - if (wincap.has_security ()) - { - HANDLE ptok; - cygsid tu, tg; - DWORD siz; - - if (OpenProcessToken (hMainProc, TOKEN_QUERY, &ptok)) - { - if (GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, - &siz) - && GetTokenInformation (ptok, TokenPrimaryGroup, &tg, - sizeof tg, &siz)) - { - char strbuf[100]; - snprintf (linebuf, sizeof (linebuf), - "%s::%lu:%lu:%s:%s:/bin/sh", - cygheap->user.name (), - *GetSidSubAuthority (tu, - *GetSidSubAuthorityCount(tu) - 1), - *GetSidSubAuthority (tg, - *GetSidSubAuthorityCount(tg) - 1), - tu.string (strbuf), getenv ("HOME") ?: "/"); - debug_printf ("Emulating /etc/passwd: %s", linebuf); - add_pwd_line (linebuf); - passwd_state = emulated; - } - CloseHandle (ptok); - } - } - if (passwd_state != emulated) - { - snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", - cygheap->user.name (), (unsigned) DEFAULT_UID, - (unsigned) DEFAULT_GID, getenv ("HOME") ?: "/"); - debug_printf ("Emulating /etc/passwd: %s", linebuf); - add_pwd_line (linebuf); - passwd_state = emulated; - } + static char linebuf[1024]; + char strbuf[128] = ""; + BOOL searchentry = TRUE; + __uid32_t default_uid = DEFAULT_UID; + struct passwd *pw; + + if (wincap.has_security ()) + { + cygsid tu = cygheap->user.sid (); + tu.string (strbuf); + if (myself->uid == ILLEGAL_UID && + (searchentry = !getpwsid (tu))) + default_uid = DEFAULT_UID_NT; } - + if (searchentry && + (!(pw = search_for (0, cygheap->user.name ())) || + (myself->uid != ILLEGAL_UID && + myself->uid != (__uid32_t) pw->pw_uid && + !search_for (myself->uid, NULL)))) + { + snprintf (linebuf, sizeof (linebuf), "%s:*:%u:%u:,%s:%s:/bin/sh", + cygheap->user.name (), + myself->uid == ILLEGAL_UID?default_uid:myself->uid, + myself->gid, + strbuf, getenv ("HOME") ?: "/"); + debug_printf ("Completing /etc/passwd: %s", linebuf); + add_pwd_line (linebuf); + } + passwd_state = loaded; } - return; } -/* Cygwin internal */ -/* If this ever becomes non-reentrant, update all the getpw*_r functions */ -static struct passwd * -search_for (__uid32_t uid, const char *name) +struct passwd * +getpwsid (cygsid &sid) { - struct passwd *res = 0; - struct passwd *default_pw = 0; + struct passwd *pw; + char *ptr1, *ptr2, *endptr; + char sid_string[128] = {0,','}; - for (int i = 0; i < curr_lines; i++) + if (curr_lines < 0 && passwd_state <= initializing) + read_etc_passwd (); + + if (sid.string (sid_string + 2)) { - res = passwd_buf + i; - if (res->pw_uid == DEFAULT_UID) - default_pw = res; - /* on Windows NT user names are case-insensitive */ - if (name) - { - if (strcasematch (name, res->pw_name)) - return res; - } - else if (uid == (__uid32_t) res->pw_uid) - return res; + endptr = strchr (sid_string + 2, 0) - 1; + for (int i = 0; i < curr_lines; i++) + if ((pw = passwd_buf + i)->pw_dir > pw->pw_gecos + 8) + for (ptr1 = endptr, ptr2 = pw->pw_dir - 2; + *ptr1 == *ptr2; ptr2--) + if (!*--ptr1) + return pw; } - - /* Return default passwd entry if passwd is emulated or it's a - request for the current user. */ - if (passwd_state != loaded - || (!name && uid == myself->uid) - || (name && strcasematch (name, cygheap->user.name ()))) - return default_pw; - return NULL; } @@ -399,6 +399,7 @@ setpassent () return 0; } +#if 0 /* Unused */ /* Internal function. ONLY USE THIS INTERNALLY, NEVER `getpwent'!!! */ struct passwd * internal_getpwent (int pos) @@ -410,6 +411,7 @@ internal_getpwent (int pos) return passwd_buf + pos; return NULL; } +#endif extern "C" char * getpass (const char * prompt) --- grp.cc.orig 2002-11-17 19:57:58.000000000 -0500 +++ grp.cc 2002-11-16 13:28:58.000000000 -0500 @@ -30,7 +30,7 @@ details. */ on the first call that needs information from it. */ static struct __group32 *group_buf; /* group contents in memory */ -static int curr_lines; +static int curr_lines = -1; static int max_lines; /* Position in the group cache */ @@ -41,6 +41,7 @@ static int grp_pos = 0; #endif static pwdgrp_check group_state; +static char * NO_COPY null_ptr = NULL; static int parse_grp (struct __group32 &grp, char *line) @@ -62,13 +63,11 @@ parse_grp (struct __group32 &grp, char * 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) { + grp.gr_mem = &null_ptr; if (*++dp) { int i = 0; @@ -87,11 +86,9 @@ parse_grp (struct __group32 &grp, char * } namearray[i++] = dp; namearray[i] = NULL; + grp.gr_mem = namearray; } - grp.gr_mem = namearray; } - else - grp.gr_mem = (char **) calloc (1, sizeof (char *)); return 1; } } @@ -134,9 +131,7 @@ pthread_mutex_t NO_COPY group_lock::mute /* 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 +static void read_etc_group () { static pwdgrp_read gr; @@ -150,76 +145,74 @@ read_etc_group () if (group_state != initializing) { group_state = initializing; + 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")) { char *line; while ((line = gr.gets ()) != NULL) - if (strlen (line)) - add_grp_line (line); + add_grp_line (line); group_state.set_last_modified (gr.get_fhandle (), gr.get_fname ()); - group_state = loaded; gr.close (); debug_printf ("Read /etc/group, %d lines", curr_lines); } - else /* /etc/group doesn't exist -- create default one in memory */ - { - char group_name [UNLEN + 1]; - DWORD group_name_len = UNLEN + 1; - char domain_name [INTERNET_MAX_HOST_NAME_LENGTH + 1]; - DWORD domain_name_len = INTERNET_MAX_HOST_NAME_LENGTH + 1; - SID_NAME_USE acType; + + /* Complete /etc/group in memory if needed */ + if (!getgrgid32 (myself->gid)) + { static char linebuf [200]; + char group_name [UNLEN + 1] = "unknown"; + char strbuf[128] = ""; if (wincap.has_security ()) - { - HANDLE ptok; - cygsid tg; - DWORD siz; - - if (OpenProcessToken (hMainProc, TOKEN_QUERY, &ptok)) - { - if (GetTokenInformation (ptok, TokenPrimaryGroup, &tg, - sizeof tg, &siz) - && LookupAccountSidA (NULL, tg, group_name, - &group_name_len, domain_name, - &domain_name_len, &acType)) - { - char strbuf[100]; - snprintf (linebuf, sizeof (linebuf), "%s:%s:%lu:", - group_name, - tg.string (strbuf), - *GetSidSubAuthority (tg, - *GetSidSubAuthorityCount (tg) - 1)); - debug_printf ("Emulating /etc/group: %s", linebuf); - add_grp_line (linebuf); - group_state = emulated; - } - CloseHandle (ptok); - } - } - if (group_state != emulated) - { - strncpy (group_name, "Administrators", sizeof (group_name)); - 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"); + { + DWORD group_name_len = UNLEN + 1; + char domain_name [INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD domain_name_len = INTERNET_MAX_HOST_NAME_LENGTH + 1; + SID_NAME_USE acType; + struct __group32 *gr; + + cygheap->user.groups.pgsid.string (strbuf); + if (!(gr = getgrsid (cygheap->user.groups.pgsid))) + { + if (!LookupAccountSidA (NULL, cygheap->user.groups.pgsid, + group_name, &group_name_len, + domain_name, &domain_name_len, + &acType)) + debug_printf ("Failed to get primary group name. %E"); } - snprintf (linebuf, sizeof (linebuf), "%s::%u:", group_name, - (unsigned) DEFAULT_GID); - debug_printf ("Emulating /etc/group: %s", linebuf); - add_grp_line (linebuf); - group_state = emulated; + else + strlcpy (group_name, gr->gr_name, sizeof (group_name)); } + snprintf (linebuf, sizeof (linebuf), "%s:%s:%lu:%s", + group_name, strbuf, myself->gid, cygheap->user.name ()); + debug_printf ("Completing /etc/group: %s", linebuf); + add_grp_line (linebuf); } + group_state = loaded; } - return; } +struct __group32 * +getgrsid (cygsid &sid) +{ + char sid_string[128]; + + if (curr_lines < 0 && group_state <= initializing) + read_etc_group (); + + if (sid.string (sid_string)) + for (int i = 0; i < curr_lines; i++) + if (!strcmp (sid_string, (group_buf + i)->gr_passwd)) + return group_buf + i; + return NULL; +} + static struct __group16 * grp32togrp16 (struct __group16 *gp16, struct __group32 *gp32) @@ -246,13 +239,12 @@ getgrgid32 (__gid32_t gid) for (int i = 0; i < curr_lines; i++) { - if (group_buf[i].gr_gid == DEFAULT_GID) + 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 ? NULL : default_grp; + return (!allow_ntsec && gid == ILLEGAL_GID)?default_grp:NULL; } extern "C" struct __group16 * @@ -482,13 +474,9 @@ setgroups32 (int ngroups, const __gid32_ for (int gidy = 0; gidy < gidx; gidy++) if (grouplist[gidy] == grouplist[gidx]) goto found; /* Duplicate */ - for (int gidy = 0; (gr = internal_getgrent (gidy)); ++gidy) - if (gr->gr_gid == (__gid32_t) grouplist[gidx]) - { - if (gsids.addfromgr (gr)) - goto found; - break; - } + if ((gr = getgrgid32 (grouplist[gidx])) && + gsids.addfromgr (gr)) + goto found; debug_printf ("No sid found for gid %d", grouplist[gidx]); gsids.free_sids (); set_errno (EINVAL); --- sec_helper.cc.orig 2002-11-14 17:41:00.000000000 -0500 +++ sec_helper.cc 2002-11-16 16:18:10.000000000 -0500 @@ -118,21 +118,20 @@ BOOL cygsid::getfrompw (const struct passwd *pw) { char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL; - return (*this = sp ? sp + 1 : "") != NULL; + return (*this = sp ? sp + 1 : sp) != NULL; } BOOL cygsid::getfromgr (const struct __group32 *gr) { char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL; - return (*this = sp ?: "") != NULL; + return (*this = sp) != NULL; } __uid32_t cygsid::get_id (BOOL search_grp, int *type) { /* First try to get SID from passwd or group entry */ - cygsid sid; __uid32_t id = ILLEGAL_UID; if (!search_grp) @@ -140,42 +139,25 @@ cygsid::get_id (BOOL search_grp, int *ty struct passwd *pw; if (*this == cygheap->user.sid ()) id = myself->uid; - else - for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx) - { - if (sid.getfrompw (pw) && sid == psid) - { - id = pw->pw_uid; - break; - } - } + else if ((pw = getpwsid (*this))) + id = pw->pw_uid; if (id != ILLEGAL_UID) { if (type) *type = USER; return id; - } + } } if (search_grp || type) { struct __group32 *gr; if (cygheap->user.groups.pgsid == psid) id = myself->gid; - else - for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) - { - if (sid.getfromgr (gr) && sid == psid) - { - id = gr->gr_gid; - break; - } - } - if (id != ILLEGAL_UID) - { - if (type) - *type = GROUP; - } - } + else if ((gr = getgrsid (*this))) + id = gr->gr_gid; + if (id != ILLEGAL_UID && type) + *type = GROUP; + } return id; } @@ -208,24 +190,17 @@ is_grp_member (__uid32_t uid, __gid32_t } /* Otherwise try getting info from examining passwd and group files. */ - for (int idx = 0; (pw = internal_getpwent (idx)); ++idx) - if ((__uid32_t) pw->pw_uid == uid) - { - /* If gid == primary group of uid, return immediately. */ - if ((__gid32_t) pw->pw_gid == gid) - return TRUE; - /* Otherwise search for supplementary user list of this group. */ - for (idx = 0; (gr = internal_getgrent (idx)); ++idx) - if ((__gid32_t) gr->gr_gid == gid) - { - if (gr->gr_mem) - for (idx = 0; gr->gr_mem[idx]; ++idx) - if (strcasematch (cygheap->user.name (), gr->gr_mem[idx])) - return TRUE; - return FALSE; - } - return FALSE; - } + if ((pw = getpwuid32 (uid))) + { + /* If gid == primary group of uid, return immediately. */ + if ((__gid32_t) pw->pw_gid == gid) + return TRUE; + /* Otherwise search for supplementary user list of this group. */ + if ((gr = getgrgid32 (gid)) && gr->gr_mem) + for (idx = 0; gr->gr_mem[idx]; ++idx) + if (strcasematch (cygheap->user.name (), gr->gr_mem[idx])) + return TRUE; + } return FALSE; } --- uinfo.cc.orig 2002-11-02 11:51:30.000000000 -0500 +++ uinfo.cc 2002-11-04 21:00:14.000000000 -0500 @@ -34,10 +34,11 @@ void internal_getlogin (cygheap_user &user) { struct passwd *pw = NULL; + HANDLE ptok = INVALID_HANDLE_VALUE; + myself->gid = DEFAULT_GID; if (wincap.has_security ()) { - HANDLE ptok = INVALID_HANDLE_VALUE; DWORD siz; cygsid tu; DWORD ret = 0; @@ -58,52 +59,39 @@ internal_getlogin (cygheap_user &user) If we have a SID, try to get the corresponding Cygwin password entry. Set user name which can be different from the Windows user name */ - if (ret) - { - cygsid gsid (NO_SID); - cygsid psid; - - for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx) - if (psid.getfrompw (pw) && EqualSid (user.sid (), psid)) - { - user.set_name (pw->pw_name); - struct __group32 *gr = getgrgid32 (pw->pw_gid); - if (gr) - if (!gsid.getfromgr (gr)) - gsid = NO_SID; - break; - } - - /* Set token owner to the same value as token user and - primary group to the group in /etc/passwd. */ + if (ret) + { + if ((pw = getpwsid (tu))) + user.set_name (pw->pw_name); + /* Set token owner to the same value as token user */ if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu)) debug_printf ("SetTokenInformation(TokenOwner): %E"); - if (gsid) - { - user.groups.pgsid = gsid; - if (!SetTokenInformation (ptok, TokenPrimaryGroup, - &gsid, sizeof gsid)) - debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); - } } - if (ptok != INVALID_HANDLE_VALUE) - CloseHandle (ptok); } - if (!pw) - pw = getpwnam (user.name ()); - - if (pw) + if (!pw && !(pw = getpwnam (user.name ()))) + debug_printf("user name not found in augmented /etc/passwd"); + else { myself->uid = pw->pw_uid; myself->gid = pw->pw_gid; + if (wincap.has_security ()) + { + cygsid gsid; + if (gsid.getfromgr (getgrgid32 (pw->pw_gid))) + { + /* Set primary group to the group in /etc/passwd. */ + user.groups.pgsid = gsid; + if (!SetTokenInformation (ptok, TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); + } + else + debug_printf ("gsid not found in augmented /etc/group"); + } } - else - { - myself->uid = DEFAULT_UID; - myself->gid = DEFAULT_GID; - } - + if (ptok != INVALID_HANDLE_VALUE) + CloseHandle (ptok); (void) cygheap->user.ontherange (CH_HOME, pw); return;