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