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