Coverage Report

Created: 2025-07-23 07:04

/src/samba/nsswitch/libwbclient/wbc_sid.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) Volker Lendecke 2010
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
#include "lib/util/smb_strtox.h"
30
31
/* Convert a sid to a string into a buffer. Return the string
32
 * length. If buflen is too small, return the string length that would
33
 * result if it was long enough. */
34
_PUBLIC_
35
int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen)
36
0
{
37
0
  uint64_t id_auth;
38
0
  int i, ofs;
39
40
0
  if (!sid) {
41
0
    strlcpy(buf, "(NULL SID)", buflen);
42
0
    return 10;  /* strlen("(NULL SID)") */
43
0
  }
44
45
0
  id_auth = (uint64_t)sid->id_auth[5] +
46
0
    ((uint64_t)sid->id_auth[4] << 8) +
47
0
    ((uint64_t)sid->id_auth[3] << 16) +
48
0
    ((uint64_t)sid->id_auth[2] << 24) +
49
0
    ((uint64_t)sid->id_auth[1] << 32) +
50
0
    ((uint64_t)sid->id_auth[0] << 40);
51
52
0
  ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
53
0
  if (id_auth >= UINT32_MAX) {
54
0
    ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "0x%llx",
55
0
        (unsigned long long)id_auth);
56
0
  } else {
57
0
    ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
58
0
        (unsigned long long)id_auth);
59
0
  }
60
61
0
  for (i = 0; i < sid->num_auths; i++) {
62
0
    ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
63
0
        (unsigned int)sid->sub_auths[i]);
64
0
  }
65
0
  return ofs;
66
0
}
67
68
/* Convert a binary SID to a character string */
69
_PUBLIC_
70
wbcErr wbcSidToString(const struct wbcDomainSid *sid,
71
          char **sid_string)
72
0
{
73
0
  char buf[WBC_SID_STRING_BUFLEN];
74
0
  char *result;
75
0
  int len;
76
77
0
  if (!sid) {
78
0
    return WBC_ERR_INVALID_SID;
79
0
  }
80
81
0
  len = wbcSidToStringBuf(sid, buf, sizeof(buf));
82
83
0
  if (len >= WBC_SID_STRING_BUFLEN) {
84
0
    return WBC_ERR_INVALID_SID;
85
0
  }
86
87
0
  result = (char *)wbcAllocateMemory(len+1, 1, NULL);
88
0
  if (result == NULL) {
89
0
    return WBC_ERR_NO_MEMORY;
90
0
  }
91
0
  memcpy(result, buf, len+1);
92
93
0
  *sid_string = result;
94
0
  return WBC_ERR_SUCCESS;
95
0
}
96
97
0
#define AUTHORITY_MASK  (~(0xffffffffffffULL))
98
99
/* Convert a character string to a binary SID */
100
_PUBLIC_
101
wbcErr wbcStringToSid(const char *str,
102
          struct wbcDomainSid *sid)
103
0
{
104
0
  const char *p;
105
0
  char *q;
106
0
  int error = 0;
107
0
  uint64_t x;
108
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
109
110
0
  if (!sid) {
111
0
    wbc_status = WBC_ERR_INVALID_PARAM;
112
0
    BAIL_ON_WBC_ERROR(wbc_status);
113
0
  }
114
115
  /* Sanity check for either "S-" or "s-" */
116
117
0
  if (!str
118
0
      || (str[0]!='S' && str[0]!='s')
119
0
      || (str[1]!='-'))
120
0
  {
121
0
    wbc_status = WBC_ERR_INVALID_PARAM;
122
0
    BAIL_ON_WBC_ERROR(wbc_status);
123
0
  }
124
125
  /* Get the SID revision number */
126
127
0
  p = str+2;
128
0
  x = (uint64_t)smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
129
0
  if (x == 0 || x > UINT8_MAX || !q || *q != '-' || error != 0) {
130
0
    wbc_status = WBC_ERR_INVALID_SID;
131
0
    BAIL_ON_WBC_ERROR(wbc_status);
132
0
  }
133
0
  sid->sid_rev_num = (uint8_t)x;
134
135
  /*
136
   * Next the Identifier Authority.  This is stored big-endian in a
137
   * 6 byte array. If the authority value is >= UINT_MAX, then it should
138
   * be expressed as a hex value, according to MS-DTYP.
139
   */
140
0
  p = q+1;
141
0
  x = smb_strtoull(p, &q, 0, &error, SMB_STR_STANDARD);
142
0
  if (!q || *q != '-' || (x & AUTHORITY_MASK) || error != 0) {
143
0
    wbc_status = WBC_ERR_INVALID_SID;
144
0
    BAIL_ON_WBC_ERROR(wbc_status);
145
0
  }
146
0
  sid->id_auth[5] = (x & 0x0000000000ffULL);
147
0
  sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
148
0
  sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
149
0
  sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
150
0
  sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
151
0
  sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
152
153
  /* now read the subauthorities */
154
0
  p = q +1;
155
0
  sid->num_auths = 0;
156
0
  while (sid->num_auths < WBC_MAXSUBAUTHS) {
157
0
    x = smb_strtoull(p, &q, 10, &error, SMB_STR_ALLOW_NO_CONVERSION);
158
0
    if (p == q)
159
0
      break;
160
0
    if (x > UINT32_MAX || error != 0) {
161
0
      wbc_status = WBC_ERR_INVALID_SID;
162
0
      BAIL_ON_WBC_ERROR(wbc_status);
163
0
    }
164
0
    sid->sub_auths[sid->num_auths++] = x;
165
166
0
    if (*q != '-') {
167
0
      break;
168
0
    }
169
0
    p = q + 1;
170
0
  }
171
172
  /* IF we ended early, then the SID could not be converted */
173
174
0
  if (q && *q!='\0') {
175
0
    wbc_status = WBC_ERR_INVALID_SID;
176
0
    BAIL_ON_WBC_ERROR(wbc_status);
177
0
  }
178
179
0
  wbc_status = WBC_ERR_SUCCESS;
180
181
0
done:
182
0
  return wbc_status;
183
184
0
}
185
186
187
/* Convert a domain and name to SID */
188
_PUBLIC_
189
wbcErr wbcCtxLookupName(struct wbcContext *ctx,
190
      const char *domain,
191
      const char *name,
192
      struct wbcDomainSid *sid,
193
      enum wbcSidType *name_type)
