Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : ID Mapping Cache
4 :
5 : Copyright (C) Volker Lendecke 2008
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.*/
19 :
20 : #include "includes.h"
21 : #include "idmap_cache.h"
22 : #include "../libcli/security/security.h"
23 : #include "../librpc/gen_ndr/idmap.h"
24 : #include "lib/gencache.h"
25 : #include "lib/util/string_wrappers.h"
26 :
27 : /**
28 : * Find a sid2xid mapping
29 : * @param[in] sid the sid to map
30 : * @param[out] id where to put the result
31 : * @param[out] expired is the cache entry expired?
32 : * @retval Was anything in the cache at all?
33 : *
34 : * If id->id == -1 this was a negative mapping.
35 : */
36 :
37 83898 : bool idmap_cache_find_sid2unixid(const struct dom_sid *sid, struct unixid *id,
38 : bool *expired)
39 : {
40 : struct dom_sid_buf sidstr;
41 : char *key;
42 83898 : char *value = NULL;
43 : char *endptr;
44 : time_t timeout;
45 : bool ret;
46 : struct unixid tmp_id;
47 :
48 83898 : key = talloc_asprintf(talloc_tos(), "IDMAP/SID2XID/%s",
49 : dom_sid_str_buf(sid, &sidstr));
50 83898 : if (key == NULL) {
51 0 : return false;
52 : }
53 83898 : ret = gencache_get(key, talloc_tos(), &value, &timeout);
54 83898 : if (!ret) {
55 4893 : goto done;
56 : }
57 :
58 79005 : DEBUG(10, ("Parsing value for key [%s]: value=[%s]\n", key, value));
59 :
60 79005 : if (value[0] == '\0') {
61 0 : DEBUG(0, ("Failed to parse value for key [%s]: "
62 : "value is empty\n", key));
63 0 : ret = false;
64 0 : goto done;
65 : }
66 :
67 79005 : tmp_id.id = strtol(value, &endptr, 10);
68 :
69 79005 : if ((value == endptr) && (tmp_id.id == 0)) {
70 0 : DEBUG(0, ("Failed to parse value for key [%s]: value[%s] does "
71 : "not start with a number\n", key, value));
72 0 : ret = false;
73 0 : goto done;
74 : }
75 :
76 79005 : DEBUG(10, ("Parsing value for key [%s]: id=[%llu], endptr=[%s]\n",
77 : key, (unsigned long long)tmp_id.id, endptr));
78 :
79 79005 : ret = (*endptr == ':');
80 79005 : if (ret) {
81 79005 : switch (endptr[1]) {
82 9505 : case 'U':
83 9505 : tmp_id.type = ID_TYPE_UID;
84 9505 : break;
85 :
86 19332 : case 'G':
87 19332 : tmp_id.type = ID_TYPE_GID;
88 19332 : break;
89 :
90 50038 : case 'B':
91 50038 : tmp_id.type = ID_TYPE_BOTH;
92 50038 : break;
93 :
94 130 : case 'N':
95 130 : tmp_id.type = ID_TYPE_NOT_SPECIFIED;
96 130 : break;
97 :
98 0 : case '\0':
99 0 : DEBUG(0, ("FAILED to parse value for key [%s] "
100 : "(id=[%llu], endptr=[%s]): "
101 : "no type character after colon\n",
102 : key, (unsigned long long)tmp_id.id, endptr));
103 0 : ret = false;
104 0 : goto done;
105 0 : default:
106 0 : DEBUG(0, ("FAILED to parse value for key [%s] "
107 : "(id=[%llu], endptr=[%s]): "
108 : "illegal type character '%c'\n",
109 : key, (unsigned long long)tmp_id.id, endptr,
110 : endptr[1]));
111 0 : ret = false;
112 0 : goto done;
113 : }
114 79005 : if (endptr[2] != '\0') {
115 0 : DEBUG(0, ("FAILED to parse value for key [%s] "
116 : "(id=[%llu], endptr=[%s]): "
117 : "more than 1 type character after colon\n",
118 : key, (unsigned long long)tmp_id.id, endptr));
119 0 : ret = false;
120 0 : goto done;
121 : }
122 :
123 79005 : *id = tmp_id;
124 79005 : *expired = (timeout <= time(NULL));
125 : } else {
126 0 : DEBUG(0, ("FAILED to parse value for key [%s] (value=[%s]): "
127 : "colon missing after id=[%llu]\n",
128 : key, value, (unsigned long long)tmp_id.id));
129 : }
130 :
131 83898 : done:
132 83898 : TALLOC_FREE(key);
133 83898 : TALLOC_FREE(value);
134 83898 : return ret;
135 : }
136 :
137 : /**
138 : * Find a sid2uid mapping
139 : * @param[in] sid the sid to map
140 : * @param[out] puid where to put the result
141 : * @param[out] expired is the cache entry expired?
142 : * @retval Was anything in the cache at all?
143 : *
144 : * If *puid == -1 this was a negative mapping.
145 : */
146 :
147 4254 : bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
148 : bool *expired)
149 : {
150 : bool ret;
151 : struct unixid id;
152 4254 : ret = idmap_cache_find_sid2unixid(sid, &id, expired);
153 4254 : if (!ret) {
154 948 : return false;
155 : }
156 :
157 3306 : if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_UID) {
158 3286 : *puid = id.id;
159 : } else {
160 20 : *puid = -1;
161 : }
162 3306 : return true;
163 : }
164 :
165 : /**
166 : * Find a sid2gid mapping
167 : * @param[in] sid the sid to map
168 : * @param[out] pgid where to put the result
169 : * @param[out] expired is the cache entry expired?
170 : * @retval Was anything in the cache at all?
171 : *
172 : * If *pgid == -1 this was a negative mapping.
173 : */
174 :
175 2385 : bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
176 : bool *expired)
177 : {
178 : bool ret;
179 : struct unixid id;
180 2385 : ret = idmap_cache_find_sid2unixid(sid, &id, expired);
181 2385 : if (!ret) {
182 301 : return false;
183 : }
184 :
185 2084 : if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_GID) {
186 2078 : *pgid = id.id;
187 : } else {
188 6 : *pgid = -1;
189 : }
190 2084 : return true;
191 : }
192 :
193 : struct idmap_cache_xid2sid_state {
194 : struct dom_sid *sid;
195 : bool *expired;
196 : bool ret;
197 : };
198 :
199 40545 : static void idmap_cache_xid2sid_parser(const struct gencache_timeout *timeout,
200 : DATA_BLOB blob,
201 : void *private_data)
202 : {
203 40545 : struct idmap_cache_xid2sid_state *state =
204 : (struct idmap_cache_xid2sid_state *)private_data;
205 : char *value;
206 :
207 40545 : if ((blob.length == 0) || (blob.data[blob.length-1] != 0)) {
208 : /*
209 : * Not a string, can't be a valid mapping
210 : */
211 0 : state->ret = false;
212 0 : return;
213 : }
214 :
215 40545 : value = (char *)blob.data;
216 :
217 40545 : if ((value[0] == '-') && (value[1] == '\0')) {
218 : /*
219 : * Return NULL SID, see comment to uid2sid
220 : */
221 5284 : *state->sid = (struct dom_sid) {0};
222 5284 : state->ret = true;
223 : } else {
224 35261 : state->ret = string_to_sid(state->sid, value);
225 : }
226 40545 : if (state->ret) {
227 40545 : *state->expired = gencache_timeout_expired(timeout);
228 : }
229 : }
230 :
231 : /**
232 : * Find a xid2sid mapping
233 : * @param[in] id the unix id to map
234 : * @param[out] sid where to put the result
235 : * @param[out] expired is the cache entry expired?
236 : * @retval Was anything in the cache at all?
237 : *
238 : * If "is_null_sid(sid)", this was a negative mapping.
239 : */
240 45384 : bool idmap_cache_find_xid2sid(
241 : const struct unixid *id, struct dom_sid *sid, bool *expired)
242 : {
243 45384 : struct idmap_cache_xid2sid_state state = {
244 : .sid = sid, .expired = expired
245 : };
246 : fstring key;
247 : char c;
248 :
249 45384 : switch (id->type) {
250 20054 : case ID_TYPE_UID:
251 20054 : c = 'U';
252 20054 : break;
253 25330 : case ID_TYPE_GID:
254 25330 : c = 'G';
255 25330 : break;
256 0 : default:
257 0 : return false;
258 : }
259 :
260 45384 : fstr_sprintf(key, "IDMAP/%cID2SID/%d", c, (int)id->id);
261 :
262 45384 : gencache_parse(key, idmap_cache_xid2sid_parser, &state);
263 45384 : return state.ret;
264 : }
265 :
266 :
267 : /**
268 : * Store a mapping in the idmap cache
269 : * @param[in] sid the sid to map
270 : * @param[in] unix_id the unix_id to map
271 : *
272 : * If both parameters are valid values, then a positive mapping in both
273 : * directions is stored. If "is_null_sid(sid)" is true, then this will be a
274 : * negative mapping of xid, we want to cache that for this xid we could not
275 : * find anything. Likewise if "xid==-1", then we want to cache that we did not
276 : * find a mapping for the sid passed here.
277 : */
278 :
279 1890 : void idmap_cache_set_sid2unixid(const struct dom_sid *sid, struct unixid *unix_id)
280 : {
281 1890 : time_t now = time(NULL);
282 : time_t timeout;
283 : fstring key, value;
284 :
285 1890 : if (!is_null_sid(sid)) {
286 : struct dom_sid_buf sidstr;
287 1766 : fstr_sprintf(key, "IDMAP/SID2XID/%s",
288 : dom_sid_str_buf(sid, &sidstr));
289 1766 : switch (unix_id->type) {
290 271 : case ID_TYPE_UID:
291 271 : fstr_sprintf(value, "%d:U", (int)unix_id->id);
292 271 : break;
293 541 : case ID_TYPE_GID:
294 541 : fstr_sprintf(value, "%d:G", (int)unix_id->id);
295 541 : break;
296 877 : case ID_TYPE_BOTH:
297 877 : fstr_sprintf(value, "%d:B", (int)unix_id->id);
298 877 : break;
299 77 : case ID_TYPE_NOT_SPECIFIED:
300 77 : fstr_sprintf(value, "%d:N", (int)unix_id->id);
301 77 : break;
302 0 : default:
303 0 : return;
304 : }
305 3532 : timeout = (unix_id->id == -1)
306 77 : ? lp_idmap_negative_cache_time()
307 1843 : : lp_idmap_cache_time();
308 1766 : gencache_set(key, value, now + timeout);
309 : }
310 1890 : if (unix_id->id != -1) {
311 1813 : if (is_null_sid(sid)) {
312 : /* negative xid mapping */
313 124 : fstrcpy(value, "-");
314 124 : timeout = lp_idmap_negative_cache_time();
315 : }
316 : else {
317 1689 : sid_to_fstring(value, sid);
318 1689 : timeout = lp_idmap_cache_time();
319 : }
320 1813 : switch (unix_id->type) {
321 877 : case ID_TYPE_BOTH:
322 877 : fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)unix_id->id);
323 877 : gencache_set(key, value, now + timeout);
324 877 : fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)unix_id->id);
325 877 : gencache_set(key, value, now + timeout);
326 877 : return;
327 :
328 305 : case ID_TYPE_UID:
329 305 : fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)unix_id->id);
330 305 : break;
331 :
332 631 : case ID_TYPE_GID:
333 631 : fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)unix_id->id);
334 631 : break;
335 :
336 0 : default:
337 0 : return;
338 : }
339 936 : gencache_set(key, value, now + timeout);
340 : }
341 : }
342 :
343 0 : static char* key_xid2sid_str(TALLOC_CTX* mem_ctx, char t, const char* id) {
344 0 : return talloc_asprintf(mem_ctx, "IDMAP/%cID2SID/%s", t, id);
345 : }
346 :
347 0 : static char* key_xid2sid(TALLOC_CTX* mem_ctx, char t, int id) {
348 : char str[32];
349 0 : snprintf(str, sizeof(str), "%d", id);
350 0 : return key_xid2sid_str(mem_ctx, t, str);
351 : }
352 :
353 0 : static char* key_sid2xid_str(TALLOC_CTX* mem_ctx, const char* id) {
354 0 : return talloc_asprintf(mem_ctx, "IDMAP/SID2XID/%s", id);
355 : }
356 :
357 0 : static bool idmap_cache_del_xid(char t, int xid)
358 : {
359 0 : TALLOC_CTX* mem_ctx = talloc_stackframe();
360 0 : const char* key = key_xid2sid(mem_ctx, t, xid);
361 0 : char* sid_str = NULL;
362 : time_t timeout;
363 0 : bool ret = true;
364 :
365 0 : if (!gencache_get(key, mem_ctx, &sid_str, &timeout)) {
366 0 : DEBUG(3, ("no entry: %s\n", key));
367 0 : ret = false;
368 0 : goto done;
369 : }
370 :
371 0 : if (sid_str[0] != '-') {
372 0 : const char* sid_key = key_sid2xid_str(mem_ctx, sid_str);
373 0 : if (!gencache_del(sid_key)) {
374 0 : DEBUG(2, ("failed to delete: %s\n", sid_key));
375 0 : ret = false;
376 : } else {
377 0 : DEBUG(5, ("delete: %s\n", sid_key));
378 : }
379 :
380 : }
381 :
382 0 : if (!gencache_del(key)) {
383 0 : DEBUG(1, ("failed to delete: %s\n", key));
384 0 : ret = false;
385 : } else {
386 0 : DEBUG(5, ("delete: %s\n", key));
387 : }
388 :
389 0 : done:
390 0 : talloc_free(mem_ctx);
391 0 : return ret;
392 : }
393 :
394 0 : bool idmap_cache_del_uid(uid_t uid) {
395 0 : return idmap_cache_del_xid('U', uid);
396 : }
397 :
398 0 : bool idmap_cache_del_gid(gid_t gid) {
399 0 : return idmap_cache_del_xid('G', gid);
400 : }
401 :
402 0 : bool idmap_cache_del_sid(const struct dom_sid *sid)
403 : {
404 0 : TALLOC_CTX* mem_ctx = talloc_stackframe();
405 0 : bool ret = true;
406 : bool expired;
407 : struct unixid id;
408 : struct dom_sid_buf sidbuf;
409 : const char *sid_key;
410 :
411 0 : if (!idmap_cache_find_sid2unixid(sid, &id, &expired)) {
412 0 : ret = false;
413 0 : goto done;
414 : }
415 :
416 0 : if (id.id != -1) {
417 0 : switch (id.type) {
418 0 : case ID_TYPE_BOTH:
419 0 : idmap_cache_del_xid('U', id.id);
420 0 : idmap_cache_del_xid('G', id.id);
421 0 : break;
422 0 : case ID_TYPE_UID:
423 0 : idmap_cache_del_xid('U', id.id);
424 0 : break;
425 0 : case ID_TYPE_GID:
426 0 : idmap_cache_del_xid('G', id.id);
427 0 : break;
428 0 : default:
429 0 : break;
430 : }
431 0 : }
432 :
433 0 : sid_key = key_sid2xid_str(mem_ctx, dom_sid_str_buf(sid, &sidbuf));
434 0 : if (sid_key == NULL) {
435 0 : return false;
436 : }
437 : /* If the mapping was symmetric, then this should fail */
438 0 : gencache_del(sid_key);
439 0 : done:
440 0 : talloc_free(mem_ctx);
441 0 : return ret;
442 : }
|