]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/grp.cc
Cygwin: sigfe: Fix a bug that signal handler destroys fpu states
[newlib-cygwin.git] / winsup / cygwin / grp.cc
CommitLineData
1fd5e000
CF
1/* grp.cc
2
1fd5e000
CF
3 Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
4 First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
5
6This file is part of Cygwin.
7
8This software is a copyrighted work licensed under the terms of the
9Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10details. */
11
4c8d72de 12#include "winsup.h"
a8cf6887 13#include <lm.h>
bef55bb5 14#include <ntsecapi.h>
0c1d8aaa 15#include <assert.h>
1fd5e000
CF
16#include <stdio.h>
17#include <stdlib.h>
169c465a 18#include "cygerrno.h"
e2ebe117 19#include "pinfo.h"
f5e8e2be 20#include "path.h"
7ac61736 21#include "fhandler.h"
47063f00 22#include "dtable.h"
df63bd49 23#include "cygheap.h"
12eac211 24#include "ntdll.h"
a8cf6887
CV
25#include "miscfuncs.h"
26#include "ldap.h"
27#include "tls_pbuf.h"
1fd5e000 28
61522196 29static char * NO_COPY_RO null_ptr;
1fd5e000 30
7905c4f1 31bool
ac413374 32pwdgrp::parse_group ()
1fd5e000 33{
1ca20a1c
CV
34 pg_grp &grp = group ()[curr_lines];
35 grp.g.gr_name = next_str (':');
36 if (!*grp.g.gr_name)
ac413374 37 return false;
1ca20a1c 38 grp.g.gr_passwd = next_str (':');
20de26eb
CV
39 /* Note that lptr points to the first byte of the gr_gid field.
40 We deliberately ignore the gr_gid and gr_mem entries when copying
41 the buffer content since they are not referenced anymore. */
42 grp.len = lptr - grp.g.gr_name;
1ca20a1c 43 if (!next_num (grp.g.gr_gid))
65037056 44 return false;
20de26eb 45 /* Don't generate gr_mem entries. */
1ca20a1c 46 grp.g.gr_mem = &null_ptr;
83b3f891 47 cygsid csid;
c7432b13
CV
48 if (csid.getfromgr_passwd (&grp.g))
49 RtlCopySid (SECURITY_MAX_SID_SIZE, grp.sid, csid);
65037056 50 return true;
1fd5e000
CF
51}
52
1ca20a1c
CV
53muto NO_COPY pwdgrp::pglock;
54
57394495 55void
1ca20a1c 56pwdgrp::init_grp ()
1fd5e000 57{
1ca20a1c
CV
58 pwdgrp_buf_elem_size = sizeof (pg_grp);
59 parse = &pwdgrp::parse_group;
60}
57394495 61
1ca20a1c
CV
62struct group *
63pwdgrp::find_group (cygpsid &sid)
64{
65 for (ULONG i = 0; i < curr_lines; i++)
66 if (sid == group ()[i].sid)
67 return &group ()[i].g;
68 return NULL;
69}
2f1086cb 70
1ca20a1c
CV
71struct group *
72pwdgrp::find_group (const char *name)
f3c1c540 73{
1ca20a1c
CV
74 for (ULONG i = 0; i < curr_lines; i++)
75 if (strcasematch (group ()[i].g.gr_name, name))
76 return &group ()[i].g;
77 return NULL;
f3c1c540
TP
78}
79
1ca20a1c
CV
80struct group *
81pwdgrp::find_group (gid_t gid)
f3c1c540 82{
1ca20a1c
CV
83 for (ULONG i = 0; i < curr_lines; i++)
84 if (gid == group ()[i].g.gr_gid)
85 return &group ()[i].g;
86 return NULL;
f3c1c540
TP
87}
88
61522196 89struct group *
b39fa2c8 90internal_getgrsid (cygpsid &sid, cyg_ldap *pldap)
647b92a7 91{
1ca20a1c 92 struct group *ret;
647b92a7 93
1ca20a1c 94 cygheap->pg.nss_init ();
29b7313d
CV
95 /* Check caches first. */
96 if (cygheap->pg.nss_cygserver_caching ()
97 && (ret = cygheap->pg.grp_cache.cygserver.find_group (sid)))
98 return ret;
99 if (cygheap->pg.nss_grp_files ()
100 && (ret = cygheap->pg.grp_cache.file.find_group (sid)))
101 return ret;
102 if (cygheap->pg.nss_grp_db ()
103 && (ret = cygheap->pg.grp_cache.win.find_group (sid)))
104 return ret;
105 /* Ask sources afterwards. */
106 if (cygheap->pg.nss_cygserver_caching ()
107 && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (sid)))
108 return ret;
1ca20a1c
CV
109 if (cygheap->pg.nss_grp_files ())
110 {
0e8dd884 111 cygheap->pg.grp_cache.file.check_file ();
1ca20a1c
CV
112 if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (sid)))
113 return ret;
114 }
115 if (cygheap->pg.nss_grp_db ())
29b7313d 116 return cygheap->pg.grp_cache.win.add_group_from_windows (sid, pldap);
647b92a7
CV
117 return NULL;
118}
119
bef55bb5
CV
120/* Like internal_getgrsid but return only already cached data,
121 NULL otherwise. */
122static struct group *
123internal_getgrsid_cachedonly (cygpsid &sid)
124{
125 struct group *ret;
126
127 /* Check caches only. */
128 if (cygheap->pg.nss_cygserver_caching ()
129 && (ret = cygheap->pg.grp_cache.cygserver.find_group (sid)))
130 return ret;
131 if (cygheap->pg.nss_grp_files ()
132 && (ret = cygheap->pg.grp_cache.file.find_group (sid)))
133 return ret;
134 if (cygheap->pg.nss_grp_db ()
135 && (ret = cygheap->pg.grp_cache.win.find_group (sid)))
136 return ret;
137 return NULL;
138}
139
140/* Called from internal_getgroups. The full information required to create
141 a group account entry is already available from the LookupAccountSids
142 call. internal_getgrfull passes all available info into
143 pwdgrp::fetch_account_from_line, thus avoiding a LookupAccountSid call
144 for each group. This is quite a bit faster, especially in slower
145 environments. */
146static struct group * __attribute__((used))
ad8d295e 147internal_getgrfull (fetch_acc_t &full_acc, cyg_ldap *pldap)
bef55bb5
CV
148{
149 struct group *ret;
150
151 cygheap->pg.nss_init ();
4cb24051
CV
152 /* Skip local caches, internal_getgroups already called
153 internal_getgrsid_cachedonly. */
bef55bb5
CV
154 if (cygheap->pg.nss_cygserver_caching ()
155 && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver
d2ef2331 156 (full_acc.sid)))
bef55bb5
CV
157 return ret;
158 if (cygheap->pg.nss_grp_files ())
159 {
160 cygheap->pg.grp_cache.file.check_file ();
161 if ((ret = cygheap->pg.grp_cache.file.add_group_from_file
d2ef2331 162 (full_acc.sid)))
bef55bb5
CV
163 return ret;
164 }
165 if (cygheap->pg.nss_grp_db ())
ad8d295e 166 return cygheap->pg.grp_cache.win.add_group_from_windows (full_acc, pldap);
bef55bb5
CV
167 return NULL;
168}
169
b211f4c1
CV
170/* This function gets only called from mkgroup via cygwin_internal. */
171struct group *
172internal_getgrsid_from_db (cygpsid &sid)
173{
174 cygheap->pg.nss_init ();
175 return cygheap->pg.grp_cache.win.add_group_from_windows (sid);
176}
177
61522196 178struct group *
b39fa2c8 179internal_getgrnam (const char *name, cyg_ldap *pldap)
d6ffc075 180{
1ca20a1c 181 struct group *ret;
d6ffc075 182
1ca20a1c 183 cygheap->pg.nss_init ();
29b7313d
CV
184 /* Check caches first. */
185 if (cygheap->pg.nss_cygserver_caching ()
186 && (ret = cygheap->pg.grp_cache.cygserver.find_group (name)))
187 return ret;
188 if (cygheap->pg.nss_grp_files ()
189 && (ret = cygheap->pg.grp_cache.file.find_group (name)))
190 return ret;
191 if (cygheap->pg.nss_grp_db ()
192 && (ret = cygheap->pg.grp_cache.win.find_group (name)))
193 return ret;
194 /* Ask sources afterwards. */
195 if (cygheap->pg.nss_cygserver_caching ()
196 && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (name)))
197 return ret;
1ca20a1c
CV
198 if (cygheap->pg.nss_grp_files ())
199 {
0e8dd884 200 cygheap->pg.grp_cache.file.check_file ();
1ca20a1c
CV
201 if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (name)))
202 return ret;
203 }
204 if (cygheap->pg.nss_grp_db ())
29b7313d 205 return cygheap->pg.grp_cache.win.add_group_from_windows (name, pldap);
14ea5029 206 return NULL;
d6ffc075
CV
207}
208
61522196 209struct group *
b39fa2c8 210internal_getgrgid (gid_t gid, cyg_ldap *pldap)
d6ffc075 211{
1ca20a1c 212 struct group *ret;
d6ffc075 213
1ca20a1c 214 cygheap->pg.nss_init ();
29b7313d
CV
215 /* Check caches first. */
216 if (cygheap->pg.nss_cygserver_caching ()
217 && (ret = cygheap->pg.grp_cache.cygserver.find_group (gid)))
218 return ret;
219 if (cygheap->pg.nss_grp_files ()
220 && (ret = cygheap->pg.grp_cache.file.find_group (gid)))
221 return ret;
222 if (cygheap->pg.nss_grp_db ()
223 && (ret = cygheap->pg.grp_cache.win.find_group (gid)))
224 return ret;
225 /* Ask sources afterwards. */
226 if (cygheap->pg.nss_cygserver_caching ()
227 && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (gid)))
228 return ret;
1ca20a1c
CV
229 if (cygheap->pg.nss_grp_files ())
230 {
0e8dd884 231 cygheap->pg.grp_cache.file.check_file ();
1ca20a1c
CV
232 if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (gid)))
233 return ret;
234 }
29b7313d 235 if (cygheap->pg.nss_grp_db () || gid == ILLEGAL_GID)
b39fa2c8 236 return cygheap->pg.grp_cache.win.add_group_from_windows (gid, pldap);
d6ffc075
CV
237 return NULL;
238}
239
68509b30 240extern "C" int
61522196
CV
241getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize,
242 struct group **result)
68509b30
CV
243{
244 *result = NULL;
245
246 if (!grp || !buffer)
247 return ERANGE;
248
1ca20a1c 249 struct group *tempgr = internal_getgrgid (gid);
e3778517 250 pthread_testcancel ();
68509b30
CV
251 if (!tempgr)
252 return 0;
253
20de26eb 254 /* Check needed buffer size. Deliberately ignore gr_mem. */
68509b30
CV
255 size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
256 + 2 + sizeof (char *);
68509b30
CV
257 if (needsize > bufsize)
258 return ERANGE;
259
20de26eb 260 /* Make a copy of tempgr. Deliberately ignore gr_mem. */
68509b30
CV
261 *result = grp;
262 grp->gr_gid = tempgr->gr_gid;
b89fb103
CV
263 buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
264 buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
265 grp->gr_mem = (char **) (buffer + 1);
20de26eb 266 grp->gr_mem[0] = NULL;
68509b30
CV
267 return 0;
268}
269
20de26eb
CV
270/* getgrgid/getgrnam are not reentrant. */
271static struct {
272 struct group g;
273 char *buf;
274 size_t bufsiz;
275} app_gr;
276
277static struct group *
278getgr_cp (struct group *tempgr)
279{
280 if (!tempgr)
281 return NULL;
282 pg_grp *gr = (pg_grp *) tempgr;
283 if (app_gr.bufsiz < gr->len)
284 {
285 char *newbuf = (char *) realloc (app_gr.buf, gr->len);
286 if (!newbuf)
287 {
288 set_errno (ENOMEM);
289 return NULL;
290 }
291 app_gr.buf = newbuf;
292 app_gr.bufsiz = gr->len;
293 }
294 memcpy (app_gr.buf, gr->g.gr_name, gr->len);
295 memcpy (&app_gr.g, &gr->g, sizeof gr->g);
296 ptrdiff_t diff = app_gr.buf - gr->g.gr_name;
297 app_gr.g.gr_name += diff;
298 app_gr.g.gr_passwd += diff;
299 return &app_gr.g;
300}
301
61522196 302extern "C" struct group *
2d9b4876 303getgrgid (gid_t gid)
57196405 304{
20de26eb
CV
305 struct group *tempgr = internal_getgrgid (gid);
306 pthread_testcancel ();
307 return getgr_cp (tempgr);
1fd5e000
CF
308}
309
68509b30 310extern "C" int
61522196
CV
311getgrnam_r (const char *nam, struct group *grp, char *buffer,
312 size_t bufsize, struct group **result)
68509b30
CV
313{
314 *result = NULL;
315
316 if (!grp || !buffer)
317 return ERANGE;
318
1ca20a1c 319 struct group *tempgr = internal_getgrnam (nam);
e3778517 320 pthread_testcancel ();
68509b30
CV
321 if (!tempgr)
322 return 0;
323
20de26eb 324 /* Check needed buffer size. Deliberately ignore gr_mem. */
68509b30
CV
325 size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
326 + 2 + sizeof (char *);
68509b30
CV
327 if (needsize > bufsize)
328 return ERANGE;
329
20de26eb 330 /* Make a copy of tempgr. Deliberately ignore gr_mem. */
68509b30
CV
331 *result = grp;
332 grp->gr_gid = tempgr->gr_gid;
b89fb103
CV
333 buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
334 buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
335 grp->gr_mem = (char **) (buffer + 1);
20de26eb 336 grp->gr_mem[0] = NULL;
68509b30
CV
337 return 0;
338}
339
61522196 340extern "C" struct group *
2d9b4876 341getgrnam (const char *name)
1fd5e000 342{
20de26eb
CV
343 struct group *tempgr = internal_getgrnam (name);
344 pthread_testcancel ();
345 return getgr_cp (tempgr);
1fd5e000
CF
346}
347
a8cf6887
CV
348/* getgrent functions are not reentrant. */
349static gr_ent grent;
1fd5e000 350
a8cf6887
CV
351void *
352gr_ent::enumerate_caches ()
1fd5e000 353{
29b7313d 354 switch (max)
1ca20a1c 355 {
29b7313d
CV
356 case 0:
357 if (cygheap->pg.nss_cygserver_caching ())
358 {
359 pwdgrp &grc = cygheap->pg.grp_cache.cygserver;
360 if (cnt < grc.cached_groups ())
361 return &grc.group ()[cnt++].g;
362 }
a8cf6887
CV
363 cnt = 0;
364 max = 1;
50ad1980 365 fallthrough;
29b7313d
CV
366 case 1:
367 if (from_files)
368 {
369 pwdgrp &grf = cygheap->pg.grp_cache.file;
370 grf.check_file ();
371 if (cnt < grf.cached_groups ())
372 return &grf.group ()[cnt++].g;
373 }
374 cnt = 0;
a5a75a5a 375 max = 2;
50ad1980 376 fallthrough;
29b7313d
CV
377 case 2:
378 if (from_db)
379 {
380 pwdgrp &grw = cygheap->pg.grp_cache.win;
381 if (cnt < grw.cached_groups ())
382 return &grw.group ()[cnt++].g;
383 }
384 break;
1ca20a1c 385 }
a8cf6887 386 cnt = max = 0;
1fd5e000
CF
387 return NULL;
388}
389
a8cf6887
CV
390void *
391gr_ent::enumerate_local ()
392{
393 while (true)
394 {
395 if (!cnt)
396 {
397 DWORD total;
398 NET_API_STATUS ret;
399
400 if (buf)
401 {
402 NetApiBufferFree (buf);
403 buf = NULL;
404 }
405 if (resume == ULONG_MAX)
406 ret = ERROR_NO_MORE_ITEMS;
407 else
408 ret = NetLocalGroupEnum (NULL, 0, (PBYTE *) &buf,
409 MAX_PREFERRED_LENGTH,
410 &max, &total, &resume);
411 if (ret == NERR_Success)
412 resume = ULONG_MAX;
413 else if (ret != ERROR_MORE_DATA)
414 {
415 cnt = max = resume = 0;
416 return NULL;
417 }
418 }
419 while (cnt < max)
420 {
421 cygsid sid;
fc3a3524 422 DWORD slen = SECURITY_MAX_SID_SIZE;
a8cf6887
CV
423 WCHAR dom[DNLEN + 1];
424 DWORD dlen = DNLEN + 1;
425 SID_NAME_USE acc_type;
426
15e82eef
CV
427 if (!LookupAccountNameW (NULL,
428 ((PLOCALGROUP_INFO_0) buf)[cnt++].lgrpi0_name,
429 sid, &slen, dom, &dlen, &acc_type))
430 continue;
5f586adc
CV
431 /* Skip builtin groups if we're enumerating AD as well to avoid
432 duplication. Don't skip "Power Users" and "Device Owners"
433 accounts, they don't show up in AD enumeration. */
434 if (cygheap->dom.member_machine ()
435 && nss_db_enum_primary ()
436 && sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
15e82eef 437 && sid_sub_auth (sid, 0) == SECURITY_BUILTIN_DOMAIN_RID
5f586adc
CV
438 && sid_sub_auth (sid, 1) != DOMAIN_ALIAS_RID_POWER_USERS
439 && sid_sub_auth (sid, 1) != DOMAIN_ALIAS_RID_DEVICE_OWNERS)
15e82eef 440 continue;
a8cf6887
CV
441 fetch_user_arg_t arg;
442 arg.type = SID_arg;
443 arg.sid = &sid;
0e8dd884 444 char *line = pg.fetch_account_from_windows (arg);
a8cf6887
CV
445 if (line)
446 return pg.add_account_post_fetch (line, false);
447 }
448 cnt = 0;
449 }
450}
451
452struct group *
453gr_ent::getgrent (void)
454{
455 if (state == rewound)
456 setent (true);
457 else
458 clear_cache ();
459 return (struct group *) getent ();
460}
461
462extern "C" void
463setgrent ()
464{
465 grent.setgrent ();
466}
467
468extern "C" struct group *
2d9b4876 469getgrent (void)
a8cf6887
CV
470{
471 return grent.getgrent ();
472}
473
38c77307 474extern "C" void
a8cf6887 475endgrent (void)
1fd5e000 476{
a8cf6887 477 grent.endgrent ();
1fd5e000
CF
478}
479
036f56cf
CV
480/* *_filtered functions are called from mkgroup */
481void *
482setgrent_filtered (int enums, PCWSTR enum_tdoms)
483{
484 gr_ent *gr = new gr_ent;
485 if (gr)
486 gr->setgrent (enums, enum_tdoms);
487 return (void *) gr;
488}
489
490void *
491getgrent_filtered (void *gr)
492{
493 return (void *) ((gr_ent *) gr)->getgrent ();
494}
495
496void
497endgrent_filtered (void *gr)
498{
499 ((gr_ent *) gr)->endgrent ();
500}
501
6cc7c925 502int
6f93f1d6 503internal_getgroups (int gidsetsize, gid_t *grouplist, cyg_ldap *pldap)
1fd5e000 504{
12eac211 505 NTSTATUS status;
b39fa2c8 506 HANDLE tok;
12eac211 507 ULONG size;
bef55bb5
CV
508 PTOKEN_GROUPS groups;
509 PSID *sidp_buf;
510 ULONG scnt;
511 PLSA_REFERENCED_DOMAIN_LIST dlst = NULL;
512 PLSA_TRANSLATED_NAME nlst = NULL;
513
514 tmp_pathbuf tp;
1ca20a1c 515 struct group *grp;
bef55bb5 516 int cnt = 0;
1fd5e000 517
b39fa2c8 518 if (cygheap->user.groups.issetgroups ())
4ce377c9 519 {
1ca20a1c 520 for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
b39fa2c8 521 if ((grp = internal_getgrsid (cygheap->user.groups.sgsids.sids[pg],
6cc7c925 522 pldap)))
1ca20a1c
CV
523 {
524 if (cnt < gidsetsize)
525 grouplist[cnt] = grp->gr_gid;
526 ++cnt;
527 if (gidsetsize && cnt > gidsetsize)
bef55bb5
CV
528 {
529 cnt = -1;
530 break;
531 }
1ca20a1c 532 }
bef55bb5 533 goto out;
4ce377c9 534 }
68a3f0d3 535
68a3f0d3 536 /* If impersonated, use impersonation token. */
bef55bb5
CV
537 tok = cygheap->user.issetuid () ? cygheap->user.primary_token ()
538 : hProcToken;
539
540 /* Fetch groups from user token. */
541 groups = (PTOKEN_GROUPS) tp.w_get ();
542 status = NtQueryInformationToken (tok, TokenGroups, groups, 2 * NT_MAX_PATH,
543 &size);
544 if (!NT_SUCCESS (status))
c4548fb4 545 {
4cb24051 546 debug_printf ("NtQueryInformationToken(TokenGroups) %y", status);
bef55bb5
CV
547 goto out;
548 }
549 /* Iterate over the group list and check which of them are already cached.
550 Those are simply copied to grouplist. The non-cached ones are collected
551 in sidp_buf for a later call to LsaLookupSids. */
552 sidp_buf = (PSID *) tp.w_get ();
553 scnt = 0;
554 for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
555 {
556 cygpsid sid = groups->Groups[pg].Sid;
557 if ((groups->Groups[pg].Attributes
558 & (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED)) == 0
559 || sid == well_known_world_sid)
560 continue;
561 if ((grp = internal_getgrsid_cachedonly (sid)))
562 {
563 if (cnt < gidsetsize)
564 grouplist[cnt] = grp->gr_gid;
565 ++cnt;
566 if (gidsetsize && cnt > gidsetsize)
567 {
568 cnt = -1;
569 goto out;
570 }
571 }
b74bc883 572 else
bef55bb5
CV
573 sidp_buf[scnt++] = sid;
574 }
4cb24051 575 /* If there are non-cached groups left, try to fetch them. */
bef55bb5
CV
576 if (scnt > 0)
577 {
4cb24051
CV
578 /* Don't call LsaLookupSids if we're not utilizing the Windows account
579 DBs. If we don't have access to the AD, which is one good reason to
580 disable passwd/group: db in nsswitch.conf, then the subsequent call
581 to LsaLookupSids will take 5 - 10 seconds in some environments. */
582 if (!cygheap->pg.nss_grp_db ())
583 {
584 for (DWORD pg = 0; pg < scnt; ++pg)
585 {
586 cygpsid sid = sidp_buf[pg];
587 if ((grp = internal_getgrsid (sid, NULL)))
588 {
589 if (cnt < gidsetsize)
590 grouplist[cnt] = grp->gr_gid;
591 ++cnt;
592 if (gidsetsize && cnt > gidsetsize)
593 {
594 cnt = -1;
595 break;
596 }
597 }
598 }
599 goto out;
600 }
601 /* Otherwise call LsaLookupSids and call internal_getgrfull on the
602 returned groups. This performs a lot better than calling
603 internal_getgrsid on each group. */
bef55bb5
CV
604 status = STATUS_ACCESS_DENIED;
605 HANDLE lsa = lsa_open_policy (NULL, POLICY_LOOKUP_NAMES);
606 if (!lsa)
607 {
4cb24051 608 debug_printf ("POLICY_LOOKUP_NAMES right not given?");
bef55bb5
CV
609 goto out;
610 }
611 status = LsaLookupSids (lsa, scnt, sidp_buf, &dlst, &nlst);
612 lsa_close_policy (lsa);
12eac211 613 if (NT_SUCCESS (status))
1ff9f4b9 614 {
bef55bb5 615 for (ULONG ncnt = 0; ncnt < scnt; ++ncnt)
1ca20a1c 616 {
71a897e4 617 static UNICODE_STRING empty = { 0, 0, (PWSTR) L"" };
ad8d295e 618 fetch_acc_t full_acc =
bef55bb5
CV
619 {
620 .sid = sidp_buf[ncnt],
621 .name = &nlst[ncnt].Name,
71a897e4 622 .dom = &empty,
bef55bb5
CV
623 .acc_type = nlst[ncnt].Use
624 };
71a897e4
CV
625
626 if (nlst[ncnt].DomainIndex >= 0)
627 full_acc.dom = &dlst->Domains[nlst[ncnt].DomainIndex].Name;
ad8d295e 628 if ((grp = internal_getgrfull (full_acc, pldap)))
1ca20a1c 629 {
9b54770b
CV
630 if (cnt < gidsetsize)
631 grouplist[cnt] = grp->gr_gid;
632 ++cnt;
633 if (gidsetsize && cnt > gidsetsize)
bef55bb5
CV
634 {
635 cnt = -1;
4cb24051 636 break;
bef55bb5 637 }
1ca20a1c
CV
638 }
639 }
1ff9f4b9 640 }
c4548fb4 641 }
4f2aac14 642
bef55bb5
CV
643out:
644 if (dlst)
645 LsaFreeMemory (dlst);
646 if (nlst)
647 LsaFreeMemory (nlst);
648 if (cnt == -1)
649 set_errno (EINVAL);
650 return cnt;
1fd5e000
CF
651}
652
6cc7c925 653extern "C" int
2d9b4876 654getgroups (int gidsetsize, gid_t *grouplist)
6cc7c925
CV
655{
656 cyg_ldap cldap;
657
658 return internal_getgroups (gidsetsize, grouplist, &cldap);
659}
660
0c1d8aaa 661/* Core functionality of initgroups and getgrouplist. */
ccd40e46 662static void
0c1d8aaa 663get_groups (const char *user, gid_t gid, cygsidlist &gsids)
57196405 664{
b39fa2c8
CV
665 cyg_ldap cldap;
666
a76877e9 667 cygheap->user.deimpersonate ();
b39fa2c8
CV
668 struct passwd *pw = internal_getpwnam (user, &cldap);
669 struct group *grp = internal_getgrgid (gid, &cldap);
a76877e9 670 cygsid usersid, grpsid;
ee6ed1db 671 if (usersid.getfrompw (pw))
02373d8b 672 get_server_groups (gsids, usersid, NO_CHK_DISABLED);
7f57a4ea 673 if (gid != ILLEGAL_GID && grpsid.getfromgr (grp))
ee6ed1db 674 gsids += grpsid;
a76877e9 675 cygheap->user.reimpersonate ();
1fd5e000
CF
676}
677
38c77307 678extern "C" int
2d9b4876 679initgroups (const char *user, gid_t gid)
0c1d8aaa 680{
0c1d8aaa
CV
681 assert (user != NULL);
682 cygsidlist tmp_gsids (cygsidlist_auto, 12);
ccd40e46
CV
683 get_groups (user, gid, tmp_gsids);
684 cygsidlist new_gsids (cygsidlist_alloc, tmp_gsids.count ());
685 for (int i = 0; i < tmp_gsids.count (); i++)
686 new_gsids.sids[i] = tmp_gsids.sids[i];
687 new_gsids.count (tmp_gsids.count ());
688 cygheap->user.groups.update_supp (new_gsids);
689 syscall_printf ( "0 = initgroups(%s, %u)", user, gid);
690 return 0;
0c1d8aaa
CV
691}
692
0c1d8aaa
CV
693extern "C" int
694getgrouplist (const char *user, gid_t gid, gid_t *groups, int *ngroups)
695{
ccd40e46
CV
696 int ret = 0;
697 int cnt = 0;
1ca20a1c 698 struct group *grp;
b39fa2c8 699 cyg_ldap cldap;
0c1d8aaa
CV
700
701 /* Note that it's not defined if groups or ngroups may be NULL!
702 GLibc does not check the pointers on entry and just uses them.
703 FreeBSD calls assert for ngroups and allows a NULL groups if
704 *ngroups is 0. We follow FreeBSD's lead here, but always allow
705 a NULL groups pointer. */
706 assert (user != NULL);
707 assert (ngroups != NULL);
708
709 cygsidlist tmp_gsids (cygsidlist_auto, 12);
ccd40e46
CV
710 get_groups (user, gid, tmp_gsids);
711 for (int i = 0; i < tmp_gsids.count (); i++)
b39fa2c8 712 if ((grp = internal_getgrsid (tmp_gsids.sids[i], &cldap)) != NULL)
ccd40e46
CV
713 {
714 if (groups && cnt < *ngroups)
1ca20a1c 715 groups[cnt] = grp->gr_gid;
ccd40e46
CV
716 ++cnt;
717 }
718 if (cnt > *ngroups)
719 ret = -1;
1e3a1509
CV
720 else
721 ret = cnt;
6681d11f 722 *ngroups = cnt;
ccd40e46 723
b9aa8149 724 syscall_printf ( "%d = getgrouplist(%s, %u, %p, %d)",
0c1d8aaa
CV
725 ret, user, gid, groups, *ngroups);
726 return ret;
1fd5e000 727}
5519d543 728
2d9b4876 729/* setgroups: standards? */
38c77307 730extern "C" int
2d9b4876 731setgroups (int ngroups, const gid_t *grouplist)
5519d543 732{
2d9b4876 733 syscall_printf ("setgroups (%d)", ngroups);
5519d543
CV
734 if (ngroups < 0 || (ngroups > 0 && !grouplist))
735 {
736 set_errno (EINVAL);
737 return -1;
738 }
739
5519d543 740 cygsidlist gsids (cygsidlist_alloc, ngroups);
1ca20a1c 741 struct group *grp;
b39fa2c8 742 cyg_ldap cldap;
5519d543
CV
743
744 if (ngroups && !gsids.sids)
745 return -1;
746
747 for (int gidx = 0; gidx < ngroups; ++gidx)
748 {
b39fa2c8 749 if ((grp = internal_getgrgid (grouplist[gidx], &cldap))
1ca20a1c 750 && gsids.addfromgr (grp))
b62b8d7c 751 continue;
61522196 752 debug_printf ("No sid found for gid %u", grouplist[gidx]);
5519d543
CV
753 gsids.free_sids ();
754 set_errno (EINVAL);
755 return -1;
5519d543
CV
756 }
757 cygheap->user.groups.update_supp (gsids);
758 return 0;
759}
This page took 0.634328 seconds and 6 git commands to generate.