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