Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/nsswitch/libwbclient/wbc_idmap.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Winbind client API
5
6
   Copyright (C) Gerald (Jerry) Carter 2007
7
8
   This library is free software; you can redistribute it and/or
9
   modify it under the terms of the GNU Lesser General Public
10
   License as published by the Free Software Foundation; either
11
   version 3 of the License, or (at your option) any later version.
12
13
   This library is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
   Library General Public License for more details.
17
18
   You should have received a copy of the GNU Lesser General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
*/
21
22
/* Required Headers */
23
24
#include "replace.h"
25
#include "libwbclient.h"
26
#include "../winbind_client.h"
27
#include "lib/util/smb_strtox.h"
28
29
/* Convert a Windows SID to a Unix uid, allocating an uid if needed */
30
_PUBLIC_
31
wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
32
          uid_t *puid)
33
0
{
34
0
  struct wbcUnixId xid;
35
0
  wbcErr wbc_status;
36
37
0
  if (!sid || !puid) {
38
0
    wbc_status = WBC_ERR_INVALID_PARAM;
39
0
    BAIL_ON_WBC_ERROR(wbc_status);
40
0
  }
41
42
0
  wbc_status = wbcCtxSidsToUnixIds(ctx, sid, 1, &xid);
43
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
44
0
    goto done;
45
0
  }
46
47
0
  if ((xid.type == WBC_ID_TYPE_UID) || (xid.type == WBC_ID_TYPE_BOTH)) {
48
0
    *puid = xid.id.uid;
49
0
    wbc_status = WBC_ERR_SUCCESS;
50
0
  } else {
51
0
    wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
52
0
  }
53
54
0
 done:
55
0
  return wbc_status;
56
0
}
57
58
_PUBLIC_
59
wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
60
0
{
61
0
  return wbcCtxSidToUid(NULL, sid, puid);
62
0
}
63
64
/* Convert a Windows SID to a Unix uid if there already is a mapping */
65
_PUBLIC_
66
wbcErr wbcQuerySidToUid(const struct wbcDomainSid *sid,
67
      uid_t *puid)
68
0
{
69
0
  return WBC_ERR_NOT_IMPLEMENTED;
70
0
}
71
72
/* Convert a Unix uid to a Windows SID, allocating a SID if needed */
73
_PUBLIC_
74
wbcErr wbcCtxUidToSid(struct wbcContext *ctx, uid_t uid,
75
          struct wbcDomainSid *psid)
76
0
{
77
0
  struct wbcUnixId xid;
78
0
  struct wbcDomainSid sid;
79
0
  struct wbcDomainSid null_sid = { 0 };
80
0
  wbcErr wbc_status;
81
82
0
  if (!psid) {
83
0
    wbc_status = WBC_ERR_INVALID_PARAM;
84
0
    BAIL_ON_WBC_ERROR(wbc_status);
85
0
  }
86
87
0
  xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_UID, .id.uid = uid };
88
89
0
  wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
90
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
91
0
    goto done;
92
0
  }
93
94
0
  if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
95
0
    *psid = sid;
96
0
  } else {
97
0
    wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
98
0
  }
99
100
0
done:
101
0
  return wbc_status;
102
0
}
103
104
_PUBLIC_
105
wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
106
0
{
107
0
  return wbcCtxUidToSid(NULL, uid, sid);
108
0
}
109
110
/* Convert a Unix uid to a Windows SID if there already is a mapping */
111
_PUBLIC_
112
wbcErr wbcQueryUidToSid(uid_t uid,
113
      struct wbcDomainSid *sid)
114
0
{
115
0
  return WBC_ERR_NOT_IMPLEMENTED;
116
0
}
117
118
/** @brief Convert a Windows SID to a Unix gid, allocating a gid if needed
119
 *
120
 * @param *sid        Pointer to the domain SID to be resolved
121
 * @param *pgid       Pointer to the resolved gid_t value
122
 *
123
 * @return #wbcErr
124
 *
125
 **/
126
127
_PUBLIC_
128
wbcErr wbcCtxSidToGid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
129
          gid_t *pgid)
130
0
{
131
0
  struct wbcUnixId xid;
132
0
  wbcErr wbc_status;
133
134
0
  if (!sid || !pgid) {
135
0
    wbc_status = WBC_ERR_INVALID_PARAM;
136
0
    BAIL_ON_WBC_ERROR(wbc_status);
137
0
  }
138
139
0
  wbc_status = wbcCtxSidsToUnixIds(ctx, sid, 1, &xid);
140
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
141
0
    goto done;
142
0
  }
