1 /*
2    Unix SMB/CIFS implementation.
3    tdb passdb backend format routines
4 
5 	Copyright (C) Simo Sorce        2000-2003
6     Copyright (C) Jelmer Vernooij 	2005
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "lib/tdb/include/tdb.h"
26 #include "lib/util/util_tdb.h"
27 #include "lib/samba3/samba3.h"
28 
29 #define TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
30 #define TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
31 #define TDB_FORMAT_STRING_V2       "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
32 #define TDBSAM_VERSION_STRING      "INFO/version"
33 
init_sam_from_buffer_v0(TDB_CONTEXT * tdb,struct samba3_samaccount * sampass,TDB_DATA buf)34 static BOOL init_sam_from_buffer_v0(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
35 {
36 	uint32_t	username_len, domain_len, nt_username_len,
37 		dir_drive_len, unknown_str_len, munged_dial_len,
38 		fullname_len, homedir_len, logon_script_len,
39 		profile_path_len, acct_desc_len, workstations_len;
40 
41 	uint32_t	remove_me;
42 	uint32_t		len = 0;
43 	uint32_t		lm_pw_len, nt_pw_len, hourslen;
44 
45 	if(sampass == NULL || buf.dptr == NULL) {
46 		DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
47 		return False;
48 	}
49 
50 	/* unpack the buffer into variables */
51 	len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V0,
52 		&sampass->logon_time,					/* d */
53 		&sampass->logoff_time,					/* d */
54 		&sampass->kickoff_time,					/* d */
55 		&sampass->pass_last_set_time,				/* d */
56 		&sampass->pass_can_change_time,				/* d */
57 		&sampass->pass_must_change_time,			/* d */
58 		&username_len, &sampass->username,			/* B */
59 		&domain_len, &sampass->domain,				/* B */
60 		&nt_username_len, &sampass->nt_username,		/* B */
61 		&fullname_len, &sampass->fullname,			/* B */
62 		&homedir_len, &sampass->homedir,			/* B */
63 		&dir_drive_len, &sampass->dir_drive,			/* B */
64 		&logon_script_len, &sampass->logon_script,		/* B */
65 		&profile_path_len, &sampass->profile_path,		/* B */
66 		&acct_desc_len, &sampass->acct_desc,			/* B */
67 		&workstations_len, &sampass->workstations,		/* B */
68 		&unknown_str_len, &sampass->unknown_str,		/* B */
69 		&munged_dial_len, &sampass->munged_dial,		/* B */
70 		&sampass->user_rid,					/* d */
71 		&sampass->group_rid,					/* d */
72 		&lm_pw_len, sampass->lm_pw.hash,			/* B */
73 		&nt_pw_len, sampass->nt_pw.hash,			/* B */
74 		&sampass->acct_ctrl,					/* w */
75 		&remove_me, /* remove on the next TDB_FORMAT upgarde */	/* d */
76 		&sampass->logon_divs,					/* w */
77 		&sampass->hours_len,					/* d */
78 		&hourslen, &sampass->hours,				/* B */
79 		&sampass->bad_password_count,				/* w */
80 		&sampass->logon_count,					/* w */
81 		&sampass->unknown_6);					/* d */
82 
83 	if (len == (uint32_t) -1)  {
84 		return False;
85 	}
86 
87 	return True;
88 }
89 
init_sam_from_buffer_v1(TDB_CONTEXT * tdb,struct samba3_samaccount * sampass,TDB_DATA buf)90 static BOOL init_sam_from_buffer_v1(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
91 {
92 	uint32_t	username_len, domain_len, nt_username_len,
93 		dir_drive_len, unknown_str_len, munged_dial_len,
94 		fullname_len, homedir_len, logon_script_len,
95 		profile_path_len, acct_desc_len, workstations_len;
96 
97 	uint32_t	remove_me;
98 	uint32_t		len = 0;
99 	uint32_t		lm_pw_len, nt_pw_len, hourslen;
100 
101 	if(sampass == NULL || buf.dptr == NULL) {
102 		DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
103 		return False;
104 	}
105 
106 	/* unpack the buffer into variables */
107 	len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V1,
108 		&sampass->logon_time,					/* d */
109 		&sampass->logoff_time,					/* d */
110 		&sampass->kickoff_time,				/* d */
111 		/* Change from V0 is addition of bad_password_time field. */
112 		&sampass->bad_password_time,				/* d */
113 		&sampass->pass_last_set_time,				/* d */
114 		&sampass->pass_can_change_time,			/* d */
115 		&sampass->pass_must_change_time,			/* d */
116 		&username_len, &sampass->username,			/* B */
117 		&domain_len, &sampass->domain,		/* B */
118 		&nt_username_len, &sampass->nt_username,	/* B */
119 		&fullname_len, &sampass->fullname,			/* B */
120 		&homedir_len, &sampass->homedir,			/* B */
121 		&dir_drive_len, &sampass->dir_drive,			/* B */
122 		&logon_script_len, &sampass->logon_script,		/* B */
123 		&profile_path_len, &sampass->profile_path,		/* B */
124 		&acct_desc_len, &sampass->acct_desc,			/* B */
125 		&workstations_len, &sampass->workstations,		/* B */
126 		&unknown_str_len, &sampass->unknown_str,		/* B */
127 		&munged_dial_len, &sampass->munged_dial,		/* B */
128 		&sampass->user_rid,					/* d */
129 		&sampass->group_rid,					/* d */
130 		&lm_pw_len, sampass->lm_pw.hash,			/* B */
131 		&nt_pw_len, sampass->nt_pw.hash,			/* B */
132 		&sampass->acct_ctrl,					/* w */
133 		&remove_me,						/* d */
134 		&sampass->logon_divs,					/* w */
135 		&sampass->hours_len,					/* d */
136 		&hourslen, &sampass->hours,				/* B */
137 		&sampass->bad_password_count,				/* w */
138 		&sampass->logon_count,					/* w */
139 		&sampass->unknown_6);					/* d */
140 
141 	if (len == (uint32_t) -1)  {
142 		return False;
143 	}
144 
145 	return True;
146 }
147 
init_sam_from_buffer_v2(TDB_CONTEXT * tdb,struct samba3_samaccount * sampass,TDB_DATA buf)148 static BOOL init_sam_from_buffer_v2(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
149 {
150 	uint32_t	username_len, domain_len, nt_username_len,
151 		dir_drive_len, unknown_str_len, munged_dial_len,
152 		fullname_len, homedir_len, logon_script_len,
153 		profile_path_len, acct_desc_len, workstations_len;
154 
155 	uint32_t		len = 0;
156 	uint32_t		lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
157 
158 	if(sampass == NULL || buf.dptr == NULL) {
159 		DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
160 		return False;
161 	}
162 
163 	/* unpack the buffer into variables */
164 	len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V2,
165 		&sampass->logon_time,					/* d */
166 		&sampass->logoff_time,					/* d */
167 		&sampass->kickoff_time,					/* d */
168 		&sampass->bad_password_time,				/* d */
169 		&sampass->pass_last_set_time,				/* d */
170 		&sampass->pass_can_change_time,				/* d */
171 		&sampass->pass_must_change_time,			/* d */
172 		&username_len, &sampass->username,			/* B */
173 		&domain_len, &sampass->domain,				/* B */
174 		&nt_username_len, &sampass->nt_username,		/* B */
175 		&fullname_len, &sampass->fullname,			/* B */
176 		&homedir_len, &sampass->homedir,			/* B */
177 		&dir_drive_len, &sampass->dir_drive,			/* B */
178 		&logon_script_len, &sampass->logon_script,		/* B */
179 		&profile_path_len, &sampass->profile_path,		/* B */
180 		&acct_desc_len, &sampass->acct_desc,			/* B */
181 		&workstations_len, &sampass->workstations,		/* B */
182 		&unknown_str_len, &sampass->unknown_str,		/* B */
183 		&munged_dial_len, &sampass->munged_dial,		/* B */
184 		&sampass->user_rid,					/* d */
185 		&sampass->group_rid,					/* d */
186 		&lm_pw_len, sampass->lm_pw.hash,			/* B */
187 		&nt_pw_len, sampass->nt_pw.hash,			/* B */
188 		/* Change from V1 is addition of password history field. */
189 		&nt_pw_hist_len, &sampass->nt_pw_hist_ptr,		/* B */
190 		&sampass->acct_ctrl,					/* w */
191 		/* Also "remove_me" field was removed. */
192 		&sampass->logon_divs,					/* w */
193 		&sampass->hours_len,					/* d */
194 		&hourslen, &sampass->hours,				/* B */
195 		&sampass->bad_password_count,				/* w */
196 		&sampass->logon_count,					/* w */
197 		&sampass->unknown_6);					/* d */
198 
199 	if (len == (uint32_t) -1)  {
200 		return False;
201 	}
202 
203 	return True;
204 }
205 
samba3_read_tdbsam(const char * filename,TALLOC_CTX * ctx,struct samba3_samaccount ** accounts,uint32_t * count)206 NTSTATUS samba3_read_tdbsam(const char *filename, TALLOC_CTX *ctx, struct samba3_samaccount **accounts, uint32_t *count)
207 {
208 	int32_t version;
209 	TDB_CONTEXT *tdb;
210 	TDB_DATA key, val;
211 
212 	/* Try to open tdb passwd */
213 	if (!(tdb = tdb_open(filename, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
214 		DEBUG(0, ("Unable to open TDB passwd file '%s'\n", filename));
215 		return NT_STATUS_UNSUCCESSFUL;
216 	}
217 
218 	/* Check the version */
219 	version = tdb_fetch_int32(tdb,
220 						TDBSAM_VERSION_STRING);
221 	if (version == -1)
222 		version = 0;	/* Version not found, assume version 0 */
223 
224 	/* Compare the version */
225 	if (version > 2) {
226 		/* Version more recent than the latest known */
227 		DEBUG(0, ("TDBSAM version unknown: %d\n", version));
228 		tdb_close(tdb);
229 		return NT_STATUS_NOT_SUPPORTED;
230 	}
231 
232 	*accounts = NULL;
233 	*count = 0;
234 
235 	for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key))
236 	{
237 		BOOL ret;
238 		if (strncmp((const char *)key.dptr, "USER_", 5) != 0)
239 			continue;
240 
241 		val = tdb_fetch(tdb, key);
242 
243 		*accounts = talloc_realloc(ctx, *accounts, struct samba3_samaccount, (*count)+1);
244 
245 		switch (version)
246 		{
247 			case 0: ret = init_sam_from_buffer_v0(tdb, &(*accounts)[*count], val); break;
248 			case 1: ret = init_sam_from_buffer_v1(tdb, &(*accounts)[*count], val); break;
249 			case 2: ret = init_sam_from_buffer_v2(tdb, &(*accounts)[*count], val); break;
250 			default: ret = False; break;
251 
252 		}
253 
254 		if (!ret) {
255 			DEBUG(0, ("Unable to parse SAM account %s\n", key.dptr));
256 		}
257 
258 		(*count)++;
259 	}
260 
261 	tdb_close(tdb);
262 
263 	return NT_STATUS_OK;
264 }
265