Coverage Report

Created: 2025-07-23 07:04

/src/samba/nsswitch/libwbclient/wbc_pwd.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Winbind client API
5
6
   Copyright (C) Gerald (Jerry) Carter 2007
7
   Copyright (C) Matthew Newton 2015
8
9
10
   This library is free software; you can redistribute it and/or
11
   modify it under the terms of the GNU Lesser General Public
12
   License as published by the Free Software Foundation; either
13
   version 3 of the License, or (at your option) any later version.
14
15
   This library is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
   Library General Public License for more details.
19
20
   You should have received a copy of the GNU Lesser General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
/* Required Headers */
25
26
#include "replace.h"
27
#include "libwbclient.h"
28
#include "../winbind_client.h"
29
30
/** @brief The maximum number of pwent structs to get from winbindd
31
 *
32
 */
33
0
#define MAX_GETPWENT_USERS 500
34
35
/** @brief The maximum number of grent structs to get from winbindd
36
 *
37
 */
38
0
#define MAX_GETGRENT_GROUPS 500
39
40
/**
41
 *
42
 **/
43
44
static void wbcPasswdDestructor(void *ptr)
45
0
{
46
0
  struct passwd *pw = (struct passwd *)ptr;
47
0
  free(pw->pw_name);
48
0
  free(pw->pw_passwd);
49
0
  free(pw->pw_gecos);
50
0
  free(pw->pw_shell);
51
0
  free(pw->pw_dir);
52
0
}
53
54
static struct passwd *copy_passwd_entry(struct winbindd_pw *p)
55
0
{
56
0
  struct passwd *pw = NULL;
57
58
0
  pw = (struct passwd *)wbcAllocateMemory(1, sizeof(struct passwd),
59
0
            wbcPasswdDestructor);
60
0
  if (pw == NULL) {
61
0
    return NULL;
62
0
  }
63
0
  pw->pw_name = strdup(p->pw_name);
64
0
  if (pw->pw_name == NULL) {
65
0
    goto fail;
66
0
  }
67
0
  pw->pw_passwd = strdup(p->pw_passwd);
68
0
  if (pw->pw_passwd == NULL) {
69
0
    goto fail;
70
0
  }
71
0
  pw->pw_gecos = strdup(p->pw_gecos);
72
0
  if (pw->pw_gecos == NULL) {
73
0
    goto fail;
74
0
  }
75
0
  pw->pw_shell = strdup(p->pw_shell);
76
0
  if (pw->pw_shell == NULL) {
77
0
    goto fail;
78
0
  }
79
0
  pw->pw_dir = strdup(p->pw_dir);
80
0
  if (pw->pw_dir == NULL) {
81
0
    goto fail;
82
0
  }
83
0
  pw->pw_uid = p->pw_uid;
84
0
  pw->pw_gid = p->pw_gid;
85
0
  return pw;
86
87
0
fail:
88
0
  wbcFreeMemory(pw);
89
0
  return NULL;
90
0
}
91
92
/**
93
 *
94
 **/
95
96
static void wbcGroupDestructor(void *ptr)
97
0
{
98
0
  struct group *gr = (struct group *)ptr;
99
0
  int i;
100
101
0
  free(gr->gr_name);
102
0
  free(gr->gr_passwd);
103
104
  /* if the array was partly created this can be NULL */
105
0
  if (gr->gr_mem == NULL) {
106
0
    return;
107
0
  }
108
109
0
  for (i=0; gr->gr_mem[i] != NULL; i++) {
110
0
    free(gr->gr_mem[i]);
111
0
  }
112
0
  free(gr->gr_mem);
113
0
}
114
115
static struct group *copy_group_entry(struct winbindd_gr *g,
116
              char *mem_buf)