194
0
{
195
0
  struct winbindd_request request;
196
0
  struct winbindd_response response;
197
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
198
199
0
  if (!sid || !name_type) {
200
0
    wbc_status = WBC_ERR_INVALID_PARAM;
201
0
    BAIL_ON_WBC_ERROR(wbc_status);
202
0
  }
203
204
  /* Initialize request */
205
206
0
  ZERO_STRUCT(request);
207
0
  ZERO_STRUCT(response);
208
209
  /* dst is already null terminated from the memset above */
210
211
0
  strncpy(request.data.name.dom_name, domain,
212
0
    sizeof(request.data.name.dom_name)-1);
213
0
  strncpy(request.data.name.name, name,
214
0
    sizeof(request.data.name.name)-1);
215
216
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
217
0
          &request,
218
0
          &response);
219
0
  BAIL_ON_WBC_ERROR(wbc_status);
220
221
0
  *name_type = (enum wbcSidType)response.data.sid.type;
222
0
  if (*name_type == WBC_SID_NAME_UNKNOWN) {
223
0
    return WBC_ERR_NOT_MAPPED;
224
0
  }
225
226
0
  wbc_status = wbcStringToSid(response.data.sid.sid, sid);
227
0
  BAIL_ON_WBC_ERROR(wbc_status);
228
229
0
  wbc_status = WBC_ERR_SUCCESS;
230
231
0
 done:
232
0
  return wbc_status;
233
0
}
234
235
_PUBLIC_
236
wbcErr wbcLookupName(const char *domain,
237
         const char *name,
238
         struct wbcDomainSid *sid,
239
         enum wbcSidType *name_type)
240
0
{
241
0
  return wbcCtxLookupName(NULL, domain, name, sid, name_type);
242
0
}
243
244
245
/* Convert a SID to a domain and name */
246
_PUBLIC_
247
wbcErr wbcCtxLookupSid(struct wbcContext *ctx,
248
           const struct wbcDomainSid *sid,
249
           char **pdomain,
250
           char **pname,
251
           enum wbcSidType *pname_type)
252
0
{
253
0
  struct winbindd_request request;
254
0
  struct winbindd_response response;
255
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
256
0
  char *domain, *name;
257
258
0
  if (!sid) {
259
0
    return WBC_ERR_INVALID_PARAM;
260
0
  }
261
262
  /* Initialize request */
263
264
0
  ZERO_STRUCT(request);
265
0
  ZERO_STRUCT(response);
266
267
0
  wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
268
269
  /* Make request */
270
271
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSID,
272
0
          &request,
273
0
          &response);
274
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
275
0
    return wbc_status;
276
0
  }
277
278
  /* Copy out result */
279
280
0
  wbc_status = WBC_ERR_NO_MEMORY;
281
0
  domain = NULL;
282
0
  name = NULL;
283
284
0
  domain = wbcStrDup(response.data.name.dom_name);
285
0
  if (domain == NULL) {
286
0
    goto done;
287
0
  }
288
0
  name = wbcStrDup(response.data.name.name);
289
0
  if (name == NULL) {
290
0
    goto done;
291
0
  }
292
0
  if (pdomain != NULL) {
293
0
    *pdomain = domain;
294
0
    domain = NULL;
295
0
  }
