/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 | } |