117
0
{
118
0
  struct group *gr = NULL;
119
0
  int i;
120
0
  char *mem_p, *mem_q;
121
122
0
  gr = (struct group *)wbcAllocateMemory(
123
0
    1, sizeof(struct group), wbcGroupDestructor);
124
0
  if (gr == NULL) {
125
0
    return NULL;
126
0
  }
127
128
0
  gr->gr_name = strdup(g->gr_name);
129
0
  if (gr->gr_name == NULL) {
130
0
    goto fail;
131
0
  }
132
0
  gr->gr_passwd = strdup(g->gr_passwd);
133
0
  if (gr->gr_passwd == NULL) {
134
0
    goto fail;
135
0
  }
136
0
  gr->gr_gid = g->gr_gid;
137
138
0
  gr->gr_mem = (char **)calloc(g->num_gr_mem+1, sizeof(char *));
139
0
  if (gr->gr_mem == NULL) {
140
0
    goto fail;
141
0
  }
142
143
0
  mem_p = mem_q = mem_buf;
144
0
  for (i=0; i<g->num_gr_mem && mem_p; i++) {
145
0
    mem_q = strchr(mem_p, ',');
146
0
    if (mem_q != NULL) {
147
0
      *mem_q = '\0';
148
0
    }
149
150
0
    gr->gr_mem[i] = strdup(mem_p);
151
0
    if (gr->gr_mem[i] == NULL) {
152
0
      goto fail;
153
0
    }
154
155
0
    if (mem_q == NULL) {
156
0
      i += 1;
157
0
      break;
158
0
    }
159
0
    mem_p = mem_q + 1;
160
0
  }
161
0
  gr->gr_mem[i] = NULL;
162
163
0
  return gr;
164
165
0
fail:
166
0
  wbcFreeMemory(gr);
167
0
  return NULL;
168
0
}
169
170
/* Fill in a struct passwd* for a domain user based on username */
171
_PUBLIC_
172
wbcErr wbcCtxGetpwnam(struct wbcContext *ctx,
173
          const char *name, struct passwd **pwd)
174
0
{
175
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
176
0
  struct winbindd_request request;
177
0
  struct winbindd_response response;
178
179
0
  if (!name || !pwd) {
180
0
    wbc_status = WBC_ERR_INVALID_PARAM;
181
0
    BAIL_ON_WBC_ERROR(wbc_status);
182
0
  }
183
184
  /* Initialize request */
185
186
0
  ZERO_STRUCT(request);
187
0
  ZERO_STRUCT(response);
188
189
  /* dst is already null terminated from the memset above */
190
191
0
  strncpy(request.data.username, name, sizeof(request.data.username)-1);
192
193
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWNAM,
194
0
          &request,
195
0
          &response);
196
0
  BAIL_ON_WBC_ERROR(wbc_status);
197
198
0
  *pwd = copy_passwd_entry(&response.data.pw);
199
0
  BAIL_ON_PTR_ERROR(*pwd, wbc_status);
200
201
0
 done:
202
0
  return wbc_status;
203
0
}
204
205
_PUBLIC_
206
wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
207
0
{
208
0
  return wbcCtxGetpwnam(NULL, name, pwd);
209
0
}
210
211
/* Fill in a struct passwd* for a domain user based on uid */
212
_PUBLIC_
213
wbcErr wbcCtxGetpwuid(struct wbcContext *ctx, uid_t uid, struct passwd **pwd)
214
0
{
215
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
216
0
  struct winbindd_request request;
217
0
  struct winbindd_response response;
218
219
0
  if (!pwd) {
220
0
    wbc_status = WBC_ERR_INVALID_PARAM;
221
0
    BAIL_ON_WBC_ERROR(wbc_status);
222
0
  }
223
224
  /* Initialize request */
225
226
0
  ZERO_STRUCT(request);
227
0
  ZERO_STRUCT(response);
228
229
0
  request.data.uid = uid;
230
231
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWUID,
232
0
          &request,
233
0
          &response);
234
0
  BAIL_ON_WBC_ERROR(wbc_status);
235
236
0
  *pwd = copy_passwd_entry(&response.data.pw);
