1/*
2   Unix SMB/CIFS implementation.
3   passdb testing utility
4
5   Copyright (C) Wilco Baan Hofman 2006
6   Copyright (C) Jelmer Vernooij 2006
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22
23#include "includes.h"
24
25static bool samu_correct(struct samu *s1, struct samu *s2)
26{
27	bool ret = True;
28	uint32 s1_len, s2_len;
29	const char *s1_buf, *s2_buf;
30	const uint8 *d1_buf, *d2_buf;
31
32	/* Check Unix username */
33	s1_buf = pdb_get_username(s1);
34	s2_buf = pdb_get_username(s2);
35	if (s2_buf == NULL && s1_buf != NULL) {
36		DEBUG(0, ("Username is not set\n"));
37		ret = False;
38	} else if (s1_buf == NULL) {
39		/* Do nothing */
40	} else if (strcmp(s1_buf,s2_buf)) {
41		DEBUG(0, ("Username not written correctly, want %s, got \"%s\"\n",
42					pdb_get_username(s1),
43					pdb_get_username(s2)));
44		ret = False;
45	}
46
47	/* Check NT username */
48	s1_buf = pdb_get_nt_username(s1);
49	s2_buf = pdb_get_nt_username(s2);
50	if (s2_buf == NULL && s1_buf != NULL) {
51		DEBUG(0, ("NT Username is not set\n"));
52		ret = False;
53	} else if (s1_buf == NULL) {
54		/* Do nothing */
55	} else if (strcmp(s1_buf, s2_buf)) {
56		DEBUG(0, ("NT Username not written correctly, want \"%s\", got \"%s\"\n",
57					pdb_get_nt_username(s1),
58					pdb_get_nt_username(s2)));
59		ret = False;
60	}
61
62	/* Check acct ctrl */
63	if (pdb_get_acct_ctrl(s1) != pdb_get_acct_ctrl(s2)) {
64		DEBUG(0, ("Acct ctrl field not written correctly, want %d (0x%X), got %d (0x%X)\n",
65					pdb_get_acct_ctrl(s1),
66					pdb_get_acct_ctrl(s1),
67					pdb_get_acct_ctrl(s2),
68					pdb_get_acct_ctrl(s2)));
69		ret = False;
70	}
71
72	/* Check NT password */
73	d1_buf = pdb_get_nt_passwd(s1);
74	d2_buf = pdb_get_nt_passwd(s2);
75	if (d2_buf == NULL && d1_buf != NULL) {
76		DEBUG(0, ("NT password is not set\n"));
77		ret = False;
78	} else if (d1_buf == NULL) {
79		/* Do nothing */
80	} else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
81		DEBUG(0, ("NT password not written correctly\n"));
82		ret = False;
83	}
84
85	/* Check lanman password */
86	d1_buf = pdb_get_lanman_passwd(s1);
87	d2_buf = pdb_get_lanman_passwd(s2);
88	if (d2_buf == NULL && d1_buf != NULL) {
89		DEBUG(0, ("Lanman password is not set\n"));
90	} else if (d1_buf == NULL) {
91		/* Do nothing */
92	} else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
93		DEBUG(0, ("Lanman password not written correctly\n"));
94		ret = False;
95	}
96
97	/* Check password history */
98	d1_buf = pdb_get_pw_history(s1, &s1_len);
99	d2_buf = pdb_get_pw_history(s2, &s2_len);
100	if (d2_buf == NULL && d1_buf != NULL) {
101		DEBUG(0, ("Password history is not set\n"));
102	} else if (d1_buf == NULL) {
103		/* Do nothing */
104	} else if (s1_len != s1_len) {
105		DEBUG(0, ("Password history not written correctly, lengths differ, want %d, got %d\n",
106					s1_len, s2_len));
107		ret = False;
108	} else if (strncmp(s1_buf, s2_buf, s1_len)) {
109		DEBUG(0, ("Password history not written correctly\n"));
110		ret = False;
111	}
112
113	/* Check logon time */
114	if (pdb_get_logon_time(s1) != pdb_get_logon_time(s2)) {
115		DEBUG(0, ("Logon time is not written correctly\n"));
116		ret = False;
117	}
118
119	/* Check logoff time */
120	if (pdb_get_logoff_time(s1) != pdb_get_logoff_time(s2)) {
121		DEBUG(0, ("Logoff time is not written correctly\n"));
122		ret = False;
123	}
124
125	/* Check kickoff time */
126	if (pdb_get_kickoff_time(s1) != pdb_get_logoff_time(s2)) {
127		DEBUG(0, ("Kickoff time is not written correctly\n"));
128		ret = False;
129	}
130
131	/* Check bad password time */
132	if (pdb_get_bad_password_time(s1) != pdb_get_bad_password_time(s2)) {
133		DEBUG(0, ("Bad password time is not written correctly\n"));
134		ret = False;
135	}
136
137	/* Check password last set time */
138	if (pdb_get_pass_last_set_time(s1) != pdb_get_pass_last_set_time(s2)) {
139		DEBUG(0, ("Password last set time is not written correctly\n"));
140		ret = False;
141	}
142
143	/* Check password can change time */
144	if (pdb_get_pass_can_change_time(s1) != pdb_get_pass_can_change_time(s2)) {
145		DEBUG(0, ("Password can change time is not written correctly\n"));
146		ret = False;
147	}
148
149	/* Check password must change time */
150	if (pdb_get_pass_must_change_time(s1) != pdb_get_pass_must_change_time(s2)) {
151		DEBUG(0, ("Password must change time is not written correctly\n"));
152		ret = False;
153	}
154
155	/* Check logon divs */
156	if (pdb_get_logon_divs(s1) != pdb_get_logon_divs(s2)) {
157		DEBUG(0, ("Logon divs not written correctly\n"));
158		ret = False;
159	}
160
161	/* Check logon hours */
162	if (pdb_get_hours_len(s1) != pdb_get_hours_len(s2)) {
163		DEBUG(0, ("Logon hours length not written correctly\n"));
164		ret = False;
165	} else if (pdb_get_hours_len(s1) != 0) {
166		d1_buf = pdb_get_hours(s1);
167		d2_buf = pdb_get_hours(s2);
168		if (d2_buf == NULL && d2_buf != NULL) {
169			DEBUG(0, ("Logon hours is not set\n"));
170			ret = False;
171		} else if (d1_buf == NULL) {
172			/* Do nothing */
173		} else if (memcmp(d1_buf, d2_buf, MAX_HOURS_LEN)) {
174			DEBUG(0, ("Logon hours is not written correctly\n"));
175			ret = False;
176		}
177	}
178
179	/* Check profile path */
180	s1_buf = pdb_get_profile_path(s1);
181	s2_buf = pdb_get_profile_path(s2);
182	if (s2_buf == NULL && s1_buf != NULL) {
183		DEBUG(0, ("Profile path is not set\n"));
184		ret = False;
185	} else if (s1_buf == NULL) {
186		/* Do nothing */
187	} else if (strcmp(s1_buf, s2_buf)) {
188		DEBUG(0, ("Profile path is not written correctly\n"));
189		ret = False;
190	}
191
192	/* Check home dir */
193	s1_buf = pdb_get_homedir(s1);
194	s2_buf = pdb_get_homedir(s2);
195	if (s2_buf == NULL && s1_buf != NULL) {
196		DEBUG(0, ("Home dir is not set\n"));
197		ret = False;
198	} else if (s1_buf == NULL) {
199		/* Do nothing */
200	} else if (strcmp(s1_buf, s2_buf)) {
201		DEBUG(0, ("Home dir is not written correctly\n"));
202		ret = False;
203	}
204
205	/* Check logon script */
206	s1_buf = pdb_get_logon_script(s1);
207	s2_buf = pdb_get_logon_script(s2);
208	if (s2_buf == NULL && s1_buf != NULL) {
209		DEBUG(0, ("Logon script not set\n"));
210		ret = False;
211	} else if (s1_buf == NULL) {
212		/* Do nothing */
213	} else if (strcmp(s1_buf, s2_buf)) {
214		DEBUG(0, ("Logon script is not written correctly\n"));
215		ret = False;
216	}
217
218	/* TODO Check user and group sids */
219
220	return ret;
221}
222
223
224int main(int argc, char **argv)
225{
226	TALLOC_CTX *ctx;
227	struct samu *out = NULL;
228	struct samu *in = NULL;
229	NTSTATUS rv;
230	int i;
231	struct timeval tv;
232	bool error = False;
233	struct passwd *pwd;
234	uint8 *buf;
235	uint32 expire, min_age, history;
236	struct pdb_methods *pdb;
237	poptContext pc;
238	static const char *backend = NULL;
239	static const char *unix_user = "nobody";
240	struct poptOption long_options[] = {
241		{"username", 'u', POPT_ARG_STRING, &unix_user, 0, "Unix user to use for testing", "USERNAME" },
242		{"backend", 'b', POPT_ARG_STRING, &backend, 0, "Backend to use if not default", "BACKEND[:SETTINGS]" },
243		POPT_AUTOHELP
244		POPT_COMMON_SAMBA
245		POPT_TABLEEND
246	};
247
248	load_case_tables();
249
250	pc = poptGetContext("vfstest", argc, (const char **) argv,
251			    long_options, 0);
252
253	poptSetOtherOptionHelp(pc, "backend[:settings] username");
254
255	while(poptGetNextOpt(pc) != -1);
256
257	poptFreeContext(pc);
258
259	/* Load configuration */
260	lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
261	setup_logging("pdbtest", True);
262
263	if (backend == NULL) {
264		backend = lp_passdb_backend();
265	}
266
267	rv = make_pdb_method_name(&pdb, backend);
268	if (NT_STATUS_IS_ERR(rv)) {
269		fprintf(stderr, "Error initializing '%s': %s\n", backend, get_friendly_nt_error_msg(rv));
270		exit(1);
271	}
272
273	ctx = talloc_init("PDBTEST");
274
275	if (!(out = samu_new(ctx))) {
276		fprintf(stderr, "Can't create samu structure.\n");
277		exit(1);
278	}
279
280	if ((pwd = Get_Pwnam_alloc(ctx, unix_user)) == NULL) {
281		fprintf(stderr, "Error getting user information for %s\n", unix_user);
282		exit(1);
283	}
284
285	samu_set_unix(out, pwd);
286
287	pdb_set_profile_path(out, "\\\\torture\\profile", PDB_SET);
288	pdb_set_homedir(out, "\\\\torture\\home", PDB_SET);
289	pdb_set_logon_script(out, "torture_script.cmd", PDB_SET);
290
291	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &history);
292	if (history * PW_HISTORY_ENTRY_LEN < NT_HASH_LEN) {
293		buf = (uint8 *)TALLOC(ctx, NT_HASH_LEN);
294	} else {
295		buf = (uint8 *)TALLOC(ctx, history * PW_HISTORY_ENTRY_LEN);
296	}
297
298	/* Generate some random hashes */
299	GetTimeOfDay(&tv);
300	srand(tv.tv_usec);
301	for (i = 0; i < NT_HASH_LEN; i++) {
302		buf[i] = (uint8) rand();
303	}
304	pdb_set_nt_passwd(out, buf, PDB_SET);
305	for (i = 0; i < LM_HASH_LEN; i++) {
306		buf[i] = (uint8) rand();
307	}
308	pdb_set_lanman_passwd(out, buf, PDB_SET);
309	for (i = 0; i < history * PW_HISTORY_ENTRY_LEN; i++) {
310		buf[i] = (uint8) rand();
311	}
312	pdb_set_pw_history(out, buf, history, PDB_SET);
313
314	pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &expire);
315	pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &min_age);
316	pdb_set_pass_last_set_time(out, time(NULL), PDB_SET);
317
318	if (expire == 0 || expire == (uint32)-1) {
319		pdb_set_pass_must_change_time(out, get_time_t_max(), PDB_SET);
320	} else {
321		pdb_set_pass_must_change_time(out, time(NULL)+expire, PDB_SET);
322	}
323
324	if (min_age == (uint32)-1) {
325		pdb_set_pass_can_change_time(out, 0, PDB_SET);
326	} else {
327		pdb_set_pass_can_change_time(out, time(NULL)+min_age, PDB_SET);
328	}
329
330	/* Create account */
331	if (!NT_STATUS_IS_OK(rv = pdb->add_sam_account(pdb, out))) {
332		fprintf(stderr, "Error in add_sam_account: %s\n",
333				get_friendly_nt_error_msg(rv));
334		exit(1);
335	}
336
337	if (!(in = samu_new(ctx))) {
338		fprintf(stderr, "Can't create samu structure.\n");
339		exit(1);
340	}
341
342	/* Get account information through getsampwnam() */
343	if (NT_STATUS_IS_ERR(pdb->getsampwnam(pdb, in, out->username))) {
344		fprintf(stderr, "Error getting sampw of added user %s.\n",
345				out->username);
346		if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
347			fprintf(stderr, "Error in delete_sam_account %s\n",
348					get_friendly_nt_error_msg(rv));
349		}
350		TALLOC_FREE(ctx);
351	}
352
353	/* Verify integrity */
354	if (samu_correct(out, in)) {
355		printf("User info written correctly\n");
356	} else {
357		printf("User info NOT written correctly\n");
358		error = True;
359	}
360
361	/* Delete account */
362	if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
363		fprintf(stderr, "Error in delete_sam_account %s\n",
364					get_friendly_nt_error_msg(rv));
365	}
366
367	TALLOC_FREE(ctx);
368
369	if (error) {
370		return 1;
371	}
372	return 0;
373}
374