s3:dom_sid Global replace of DOM_SID with struct dom_sid
[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 "librpc/gen_ndr/ndr_krb5pac.h"
26
27 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
28
29 static TDB_CONTEXT *netsamlogon_tdb = NULL;
30
31 /***********************************************************************
32  open the tdb
33  ***********************************************************************/
34
35 bool netsamlogon_cache_init(void)
36 {
37         bool first_try = true;
38         const char *path = NULL;
39         int ret;
40         struct tdb_context *tdb;
41
42         if (netsamlogon_tdb) {
43                 return true;
44         }
45
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;
53         }
54
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;
60         }
61
62         netsamlogon_tdb = tdb;
63         return true;
64
65 clear:
66         if (!first_try) {
67                 return false;
68         }
69         first_try = false;
70
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;
77         }
78         DEBUG(0,("tdb_open_log(%s) with CLEAR_IF_FIRST - failed\n", path));
79
80         return false;
81 }
82
83
84 /***********************************************************************
85  Shutdown samlogon_cache database
86 ***********************************************************************/
87
88 bool netsamlogon_cache_shutdown(void)
89 {
90         if (netsamlogon_tdb) {
91                 return (tdb_close(netsamlogon_tdb) == 0);
92         }
93
94         return true;
95 }
96
97 /***********************************************************************
98  Clear cache getpwnam and getgroups entries from the winbindd cache
99 ***********************************************************************/
100
101 void netsamlogon_clear_cached_user(struct netr_SamInfo3 *info3)
102 {
103         struct dom_sid  user_sid;
104         fstring keystr, tmp;
105
106         if (!info3) {
107                 return;
108         }
109
110         if (!netsamlogon_cache_init()) {
111                 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
112                         "%s for write!\n",
113                         NETSAMLOGON_TDB));
114                 return;
115         }
116         sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
117
118         /* Prepare key as DOMAIN-SID/USER-RID string */
119         slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
120
121         DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
122
123         tdb_delete_bystring(netsamlogon_tdb, keystr);
124 }
125
126 /***********************************************************************
127  Store a netr_SamInfo3 structure in a tdb for later user
128  username should be in UTF-8 format
129 ***********************************************************************/
130
131 bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
132 {
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;
142
143         if (!info3) {
144                 return false;
145         }
146
147         if (!netsamlogon_cache_init()) {
148                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
149                         NETSAMLOGON_TDB));
150                 return false;
151         }
152
153         sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
154
155         /* Prepare key as DOMAIN-SID/USER-RID string */
156         slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
157
158         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
159
160         /* Prepare data */
161
162         if (!(mem_ctx = TALLOC_P( NULL, int))) {
163                 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
164                 return false;
165         }
166
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 */
169
170         if (!info3->base.account_name.string) {
171                 info3->base.account_name.string = talloc_strdup(info3, username);
172         }
173
174         r.timestamp = t;
175         r.info3 = *info3;
176
177         if (DEBUGLEVEL >= 10) {
178                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
179         }
180
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;
187         }
188
189         data.dsize = blob.length;
190         data.dptr = blob.data;
191
192         if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) {
193                 result = true;
194         }
195
196         TALLOC_FREE(mem_ctx);
197
198         return result;
199 }
200
201 /***********************************************************************
202  Retrieves a netr_SamInfo3 structure from a tdb.  Caller must
203  free the user_info struct (malloc()'d memory)
204 ***********************************************************************/
205
206 struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
207 {
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;
214
215         if (!netsamlogon_cache_init()) {
216                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
217                         NETSAMLOGON_TDB));
218                 return false;
219         }
220
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 );
225
226         if (!data.dptr) {
227                 return NULL;
228         }
229
230         info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
231         if (!info3) {
232                 goto done;
233         }
234
235         blob = data_blob_const(data.dptr, data.dsize);
236
237         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
238                                       (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
239
240         if (DEBUGLEVEL >= 10) {
241                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
242         }
243
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;
249         }
250
251         info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
252                                                       sizeof(r.info3));
253
254  done:
255         SAFE_FREE(data.dptr);
256
257         return info3;
258
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 */
263         {
264                 time_t          now = time(NULL);
265                 uint32          time_diff;
266
267                 /* is the entry expired? */
268                 time_diff = now - t;
269
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 );
274                 }
275         }
276 #endif
277 }
278
279 bool netsamlogon_cache_have(const struct dom_sid *user_sid)
280 {
281         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
282         struct netr_SamInfo3 *info3 = NULL;
283         bool result;
284
285         if (!mem_ctx)
286                 return False;
287
288         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
289
290         result = (info3 != NULL);
291
292         talloc_destroy(mem_ctx);
293
294         return result;
295 }