143
144
0
  if ((xid.type == WBC_ID_TYPE_GID) || (xid.type == WBC_ID_TYPE_BOTH)) {
145
0
    *pgid = xid.id.gid;
146
0
    wbc_status = WBC_ERR_SUCCESS;
147
0
  } else {
148
0
    wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
149
0
  }
150
151
0
 done:
152
0
  return wbc_status;
153
0
}
154
155
_PUBLIC_
156
wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
157
0
{
158
0
  return wbcCtxSidToGid(NULL, sid, pgid);
159
0
}
160
161
/* Convert a Windows SID to a Unix gid if there already is a mapping */
162
163
_PUBLIC_
164
wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid,
165
      gid_t *pgid)
166
0
{
167
0
  return WBC_ERR_NOT_IMPLEMENTED;
168
0
}
169
170
171
/* Convert a Unix gid to a Windows SID, allocating a SID if needed */
172
_PUBLIC_
173
wbcErr wbcCtxGidToSid(struct wbcContext *ctx, gid_t gid,
174
          struct wbcDomainSid *psid)
175
0
{
176
0
  struct wbcUnixId xid;
177
0
  struct wbcDomainSid sid;
178
0
  struct wbcDomainSid null_sid = { 0 };
179
0
  wbcErr wbc_status;
180
181
0
  if (!psid) {
182
0
    wbc_status = WBC_ERR_INVALID_PARAM;
183
0
    BAIL_ON_WBC_ERROR(wbc_status);
184
0
  }
185
186
0
  xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_GID, .id.gid = gid };
187
188
0
  wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
189
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
190
0
    goto done;
191
0
  }
192
193
0
  if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
194
0
    *psid = sid;
195
0
  } else {
196
0
    wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
197
0
  }
198
199
0
done:
200
0
  return wbc_status;
201
0
}
202
203
_PUBLIC_
204
wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
205
0
{
206
0
  return wbcCtxGidToSid(NULL, gid, sid);
207
0
}
208
209
/* Convert a Unix gid to a Windows SID if there already is a mapping */
210
_PUBLIC_
211
wbcErr wbcQueryGidToSid(gid_t gid,
212
      struct wbcDomainSid *sid)
213
0
{
214
0
  return WBC_ERR_NOT_IMPLEMENTED;
215
0
}
216
217
/* Obtain a new uid from Winbind */
218
_PUBLIC_
219
wbcErr wbcCtxAllocateUid(struct wbcContext *ctx, uid_t *puid)
220
0
{
221
0
  struct winbindd_request request;
222
0
  struct winbindd_response response;
223
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
224
225
0
  if (!puid)
226
0
    return WBC_ERR_INVALID_PARAM;
227
228
  /* Initialise request */
229
230
0
  ZERO_STRUCT(request);
231
0
  ZERO_STRUCT(response);
232
233
  /* Make request */
234
235
0
  wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_UID,
236
0
              &request, &response);
237
0
  BAIL_ON_WBC_ERROR(wbc_status);
238
239
  /* Copy out result */
240
0
  *puid = response.data.uid;
241
242
0
  wbc_status = WBC_ERR_SUCCESS;
243
244
0
 done:
245
0
  return wbc_status;
246
0
}
247
248
_PUBLIC_
249
wbcErr wbcAllocateUid(uid_t *puid)
250
0
{
251
0
  return wbcCtxAllocateUid(NULL, puid);
252
0
}
253
254
/* Obtain a new gid from Winbind */
255
_PUBLIC_
256
wbcErr wbcCtxAllocateGid(struct wbcContext *ctx, gid_t *pgid)
257
0
{
258
0
  struct winbindd_request request;
259
0
  struct winbindd_response response;
260
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
261
262
0
  if (!pgid)
263
0
    return WBC_ERR_INVALID_PARAM;
264
265
  /* Initialise request */
266
267
0
  ZERO_STRUCT(request);
268
0
  ZERO_STRUCT(response);
269
270
  /* Make request */
271
272
0
  wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_GID,
273
0
              &request, &response);
274
0
  BAIL_ON_WBC_ERROR(wbc_status);
275
276
  /* Copy out result */
277
0
  *pgid = response.data.gid;
278
279
0
  wbc_status = WBC_ERR_SUCCESS;
280
281
0
 done:
282
0
  return wbc_status;
