diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 806539cd9..99a843935 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,24 @@ +2014-05-07 Corinna Vinschen + + * grp.cc (pwdgrp::parse_group): Set grp.len. Drop generating any + gr_mem entries. + (getgrgid_r): Don't try to copy gr_mem entries. Always set gr_mem + to an empty list. + (getgrnam_r): Ditto. + (app_gr): New static struct to store group data propagated to the + calling application via getgrgid/getgrnam. + (getgr_cp): Fill app_gr and return pointer to app_gr.g. + (getgrgid32): Call getgr_cp. + (getgrnam32): Ditto. + * passwd.cc (pwdgrp::parse_passwd): Set res.len. + (app_pw): New static struct to store passwd data propagated to the + calling application via getpwuid/getpwnam. + (getpw_cp): Fill app_pw and return pointer to app_pw.p. + (getpwuid32): Cal getpw_cp. + (getpwnam): Ditto. + * pwdgrp.h (struct pg_pwd): Add len member. + (struct pg_grp): Ditto. + 2014-05-06 Corinna Vinschen * security.h (MAX_SUBAUTH_CNT): Drop. Use SID_MAX_SUB_AUTHORITIES diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index fadadff64..3ccdbee0f 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -38,23 +38,14 @@ pwdgrp::parse_group () if (!*grp.g.gr_name) return false; grp.g.gr_passwd = next_str (':'); + /* Note that lptr points to the first byte of the gr_gid field. + We deliberately ignore the gr_gid and gr_mem entries when copying + the buffer content since they are not referenced anymore. */ + grp.len = lptr - grp.g.gr_name; if (!next_num (grp.g.gr_gid)) return false; - int n; - char *dp = raw_ptr (); - for (n = 0; *next_str (','); n++) - continue; + /* Don't generate gr_mem entries. */ grp.g.gr_mem = &null_ptr; - if (n) - { - char **namearray = (char **) ccalloc (HEAP_BUF, n + 1, sizeof (char *)); - if (namearray) - { - for (int i = 0; i < n; i++, dp = strchr (dp, '\0') + 1) - namearray[i] = dp; - grp.g.gr_mem = namearray; - } - } grp.sid.getfromgr (&grp.g); return true; } @@ -228,32 +219,60 @@ getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize, if (!tempgr) return 0; - /* check needed buffer size. */ - int i; + /* Check needed buffer size. Deliberately ignore gr_mem. */ size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd) + 2 + sizeof (char *); - for (i = 0; tempgr->gr_mem[i]; ++i) - needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *); if (needsize > bufsize) return ERANGE; - /* make a copy of tempgr */ + /* Make a copy of tempgr. Deliberately ignore gr_mem. */ *result = grp; grp->gr_gid = tempgr->gr_gid; buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name); buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd); grp->gr_mem = (char **) (buffer + 1); - buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *); - for (i = 0; tempgr->gr_mem[i]; ++i) - buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1; - grp->gr_mem[i] = NULL; + grp->gr_mem[0] = NULL; return 0; } +/* getgrgid/getgrnam are not reentrant. */ +static struct { + struct group g; + char *buf; + size_t bufsiz; +} app_gr; + +static struct group * +getgr_cp (struct group *tempgr) +{ + if (!tempgr) + return NULL; + pg_grp *gr = (pg_grp *) tempgr; + if (app_gr.bufsiz < gr->len) + { + char *newbuf = (char *) realloc (app_gr.buf, gr->len); + if (!newbuf) + { + set_errno (ENOMEM); + return NULL; + } + app_gr.buf = newbuf; + app_gr.bufsiz = gr->len; + } + memcpy (app_gr.buf, gr->g.gr_name, gr->len); + memcpy (&app_gr.g, &gr->g, sizeof gr->g); + ptrdiff_t diff = app_gr.buf - gr->g.gr_name; + app_gr.g.gr_name += diff; + app_gr.g.gr_passwd += diff; + return &app_gr.g; +} + extern "C" struct group * getgrgid32 (gid_t gid) { - return internal_getgrgid (gid); + struct group *tempgr = internal_getgrgid (gid); + pthread_testcancel (); + return getgr_cp (tempgr); } #ifdef __x86_64__ @@ -282,32 +301,28 @@ getgrnam_r (const char *nam, struct group *grp, char *buffer, if (!tempgr) return 0; - /* check needed buffer size. */ - int i; + /* Check needed buffer size. Deliberately ignore gr_mem. */ size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd) + 2 + sizeof (char *); - for (i = 0; tempgr->gr_mem[i]; ++i) - needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *); if (needsize > bufsize) return ERANGE; - /* make a copy of tempgr */ + /* Make a copy of tempgr. Deliberately ignore gr_mem. */ *result = grp; grp->gr_gid = tempgr->gr_gid; buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name); buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd); grp->gr_mem = (char **) (buffer + 1); - buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *); - for (i = 0; tempgr->gr_mem[i]; ++i) - buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1; - grp->gr_mem[i] = NULL; + grp->gr_mem[0] = NULL; return 0; } extern "C" struct group * getgrnam32 (const char *name) { - return internal_getgrnam (name); + struct group *tempgr = internal_getgrnam (name); + pthread_testcancel (); + return getgr_cp (tempgr); } #ifdef __x86_64__ diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index b0e5ff8de..9a7c91863 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -41,6 +41,7 @@ pwdgrp::parse_passwd () res.p.pw_dir = next_str (':'); res.p.pw_shell = next_str (':'); res.sid.getfrompw (&res.p); + res.len = lptr - res.p.pw_name; return true; } @@ -180,12 +181,47 @@ internal_getpwuid (uid_t uid, cyg_ldap *pldap) return NULL; } +/* getpwuid/getpwnam are not reentrant. */ +static struct { + struct passwd p; + char *buf; + size_t bufsiz; +} app_pw; + +static struct passwd * +getpw_cp (struct passwd *temppw) +{ + if (!temppw) + return NULL; + pg_pwd *pw = (pg_pwd *) temppw; + if (app_pw.bufsiz < pw->len) + { + char *newbuf = (char *) realloc (app_pw.buf, pw->len); + if (!newbuf) + { + set_errno (ENOMEM); + return NULL; + } + app_pw.buf = newbuf; + app_pw.bufsiz = pw->len; + } + memcpy (app_pw.buf, pw->p.pw_name, pw->len); + memcpy (&app_pw.p, &pw->p, sizeof pw->p); + ptrdiff_t diff = app_pw.buf - pw->p.pw_name; + app_pw.p.pw_name += diff; + app_pw.p.pw_passwd += diff; + app_pw.p.pw_gecos += diff; + app_pw.p.pw_dir += diff; + app_pw.p.pw_shell += diff; + return &app_pw.p; +} + extern "C" struct passwd * getpwuid32 (uid_t uid) { struct passwd *temppw = internal_getpwuid (uid); pthread_testcancel (); - return temppw; + return getpw_cp (temppw); } #ifdef __x86_64__ @@ -246,7 +282,7 @@ getpwnam (const char *name) { struct passwd *temppw = internal_getpwnam (name); pthread_testcancel (); - return temppw; + return getpw_cp (temppw); } diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h index 1a964def3..dfeef5680 100644 --- a/winsup/cygwin/pwdgrp.h +++ b/winsup/cygwin/pwdgrp.h @@ -59,12 +59,14 @@ struct pg_pwd { struct passwd p; cygsid sid; + size_t len; }; struct pg_grp { struct group g; cygsid sid; + size_t len; }; class pwdgrp