OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / passwd.cc
1 /* passwd.cc: getpwnam () and friends
2
3    Copyright 1996, 1997, 1998 Cygnus Solutions.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdlib.h>
12 #include <pwd.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include "winsup.h"
16
17 /* Read /etc/passwd only once for better performance.  This is done
18    on the first call that needs information from it. */
19
20 static struct passwd *passwd_buf = NULL;        /* passwd contents in memory */
21 static int curr_lines = 0;
22 static int max_lines = 0;
23
24 /* Set to 1 when /etc/passwd has been read in by read_etc_passwd (). */
25 /* Functions in this file need to check the value of passwd_in_memory_p
26    and read in the password file if it isn't set. */
27 static int passwd_in_memory_p = 0;
28
29 /* Position in the passwd cache */
30 #ifdef _MT_SAFE
31 #define pw_pos  _reent_winsup()->_pw_pos
32 #else
33 static int pw_pos = 0;
34 #endif
35
36 /* Remove a : teminated string from the buffer, and increment the pointer */
37 static char *
38 grab_string (char **p)
39 {
40   char *src = *p;
41   char *res = src;
42
43   while (*src && *src != ':' && *src != '\n')
44     src++;
45
46   if (*src == ':')
47     {
48       *src = 0;
49       src++;
50     }
51   *p = src;
52   return res;
53 }
54
55 /* same, for ints */
56 static int
57 grab_int (char **p)
58 {
59   char *src = *p;
60   int val = atoi (src);
61   while (*src && *src != ':' && *src != '\n')
62     src++;
63   if (*src == ':')
64     src++;
65   *p = src;
66   return val;
67 }
68
69 /* Parse /etc/passwd line into passwd structure. */
70 void
71 parse_pwd (struct passwd &res, char *buf)
72 {
73   /* Allocate enough room for the passwd struct and all the strings
74      in it in one go */
75   size_t len = strlen (buf);
76   char *mybuf = (char *) malloc (len + 1);
77   (void) memcpy (mybuf, buf, len + 1);
78   if (mybuf[--len] == '\n')
79     mybuf[len] = '\0';
80
81   res.pw_name = strlwr(grab_string (&mybuf));
82   res.pw_passwd = grab_string (&mybuf);
83   res.pw_uid = grab_int (&mybuf);
84   res.pw_gid = grab_int (&mybuf);
85   res.pw_comment = 0;
86   res.pw_gecos = grab_string (&mybuf);
87   res.pw_dir =  grab_string (&mybuf);
88   res.pw_shell = grab_string (&mybuf);
89 }
90
91 /* Add one line from /etc/passwd into the password cache */
92 static void
93 add_pwd_line (char *line)
94 {
95     if (curr_lines >= max_lines)
96       {
97         max_lines += 10;
98         passwd_buf = (struct passwd *) realloc (passwd_buf, max_lines * sizeof (struct passwd));
99       }
100     parse_pwd (passwd_buf[curr_lines++], line);
101 }
102
103 /* Read in /etc/passwd and save contents in the password cache.
104    This sets passwd_in_memory_p to 1 so functions in this file can
105    tell that /etc/passwd has been read in */
106 static void
107 read_etc_passwd ()
108 {
109     extern int passwd_sem;
110     char linebuf[1024];
111     ++passwd_sem;
112     FILE *f = fopen ("/etc/passwd", "r");
113     --passwd_sem;
114
115     if (f)
116       {
117         while (fgets (linebuf, sizeof (linebuf), f) != NULL)
118           {
119             if (strlen (linebuf))
120               add_pwd_line (linebuf);
121           }
122
123         fclose (f);
124       }
125     else
126       {
127         debug_printf ("Emulating /etc/passwd");
128         char user_name [ MAX_USER_NAME ];
129         DWORD user_name_len = MAX_USER_NAME;
130         if (! GetUserNameA (user_name, &user_name_len))
131           {
132             strncpy (user_name, "Administrator", MAX_USER_NAME);
133             debug_printf ("Failed to get current user name. %E");
134           }
135         snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", user_name,
136                   DEFAULT_UID, DEFAULT_GID, getenv ("HOME") ?: "/");
137         add_pwd_line (linebuf);
138       }
139     passwd_in_memory_p = 1;
140 }
141
142 /* Cygwin internal */
143 static struct passwd *
144 search_for (uid_t uid, const char *name)
145 {
146   struct passwd *res = 0;
147   struct passwd *default_pw = 0;
148
149   for (int i = 0; i < curr_lines; i++)
150     {
151       res = passwd_buf + i;
152       if (res->pw_uid == DEFAULT_UID)
153         default_pw = res;
154       /* on Windows NT user names are case-insensitive */
155       if (name)
156         {
157           if (strcasematch (name, res->pw_name))
158             return res;
159         }
160       else if (uid == res->pw_uid)
161         return res;
162     }
163
164   return default_pw;
165 }
166
167 extern "C"
168 struct passwd *
169 getpwuid (uid_t uid)
170 {
171   if (!passwd_in_memory_p)
172     read_etc_passwd();
173
174   return search_for (uid, 0);
175 }
176
177 extern "C"
178 struct passwd *
179 getpwnam (const char *name)
180 {
181   if (!passwd_in_memory_p)
182     read_etc_passwd();
183
184   return search_for (0, name);
185 }
186
187 extern "C"
188 struct passwd *
189 getpwent (void)
190 {
191   if (!passwd_in_memory_p)
192     read_etc_passwd();
193
194   if (pw_pos < curr_lines)
195     return passwd_buf + pw_pos++;
196
197   return NULL;
198 }
199
200 extern "C"
201 struct passwd *
202 getpwduid (uid_t uid)
203 {
204   if (!passwd_in_memory_p)
205     read_etc_passwd();
206
207   return NULL;
208 }
209
210 extern "C"
211 void
212 setpwent (void)
213 {
214   if (!passwd_in_memory_p)
215     read_etc_passwd();
216
217   pw_pos = 0;
218 }
219
220 extern "C"
221 void
222 endpwent (void)
223 {
224   if (!passwd_in_memory_p)
225     read_etc_passwd();
226
227   pw_pos = 0;
228 }
229
230 extern "C"
231 int
232 setpassent ()
233 {
234   if (!passwd_in_memory_p)
235     read_etc_passwd();
236
237   return 0;
238 }
239
240 extern "C"
241 char *
242 getpass (const char * prompt)
243 {
244 #ifdef _MT_SAFE
245   char *pass=_reent_winsup()->_pass;
246 #else
247   static char pass[_PASSWORD_LEN];
248 #endif
249   struct termios ti, newti;
250
251   if (!passwd_in_memory_p)
252     read_etc_passwd();
253
254   if (dtable.not_open (0))
255     {
256       set_errno (EBADF);
257       pass[0] = '\0';
258     }
259   else
260     {
261       fhandler_base *fhstdin = dtable[0];
262       fhstdin->tcgetattr (&ti);
263       newti = ti;
264       newti.c_lflag &= ~ECHO;
265       fhstdin->tcsetattr (TCSANOW, &newti);
266       fputs (prompt, stderr);
267       fgets (pass, _PASSWORD_LEN, stdin);
268       fprintf (stderr, "\n");
269       for (int i=0; pass[i]; i++)
270         if (pass[i] == '\r' || pass[i] == '\n')
271           pass[i] = '\0';
272       fhstdin->tcsetattr (TCSANOW, &ti);
273     }
274   return pass;
275 }