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