diff options
author | Christopher Faylor <me@cgf.cx> | 2001-04-18 21:10:15 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2001-04-18 21:10:15 +0000 |
commit | 0381fec68f46471d29d3b87c5361e05fcdeb2cd5 (patch) | |
tree | 718cfaf2d3d8734c48f8957892329c0e8fc2fbfc /winsup/cygwin/passwd.cc | |
parent | a2d47fe9d983ec85075172211172af9e5ab4054f (diff) | |
download | cygnal-0381fec68f46471d29d3b87c5361e05fcdeb2cd5.tar.gz cygnal-0381fec68f46471d29d3b87c5361e05fcdeb2cd5.tar.bz2 cygnal-0381fec68f46471d29d3b87c5361e05fcdeb2cd5.zip |
Throughout, change fdtab references to cygheap->fdtab.
* child_info.h (cygheap_exec_info): Eliminate special fdtab stuff.
* spawn.cc (spawn_guts): Ditto.
* cygheap.cc (cygheap_init): Initialize fdtab, if appropriate.
* cygheap.h (CYGHEAPSIZE): Include size of init_cygheap.
(_cmalloc_entry): Include fdtab here.
* dtable.h (dtable): Declare/define new methods.
* dtable.cc (dtable::vfork_child_fixup): New method.
(dtable::fixup_after_exec): Remove unneeded extra arguments.
* dcrt0.cc (dll_crt0_1): Ditto.
* environ.cc (getwinenv): Use case sensitive comparison.
(winenv): Make a copy of environment cache to avoid realloc problems when
duplicate environment variables exist in the environment. (From Egor Duda)
* net.cc (cygwin_socket): Revert Apr 14 change.
* include/sys/file.h: Protect against previous X_OK definition.
* passwd.cc: Eliminate passwd_sem throughout.
* security.cc: Ditto.
* cygwin.din: Export New functions.
* passwd.cc (read_etc_passwd): Make race safe.
(getpwuid_r): New function.
(getpwnam_r): New function.
Diffstat (limited to 'winsup/cygwin/passwd.cc')
-rw-r--r-- | winsup/cygwin/passwd.cc | 150 |
1 files changed, 122 insertions, 28 deletions
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 21c3e786d..6164b0930 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -35,6 +35,7 @@ static int max_lines = 0; and read in the password file if it isn't set. */ enum pwd_state { uninitialized = 0, + initializing, emulated, loaded }; @@ -120,34 +121,54 @@ add_pwd_line (char *line) void read_etc_passwd () { - extern int passwd_sem; char linebuf[1024]; - ++passwd_sem; - FILE *f = fopen ("/etc/passwd", "rt"); - --passwd_sem; + /* A mutex is ok for speed here - pthreads will use critical sections not mutex's + * for non-shared mutexs in the future. Also, this function will at most be called + * once from each thread, after that the passwd_state test will succeed + */ + static pthread_mutex_t etc_passwd_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock (&etc_passwd_mutex); + + /* if we got blocked by the mutex, then etc_passwd may have been processed */ + if (passwd_state != uninitialized) + { + pthread_mutex_unlock(&etc_passwd_mutex); + return; + } - if (f) + if (passwd_state != initializing) { - while (fgets (linebuf, sizeof (linebuf), f) != NULL) + passwd_state = initializing; + + FILE *f = fopen ("/etc/passwd", "rt"); + + if (f) { - if (strlen (linebuf)) - add_pwd_line (linebuf); + while (fgets (linebuf, sizeof (linebuf), f) != NULL) + { + if (strlen (linebuf)) + add_pwd_line (linebuf); + } + + fclose (f); + passwd_state = loaded; + } + else + { + debug_printf ("Emulating /etc/passwd"); + snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", cygheap->user.name (), + DEFAULT_UID, DEFAULT_GID, getenv ("HOME") ?: "/"); + add_pwd_line (linebuf); + passwd_state = emulated; } - fclose (f); - passwd_state = loaded; - } - else - { - debug_printf ("Emulating /etc/passwd"); - snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", cygheap->user.name (), - DEFAULT_UID, DEFAULT_GID, getenv ("HOME") ?: "/"); - add_pwd_line (linebuf); - passwd_state = emulated; } + + pthread_mutex_unlock (&etc_passwd_mutex); } /* Cygwin internal */ +/* If this ever becomes non-reentrant, update all the getpw*_r functions */ static struct passwd * search_for (uid_t uid, const char *name) { @@ -182,25 +203,98 @@ search_for (uid_t uid, const char *name) extern "C" struct passwd * getpwuid (uid_t uid) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); return search_for (uid, 0); } +extern "C" int +getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) +{ + *result = NULL; + + if (!pwd || !buffer) + return ERANGE; + + if (passwd_state <= initializing) + read_etc_passwd (); + + struct passwd *temppw = search_for (uid, 0); + + if (!temppw) + return 0; + + /* check needed buffer size. */ + size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_dir) + strlen (temppw->pw_shell); + if (needsize > bufsize) + return ERANGE; + + /* make a copy of temppw */ + *result = pwd; + pwd->pw_uid = temppw->pw_uid; + pwd->pw_gid = temppw->pw_gid; + pwd->pw_name = buffer; + pwd->pw_dir = buffer + strlen (temppw->pw_name); + pwd->pw_shell = buffer + strlen (temppw->pw_name) + strlen (temppw->pw_dir); + strcpy (pwd->pw_name, temppw->pw_name); + strcpy (pwd->pw_dir, temppw->pw_dir); + strcpy (pwd->pw_shell, temppw->pw_shell); + return 0; +} + extern "C" struct passwd * getpwnam (const char *name) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); return search_for (0, name); } + +/* the max size buffer we can expect to + * use is returned via sysconf with _SC_GETPW_R_SIZE_MAX. + * This may need updating! - Rob Collins April 2001. + */ +extern "C" int +getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) +{ + *result = NULL; + + if (!pwd || !buffer || !nam) + return ERANGE; + + if (passwd_state <= initializing) + read_etc_passwd (); + + struct passwd *temppw = search_for (0, nam); + + if (!temppw) + return 0; + + /* check needed buffer size. */ + size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_dir) + strlen (temppw->pw_shell); + if (needsize > bufsize) + return ERANGE; + + /* make a copy of temppw */ + *result = pwd; + pwd->pw_uid = temppw->pw_uid; + pwd->pw_gid = temppw->pw_gid; + pwd->pw_name = buffer; + pwd->pw_dir = buffer + strlen (temppw->pw_name); + pwd->pw_shell = buffer + strlen (temppw->pw_name) + strlen (temppw->pw_dir); + strcpy (pwd->pw_name, temppw->pw_name); + strcpy (pwd->pw_dir, temppw->pw_dir); + strcpy (pwd->pw_shell, temppw->pw_shell); + return 0; +} + extern "C" struct passwd * getpwent (void) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); if (pw_pos < curr_lines) @@ -212,7 +306,7 @@ getpwent (void) extern "C" struct passwd * getpwduid (uid_t) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); return NULL; @@ -221,7 +315,7 @@ getpwduid (uid_t) extern "C" void setpwent (void) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); pw_pos = 0; @@ -230,7 +324,7 @@ setpwent (void) extern "C" void endpwent (void) { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); pw_pos = 0; @@ -239,7 +333,7 @@ endpwent (void) extern "C" int setpassent () { - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); return 0; @@ -255,17 +349,17 @@ getpass (const char * prompt) #endif struct termios ti, newti; - if (passwd_state == uninitialized) + if (passwd_state <= initializing) read_etc_passwd (); - if (fdtab.not_open (0)) + if (cygheap->fdtab.not_open (0)) { set_errno (EBADF); pass[0] = '\0'; } else { - fhandler_base *fhstdin = fdtab[0]; + fhandler_base *fhstdin = cygheap->fdtab[0]; fhstdin->tcgetattr (&ti); newti = ti; newti.c_lflag &= ~ECHO; |