r11661: Store the INFO3 in the PAC data into the netsamlogon_cache.
[bbaumbach/samba-autobuild/.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"), 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         if ( !prs_uint32( "timestamp", &ps, 0, (uint32*)&t ) )
154                 return False;
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, key;
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         key.dptr = keystr;
194         key.dsize = strlen(keystr)+1;
195         data = tdb_fetch( netsamlogon_tdb, key );
196         
197         if ( data.dptr ) {
198                 
199                 if ( (user = SMB_MALLOC_P(NET_USER_INFO_3)) == NULL )
200                         return NULL;
201                         
202                 prs_init( &ps, 0, mem_ctx, UNMARSHALL );
203                 prs_give_memory( &ps, data.dptr, data.dsize, True );
204                 
205                 if ( !prs_uint32( "timestamp", &ps, 0, &t ) ) {
206                         prs_mem_free( &ps );
207                         return False;
208                 }
209                 
210                 if ( !net_io_user_info3("", user, &ps, 0, 3, 0) ) {
211                         SAFE_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                         SAFE_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         SAFE_FREE(user);
253
254         return result;
255 }