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