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
28static TDB_CONTEXT *netsamlogon_tdb = NULL;
29
30/***********************************************************************
31 open the tdb
32 ***********************************************************************/
33
34BOOL 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
49BOOL 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***********************************************************************/
60void 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
112BOOL 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, UNI_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
169NET_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 = SMB_MALLOC_P(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
230BOOL 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}
248