samlogoncache: Use data_blob_const in netsamlogon_cache_get.
[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(info3, 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_blob_const(data.dptr, data.dsize);
217
218         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
219                                       (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
220
221         if (DEBUGLEVEL >= 10) {
222                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
223         }
224
225         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
226                 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
227                 tdb_delete(netsamlogon_tdb, data);
228                 TALLOC_FREE(info3);
229                 goto done;
230         }
231
232         info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
233                                                       sizeof(r.info3));
234
235  done:
236         SAFE_FREE(data.dptr);
237
238         return info3;
239
240 #if 0   /* The netsamlogon cache needs to hang around.  Something about
241            this feels wrong, but it is the only way we can get all of the
242            groups.  The old universal groups cache didn't expire either.
243            --jerry */
244         {
245                 time_t          now = time(NULL);
246                 uint32          time_diff;
247
248                 /* is the entry expired? */
249                 time_diff = now - t;
250
251                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
252                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
253                         tdb_delete( netsamlogon_tdb, key );
254                         TALLOC_FREE( user );
255                 }
256         }
257 #endif
258 }
259
260 bool netsamlogon_cache_have(const DOM_SID *user_sid)
261 {
262         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
263         struct netr_SamInfo3 *info3 = NULL;
264         bool result;
265
266         if (!mem_ctx)
267                 return False;
268
269         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
270
271         result = (info3 != NULL);
272
273         talloc_destroy(mem_ctx);
274
275         return result;
276 }