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