r2086: fix bug with winbindd_getpwnam() caused by Microsoft DC's not filling in the...
[vlendec/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(TALLOC_CTX *mem_ctx, 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         
121
122         if (!netsamlogon_cache_init()) {
123                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB));
124                 return False;
125         }
126
127         sid_copy( &user_sid, &user->dom_sid.sid );
128         sid_append_rid( &user_sid, user->user_rid );
129
130         /* Prepare key as DOMAIN-SID/USER-RID string */
131         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(&user_sid));
132
133         DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
134         
135         /* only Samba fills in the username, not sure why NT doesn't */
136         /* so we fill it in since winbindd_getpwnam() makes use of it */
137         
138         if ( !user->uni_user_name.buffer ) {
139                 init_unistr2( &user->uni_user_name, username, STR_TERMINATE );
140                 init_uni_hdr( &user->hdr_user_name, &user->uni_user_name );
141         }
142                 
143         /* Prepare data */
144         
145         prs_init( &ps,MAX_PDU_FRAG_LEN , mem_ctx, MARSHALL);
146         
147         if ( !prs_uint32( "timestamp", &ps, 0, (uint32*)&t ) )
148                 return False;
149         
150         if ( net_io_user_info3("", user, &ps, 0, 3) ) 
151         {
152                 data.dsize = prs_offset( &ps );
153                 data.dptr = prs_data_p( &ps );
154
155                 if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1)
156                         result = True;
157                 
158                 prs_mem_free( &ps );
159         }
160                 
161         return result;
162 }
163
164 /***********************************************************************
165  Retrieves a NET_USER_INFO_3 structure from a tdb.  Caller must 
166  free the user_info struct (malloc()'d memory)
167 ***********************************************************************/
168
169 NET_USER_INFO_3* netsamlogon_cache_get( TALLOC_CTX *mem_ctx, const DOM_SID *user_sid)
170 {
171         NET_USER_INFO_3 *user = NULL;
172         TDB_DATA        data, key;
173         prs_struct      ps;
174         fstring         keystr;
175         uint32          t;
176         
177         if (!netsamlogon_cache_init()) {
178                 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB));
179                 return False;
180         }
181
182         /* Prepare key as DOMAIN-SID/USER-RID string */
183         slprintf(keystr, sizeof(keystr), "%s", sid_string_static(user_sid));
184         DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
185         key.dptr = keystr;
186         key.dsize = strlen(keystr)+1;
187         data = tdb_fetch( netsamlogon_tdb, key );
188         
189         if ( data.dptr ) {
190                 
191                 if ( (user = (NET_USER_INFO_3*)malloc(sizeof(NET_USER_INFO_3))) == NULL )
192                         return NULL;
193                         
194                 prs_init( &ps, 0, mem_ctx, UNMARSHALL );
195                 prs_give_memory( &ps, data.dptr, data.dsize, True );
196                 
197                 if ( !prs_uint32( "timestamp", &ps, 0, &t ) ) {
198                         prs_mem_free( &ps );
199                         return False;
200                 }
201                 
202                 if ( !net_io_user_info3("", user, &ps, 0, 3) ) {
203                         SAFE_FREE( user );
204                 }
205                         
206                 prs_mem_free( &ps );
207
208 #if 0   /* The netsamlogon cache needs to hang around.  Something about 
209            this feels wrong, but it is the only way we can get all of the
210            groups.  The old universal groups cache didn't expire either.
211            --jerry */
212         {
213                 time_t          now = time(NULL);
214                 uint32          time_diff;
215            
216                 /* is the entry expired? */
217                 time_diff = now - t;
218                 
219                 if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
220                         DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
221                         tdb_delete( netsamlogon_tdb, key );
222                         SAFE_FREE( user );
223                 }
224 #endif
225         }
226         
227         return user;
228 }
229
230 BOOL netsamlogon_cache_have(const DOM_SID *user_sid)
231 {
232         TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
233         NET_USER_INFO_3 *user = NULL;
234         BOOL result;
235
236         if (!mem_ctx)
237                 return False;
238
239         user = netsamlogon_cache_get(mem_ctx, user_sid);
240
241         result = (user != NULL);
242
243         talloc_destroy(mem_ctx);
244         SAFE_FREE(user);
245
246         return result;
247 }