s3-includes: only include system/filesys.h when needed.
[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
29 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
30
31 static TDB_CONTEXT *netsamlogon_tdb = NULL;
32
33 /***********************************************************************
34  open the tdb
35  ***********************************************************************/
36
37 bool netsamlogon_cache_init(void)
38 {
39         bool first_try = true;
40         const char *path = NULL;
41         int ret;
42         struct tdb_context *tdb;
43
44         if (netsamlogon_tdb) {
45                 return true;
46         }
47
48         path = cache_path(NETSAMLOGON_TDB);
49 again:
50         tdb = tdb_open_log(path, 0, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
51                            O_RDWR | O_CREAT, 0600);
52         if (tdb == NULL) {
53                 DEBUG(0,("tdb_open_log('%s') - failed\n", path));
54                 goto clear;
55         }
56
57         ret = tdb_check(tdb, NULL, NULL);
58         if (ret != 0) {
59                 tdb_close(tdb);
60                 DEBUG(0,("tdb_check('%s') - failed\n", path));
61                 goto clear;
62         }
63
64         netsamlogon_tdb = tdb;
65         return true;
66
67 clear:
68         if (!first_try) {
69                 return false;
70         }
71         first_try = false;
72
73         DEBUG(0,("retry after CLEAR_IF_FIRST for '%s'\n", path));
74         tdb = tdb_open_log(path, 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
75                            O_RDWR | O_CREAT, 0600);
76         if (tdb) {
77                 tdb_close(tdb);
78                 goto again;
79         }
80         DEBUG(0,("tdb_open_log(%s) with CLEAR_IF_FIRST - failed\n", path));
81
82         return false;
83 }
84
85
86 /***********************************************************************
87  Shutdown samlogon_cache database
88 ***********************************************************************/
89
90 bool netsamlogon_cache_shutdown(void)
91 {
92         if (netsamlogon_tdb) {
93                 return (tdb_close(netsamlogon_tdb) == 0);
94         }
95
96         return true;
97 }
98
99 /***********************************************************************
100  Clear cache getpwnam and getgroups entries from the winbindd cache
101 ***********************************************************************/
102
103 void netsamlogon_clear_cached_user(const struct dom_sid *user_sid)
104 {
105         fstring keystr;
106
107         if (!netsamlogon_cache_init()) {
108                 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
109                         "%s for write!\n",
110                         NETSAMLOGON_TDB));
111                 return;
112         }
113
114         /* Prepare key as DOMAIN-SID/USER-RID string */
115         sid_to_fstring(keystr, user_sid);
116
117         DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
118
119         tdb_delete_bystring(netsamlogon_tdb, keystr);
120 }
121
122 /***********************************************************************
123  Store a netr_SamInfo3 structure in a tdb for later user
124  username should be in UTF-8 format
125 ***********************************************************************/
126
127 bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
128 {
129         TDB_DATA data;
130         fstring keystr;
131         bool result = false;
132         struct dom_sid  user_sid;
133         time_t t = time(NULL);
134         TALLOC_CTX *mem_ctx;
135         DATA_BLOB blob;
136         enum ndr_err_code ndr_err;
137         struct netsamlogoncache_entry r;
138
139         if (!info3) {
140                 return false;
141         }
142
143         if (!netsamlogon_cache_init()) {
144                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
145                         NETSAMLOGON_TDB));
146                 return false;
147         }
148
149         sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
150
151         /* Prepare key as DOMAIN-SID/USER-RID string */
152         sid_to_fstring(keystr, &user_sid);
153
154         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
155
156         /* Prepare data */
157
158         if (!(mem_ctx = TALLOC_P( NULL, int))) {
159                 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
160                 return false;
161         }
162
163         /* only Samba fills in the username, not sure why NT doesn't */
164         /* so we fill it in since winbindd_getpwnam() makes use of it */
165
166         if (!info3->base.account_name.string) {
167                 info3->base.account_name.string = talloc_strdup(info3, username);
168         }
169
170         r.timestamp = t;
171         r.info3 = *info3;
172
173         if (DEBUGLEVEL >= 10) {
174                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
175         }
176
177         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &r,
178                                        (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
179         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
180                 DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
181                 TALLOC_FREE(mem_ctx);
182                 return false;
183         }
184
185         data.dsize = blob.length;
186         data.dptr = blob.data;
187
188         if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) {
189                 result = true;
190         }
191
192         TALLOC_FREE(mem_ctx);
193
194         return result;
195 }
196
197 /***********************************************************************
198  Retrieves a netr_SamInfo3 structure from a tdb.  Caller must
199  free the user_info struct (malloc()'d memory)
200 ***********************************************************************/
201
202 struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
203 {
204         struct netr_SamInfo3 *info3 = NULL;
205         TDB_DATA data;
206         fstring keystr, tmp;
207         enum ndr_err_code ndr_err;
208         DATA_BLOB blob;
209         struct netsamlogoncache_entry r;
210
211         if (!netsamlogon_cache_init()) {
212                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
213                         NETSAMLOGON_TDB));
214                 return false;
215         }
216
217         /* Prepare key as DOMAIN-SID/USER-RID string */
218         slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, user_sid));
219         DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
220         data = tdb_fetch_bystring( netsamlogon_tdb, keystr );
221
222         if (!data.dptr) {
223                 return NULL;
224         }
225
226         info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
227         if (!info3) {
228                 goto done;
229         }
230
231         blob = data_blob_const(data.dptr, data.dsize);
232
233         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
234                                       (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
235
236         if (DEBUGLEVEL >= 10) {
237                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
238         }
239
240         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
241                 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
242                 tdb_delete(netsamlogon_tdb, data);
243                 TALLOC_FREE(info3);
244                 goto done;
245         }
246
247         info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
248                                                       sizeof(r.info3));
249
250  done:
251         SAFE_FREE(data.dptr);
252
253         return info3;
254
255 #if 0   /* The netsamlogon cache needs to hang around.  Something about
256            this feels wrong, but it is the only way we can get all of the
257            groups.  The old universal groups cache didn't expire either.
258            --jerry */
259         {
260                 time_t          now = time(NULL);
261                 uint32          time_diff;
262
263                 /* is the entry expired? */
264                 time_diff = now - t;
265
266                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
267                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
268                         tdb_delete( netsamlogon_tdb, key );
269                         TALLOC_FREE( user );
270                 }
271         }
272 #endif
273 }
274
275 bool netsamlogon_cache_have(const struct dom_sid *user_sid)
276 {
277         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
278         struct netr_SamInfo3 *info3 = NULL;
279         bool result;
280
281         if (!mem_ctx)
282                 return False;
283
284         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
285
286         result = (info3 != NULL);
287
288         talloc_destroy(mem_ctx);
289
290         return result;
291 }