237
0
  BAIL_ON_PTR_ERROR(*pwd, wbc_status);
238
239
0
 done:
240
0
  return wbc_status;
241
0
}
242
243
_PUBLIC_
244
wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
245
0
{
246
0
  return wbcCtxGetpwuid(NULL, uid, pwd);
247
0
}
248
249
/* Fill in a struct passwd* for a domain user based on sid */
250
_PUBLIC_
251
wbcErr wbcCtxGetpwsid(struct wbcContext *ctx,
252
          struct wbcDomainSid *sid, struct passwd **pwd)
253
0
{
254
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
255
0
  struct winbindd_request request;
256
0
  struct winbindd_response response;
257
258
0
  if (!pwd) {
259
0
    wbc_status = WBC_ERR_INVALID_PARAM;
260
0
    BAIL_ON_WBC_ERROR(wbc_status);
261
0
  }
262
263
  /* Initialize request */
264
265
0
  ZERO_STRUCT(request);
266
0
  ZERO_STRUCT(response);
267
268
0
        wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
269
270
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWSID,
271
0
          &request,
272
0
          &response);
273
0
  BAIL_ON_WBC_ERROR(wbc_status);
274
275
0
  *pwd = copy_passwd_entry(&response.data.pw);
276
0
  BAIL_ON_PTR_ERROR(*pwd, wbc_status);
277
278
0
 done:
279
0
  return wbc_status;
280
0
}
281
282
_PUBLIC_
283
wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd)
284
0
{
285
0
  return wbcCtxGetpwsid(NULL, sid, pwd);
286
0
}
287
288
/* Fill in a struct passwd* for a domain user based on username */
289
_PUBLIC_
290
wbcErr wbcCtxGetgrnam(struct wbcContext *ctx,
291
          const char *name, struct group **grp)
292
0
{
293
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
294
0
  struct winbindd_request request;
295
0
  struct winbindd_response response;
296
297
  /* Initialize request */
298
299
0
  ZERO_STRUCT(request);
300
0
  ZERO_STRUCT(response);
301
302
0
  if (!name || !grp) {
303
0
    wbc_status = WBC_ERR_INVALID_PARAM;
304
0
    BAIL_ON_WBC_ERROR(wbc_status);
305
0
  }
306
307
  /* dst is already null terminated from the memset above */
308
309
0
  strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1);
310
311
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRNAM,
312
0
          &request,
313
0
          &response);
314
0
  BAIL_ON_WBC_ERROR(wbc_status);
315
316
0
  *grp = copy_group_entry(&response.data.gr,
317
0
        (char*)response.extra_data.data);
318
0
  BAIL_ON_PTR_ERROR(*grp, wbc_status);
319
320
0
 done:
321
0
  winbindd_free_response(&response);
322
323
0
  return wbc_status;
324
0
}
325
326
_PUBLIC_
327
wbcErr wbcGetgrnam(const char *name, struct group **grp)
328
0
{
329
0
  return wbcCtxGetgrnam(NULL, name, grp);
330
0
}
331
332
/* Fill in a struct passwd* for a domain user based on uid */
333
_PUBLIC_
334
wbcErr wbcCtxGetgrgid(struct wbcContext *ctx, gid_t gid, struct group **grp)
335
0
{
336
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
337
0
  struct winbindd_request request;
338
0
  struct winbindd_response response;
339
340
  /* Initialize request */
341
342
0
  ZERO_STRUCT(request);
343
0
  ZERO_STRUCT(response);
344
345
0
  if (!grp) {
346
0
    wbc_status = WBC_ERR_INVALID_PARAM;
347
0
    BAIL_ON_WBC_ERROR(wbc_status);
348
0
  }
349
350
0
  request.data.gid = gid;
351
352
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRGID,
353
0
          &request,
354
0
          &response);
355
0
  BAIL_ON_WBC_ERROR(wbc_status);
356
357
0
  *grp = copy_group_entry(&response.data.gr,
358
0
        (char*)response.extra_data.data);