296
0
  if (pname != NULL) {
297
0
    *pname = name;
298
0
    name = NULL;
299
0
  }
300
0
  if (pname_type != NULL) {
301
0
    *pname_type = (enum wbcSidType)response.data.name.type;
302
0
  }
303
0
  wbc_status = WBC_ERR_SUCCESS;
304
0
done:
305
0
  wbcFreeMemory(name);
306
0
  wbcFreeMemory(domain);
307
0
  return wbc_status;
308
0
}
309
310
_PUBLIC_
311
wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
312
        char **pdomain,
313
        char **pname,
314
        enum wbcSidType *pname_type)
315
0
{
316
0
  return wbcCtxLookupSid(NULL, sid, pdomain, pname, pname_type);
317
0
}
318
319
static void wbcDomainInfosDestructor(void *ptr)
320
0
{
321
0
  struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
322
323
0
  while (i->short_name != NULL) {
324
0
    wbcFreeMemory(i->short_name);
325
0
    wbcFreeMemory(i->dns_name);
326
0
    i += 1;
327
0
  }
328
0
}
329
330
static void wbcTranslatedNamesDestructor(void *ptr)
331
0
{
332
0
  struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr;
333
334
0
  while (n->name != NULL) {
335
0
    wbcFreeMemory(n->name);
336
0
    n += 1;
337
0
  }
338
0
}
339
340
_PUBLIC_
341
wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
342
      const struct wbcDomainSid *sids, int num_sids,
343
      struct wbcDomainInfo **pdomains, int *pnum_domains,
344
      struct wbcTranslatedName **pnames)
345
0
{
346
0
  struct winbindd_request request;
347
0
  struct winbindd_response response;
348
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
349
0
  int buflen, i, extra_len, num_domains, num_names;
350
0
  char *sidlist, *p, *q, *extra_data;
351
0
  struct wbcDomainInfo *domains = NULL;
352
0
  struct wbcTranslatedName *names = NULL;
353
0
  int error = 0;
354
355
0
  buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
356
357
0
  sidlist = (char *)malloc(buflen);
358
0
  if (sidlist == NULL) {
359
0
    return WBC_ERR_NO_MEMORY;
360
0
  }
361
362
0
  p = sidlist;
363
364
0
  for (i=0; i<num_sids; i++) {
365
0
    int remaining;
366
0
    int len;
367
368
0
    remaining = buflen - (p - sidlist);
369
370
0
    len = wbcSidToStringBuf(&sids[i], p, remaining);
371
0
    if (len > remaining) {
372
0
      free(sidlist);
373
0
      return WBC_ERR_UNKNOWN_FAILURE;
374
0
    }
375
376
0
    p += len;
377
0
    *p++ = '\n';
378
0
  }
379
0
  *p++ = '\0';
380
381
0
  ZERO_STRUCT(request);
382
0
  ZERO_STRUCT(response);
383
384
0
  request.extra_data.data = sidlist;
385
0
  request.extra_len = p - sidlist;
386
387
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSIDS,
388
0
          &request, &response);
389
0
  free(sidlist);
390
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
391
0
    return wbc_status;
392
0
  }
393
394
0
  extra_len = response.length - sizeof(struct winbindd_response);
395
0
  extra_data = (char *)response.extra_data.data;
396
397
0
  if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
398
0
    goto wbc_err_invalid;
399
0
  }
400
401
0
  p = extra_data;
402
403
0
  num_domains = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
404
0
  if (*q != '\n' || error != 0) {
405
0
    goto wbc_err_invalid;
406
0
  }
407
0
  p = q+1;
408
409
0
  domains = (struct wbcDomainInfo *)wbcAllocateMemory(
410
0
    num_domains+1, sizeof(struct wbcDomainInfo),
411
0
    wbcDomainInfosDestructor);
412
0
  if (domains == NULL) {
413
0
    wbc_status = WBC_ERR_NO_MEMORY;
414
0
    goto fail;
415
0
  }
416
417
0
  for (i=0; i<num_domains; i++) {
418
419
0
    q = strchr(p, ' ');
420
0
    if (q == NULL) {
421
0
      goto wbc_err_invalid;
422
0
    }
423
0
    *q = '\0';
424
0
    wbc_status = wbcStringToSid(p, &domains[i].sid);
425
0
    if (!WBC_ERROR_IS_OK(wbc_status)) {
426
0
      goto fail;
427
0
    }
428
0
    p = q+1;
429
430
0
    q = strchr(p, '\n');
431
0
    if (q == NULL) {
432
0
      goto wbc_err_invalid;
433
0
    }
434
0
    *q = '\0';
435
0
    domains[i].short_name = wbcStrDup(p);
436
0
    if (domains[i].short_name == NULL) {
437
0
      wbc_status = WBC_ERR_NO_MEMORY;
438
0
      goto fail;
439
0
    }
440
0
    p = q+1;
441
0
  }
