s3-idmap: remove (now) unused function idmap_cache_set_sid2both()
[samba.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 #include "../librpc/gen_ndr/idmap.h"
24
25 /**
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?
31  *
32  * If id->id == -1 this was a negative mapping.
33  */
34
35 bool idmap_cache_find_sid2unixid(const struct dom_sid *sid, struct unixid *id,
36                                  bool *expired)
37 {
38         fstring sidstr;
39         char *key;
40         char *value;
41         char *endptr;
42         time_t timeout;
43         bool ret;
44         struct unixid tmp_id;
45
46         key = talloc_asprintf(talloc_tos(), "IDMAP/SID2XID/%s",
47                               sid_to_fstring(sidstr, sid));
48         if (key == NULL) {
49                 return false;
50         }
51         ret = gencache_get(key, &value, &timeout);
52         if (!ret) {
53                 TALLOC_FREE(key);
54                 return false;
55         }
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));
58
59         ret = (*endptr == ':');
60         if (ret) {
61                 switch (endptr[1]) {
62                 case 'U':
63                         tmp_id.type = ID_TYPE_UID;
64                         break;
65
66                 case 'G':
67                         tmp_id.type = ID_TYPE_GID;
68                         break;
69
70                 case 'B':
71                         tmp_id.type = ID_TYPE_BOTH;
72                         break;
73
74                 case '\0':
75                 default:
76                         TALLOC_FREE(key);
77                         SAFE_FREE(value);
78                         DEBUG(0, ("FAILED Parsing result of %s, endptr=%s, id=%llu\n", key, endptr, (unsigned long long)tmp_id.id));
79                         return false;
80                 }
81                 if (endptr[2] != '\0') {
82                         TALLOC_FREE(key);
83                         SAFE_FREE(value);
84                         DEBUG(0, ("FAILED (2) Parsing result of %s, endptr=%s, id=%llu\n", key, endptr, (unsigned long long)tmp_id.id));
85                         return false;
86                 }
87
88                 *id = tmp_id;
89                 *expired = (timeout <= time(NULL));
90         } else {
91                 DEBUG(0, ("FAILED (3) Parsing result of %s, value=%s\n", key, value));
92         }
93         TALLOC_FREE(key);
94         SAFE_FREE(value);
95         return ret;
96 }
97
98 /**
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?
104  *
105  * If *puid == -1 this was a negative mapping.
106  */
107
108 bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
109                               bool *expired)
110 {
111         bool ret;
112         struct unixid id;
113         ret = idmap_cache_find_sid2unixid(sid, &id, expired);
114         if (!ret) {
115                 return false;
116         }
117
118         if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_UID) {
119                 *puid = id.id;
120         } else {
121                 *puid = -1;
122         }
123         return true;
124 }
125
126 /**
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?
132  *
133  * If *pgid == -1 this was a negative mapping.
134  */
135
136 bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
137                               bool *expired)
138 {
139         bool ret;
140         struct unixid id;
141         ret = idmap_cache_find_sid2unixid(sid, &id, expired);
142         if (!ret) {
143                 return false;
144         }
145
146         if (id.type == ID_TYPE_BOTH || id.type == ID_TYPE_GID) {
147                 *pgid = id.id;
148         } else {
149                 *pgid = -1;
150         }
151         return true;
152 }
153
154 /**
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?
160  *
161  * If "is_null_sid(sid)", this was a negative mapping.
162  */
163
164 bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired)
165 {
166         char *key;
167         char *value;
168         time_t timeout;
169         bool ret = true;
170
171         key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid);
172         if (key == NULL) {
173                 return false;
174         }
175         ret = gencache_get(key, &value, &timeout);
176         TALLOC_FREE(key);
177         if (!ret) {
178                 return false;
179         }
180         ZERO_STRUCTP(sid);
181         if (value[0] != '-') {
182                 ret = string_to_sid(sid, value);
183         }
184         SAFE_FREE(value);
185         if (ret) {
186                 *expired = (timeout <= time(NULL));
187         }
188         return ret;
189 }
190
191 /**
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?
197  *
198  * If "is_null_sid(sid)", this was a negative mapping.
199  */
200
201 bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired)
202 {
203         char *key;
204         char *value;
205         time_t timeout;
206         bool ret = true;
207
208         key = talloc_asprintf(talloc_tos(), "IDMAP/GID2SID/%d", (int)gid);
209         if (key == NULL) {
210                 return false;
211         }
212         ret = gencache_get(key, &value, &timeout);
213         TALLOC_FREE(key);
214         if (!ret) {
215                 return false;
216         }
217         ZERO_STRUCTP(sid);
218         if (value[0] != '-') {
219                 ret = string_to_sid(sid, value);
220         }
221         SAFE_FREE(value);
222         if (ret) {
223                 *expired = (timeout <= time(NULL));
224         }
225         return ret;
226 }
227
228 /**
229  * Store a mapping in the idmap cache
230  * @param[in] sid               the sid to map
231  * @param[in] gid               the gid to map
232  *
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.
238  */
239
240 void idmap_cache_set_sid2unixid(const struct dom_sid *sid, struct unixid *unix_id)
241 {
242         time_t now = time(NULL);
243         time_t timeout;
244         fstring sidstr, key, value;
245
246         if (!is_null_sid(sid)) {
247                 fstr_sprintf(key, "IDMAP/SID2XID/%s",
248                              sid_to_fstring(sidstr, sid));
249                 switch (unix_id->type) {
250                 case ID_TYPE_UID:
251                         fstr_sprintf(value, "%d:U", (int)unix_id->id);
252                         break;
253                 case ID_TYPE_GID:
254                         fstr_sprintf(value, "%d:G", (int)unix_id->id);
255                         break;
256                 case ID_TYPE_BOTH:
257                         fstr_sprintf(value, "%d:B", (int)unix_id->id);
258                         break;
259                 default:
260                         return;
261                 }
262                 timeout = (unix_id->id == -1)
263                         ? lp_idmap_negative_cache_time()
264                         : lp_idmap_cache_time();
265                 gencache_set(key, value, now + timeout);
266         }
267         if (unix_id->id != -1) {
268                 if (is_null_sid(sid)) {
269                         /* negative gid mapping */
270                         fstrcpy(value, "-");
271                         timeout = lp_idmap_negative_cache_time();
272                 }
273                 else {
274                         sid_to_fstring(value, sid);
275                         timeout = lp_idmap_cache_time();
276                 }
277                 switch (unix_id->type) {
278                 case ID_TYPE_BOTH:
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);
283                         return;
284
285                 case ID_TYPE_UID:
286                         fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)unix_id->id);
287                         break;
288
289                 case ID_TYPE_GID:
290                         fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)unix_id->id);
291                         break;
292
293                 default:
294                         return;
295                 }
296                 gencache_set(key, value, now + timeout);
297         }
298 }
299
300 /**
301  * Store a mapping in the idmap cache
302  * @param[in] sid               the sid to map
303  * @param[in] uid               the uid to map
304  *
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.
310  */
311
312 void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid)
313 {
314         struct unixid id;
315         id.type = ID_TYPE_UID;
316         id.id = uid;
317
318         if (uid == -1) {
319                 uid_t tmp_gid;
320                 bool expired;
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
324                  * BOTH mapping */
325                 if (idmap_cache_find_sid2gid(sid, &tmp_gid, &expired)) {
326                         if (!expired) {
327                                 return;
328                         }
329                 }
330         }
331
332         idmap_cache_set_sid2unixid(sid, &id);
333         return;
334 }
335
336 /**
337  * Store a mapping in the idmap cache
338  * @param[in] sid               the sid to map
339  * @param[in] gid               the gid to map
340  *
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.
346  */
347
348 void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid)
349 {
350         struct unixid id;
351         id.type = ID_TYPE_GID;
352         id.id = gid;
353
354         if (gid == -1) {
355                 uid_t tmp_uid;
356                 bool expired;
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
360                  * BOTH mapping */
361                 if (idmap_cache_find_sid2uid(sid, &tmp_uid, &expired)) {
362                         if (!expired) {
363                                 return;
364                         }
365                 }
366         }
367
368         idmap_cache_set_sid2unixid(sid, &id);
369         return;
370 }
371
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);
374 }
375
376 static char* key_xid2sid(TALLOC_CTX* mem_ctx, char t, int id) {
377         char str[32];
378         snprintf(str, sizeof(str), "%d", id);
379         return key_xid2sid_str(mem_ctx, t, str);
380 }
381
382 static char* key_sid2xid_str(TALLOC_CTX* mem_ctx, const char* id) {
383         return talloc_asprintf(mem_ctx, "IDMAP/SID2XID/%s", id);
384 }
385
386 static bool idmap_cache_del_xid(char t, int xid)
387 {
388         TALLOC_CTX* mem_ctx = talloc_stackframe();
389         const char* key = key_xid2sid(mem_ctx, t, xid);
390         char* sid_str = NULL;
391         time_t timeout;
392         bool ret = true;
393
394         if (!gencache_get(key, &sid_str, &timeout)) {
395                 DEBUG(3, ("no entry: %s\n", key));
396                 ret = false;
397                 goto done;
398         }
399
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));
404                         ret = false;
405                 } else {
406                         DEBUG(5, ("delete: %s\n", sid_key));
407                 }
408
409         }
410
411         if (!gencache_del(key)) {
412                 DEBUG(1, ("failed to delete: %s\n", key));
413                 ret = false;
414         } else {
415                 DEBUG(5, ("delete: %s\n", key));
416         }
417
418 done:
419         talloc_free(mem_ctx);
420         return ret;
421 }
422
423 bool idmap_cache_del_uid(uid_t uid) {
424         return idmap_cache_del_xid('U', uid);
425 }
426
427 bool idmap_cache_del_gid(gid_t gid) {
428         return idmap_cache_del_xid('G', gid);
429 }
430
431 bool idmap_cache_del_sid(const struct dom_sid *sid)
432 {
433         TALLOC_CTX* mem_ctx = talloc_stackframe();
434         bool ret = true;
435         bool expired;
436         struct unixid id;
437         const char *sid_key;
438
439         if (!idmap_cache_find_sid2unixid(sid, &id, &expired)) {
440                 ret = false;
441                 goto done;
442         }
443
444         if (id.id != -1) {
445                 switch (id.type) {
446                 case ID_TYPE_BOTH:
447                         idmap_cache_del_xid('U', id.id);
448                         idmap_cache_del_xid('G', id.id);
449                         break;
450                 case ID_TYPE_UID:
451                         idmap_cache_del_xid('U', id.id);
452                         break;
453                 case ID_TYPE_GID:
454                         idmap_cache_del_xid('G', id.id);
455                         break;
456                 default:
457                         break;
458                 }
459         }
460
461         sid_key = key_sid2xid_str(mem_ctx, dom_sid_string(mem_ctx, sid));
462         if (sid_key == NULL) {
463                 return false;
464         }
465         /* If the mapping was symmetric, then this should fail */
466         gencache_del(sid_key);
467 done:
468         talloc_free(mem_ctx);
469         return ret;
470 }