s3:lib: Use portable format specifiers
[samba.git] / source3 / lib / namemap_cache.c
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 {
35         char typebuf[16];
36         struct dom_sid_buf sidbuf;
37         char keybuf[sizeof(sidbuf.buf)+10];
38         char *val = NULL;
39         DATA_BLOB data;
40         int ret;
41         bool ok = false;
42
43         if ((sid == NULL) || is_null_sid(sid)) {
44                 return true;
45         }
46         if (domain == NULL) {
47                 domain = "";
48         }
49         if (name == NULL) {
50                 name = "";
51         }
52         if (type == SID_NAME_UNKNOWN) {
53                 domain = "";
54                 name = "";
55         }
56
57         snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
58
59         ret = strv_add(talloc_tos(), &val, domain);
60         if (ret != 0) {
61                 DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
62                 goto fail;
63         }
64         ret = strv_add(NULL, &val, name);
65         if (ret != 0) {
66                 DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
67                 goto fail;
68         }
69         ret = strv_add(NULL, &val, typebuf);
70         if (ret != 0) {
71                 DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
72                 goto fail;
73         }
74
75         dom_sid_str_buf(sid, &sidbuf);
76         snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf);
77
78         data = data_blob_const(val, talloc_get_size(val));
79
80         ok = gencache_set_data_blob(keybuf, data, timeout);
81         if (!ok) {
82                 DBG_DEBUG("gencache_set_data_blob failed\n");
83         }
84 fail:
85         TALLOC_FREE(val);
86         return ok;
87 }
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 {
104         struct namemap_cache_find_sid_state *state = private_data;
105         const char *strv = (const char *)blob.data;
106         size_t strv_len = blob.length;
107         const char *domain;
108         const char *name;
109         const char *typebuf;
110         int error = 0;
111         unsigned long type;
112
113         state->ok = false;
114
115         domain = strv_len_next(strv, strv_len, NULL);
116         if (domain == NULL) {
117                 return;
118         }
119         name = strv_len_next(strv, strv_len, domain);
120         if (name == NULL) {
121                 return;
122         }
123         typebuf = strv_len_next(strv, strv_len, name);
124         if (typebuf == NULL) {
125                 return;
126         }
127
128         type = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
129         if (error != 0) {
130                 return;
131         }
132
133         state->fn(domain,
134                   name,
135                   (enum lsa_SidType)type,
136                   gencache_timeout_expired(timeout),
137                   state->private_data);
138
139         state->ok = true;
140 }
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 {
150         struct namemap_cache_find_sid_state state = {
151                 .fn = fn, .private_data = private_data
152         };
153         struct dom_sid_buf sidbuf;
154         char keybuf[sizeof(sidbuf.buf)+10];
155         bool ok;
156
157         dom_sid_str_buf(sid, &sidbuf);
158         snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf);
159
160         ok = gencache_parse(keybuf, namemap_cache_find_sid_parser, &state);
161         if (!ok) {
162                 DBG_DEBUG("gencache_parse(%s) failed\n", keybuf);
163                 return false;
164         }
165
166         if (!state.ok) {
167                 DBG_DEBUG("Could not parse %s, deleting\n", keybuf);
168                 gencache_del(keybuf);
169                 return false;
170         }
171
172         return true;
173 }
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 {
180         char typebuf[16];
181         struct dom_sid_buf sidbuf = {{0}};
182         char *key;
183         char *key_upper;
184         char *val = NULL;
185         DATA_BLOB data;
186         int ret;
187         bool ok = false;
188
189         if (domain == NULL) {
190                 domain = "";
191         }
192         if (name == NULL) {
193                 name = "";
194         }
195         if (type != SID_NAME_UNKNOWN) {
196                 dom_sid_str_buf(sid, &sidbuf);
197         }
198
199         snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
200
201         key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
202         if (key == NULL) {
203                 DBG_DEBUG("talloc_asprintf failed\n");
204                 goto fail;
205         }
206         key_upper = strupper_talloc(key, key);
207         if (key_upper == NULL) {
208                 DBG_DEBUG("strupper_talloc failed\n");
209                 goto fail;
210         }
211
212         ret = strv_add(key, &val, sidbuf.buf);
213         if (ret != 0) {
214                 DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
215                 goto fail;
216         }
217         ret = strv_add(NULL, &val, typebuf);
218         if (ret != 0) {
219                 DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
220                 goto fail;
221         }
222
223         data = data_blob_const(val, talloc_get_size(val));
224
225         ok = gencache_set_data_blob(key_upper, data, timeout);
226         if (!ok) {
227                 DBG_DEBUG("gencache_set_data_blob failed\n");
228         }
229 fail:
230         TALLOC_FREE(key);
231         return ok;
232 }
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 {
248         struct namemap_cache_find_name_state *state = private_data;
249         const char *strv = (const char *)blob.data;
250         size_t strv_len = blob.length;
251         const char *sidbuf;
252         const char *sid_endptr;
253         const char *typebuf;
254         int error = 0;
255         struct dom_sid sid;
256         unsigned long type;
257         bool ok;
258
259         state->ok = false;
260
261         sidbuf = strv_len_next(strv, strv_len, NULL);
262         if (sidbuf == NULL) {
263                 return;
264         }
265         typebuf = strv_len_next(strv, strv_len, sidbuf);
266         if (typebuf == NULL) {
267                 return;
268         }
269
270         ok = dom_sid_parse_endp(sidbuf, &sid, &sid_endptr);
271         if (!ok) {
272                 return;
273         }
274         if (*sid_endptr != '\0') {
275                 return;
276         }
277
278         type = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
279         if (error != 0) {
280                 return;
281         }
282
283         state->fn(&sid,
284                   (enum lsa_SidType)type,
285                   gencache_timeout_expired(timeout),
286                   state->private_data);
287
288         state->ok = true;
289 }
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 {
299         struct namemap_cache_find_name_state state = {
300                 .fn = fn, .private_data = private_data
301         };
302         char *key;
303         char *key_upper;
304         bool ret = false;
305         bool ok;
306
307         key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
308         if (key == NULL) {
309                 DBG_DEBUG("talloc_asprintf failed\n");
310                 return false;
311         }
312         key_upper = strupper_talloc(key, key);
313         if (key_upper == NULL) {
314                 DBG_DEBUG("strupper_talloc failed\n");
315                 goto fail;
316         }
317
318         ok = gencache_parse(key_upper, namemap_cache_find_name_parser, &state);
319         if (!ok) {
320                 DBG_DEBUG("gencache_parse(%s) failed\n", key_upper);
321                 goto fail;
322         }
323
324         if (!state.ok) {
325                 DBG_DEBUG("Could not parse %s, deleting\n", key_upper);
326                 goto fail;
327         }
328
329         ret = true;
330 fail:
331         TALLOC_FREE(key);
332         return ret;
333 }