ldb: version 1.1.27
[Samba.git] / source3 / libsmb / samlogon_cache.c
blob7be54792fff54a80dc3b3a6bcc2fbe651b7461c6
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.
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.
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.
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/>.
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"
30 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
32 static TDB_CONTEXT *netsamlogon_tdb = NULL;
34 /***********************************************************************
35 open the tdb
36 ***********************************************************************/
38 bool netsamlogon_cache_init(void)
40 bool first_try = true;
41 char *path = NULL;
42 int ret;
43 struct tdb_context *tdb;
45 if (netsamlogon_tdb) {
46 return true;
49 path = cache_path(NETSAMLOGON_TDB);
50 if (path == NULL) {
51 return false;
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;
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;
68 netsamlogon_tdb = tdb;
69 talloc_free(path);
70 return true;
72 clear:
73 if (!first_try) {
74 talloc_free(path);
75 return false;
77 first_try = false;
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;
87 goto again;
91 /***********************************************************************
92 Shutdown samlogon_cache database
93 ***********************************************************************/
95 bool netsamlogon_cache_shutdown(void)
97 if (netsamlogon_tdb) {
98 return (tdb_close(netsamlogon_tdb) == 0);
101 return true;
104 /***********************************************************************
105 Clear cache getpwnam and getgroups entries from the winbindd cache
106 ***********************************************************************/
108 void netsamlogon_clear_cached_user(const struct dom_sid *user_sid)
110 fstring keystr;
112 if (!netsamlogon_cache_init()) {
113 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
114 "%s for write!\n",
115 NETSAMLOGON_TDB));
116 return;
119 /* Prepare key as DOMAIN-SID/USER-RID string */
120 sid_to_fstring(keystr, user_sid);
122 DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
124 tdb_delete_bystring(netsamlogon_tdb, keystr);
127 /***********************************************************************
128 Store a netr_SamInfo3 structure in a tdb for later user
129 username should be in UTF-8 format
130 ***********************************************************************/
132 bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
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;
144 if (!info3) {
145 return false;
148 if (!netsamlogon_cache_init()) {
149 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
150 NETSAMLOGON_TDB));
151 return false;
154 sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
156 /* Prepare key as DOMAIN-SID/USER-RID string */
157 sid_to_fstring(keystr, &user_sid);
159 DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
161 /* Prepare data */
163 if (info3->base.full_name.string == NULL) {
164 struct netr_SamInfo3 *cached_info3;
165 const char *full_name = NULL;
167 cached_info3 = netsamlogon_cache_get(tmp_ctx, &user_sid);
168 if (cached_info3 != NULL) {
169 full_name = cached_info3->base.full_name.string;
172 if (full_name != NULL) {
173 info3->base.full_name.string = talloc_strdup(info3, full_name);
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 */
180 if (!info3->base.account_name.string) {
181 info3->base.account_name.string = talloc_strdup(info3, username);
184 r.timestamp = t;
185 r.info3 = *info3;
187 if (DEBUGLEVEL >= 10) {
188 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
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;
199 data.dsize = blob.length;
200 data.dptr = blob.data;
202 if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) == 0) {
203 result = true;
206 TALLOC_FREE(tmp_ctx);
208 return result;
211 /***********************************************************************
212 Retrieves a netr_SamInfo3 structure from a tdb. Caller must
213 free the user_info struct (malloc()'d memory)
214 ***********************************************************************/
216 struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
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;
225 if (!netsamlogon_cache_init()) {
226 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
227 NETSAMLOGON_TDB));
228 return NULL;
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 );
236 if (!data.dptr) {
237 return NULL;
240 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
241 if (!info3) {
242 goto done;
245 blob = data_blob_const(data.dptr, data.dsize);
247 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
248 (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
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;
257 if (DEBUGLEVEL >= 10) {
258 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
261 info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
262 sizeof(r.info3));
264 done:
265 SAFE_FREE(data.dptr);
267 return info3;
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 */
274 time_t now = time(NULL);
275 uint32_t time_diff;
277 /* is the entry expired? */
278 time_diff = now - t;
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 );
286 #endif
289 bool netsamlogon_cache_have(const struct dom_sid *user_sid)
291 TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
292 struct netr_SamInfo3 *info3 = NULL;
293 bool result;
295 if (!mem_ctx)
296 return False;
298 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
300 result = (info3 != NULL);
302 talloc_destroy(mem_ctx);
304 return result;