2 Unix SMB/CIFS implementation.
5 Copyright (C) Volker Lendecke 2008
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.
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.
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/>.*/
21 #include "idmap_cache.h"
22 #include "../libcli/security/security.h"
23 #include "../librpc/gen_ndr/idmap.h"
26 * Find a sid2xid mapping
27 * @param[in] sid the sid to map
28 * @param[out] id where to put the result
29 * @param[out] expired is the cache entry expired?
30 * @retval Was anything in the cache at all?
32 * If id->id == -1 this was a negative mapping.
35 bool idmap_cache_find_sid2unixid(const struct dom_sid *sid, struct unixid *id,
46 key = talloc_asprintf(talloc_tos(), "IDMAP/SID2XID/%s",
47 sid_to_fstring(sidstr, sid));
51 ret = gencache_get(key, &value, &timeout);
56 tmp_id.id = strtol(value, &endptr, 10);
57 DEBUG(0, ("Parsing result of %s, endptr=%s, id=%llu\n", key, endptr, (unsigned long long)tmp_id.id));
59 ret = (*endptr == ':');
63 tmp_id.type = ID_TYPE_UID;
67 tmp_id.type = ID_TYPE_GID;
71 tmp_id.type = ID_TYPE_BOTH;
78 DEBUG(0, ("FAILED Parsing result of %s, endptr=%s, id=%llu\n", key, endptr, (unsigned long long)tmp_id.id));
81 if (endptr[2] != '\0') {
84 DEBUG(0, ("FAILED (2) Parsing result of %s, endptr=%s, id=%llu\n", key, endptr, (unsigned long long)tmp_id.id));
89 *expired = (timeout <= time(NULL));
91 DEBUG(0, ("FAILED (3) Parsing result of %s, value=%s\n", key, value));
99 * Find a sid2uid mapping
100 * @param[in] sid the sid to map
101 * @param[out] puid where to put the result
102 * @param[out] expired is the cache entry expired?
103 * @retval Was anything in the cache at all?
105 * If *puid == -1 this was a negative mapping.
108 bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
113 ret = idmap_cache_find_sid2unixid(sid, &id, expired);
118 if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_UID) {
127 * Find a sid2gid mapping
128 * @param[in] sid the sid to map
129 * @param[out] pgid where to put the result
130 * @param[out] expired is the cache entry expired?
131 * @retval Was anything in the cache at all?
133 * If *pgid == -1 this was a negative mapping.
136 bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
141 ret = idmap_cache_find_sid2unixid(sid, &id, expired);
146 if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_GID) {
155 * Find a uid2sid mapping
156 * @param[in] uid the uid to map
157 * @param[out] sid where to put the result
158 * @param[out] expired is the cache entry expired?
159 * @retval Was anything in the cache at all?
161 * If "is_null_sid(sid)", this was a negative mapping.
164 bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired)
171 key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid);
175 ret = gencache_get(key, &value, &timeout);
181 if (value[0] != '-') {
182 ret = string_to_sid(sid, value);
186 *expired = (timeout <= time(NULL));
192 * Find a gid2sid mapping
193 * @param[in] gid the gid to map
194 * @param[out] sid where to put the result
195 * @param[out] expired is the cache entry expired?
196 * @retval Was anything in the cache at all?
198 * If "is_null_sid(sid)", this was a negative mapping.
201 bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired)
208 key = talloc_asprintf(talloc_tos(), "IDMAP/GID2SID/%d", (int)gid);
212 ret = gencache_get(key, &value, &timeout);
218 if (value[0] != '-') {
219 ret = string_to_sid(sid, value);
223 *expired = (timeout <= time(NULL));
229 * Store a mapping in the idmap cache
230 * @param[in] sid the sid to map
231 * @param[in] gid the gid to map
233 * If both parameters are valid values, then a positive mapping in both
234 * directions is stored. If "is_null_sid(sid)" is true, then this will be a
235 * negative mapping of gid, we want to cache that for this gid we could not
236 * find anything. Likewise if "gid==-1", then we want to cache that we did not
237 * find a mapping for the sid passed here.
240 void idmap_cache_set_sid2unixid(const struct dom_sid *sid, struct unixid *unix_id)
242 time_t now = time(NULL);
244 fstring sidstr, key, value;
246 if (!is_null_sid(sid)) {
247 fstr_sprintf(key, "IDMAP/SID2XID/%s",
248 sid_to_fstring(sidstr, sid));
249 switch (unix_id->type) {
251 fstr_sprintf(value, "%d:U", (int)unix_id->id);
254 fstr_sprintf(value, "%d:G", (int)unix_id->id);
257 fstr_sprintf(value, "%d:B", (int)unix_id->id);
262 timeout = (unix_id->id == -1)
263 ? lp_idmap_negative_cache_time()
264 : lp_idmap_cache_time();
265 gencache_set(key, value, now + timeout);
267 if (unix_id->id != -1) {
268 if (is_null_sid(sid)) {
269 /* negative gid mapping */
271 timeout = lp_idmap_negative_cache_time();
274 sid_to_fstring(value, sid);
275 timeout = lp_idmap_cache_time();
277 switch (unix_id->type) {
279 fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)unix_id->id);
280 gencache_set(key, value, now + timeout);
281 fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)unix_id->id);
282 gencache_set(key, value, now + timeout);
286 fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)unix_id->id);
290 fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)unix_id->id);
296 gencache_set(key, value, now + timeout);
301 * Store a mapping in the idmap cache
302 * @param[in] sid the sid to map
303 * @param[in] uid the uid to map
305 * If both parameters are valid values, then a positive mapping in both
306 * directions is stored. If "is_null_sid(sid)" is true, then this will be a
307 * negative mapping of uid, we want to cache that for this uid we could not
308 * find anything. Likewise if "uid==-1", then we want to cache that we did not
309 * find a mapping for the sid passed here.
312 void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid)
315 id.type = ID_TYPE_UID;
321 /* If we were asked to invalidate this SID -> UID
322 * mapping, it was because we found out that this was
323 * not a UID at all. Do not overwrite a valid GID or
325 if (idmap_cache_find_sid2gid(sid, &tmp_gid, &expired)) {
332 idmap_cache_set_sid2unixid(sid, &id);
337 * Store a mapping in the idmap cache
338 * @param[in] sid the sid to map
339 * @param[in] gid the gid to map
341 * If both parameters are valid values, then a positive mapping in both
342 * directions is stored. If "is_null_sid(sid)" is true, then this will be a
343 * negative mapping of gid, we want to cache that for this gid we could not
344 * find anything. Likewise if "gid==-1", then we want to cache that we did not
345 * find a mapping for the sid passed here.
348 void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid)
351 id.type = ID_TYPE_GID;
357 /* If we were asked to invalidate this SID -> GID
358 * mapping, it was because we found out that this was
359 * not a GID at all. Do not overwrite a valid UID or
361 if (idmap_cache_find_sid2uid(sid, &tmp_uid, &expired)) {
368 idmap_cache_set_sid2unixid(sid, &id);
372 static char* key_xid2sid_str(TALLOC_CTX* mem_ctx, char t, const char* id) {
373 return talloc_asprintf(mem_ctx, "IDMAP/%cID2SID/%s", t, id);
376 static char* key_xid2sid(TALLOC_CTX* mem_ctx, char t, int id) {
378 snprintf(str, sizeof(str), "%d", id);
379 return key_xid2sid_str(mem_ctx, t, str);
382 static char* key_sid2xid_str(TALLOC_CTX* mem_ctx, const char* id) {
383 return talloc_asprintf(mem_ctx, "IDMAP/SID2XID/%s", id);
386 static bool idmap_cache_del_xid(char t, int xid)
388 TALLOC_CTX* mem_ctx = talloc_stackframe();
389 const char* key = key_xid2sid(mem_ctx, t, xid);
390 char* sid_str = NULL;
394 if (!gencache_get(key, &sid_str, &timeout)) {
395 DEBUG(3, ("no entry: %s\n", key));
400 if (sid_str[0] != '-') {
401 const char* sid_key = key_sid2xid_str(mem_ctx, sid_str);
402 if (!gencache_del(sid_key)) {
403 DEBUG(2, ("failed to delete: %s\n", sid_key));
406 DEBUG(5, ("delete: %s\n", sid_key));
411 if (!gencache_del(key)) {
412 DEBUG(1, ("failed to delete: %s\n", key));
415 DEBUG(5, ("delete: %s\n", key));
419 talloc_free(mem_ctx);
423 bool idmap_cache_del_uid(uid_t uid) {
424 return idmap_cache_del_xid('U', uid);
427 bool idmap_cache_del_gid(gid_t gid) {
428 return idmap_cache_del_xid('G', gid);
431 bool idmap_cache_del_sid(const struct dom_sid *sid)
433 TALLOC_CTX* mem_ctx = talloc_stackframe();
439 if (!idmap_cache_find_sid2unixid(sid, &id, &expired)) {
447 idmap_cache_del_xid('U', id.id);
448 idmap_cache_del_xid('G', id.id);
451 idmap_cache_del_xid('U', id.id);
454 idmap_cache_del_xid('G', id.id);
461 sid_key = key_sid2xid_str(mem_ctx, dom_sid_string(mem_ctx, sid));
462 if (sid_key == NULL) {
465 /* If the mapping was symmetric, then this should fail */
466 gencache_del(sid_key);
468 talloc_free(mem_ctx);