]> sourceware.org Git - newlib-cygwin.git/blobdiff - winsup/cygwin/passwd.cc
* cygheap.cc (init_cygheap::etc_changed): New method to signal
[newlib-cygwin.git] / winsup / cygwin / passwd.cc
index 6dd01295d92a932a39849688508dab6058f4a56b..f6943cda8a592202f23c9178d212674e21123c44 100644 (file)
@@ -1,6 +1,6 @@
 /* passwd.cc: getpwnam () and friends
 
-   Copyright 1996, 1997, 1998 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 2001 Cygnus Solutions.
 
 This file is part of Cygwin.
 
@@ -13,28 +13,31 @@ details. */
 #include <pwd.h>
 #include <stdio.h>
 #include <errno.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "path.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "cygheap.h"
+#include <sys/termios.h>
+#include "pwdgrp.h"
 
 /* Read /etc/passwd only once for better performance.  This is done
    on the first call that needs information from it. */
 
-static struct passwd *passwd_buf = NULL;       /* passwd contents in memory */
-static int curr_lines = 0;
-static int max_lines = 0;
-
-/* Set to loaded when /etc/passwd has been read in by read_etc_passwd ().
-   Set to emulated if passwd is emulated. */
-/* Functions in this file need to check the value of passwd_state
-   and read in the password file if it isn't set. */
-enum pwd_state {
-  uninitialized = 0,
-  emulated,
-  loaded
-};
-static pwd_state passwd_state = uninitialized;
+static struct passwd *passwd_buf;      /* passwd contents in memory */
+static int curr_lines;
+static int max_lines;
+
+static pwdgrp_check passwd_state;
+
 
 /* Position in the passwd cache */
 #ifdef _MT_SAFE
-#define pw_pos  _reent_winsup()->_pw_pos
+#define pw_pos  _reent_winsup ()->_pw_pos
 #else
 static int pw_pos = 0;
 #endif
@@ -84,7 +87,7 @@ parse_pwd (struct passwd &res, char *buf)
   if (mybuf[--len] == '\n')
     mybuf[len] = '\0';
 
-  res.pw_name = strlwr(grab_string (&mybuf));
+  res.pw_name = grab_string (&mybuf);
   res.pw_passwd = grab_string (&mybuf);
   res.pw_uid = grab_int (&mybuf);
   res.pw_gid = grab_int (&mybuf);
@@ -112,41 +115,62 @@ 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 NO_COPY 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;
+       if (max_lines) /* When rereading, free allocated memory first. */
          {
-           if (strlen (linebuf))
-             add_pwd_line (linebuf);
+           for (int i = 0; i < curr_lines; ++i)
+             free (passwd_buf[i].pw_name);
+           free (passwd_buf);
+           curr_lines = max_lines = 0;
+         }
+
+       FILE *f = fopen ("/etc/passwd", "rt");
+
+       if (f)
+         {
+           while (fgets (linebuf, sizeof (linebuf), f) != NULL)
+             {
+               if (strlen (linebuf))
+                 add_pwd_line (linebuf);
+             }
+
+           passwd_state.set_last_modified (f);
+           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");
-        char user_name [ MAX_USER_NAME ];
-        DWORD user_name_len = MAX_USER_NAME;
-        if (! GetUserNameA (user_name, &user_name_len))
-          {
-            strncpy (user_name, "Administrator", MAX_USER_NAME);
-            debug_printf ("Failed to get current user name. %E");
-          }
-        snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", 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)
 {
@@ -157,7 +181,7 @@ search_for (uid_t uid, const char *name)
     {
       res = passwd_buf + i;
       if (res->pw_uid == DEFAULT_UID)
-        default_pw = res;
+       default_pw = res;
       /* on Windows NT user names are case-insensitive */
       if (name)
        {
@@ -171,8 +195,8 @@ search_for (uid_t uid, const char *name)
   /* 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, myself->username)))
+      || (!name && uid == myself->uid)
+      || (name && strcasematch (name, cygheap->user.name ())))
     return default_pw;
 
   return NULL;
@@ -181,26 +205,119 @@ search_for (uid_t uid, const char *name)
 extern "C" struct passwd *
 getpwuid (uid_t uid)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
+  if (passwd_state  <= initializing)
+    read_etc_passwd ();
+
+  pthread_testcancel();
 
   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 ();
+
+  pthread_testcancel();
+
+  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) + strlen (temppw->pw_gecos) +
+                   strlen (temppw->pw_passwd) + 5;
+  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 = pwd->pw_name + strlen (temppw->pw_name) + 1;
+  pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1;
+  pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1;
+  pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1;
+  strcpy (pwd->pw_name, temppw->pw_name);
+  strcpy (pwd->pw_dir, temppw->pw_dir);
+  strcpy (pwd->pw_shell, temppw->pw_shell);
+  strcpy (pwd->pw_gecos, temppw->pw_gecos);
+  strcpy (pwd->pw_passwd, temppw->pw_passwd);
+  return 0;
+}
+
 extern "C" struct passwd *
 getpwnam (const char *name)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
+  if (passwd_state  <= initializing)
+    read_etc_passwd ();
+
+  pthread_testcancel();
 
   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 ();
+
+  pthread_testcancel();
+
+  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) + strlen (temppw->pw_gecos) +
+                   strlen (temppw->pw_passwd) + 5;
+  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 = pwd->pw_name + strlen (temppw->pw_name) + 1;
+  pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1;
+  pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1;
+  pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1;
+  strcpy (pwd->pw_name, temppw->pw_name);
+  strcpy (pwd->pw_dir, temppw->pw_dir);
+  strcpy (pwd->pw_shell, temppw->pw_shell);
+  strcpy (pwd->pw_gecos, temppw->pw_gecos);
+  strcpy (pwd->pw_passwd, temppw->pw_passwd);
+  return 0;
+}
+
 extern "C" struct passwd *
 getpwent (void)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
+  if (passwd_state  <= initializing)
+    read_etc_passwd ();
 
   if (pw_pos < curr_lines)
     return passwd_buf + pw_pos++;
@@ -211,60 +328,60 @@ getpwent (void)
 extern "C" struct passwd *
 getpwduid (uid_t)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
-
   return NULL;
 }
 
 extern "C" void
 setpwent (void)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
-
   pw_pos = 0;
 }
 
 extern "C" void
 endpwent (void)
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
-
   pw_pos = 0;
 }
 
 extern "C" int
 setpassent ()
 {
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
-
   return 0;
 }
 
+/* Internal function. ONLY USE THIS INTERNALLY, NEVER `getpwent'!!! */
+struct passwd *
+internal_getpwent (int pos)
+{
+  if (passwd_state  <= initializing)
+    read_etc_passwd ();
+
+  if (pos < curr_lines)
+    return passwd_buf + pos;
+  return NULL;
+}
+
 extern "C" char *
 getpass (const char * prompt)
 {
 #ifdef _MT_SAFE
-  char *pass=_reent_winsup()->_pass;
+  char *pass=_reent_winsup ()->_pass;
 #else
   static char pass[_PASSWORD_LEN];
 #endif
   struct termios ti, newti;
 
-  if (passwd_state == uninitialized)
-    read_etc_passwd();
+  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;
This page took 0.030629 seconds and 5 git commands to generate.