283
0
}
284
285
_PUBLIC_
286
wbcErr wbcAllocateGid(gid_t *pgid)
287
0
{
288
0
  return wbcCtxAllocateGid(NULL, pgid);
289
0
}
290
291
/* we can't include smb.h here... */
292
#define _ID_TYPE_UID 1
293
#define _ID_TYPE_GID 2
294
295
/* Set an user id mapping - not implemented any more */
296
_PUBLIC_
297
wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid)
298
0
{
299
0
  return WBC_ERR_NOT_IMPLEMENTED;
300
0
}
301
302
/* Set a group id mapping - not implemented any more */
303
_PUBLIC_
304
wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid)
305
0
{
306
0
  return WBC_ERR_NOT_IMPLEMENTED;
307
0
}
308
309
/* Remove a user id mapping - not implemented any more */
310
_PUBLIC_
311
wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid)
312
0
{
313
0
  return WBC_ERR_NOT_IMPLEMENTED;
314
0
}
315
316
/* Remove a group id mapping - not implemented any more */
317
_PUBLIC_
318
wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid)
319
0
{
320
0
  return WBC_ERR_NOT_IMPLEMENTED;
321
0
}
322
323
/* Set the highwater mark for allocated uids - not implemented any more */
324
_PUBLIC_
325
wbcErr wbcSetUidHwm(uid_t uid_hwm)
326
0
{
327
0
  return WBC_ERR_NOT_IMPLEMENTED;
328
0
}
329
330
/* Set the highwater mark for allocated gids - not implemented any more */
331
_PUBLIC_
332
wbcErr wbcSetGidHwm(gid_t gid_hwm)
333
0
{
334
0
  return WBC_ERR_NOT_IMPLEMENTED;
335
0
}
336
337
/* Convert a list of SIDs */
338
_PUBLIC_
339
wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
340
         const struct wbcDomainSid *sids,
341
         uint32_t num_sids, struct wbcUnixId *ids)
342
0
{
343
0
  struct winbindd_request request;
344
0
  struct winbindd_response response;
345
0
  wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
346
0
  int buflen, extra_len;
347
0
  uint32_t i;
348
0
  char *sidlist, *p, *extra_data;
349
350
0
  buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
351
352
0
  sidlist = (char *)malloc(buflen);
353
0
  if (sidlist == NULL) {
354
0
    return WBC_ERR_NO_MEMORY;
355
0
  }
356
357
0
  p = sidlist;
358
359
0
  for (i=0; i<num_sids; i++) {
360
0
    int remaining;
361
0
    int len;
362
363
0
    remaining = buflen - (p - sidlist);
364
365
0
    len = wbcSidToStringBuf(&sids[i], p, remaining);
366
0
    if (len > remaining) {
367
0
      free(sidlist);
368
0
      return WBC_ERR_UNKNOWN_FAILURE;
369
0
    }
370
371
0
    p += len;
372
0
    *p++ = '\n';
373
0
  }
374
0
  *p++ = '\0';
375
376
0
  ZERO_STRUCT(request);
377
0
  ZERO_STRUCT(response);
378
379
0
  request.extra_data.data = sidlist;
380
0
  request.extra_len = p - sidlist;
381
382
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_SIDS_TO_XIDS,
383
0
          &request, &response);
384
0
  free(sidlist);
385
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
386
0
    return wbc_status;
387
0
  }
388
389
0
  extra_len = response.length - sizeof(struct winbindd_response);
390
0
  extra_data = (char *)response.extra_data.data;
391
392
0
  if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
393
0
    goto wbc_err_invalid;
394
0
  }
395
396
0
  p = extra_data;
397
398
0
  for (i=0; i<num_sids; i++) {
399
0
    struct wbcUnixId *id = &ids[i];
400
0
    char *q;
401
0
    int error = 0;
402
403
0
    switch (p[0]) {
404
0
    case 'U':
405
0
      id->type = WBC_ID_TYPE_UID;
406
0
      id->id.uid = smb_strtoul(p+1,
407
0
             &q,
408
0
             10,
409
0
             &error,
410
0
             SMB_STR_STANDARD);
411
0
      break;
412
0
    case 'G':
413
0
      id->type = WBC_ID_TYPE_GID;
414
0
      id->id.gid = smb_strtoul(p+1,
415
0
             &q,
416
0
             10,
417
0
             &error,
418
0
             SMB_STR_STANDARD);
419
0
      break;
420
0
    case 'B':
421
0
      id->type = WBC_ID_TYPE_BOTH;
422
0
      id->id.uid = smb_strtoul(p+1,
423
0
             &q,
424
0
             10,
425
0
             &error,
426
0
             SMB_STR_STANDARD);
427
0
      break;
428
0
    default:
429
0
      id->type = WBC_ID_TYPE_NOT_SPECIFIED;
430
0
      q = strchr(p, '\n');
431
0
      break;
432
0
    };
433
0
    if (q == NULL || q[0] != '\n' || error != 0) {
434
0
      goto wbc_err_invalid;
435
0
    }
436
0
    p = q+1;
437
0
  }