442
443
0
  num_names = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
444
0
  if (*q != '\n' || error != 0) {
445
0
    goto wbc_err_invalid;
446
0
  }
447
0
  p = q+1;
448
449
0
  if (num_names != num_sids) {
450
0
    goto wbc_err_invalid;
451
0
  }
452
453
0
  names = (struct wbcTranslatedName *)wbcAllocateMemory(
454
0
    num_names+1, sizeof(struct wbcTranslatedName),
455
0
    wbcTranslatedNamesDestructor);
456
0
  if (names == NULL) {
457
0
    wbc_status = WBC_ERR_NO_MEMORY;
458
0
    goto fail;
459
0
  }
460
461
0
  for (i=0; i<num_names; i++) {
462
463
0
    names[i].domain_index = smb_strtoul(p,
464
0
                &q,
465
0
                10,
466
0
                &error,
467
0
                SMB_STR_STANDARD);
468
0
    if (names[i].domain_index < 0 || error != 0) {
469
0
      goto wbc_err_invalid;
470
0
    }
471
0
    if (names[i].domain_index >= num_domains) {
472
0
      goto wbc_err_invalid;
473
0
    }
474
475
0
    if (*q != ' ') {
476
0
      goto wbc_err_invalid;
477
0
    }
478
0
    p = q+1;
479
480
0
    names[i].type = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
481
0
    if (*q != ' ' || error != 0) {
482
0
      goto wbc_err_invalid;
483
0
    }
484
0
    p = q+1;
485
486
0
    q = strchr(p, '\n');
487
0
    if (q == NULL) {
488
0
      goto wbc_err_invalid;
489
0
    }
490
0
    *q = '\0';
491
0
    names[i].name = wbcStrDup(p);
492
0
    if (names[i].name == NULL) {
493
0
      wbc_status = WBC_ERR_NO_MEMORY;
494
0
      goto fail;
495
0
    }
496
0
    p = q+1;
497
0
  }
498
0
  if (*p != '\0') {
499
0
    goto wbc_err_invalid;
500
0
  }
501
502
0
  *pdomains = domains;
503
0
  *pnames = names;
504
0
  winbindd_free_response(&response);
505
0
  return WBC_ERR_SUCCESS;
506
507
0
wbc_err_invalid:
508
0
  wbc_status = WBC_ERR_INVALID_RESPONSE;
509
0
fail:
510
0
  winbindd_free_response(&response);
511
0
  wbcFreeMemory(domains);
512
0
  wbcFreeMemory(names);
513
0
  return wbc_status;
514
0
}
515
516
_PUBLIC_
517
wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
518
         struct wbcDomainInfo **pdomains, int *pnum_domains,
519
         struct wbcTranslatedName **pnames)
520
0
{
521
0
  return wbcCtxLookupSids(NULL, sids, num_sids, pdomains,
522
0
        pnum_domains, pnames);
523
0
}
524
525
/* Translate a collection of RIDs within a domain to names */
526
527
_PUBLIC_
528
wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
529
         int num_rids,
530
         uint32_t *rids,
531
         const char **pp_domain_name,
532
         const char ***pnames,
533
         enum wbcSidType **ptypes)
534
0
{
535
0
  int i;
536
0
  size_t  len, ridbuf_size;
537
0
  char *ridlist;
538
0
  char *p;
539
0
  int error = 0;
540
0
  struct winbindd_request request;
541
0
  struct winbindd_response response;
542
0
  char *domain_name = NULL;
543
0
  const char **names = NULL;
544
0
  enum wbcSidType *types = NULL;
545
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
546
547
  /* Initialise request */
548
549
0
  ZERO_STRUCT(request);
550
0
  ZERO_STRUCT(response);
551
552
0
  if (!dom_sid || (num_rids == 0)) {
553
0
    wbc_status = WBC_ERR_INVALID_PARAM;
554
0
    BAIL_ON_WBC_ERROR(wbc_status);
555
0
  }
556
557
0
  wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
558
559
  /* Even if all the Rids were of maximum 32bit values,
560
     we would only have 11 bytes per rid in the final array
561
     ("4294967296" + \n).  Add one more byte for the
562
     terminating '\0' */
563
564
0
  ridbuf_size = (sizeof(char)*11) * num_rids + 1;
565
566
0
  ridlist = (char *)malloc(ridbuf_size);
567
0
  BAIL_ON_PTR_ERROR(ridlist, wbc_status);
568
569
0
  len = 0;
570
0
  for (i=0; i<num_rids; i++) {
571
0
    len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
572
0
        rids[i]);
573
0
  }
574
0
  ridlist[len] = '\0';
575
0
  len += 1;
576
577
0
  request.extra_data.data = ridlist;
578
0
  request.extra_len = len;
