Initial import
[samba] / 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    
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"), 5000,
71                                    TDB_DEFAULT, O_RDWR, 0600);
72                 if (!tdb) {
73                         DEBUG(5, ("netsamlogon_clear_cached_user: failed to open cache\n"));
74                         return;
75                 }
76                 got_tdb = True;
77         }
78
79         unistr2_to_ascii(domain, &user->uni_logon_dom, sizeof(domain) - 1);
80
81         /* Clear U/DOMAIN/RID cache entry */
82
83         asprintf(&key.dptr, "U/%s/%d", domain, user->user_rid);
84         key.dsize = strlen(key.dptr) - 1; /* keys are not NULL terminated */
85
86         DEBUG(10, ("netsamlogon_clear_cached_user: clearing %s\n", key.dptr));
87
88         tdb_delete(tdb, key);
89
90         SAFE_FREE(key.dptr);
91
92         /* Clear UG/DOMAIN/RID cache entry */
93
94         asprintf(&key.dptr, "UG/%s/%d", domain, user->user_rid);
95         key.dsize = strlen(key.dptr) - 1; /* keys are not NULL terminated */
96
97         DEBUG(10, ("netsamlogon_clear_cached_user: clearing %s\n", key.dptr));
98
99         tdb_delete(tdb, key);
100
101         SAFE_FREE(key.dptr);
102
103         if (got_tdb)
104                 tdb_close(tdb);
105 }
106
107 /***********************************************************************
108  Store a NET_USER_INFO_3 structure in a tdb for later user 
109  username should be in UTF-8 format
110 ***********************************************************************/
111
112 BOOL netsamlogon_cache_store( const char *username, NET_USER_INFO_3 *user )
113 {
114         TDB_DATA        data;
115         fstring         keystr;
116         prs_struct      ps;
117         BOOL            result = False;
118         DOM_SID         user_sid;
119         time_t          t = time(NULL);
120         TALLOC_CTX      *mem_ctx;
121         
122
123         if (!netsamlogon_cache_init()) {
124                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB));
125                 return False;
126         }
127
128         sid_copy( &user_sid, &user->dom_sid.sid );
129         sid_append_rid( &user_sid, user->user_rid );
130
131         /* Prepare key as DOMAIN-SID/USER-RID string */
132         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(&user_sid));
133
134         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
135         
136         /* only Samba fills in the username, not sure why NT doesn't */
137         /* so we fill it in since winbindd_getpwnam() makes use of it */
138         
139         if ( !user->uni_user_name.buffer ) {
140                 init_unistr2( &user->uni_user_name, username, UNI_STR_TERMINATE );
141                 init_uni_hdr( &user->hdr_user_name, &user->uni_user_name );
142         }
143                 
144         /* Prepare data */
145         
146         if ( !(mem_ctx = TALLOC_P( NULL, int )) ) {
147                 DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
148                 return False;
149         }
150
151         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
152         
153         {
154                 uint32 ts;
155                 if ( !prs_uint32( "timestamp", &ps, 0, &ts ) )
156                         return False;
157                 t = (time_t)ts;
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                         return False;
212                 }
213                 
214                 if ( !net_io_user_info3("", user, &ps, 0, 3, 0) ) {
215                         SAFE_FREE( user );
216                 }
217                         
218                 prs_mem_free( &ps );
219
220 #if 0   /* The netsamlogon cache needs to hang around.  Something about 
221            this feels wrong, but it is the only way we can get all of the
222            groups.  The old universal groups cache didn't expire either.
223            --jerry */
224         {
225                 time_t          now = time(NULL);
226                 uint32          time_diff;
227            
228                 /* is the entry expired? */
229                 time_diff = now - t;
230                 
231                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
232                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
233                         tdb_delete( netsamlogon_tdb, key );
234                         SAFE_FREE( user );
235                 }
236 #endif
237         }
238         
239         return user;
240 }
241
242 BOOL netsamlogon_cache_have(const DOM_SID *user_sid)
243 {
244         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
245         NET_USER_INFO_3 *user = NULL;
246         BOOL result;
247
248         if (!mem_ctx)
249                 return False;
250
251         user = netsamlogon_cache_get(mem_ctx, user_sid);
252
253         result = (user != NULL);
254
255         talloc_destroy(mem_ctx);
256         SAFE_FREE(user);
257
258         return result;
259 }