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