579
580
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
581
0
          &request,
582
0
          &response);
583
0
  free(ridlist);
584
0
  BAIL_ON_WBC_ERROR(wbc_status);
585
586
0
  domain_name = wbcStrDup(response.data.domain_name);
587
0
  BAIL_ON_PTR_ERROR(domain_name, wbc_status);
588
589
0
  names = wbcAllocateStringArray(num_rids);
590
0
  BAIL_ON_PTR_ERROR(names, wbc_status);
591
592
0
  types = (enum wbcSidType *)wbcAllocateMemory(
593
0
    num_rids, sizeof(enum wbcSidType), NULL);
594
0
  BAIL_ON_PTR_ERROR(types, wbc_status);
595
596
0
  p = (char *)response.extra_data.data;
597
598
0
  for (i=0; i<num_rids; i++) {
599
0
    char *q;
600
601
0
    if (*p == '\0') {
602
0
      wbc_status = WBC_ERR_INVALID_RESPONSE;
603
0
      goto done;
604
0
    }
605
606
0
    types[i] = (enum wbcSidType)smb_strtoul(p,
607
0
              &q,
608
0
              10,
609
0
              &error,
610
0
              SMB_STR_STANDARD);
611
612
0
    if (*q != ' ' || error != 0) {
613
0
      wbc_status = WBC_ERR_INVALID_RESPONSE;
614
0
      goto done;
615
0
    }
616
617
0
    p = q+1;
618
619
0
    if ((q = strchr(p, '\n')) == NULL) {
620
0
      wbc_status = WBC_ERR_INVALID_RESPONSE;
621
0
      goto done;
622
0
    }
623
624
0
    *q = '\0';
625
626
0
    names[i] = strdup(p);
627
0
    BAIL_ON_PTR_ERROR(names[i], wbc_status);
628
629
0
    p = q+1;
630
0
  }
631
632
0
  if (*p != '\0') {
633
0
    wbc_status = WBC_ERR_INVALID_RESPONSE;
634
0
    goto done;
635
0
  }
636
637
0
  wbc_status = WBC_ERR_SUCCESS;
638
639
0
 done:
640
0
  winbindd_free_response(&response);
641
642
0
  if (WBC_ERROR_IS_OK(wbc_status)) {
643
0
    *pp_domain_name = domain_name;
644
0
    *pnames = names;
645
0
    *ptypes = types;
646
0
  }
647
0
  else {
648
0
    wbcFreeMemory(domain_name);
649
0
    wbcFreeMemory(names);
650
0
    wbcFreeMemory(types);
651
0
  }
652
653
0
  return wbc_status;
654
0
}
655
656
_PUBLIC_
657
wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
658
         int num_rids,
659
         uint32_t *rids,
660
         const char **pp_domain_name,
661
         const char ***pnames,
662
         enum wbcSidType **ptypes)
663
0
{
664
0
  return wbcCtxLookupRids(NULL, dom_sid, num_rids, rids,
665
0
        pp_domain_name, pnames, ptypes);
666
0
}
667
668
/* Get the groups a user belongs to */
669
_PUBLIC_
670
wbcErr wbcCtxLookupUserSids(struct wbcContext *ctx,
671
          const struct wbcDomainSid *user_sid,
672
          bool domain_groups_only,
673
          uint32_t *num_sids,
674
          struct wbcDomainSid **_sids)
675
0
{
676
0
  uint32_t i;
677
0
  const char *s;
678
0
  struct winbindd_request request;
679
0
  struct winbindd_response response;
680
0
  struct wbcDomainSid *sids = NULL;
681
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
682
0
  int cmd;
683
684
  /* Initialise request */
685
686
0
  ZERO_STRUCT(request);
687
0
  ZERO_STRUCT(response);
688
689
0
  if (!user_sid) {
690
0
    wbc_status = WBC_ERR_INVALID_PARAM;
691
0
    BAIL_ON_WBC_ERROR(wbc_status);
692
0
  }
693
694
0
  wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
695
696
0
  if (domain_groups_only) {
697
0
    cmd = WINBINDD_GETUSERDOMGROUPS;
698
0
  } else {
699
0
    cmd = WINBINDD_GETUSERSIDS;
700
0
  }
701
702
0
  wbc_status = wbcRequestResponse(ctx, cmd,
703
0
          &request,
704
0
          &response);
705
0
  BAIL_ON_WBC_ERROR(wbc_status);
706
707
0
  if (response.data.num_entries &&
708
0
      !response.extra_data.data) {
709
0
    wbc_status = WBC_ERR_INVALID_RESPONSE;
710
0
    BAIL_ON_WBC_ERROR(wbc_status);
711
0
  }
712
713
0
  sids = (struct wbcDomainSid *)wbcAllocateMemory(
714
0
    response.data.num_entries, sizeof(struct wbcDomainSid),
715
0
    NULL);
716
0
  BAIL_ON_PTR_ERROR(sids, wbc_status);
717
718
0
  s = (const char *)response.extra_data.data;
719
0
  for (i = 0; i < response.data.num_entries; i++) {
720
0
    char *n = strchr(s, '\n');
721
0
    if (n) {
722
0
      *n = '\0';
723
0
    }
724
0
    wbc_status = wbcStringToSid(s, &sids[i]);
725
0
    BAIL_ON_WBC_ERROR(wbc_status);
726
0
    s += strlen(s) + 1;
727
0
  }
728
729
0
  *num_sids = response.data.num_entries;
730
0
  *_sids = sids;
731
0
  sids = NULL;
732
0
  wbc_status = WBC_ERR_SUCCESS;
733
734
0
 done:
735
0
  winbindd_free_response(&response);
736
0
  if (sids) {
737
0
    wbcFreeMemory(sids);
738
0
  }
739
740
0
  return wbc_status;
741
0
}
742
743
_PUBLIC_
744
wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
745
       bool domain_groups_only,