359
0
  BAIL_ON_PTR_ERROR(*grp, wbc_status);
360
361
0
 done:
362
0
  winbindd_free_response(&response);
363
364
0
  return wbc_status;
365
0
}
366
367
_PUBLIC_
368
wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
369
0
{
370
0
  return wbcCtxGetgrgid(NULL, gid, grp);
371
0
}
372
373
/** @brief Winbindd response containing the passwd structs
374
 *
375
 */
376
static struct winbindd_response pw_response;
377
378
/* Reset the passwd iterator */
379
_PUBLIC_
380
wbcErr wbcCtxSetpwent(struct wbcContext *ctx)
381
0
{
382
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
383
384
0
  if (!ctx) {
385
0
    ctx = wbcGetGlobalCtx();
386
0
  }
387
388
0
  if (ctx->pw_cache_size > 0) {
389
0
    ctx->pw_cache_idx = ctx->pw_cache_size = 0;
390
0
    winbindd_free_response(&pw_response);
391
0
  }
392
393
0
  ZERO_STRUCT(pw_response);
394
395
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_SETPWENT,
396
0
          NULL, NULL);
397
0
  BAIL_ON_WBC_ERROR(wbc_status);
398
399
0
 done:
400
0
  return wbc_status;
401
0
}
402
403
_PUBLIC_
404
wbcErr wbcSetpwent(void)
405
0
{
406
0
  return wbcCtxSetpwent(NULL);
407
0
}
408
409
/* Close the passwd iterator */
410
_PUBLIC_
411
wbcErr wbcCtxEndpwent(struct wbcContext *ctx)
412
0
{
413
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
414
415
0
  if (!ctx) {
416
0
    ctx = wbcGetGlobalCtx();
417
0
  }
418
419
0
  if (ctx->pw_cache_size > 0) {
420
0
    ctx->pw_cache_idx = ctx->pw_cache_size = 0;
421
0
    winbindd_free_response(&pw_response);
422
0
  }
423
424
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDPWENT,
425
0
          NULL, NULL);
426
0
  BAIL_ON_WBC_ERROR(wbc_status);
427
428
0
 done:
429
0
  return wbc_status;
430
0
}
431
432
_PUBLIC_
433
wbcErr wbcEndpwent(void)
434
0
{
435
0
  return wbcCtxEndpwent(NULL);
436
0
}
437
438
/* Return the next struct passwd* entry from the pwent iterator */
439
_PUBLIC_
440
wbcErr wbcCtxGetpwent(struct wbcContext *ctx, struct passwd **pwd)
441
0
{
442
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
443
0
  struct winbindd_request request;
444
0
  struct winbindd_pw *wb_pw;
445
446
0
  if (!ctx) {
447
0
    ctx = wbcGetGlobalCtx();
448
0
  }
449
450
  /* If there's a cached result, return that. */
451
0
  if (ctx->pw_cache_idx < ctx->pw_cache_size) {
452
0
    goto return_result;
453
0
  }
454
455
  /* Otherwise, query winbindd for some entries. */
456
457
0
  ctx->pw_cache_idx = 0;
458
459
0
  winbindd_free_response(&pw_response);
460
461
0
  ZERO_STRUCT(request);
462
0
  request.data.num_entries = MAX_GETPWENT_USERS;
463
464
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWENT, &request,
465
0
          &pw_response);
466
467
0
  BAIL_ON_WBC_ERROR(wbc_status);
468
469
0
  ctx->pw_cache_size = pw_response.data.num_entries;
470
471
0
return_result:
472
473
0
  wb_pw = (struct winbindd_pw *) pw_response.extra_data.data;
474
475
0
  *pwd = copy_passwd_entry(&wb_pw[ctx->pw_cache_idx]);
476
477
0
  BAIL_ON_PTR_ERROR(*pwd, wbc_status);
478
479
0
  ctx->pw_cache_idx++;
480
481
0
done:
482
0
  return wbc_status;
