Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/namemap_cache.c
Line
Count
Source
1
/*
2
 * Unix SMB/CIFS implementation.
3
 * Utils for caching sid2name and name2sid
4
 * Copyright (C) Volker Lendecke 2017
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include "replace.h"
21
#include "namemap_cache.h"
22
#include "source3/lib/gencache.h"
23
#include "lib/util/debug.h"
24
#include "lib/util/strv.h"
25
#include "lib/util/util.h"
26
#include "lib/util/talloc_stack.h"
27
#include "lib/util/charset/charset.h"
28
#include "libcli/security/dom_sid.h"
29
#include "lib/util/smb_strtox.h"
30
31
bool namemap_cache_set_sid2name(const struct dom_sid *sid,
32
        const char *domain, const char *name,
33
        enum lsa_SidType type, time_t timeout)
34
0
{
35
0
  char typebuf[16];
36
0
  struct dom_sid_buf sidbuf;
37
0
  char keybuf[sizeof(sidbuf.buf)+10];
38
0
  char *val = NULL;
39
0
  DATA_BLOB data;
40
0
  int ret;
41
0
  bool ok = false;
42
43
0
  if ((sid == NULL) || is_null_sid(sid)) {
44
0
    return true;
45
0
  }
46
0
  if (domain == NULL) {
47
0
    domain = "";
48
0
  }
49
0
  if (name == NULL) {
50
0
    name = "";
51
0
  }
52
0
  if (type == SID_NAME_UNKNOWN) {
53
0
    domain = "";
54
0
    name = "";
55
0
  }
56
57
0
  snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
58
59
0
  ret = strv_add(talloc_tos(), &val, domain);
60
0
  if (ret != 0) {
61
0
    DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
62
0
    goto fail;
63
0
  }
64
0
  ret = strv_add(NULL, &val, name);
65
0
  if (ret != 0) {
66
0
    DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
67
0
    goto fail;
68
0
  }
69
0
  ret = strv_add(NULL, &val, typebuf);
70
0
  if (ret != 0) {
71
0
    DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
72
0
    goto fail;
73
0
  }
74
75
0
  dom_sid_str_buf(sid, &sidbuf);
76
0
  snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf);
77
78
0
  data = data_blob_const(val, talloc_get_size(val));
79
80
0
  ok = gencache_set_data_blob(keybuf, data, timeout);
81
0
  if (!ok) {
82
0
    DBG_DEBUG("gencache_set_data_blob failed\n");
83
0
  }
84
0
fail:
85
0
  TALLOC_FREE(val);
86
0
  return ok;
87
0
}
88
89
struct namemap_cache_find_sid_state {
90
  void (*fn)(const char *domain,
91
       const char *name,
92
       enum lsa_SidType type,
93
       bool expired,
94
       void *private_data);
95
  void *private_data;
96
  bool ok;
97
};
98
99
static void namemap_cache_find_sid_parser(
100
  const struct gencache_timeout *timeout,
101
  DATA_BLOB blob,
102
  void *private_data)
103
0
{
104
0
  struct namemap_cache_find_sid_state *state = private_data;
105
0
  const char *strv = (const char *)blob.data;
106
0
  size_t strv_len = blob.length;
107
0
  const char *domain;
108
0
  const char *name;
109
0
  const char *typebuf;
110
0
  int error = 0;
111
0
  unsigned long type;
112
113
0
  state->ok = false;
114
115
0
  domain = strv_len_next(strv, strv_len, NULL);
116
0
  if (domain == NULL) {
117
0
    return;
118
0
  }
119
0
  name = strv_len_next(strv, strv_len, domain);
120
0
  if (name == NULL) {
121
0
    return;
122
0
  }
123
0
  typebuf = strv_len_next(strv, strv_len, name);
124
0
  if (typebuf == NULL) {
125
0
    return;
126
0
  }
127
128
0
  type = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
129
0
  if (error != 0) {
130
0
    return;
131
0
  }
132
133
0
  state->fn(domain,
134
0
      name,
135
0
      (enum lsa_SidType)type,
136
0
      gencache_timeout_expired(timeout),
137
0
      state->private_data);
138
139
0
  state->ok = true;
140
0
}
141
142
bool namemap_cache_find_sid(const struct dom_sid *sid,
143
          void (*fn)(const char *domain,
144
               const char *name,
145
               enum lsa_SidType type,
146
               bool expired,
147
               void *private_data),
148
          void *private_data)
149
0
{
150
0
  struct namemap_cache_find_sid_state state = {
151
0
    .fn = fn, .private_data = private_data
152
0
  };
153
0
  struct dom_sid_buf sidbuf;
154
0
  char keybuf[sizeof(sidbuf.buf)+10];
155
0
  bool ok;
156
157
0
  dom_sid_str_buf(sid, &sidbuf);
158
0
  snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf);
159
160
0
  ok = gencache_parse(keybuf, namemap_cache_find_sid_parser, &state);
161
0
  if (!ok) {
162
0
    DBG_DEBUG("gencache_parse(%s) failed\n", keybuf);
163
0
    return false;
164
0
  }
165
166
0
  if (!state.ok) {
167
0
    DBG_DEBUG("Could not parse %s, deleting\n", keybuf);
168
0
    gencache_del(keybuf);
169
0
    return false;
170
0
  }
171
172
0
  return true;
173
0
}
174
175
bool namemap_cache_set_name2sid(const char *domain, const char *name,
176
        const struct dom_sid *sid,
177
        enum lsa_SidType type,
178
        time_t timeout)
179
0
{
180
0
  char typebuf[16];
181
0
  struct dom_sid_buf sidbuf = {{0}};
182
0
  char *key;
183
0
  char *key_upper;
184
0
  char *val = NULL;
185
0
  DATA_BLOB data;
186
0
  int ret;
187
0
  bool ok = false;
188
189
0
  if (domain == NULL) {
190
0
    domain = "";
191
0
  }
192
0
  if (name == NULL) {
193
0
    name = "";
194
0
  }
195
0
  if (type != SID_NAME_UNKNOWN) {
196
0
    dom_sid_str_buf(sid, &sidbuf);
197
0
  }
198
199
0
  snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
200
201
0
  key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
202
0
  if (key == NULL) {
203
0
    DBG_DEBUG("talloc_asprintf failed\n");
204
0
    goto fail;
205
0
  }
206
0
  key_upper = strupper_talloc(key, key);
207
0
  if (key_upper == NULL) {
208
0
    DBG_DEBUG("strupper_talloc failed\n");
209
0
    goto fail;
210
0
  }
211
212
0
  ret = strv_add(key, &val, sidbuf.buf);
213
0
  if (ret != 0) {
214
0
    DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
215
0
    goto fail;
216
0
  }
217
0
  ret = strv_add(NULL, &val, typebuf);
218
0
  if (ret != 0) {
219
0
    DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
220
0
    goto fail;
221
0
  }
222
223
0
  data = data_blob_const(val, talloc_get_size(val));
224
225
0
  ok = gencache_set_data_blob(key_upper, data, timeout);
226
0
  if (!ok) {
227
0
    DBG_DEBUG("gencache_set_data_blob failed\n");
228
0
  }
229
0
fail:
230
0
  TALLOC_FREE(key);
231
0
  return ok;
232
0
}
233
234
struct namemap_cache_find_name_state {
235
  void (*fn)(const struct dom_sid *sid,
236
       enum lsa_SidType type,
237
       bool expired,
238
       void *private_data);
239
  void *private_data;
240
  bool ok;
241
};
242
243
static void namemap_cache_find_name_parser(
244
  const struct gencache_timeout *timeout,
245
  DATA_BLOB blob,
246
  void *private_data)
247
0
{
248
0
  struct namemap_cache_find_name_state *state = private_data;
249
0
  const char *strv = (const char *)blob.data;
250
0
  size_t strv_len = blob.length;
251
0
  const char *sidbuf;
252
0
  const char *sid_endptr;
253
0
  const char *typebuf;
254
0
  int error = 0;
255
0
  struct dom_sid sid;
256
0
  unsigned long type;
257
0
  bool ok;
258
259
0
  state->ok = false;
260
261
0
  sidbuf = strv_len_next(strv, strv_len, NULL);
262
0
  if (sidbuf == NULL) {
263
0
    return;
264
0
  }
265
0
  typebuf = strv_len_next(strv, strv_len, sidbuf);
266
0
  if (typebuf == NULL) {
267
0
    return;
268
0
  }
269
270
0
  ok = dom_sid_parse_endp(sidbuf, &sid, &sid_endptr);
271
0
  if (!ok) {
272
0
    return;
273
0
  }
274
0
  if (*sid_endptr != '\0') {
275
0
    return;
276
0
  }
277
278
0
  type = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
279
0
  if (error != 0) {
280
0
    return;
281
0
  }
282
283
0
  state->fn(&sid,
284
0
      (enum lsa_SidType)type,
285
0
      gencache_timeout_expired(timeout),
286
0
      state->private_data);
287
288
0
  state->ok = true;
289
0
}
290
291
bool namemap_cache_find_name(const char *domain,
292
           const char *name,
293
           void (*fn)(const struct dom_sid *sid,
294
          enum lsa_SidType type,
295
          bool expired,
296
          void *private_data),
297
           void *private_data)
298
0
{
299
0
  struct namemap_cache_find_name_state state = {
300
0
    .fn = fn, .private_data = private_data
301
0
  };
302
0
  char *key;
303
0
  char *key_upper;
304
0
  bool ret = false;
305
0
  bool ok;
306
307
0
  key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
308
0
  if (key == NULL) {
309
0
    DBG_DEBUG("talloc_asprintf failed\n");
310
0
    return false;
311
0
  }
312
0
  key_upper = strupper_talloc(key, key);
313
0
  if (key_upper == NULL) {
314
0
    DBG_DEBUG("strupper_talloc failed\n");
315
0
    goto fail;
316
0
  }
317
318
0
  ok = gencache_parse(key_upper, namemap_cache_find_name_parser, &state);
319
0
  if (!ok) {
320
0
    DBG_DEBUG("gencache_parse(%s) failed\n", key_upper);
321
0
    goto fail;
322
0
  }
323
324
0
  if (!state.ok) {
325
0
    DBG_DEBUG("Could not parse %s, deleting\n", key_upper);
326
0
    goto fail;
327
0
  }
328
329
0
  ret = true;
330
0
fail:
331
  TALLOC_FREE(key);
332
0
  return ret;
333
0
}