s3:samlogon_cache: fix O3 error unused result of truncate
[metze/samba/wip.git] / source3 / libsmb / samlogon_cache.c
1 /*
2    Unix SMB/CIFS implementation.
3    Net_sam_logon info3 helpers
4    Copyright (C) Alexander Bokovoy              2002.
5    Copyright (C) Andrew Bartlett                2002.
6    Copyright (C) Gerald Carter                  2003.
7    Copyright (C) Tim Potter                     2003.
8    Copyright (C) Guenther Deschner              2008.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../libcli/security/security.h"
28 #include "util_tdb.h"
29
30 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
31
32 static TDB_CONTEXT *netsamlogon_tdb = NULL;
33
34 /***********************************************************************
35  open the tdb
36  ***********************************************************************/
37
38 bool netsamlogon_cache_init(void)
39 {
40         bool first_try = true;
41         char *path = NULL;
42         int ret;
43         struct tdb_context *tdb;
44
45         if (netsamlogon_tdb) {
46                 return true;
47         }
48
49         path = cache_path(NETSAMLOGON_TDB);
50         if (path == NULL) {
51                 return false;
52         }
53 again:
54         tdb = tdb_open_log(path, 0, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
55                            O_RDWR | O_CREAT, 0600);
56         if (tdb == NULL) {
57                 DEBUG(0,("tdb_open_log('%s') - failed\n", path));
58                 goto clear;
59         }
60
61         ret = tdb_check(tdb, NULL, NULL);
62         if (ret != 0) {
63                 tdb_close(tdb);
64                 DEBUG(0,("tdb_check('%s') - failed\n", path));
65                 goto clear;
66         }
67
68         netsamlogon_tdb = tdb;
69         talloc_free(path);
70         return true;
71
72 clear:
73         if (!first_try) {
74                 talloc_free(path);
75                 return false;
76         }
77         first_try = false;
78
79         DEBUG(0,("retry after truncate for '%s'\n", path));
80         ret = truncate(path, 0);
81         if (ret == -1) {
82                 DBG_ERR("truncate failed: %s\n", strerror(errno));
83                 talloc_free(path);
84                 return false;
85         }
86
87         goto again;
88 }
89
90
91 /***********************************************************************
92  Shutdown samlogon_cache database
93 ***********************************************************************/
94
95 bool netsamlogon_cache_shutdown(void)
96 {
97         if (netsamlogon_tdb) {
98                 return (tdb_close(netsamlogon_tdb) == 0);
99         }
100
101         return true;
102 }
103
104 /***********************************************************************
105  Clear cache getpwnam and getgroups entries from the winbindd cache
106 ***********************************************************************/
107
108 void netsamlogon_clear_cached_user(const struct dom_sid *user_sid)
109 {
110         fstring keystr;
111
112         if (!netsamlogon_cache_init()) {
113                 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
114                         "%s for write!\n",
115                         NETSAMLOGON_TDB));
116                 return;
117         }
118
119         /* Prepare key as DOMAIN-SID/USER-RID string */
120         sid_to_fstring(keystr, user_sid);
121
122         DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
123
124         tdb_delete_bystring(netsamlogon_tdb, keystr);
125 }
126
127 /***********************************************************************
128  Store a netr_SamInfo3 structure in a tdb for later user
129  username should be in UTF-8 format
130 ***********************************************************************/
131
132 bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
133 {
134         TDB_DATA data;
135         fstring keystr;
136         bool result = false;
137         struct dom_sid  user_sid;
138         time_t t = time(NULL);
139         TALLOC_CTX *tmp_ctx = talloc_stackframe();
140         DATA_BLOB blob;
141         enum ndr_err_code ndr_err;
142         struct netsamlogoncache_entry r;
143
144         if (!info3) {
145                 return false;
146         }
147
148         if (!netsamlogon_cache_init()) {
149                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
150                         NETSAMLOGON_TDB));
151                 return false;
152         }
153
154         sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
155
156         /* Prepare key as DOMAIN-SID/USER-RID string */
157         sid_to_fstring(keystr, &user_sid);
158
159         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
160
161         /* Prepare data */
162
163         if (info3->base.full_name.string == NULL) {
164                 struct netr_SamInfo3 *cached_info3;
165                 const char *full_name = NULL;
166
167                 cached_info3 = netsamlogon_cache_get(tmp_ctx, &user_sid);
168                 if (cached_info3 != NULL) {
169                         full_name = cached_info3->base.full_name.string;
170                 }
171
172                 if (full_name != NULL) {
173                         info3->base.full_name.string = talloc_strdup(info3, full_name);
174                 }
175         }
176
177         /* only Samba fills in the username, not sure why NT doesn't */
178         /* so we fill it in since winbindd_getpwnam() makes use of it */
179
180         if (!info3->base.account_name.string) {
181                 info3->base.account_name.string = talloc_strdup(info3, username);
182         }
183
184         r.timestamp = t;
185         r.info3 = *info3;
186
187         if (DEBUGLEVEL >= 10) {
188                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
189         }
190
191         ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, &r,
192                                        (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
193         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
194                 DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
195                 TALLOC_FREE(tmp_ctx);
196                 return false;
197         }
198
199         data.dsize = blob.length;
200         data.dptr = blob.data;
201
202         if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) == 0) {
203                 result = true;
204         }
205
206         TALLOC_FREE(tmp_ctx);
207
208         return result;
209 }
210
211 /***********************************************************************
212  Retrieves a netr_SamInfo3 structure from a tdb.  Caller must
213  free the user_info struct (malloc()'d memory)
214 ***********************************************************************/
215
216 struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
217 {
218         struct netr_SamInfo3 *info3 = NULL;
219         TDB_DATA data;
220         fstring keystr;
221         enum ndr_err_code ndr_err;
222         DATA_BLOB blob;
223         struct netsamlogoncache_entry r;
224
225         if (!netsamlogon_cache_init()) {
226                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
227                         NETSAMLOGON_TDB));
228                 return NULL;
229         }
230
231         /* Prepare key as DOMAIN-SID/USER-RID string */
232         sid_to_fstring(keystr, user_sid);
233         DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
234         data = tdb_fetch_bystring( netsamlogon_tdb, keystr );
235
236         if (!data.dptr) {
237                 return NULL;
238         }
239
240         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
241         if (!info3) {
242                 goto done;
243         }
244
245         blob = data_blob_const(data.dptr, data.dsize);
246
247         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
248                                       (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
249
250         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
251                 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
252                 tdb_delete_bystring(netsamlogon_tdb, keystr);
253                 TALLOC_FREE(info3);
254                 goto done;
255         }
256
257         if (DEBUGLEVEL >= 10) {
258                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
259         }
260
261         info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
262                                                       sizeof(r.info3));
263
264  done:
265         SAFE_FREE(data.dptr);
266
267         return info3;
268
269 #if 0   /* The netsamlogon cache needs to hang around.  Something about
270            this feels wrong, but it is the only way we can get all of the
271            groups.  The old universal groups cache didn't expire either.
272            --jerry */
273         {
274                 time_t          now = time(NULL);
275                 uint32_t        time_diff;
276
277                 /* is the entry expired? */
278                 time_diff = now - t;
279
280                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
281                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
282                         tdb_delete( netsamlogon_tdb, key );
283                         TALLOC_FREE( user );
284                 }
285         }
286 #endif
287 }
288
289 bool netsamlogon_cache_have(const struct dom_sid *user_sid)
290 {
291         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
292         struct netr_SamInfo3 *info3 = NULL;
293         bool result;
294
295         if (!mem_ctx)
296                 return False;
297
298         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
299
300         result = (info3 != NULL);
301
302         talloc_destroy(mem_ctx);
303
304         return result;
305 }