1 /* passwd.cc: getpwnam () and friends
3 Copyright 1996, 1997, 1998, 2001, 2002 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
25 #include <sys/termios.h>
28 /* Read /etc/passwd only once for better performance. This is done
29 on the first call that needs information from it. */
31 static struct passwd *passwd_buf; /* passwd contents in memory */
32 static int curr_lines;
35 static pwdgrp_check passwd_state;
38 /* Position in the passwd cache */
40 #define pw_pos _reent_winsup ()->_pw_pos
42 static int pw_pos = 0;
45 /* Remove a : teminated string from the buffer, and increment the pointer */
47 grab_string (char **p)
52 while (*src && *src != ':' && *src != '\n')
69 int val = strtol (src, NULL, 10);
70 while (*src && *src != ':' && *src != '\n')
78 /* Parse /etc/passwd line into passwd structure. */
80 parse_pwd (struct passwd &res, char *buf)
82 /* Allocate enough room for the passwd struct and all the strings
84 size_t len = strlen (buf);
85 char *mybuf = (char *) malloc (len + 1);
86 (void) memcpy (mybuf, buf, len + 1);
87 if (mybuf[--len] == '\n')
90 res.pw_name = grab_string (&mybuf);
91 res.pw_passwd = grab_string (&mybuf);
92 res.pw_uid = grab_int (&mybuf);
93 res.pw_gid = grab_int (&mybuf);
95 res.pw_gecos = grab_string (&mybuf);
96 res.pw_dir = grab_string (&mybuf);
97 res.pw_shell = grab_string (&mybuf);
100 /* Add one line from /etc/passwd into the password cache */
102 add_pwd_line (char *line)
104 if (curr_lines >= max_lines)
107 passwd_buf = (struct passwd *) realloc (passwd_buf, max_lines * sizeof (struct passwd));
109 parse_pwd (passwd_buf[curr_lines++], line);
115 static NO_COPY pthread_mutex_t mutex;
117 passwd_lock (bool doit)
120 pthread_mutex_lock (&mutex);
126 pthread_mutex_unlock (&mutex);
130 pthread_mutex_t NO_COPY passwd_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
132 /* Read in /etc/passwd and save contents in the password cache.
133 This sets passwd_state to loaded or emulated so functions in this file can
134 tell that /etc/passwd has been read in or will be emulated. */
139 /* A mutex is ok for speed here - pthreads will use critical sections not mutex's
140 * for non-shared mutexs in the future. Also, this function will at most be called
141 * once from each thread, after that the passwd_state test will succeed
143 passwd_lock here (cygwin_finished_initializing);
145 /* if we got blocked by the mutex, then etc_passwd may have been processed */
146 if (passwd_state != uninitialized)
149 if (passwd_state != initializing)
151 passwd_state = initializing;
152 if (max_lines) /* When rereading, free allocated memory first. */
154 for (int i = 0; i < curr_lines; ++i)
155 free (passwd_buf[i].pw_name);
159 FILE *f = fopen ("/etc/passwd", "rt");
163 while (fgets (linebuf, sizeof (linebuf), f) != NULL)
165 if (strlen (linebuf))
166 add_pwd_line (linebuf);
169 passwd_state.set_last_modified (f);
171 passwd_state = loaded;
175 debug_printf ("Emulating /etc/passwd");
176 snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", cygheap->user.name (),
177 (unsigned) DEFAULT_UID, (unsigned) DEFAULT_GID, getenv ("HOME") ?: "/");
178 add_pwd_line (linebuf);
179 passwd_state = emulated;
187 /* Cygwin internal */
188 /* If this ever becomes non-reentrant, update all the getpw*_r functions */
189 static struct passwd *
190 search_for (__uid16_t uid, const char *name)
192 struct passwd *res = 0;
193 struct passwd *default_pw = 0;
195 for (int i = 0; i < curr_lines; i++)
197 res = passwd_buf + i;
198 if (res->pw_uid == DEFAULT_UID)
200 /* on Windows NT user names are case-insensitive */
203 if (strcasematch (name, res->pw_name))
206 else if (uid == res->pw_uid)
210 /* Return default passwd entry if passwd is emulated or it's a
211 request for the current user. */
212 if (passwd_state != loaded
213 || (!name && uid == myself->uid)
214 || (name && strcasematch (name, cygheap->user.name ())))
220 extern "C" struct passwd *
221 getpwuid (__uid16_t uid)
223 if (passwd_state <= initializing)
226 pthread_testcancel();
228 return search_for (uid, 0);
232 getpwuid_r (__uid16_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
239 if (passwd_state <= initializing)
242 pthread_testcancel();
244 struct passwd *temppw = search_for (uid, 0);
249 /* check needed buffer size. */
250 size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_dir) +
251 strlen (temppw->pw_shell) + strlen (temppw->pw_gecos) +
252 strlen (temppw->pw_passwd) + 5;
253 if (needsize > bufsize)
256 /* make a copy of temppw */
258 pwd->pw_uid = temppw->pw_uid;
259 pwd->pw_gid = temppw->pw_gid;
260 pwd->pw_name = buffer;
261 pwd->pw_dir = pwd->pw_name + strlen (temppw->pw_name) + 1;
262 pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1;
263 pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1;
264 pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1;
265 strcpy (pwd->pw_name, temppw->pw_name);
266 strcpy (pwd->pw_dir, temppw->pw_dir);
267 strcpy (pwd->pw_shell, temppw->pw_shell);
268 strcpy (pwd->pw_gecos, temppw->pw_gecos);
269 strcpy (pwd->pw_passwd, temppw->pw_passwd);
273 extern "C" struct passwd *
274 getpwnam (const char *name)
276 if (passwd_state <= initializing)
279 pthread_testcancel();
281 return search_for (0, name);
285 /* the max size buffer we can expect to
286 * use is returned via sysconf with _SC_GETPW_R_SIZE_MAX.
287 * This may need updating! - Rob Collins April 2001.
290 getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
294 if (!pwd || !buffer || !nam)
297 if (passwd_state <= initializing)
300 pthread_testcancel();
302 struct passwd *temppw = search_for (0, nam);
307 /* check needed buffer size. */
308 size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_dir) +
309 strlen (temppw->pw_shell) + strlen (temppw->pw_gecos) +
310 strlen (temppw->pw_passwd) + 5;
311 if (needsize > bufsize)
314 /* make a copy of temppw */
316 pwd->pw_uid = temppw->pw_uid;
317 pwd->pw_gid = temppw->pw_gid;
318 pwd->pw_name = buffer;
319 pwd->pw_dir = pwd->pw_name + strlen (temppw->pw_name) + 1;
320 pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1;
321 pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1;
322 pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1;
323 strcpy (pwd->pw_name, temppw->pw_name);
324 strcpy (pwd->pw_dir, temppw->pw_dir);
325 strcpy (pwd->pw_shell, temppw->pw_shell);
326 strcpy (pwd->pw_gecos, temppw->pw_gecos);
327 strcpy (pwd->pw_passwd, temppw->pw_passwd);
331 extern "C" struct passwd *
334 if (passwd_state <= initializing)
337 if (pw_pos < curr_lines)
338 return passwd_buf + pw_pos++;
343 extern "C" struct passwd *
344 getpwduid (__uid16_t)
367 /* Internal function. ONLY USE THIS INTERNALLY, NEVER `getpwent'!!! */
369 internal_getpwent (int pos)
371 if (passwd_state <= initializing)
374 if (pos < curr_lines)
375 return passwd_buf + pos;
380 getpass (const char * prompt)
383 char *pass=_reent_winsup ()->_pass;
385 static char pass[_PASSWORD_LEN];
387 struct termios ti, newti;
389 if (passwd_state <= initializing)
392 cygheap_fdget fhstdin (0);
398 fhstdin->tcgetattr (&ti);
400 newti.c_lflag &= ~ECHO;
401 fhstdin->tcsetattr (TCSANOW, &newti);
402 fputs (prompt, stderr);
403 fgets (pass, _PASSWORD_LEN, stdin);
404 fprintf (stderr, "\n");
405 for (int i=0; pass[i]; i++)
406 if (pass[i] == '\r' || pass[i] == '\n')
408 fhstdin->tcsetattr (TCSANOW, &ti);