483
0
}
484
485
_PUBLIC_
486
wbcErr wbcGetpwent(struct passwd **pwd)
487
0
{
488
0
  return wbcCtxGetpwent(NULL, pwd);
489
0
}
490
491
/** @brief Winbindd response containing the group structs
492
 *
493
 */
494
static struct winbindd_response gr_response;
495
496
/* Reset the group iterator */
497
_PUBLIC_
498
wbcErr wbcCtxSetgrent(struct wbcContext *ctx)
499
0
{
500
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
501
502
0
  if (!ctx) {
503
0
    ctx = wbcGetGlobalCtx();
504
0
  }
505
506
0
  if (ctx->gr_cache_size > 0) {
507
0
    ctx->gr_cache_idx = ctx->gr_cache_size = 0;
508
0
    winbindd_free_response(&gr_response);
509
0
  }
510
511
0
  ZERO_STRUCT(gr_response);
512
513
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_SETGRENT,
514
0
          NULL, NULL);
515
0
  BAIL_ON_WBC_ERROR(wbc_status);
516
517
0
 done:
518
0
  return wbc_status;
519
0
}
520
521
_PUBLIC_
522
wbcErr wbcSetgrent(void)
523
0
{
524
0
  return wbcCtxSetgrent(NULL);
525
0
}
526
527
/* Close the group iterator */
528
_PUBLIC_
529
wbcErr wbcCtxEndgrent(struct wbcContext *ctx)
530
0
{
531
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
532
533
0
  if (!ctx) {
534
0
    ctx = wbcGetGlobalCtx();
535
0
  }
536
537
0
  if (ctx->gr_cache_size > 0) {
538
0
    ctx->gr_cache_idx = ctx->gr_cache_size = 0;
539
0
    winbindd_free_response(&gr_response);
540
0
  }
541
542
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDGRENT,
543
0
          NULL, NULL);
544
0
  BAIL_ON_WBC_ERROR(wbc_status);
545
546
0
 done:
547
0
  return wbc_status;
548
0
}
549
550
_PUBLIC_
551
wbcErr wbcEndgrent(void)
552
0
{
553
0
  return wbcCtxEndgrent(NULL);
554
0
}
555
556
/* Return the next struct group* entry from the pwent iterator */
557
_PUBLIC_
558
wbcErr wbcCtxGetgrent(struct wbcContext *ctx, struct group **grp)
559
0
{
560
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
561
0
  struct winbindd_request request;
562
0
  struct winbindd_gr *wb_gr;
563
0
  uint32_t mem_ofs;
564
565
0
  if (!ctx) {
566
0
    ctx = wbcGetGlobalCtx();
567
0
  }
568
569
  /* If there's a cached result, return that. */
570
0
  if (ctx->gr_cache_idx < ctx->gr_cache_size) {
571
0
    goto return_result;
572
0
  }
573
574
  /* Otherwise, query winbindd for some entries. */
575
576
0
  ctx->gr_cache_idx = 0;
577
578
0
  winbindd_free_response(&gr_response);
579
580
0
  ZERO_STRUCT(request);
581
0
  request.data.num_entries = MAX_GETGRENT_GROUPS;
582
583
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRENT,
584
0
          &request, &gr_response);
585
586
0
  BAIL_ON_WBC_ERROR(wbc_status);
587
588
0
  ctx->gr_cache_size = gr_response.data.num_entries;
589
590
0
return_result:
591
592
0
  wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
593
594
0
  mem_ofs = wb_gr[ctx->gr_cache_idx].gr_mem_ofs +
595
0
      ctx->gr_cache_size * sizeof(struct winbindd_gr);
596
597
0
  *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx],
598
0
        ((char *)gr_response.extra_data.data)+mem_ofs);
599
600
0
  BAIL_ON_PTR_ERROR(*grp, wbc_status);
601
602
0
  ctx->gr_cache_idx++;
603
604
0
done:
605
0
  return wbc_status;