746
       uint32_t *num_sids,
747
       struct wbcDomainSid **_sids)
748
0
{
749
0
  return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
750
0
            num_sids, _sids);
751
0
}
752
753
static inline
754
wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
755
0
{
756
0
  if (sid->num_auths < 1) {
757
0
    return WBC_ERR_INVALID_RESPONSE;
758
0
  }
759
0
  *rid = sid->sub_auths[sid->num_auths - 1];
760
761
0
  return WBC_ERR_SUCCESS;
762
0
}
763
764
/* Get alias membership for sids */
765
_PUBLIC_
766
wbcErr wbcCtxGetSidAliases(struct wbcContext *ctx,
767
         const struct wbcDomainSid *dom_sid,
768
         struct wbcDomainSid *sids,
769
         uint32_t num_sids,
770
         uint32_t **alias_rids,
771
         uint32_t *num_alias_rids)
772
0
{
773
0
  uint32_t i;
774
0
  const char *s;
775
0
  struct winbindd_request request;
776
0
  struct winbindd_response response;
777
0
  ssize_t extra_data_len = 0;
778
0
  char * extra_data = NULL;
779
0
  ssize_t buflen = 0;
780
0
  struct wbcDomainSid sid;
781
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
782
0
  uint32_t * rids = NULL;
783
784
  /* Initialise request */
785
786
0
  ZERO_STRUCT(request);
787
0
  ZERO_STRUCT(response);
788
789
0
  if (!dom_sid) {
790
0
    wbc_status = WBC_ERR_INVALID_PARAM;
791
0
    goto done;
792
0
  }
793
794
0
  wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
795
796
  /* Lets assume each sid is around 57 characters
797
   * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
798
0
  buflen = 57 * num_sids;
799
0
  extra_data = (char *)malloc(buflen);
800
0
  if (!extra_data) {
801
0
    wbc_status = WBC_ERR_NO_MEMORY;
802
0
    goto done;
803
0
  }
804
805
  /* Build the sid list */
806
0
  for (i=0; i<num_sids; i++) {
807
0
    char sid_str[WBC_SID_STRING_BUFLEN];
808
0
    size_t sid_len;
809
810
0
    sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
811
812
0
    if (buflen < extra_data_len + sid_len + 2) {
813
0
      char * tmp_data = NULL;
814
0
      buflen *= 2;
815
0
      tmp_data = (char *)realloc(extra_data, buflen);
816
0
      if (!tmp_data) {
817
0
        wbc_status = WBC_ERR_NO_MEMORY;
818
0
        BAIL_ON_WBC_ERROR(wbc_status);
819
0
      }
820
0
      extra_data = tmp_data;
821
0
    }
822
823
0
    strncpy(&extra_data[extra_data_len], sid_str,
824
0
      buflen - extra_data_len);
825
0
    extra_data_len += sid_len;
826
0
    extra_data[extra_data_len++] = '\n';
827
0
    extra_data[extra_data_len] = '\0';
828
0
  }
829
0
  extra_data_len += 1;
830
831
0
  request.extra_data.data = extra_data;
832
0
  request.extra_len = extra_data_len;
833
834
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
835
0
          &request,
836
0
          &response);
837
0
  BAIL_ON_WBC_ERROR(wbc_status);
838
839
0
  if (response.data.num_entries &&
840
0
      !response.extra_data.data) {
841
0
    wbc_status = WBC_ERR_INVALID_RESPONSE;
842
0
    goto done;
843
0
  }
844
845
0
  rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
846
0
               sizeof(uint32_t), NULL);
847
0
  BAIL_ON_PTR_ERROR(rids, wbc_status);
848
849
0
  s = (const char *)response.extra_data.data;
