r21998: Fix tdb keynames in netsamlogon_clear_cached_user().
[tprouty/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    
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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         return True;
55 }
56
57 /***********************************************************************
58  Clear cache getpwnam and getgroups entries from the winbindd cache
59 ***********************************************************************/
60 void netsamlogon_clear_cached_user(TDB_CONTEXT *tdb, NET_USER_INFO_3 *user)
61 {
62         TDB_DATA key;
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, &user->dom_sid.sid);
82         sid_append_rid(&sid, user->user_rid);
83
84         /* Clear U/SID cache entry */
85
86         fstr_sprintf(key_str, "U/%s", sid_to_string(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_string(sid_string, &sid));
95
96         DEBUG(10, ("netsamlogon_clear_cached_user: clearing %s\n", key.dptr));
97
98         tdb_delete(tdb, string_tdb_data(key_str));
99
100         if (got_tdb)
101                 tdb_close(tdb);
102 }
103
104 /***********************************************************************
105  Store a NET_USER_INFO_3 structure in a tdb for later user 
106  username should be in UTF-8 format
107 ***********************************************************************/
108
109 BOOL netsamlogon_cache_store( const char *username, NET_USER_INFO_3 *user )
110 {
111         TDB_DATA        data;
112         fstring         keystr;
113         prs_struct      ps;
114         BOOL            result = False;
115         DOM_SID         user_sid;
116         time_t          t = time(NULL);
117         TALLOC_CTX      *mem_ctx;
118         
119
120         if (!netsamlogon_cache_init()) {
121                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB));
122                 return False;
123         }
124
125         sid_copy( &user_sid, &user->dom_sid.sid );
126         sid_append_rid( &user_sid, user->user_rid );
127
128         /* Prepare key as DOMAIN-SID/USER-RID string */
129         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(&user_sid));
130
131         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
132         
133         /* only Samba fills in the username, not sure why NT doesn't */
134         /* so we fill it in since winbindd_getpwnam() makes use of it */
135         
136         if ( !user->uni_user_name.buffer ) {
137                 init_unistr2( &user->uni_user_name, username, UNI_STR_TERMINATE );
138                 init_uni_hdr( &user->hdr_user_name, &user->uni_user_name );
139         }
140                 
141         /* Prepare data */
142         
143         if ( !(mem_ctx = TALLOC_P( NULL, int )) ) {
144                 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
145                 return False;
146         }
147
148         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
149         
150         {
151                 uint32 ts = (uint32)t;
152                 if ( !prs_uint32( "timestamp", &ps, 0, &ts ) )
153                         return False;
154         }
155         
156         if ( net_io_user_info3("", user, &ps, 0, 3, 0) ) 
157         {
158                 data.dsize = prs_offset( &ps );
159                 data.dptr = prs_data_p( &ps );
160
161                 if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1)
162                         result = True;
163                 
164                 prs_mem_free( &ps );
165         }
166
167         TALLOC_FREE( mem_ctx );
168                 
169         return result;
170 }
171
172 /***********************************************************************
173  Retrieves a NET_USER_INFO_3 structure from a tdb.  Caller must 
174  free the user_info struct (malloc()'d memory)
175 ***********************************************************************/
176
177 NET_USER_INFO_3* netsamlogon_cache_get( TALLOC_CTX *mem_ctx, const DOM_SID *user_sid)
178 {
179         NET_USER_INFO_3 *user = NULL;
180         TDB_DATA        data;
181         prs_struct      ps;
182         fstring         keystr;
183         uint32          t;
184         
185         if (!netsamlogon_cache_init()) {
186                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n", NETSAMLOGON_TDB));
187                 return False;
188         }
189
190         /* Prepare key as DOMAIN-SID/USER-RID string */
191         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(user_sid));
192         DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
193         data = tdb_fetch_bystring( netsamlogon_tdb, keystr );
194         
195         if ( data.dptr ) {
196                 
197                 if ( (user = SMB_MALLOC_P(NET_USER_INFO_3)) == NULL )
198                         return NULL;
199                         
200                 prs_init( &ps, 0, mem_ctx, UNMARSHALL );
201                 prs_give_memory( &ps, data.dptr, data.dsize, True );
202                 
203                 if ( !prs_uint32( "timestamp", &ps, 0, &t ) ) {
204                         prs_mem_free( &ps );
205                         SAFE_FREE(user);
206                         return False;
207                 }
208                 
209                 if ( !net_io_user_info3("", user, &ps, 0, 3, 0) ) {
210                         SAFE_FREE( user );
211                 }
212                         
213                 prs_mem_free( &ps );
214
215 #if 0   /* The netsamlogon cache needs to hang around.  Something about 
216            this feels wrong, but it is the only way we can get all of the
217            groups.  The old universal groups cache didn't expire either.
218            --jerry */
219         {
220                 time_t          now = time(NULL);
221                 uint32          time_diff;
222            
223                 /* is the entry expired? */
224                 time_diff = now - t;
225                 
226                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
227                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
228                         tdb_delete( netsamlogon_tdb, key );
229                         SAFE_FREE( user );
230                 }
231 #endif
232         }
233         
234         return user;
235 }
236
237 BOOL netsamlogon_cache_have(const DOM_SID *user_sid)
238 {
239         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
240         NET_USER_INFO_3 *user = NULL;
241         BOOL result;
242
243         if (!mem_ctx)
244                 return False;
245
246         user = netsamlogon_cache_get(mem_ctx, user_sid);
247
248         result = (user != NULL);
249
250         talloc_destroy(mem_ctx);
251         SAFE_FREE(user);
252
253         return result;
254 }