s3: adjust loglevel for idmap_cache
[nivanova/samba-autobuild/.git] / source3 / lib / idmap_cache.c
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
24 /**
25  * Find a sid2uid mapping
26  * @param[in] sid               the sid to map
27  * @param[out] puid             where to put the result
28  * @param[out] expired          is the cache entry expired?
29  * @retval Was anything in the cache at all?
30  *
31  * If *puid == -1 this was a negative mapping.
32  */
33
34 bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
35                               bool *expired)
36 {
37         fstring sidstr;
38         char *key;
39         char *value;
40         char *endptr;
41         time_t timeout;
42         uid_t uid;
43         bool ret;
44
45         key = talloc_asprintf(talloc_tos(), "IDMAP/SID2UID/%s",
46                               sid_to_fstring(sidstr, sid));
47         if (key == NULL) {
48                 return false;
49         }
50         ret = gencache_get(key, &value, &timeout);
51         TALLOC_FREE(key);
52         if (!ret) {
53                 return false;
54         }
55         uid = strtol(value, &endptr, 10);
56         ret = (*endptr == '\0');
57         SAFE_FREE(value);
58         if (ret) {
59                 *puid = uid;
60                 *expired = (timeout <= time(NULL));
61         }
62         return ret;
63 }
64
65 /**
66  * Find a uid2sid mapping
67  * @param[in] uid               the uid to map
68  * @param[out] sid              where to put the result
69  * @param[out] expired          is the cache entry expired?
70  * @retval Was anything in the cache at all?
71  *
72  * If "is_null_sid(sid)", this was a negative mapping.
73  */
74
75 bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired)
76 {
77         char *key;
78         char *value;
79         time_t timeout;
80         bool ret = true;
81
82         key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid);
83         if (key == NULL) {
84                 return false;
85         }
86         ret = gencache_get(key, &value, &timeout);
87         TALLOC_FREE(key);
88         if (!ret) {
89                 return false;
90         }
91         ZERO_STRUCTP(sid);
92         if (value[0] != '-') {
93                 ret = string_to_sid(sid, value);
94         }
95         SAFE_FREE(value);
96         if (ret) {
97                 *expired = (timeout <= time(NULL));
98         }
99         return ret;
100 }
101
102 /**
103  * Store a mapping in the idmap cache
104  * @param[in] sid               the sid to map
105  * @param[in] uid               the uid to map
106  *
107  * If both parameters are valid values, then a positive mapping in both
108  * directions is stored. If "is_null_sid(sid)" is true, then this will be a
109  * negative mapping of uid, we want to cache that for this uid we could not
110  * find anything. Likewise if "uid==-1", then we want to cache that we did not
111  * find a mapping for the sid passed here.
112  */
113
114 void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid)
115 {
116         time_t now = time(NULL);
117         time_t timeout;
118         fstring sidstr, key, value;
119
120         if (!is_null_sid(sid)) {
121                 fstr_sprintf(key, "IDMAP/SID2UID/%s",
122                              sid_to_fstring(sidstr, sid));
123                 fstr_sprintf(value, "%d", (int)uid);
124                 timeout = (uid == -1)
125                         ? lp_idmap_negative_cache_time()
126                         : lp_idmap_cache_time();
127                 gencache_set(key, value, now + timeout);
128         }
129         if (uid != -1) {
130                 fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)uid);
131                 if (is_null_sid(sid)) {
132                         /* negative uid mapping */
133                         fstrcpy(value, "-");
134                         timeout = lp_idmap_negative_cache_time();
135                 }
136                 else {
137                         sid_to_fstring(value, sid);
138                         timeout = lp_idmap_cache_time();
139                 }
140                 gencache_set(key, value, now + timeout);
141         }
142 }
143
144 /**
145  * Find a sid2gid mapping
146  * @param[in] sid               the sid to map
147  * @param[out] pgid             where to put the result
148  * @param[out] expired          is the cache entry expired?
149  * @retval Was anything in the cache at all?
150  *
151  * If *pgid == -1 this was a negative mapping.
152  */
153
154 bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
155                               bool *expired)
156 {
157         fstring sidstr;
158         char *key;
159         char *value;
160         char *endptr;
161         time_t timeout;
162         gid_t gid;
163         bool ret;
164
165         key = talloc_asprintf(talloc_tos(), "IDMAP/SID2GID/%s",
166                               sid_to_fstring(sidstr, sid));
167         if (key == NULL) {
168                 return false;
169         }
170         ret = gencache_get(key, &value, &timeout);
171         TALLOC_FREE(key);
172         if (!ret) {
173                 return false;
174         }
175         gid = strtol(value, &endptr, 10);
176         ret = (*endptr == '\0');
177         SAFE_FREE(value);
178         if (ret) {
179                 *pgid = gid;
180                 *expired = (timeout <= time(NULL));
181         }
182         return ret;
183 }
184
185 /**
186  * Find a gid2sid mapping
187  * @param[in] gid               the gid to map
188  * @param[out] sid              where to put the result
189  * @param[out] expired          is the cache entry expired?
190  * @retval Was anything in the cache at all?
191  *
192  * If "is_null_sid(sid)", this was a negative mapping.
193  */
194
195 bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired)
196 {
197         char *key;
198         char *value;
199         time_t timeout;
200         bool ret = true;
201
202         key = talloc_asprintf(talloc_tos(), "IDMAP/GID2SID/%d", (int)gid);
203         if (key == NULL) {
204                 return false;
205         }
206         ret = gencache_get(key, &value, &timeout);
207         TALLOC_FREE(key);
208         if (!ret) {
209                 return false;
210         }
211         ZERO_STRUCTP(sid);
212         if (value[0] != '-') {
213                 ret = string_to_sid(sid, value);
214         }
215         SAFE_FREE(value);
216         if (ret) {
217                 *expired = (timeout <= time(NULL));
218         }
219         return ret;
220 }
221
222 /**
223  * Store a mapping in the idmap cache
224  * @param[in] sid               the sid to map
225  * @param[in] gid               the gid to map
226  *
227  * If both parameters are valid values, then a positive mapping in both
228  * directions is stored. If "is_null_sid(sid)" is true, then this will be a
229  * negative mapping of gid, we want to cache that for this gid we could not
230  * find anything. Likewise if "gid==-1", then we want to cache that we did not
231  * find a mapping for the sid passed here.
232  */
233
234 void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid)
235 {
236         time_t now = time(NULL);
237         time_t timeout;
238         fstring sidstr, key, value;
239
240         if (!is_null_sid(sid)) {
241                 fstr_sprintf(key, "IDMAP/SID2GID/%s",
242                              sid_to_fstring(sidstr, sid));
243                 fstr_sprintf(value, "%d", (int)gid);
244                 timeout = (gid == -1)
245                         ? lp_idmap_negative_cache_time()
246                         : lp_idmap_cache_time();
247                 gencache_set(key, value, now + timeout);
248         }
249         if (gid != -1) {
250                 fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)gid);
251                 if (is_null_sid(sid)) {
252                         /* negative gid mapping */
253                         fstrcpy(value, "-");
254                         timeout = lp_idmap_negative_cache_time();
255                 }
256                 else {
257                         sid_to_fstring(value, sid);
258                         timeout = lp_idmap_cache_time();
259                 }
260                 gencache_set(key, value, now + timeout);
261         }
262 }
263
264 static char* key_xid2sid_str(TALLOC_CTX* mem_ctx, char t, const char* id) {
265         return talloc_asprintf(mem_ctx, "IDMAP/%cID2SID/%s", t, id);
266 }
267
268 static char* key_xid2sid(TALLOC_CTX* mem_ctx, char t, int id) {
269         char str[32];
270         snprintf(str, sizeof(str), "%d", id);
271         return key_xid2sid_str(mem_ctx, t, str);
272 }
273
274 static char* key_sid2xid_str(TALLOC_CTX* mem_ctx, char t, const char* sid) {
275         return talloc_asprintf(mem_ctx, "IDMAP/SID2%cID/%s", t, sid);
276 }
277
278 /* static char* key_sid2xid(TALLOC_CTX* mem_ctx, char t, const struct dom_sid* sid) */
279 /* { */
280 /*      char* sid_str = sid_string_talloc(mem_ctx, sid); */
281 /*      char* key = key_sid2xid_str(mem_ctx, t, sid_str); */
282 /*      talloc_free(sid_str); */
283 /*      return key; */
284 /* } */
285
286 static bool idmap_cache_del_xid(char t, int xid)
287 {
288         TALLOC_CTX* mem_ctx = talloc_stackframe();
289         const char* key = key_xid2sid(mem_ctx, t, xid);
290         char* sid_str = NULL;
291         time_t timeout;
292         bool ret = true;
293
294         if (!gencache_get(key, &sid_str, &timeout)) {
295                 DEBUG(3, ("no entry: %s\n", key));
296                 ret = false; //???
297                 goto done;
298         }
299
300         if (sid_str[0] != '-') {
301                 const char* sid_key = key_sid2xid_str(mem_ctx, t, sid_str);
302                 if (!gencache_del(sid_key)) {
303                         DEBUG(2, ("failed to delete: %s\n", sid_key));
304                         ret = false;
305                 } else {
306                         DEBUG(5, ("delete: %s\n", sid_key));
307                 }
308
309         }
310
311         if (!gencache_del(key)) {
312                 DEBUG(1, ("failed to delete: %s\n", key));
313                 ret = false;
314         } else {
315                 DEBUG(5, ("delete: %s\n", key));
316         }
317
318 done:
319         talloc_free(mem_ctx);
320         return ret;
321 }
322
323 bool idmap_cache_del_uid(uid_t uid) {
324         return idmap_cache_del_xid('U', uid);
325 }
326
327 bool idmap_cache_del_gid(gid_t gid) {
328         return idmap_cache_del_xid('G', gid);
329 }
330
331 static bool idmap_cache_del_sid2xid(TALLOC_CTX* mem_ctx, char t, const char* sid)
332 {
333         const char* sid_key = key_sid2xid_str(mem_ctx, t, sid);
334         char* xid_str;
335         time_t timeout;
336         bool ret = true;
337
338         if (!gencache_get(sid_key, &xid_str, &timeout)) {
339                 ret = false;
340                 goto done;
341         }
342
343         if (atoi(xid_str) != -1) {
344                 const char* xid_key = key_xid2sid_str(mem_ctx, t, xid_str);
345                 if (!gencache_del(xid_key)) {
346                         DEBUG(2, ("failed to delete: %s\n", xid_key));
347                         ret = false;
348                 } else {
349                         DEBUG(5, ("delete: %s\n", xid_key));
350                 }
351         }
352
353         if (!gencache_del(sid_key)) {
354                 DEBUG(2, ("failed to delete: %s\n", sid_key));
355                 ret = false;
356         } else {
357                 DEBUG(5, ("delete: %s\n", sid_key));
358         }
359 done:
360         return ret;
361 }
362
363 bool idmap_cache_del_sid(const struct dom_sid *sid)
364 {
365         TALLOC_CTX* mem_ctx = talloc_stackframe();
366         const char* sid_str = sid_string_talloc(mem_ctx, sid);
367         bool ret = true;
368
369         if (!idmap_cache_del_sid2xid(mem_ctx, 'U', sid_str) &&
370             !idmap_cache_del_sid2xid(mem_ctx, 'G', sid_str))
371         {
372                 DEBUG(3, ("no entry: %s\n", key_xid2sid_str(mem_ctx, '?', sid_str)));
373                 ret = false;
374         }
375
376         talloc_free(mem_ctx);
377         return ret;
378 }