3 Copyright 1996, 1997, 1998, 2000, 2001 Cygnus Solutions.
5 Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
6 First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
8 This file is part of Cygwin.
10 This software is a copyrighted work licensed under the terms of the
11 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
30 /* Read /etc/group only once for better performance. This is done
31 on the first call that needs information from it. */
33 static NO_COPY
const char *etc_group
= "/etc/group";
34 static struct group
*group_buf
; /* group contents in memory */
35 static int curr_lines
;
38 /* Position in the group cache */
40 #define grp_pos _reent_winsup()->_grp_pos
42 static int grp_pos
= 0;
45 /* Set to loaded when /etc/passwd has been read in by read_etc_passwd ().
46 Set to emulated if passwd is emulated. */
47 /* Functions in this file need to check the value of passwd_state
48 and read in the password file if it isn't set. */
57 FILETIME last_modified
;
58 char grp_w32
[MAX_PATH
];
61 grp_check () : state (uninitialized
)
63 last_modified
.dwLowDateTime
= last_modified
.dwHighDateTime
= 0;
71 if (!grp_w32
[0]) /* First call. */
73 path_conv
g ("/etc/group", PC_SYM_FOLLOW
| PC_FULL
);
75 strcpy (grp_w32
, g
.get_win32 ());
78 if ((h
= FindFirstFile (grp_w32
, &data
)) != INVALID_HANDLE_VALUE
)
80 if (CompareFileTime (&data
.ftLastWriteTime
, &last_modified
) > 0)
82 state
= uninitialized
;
83 last_modified
= data
.ftLastWriteTime
;
89 void operator = (grp_state nstate
)
95 static grp_check group_state
;
98 parse_grp (struct group
&grp
, const char *line
)
100 int len
= strlen(line
);
101 char *newline
= (char *) malloc (len
+ 1);
102 (void) memcpy (newline
, line
, len
+ 1);
104 if (newline
[--len
] == '\n')
107 char *dp
= strchr (newline
, ':');
113 grp
.gr_name
= newline
;
116 dp
= strchr (grp
.gr_passwd
, ':');
120 if (!strlen (grp
.gr_passwd
))
121 grp
.gr_passwd
= NULL
;
123 grp
.gr_gid
= strtol (dp
, NULL
, 10);
124 dp
= strchr (dp
, ':');
132 for (cp
= dp
; (cp
= strchr (cp
, ',')) != NULL
; ++cp
)
134 char **namearray
= (char **) calloc (i
+ 2, sizeof (char *));
138 for (cp
= dp
; (cp
= strchr (dp
, ',')) != NULL
; dp
= cp
+ 1)
146 grp
.gr_mem
= namearray
;
149 grp
.gr_mem
= (char **) calloc (1, sizeof (char *));
156 /* Read one line from /etc/group into the group cache */
158 add_grp_line (const char *line
)
160 if (curr_lines
== max_lines
)
163 group_buf
= (struct group
*) realloc (group_buf
, max_lines
* sizeof (struct group
));
165 if (parse_grp (group_buf
[curr_lines
], line
))
169 /* Cygwin internal */
170 /* Read in /etc/group and save contents in the group cache */
171 /* This sets group_in_memory_p to 1 so functions in this file can
172 tell that /etc/group has been read in */
173 /* FIXME: should be static but this is called in uinfo_init outside this
179 char group_name
[UNLEN
+ 1];
180 DWORD group_name_len
= UNLEN
+ 1;
182 strncpy (group_name
, "Administrators", sizeof (group_name
));
184 static NO_COPY pthread_mutex_t etc_group_mutex
= (pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
;
185 pthread_mutex_lock (&etc_group_mutex
);
187 /* if we got blocked by the mutex, then etc_group may have been processed */
188 if (group_state
!= uninitialized
)
190 pthread_mutex_unlock(&etc_group_mutex
);
194 if (group_state
!= initializing
)
196 group_state
= initializing
;
197 if (max_lines
) /* When rereading, free allocated memory first. */
199 for (int i
= 0; i
< curr_lines
; ++i
)
201 free (group_buf
[i
].gr_name
);
202 free (group_buf
[i
].gr_mem
);
205 curr_lines
= max_lines
= 0;
208 FILE *f
= fopen (etc_group
, "rt");
212 while (fgets (linebuf
, sizeof (linebuf
), f
) != NULL
)
214 if (strlen (linebuf
))
215 add_grp_line (linebuf
);
219 group_state
= loaded
;
221 else /* /etc/group doesn't exist -- create default one in memory */
223 char domain_name
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
224 DWORD domain_name_len
= INTERNET_MAX_HOST_NAME_LENGTH
+ 1;
226 debug_printf ("Emulating /etc/group");
227 if (! LookupAccountSidA (NULL
,
228 well_known_admins_sid
,
235 strcpy (group_name
, "unknown");
236 debug_printf ("Failed to get local admins group name. %E");
239 snprintf (linebuf
, sizeof (linebuf
), "%s::%u:\n", group_name
, DEFAULT_GID
);
240 add_grp_line (linebuf
);
241 group_state
= emulated
;
245 pthread_mutex_unlock(&etc_group_mutex
);
252 struct group
* default_grp
= NULL
;
253 if (group_state
<= initializing
)
256 for (int i
= 0; i
< curr_lines
; i
++)
258 if (group_buf
[i
].gr_gid
== DEFAULT_GID
)
259 default_grp
= group_buf
+ i
;
260 if (group_buf
[i
].gr_gid
== gid
)
261 return group_buf
+ i
;
269 getgrnam (const char *name
)
271 if (group_state
<= initializing
)
274 for (int i
= 0; i
< curr_lines
; i
++)
275 if (strcasematch (group_buf
[i
].gr_name
, name
))
276 return group_buf
+ i
;
278 /* Didn't find requested group */
293 if (group_state
<= initializing
)
296 if (grp_pos
< curr_lines
)
297 return group_buf
+ grp_pos
++;
309 /* Internal function. ONLY USE THIS INTERNALLY, NEVER `getgrent'!!! */
311 internal_getgrent (int pos
)
313 if (group_state
<= initializing
)
316 if (pos
< curr_lines
)
317 return group_buf
+ pos
;
322 getgroups (int gidsetsize
, gid_t
*grouplist
, gid_t gid
, const char *username
)
324 HANDLE hToken
= NULL
;
329 if (group_state
<= initializing
)
333 OpenProcessToken (hMainProc
, TOKEN_QUERY
, &hToken
))
335 if (GetTokenInformation (hToken
, TokenGroups
, NULL
, 0, &size
)
336 || GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
339 TOKEN_GROUPS
*groups
= (TOKEN_GROUPS
*) buf
;
341 if (GetTokenInformation (hToken
, TokenGroups
, buf
, size
, &size
))
345 for (int gidx
= 0; (gr
= internal_getgrent (gidx
)); ++gidx
)
346 if (sid
.getfromgr (gr
))
347 for (DWORD pg
= 0; pg
< groups
->GroupCount
; ++pg
)
348 if (sid
== groups
->Groups
[pg
].Sid
)
350 if (cnt
< gidsetsize
)
351 grouplist
[cnt
] = gr
->gr_gid
;
353 if (gidsetsize
&& cnt
> gidsetsize
)
355 CloseHandle (hToken
);
363 debug_printf ("%d = GetTokenInformation(NULL) %E", size
);
364 CloseHandle (hToken
);
369 for (int gidx
= 0; (gr
= internal_getgrent (gidx
)); ++gidx
)
370 if (gid
== gr
->gr_gid
)
372 if (cnt
< gidsetsize
)
373 grouplist
[cnt
] = gr
->gr_gid
;
375 if (gidsetsize
&& cnt
> gidsetsize
)
379 for (int gi
= 0; gr
->gr_mem
[gi
]; ++gi
)
380 if (strcasematch (username
, gr
->gr_mem
[gi
]))
382 if (cnt
< gidsetsize
)
383 grouplist
[cnt
] = gr
->gr_gid
;
385 if (gidsetsize
&& cnt
> gidsetsize
)
397 getgroups (int gidsetsize
, gid_t
*grouplist
)
399 return getgroups (gidsetsize
, grouplist
, myself
->gid
, cygheap
->user
.name ());
404 initgroups (const char *, gid_t
)