606
0
}
607
608
_PUBLIC_
609
wbcErr wbcGetgrent(struct group **grp)
610
0
{
611
0
  return wbcCtxGetgrent(NULL, grp);
612
0
}
613
614
/* Return the next struct group* entry from the pwent iterator */
615
_PUBLIC_
616
wbcErr wbcCtxGetgrlist(struct wbcContext *ctx, struct group **grp)
617
0
{
618
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
619
0
  struct winbindd_request request;
620
0
  struct winbindd_gr *wb_gr;
621
622
0
  if (!ctx) {
623
0
    ctx = wbcGetGlobalCtx();
624
0
  }
625
626
  /* If there's a cached result, return that. */
627
0
  if (ctx->gr_cache_idx < ctx->gr_cache_size) {
628
0
    goto return_result;
629
0
  }
630
631
  /* Otherwise, query winbindd for some entries. */
632
633
0
  ctx->gr_cache_idx = 0;
634
635
0
  winbindd_free_response(&gr_response);
636
0
  ZERO_STRUCT(gr_response);
637
638
0
  ZERO_STRUCT(request);
639
0
  request.data.num_entries = MAX_GETGRENT_GROUPS;
640
641
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRLST,
642
0
          &request, &gr_response);
643
644
0
  BAIL_ON_WBC_ERROR(wbc_status);
645
646
0
  ctx->gr_cache_size = gr_response.data.num_entries;
647
648
0
return_result:
649
650
0
  wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
651
652
0
  *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx], NULL);
653
654
0
  BAIL_ON_PTR_ERROR(*grp, wbc_status);
655
656
0
  ctx->gr_cache_idx++;
657
658
0
done:
659
0
  return wbc_status;
660
0
}
661
662
_PUBLIC_
663
wbcErr wbcGetgrlist(struct group **grp)
664
0
{
665
0
  return wbcCtxGetgrlist(NULL, grp);
666
0
}
667
668
/* Return the unix group array belonging to the given user */
669
_PUBLIC_
670
wbcErr wbcCtxGetGroups(struct wbcContext *ctx, const char *account,
671
           uint32_t *num_groups, gid_t **_groups)
672
0
{
673
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
674
0
  struct winbindd_request request;
675
0
  struct winbindd_response response;
676
0
  uint32_t i;
677
0
  gid_t *groups = NULL;
678
679
  /* Initialize request */
680
681
0
  ZERO_STRUCT(request);
682
0
  ZERO_STRUCT(response);
683
684
0
  if (!account) {
685
0
    wbc_status = WBC_ERR_INVALID_PARAM;
686
0
    BAIL_ON_WBC_ERROR(wbc_status);
687
0
  }
688
689
  /* Send request */
690
691
0
  strncpy(request.data.username, account, sizeof(request.data.username)-1);
692
693
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGROUPS,
694
0
          &request,
695
0
          &response);
696
0
  BAIL_ON_WBC_ERROR(wbc_status);
697
698
0
  groups = (gid_t *)wbcAllocateMemory(
699
0
    response.data.num_entries, sizeof(gid_t), NULL);
700
0
  BAIL_ON_PTR_ERROR(groups, wbc_status);
701
702
0
  for (i = 0; i < response.data.num_entries; i++) {
703
0
    groups[i] = ((gid_t *)response.extra_data.data)[i];
704
0
  }
705
706
0
  *num_groups = response.data.num_entries;
707
0
  *_groups = groups;
708
0
  groups = NULL;
709
710
0
  wbc_status = WBC_ERR_SUCCESS;
711
712
0
 done:
713
0
  winbindd_free_response(&response);
714
0
  wbcFreeMemory(groups);
715
0
  return wbc_status;
716
0
}
717
718
_PUBLIC_
719
wbcErr wbcGetGroups(const char *account, uint32_t *num_groups, gid_t **_groups)
720
0
{
721
0
  return wbcCtxGetGroups(NULL, account, num_groups, _groups);
722
0
}