r19368: Use WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE whereever the winbindd tdb is
[jra/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         fstring domain;
63         TDB_DATA key;
64         BOOL got_tdb = False;
65
66         /* We may need to call this function from smbd which will not have
67            winbindd_cache.tdb open.  Open the tdb if a NULL is passed. */
68
69         if (!tdb) {
70                 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 
71                                    WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
72                                    TDB_DEFAULT, O_RDWR, 0600);
73                 if (!tdb) {
74                         DEBUG(5, ("netsamlogon_clear_cached_user: failed to open cache\n"));
75                         return;
76                 }
77                 got_tdb = True;
78         }
79
80         unistr2_to_ascii(domain, &user->uni_logon_dom, sizeof(domain) - 1);
81
82         /* Clear U/DOMAIN/RID cache entry */
83
84         asprintf(&key.dptr, "U/%s/%d", domain, user->user_rid);
85         key.dsize = strlen(key.dptr) - 1; /* keys are not NULL terminated */
86
87         DEBUG(10, ("netsamlogon_clear_cached_user: clearing %s\n", key.dptr));
88
89         tdb_delete(tdb, key);
90
91         SAFE_FREE(key.dptr);
92
93         /* Clear UG/DOMAIN/RID cache entry */
94
95         asprintf(&key.dptr, "UG/%s/%d", domain, user->user_rid);
96         key.dsize = strlen(key.dptr) - 1; /* keys are not NULL terminated */
97
98         DEBUG(10, ("netsamlogon_clear_cached_user: clearing %s\n", key.dptr));
99
100         tdb_delete(tdb, key);
101
102         SAFE_FREE(key.dptr);
103
104         if (got_tdb)
105                 tdb_close(tdb);
106 }
107
108 /***********************************************************************
109  Store a NET_USER_INFO_3 structure in a tdb for later user 
110  username should be in UTF-8 format
111 ***********************************************************************/
112
113 BOOL netsamlogon_cache_store( const char *username, NET_USER_INFO_3 *user )
114 {
115         TDB_DATA        data;
116         fstring         keystr;
117         prs_struct      ps;
118         BOOL            result = False;
119         DOM_SID         user_sid;
120         time_t          t = time(NULL);
121         TALLOC_CTX      *mem_ctx;
122         
123
124         if (!netsamlogon_cache_init()) {
125                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB));
126                 return False;
127         }
128
129         sid_copy( &user_sid, &user->dom_sid.sid );
130         sid_append_rid( &user_sid, user->user_rid );
131
132         /* Prepare key as DOMAIN-SID/USER-RID string */
133         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(&user_sid));
134
135         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
136         
137         /* only Samba fills in the username, not sure why NT doesn't */
138         /* so we fill it in since winbindd_getpwnam() makes use of it */
139         
140         if ( !user->uni_user_name.buffer ) {
141                 init_unistr2( &user->uni_user_name, username, UNI_STR_TERMINATE );
142                 init_uni_hdr( &user->hdr_user_name, &user->uni_user_name );
143         }
144                 
145         /* Prepare data */
146         
147         if ( !(mem_ctx = TALLOC_P( NULL, int )) ) {
148                 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
149                 return False;
150         }
151
152         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
153         
154         {
155                 uint32 ts = (uint32)t;
156                 if ( !prs_uint32( "timestamp", &ps, 0, &ts ) )
157                         return False;
158         }
159         
160         if ( net_io_user_info3("", user, &ps, 0, 3, 0) ) 
161         {
162                 data.dsize = prs_offset( &ps );
163                 data.dptr = prs_data_p( &ps );
164
165                 if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1)
166                         result = True;
167                 
168                 prs_mem_free( &ps );
169         }
170
171         TALLOC_FREE( mem_ctx );
172                 
173         return result;
174 }
175
176 /***********************************************************************
177  Retrieves a NET_USER_INFO_3 structure from a tdb.  Caller must 
178  free the user_info struct (malloc()'d memory)
179 ***********************************************************************/
180
181 NET_USER_INFO_3* netsamlogon_cache_get( TALLOC_CTX *mem_ctx, const DOM_SID *user_sid)
182 {
183         NET_USER_INFO_3 *user = NULL;
184         TDB_DATA        data, key;
185         prs_struct      ps;
186         fstring         keystr;
187         uint32          t;
188         
189         if (!netsamlogon_cache_init()) {
190                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n", NETSAMLOGON_TDB));
191                 return False;
192         }
193
194         /* Prepare key as DOMAIN-SID/USER-RID string */
195         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(user_sid));
196         DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
197         key.dptr = keystr;
198         key.dsize = strlen(keystr)+1;
199         data = tdb_fetch( netsamlogon_tdb, key );
200         
201         if ( data.dptr ) {
202                 
203                 if ( (user = SMB_MALLOC_P(NET_USER_INFO_3)) == NULL )
204                         return NULL;
205                         
206                 prs_init( &ps, 0, mem_ctx, UNMARSHALL );
207                 prs_give_memory( &ps, data.dptr, data.dsize, True );
208                 
209                 if ( !prs_uint32( "timestamp", &ps, 0, &t ) ) {
210                         prs_mem_free( &ps );
211                         SAFE_FREE(user);
212                         return False;
213                 }
214                 
215                 if ( !net_io_user_info3("", user, &ps, 0, 3, 0) ) {
216                         SAFE_FREE( user );
217                 }
218                         
219                 prs_mem_free( &ps );
220
221 #if 0   /* The netsamlogon cache needs to hang around.  Something about 
222            this feels wrong, but it is the only way we can get all of the
223            groups.  The old universal groups cache didn't expire either.
224            --jerry */
225         {
226                 time_t          now = time(NULL);
227                 uint32          time_diff;
228            
229                 /* is the entry expired? */
230                 time_diff = now - t;
231                 
232                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
233                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
234                         tdb_delete( netsamlogon_tdb, key );
235                         SAFE_FREE( user );
236                 }
237 #endif
238         }
239         
240         return user;
241 }
242
243 BOOL netsamlogon_cache_have(const DOM_SID *user_sid)
244 {
245         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
246         NET_USER_INFO_3 *user = NULL;
247         BOOL result;
248
249         if (!mem_ctx)
250                 return False;
251
252         user = netsamlogon_cache_get(mem_ctx, user_sid);
253
254         result = (user != NULL);
255
256         talloc_destroy(mem_ctx);
257         SAFE_FREE(user);
258
259         return result;
260 }