850
0
  for (i = 0; i < response.data.num_entries; i++) {
851
0
    char *n = strchr(s, '\n');
852
0
    if (n) {
853
0
      *n = '\0';
854
0
    }
855
0
    wbc_status = wbcStringToSid(s, &sid);
856
0
    BAIL_ON_WBC_ERROR(wbc_status);
857
0
    wbc_status = _sid_to_rid(&sid, &rids[i]);
858
0
    BAIL_ON_WBC_ERROR(wbc_status);
859
0
    s += strlen(s) + 1;
860
0
  }
861
862
0
  *num_alias_rids = response.data.num_entries;
863
0
  *alias_rids = rids;
864
0
  rids = NULL;
865
0
  wbc_status = WBC_ERR_SUCCESS;
866
867
0
 done:
868
0
  free(extra_data);
869
0
  winbindd_free_response(&response);
870
0
  wbcFreeMemory(rids);
871
0
  return wbc_status;
872
0
}
873
874
_PUBLIC_
875
wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
876
      struct wbcDomainSid *sids,
877
      uint32_t num_sids,
878
      uint32_t **alias_rids,
879
      uint32_t *num_alias_rids)
880
0
{
881
0
  return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
882
0
           alias_rids, num_alias_rids);
883
0
}
884
885
886
/* Lists Users */
887
_PUBLIC_
888
wbcErr wbcCtxListUsers(struct wbcContext *ctx,
889
           const char *domain_name,
890
           uint32_t *_num_users,
891
           const char ***_users)
892
0
{
893
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
894
0
  struct winbindd_request request;
895
0
  struct winbindd_response response;
896
0
  uint32_t num_users = 0;
897
0
  const char **users = NULL;
898
0
  const char *next;
899
900
  /* Initialise request */
901
902
0
  ZERO_STRUCT(request);
903
0
  ZERO_STRUCT(response);
904
905
0
  if (domain_name) {
906
0
    strncpy(request.domain_name, domain_name,
907
0
      sizeof(request.domain_name)-1);
908
0
  }
909
910
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
911
0
          &request,
912
0
          &response);
913
0
  BAIL_ON_WBC_ERROR(wbc_status);
914
915
0
  users = wbcAllocateStringArray(response.data.num_entries);
916
0
  if (users == NULL) {
917
0
    return WBC_ERR_NO_MEMORY;
918
0
  }
919
920
  /* Look through extra data */
921
922
0
  next = (const char *)response.extra_data.data;
923
0
  while (next) {
924
0
    const char *current;
925
0
    char *k;
926
927
0
    if (num_users >= response.data.num_entries) {
928
0
      wbc_status = WBC_ERR_INVALID_RESPONSE;
929
0
      goto done;
930
0
    }
931
932
0
    current = next;
933
0
    k = strchr(next, ',');
934
935
0
    if (k) {
936
0
      k[0] = '\0';
937
0
      next = k+1;
938
0
    } else {
939
0
      next = NULL;
940
0
    }
941
942
0
    users[num_users] = strdup(current);
943
0
    BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
944
0
    num_users += 1;
945
0
  }
946
0
  if (num_users != response.data.num_entries) {
947
0
    wbc_status = WBC_ERR_INVALID_RESPONSE;
948
0
    goto done;
949
0
  }
950
951
0
  *_num_users = response.data.num_entries;
952
0
  *_users = users;
953
0
  users = NULL;
954
0
  wbc_status = WBC_ERR_SUCCESS;
955
956
0
 done:
957
0
  winbindd_free_response(&response);
958
0
  wbcFreeMemory(users);
959
0
  return wbc_status;
960
0
}
961
962
_PUBLIC_
963
wbcErr wbcListUsers(const char *domain_name,
964
        uint32_t *_num_users,
965
        const char ***_users)
966
0
{
967
0
  return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
968
0
}
969
970
/* Lists Groups */
971
_PUBLIC_
972
wbcErr wbcCtxListGroups(struct wbcContext *ctx,
973
      const char *domain_name,
974
      uint32_t *_num_groups,
975
      const char ***_groups)
976
0
{
977
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
978
0
  struct winbindd_request request;
979
0
  struct winbindd_response response;
980
0
  uint32_t num_groups = 0;
981
0
  const char **groups = NULL;
982
0
  const char *next;
983
984
  /* Initialise request */
985
986
0
  ZERO_STRUCT(request);
987
0
  ZERO_STRUCT(response);
988
989
0
  if (domain_name) {
990
0
    strncpy(request.domain_name, domain_name,
991
0
      sizeof(request.domain_name)-1);
992
0
  }
993
994
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_GROUPS,
995
0
          &request,
996
0
          &response);
997
0
  BAIL_ON_WBC_ERROR(wbc_status);
998
999
0
  groups = wbcAllocateStringArray(response.data.num_entries);
1000
0
  if (groups == NULL) {
1001
0
    return WBC_ERR_NO_MEMORY;
1002
0
  }