438
0
  wbc_status = WBC_ERR_SUCCESS;
439
0
  goto done;
440
441
0
wbc_err_invalid:
442
0
  wbc_status = WBC_ERR_INVALID_RESPONSE;
443
0
done:
444
0
  winbindd_free_response(&response);
445
0
  return wbc_status;
446
0
}
447
448
_PUBLIC_
449
wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids,
450
      struct wbcUnixId *ids)
451
0
{
452
0
  return wbcCtxSidsToUnixIds(NULL, sids, num_sids, ids);
453
0
}
454
455
_PUBLIC_
456
wbcErr wbcCtxUnixIdsToSids(struct wbcContext *ctx,
457
         const struct wbcUnixId *ids, uint32_t num_ids,
458
         struct wbcDomainSid *sids)
459
0
{
460
0
  struct winbindd_request request;
461
0
  struct winbindd_response response;
462
0
  wbcErr wbc_status;
463
0
  char *buf;
464
0
  char *s;
465
0
  const size_t sidlen = (1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */);
466
0
  size_t ofs, buflen;
467
0
  uint32_t i;
468
469
0
  if (num_ids > SIZE_MAX / sidlen) {
470
0
    return WBC_ERR_NO_MEMORY; /* overflow */
471
0
  }
472
0
  buflen = num_ids * sidlen;
473
474
0
  buflen += 1;    /* trailing \0 */
475
0
  if (buflen < 1) {
476
0
    return WBC_ERR_NO_MEMORY; /* overflow */
477
0
  }
478
479
0
  buf = malloc(buflen);
480
0
  if (buf == NULL) {
481
0
    return WBC_ERR_NO_MEMORY;
482
0
  }
483
484
0
  ofs = 0;
485
486
0
  for (i=0; i<num_ids; i++) {
487
0
    const struct wbcUnixId *id = &ids[i];
488
0
    int len;
489
490
0
    switch (id->type) {
491
0
    case WBC_ID_TYPE_UID:
492
0
      len = snprintf(buf+ofs, buflen-ofs, "U%"PRIu32"\n",
493
0
               (uint32_t)id->id.uid);
494
0
      break;
495
0
    case WBC_ID_TYPE_GID:
496
0
      len = snprintf(buf+ofs, buflen-ofs, "G%"PRIu32"\n",
497
0
               (uint32_t)id->id.gid);
498
0
      break;
499
0
    default:
500
0
      free(buf);
501
0
      return WBC_ERR_INVALID_PARAM;
502
0
    }
503
504
0
    if (len + ofs >= buflen) { /* >= for the terminating '\0' */
505
0
      free(buf);
506
0
      return WBC_ERR_UNKNOWN_FAILURE;
507
0
    }
508
0
    ofs += len;
509
0
  }
510
511
0
  request = (struct winbindd_request) {
512
0
    .extra_data.data = buf, .extra_len = ofs+1
513
0
  };
514
0
  response = (struct winbindd_response) {0};
515
516
0
  wbc_status = wbcRequestResponse(ctx, WINBINDD_XIDS_TO_SIDS,
517
0
          &request, &response);
518
0
  free(buf);
519
0
  if (!WBC_ERROR_IS_OK(wbc_status)) {
520
0
    return wbc_status;
521
0
  }
522
523
0
  s = response.extra_data.data;
524
0
  for (i=0; i<num_ids; i++) {
525
0
    char *n = strchr(s, '\n');
526
527
0
    if (n == NULL) {
528
0
      goto fail;
529
0
    }
530
0
    *n = '\0';
531
532
0
    wbc_status = wbcStringToSid(s, &sids[i]);
533
0
    if (!WBC_ERROR_IS_OK(wbc_status)) {
534
0
      sids[i] = (struct wbcDomainSid) {0};
535
0
    }
536
0
    s = n+1;
537
0
  }
538
539
0
  wbc_status = WBC_ERR_SUCCESS;
540
0
fail:
541
0
  winbindd_free_response(&response);
542
0
  return wbc_status;
543
0
}
544
545
_PUBLIC_
546
wbcErr wbcUnixIdsToSids(const struct wbcUnixId *ids, uint32_t num_ids,
547
      struct wbcDomainSid *sids)
548
0
{
549
  return wbcCtxUnixIdsToSids(NULL, ids, num_ids, sids);
550
0
}