s3-net: let rpccli_winreg_Connect optionally return WERROR
[Samba.git] / source3 / libsmb / samlogon_cache.c
blob7f096ece76f1909dbaf2c1a816fc4b7c65285cfd
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 "librpc/gen_ndr/ndr_krb5pac.h"
27 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
29 static TDB_CONTEXT *netsamlogon_tdb = NULL;
31 /***********************************************************************
32 open the tdb
33 ***********************************************************************/
35 bool netsamlogon_cache_init(void)
37 bool first_try = true;
38 const char *path = NULL;
39 int ret;
40 struct tdb_context *tdb;
42 if (netsamlogon_tdb) {
43 return true;
46 path = cache_path(NETSAMLOGON_TDB);
47 again:
48 tdb = tdb_open_log(path, 0, TDB_DEFAULT,
49 O_RDWR | O_CREAT, 0600);
50 if (tdb == NULL) {
51 DEBUG(0,("tdb_open_log('%s') - failed\n", path));
52 goto clear;
55 ret = tdb_check(tdb, NULL, NULL);
56 if (ret != 0) {
57 tdb_close(tdb);
58 DEBUG(0,("tdb_check('%s') - failed\n", path));
59 goto clear;
62 netsamlogon_tdb = tdb;
63 return true;
65 clear:
66 if (!first_try) {
67 return false;
69 first_try = false;
71 DEBUG(0,("retry after CLEAR_IF_FIRST for '%s'\n", path));
72 tdb = tdb_open_log(path, 0, TDB_CLEAR_IF_FIRST,
73 O_RDWR | O_CREAT, 0600);
74 if (tdb) {
75 tdb_close(tdb);
76 goto again;
78 DEBUG(0,("tdb_open_log(%s) with CLEAR_IF_FIRST - failed\n", path));
80 return false;
84 /***********************************************************************
85 Shutdown samlogon_cache database
86 ***********************************************************************/
88 bool netsamlogon_cache_shutdown(void)
90 if (netsamlogon_tdb) {
91 return (tdb_close(netsamlogon_tdb) == 0);
94 return true;
97 /***********************************************************************
98 Clear cache getpwnam and getgroups entries from the winbindd cache
99 ***********************************************************************/
101 void netsamlogon_clear_cached_user(struct netr_SamInfo3 *info3)
103 struct dom_sid user_sid;
104 fstring keystr, tmp;
106 if (!info3) {
107 return;
110 if (!netsamlogon_cache_init()) {
111 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
112 "%s for write!\n",
113 NETSAMLOGON_TDB));
114 return;
116 sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
118 /* Prepare key as DOMAIN-SID/USER-RID string */
119 slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
121 DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
123 tdb_delete_bystring(netsamlogon_tdb, keystr);
126 /***********************************************************************
127 Store a netr_SamInfo3 structure in a tdb for later user
128 username should be in UTF-8 format
129 ***********************************************************************/
131 bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
133 TDB_DATA data;
134 fstring keystr, tmp;
135 bool result = false;
136 struct dom_sid user_sid;
137 time_t t = time(NULL);
138 TALLOC_CTX *mem_ctx;
139 DATA_BLOB blob;
140 enum ndr_err_code ndr_err;
141 struct netsamlogoncache_entry r;
143 if (!info3) {
144 return false;
147 if (!netsamlogon_cache_init()) {
148 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
149 NETSAMLOGON_TDB));
150 return false;
153 sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
155 /* Prepare key as DOMAIN-SID/USER-RID string */
156 slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
158 DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
160 /* Prepare data */
162 if (!(mem_ctx = TALLOC_P( NULL, int))) {
163 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
164 return false;
167 /* only Samba fills in the username, not sure why NT doesn't */
168 /* so we fill it in since winbindd_getpwnam() makes use of it */
170 if (!info3->base.account_name.string) {
171 info3->base.account_name.string = talloc_strdup(info3, username);
174 r.timestamp = t;
175 r.info3 = *info3;
177 if (DEBUGLEVEL >= 10) {
178 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
181 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &r,
182 (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
183 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
184 DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
185 TALLOC_FREE(mem_ctx);
186 return false;
189 data.dsize = blob.length;
190 data.dptr = blob.data;
192 if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) {
193 result = true;
196 TALLOC_FREE(mem_ctx);
198 return result;
201 /***********************************************************************
202 Retrieves a netr_SamInfo3 structure from a tdb. Caller must
203 free the user_info struct (malloc()'d memory)
204 ***********************************************************************/
206 struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
208 struct netr_SamInfo3 *info3 = NULL;
209 TDB_DATA data;
210 fstring keystr, tmp;
211 enum ndr_err_code ndr_err;
212 DATA_BLOB blob;
213 struct netsamlogoncache_entry r;
215 if (!netsamlogon_cache_init()) {
216 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
217 NETSAMLOGON_TDB));
218 return false;
221 /* Prepare key as DOMAIN-SID/USER-RID string */
222 slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, user_sid));
223 DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
224 data = tdb_fetch_bystring( netsamlogon_tdb, keystr );
226 if (!data.dptr) {
227 return NULL;
230 info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
231 if (!info3) {
232 goto done;
235 blob = data_blob_const(data.dptr, data.dsize);
237 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
238 (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
240 if (DEBUGLEVEL >= 10) {
241 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
244 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
245 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
246 tdb_delete(netsamlogon_tdb, data);
247 TALLOC_FREE(info3);
248 goto done;
251 info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
252 sizeof(r.info3));
254 done:
255 SAFE_FREE(data.dptr);
257 return info3;
259 #if 0 /* The netsamlogon cache needs to hang around. Something about
260 this feels wrong, but it is the only way we can get all of the
261 groups. The old universal groups cache didn't expire either.
262 --jerry */
264 time_t now = time(NULL);
265 uint32 time_diff;
267 /* is the entry expired? */
268 time_diff = now - t;
270 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
271 DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
272 tdb_delete( netsamlogon_tdb, key );
273 TALLOC_FREE( user );
276 #endif
279 bool netsamlogon_cache_have(const struct dom_sid *user_sid)
281 TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
282 struct netr_SamInfo3 *info3 = NULL;
283 bool result;
285 if (!mem_ctx)
286 return False;
288 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
290 result = (info3 != NULL);
292 talloc_destroy(mem_ctx);
294 return result;