1003
1004
  /* Look through extra data */
1005
1006
0
  next = (const char *)response.extra_data.data;
1007
0
  while (next) {
1008
0
    const char *current;
1009
0
    char *k;
1010
1011
0
    if (num_groups >= response.data.num_entries) {
1012
0
      wbc_status = WBC_ERR_INVALID_RESPONSE;
1013
0
      goto done;
1014
0
    }
1015
1016
0
    current = next;
1017
0
    k = strchr(next, ',');
1018
1019
0
    if (k) {
1020
0
      k[0] = '\0';
1021
0
      next = k+1;
1022
0
    } else {
1023
0
      next = NULL;
1024
0
    }
1025
1026
0
    groups[num_groups] = strdup(current);
1027
0
    BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
1028
0
    num_groups += 1;
1029
0
  }
1030
0
  if (num_groups != response.data.num_entries) {
1031
0
    wbc_status = WBC_ERR_INVALID_RESPONSE;
1032
0
    goto done;
1033
0
  }
1034
1035
0
  *_num_groups = response.data.num_entries;
1036
0
  *_groups = groups;
1037
0
  groups = NULL;
1038
0
  wbc_status = WBC_ERR_SUCCESS;
1039
1040
0
 done:
1041
0
  winbindd_free_response(&response);
1042
0
  wbcFreeMemory(groups);
1043
0
  return wbc_status;
1044
0
}
1045
1046
_PUBLIC_
1047
wbcErr wbcListGroups(const char *domain_name,
1048
         uint32_t *_num_groups,
1049
         const char ***_groups)
1050
0
{
1051
0
  return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
1052
0
}
1053
1054
_PUBLIC_
1055
wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
1056
          const struct wbcDomainSid *sid,
1057
          char **pdomain,
1058
          char **pfullname,
1059
          enum wbcSidType *pname_type)
1060
0
{
1061
0
  wbcErr wbc_status;
1062
0
  char *domain = NULL;
1063
0
  char *name = NULL;
1064
0
  enum wbcSidType name_type;
1065
1066
0
  wbc_status = wbcCtxLookupSid(ctx, sid, &domain, &name, &name_type);
1067
0
  BAIL_ON_WBC_ERROR(wbc_status);
1068
1069
0
  if (name_type == WBC_SID_NAME_USER) {
1070
0
    uid_t uid;
1071
0
    struct passwd *pwd;
1072
1073
0
    wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
1074
0
    BAIL_ON_WBC_ERROR(wbc_status);
1075
1076
0
    wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
1077
0
    BAIL_ON_WBC_ERROR(wbc_status);
1078
1079
0
    wbcFreeMemory(name);
1080
1081
0
    name = wbcStrDup(pwd->pw_gecos);
1082
0
    wbcFreeMemory(pwd);
1083
0
    BAIL_ON_PTR_ERROR(name, wbc_status);
1084
0
  }
1085
1086
0
  wbc_status = WBC_ERR_SUCCESS;
1087
1088
0
 done:
1089
0
  if (WBC_ERROR_IS_OK(wbc_status)) {
1090
0
    *pdomain = domain;
1091
0
    *pfullname = name;
1092
0
    *pname_type = name_type;
1093
0
  } else {
1094
0
    wbcFreeMemory(domain);
1095
0
    wbcFreeMemory(name);
1096
0
  }
1097
1098
0
  return wbc_status;
1099
0
}
1100
1101
_PUBLIC_
1102
wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
1103
       char **pdomain,
1104
       char **pfullname,
1105
       enum wbcSidType *pname_type)
1106
0
{
1107
0
  return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
1108
0
}
1109
1110
_PUBLIC_
1111
const char* wbcSidTypeString(enum wbcSidType type)
1112
0
{
1113
0
  switch (type) {
1114
0
  case WBC_SID_NAME_USE_NONE: return "SID_NONE";
1115
0
  case WBC_SID_NAME_USER:     return "SID_USER";
1116
0
  case WBC_SID_NAME_DOM_GRP:  return "SID_DOM_GROUP";
1117
0
  case WBC_SID_NAME_DOMAIN:   return "SID_DOMAIN";
1118
0
  case WBC_SID_NAME_ALIAS:    return "SID_ALIAS";
1119
0
  case WBC_SID_NAME_WKN_GRP:  return "SID_WKN_GROUP";
1120
0
  case WBC_SID_NAME_DELETED:  return "SID_DELETED";
1121
0
  case WBC_SID_NAME_INVALID:  return "SID_INVALID";
1122
0
  case WBC_SID_NAME_UNKNOWN:  return "SID_UNKNOWN";
1123
0
  case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
1124
0
  case WBC_SID_NAME_LABEL:    return "SID_LABEL";
1125
0
  default:                    return "Unknown type";
1126
0
  }
1127
0
}