1/*
2   Unix SMB/CIFS implementation.
3   struct samu local cache for
4   Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2004.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21
22#undef DBGC_CLASS
23#define DBGC_CLASS DBGC_PASSDB
24
25#define LOGIN_CACHE_FILE "login_cache.tdb"
26
27#define SAM_CACHE_FORMAT "dwwd"
28
29static TDB_CONTEXT *cache;
30
31bool login_cache_init(void)
32{
33	char* cache_fname = NULL;
34
35	/* skip file open if it's already opened */
36	if (cache) return True;
37
38	cache_fname = cache_path(LOGIN_CACHE_FILE);
39	if (cache_fname == NULL) {
40		DEBUG(0, ("Filename allocation failed.\n"));
41		return False;
42	}
43
44	DEBUG(5, ("Opening cache file at %s\n", cache_fname));
45
46	cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
47	                     O_RDWR|O_CREAT, 0644);
48
49	if (!cache)
50		DEBUG(5, ("Attempt to open %s failed.\n", cache_fname));
51
52	TALLOC_FREE(cache_fname);
53
54	return (cache ? True : False);
55}
56
57bool login_cache_shutdown(void)
58{
59	/* tdb_close routine returns -1 on error */
60	if (!cache) return False;
61	DEBUG(5, ("Closing cache file\n"));
62	return tdb_close(cache) != -1;
63}
64
65/* if we can't read the cache, oh well, no need to return anything */
66LOGIN_CACHE * login_cache_read(struct samu *sampass)
67{
68	char *keystr;
69	TDB_DATA databuf;
70	LOGIN_CACHE *entry;
71	uint32_t entry_timestamp = 0, bad_password_time = 0;
72	uint16_t acct_ctrl;
73
74	if (!login_cache_init())
75		return NULL;
76
77	if (pdb_get_nt_username(sampass) == NULL) {
78		return NULL;
79	}
80
81	keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
82	if (!keystr || !keystr[0]) {
83		SAFE_FREE(keystr);
84		return NULL;
85	}
86
87	DEBUG(7, ("Looking up login cache for user %s\n",
88		  keystr));
89	databuf = tdb_fetch_bystring(cache, keystr);
90	SAFE_FREE(keystr);
91
92	if (!(entry = SMB_MALLOC_P(LOGIN_CACHE))) {
93		DEBUG(1, ("Unable to allocate cache entry buffer!\n"));
94		SAFE_FREE(databuf.dptr);
95		return NULL;
96	}
97	ZERO_STRUCTP(entry);
98
99	if (tdb_unpack (databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
100			&entry_timestamp,
101			&acct_ctrl,
102			&entry->bad_password_count,
103			&bad_password_time) == -1) {
104		DEBUG(7, ("No cache entry found\n"));
105		SAFE_FREE(entry);
106		SAFE_FREE(databuf.dptr);
107		return NULL;
108	}
109
110	/*
111	 * Deal with 32-bit acct_ctrl. In the tdb we only store 16-bit
112	 * ("w" in SAM_CACHE_FORMAT). Fixes bug 7253.
113	 */
114	entry->acct_ctrl = acct_ctrl;
115
116	/* Deal with possible 64-bit time_t. */
117	entry->entry_timestamp = (time_t)entry_timestamp;
118	entry->bad_password_time = (time_t)bad_password_time;
119
120	SAFE_FREE(databuf.dptr);
121
122	DEBUG(5, ("Found login cache entry: timestamp %12u, flags 0x%x, count %d, time %12u\n",
123		  (unsigned int)entry->entry_timestamp, entry->acct_ctrl,
124		  entry->bad_password_count, (unsigned int)entry->bad_password_time));
125	return entry;
126}
127
128bool login_cache_write(const struct samu *sampass, LOGIN_CACHE entry)
129{
130	char *keystr;
131	TDB_DATA databuf;
132	bool ret;
133	uint32_t entry_timestamp;
134	uint32_t bad_password_time = (uint32_t)entry.bad_password_time;
135
136	if (!login_cache_init())
137		return False;
138
139	if (pdb_get_nt_username(sampass) == NULL) {
140		return False;
141	}
142
143	keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
144	if (!keystr || !keystr[0]) {
145		SAFE_FREE(keystr);
146		return False;
147	}
148
149	entry_timestamp = (uint32_t)time(NULL);
150
151	databuf.dsize =
152		tdb_pack(NULL, 0, SAM_CACHE_FORMAT,
153			 entry_timestamp,
154			 entry.acct_ctrl,
155			 entry.bad_password_count,
156			 bad_password_time);
157	databuf.dptr = SMB_MALLOC_ARRAY(uint8, databuf.dsize);
158	if (!databuf.dptr) {
159		SAFE_FREE(keystr);
160		return False;
161	}
162
163	if (tdb_pack(databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
164			 entry_timestamp,
165			 entry.acct_ctrl,
166			 entry.bad_password_count,
167			 bad_password_time)
168	    != databuf.dsize) {
169		SAFE_FREE(keystr);
170		SAFE_FREE(databuf.dptr);
171		return False;
172	}
173
174	ret = tdb_store_bystring(cache, keystr, databuf, 0);
175	SAFE_FREE(keystr);
176	SAFE_FREE(databuf.dptr);
177	return ret == 0;
178}
179
180bool login_cache_delentry(const struct samu *sampass)
181{
182	int ret;
183	char *keystr;
184
185	if (!login_cache_init())
186		return False;
187
188	if (pdb_get_nt_username(sampass) == NULL) {
189		return False;
190	}
191
192	keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
193	if (!keystr || !keystr[0]) {
194		SAFE_FREE(keystr);
195		return False;
196	}
197
198	DEBUG(9, ("About to delete entry for %s\n", keystr));
199	ret = tdb_delete_bystring(cache, keystr);
200	DEBUG(9, ("tdb_delete returned %d\n", ret));
201
202	SAFE_FREE(keystr);
203	return ret == 0;
204}
205