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