/src/samba/source3/passdb/passdb.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Password and authentication handling |
4 | | Copyright (C) Jeremy Allison 1996-2001 |
5 | | Copyright (C) Luke Kenneth Casson Leighton 1996-1998 |
6 | | Copyright (C) Gerald (Jerry) Carter 2000-2006 |
7 | | Copyright (C) Andrew Bartlett 2001-2002 |
8 | | Copyright (C) Simo Sorce 2003 |
9 | | Copyright (C) Volker Lendecke 2006 |
10 | | |
11 | | This program is free software; you can redistribute it and/or modify |
12 | | it under the terms of the GNU General Public License as published by |
13 | | the Free Software Foundation; either version 3 of the License, or |
14 | | (at your option) any later version. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, |
17 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | GNU General Public License for more details. |
20 | | |
21 | | You should have received a copy of the GNU General Public License |
22 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | #include "includes.h" |
26 | | #include "passdb.h" |
27 | | #include "system/passwd.h" |
28 | | #include "../libcli/auth/libcli_auth.h" |
29 | | #include "secrets.h" |
30 | | #include "../libcli/security/security.h" |
31 | | #include "../lib/util/util_pw.h" |
32 | | #include "util_tdb.h" |
33 | | #include "auth/credentials/credentials.h" |
34 | | #include "lib/param/param.h" |
35 | | #include "lib/util/string_wrappers.h" |
36 | | #include "source3/lib/substitute.h" |
37 | | |
38 | | #undef DBGC_CLASS |
39 | 0 | #define DBGC_CLASS DBGC_PASSDB |
40 | | |
41 | | /********************************************************************** |
42 | | ***********************************************************************/ |
43 | | |
44 | | static int samu_destroy(struct samu *user) |
45 | 0 | { |
46 | 0 | data_blob_clear_free( &user->lm_pw ); |
47 | 0 | data_blob_clear_free( &user->nt_pw ); |
48 | |
|
49 | 0 | if ( user->plaintext_pw ) |
50 | 0 | BURN_STR(user->plaintext_pw); |
51 | |
|
52 | 0 | return 0; |
53 | 0 | } |
54 | | |
55 | | /********************************************************************** |
56 | | generate a new struct samuser |
57 | | ***********************************************************************/ |
58 | | |
59 | | struct samu *samu_new( TALLOC_CTX *ctx ) |
60 | 0 | { |
61 | 0 | struct samu *user; |
62 | |
|
63 | 0 | if ( !(user = talloc_zero( ctx, struct samu )) ) { |
64 | 0 | DEBUG(0,("samuser_new: Talloc failed!\n")); |
65 | 0 | return NULL; |
66 | 0 | } |
67 | | |
68 | 0 | talloc_set_destructor( user, samu_destroy ); |
69 | | |
70 | | /* no initial methods */ |
71 | |
|
72 | 0 | user->methods = NULL; |
73 | | |
74 | | /* Don't change these timestamp settings without a good reason. |
75 | | They are important for NT member server compatibility. */ |
76 | |
|
77 | 0 | user->logon_time = (time_t)0; |
78 | 0 | user->pass_last_set_time = (time_t)0; |
79 | 0 | user->pass_can_change_time = (time_t)0; |
80 | 0 | user->logoff_time = get_time_t_max(); |
81 | 0 | user->kickoff_time = get_time_t_max(); |
82 | 0 | user->fields_present = 0x00ffffff; |
83 | 0 | user->logon_divs = 168; /* hours per week */ |
84 | 0 | user->hours_len = 21; /* 21 times 8 bits = 168 */ |
85 | 0 | memset(user->hours, 0xff, user->hours_len); /* available at all hours */ |
86 | 0 | user->bad_password_count = 0; |
87 | 0 | user->logon_count = 0; |
88 | 0 | user->unknown_6 = 0x000004ec; /* don't know */ |
89 | | |
90 | | /* Some parts of samba strlen their pdb_get...() returns, |
91 | | so this keeps the interface unchanged for now. */ |
92 | |
|
93 | 0 | user->username = ""; |
94 | 0 | user->domain = ""; |
95 | 0 | user->nt_username = ""; |
96 | 0 | user->full_name = ""; |
97 | 0 | user->home_dir = ""; |
98 | 0 | user->logon_script = ""; |
99 | 0 | user->profile_path = ""; |
100 | 0 | user->acct_desc = ""; |
101 | 0 | user->workstations = ""; |
102 | 0 | user->comment = ""; |
103 | 0 | user->munged_dial = ""; |
104 | |
|
105 | 0 | user->plaintext_pw = NULL; |
106 | | |
107 | | /* Unless we know otherwise have a Account Control Bit |
108 | | value of 'normal user'. This helps User Manager, which |
109 | | asks for a filtered list of users. */ |
110 | |
|
111 | 0 | user->acct_ctrl = ACB_NORMAL; |
112 | |
|
113 | 0 | return user; |
114 | 0 | } |
115 | | |
116 | | static int count_commas(const char *str) |
117 | 0 | { |
118 | 0 | int num_commas = 0; |
119 | 0 | const char *comma = str; |
120 | |
|
121 | 0 | while ((comma = strchr(comma, ',')) != NULL) { |
122 | 0 | comma += 1; |
123 | 0 | num_commas += 1; |
124 | 0 | } |
125 | 0 | return num_commas; |
126 | 0 | } |
127 | | |
128 | | /********************************************************************* |
129 | | Initialize a struct samu from a struct passwd including the user |
130 | | and group SIDs. The *user structure is filled out with the Unix |
131 | | attributes and a user SID. |
132 | | *********************************************************************/ |
133 | | |
134 | | static NTSTATUS samu_set_unix_internal(struct pdb_methods *methods, |
135 | | struct samu *user, const struct passwd *pwd, bool create) |
136 | 0 | { |
137 | 0 | const char *guest_account = lp_guest_account(); |
138 | 0 | const char *domain = lp_netbios_name(); |
139 | 0 | char *fullname; |
140 | 0 | uint32_t urid; |
141 | 0 | bool ok; |
142 | |
|
143 | 0 | if ( !pwd ) { |
144 | 0 | return NT_STATUS_NO_SUCH_USER; |
145 | 0 | } |
146 | | |
147 | | /* Basic properties based upon the Unix account information */ |
148 | | |
149 | 0 | ok = pdb_set_username(user, pwd->pw_name, PDB_SET); |
150 | 0 | if (!ok) { |
151 | 0 | return NT_STATUS_NO_MEMORY; |
152 | 0 | } |
153 | | |
154 | 0 | fullname = NULL; |
155 | |
|
156 | 0 | if (count_commas(pwd->pw_gecos) == 3) { |
157 | | /* |
158 | | * Heuristic: This seems to be a gecos field that has been |
159 | | * edited by chfn(1). Only use the part before the first |
160 | | * comma. Fixes bug 5198. |
161 | | */ |
162 | 0 | fullname = talloc_strndup( |
163 | 0 | talloc_tos(), pwd->pw_gecos, |
164 | 0 | strchr(pwd->pw_gecos, ',') - pwd->pw_gecos); |
165 | 0 | if (fullname == NULL) { |
166 | 0 | return NT_STATUS_NO_MEMORY; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | if (fullname != NULL) { |
171 | 0 | ok = pdb_set_fullname(user, fullname, PDB_SET); |
172 | 0 | } else { |
173 | 0 | ok = pdb_set_fullname(user, pwd->pw_gecos, PDB_SET); |
174 | 0 | } |
175 | 0 | TALLOC_FREE(fullname); |
176 | |
|
177 | 0 | if (!ok) { |
178 | 0 | return NT_STATUS_NO_MEMORY; |
179 | 0 | } |
180 | | |
181 | 0 | ok = pdb_set_domain(user, get_global_sam_name(), PDB_DEFAULT); |
182 | 0 | if (!ok) { |
183 | 0 | return NT_STATUS_NO_MEMORY; |
184 | 0 | } |
185 | | #if 0 |
186 | | /* This can lead to a primary group of S-1-22-2-XX which |
187 | | will be rejected by other parts of the Samba code. |
188 | | Rely on pdb_get_group_sid() to "Do The Right Thing" (TM) |
189 | | --jerry */ |
190 | | |
191 | | gid_to_sid(&group_sid, pwd->pw_gid); |
192 | | pdb_set_group_sid(user, &group_sid, PDB_SET); |
193 | | #endif |
194 | | |
195 | | /* save the password structure for later use */ |
196 | | |
197 | 0 | user->unix_pw = tcopy_passwd( user, pwd ); |
198 | 0 | if (user->unix_pw == NULL) { |
199 | 0 | return NT_STATUS_NO_MEMORY; |
200 | 0 | } |
201 | | |
202 | | /* Special case for the guest account which must have a RID of 501 */ |
203 | | |
204 | 0 | if ( strequal( pwd->pw_name, guest_account ) ) { |
205 | 0 | if ( !pdb_set_user_sid_from_rid(user, DOMAIN_RID_GUEST, PDB_DEFAULT)) { |
206 | 0 | return NT_STATUS_NO_SUCH_USER; |
207 | 0 | } |
208 | 0 | return NT_STATUS_OK; |
209 | 0 | } |
210 | | |
211 | | /* Non-guest accounts...Check for a workstation or user account */ |
212 | | |
213 | 0 | if (pwd->pw_name[strlen(pwd->pw_name)-1] == '$') { |
214 | | /* workstation */ |
215 | |
|
216 | 0 | if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_DEFAULT)) { |
217 | 0 | DEBUG(1, ("Failed to set 'workstation account' flags for user %s.\n", |
218 | 0 | pwd->pw_name)); |
219 | 0 | return NT_STATUS_INVALID_COMPUTER_NAME; |
220 | 0 | } |
221 | 0 | } |
222 | 0 | else { |
223 | | /* user */ |
224 | |
|
225 | 0 | if (!pdb_set_acct_ctrl(user, ACB_NORMAL, PDB_DEFAULT)) { |
226 | 0 | DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n", |
227 | 0 | pwd->pw_name)); |
228 | 0 | return NT_STATUS_INVALID_ACCOUNT_NAME; |
229 | 0 | } |
230 | | |
231 | | /* set some basic attributes */ |
232 | | |
233 | 0 | ok = pdb_set_profile_path( |
234 | 0 | user, |
235 | 0 | talloc_sub_specified( |
236 | 0 | user, |
237 | 0 | lp_logon_path(), |
238 | 0 | pwd->pw_name, |
239 | 0 | NULL, |
240 | 0 | domain, |
241 | 0 | pwd->pw_uid, |
242 | 0 | pwd->pw_gid), |
243 | 0 | PDB_DEFAULT); |
244 | 0 | ok &= pdb_set_homedir( |
245 | 0 | user, |
246 | 0 | talloc_sub_specified( |
247 | 0 | user, |
248 | 0 | lp_logon_home(), |
249 | 0 | pwd->pw_name, |
250 | 0 | NULL, |
251 | 0 | domain, |
252 | 0 | pwd->pw_uid, |
253 | 0 | pwd->pw_gid), |
254 | 0 | PDB_DEFAULT); |
255 | 0 | ok &= pdb_set_dir_drive( |
256 | 0 | user, |
257 | 0 | talloc_sub_specified( |
258 | 0 | user, |
259 | 0 | lp_logon_drive(), |
260 | 0 | pwd->pw_name, |
261 | 0 | NULL, |
262 | 0 | domain, |
263 | 0 | pwd->pw_uid, |
264 | 0 | pwd->pw_gid), |
265 | 0 | PDB_DEFAULT); |
266 | 0 | ok &= pdb_set_logon_script( |
267 | 0 | user, |
268 | 0 | talloc_sub_specified( |
269 | 0 | user, |
270 | 0 | lp_logon_script(), |
271 | 0 | pwd->pw_name, |
272 | 0 | NULL, |
273 | 0 | domain, |
274 | 0 | pwd->pw_uid, |
275 | 0 | pwd->pw_gid), |
276 | 0 | PDB_DEFAULT); |
277 | 0 | if (!ok) { |
278 | 0 | return NT_STATUS_NO_MEMORY; |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | /* Now deal with the user SID. If we have a backend that can generate |
283 | | RIDs, then do so. But sometimes the caller just wanted a structure |
284 | | initialized and will fill in these fields later (such as from a |
285 | | netr_SamInfo3 structure) */ |
286 | | |
287 | 0 | if ( create && (methods->capabilities(methods) & PDB_CAP_STORE_RIDS)) { |
288 | 0 | uint32_t user_rid; |
289 | 0 | struct dom_sid user_sid; |
290 | |
|
291 | 0 | if ( !methods->new_rid(methods, &user_rid) ) { |
292 | 0 | DEBUG(3, ("Could not allocate a new RID\n")); |
293 | 0 | return NT_STATUS_ACCESS_DENIED; |
294 | 0 | } |
295 | | |
296 | 0 | sid_compose(&user_sid, get_global_sam_sid(), user_rid); |
297 | |
|
298 | 0 | if ( !pdb_set_user_sid(user, &user_sid, PDB_SET) ) { |
299 | 0 | DEBUG(3, ("pdb_set_user_sid failed\n")); |
300 | 0 | return NT_STATUS_INTERNAL_ERROR; |
301 | 0 | } |
302 | | |
303 | 0 | return NT_STATUS_OK; |
304 | 0 | } |
305 | | |
306 | | /* generate a SID for the user with the RID algorithm */ |
307 | | |
308 | 0 | urid = algorithmic_pdb_uid_to_user_rid( user->unix_pw->pw_uid ); |
309 | |
|
310 | 0 | if ( !pdb_set_user_sid_from_rid( user, urid, PDB_SET) ) { |
311 | 0 | return NT_STATUS_INTERNAL_ERROR; |
312 | 0 | } |
313 | | |
314 | 0 | return NT_STATUS_OK; |
315 | 0 | } |
316 | | |
317 | | /******************************************************************** |
318 | | Set the Unix user attributes |
319 | | ********************************************************************/ |
320 | | |
321 | | NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd) |
322 | 0 | { |
323 | 0 | return samu_set_unix_internal( NULL, user, pwd, False ); |
324 | 0 | } |
325 | | |
326 | | NTSTATUS samu_alloc_rid_unix(struct pdb_methods *methods, |
327 | | struct samu *user, const struct passwd *pwd) |
328 | 0 | { |
329 | 0 | return samu_set_unix_internal( methods, user, pwd, True ); |
330 | 0 | } |
331 | | |
332 | | /********************************************************** |
333 | | Encode the account control bits into a string. |
334 | | length = length of string to encode into (including terminating |
335 | | null). length *MUST BE MORE THAN 2* ! |
336 | | **********************************************************/ |
337 | | |
338 | | char *pdb_encode_acct_ctrl(uint32_t acct_ctrl, size_t length) |
339 | 0 | { |
340 | 0 | fstring acct_str; |
341 | 0 | char *result; |
342 | |
|
343 | 0 | size_t i = 0; |
344 | |
|
345 | 0 | SMB_ASSERT(length <= sizeof(acct_str)); |
346 | | |
347 | 0 | acct_str[i++] = '['; |
348 | |
|
349 | 0 | if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N'; |
350 | 0 | if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D'; |
351 | 0 | if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H'; |
352 | 0 | if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T'; |
353 | 0 | if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U'; |
354 | 0 | if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M'; |
355 | 0 | if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W'; |
356 | 0 | if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S'; |
357 | 0 | if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L'; |
358 | 0 | if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X'; |
359 | 0 | if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I'; |
360 | |
|
361 | 0 | for ( ; i < length - 2 ; i++ ) |
362 | 0 | acct_str[i] = ' '; |
363 | |
|
364 | 0 | i = length - 2; |
365 | 0 | acct_str[i++] = ']'; |
366 | 0 | acct_str[i++] = '\0'; |
367 | |
|
368 | 0 | result = talloc_strdup(talloc_tos(), acct_str); |
369 | 0 | SMB_ASSERT(result != NULL); |
370 | 0 | return result; |
371 | 0 | } |
372 | | |
373 | | /********************************************************** |
374 | | Decode the account control bits from a string. |
375 | | **********************************************************/ |
376 | | |
377 | | uint32_t pdb_decode_acct_ctrl(const char *p) |
378 | 0 | { |
379 | 0 | uint32_t acct_ctrl = 0; |
380 | 0 | bool finished = false; |
381 | | |
382 | | /* |
383 | | * Check if the account type bits have been encoded after the |
384 | | * NT password (in the form [NDHTUWSLXI]). |
385 | | */ |
386 | |
|
387 | 0 | if (*p != '[') |
388 | 0 | return 0; |
389 | | |
390 | 0 | for (p++; *p && !finished; p++) { |
391 | 0 | switch (*p) { |
392 | 0 | case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ } |
393 | 0 | case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ } |
394 | 0 | case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ } |
395 | 0 | case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ } |
396 | 0 | case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ } |
397 | 0 | case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ } |
398 | 0 | case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ } |
399 | 0 | case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } |
400 | 0 | case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } |
401 | 0 | case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ } |
402 | 0 | case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ } |
403 | 0 | case ' ': { break; } |
404 | 0 | case ':': |
405 | 0 | case '\n': |
406 | 0 | case '\0': |
407 | 0 | case ']': |
408 | 0 | default: { finished = true; } |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | 0 | return acct_ctrl; |
413 | 0 | } |
414 | | |
415 | | /************************************************************* |
416 | | Routine to set 32 hex password characters from a 16 byte array. |
417 | | **************************************************************/ |
418 | | |
419 | | void pdb_sethexpwd(char p[33], const unsigned char *pwd, uint32_t acct_ctrl) |
420 | 0 | { |
421 | 0 | if (pwd != NULL) { |
422 | 0 | hex_encode_buf(p, pwd, 16); |
423 | 0 | } else { |
424 | 0 | if (acct_ctrl & ACB_PWNOTREQ) |
425 | 0 | strlcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33); |
426 | 0 | else |
427 | 0 | strlcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33); |
428 | 0 | } |
429 | 0 | } |
430 | | |
431 | | /************************************************************* |
432 | | Routine to get the 32 hex characters and turn them |
433 | | into a 16 byte array. |
434 | | **************************************************************/ |
435 | | |
436 | | bool pdb_gethexpwd(const char *p, unsigned char *pwd) |
437 | 0 | { |
438 | 0 | int i; |
439 | |
|
440 | 0 | if (!p) |
441 | 0 | return false; |
442 | | |
443 | 0 | for (i = 0; i < 32; i += 2) { |
444 | 0 | bool ok = hex_byte(p + i, &pwd[i / 2]); |
445 | 0 | if (!ok) { |
446 | 0 | return false; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | return true; |
450 | 0 | } |
451 | | |
452 | | /************************************************************* |
453 | | Routine to set 42 hex hours characters from a 21 byte array. |
454 | | **************************************************************/ |
455 | | |
456 | | void pdb_sethexhours(char *p, const unsigned char *hours) |
457 | 0 | { |
458 | 0 | if (hours != NULL) { |
459 | 0 | hex_encode_buf(p, hours, 21); |
460 | 0 | } else { |
461 | 0 | strlcpy(p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 44); |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | | /************************************************************* |
466 | | Routine to get the 42 hex characters and turn them |
467 | | into a 21 byte array. |
468 | | **************************************************************/ |
469 | | |
470 | | bool pdb_gethexhours(const char *p, unsigned char *hours) |
471 | 0 | { |
472 | 0 | int i; |
473 | |
|
474 | 0 | if (!p) { |
475 | 0 | return (False); |
476 | 0 | } |
477 | | |
478 | 0 | for (i = 0; i < 42; i += 2) { |
479 | 0 | bool ok = hex_byte(p, (uint8_t *)&hours[i / 2]); |
480 | 0 | if (!ok) { |
481 | 0 | return false; |
482 | 0 | } |
483 | 0 | } |
484 | 0 | return (True); |
485 | 0 | } |
486 | | |
487 | | /******************************************************************** |
488 | | ********************************************************************/ |
489 | | |
490 | | int algorithmic_rid_base(void) |
491 | 0 | { |
492 | 0 | int rid_offset; |
493 | |
|
494 | 0 | rid_offset = lp_algorithmic_rid_base(); |
495 | |
|
496 | 0 | if (rid_offset < BASE_RID) { |
497 | | /* Try to prevent admin foot-shooting, we can't put algorithmic |
498 | | rids below 1000, that's the 'well known RIDs' on NT */ |
499 | 0 | DEBUG(0, ("'algorithmic rid base' must be equal to or above %ld\n", BASE_RID)); |
500 | 0 | rid_offset = BASE_RID; |
501 | 0 | } |
502 | 0 | if (rid_offset & 1) { |
503 | 0 | DEBUG(0, ("algorithmic rid base must be even\n")); |
504 | 0 | rid_offset += 1; |
505 | 0 | } |
506 | 0 | return rid_offset; |
507 | 0 | } |
508 | | |
509 | | /******************************************************************* |
510 | | Converts NT user RID to a UNIX uid. |
511 | | ********************************************************************/ |
512 | | |
513 | | uid_t algorithmic_pdb_user_rid_to_uid(uint32_t user_rid) |
514 | 0 | { |
515 | 0 | int rid_offset = algorithmic_rid_base(); |
516 | 0 | return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER); |
517 | 0 | } |
518 | | |
519 | | uid_t max_algorithmic_uid(void) |
520 | 0 | { |
521 | 0 | return algorithmic_pdb_user_rid_to_uid(0xfffffffe); |
522 | 0 | } |
523 | | |
524 | | /******************************************************************* |
525 | | converts UNIX uid to an NT User RID. |
526 | | ********************************************************************/ |
527 | | |
528 | | uint32_t algorithmic_pdb_uid_to_user_rid(uid_t uid) |
529 | 0 | { |
530 | 0 | int rid_offset = algorithmic_rid_base(); |
531 | 0 | return (((((uint32_t)uid)*RID_MULTIPLIER) + rid_offset) | USER_RID_TYPE); |
532 | 0 | } |
533 | | |
534 | | /******************************************************************* |
535 | | Converts NT group RID to a UNIX gid. |
536 | | ********************************************************************/ |
537 | | |
538 | | gid_t pdb_group_rid_to_gid(uint32_t group_rid) |
539 | 0 | { |
540 | 0 | int rid_offset = algorithmic_rid_base(); |
541 | 0 | return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER); |
542 | 0 | } |
543 | | |
544 | | gid_t max_algorithmic_gid(void) |
545 | 0 | { |
546 | 0 | return pdb_group_rid_to_gid(0xffffffff); |
547 | 0 | } |
548 | | |
549 | | /******************************************************************* |
550 | | converts NT Group RID to a UNIX uid. |
551 | | |
552 | | warning: you must not call that function only |
553 | | you must do a call to the group mapping first. |
554 | | there is not anymore a direct link between the gid and the rid. |
555 | | ********************************************************************/ |
556 | | |
557 | | uint32_t algorithmic_pdb_gid_to_group_rid(gid_t gid) |
558 | 0 | { |
559 | 0 | int rid_offset = algorithmic_rid_base(); |
560 | 0 | return (((((uint32_t)gid)*RID_MULTIPLIER) + rid_offset) | GROUP_RID_TYPE); |
561 | 0 | } |
562 | | |
563 | | /******************************************************************* |
564 | | Decides if a RID is a well known RID. |
565 | | ********************************************************************/ |
566 | | |
567 | | static bool rid_is_well_known(uint32_t rid) |
568 | 0 | { |
569 | | /* Not using rid_offset here, because this is the actual |
570 | | NT fixed value (1000) */ |
571 | |
|
572 | 0 | return (rid < BASE_RID); |
573 | 0 | } |
574 | | |
575 | | /******************************************************************* |
576 | | Decides if a RID is a user or group RID. |
577 | | ********************************************************************/ |
578 | | |
579 | | bool algorithmic_pdb_rid_is_user(uint32_t rid) |
580 | 0 | { |
581 | 0 | if ( rid_is_well_known(rid) ) { |
582 | | /* |
583 | | * The only well known user RIDs are DOMAIN_RID_ADMINISTRATOR |
584 | | * and DOMAIN_RID_GUEST. |
585 | | */ |
586 | 0 | if(rid == DOMAIN_RID_ADMINISTRATOR || rid == DOMAIN_RID_GUEST) |
587 | 0 | return True; |
588 | 0 | } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) { |
589 | 0 | return True; |
590 | 0 | } |
591 | 0 | return False; |
592 | 0 | } |
593 | | |
594 | | /******************************************************************* |
595 | | Convert a name into a SID. Used in the lookup name rpc. |
596 | | ********************************************************************/ |
597 | | |
598 | | bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid, |
599 | | enum lsa_SidType *type) |
600 | 0 | { |
601 | 0 | GROUP_MAP *map; |
602 | 0 | bool ret; |
603 | | |
604 | | /* Windows treats "MACHINE\None" as a special name for |
605 | | rid 513 on non-DCs. You cannot create a user or group |
606 | | name "None" on Windows. You will get an error that |
607 | | the group already exists. */ |
608 | |
|
609 | 0 | if ( strequal( name, "None" ) ) { |
610 | 0 | *rid = DOMAIN_RID_USERS; |
611 | 0 | *type = SID_NAME_DOM_GRP; |
612 | |
|
613 | 0 | return True; |
614 | 0 | } |
615 | | |
616 | | /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work |
617 | | * correctly in the case where foo also exists as a user. If the flag |
618 | | * is set, don't look for users at all. */ |
619 | | |
620 | 0 | if ((flags & LOOKUP_NAME_GROUP) == 0) { |
621 | 0 | struct samu *sam_account = NULL; |
622 | 0 | struct dom_sid user_sid; |
623 | |
|
624 | 0 | if ( !(sam_account = samu_new( NULL )) ) { |
625 | 0 | return False; |
626 | 0 | } |
627 | | |
628 | 0 | become_root(); |
629 | 0 | ret = pdb_getsampwnam(sam_account, name); |
630 | 0 | unbecome_root(); |
631 | |
|
632 | 0 | if (ret) { |
633 | 0 | sid_copy(&user_sid, pdb_get_user_sid(sam_account)); |
634 | 0 | } |
635 | |
|
636 | 0 | TALLOC_FREE(sam_account); |
637 | |
|
638 | 0 | if (ret) { |
639 | 0 | if (!sid_check_is_in_our_sam(&user_sid)) { |
640 | 0 | struct dom_sid_buf buf; |
641 | 0 | DBG_ERR("User %s with invalid SID %s" |
642 | 0 | " in passdb\n", |
643 | 0 | name, |
644 | 0 | dom_sid_str_buf(&user_sid, &buf)); |
645 | 0 | return False; |
646 | 0 | } |
647 | | |
648 | 0 | sid_peek_rid(&user_sid, rid); |
649 | 0 | *type = SID_NAME_USER; |
650 | 0 | return True; |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | | /* |
655 | | * Maybe it is a group ? |
656 | | */ |
657 | | |
658 | 0 | map = talloc_zero(NULL, GROUP_MAP); |
659 | 0 | if (!map) { |
660 | 0 | return false; |
661 | 0 | } |
662 | | |
663 | 0 | become_root(); |
664 | 0 | ret = pdb_getgrnam(map, name); |
665 | 0 | unbecome_root(); |
666 | |
|
667 | 0 | if (!ret) { |
668 | 0 | TALLOC_FREE(map); |
669 | 0 | return False; |
670 | 0 | } |
671 | | |
672 | | /* BUILTIN groups are looked up elsewhere */ |
673 | 0 | if (!sid_check_is_in_our_sam(&map->sid)) { |
674 | 0 | struct dom_sid_buf buf; |
675 | 0 | DEBUG(10, ("Found group %s (%s) not in our domain -- " |
676 | 0 | "ignoring.\n", |
677 | 0 | name, |
678 | 0 | dom_sid_str_buf(&map->sid, &buf))); |
679 | 0 | TALLOC_FREE(map); |
680 | 0 | return False; |
681 | 0 | } |
682 | | |
683 | | /* yes it's a mapped group */ |
684 | 0 | sid_peek_rid(&map->sid, rid); |
685 | 0 | *type = map->sid_name_use; |
686 | 0 | TALLOC_FREE(map); |
687 | 0 | return True; |
688 | 0 | } |
689 | | |
690 | | /************************************************************* |
691 | | Change a password entry in the local passdb backend. |
692 | | |
693 | | Assumptions: |
694 | | - always called as root |
695 | | - ignores the account type except when adding a new account |
696 | | - will create/delete the unix account if the relative |
697 | | add/delete user script is configured |
698 | | |
699 | | *************************************************************/ |
700 | | |
701 | | NTSTATUS local_password_change(const char *user_name, |
702 | | int local_flags, |
703 | | const char *new_passwd, |
704 | | char **pp_err_str, |
705 | | char **pp_msg_str) |
706 | 0 | { |
707 | 0 | TALLOC_CTX *tosctx; |
708 | 0 | struct samu *sam_pass; |
709 | 0 | uint32_t acb; |
710 | 0 | uint32_t rid; |
711 | 0 | NTSTATUS result; |
712 | 0 | bool user_exists; |
713 | 0 | int ret = -1; |
714 | |
|
715 | 0 | *pp_err_str = NULL; |
716 | 0 | *pp_msg_str = NULL; |
717 | |
|
718 | 0 | tosctx = talloc_tos(); |
719 | |
|
720 | 0 | sam_pass = samu_new(tosctx); |
721 | 0 | if (!sam_pass) { |
722 | 0 | result = NT_STATUS_NO_MEMORY; |
723 | 0 | goto done; |
724 | 0 | } |
725 | | |
726 | | /* Get the smb passwd entry for this user */ |
727 | 0 | user_exists = pdb_getsampwnam(sam_pass, user_name); |
728 | | |
729 | | /* Check delete first, we don't need to do anything else if we |
730 | | * are going to delete the account */ |
731 | 0 | if (user_exists && (local_flags & LOCAL_DELETE_USER)) { |
732 | |
|
733 | 0 | result = pdb_delete_user(tosctx, sam_pass); |
734 | 0 | if (!NT_STATUS_IS_OK(result)) { |
735 | 0 | ret = asprintf(pp_err_str, |
736 | 0 | "Failed to delete entry for user %s.\n", |
737 | 0 | user_name); |
738 | 0 | if (ret < 0) { |
739 | 0 | *pp_err_str = NULL; |
740 | 0 | } |
741 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
742 | 0 | } else { |
743 | 0 | ret = asprintf(pp_msg_str, |
744 | 0 | "Deleted user %s.\n", |
745 | 0 | user_name); |
746 | 0 | if (ret < 0) { |
747 | 0 | *pp_msg_str = NULL; |
748 | 0 | } |
749 | 0 | } |
750 | 0 | goto done; |
751 | 0 | } |
752 | | |
753 | 0 | if (user_exists && (local_flags & LOCAL_ADD_USER)) { |
754 | | /* the entry already existed */ |
755 | 0 | local_flags &= ~LOCAL_ADD_USER; |
756 | 0 | } |
757 | |
|
758 | 0 | if (!user_exists && !(local_flags & LOCAL_ADD_USER)) { |
759 | 0 | ret = asprintf(pp_err_str, |
760 | 0 | "Failed to find entry for user %s.\n", |
761 | 0 | user_name); |
762 | 0 | if (ret < 0) { |
763 | 0 | *pp_err_str = NULL; |
764 | 0 | } |
765 | 0 | result = NT_STATUS_NO_SUCH_USER; |
766 | 0 | goto done; |
767 | 0 | } |
768 | | |
769 | | /* First thing add the new user if we are required to do so */ |
770 | 0 | if (local_flags & LOCAL_ADD_USER) { |
771 | |
|
772 | 0 | if (local_flags & LOCAL_TRUST_ACCOUNT) { |
773 | 0 | acb = ACB_WSTRUST; |
774 | 0 | } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { |
775 | 0 | acb = ACB_DOMTRUST; |
776 | 0 | } else { |
777 | 0 | acb = ACB_NORMAL; |
778 | 0 | } |
779 | |
|
780 | 0 | result = pdb_create_user(tosctx, user_name, acb, &rid); |
781 | 0 | if (!NT_STATUS_IS_OK(result)) { |
782 | 0 | ret = asprintf(pp_err_str, |
783 | 0 | "Failed to add entry for user %s.\n", |
784 | 0 | user_name); |
785 | 0 | if (ret < 0) { |
786 | 0 | *pp_err_str = NULL; |
787 | 0 | } |
788 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
789 | 0 | goto done; |
790 | 0 | } |
791 | | |
792 | 0 | sam_pass = samu_new(tosctx); |
793 | 0 | if (!sam_pass) { |
794 | 0 | result = NT_STATUS_NO_MEMORY; |
795 | 0 | goto done; |
796 | 0 | } |
797 | | |
798 | | /* Now get back the smb passwd entry for this new user */ |
799 | 0 | user_exists = pdb_getsampwnam(sam_pass, user_name); |
800 | 0 | if (!user_exists) { |
801 | 0 | ret = asprintf(pp_err_str, |
802 | 0 | "Failed to add entry for user %s.\n", |
803 | 0 | user_name); |
804 | 0 | if (ret < 0) { |
805 | 0 | *pp_err_str = NULL; |
806 | 0 | } |
807 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
808 | 0 | goto done; |
809 | 0 | } |
810 | 0 | } |
811 | | |
812 | 0 | acb = pdb_get_acct_ctrl(sam_pass); |
813 | | |
814 | | /* |
815 | | * We are root - just write the new password |
816 | | * and the valid last change time. |
817 | | */ |
818 | 0 | if ((local_flags & LOCAL_SET_NO_PASSWORD) && !(acb & ACB_PWNOTREQ)) { |
819 | 0 | acb |= ACB_PWNOTREQ; |
820 | 0 | if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) { |
821 | 0 | ret = asprintf(pp_err_str, |
822 | 0 | "Failed to set 'no password required' " |
823 | 0 | "flag for user %s.\n", user_name); |
824 | 0 | if (ret < 0) { |
825 | 0 | *pp_err_str = NULL; |
826 | 0 | } |
827 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
828 | 0 | goto done; |
829 | 0 | } |
830 | 0 | } |
831 | | |
832 | 0 | if (local_flags & LOCAL_SET_PASSWORD) { |
833 | | /* |
834 | | * If we're dealing with setting a completely empty user account |
835 | | * ie. One with a password of 'XXXX', but not set disabled (like |
836 | | * an account created from scratch) then if the old password was |
837 | | * 'XX's then getsmbpwent will have set the ACB_DISABLED flag. |
838 | | * We remove that as we're giving this user their first password |
839 | | * and the decision hasn't really been made to disable them (ie. |
840 | | * don't create them disabled). JRA. |
841 | | */ |
842 | 0 | if ((pdb_get_lanman_passwd(sam_pass) == NULL) && |
843 | 0 | (acb & ACB_DISABLED)) { |
844 | 0 | acb &= (~ACB_DISABLED); |
845 | 0 | if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) { |
846 | 0 | ret = asprintf(pp_err_str, |
847 | 0 | "Failed to unset 'disabled' " |
848 | 0 | "flag for user %s.\n", |
849 | 0 | user_name); |
850 | 0 | if (ret < 0) { |
851 | 0 | *pp_err_str = NULL; |
852 | 0 | } |
853 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
854 | 0 | goto done; |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | 0 | acb &= (~ACB_PWNOTREQ); |
859 | 0 | if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) { |
860 | 0 | ret = asprintf(pp_err_str, |
861 | 0 | "Failed to unset 'no password required'" |
862 | 0 | " flag for user %s.\n", user_name); |
863 | 0 | if (ret < 0) { |
864 | 0 | *pp_err_str = NULL; |
865 | 0 | } |
866 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
867 | 0 | goto done; |
868 | 0 | } |
869 | | |
870 | 0 | if (!pdb_set_plaintext_passwd(sam_pass, new_passwd)) { |
871 | 0 | ret = asprintf(pp_err_str, |
872 | 0 | "Failed to set password for " |
873 | 0 | "user %s.\n", user_name); |
874 | 0 | if (ret < 0) { |
875 | 0 | *pp_err_str = NULL; |
876 | 0 | } |
877 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
878 | 0 | goto done; |
879 | 0 | } |
880 | 0 | } |
881 | | |
882 | 0 | if ((local_flags & LOCAL_DISABLE_USER) && !(acb & ACB_DISABLED)) { |
883 | 0 | acb |= ACB_DISABLED; |
884 | 0 | if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) { |
885 | 0 | ret = asprintf(pp_err_str, |
886 | 0 | "Failed to set 'disabled' flag for " |
887 | 0 | "user %s.\n", user_name); |
888 | 0 | if (ret < 0) { |
889 | 0 | *pp_err_str = NULL; |
890 | 0 | } |
891 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
892 | 0 | goto done; |
893 | 0 | } |
894 | 0 | } |
895 | | |
896 | 0 | if ((local_flags & LOCAL_ENABLE_USER) && (acb & ACB_DISABLED)) { |
897 | 0 | acb &= (~ACB_DISABLED); |
898 | 0 | if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) { |
899 | 0 | ret = asprintf(pp_err_str, |
900 | 0 | "Failed to unset 'disabled' flag for " |
901 | 0 | "user %s.\n", user_name); |
902 | 0 | if (ret < 0) { |
903 | 0 | *pp_err_str = NULL; |
904 | 0 | } |
905 | 0 | result = NT_STATUS_UNSUCCESSFUL; |
906 | 0 | goto done; |
907 | 0 | } |
908 | 0 | } |
909 | | |
910 | | /* now commit changes if any */ |
911 | 0 | result = pdb_update_sam_account(sam_pass); |
912 | 0 | if (!NT_STATUS_IS_OK(result)) { |
913 | 0 | ret = asprintf(pp_err_str, |
914 | 0 | "Failed to modify entry for user %s.\n", |
915 | 0 | user_name); |
916 | 0 | if (ret < 0) { |
917 | 0 | *pp_err_str = NULL; |
918 | 0 | } |
919 | 0 | goto done; |
920 | 0 | } |
921 | | |
922 | 0 | if (local_flags & LOCAL_ADD_USER) { |
923 | 0 | ret = asprintf(pp_msg_str, "Added user %s.\n", user_name); |
924 | 0 | } else if (local_flags & LOCAL_DISABLE_USER) { |
925 | 0 | ret = asprintf(pp_msg_str, "Disabled user %s.\n", user_name); |
926 | 0 | } else if (local_flags & LOCAL_ENABLE_USER) { |
927 | 0 | ret = asprintf(pp_msg_str, "Enabled user %s.\n", user_name); |
928 | 0 | } else if (local_flags & LOCAL_SET_NO_PASSWORD) { |
929 | 0 | ret = asprintf(pp_msg_str, |
930 | 0 | "User %s password set to none.\n", user_name); |
931 | 0 | } |
932 | |
|
933 | 0 | if (ret < 0) { |
934 | 0 | *pp_msg_str = NULL; |
935 | 0 | } |
936 | |
|
937 | 0 | result = NT_STATUS_OK; |
938 | |
|
939 | 0 | done: |
940 | 0 | TALLOC_FREE(sam_pass); |
941 | 0 | return result; |
942 | 0 | } |
943 | | |
944 | | /********************************************************************** |
945 | | Marshall/unmarshall struct samu structs. |
946 | | *********************************************************************/ |
947 | | |
948 | 0 | #define SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" |
949 | 0 | #define SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" |
950 | 0 | #define SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" |
951 | 0 | #define SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" |
952 | | /* nothing changed between V3 and V4 */ |
953 | | |
954 | | /********************************************************************* |
955 | | *********************************************************************/ |
956 | | |
957 | | static bool init_samu_from_buffer_v0(struct samu *sampass, uint8_t *buf, uint32_t buflen) |
958 | 0 | { |
959 | | |
960 | | /* times are stored as 32bit integer |
961 | | take care on system with 64bit wide time_t |
962 | | --SSS */ |
963 | 0 | uint32_t logon_time, |
964 | 0 | logoff_time, |
965 | 0 | kickoff_time, |
966 | 0 | pass_last_set_time, |
967 | 0 | pass_can_change_time, |
968 | 0 | pass_must_change_time; |
969 | 0 | char *username = NULL; |
970 | 0 | char *domain = NULL; |
971 | 0 | char *nt_username = NULL; |
972 | 0 | char *dir_drive = NULL; |
973 | 0 | char *unknown_str = NULL; |
974 | 0 | char *munged_dial = NULL; |
975 | 0 | char *fullname = NULL; |
976 | 0 | char *homedir = NULL; |
977 | 0 | char *logon_script = NULL; |
978 | 0 | char *profile_path = NULL; |
979 | 0 | char *acct_desc = NULL; |
980 | 0 | char *workstations = NULL; |
981 | 0 | uint32_t username_len, domain_len, nt_username_len, |
982 | 0 | dir_drive_len, unknown_str_len, munged_dial_len, |
983 | 0 | fullname_len, homedir_len, logon_script_len, |
984 | 0 | profile_path_len, acct_desc_len, workstations_len; |
985 | |
|
986 | 0 | uint32_t user_rid, group_rid, remove_me, hours_len, unknown_6; |
987 | 0 | uint16_t acct_ctrl, logon_divs; |
988 | 0 | uint16_t bad_password_count, logon_count; |
989 | 0 | uint8_t *hours = NULL; |
990 | 0 | uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; |
991 | 0 | uint32_t len = 0; |
992 | 0 | uint32_t lm_pw_len, nt_pw_len, hourslen; |
993 | 0 | bool ret = True; |
994 | |
|
995 | 0 | if(sampass == NULL || buf == NULL) { |
996 | 0 | DEBUG(0, ("init_samu_from_buffer_v0: NULL parameters found!\n")); |
997 | 0 | return False; |
998 | 0 | } |
999 | | |
1000 | | /* SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */ |
1001 | | |
1002 | | /* unpack the buffer into variables */ |
1003 | 0 | len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V0, |
1004 | 0 | &logon_time, /* d */ |
1005 | 0 | &logoff_time, /* d */ |
1006 | 0 | &kickoff_time, /* d */ |
1007 | 0 | &pass_last_set_time, /* d */ |
1008 | 0 | &pass_can_change_time, /* d */ |
1009 | 0 | &pass_must_change_time, /* d */ |
1010 | 0 | &username_len, &username, /* B */ |
1011 | 0 | &domain_len, &domain, /* B */ |
1012 | 0 | &nt_username_len, &nt_username, /* B */ |
1013 | 0 | &fullname_len, &fullname, /* B */ |
1014 | 0 | &homedir_len, &homedir, /* B */ |
1015 | 0 | &dir_drive_len, &dir_drive, /* B */ |
1016 | 0 | &logon_script_len, &logon_script, /* B */ |
1017 | 0 | &profile_path_len, &profile_path, /* B */ |
1018 | 0 | &acct_desc_len, &acct_desc, /* B */ |
1019 | 0 | &workstations_len, &workstations, /* B */ |
1020 | 0 | &unknown_str_len, &unknown_str, /* B */ |
1021 | 0 | &munged_dial_len, &munged_dial, /* B */ |
1022 | 0 | &user_rid, /* d */ |
1023 | 0 | &group_rid, /* d */ |
1024 | 0 | &lm_pw_len, &lm_pw_ptr, /* B */ |
1025 | 0 | &nt_pw_len, &nt_pw_ptr, /* B */ |
1026 | 0 | &acct_ctrl, /* w */ |
1027 | 0 | &remove_me, /* remove on the next TDB_FORMAT upgrade */ /* d */ |
1028 | 0 | &logon_divs, /* w */ |
1029 | 0 | &hours_len, /* d */ |
1030 | 0 | &hourslen, &hours, /* B */ |
1031 | 0 | &bad_password_count, /* w */ |
1032 | 0 | &logon_count, /* w */ |
1033 | 0 | &unknown_6); /* d */ |
1034 | |
|
1035 | 0 | if (len == (uint32_t) -1) { |
1036 | 0 | ret = False; |
1037 | 0 | goto done; |
1038 | 0 | } |
1039 | | |
1040 | 0 | pdb_set_logon_time(sampass, logon_time, PDB_SET); |
1041 | 0 | pdb_set_logoff_time(sampass, logoff_time, PDB_SET); |
1042 | 0 | pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); |
1043 | 0 | pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); |
1044 | 0 | pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); |
1045 | |
|
1046 | 0 | pdb_set_username(sampass, username, PDB_SET); |
1047 | 0 | pdb_set_domain(sampass, domain, PDB_SET); |
1048 | 0 | pdb_set_nt_username(sampass, nt_username, PDB_SET); |
1049 | 0 | pdb_set_fullname(sampass, fullname, PDB_SET); |
1050 | |
|
1051 | 0 | if (homedir) { |
1052 | 0 | pdb_set_homedir(sampass, homedir, PDB_SET); |
1053 | 0 | } |
1054 | 0 | else { |
1055 | 0 | pdb_set_homedir(sampass, |
1056 | 0 | talloc_sub_basic(sampass, username, domain, |
1057 | 0 | lp_logon_home()), |
1058 | 0 | PDB_DEFAULT); |
1059 | 0 | } |
1060 | |
|
1061 | 0 | if (dir_drive) |
1062 | 0 | pdb_set_dir_drive(sampass, dir_drive, PDB_SET); |
1063 | 0 | else { |
1064 | 0 | pdb_set_dir_drive(sampass, |
1065 | 0 | talloc_sub_basic(sampass, username, domain, |
1066 | 0 | lp_logon_drive()), |
1067 | 0 | PDB_DEFAULT); |
1068 | 0 | } |
1069 | |
|
1070 | 0 | if (logon_script) |
1071 | 0 | pdb_set_logon_script(sampass, logon_script, PDB_SET); |
1072 | 0 | else { |
1073 | 0 | pdb_set_logon_script(sampass, |
1074 | 0 | talloc_sub_basic(sampass, username, domain, |
1075 | 0 | lp_logon_script()), |
1076 | 0 | PDB_DEFAULT); |
1077 | 0 | } |
1078 | |
|
1079 | 0 | if (profile_path) { |
1080 | 0 | pdb_set_profile_path(sampass, profile_path, PDB_SET); |
1081 | 0 | } else { |
1082 | 0 | pdb_set_profile_path(sampass, |
1083 | 0 | talloc_sub_basic(sampass, username, domain, |
1084 | 0 | lp_logon_path()), |
1085 | 0 | PDB_DEFAULT); |
1086 | 0 | } |
1087 | |
|
1088 | 0 | pdb_set_acct_desc(sampass, acct_desc, PDB_SET); |
1089 | 0 | pdb_set_workstations(sampass, workstations, PDB_SET); |
1090 | 0 | pdb_set_munged_dial(sampass, munged_dial, PDB_SET); |
1091 | |
|
1092 | 0 | if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { |
1093 | 0 | if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { |
1094 | 0 | ret = False; |
1095 | 0 | goto done; |
1096 | 0 | } |
1097 | 0 | } |
1098 | | |
1099 | 0 | if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { |
1100 | 0 | if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { |
1101 | 0 | ret = False; |
1102 | 0 | goto done; |
1103 | 0 | } |
1104 | 0 | } |
1105 | | |
1106 | 0 | pdb_set_pw_history(sampass, NULL, 0, PDB_SET); |
1107 | 0 | pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); |
1108 | 0 | pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); |
1109 | 0 | pdb_set_hours_len(sampass, hours_len, PDB_SET); |
1110 | 0 | pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); |
1111 | 0 | pdb_set_logon_count(sampass, logon_count, PDB_SET); |
1112 | 0 | pdb_set_unknown_6(sampass, unknown_6, PDB_SET); |
1113 | 0 | pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); |
1114 | 0 | pdb_set_logon_divs(sampass, logon_divs, PDB_SET); |
1115 | 0 | pdb_set_hours(sampass, hours, hours_len, PDB_SET); |
1116 | |
|
1117 | 0 | done: |
1118 | |
|
1119 | 0 | SAFE_FREE(username); |
1120 | 0 | SAFE_FREE(domain); |
1121 | 0 | SAFE_FREE(nt_username); |
1122 | 0 | SAFE_FREE(fullname); |
1123 | 0 | SAFE_FREE(homedir); |
1124 | 0 | SAFE_FREE(dir_drive); |
1125 | 0 | SAFE_FREE(logon_script); |
1126 | 0 | SAFE_FREE(profile_path); |
1127 | 0 | SAFE_FREE(acct_desc); |
1128 | 0 | SAFE_FREE(workstations); |
1129 | 0 | SAFE_FREE(munged_dial); |
1130 | 0 | SAFE_FREE(unknown_str); |
1131 | 0 | SAFE_FREE(lm_pw_ptr); |
1132 | 0 | SAFE_FREE(nt_pw_ptr); |
1133 | 0 | SAFE_FREE(hours); |
1134 | |
|
1135 | 0 | return ret; |
1136 | 0 | } |
1137 | | |
1138 | | /********************************************************************* |
1139 | | *********************************************************************/ |
1140 | | |
1141 | | static bool init_samu_from_buffer_v1(struct samu *sampass, uint8_t *buf, uint32_t buflen) |
1142 | 0 | { |
1143 | | |
1144 | | /* times are stored as 32bit integer |
1145 | | take care on system with 64bit wide time_t |
1146 | | --SSS */ |
1147 | 0 | uint32_t logon_time, |
1148 | 0 | logoff_time, |
1149 | 0 | kickoff_time, |
1150 | 0 | bad_password_time, |
1151 | 0 | pass_last_set_time, |
1152 | 0 | pass_can_change_time, |
1153 | 0 | pass_must_change_time; |
1154 | 0 | char *username = NULL; |
1155 | 0 | char *domain = NULL; |
1156 | 0 | char *nt_username = NULL; |
1157 | 0 | char *dir_drive = NULL; |
1158 | 0 | char *unknown_str = NULL; |
1159 | 0 | char *munged_dial = NULL; |
1160 | 0 | char *fullname = NULL; |
1161 | 0 | char *homedir = NULL; |
1162 | 0 | char *logon_script = NULL; |
1163 | 0 | char *profile_path = NULL; |
1164 | 0 | char *acct_desc = NULL; |
1165 | 0 | char *workstations = NULL; |
1166 | 0 | uint32_t username_len, domain_len, nt_username_len, |
1167 | 0 | dir_drive_len, unknown_str_len, munged_dial_len, |
1168 | 0 | fullname_len, homedir_len, logon_script_len, |
1169 | 0 | profile_path_len, acct_desc_len, workstations_len; |
1170 | |
|
1171 | 0 | uint32_t user_rid, group_rid, remove_me, hours_len, unknown_6; |
1172 | 0 | uint16_t acct_ctrl, logon_divs; |
1173 | 0 | uint16_t bad_password_count, logon_count; |
1174 | 0 | uint8_t *hours = NULL; |
1175 | 0 | uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; |
1176 | 0 | uint32_t len = 0; |
1177 | 0 | uint32_t lm_pw_len, nt_pw_len, hourslen; |
1178 | 0 | bool ret = True; |
1179 | |
|
1180 | 0 | if(sampass == NULL || buf == NULL) { |
1181 | 0 | DEBUG(0, ("init_samu_from_buffer_v1: NULL parameters found!\n")); |
1182 | 0 | return False; |
1183 | 0 | } |
1184 | | |
1185 | | /* SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */ |
1186 | | |
1187 | | /* unpack the buffer into variables */ |
1188 | 0 | len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V1, |
1189 | 0 | &logon_time, /* d */ |
1190 | 0 | &logoff_time, /* d */ |
1191 | 0 | &kickoff_time, /* d */ |
1192 | | /* Change from V0 is addition of bad_password_time field. */ |
1193 | 0 | &bad_password_time, /* d */ |
1194 | 0 | &pass_last_set_time, /* d */ |
1195 | 0 | &pass_can_change_time, /* d */ |
1196 | 0 | &pass_must_change_time, /* d */ |
1197 | 0 | &username_len, &username, /* B */ |
1198 | 0 | &domain_len, &domain, /* B */ |
1199 | 0 | &nt_username_len, &nt_username, /* B */ |
1200 | 0 | &fullname_len, &fullname, /* B */ |
1201 | 0 | &homedir_len, &homedir, /* B */ |
1202 | 0 | &dir_drive_len, &dir_drive, /* B */ |
1203 | 0 | &logon_script_len, &logon_script, /* B */ |
1204 | 0 | &profile_path_len, &profile_path, /* B */ |
1205 | 0 | &acct_desc_len, &acct_desc, /* B */ |
1206 | 0 | &workstations_len, &workstations, /* B */ |
1207 | 0 | &unknown_str_len, &unknown_str, /* B */ |
1208 | 0 | &munged_dial_len, &munged_dial, /* B */ |
1209 | 0 | &user_rid, /* d */ |
1210 | 0 | &group_rid, /* d */ |
1211 | 0 | &lm_pw_len, &lm_pw_ptr, /* B */ |
1212 | 0 | &nt_pw_len, &nt_pw_ptr, /* B */ |
1213 | 0 | &acct_ctrl, /* w */ |
1214 | 0 | &remove_me, /* d */ |
1215 | 0 | &logon_divs, /* w */ |
1216 | 0 | &hours_len, /* d */ |
1217 | 0 | &hourslen, &hours, /* B */ |
1218 | 0 | &bad_password_count, /* w */ |
1219 | 0 | &logon_count, /* w */ |
1220 | 0 | &unknown_6); /* d */ |
1221 | |
|
1222 | 0 | if (len == (uint32_t) -1) { |
1223 | 0 | ret = False; |
1224 | 0 | goto done; |
1225 | 0 | } |
1226 | | |
1227 | 0 | pdb_set_logon_time(sampass, logon_time, PDB_SET); |
1228 | 0 | pdb_set_logoff_time(sampass, logoff_time, PDB_SET); |
1229 | 0 | pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); |
1230 | | |
1231 | | /* Change from V0 is addition of bad_password_time field. */ |
1232 | 0 | pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); |
1233 | 0 | pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); |
1234 | 0 | pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); |
1235 | |
|
1236 | 0 | pdb_set_username(sampass, username, PDB_SET); |
1237 | 0 | pdb_set_domain(sampass, domain, PDB_SET); |
1238 | 0 | pdb_set_nt_username(sampass, nt_username, PDB_SET); |
1239 | 0 | pdb_set_fullname(sampass, fullname, PDB_SET); |
1240 | |
|
1241 | 0 | if (homedir) { |
1242 | 0 | pdb_set_homedir(sampass, homedir, PDB_SET); |
1243 | 0 | } |
1244 | 0 | else { |
1245 | 0 | pdb_set_homedir(sampass, |
1246 | 0 | talloc_sub_basic(sampass, username, domain, |
1247 | 0 | lp_logon_home()), |
1248 | 0 | PDB_DEFAULT); |
1249 | 0 | } |
1250 | |
|
1251 | 0 | if (dir_drive) |
1252 | 0 | pdb_set_dir_drive(sampass, dir_drive, PDB_SET); |
1253 | 0 | else { |
1254 | 0 | pdb_set_dir_drive(sampass, |
1255 | 0 | talloc_sub_basic(sampass, username, domain, |
1256 | 0 | lp_logon_drive()), |
1257 | 0 | PDB_DEFAULT); |
1258 | 0 | } |
1259 | |
|
1260 | 0 | if (logon_script) |
1261 | 0 | pdb_set_logon_script(sampass, logon_script, PDB_SET); |
1262 | 0 | else { |
1263 | 0 | pdb_set_logon_script(sampass, |
1264 | 0 | talloc_sub_basic(sampass, username, domain, |
1265 | 0 | lp_logon_script()), |
1266 | 0 | PDB_DEFAULT); |
1267 | 0 | } |
1268 | |
|
1269 | 0 | if (profile_path) { |
1270 | 0 | pdb_set_profile_path(sampass, profile_path, PDB_SET); |
1271 | 0 | } else { |
1272 | 0 | pdb_set_profile_path(sampass, |
1273 | 0 | talloc_sub_basic(sampass, username, domain, |
1274 | 0 | lp_logon_path()), |
1275 | 0 | PDB_DEFAULT); |
1276 | 0 | } |
1277 | |
|
1278 | 0 | pdb_set_acct_desc(sampass, acct_desc, PDB_SET); |
1279 | 0 | pdb_set_workstations(sampass, workstations, PDB_SET); |
1280 | 0 | pdb_set_munged_dial(sampass, munged_dial, PDB_SET); |
1281 | |
|
1282 | 0 | if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { |
1283 | 0 | if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { |
1284 | 0 | ret = False; |
1285 | 0 | goto done; |
1286 | 0 | } |
1287 | 0 | } |
1288 | | |
1289 | 0 | if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { |
1290 | 0 | if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { |
1291 | 0 | ret = False; |
1292 | 0 | goto done; |
1293 | 0 | } |
1294 | 0 | } |
1295 | | |
1296 | 0 | pdb_set_pw_history(sampass, NULL, 0, PDB_SET); |
1297 | |
|
1298 | 0 | pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); |
1299 | 0 | pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); |
1300 | 0 | pdb_set_hours_len(sampass, hours_len, PDB_SET); |
1301 | 0 | pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); |
1302 | 0 | pdb_set_logon_count(sampass, logon_count, PDB_SET); |
1303 | 0 | pdb_set_unknown_6(sampass, unknown_6, PDB_SET); |
1304 | 0 | pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); |
1305 | 0 | pdb_set_logon_divs(sampass, logon_divs, PDB_SET); |
1306 | 0 | pdb_set_hours(sampass, hours, hours_len, PDB_SET); |
1307 | |
|
1308 | 0 | done: |
1309 | |
|
1310 | 0 | SAFE_FREE(username); |
1311 | 0 | SAFE_FREE(domain); |
1312 | 0 | SAFE_FREE(nt_username); |
1313 | 0 | SAFE_FREE(fullname); |
1314 | 0 | SAFE_FREE(homedir); |
1315 | 0 | SAFE_FREE(dir_drive); |
1316 | 0 | SAFE_FREE(logon_script); |
1317 | 0 | SAFE_FREE(profile_path); |
1318 | 0 | SAFE_FREE(acct_desc); |
1319 | 0 | SAFE_FREE(workstations); |
1320 | 0 | SAFE_FREE(munged_dial); |
1321 | 0 | SAFE_FREE(unknown_str); |
1322 | 0 | SAFE_FREE(lm_pw_ptr); |
1323 | 0 | SAFE_FREE(nt_pw_ptr); |
1324 | 0 | SAFE_FREE(hours); |
1325 | |
|
1326 | 0 | return ret; |
1327 | 0 | } |
1328 | | |
1329 | | static bool init_samu_from_buffer_v2(struct samu *sampass, uint8_t *buf, uint32_t buflen) |
1330 | 0 | { |
1331 | | |
1332 | | /* times are stored as 32bit integer |
1333 | | take care on system with 64bit wide time_t |
1334 | | --SSS */ |
1335 | 0 | uint32_t logon_time, |
1336 | 0 | logoff_time, |
1337 | 0 | kickoff_time, |
1338 | 0 | bad_password_time, |
1339 | 0 | pass_last_set_time, |
1340 | 0 | pass_can_change_time, |
1341 | 0 | pass_must_change_time; |
1342 | 0 | char *username = NULL; |
1343 | 0 | char *domain = NULL; |
1344 | 0 | char *nt_username = NULL; |
1345 | 0 | char *dir_drive = NULL; |
1346 | 0 | char *unknown_str = NULL; |
1347 | 0 | char *munged_dial = NULL; |
1348 | 0 | char *fullname = NULL; |
1349 | 0 | char *homedir = NULL; |
1350 | 0 | char *logon_script = NULL; |
1351 | 0 | char *profile_path = NULL; |
1352 | 0 | char *acct_desc = NULL; |
1353 | 0 | char *workstations = NULL; |
1354 | 0 | uint32_t username_len, domain_len, nt_username_len, |
1355 | 0 | dir_drive_len, unknown_str_len, munged_dial_len, |
1356 | 0 | fullname_len, homedir_len, logon_script_len, |
1357 | 0 | profile_path_len, acct_desc_len, workstations_len; |
1358 | |
|
1359 | 0 | uint32_t user_rid, group_rid, hours_len, unknown_6; |
1360 | 0 | uint16_t acct_ctrl, logon_divs; |
1361 | 0 | uint16_t bad_password_count, logon_count; |
1362 | 0 | uint8_t *hours = NULL; |
1363 | 0 | uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL; |
1364 | 0 | uint32_t len = 0; |
1365 | 0 | uint32_t lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen; |
1366 | 0 | uint32_t pwHistLen = 0; |
1367 | 0 | bool ret = True; |
1368 | 0 | fstring tmp_string; |
1369 | 0 | bool expand_explicit = lp_passdb_expand_explicit(); |
1370 | |
|
1371 | 0 | if(sampass == NULL || buf == NULL) { |
1372 | 0 | DEBUG(0, ("init_samu_from_buffer_v2: NULL parameters found!\n")); |
1373 | 0 | return False; |
1374 | 0 | } |
1375 | | |
1376 | | /* SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ |
1377 | | |
1378 | | /* unpack the buffer into variables */ |
1379 | 0 | len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V2, |
1380 | 0 | &logon_time, /* d */ |
1381 | 0 | &logoff_time, /* d */ |
1382 | 0 | &kickoff_time, /* d */ |
1383 | 0 | &bad_password_time, /* d */ |
1384 | 0 | &pass_last_set_time, /* d */ |
1385 | 0 | &pass_can_change_time, /* d */ |
1386 | 0 | &pass_must_change_time, /* d */ |
1387 | 0 | &username_len, &username, /* B */ |
1388 | 0 | &domain_len, &domain, /* B */ |
1389 | 0 | &nt_username_len, &nt_username, /* B */ |
1390 | 0 | &fullname_len, &fullname, /* B */ |
1391 | 0 | &homedir_len, &homedir, /* B */ |
1392 | 0 | &dir_drive_len, &dir_drive, /* B */ |
1393 | 0 | &logon_script_len, &logon_script, /* B */ |
1394 | 0 | &profile_path_len, &profile_path, /* B */ |
1395 | 0 | &acct_desc_len, &acct_desc, /* B */ |
1396 | 0 | &workstations_len, &workstations, /* B */ |
1397 | 0 | &unknown_str_len, &unknown_str, /* B */ |
1398 | 0 | &munged_dial_len, &munged_dial, /* B */ |
1399 | 0 | &user_rid, /* d */ |
1400 | 0 | &group_rid, /* d */ |
1401 | 0 | &lm_pw_len, &lm_pw_ptr, /* B */ |
1402 | 0 | &nt_pw_len, &nt_pw_ptr, /* B */ |
1403 | | /* Change from V1 is addition of password history field. */ |
1404 | 0 | &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */ |
1405 | 0 | &acct_ctrl, /* w */ |
1406 | | /* Also "remove_me" field was removed. */ |
1407 | 0 | &logon_divs, /* w */ |
1408 | 0 | &hours_len, /* d */ |
1409 | 0 | &hourslen, &hours, /* B */ |
1410 | 0 | &bad_password_count, /* w */ |
1411 | 0 | &logon_count, /* w */ |
1412 | 0 | &unknown_6); /* d */ |
1413 | |
|
1414 | 0 | if (len == (uint32_t) -1) { |
1415 | 0 | ret = False; |
1416 | 0 | goto done; |
1417 | 0 | } |
1418 | | |
1419 | 0 | pdb_set_logon_time(sampass, logon_time, PDB_SET); |
1420 | 0 | pdb_set_logoff_time(sampass, logoff_time, PDB_SET); |
1421 | 0 | pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); |
1422 | 0 | pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); |
1423 | 0 | pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); |
1424 | 0 | pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); |
1425 | |
|
1426 | 0 | pdb_set_username(sampass, username, PDB_SET); |
1427 | 0 | pdb_set_domain(sampass, domain, PDB_SET); |
1428 | 0 | pdb_set_nt_username(sampass, nt_username, PDB_SET); |
1429 | 0 | pdb_set_fullname(sampass, fullname, PDB_SET); |
1430 | |
|
1431 | 0 | if (homedir) { |
1432 | 0 | fstrcpy( tmp_string, homedir ); |
1433 | 0 | if (expand_explicit) { |
1434 | 0 | standard_sub_basic( username, domain, tmp_string, |
1435 | 0 | sizeof(tmp_string) ); |
1436 | 0 | } |
1437 | 0 | pdb_set_homedir(sampass, tmp_string, PDB_SET); |
1438 | 0 | } |
1439 | 0 | else { |
1440 | 0 | pdb_set_homedir(sampass, |
1441 | 0 | talloc_sub_basic(sampass, username, domain, |
1442 | 0 | lp_logon_home()), |
1443 | 0 | PDB_DEFAULT); |
1444 | 0 | } |
1445 | |
|
1446 | 0 | if (dir_drive) |
1447 | 0 | pdb_set_dir_drive(sampass, dir_drive, PDB_SET); |
1448 | 0 | else |
1449 | 0 | pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT ); |
1450 | |
|
1451 | 0 | if (logon_script) { |
1452 | 0 | fstrcpy( tmp_string, logon_script ); |
1453 | 0 | if (expand_explicit) { |
1454 | 0 | standard_sub_basic( username, domain, tmp_string, |
1455 | 0 | sizeof(tmp_string) ); |
1456 | 0 | } |
1457 | 0 | pdb_set_logon_script(sampass, tmp_string, PDB_SET); |
1458 | 0 | } |
1459 | 0 | else { |
1460 | 0 | pdb_set_logon_script(sampass, |
1461 | 0 | talloc_sub_basic(sampass, username, domain, |
1462 | 0 | lp_logon_script()), |
1463 | 0 | PDB_DEFAULT); |
1464 | 0 | } |
1465 | |
|
1466 | 0 | if (profile_path) { |
1467 | 0 | fstrcpy( tmp_string, profile_path ); |
1468 | 0 | if (expand_explicit) { |
1469 | 0 | standard_sub_basic( username, domain, tmp_string, |
1470 | 0 | sizeof(tmp_string) ); |
1471 | 0 | } |
1472 | 0 | pdb_set_profile_path(sampass, tmp_string, PDB_SET); |
1473 | 0 | } |
1474 | 0 | else { |
1475 | 0 | pdb_set_profile_path(sampass, |
1476 | 0 | talloc_sub_basic(sampass, username, domain, |
1477 | 0 | lp_logon_path()), |
1478 | 0 | PDB_DEFAULT); |
1479 | 0 | } |
1480 | |
|
1481 | 0 | pdb_set_acct_desc(sampass, acct_desc, PDB_SET); |
1482 | 0 | pdb_set_workstations(sampass, workstations, PDB_SET); |
1483 | 0 | pdb_set_munged_dial(sampass, munged_dial, PDB_SET); |
1484 | |
|
1485 | 0 | if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { |
1486 | 0 | if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { |
1487 | 0 | ret = False; |
1488 | 0 | goto done; |
1489 | 0 | } |
1490 | 0 | } |
1491 | | |
1492 | 0 | if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { |
1493 | 0 | if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { |
1494 | 0 | ret = False; |
1495 | 0 | goto done; |
1496 | 0 | } |
1497 | 0 | } |
1498 | | |
1499 | | /* Change from V1 is addition of password history field. */ |
1500 | 0 | pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen); |
1501 | 0 | if (pwHistLen) { |
1502 | 0 | uint8_t *pw_hist = SMB_MALLOC_ARRAY(uint8_t, pwHistLen * PW_HISTORY_ENTRY_LEN); |
1503 | 0 | if (!pw_hist) { |
1504 | 0 | ret = False; |
1505 | 0 | goto done; |
1506 | 0 | } |
1507 | 0 | memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN); |
1508 | 0 | if (nt_pw_hist_ptr && nt_pw_hist_len) { |
1509 | 0 | int i; |
1510 | 0 | SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0); |
1511 | 0 | nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN; |
1512 | 0 | for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) { |
1513 | 0 | memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN], |
1514 | 0 | &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN], |
1515 | 0 | PW_HISTORY_ENTRY_LEN); |
1516 | 0 | } |
1517 | 0 | } |
1518 | 0 | if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) { |
1519 | 0 | SAFE_FREE(pw_hist); |
1520 | 0 | ret = False; |
1521 | 0 | goto done; |
1522 | 0 | } |
1523 | 0 | SAFE_FREE(pw_hist); |
1524 | 0 | } else { |
1525 | 0 | pdb_set_pw_history(sampass, NULL, 0, PDB_SET); |
1526 | 0 | } |
1527 | | |
1528 | 0 | pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); |
1529 | 0 | pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); |
1530 | 0 | pdb_set_hours_len(sampass, hours_len, PDB_SET); |
1531 | 0 | pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); |
1532 | 0 | pdb_set_logon_count(sampass, logon_count, PDB_SET); |
1533 | 0 | pdb_set_unknown_6(sampass, unknown_6, PDB_SET); |
1534 | 0 | pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); |
1535 | 0 | pdb_set_logon_divs(sampass, logon_divs, PDB_SET); |
1536 | 0 | pdb_set_hours(sampass, hours, hours_len, PDB_SET); |
1537 | |
|
1538 | 0 | done: |
1539 | |
|
1540 | 0 | SAFE_FREE(username); |
1541 | 0 | SAFE_FREE(domain); |
1542 | 0 | SAFE_FREE(nt_username); |
1543 | 0 | SAFE_FREE(fullname); |
1544 | 0 | SAFE_FREE(homedir); |
1545 | 0 | SAFE_FREE(dir_drive); |
1546 | 0 | SAFE_FREE(logon_script); |
1547 | 0 | SAFE_FREE(profile_path); |
1548 | 0 | SAFE_FREE(acct_desc); |
1549 | 0 | SAFE_FREE(workstations); |
1550 | 0 | SAFE_FREE(munged_dial); |
1551 | 0 | SAFE_FREE(unknown_str); |
1552 | 0 | SAFE_FREE(lm_pw_ptr); |
1553 | 0 | SAFE_FREE(nt_pw_ptr); |
1554 | 0 | SAFE_FREE(nt_pw_hist_ptr); |
1555 | 0 | SAFE_FREE(hours); |
1556 | |
|
1557 | 0 | return ret; |
1558 | 0 | } |
1559 | | |
1560 | | /********************************************************************* |
1561 | | *********************************************************************/ |
1562 | | |
1563 | | static bool init_samu_from_buffer_v3(struct samu *sampass, uint8_t *buf, uint32_t buflen) |
1564 | 0 | { |
1565 | | |
1566 | | /* times are stored as 32bit integer |
1567 | | take care on system with 64bit wide time_t |
1568 | | --SSS */ |
1569 | 0 | uint32_t logon_time, |
1570 | 0 | logoff_time, |
1571 | 0 | kickoff_time, |
1572 | 0 | bad_password_time, |
1573 | 0 | pass_last_set_time, |
1574 | 0 | pass_can_change_time, |
1575 | 0 | pass_must_change_time; |
1576 | 0 | char *username = NULL; |
1577 | 0 | char *domain = NULL; |
1578 | 0 | char *nt_username = NULL; |
1579 | 0 | char *dir_drive = NULL; |
1580 | 0 | char *comment = NULL; |
1581 | 0 | char *munged_dial = NULL; |
1582 | 0 | char *fullname = NULL; |
1583 | 0 | char *homedir = NULL; |
1584 | 0 | char *logon_script = NULL; |
1585 | 0 | char *profile_path = NULL; |
1586 | 0 | char *acct_desc = NULL; |
1587 | 0 | char *workstations = NULL; |
1588 | 0 | uint32_t username_len, domain_len, nt_username_len, |
1589 | 0 | dir_drive_len, comment_len, munged_dial_len, |
1590 | 0 | fullname_len, homedir_len, logon_script_len, |
1591 | 0 | profile_path_len, acct_desc_len, workstations_len; |
1592 | |
|
1593 | 0 | uint32_t user_rid, group_rid, hours_len, unknown_6, acct_ctrl; |
1594 | 0 | uint16_t logon_divs; |
1595 | 0 | uint16_t bad_password_count, logon_count; |
1596 | 0 | uint8_t *hours = NULL; |
1597 | 0 | uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL; |
1598 | 0 | uint32_t len = 0; |
1599 | 0 | uint32_t lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen; |
1600 | 0 | uint32_t pwHistLen = 0; |
1601 | 0 | bool ret = True; |
1602 | 0 | fstring tmp_string; |
1603 | 0 | bool expand_explicit = lp_passdb_expand_explicit(); |
1604 | |
|
1605 | 0 | if(sampass == NULL || buf == NULL) { |
1606 | 0 | DEBUG(0, ("init_samu_from_buffer_v3: NULL parameters found!\n")); |
1607 | 0 | return False; |
1608 | 0 | } |
1609 | | |
1610 | | /* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */ |
1611 | | |
1612 | | /* unpack the buffer into variables */ |
1613 | 0 | len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V3, |
1614 | 0 | &logon_time, /* d */ |
1615 | 0 | &logoff_time, /* d */ |
1616 | 0 | &kickoff_time, /* d */ |
1617 | 0 | &bad_password_time, /* d */ |
1618 | 0 | &pass_last_set_time, /* d */ |
1619 | 0 | &pass_can_change_time, /* d */ |
1620 | 0 | &pass_must_change_time, /* d */ |
1621 | 0 | &username_len, &username, /* B */ |
1622 | 0 | &domain_len, &domain, /* B */ |
1623 | 0 | &nt_username_len, &nt_username, /* B */ |
1624 | 0 | &fullname_len, &fullname, /* B */ |
1625 | 0 | &homedir_len, &homedir, /* B */ |
1626 | 0 | &dir_drive_len, &dir_drive, /* B */ |
1627 | 0 | &logon_script_len, &logon_script, /* B */ |
1628 | 0 | &profile_path_len, &profile_path, /* B */ |
1629 | 0 | &acct_desc_len, &acct_desc, /* B */ |
1630 | 0 | &workstations_len, &workstations, /* B */ |
1631 | 0 | &comment_len, &comment, /* B */ |
1632 | 0 | &munged_dial_len, &munged_dial, /* B */ |
1633 | 0 | &user_rid, /* d */ |
1634 | 0 | &group_rid, /* d */ |
1635 | 0 | &lm_pw_len, &lm_pw_ptr, /* B */ |
1636 | 0 | &nt_pw_len, &nt_pw_ptr, /* B */ |
1637 | | /* Change from V1 is addition of password history field. */ |
1638 | 0 | &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */ |
1639 | | /* Change from V2 is the uint32_t acb_mask */ |
1640 | 0 | &acct_ctrl, /* d */ |
1641 | | /* Also "remove_me" field was removed. */ |
1642 | 0 | &logon_divs, /* w */ |
1643 | 0 | &hours_len, /* d */ |
1644 | 0 | &hourslen, &hours, /* B */ |
1645 | 0 | &bad_password_count, /* w */ |
1646 | 0 | &logon_count, /* w */ |
1647 | 0 | &unknown_6); /* d */ |
1648 | |
|
1649 | 0 | if (len == (uint32_t) -1) { |
1650 | 0 | ret = False; |
1651 | 0 | goto done; |
1652 | 0 | } |
1653 | | |
1654 | 0 | pdb_set_logon_time(sampass, convert_uint32_t_to_time_t(logon_time), PDB_SET); |
1655 | 0 | pdb_set_logoff_time(sampass, convert_uint32_t_to_time_t(logoff_time), PDB_SET); |
1656 | 0 | pdb_set_kickoff_time(sampass, convert_uint32_t_to_time_t(kickoff_time), PDB_SET); |
1657 | 0 | pdb_set_bad_password_time(sampass, convert_uint32_t_to_time_t(bad_password_time), PDB_SET); |
1658 | 0 | pdb_set_pass_can_change_time(sampass, convert_uint32_t_to_time_t(pass_can_change_time), PDB_SET); |
1659 | 0 | pdb_set_pass_last_set_time(sampass, convert_uint32_t_to_time_t(pass_last_set_time), PDB_SET); |
1660 | |
|
1661 | 0 | pdb_set_username(sampass, username, PDB_SET); |
1662 | 0 | pdb_set_domain(sampass, domain, PDB_SET); |
1663 | 0 | pdb_set_nt_username(sampass, nt_username, PDB_SET); |
1664 | 0 | pdb_set_fullname(sampass, fullname, PDB_SET); |
1665 | |
|
1666 | 0 | if (homedir) { |
1667 | 0 | fstrcpy( tmp_string, homedir ); |
1668 | 0 | if (expand_explicit) { |
1669 | 0 | standard_sub_basic( username, domain, tmp_string, |
1670 | 0 | sizeof(tmp_string) ); |
1671 | 0 | } |
1672 | 0 | pdb_set_homedir(sampass, tmp_string, PDB_SET); |
1673 | 0 | } |
1674 | 0 | else { |
1675 | 0 | pdb_set_homedir(sampass, |
1676 | 0 | talloc_sub_basic(sampass, username, domain, |
1677 | 0 | lp_logon_home()), |
1678 | 0 | PDB_DEFAULT); |
1679 | 0 | } |
1680 | |
|
1681 | 0 | if (dir_drive) |
1682 | 0 | pdb_set_dir_drive(sampass, dir_drive, PDB_SET); |
1683 | 0 | else |
1684 | 0 | pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT ); |
1685 | |
|
1686 | 0 | if (logon_script) { |
1687 | 0 | fstrcpy( tmp_string, logon_script ); |
1688 | 0 | if (expand_explicit) { |
1689 | 0 | standard_sub_basic( username, domain, tmp_string, |
1690 | 0 | sizeof(tmp_string) ); |
1691 | 0 | } |
1692 | 0 | pdb_set_logon_script(sampass, tmp_string, PDB_SET); |
1693 | 0 | } |
1694 | 0 | else { |
1695 | 0 | pdb_set_logon_script(sampass, |
1696 | 0 | talloc_sub_basic(sampass, username, domain, |
1697 | 0 | lp_logon_script()), |
1698 | 0 | PDB_DEFAULT); |
1699 | 0 | } |
1700 | |
|
1701 | 0 | if (profile_path) { |
1702 | 0 | fstrcpy( tmp_string, profile_path ); |
1703 | 0 | if (expand_explicit) { |
1704 | 0 | standard_sub_basic( username, domain, tmp_string, |
1705 | 0 | sizeof(tmp_string) ); |
1706 | 0 | } |
1707 | 0 | pdb_set_profile_path(sampass, tmp_string, PDB_SET); |
1708 | 0 | } |
1709 | 0 | else { |
1710 | 0 | pdb_set_profile_path(sampass, |
1711 | 0 | talloc_sub_basic(sampass, username, domain, lp_logon_path()), |
1712 | 0 | PDB_DEFAULT); |
1713 | 0 | } |
1714 | |
|
1715 | 0 | pdb_set_acct_desc(sampass, acct_desc, PDB_SET); |
1716 | 0 | pdb_set_comment(sampass, comment, PDB_SET); |
1717 | 0 | pdb_set_workstations(sampass, workstations, PDB_SET); |
1718 | 0 | pdb_set_munged_dial(sampass, munged_dial, PDB_SET); |
1719 | |
|
1720 | 0 | if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { |
1721 | 0 | if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { |
1722 | 0 | ret = False; |
1723 | 0 | goto done; |
1724 | 0 | } |
1725 | 0 | } |
1726 | | |
1727 | 0 | if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { |
1728 | 0 | if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { |
1729 | 0 | ret = False; |
1730 | 0 | goto done; |
1731 | 0 | } |
1732 | 0 | } |
1733 | | |
1734 | 0 | pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen); |
1735 | 0 | if (pwHistLen) { |
1736 | 0 | uint8_t *pw_hist = (uint8_t *)SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN); |
1737 | 0 | if (!pw_hist) { |
1738 | 0 | ret = False; |
1739 | 0 | goto done; |
1740 | 0 | } |
1741 | 0 | memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN); |
1742 | 0 | if (nt_pw_hist_ptr && nt_pw_hist_len) { |
1743 | 0 | int i; |
1744 | 0 | SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0); |
1745 | 0 | nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN; |
1746 | 0 | for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) { |
1747 | 0 | memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN], |
1748 | 0 | &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN], |
1749 | 0 | PW_HISTORY_ENTRY_LEN); |
1750 | 0 | } |
1751 | 0 | } |
1752 | 0 | if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) { |
1753 | 0 | SAFE_FREE(pw_hist); |
1754 | 0 | ret = False; |
1755 | 0 | goto done; |
1756 | 0 | } |
1757 | 0 | SAFE_FREE(pw_hist); |
1758 | 0 | } else { |
1759 | 0 | pdb_set_pw_history(sampass, NULL, 0, PDB_SET); |
1760 | 0 | } |
1761 | | |
1762 | 0 | pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); |
1763 | 0 | pdb_set_hours_len(sampass, hours_len, PDB_SET); |
1764 | 0 | pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); |
1765 | 0 | pdb_set_logon_count(sampass, logon_count, PDB_SET); |
1766 | 0 | pdb_set_unknown_6(sampass, unknown_6, PDB_SET); |
1767 | | /* Change from V2 is the uint32_t acct_ctrl */ |
1768 | 0 | pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); |
1769 | 0 | pdb_set_logon_divs(sampass, logon_divs, PDB_SET); |
1770 | 0 | pdb_set_hours(sampass, hours, hours_len, PDB_SET); |
1771 | |
|
1772 | 0 | done: |
1773 | |
|
1774 | 0 | SAFE_FREE(username); |
1775 | 0 | SAFE_FREE(domain); |
1776 | 0 | SAFE_FREE(nt_username); |
1777 | 0 | SAFE_FREE(fullname); |
1778 | 0 | SAFE_FREE(homedir); |
1779 | 0 | SAFE_FREE(dir_drive); |
1780 | 0 | SAFE_FREE(logon_script); |
1781 | 0 | SAFE_FREE(profile_path); |
1782 | 0 | SAFE_FREE(acct_desc); |
1783 | 0 | SAFE_FREE(workstations); |
1784 | 0 | SAFE_FREE(munged_dial); |
1785 | 0 | SAFE_FREE(comment); |
1786 | 0 | SAFE_FREE(lm_pw_ptr); |
1787 | 0 | SAFE_FREE(nt_pw_ptr); |
1788 | 0 | SAFE_FREE(nt_pw_hist_ptr); |
1789 | 0 | SAFE_FREE(hours); |
1790 | |
|
1791 | 0 | return ret; |
1792 | 0 | } |
1793 | | |
1794 | | /********************************************************************* |
1795 | | *********************************************************************/ |
1796 | | |
1797 | | static uint32_t init_buffer_from_samu_v3 (uint8_t **buf, struct samu *sampass, bool size_only) |
1798 | 0 | { |
1799 | 0 | size_t len, buflen; |
1800 | | |
1801 | | /* times are stored as 32bit integer |
1802 | | take care on system with 64bit wide time_t |
1803 | | --SSS */ |
1804 | 0 | uint32_t logon_time, |
1805 | 0 | logoff_time, |
1806 | 0 | kickoff_time, |
1807 | 0 | bad_password_time, |
1808 | 0 | pass_last_set_time, |
1809 | 0 | pass_can_change_time, |
1810 | 0 | pass_must_change_time; |
1811 | |
|
1812 | 0 | uint32_t user_rid, group_rid; |
1813 | |
|
1814 | 0 | const char *username; |
1815 | 0 | const char *domain; |
1816 | 0 | const char *nt_username; |
1817 | 0 | const char *dir_drive; |
1818 | 0 | const char *comment; |
1819 | 0 | const char *munged_dial; |
1820 | 0 | const char *fullname; |
1821 | 0 | const char *homedir; |
1822 | 0 | const char *logon_script; |
1823 | 0 | const char *profile_path; |
1824 | 0 | const char *acct_desc; |
1825 | 0 | const char *workstations; |
1826 | 0 | uint32_t username_len, domain_len, nt_username_len, |
1827 | 0 | dir_drive_len, comment_len, munged_dial_len, |
1828 | 0 | fullname_len, homedir_len, logon_script_len, |
1829 | 0 | profile_path_len, acct_desc_len, workstations_len; |
1830 | |
|
1831 | 0 | const uint8_t *lm_pw; |
1832 | 0 | const uint8_t *nt_pw; |
1833 | 0 | const uint8_t *nt_pw_hist; |
1834 | 0 | uint32_t lm_pw_len = 16; |
1835 | 0 | uint32_t nt_pw_len = 16; |
1836 | 0 | uint32_t nt_pw_hist_len; |
1837 | 0 | uint32_t pwHistLen = 0; |
1838 | |
|
1839 | 0 | *buf = NULL; |
1840 | 0 | buflen = 0; |
1841 | |
|
1842 | 0 | logon_time = convert_time_t_to_uint32_t(pdb_get_logon_time(sampass)); |
1843 | 0 | logoff_time = convert_time_t_to_uint32_t(pdb_get_logoff_time(sampass)); |
1844 | 0 | kickoff_time = convert_time_t_to_uint32_t(pdb_get_kickoff_time(sampass)); |
1845 | 0 | bad_password_time = convert_time_t_to_uint32_t(pdb_get_bad_password_time(sampass)); |
1846 | 0 | pass_can_change_time = convert_time_t_to_uint32_t(pdb_get_pass_can_change_time_noncalc(sampass)); |
1847 | 0 | pass_must_change_time = convert_time_t_to_uint32_t(pdb_get_pass_must_change_time(sampass)); |
1848 | 0 | pass_last_set_time = convert_time_t_to_uint32_t(pdb_get_pass_last_set_time(sampass)); |
1849 | |
|
1850 | 0 | user_rid = pdb_get_user_rid(sampass); |
1851 | 0 | group_rid = pdb_get_group_rid(sampass); |
1852 | |
|
1853 | 0 | username = pdb_get_username(sampass); |
1854 | 0 | if (username) { |
1855 | 0 | username_len = strlen(username) +1; |
1856 | 0 | } else { |
1857 | 0 | username_len = 0; |
1858 | 0 | } |
1859 | |
|
1860 | 0 | domain = pdb_get_domain(sampass); |
1861 | 0 | if (domain) { |
1862 | 0 | domain_len = strlen(domain) +1; |
1863 | 0 | } else { |
1864 | 0 | domain_len = 0; |
1865 | 0 | } |
1866 | |
|
1867 | 0 | nt_username = pdb_get_nt_username(sampass); |
1868 | 0 | if (nt_username) { |
1869 | 0 | nt_username_len = strlen(nt_username) +1; |
1870 | 0 | } else { |
1871 | 0 | nt_username_len = 0; |
1872 | 0 | } |
1873 | |
|
1874 | 0 | fullname = pdb_get_fullname(sampass); |
1875 | 0 | if (fullname) { |
1876 | 0 | fullname_len = strlen(fullname) +1; |
1877 | 0 | } else { |
1878 | 0 | fullname_len = 0; |
1879 | 0 | } |
1880 | | |
1881 | | /* |
1882 | | * Only updates fields which have been set (not defaults from smb.conf) |
1883 | | */ |
1884 | |
|
1885 | 0 | if (!IS_SAM_DEFAULT(sampass, PDB_DRIVE)) { |
1886 | 0 | dir_drive = pdb_get_dir_drive(sampass); |
1887 | 0 | } else { |
1888 | 0 | dir_drive = NULL; |
1889 | 0 | } |
1890 | 0 | if (dir_drive) { |
1891 | 0 | dir_drive_len = strlen(dir_drive) +1; |
1892 | 0 | } else { |
1893 | 0 | dir_drive_len = 0; |
1894 | 0 | } |
1895 | |
|
1896 | 0 | if (!IS_SAM_DEFAULT(sampass, PDB_SMBHOME)) { |
1897 | 0 | homedir = pdb_get_homedir(sampass); |
1898 | 0 | } else { |
1899 | 0 | homedir = NULL; |
1900 | 0 | } |
1901 | 0 | if (homedir) { |
1902 | 0 | homedir_len = strlen(homedir) +1; |
1903 | 0 | } else { |
1904 | 0 | homedir_len = 0; |
1905 | 0 | } |
1906 | |
|
1907 | 0 | if (!IS_SAM_DEFAULT(sampass, PDB_LOGONSCRIPT)) { |
1908 | 0 | logon_script = pdb_get_logon_script(sampass); |
1909 | 0 | } else { |
1910 | 0 | logon_script = NULL; |
1911 | 0 | } |
1912 | 0 | if (logon_script) { |
1913 | 0 | logon_script_len = strlen(logon_script) +1; |
1914 | 0 | } else { |
1915 | 0 | logon_script_len = 0; |
1916 | 0 | } |
1917 | |
|
1918 | 0 | if (!IS_SAM_DEFAULT(sampass, PDB_PROFILE)) { |
1919 | 0 | profile_path = pdb_get_profile_path(sampass); |
1920 | 0 | } else { |
1921 | 0 | profile_path = NULL; |
1922 | 0 | } |
1923 | 0 | if (profile_path) { |
1924 | 0 | profile_path_len = strlen(profile_path) +1; |
1925 | 0 | } else { |
1926 | 0 | profile_path_len = 0; |
1927 | 0 | } |
1928 | |
|
1929 | 0 | lm_pw = pdb_get_lanman_passwd(sampass); |
1930 | 0 | if (!lm_pw) { |
1931 | 0 | lm_pw_len = 0; |
1932 | 0 | } |
1933 | |
|
1934 | 0 | nt_pw = pdb_get_nt_passwd(sampass); |
1935 | 0 | if (!nt_pw) { |
1936 | 0 | nt_pw_len = 0; |
1937 | 0 | } |
1938 | |
|
1939 | 0 | pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen); |
1940 | 0 | nt_pw_hist = pdb_get_pw_history(sampass, &nt_pw_hist_len); |
1941 | 0 | if (pwHistLen && nt_pw_hist && nt_pw_hist_len) { |
1942 | 0 | nt_pw_hist_len *= PW_HISTORY_ENTRY_LEN; |
1943 | 0 | } else { |
1944 | 0 | nt_pw_hist_len = 0; |
1945 | 0 | } |
1946 | |
|
1947 | 0 | acct_desc = pdb_get_acct_desc(sampass); |
1948 | 0 | if (acct_desc) { |
1949 | 0 | acct_desc_len = strlen(acct_desc) +1; |
1950 | 0 | } else { |
1951 | 0 | acct_desc_len = 0; |
1952 | 0 | } |
1953 | |
|
1954 | 0 | workstations = pdb_get_workstations(sampass); |
1955 | 0 | if (workstations) { |
1956 | 0 | workstations_len = strlen(workstations) +1; |
1957 | 0 | } else { |
1958 | 0 | workstations_len = 0; |
1959 | 0 | } |
1960 | |
|
1961 | 0 | comment = pdb_get_comment(sampass); |
1962 | 0 | if (comment) { |
1963 | 0 | comment_len = strlen(comment) +1; |
1964 | 0 | } else { |
1965 | 0 | comment_len = 0; |
1966 | 0 | } |
1967 | |
|
1968 | 0 | munged_dial = pdb_get_munged_dial(sampass); |
1969 | 0 | if (munged_dial) { |
1970 | 0 | munged_dial_len = strlen(munged_dial) +1; |
1971 | 0 | } else { |
1972 | 0 | munged_dial_len = 0; |
1973 | 0 | } |
1974 | | |
1975 | | /* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */ |
1976 | | |
1977 | | /* one time to get the size needed */ |
1978 | 0 | len = tdb_pack(NULL, 0, SAMU_BUFFER_FORMAT_V3, |
1979 | 0 | logon_time, /* d */ |
1980 | 0 | logoff_time, /* d */ |
1981 | 0 | kickoff_time, /* d */ |
1982 | 0 | bad_password_time, /* d */ |
1983 | 0 | pass_last_set_time, /* d */ |
1984 | 0 | pass_can_change_time, /* d */ |
1985 | 0 | pass_must_change_time, /* d */ |
1986 | 0 | username_len, username, /* B */ |
1987 | 0 | domain_len, domain, /* B */ |
1988 | 0 | nt_username_len, nt_username, /* B */ |
1989 | 0 | fullname_len, fullname, /* B */ |
1990 | 0 | homedir_len, homedir, /* B */ |
1991 | 0 | dir_drive_len, dir_drive, /* B */ |
1992 | 0 | logon_script_len, logon_script, /* B */ |
1993 | 0 | profile_path_len, profile_path, /* B */ |
1994 | 0 | acct_desc_len, acct_desc, /* B */ |
1995 | 0 | workstations_len, workstations, /* B */ |
1996 | 0 | comment_len, comment, /* B */ |
1997 | 0 | munged_dial_len, munged_dial, /* B */ |
1998 | 0 | user_rid, /* d */ |
1999 | 0 | group_rid, /* d */ |
2000 | 0 | lm_pw_len, lm_pw, /* B */ |
2001 | 0 | nt_pw_len, nt_pw, /* B */ |
2002 | 0 | nt_pw_hist_len, nt_pw_hist, /* B */ |
2003 | 0 | pdb_get_acct_ctrl(sampass), /* d */ |
2004 | 0 | pdb_get_logon_divs(sampass), /* w */ |
2005 | 0 | pdb_get_hours_len(sampass), /* d */ |
2006 | 0 | MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */ |
2007 | 0 | pdb_get_bad_password_count(sampass), /* w */ |
2008 | 0 | pdb_get_logon_count(sampass), /* w */ |
2009 | 0 | pdb_get_unknown_6(sampass)); /* d */ |
2010 | |
|
2011 | 0 | if (size_only) { |
2012 | 0 | return buflen; |
2013 | 0 | } |
2014 | | |
2015 | | /* malloc the space needed */ |
2016 | 0 | if ( (*buf=(uint8_t*)SMB_MALLOC(len)) == NULL) { |
2017 | 0 | DEBUG(0,("init_buffer_from_samu_v3: Unable to malloc() memory for buffer!\n")); |
2018 | 0 | return (-1); |
2019 | 0 | } |
2020 | | |
2021 | | /* now for the real call to tdb_pack() */ |
2022 | 0 | buflen = tdb_pack(*buf, len, SAMU_BUFFER_FORMAT_V3, |
2023 | 0 | logon_time, /* d */ |
2024 | 0 | logoff_time, /* d */ |
2025 | 0 | kickoff_time, /* d */ |
2026 | 0 | bad_password_time, /* d */ |
2027 | 0 | pass_last_set_time, /* d */ |
2028 | 0 | pass_can_change_time, /* d */ |
2029 | 0 | pass_must_change_time, /* d */ |
2030 | 0 | username_len, username, /* B */ |
2031 | 0 | domain_len, domain, /* B */ |
2032 | 0 | nt_username_len, nt_username, /* B */ |
2033 | 0 | fullname_len, fullname, /* B */ |
2034 | 0 | homedir_len, homedir, /* B */ |
2035 | 0 | dir_drive_len, dir_drive, /* B */ |
2036 | 0 | logon_script_len, logon_script, /* B */ |
2037 | 0 | profile_path_len, profile_path, /* B */ |
2038 | 0 | acct_desc_len, acct_desc, /* B */ |
2039 | 0 | workstations_len, workstations, /* B */ |
2040 | 0 | comment_len, comment, /* B */ |
2041 | 0 | munged_dial_len, munged_dial, /* B */ |
2042 | 0 | user_rid, /* d */ |
2043 | 0 | group_rid, /* d */ |
2044 | 0 | lm_pw_len, lm_pw, /* B */ |
2045 | 0 | nt_pw_len, nt_pw, /* B */ |
2046 | 0 | nt_pw_hist_len, nt_pw_hist, /* B */ |
2047 | 0 | pdb_get_acct_ctrl(sampass), /* d */ |
2048 | 0 | pdb_get_logon_divs(sampass), /* w */ |
2049 | 0 | pdb_get_hours_len(sampass), /* d */ |
2050 | 0 | MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */ |
2051 | 0 | pdb_get_bad_password_count(sampass), /* w */ |
2052 | 0 | pdb_get_logon_count(sampass), /* w */ |
2053 | 0 | pdb_get_unknown_6(sampass)); /* d */ |
2054 | | |
2055 | | /* check to make sure we got it correct */ |
2056 | 0 | if (buflen != len) { |
2057 | 0 | DEBUG(0, ("init_buffer_from_samu_v3: something odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", |
2058 | 0 | (unsigned long)buflen, (unsigned long)len)); |
2059 | | /* error */ |
2060 | 0 | SAFE_FREE (*buf); |
2061 | 0 | return (-1); |
2062 | 0 | } |
2063 | | |
2064 | 0 | return (buflen); |
2065 | 0 | } |
2066 | | |
2067 | | static bool init_samu_from_buffer_v4(struct samu *sampass, uint8_t *buf, uint32_t buflen) |
2068 | 0 | { |
2069 | | /* nothing changed between V3 and V4 */ |
2070 | 0 | return init_samu_from_buffer_v3(sampass, buf, buflen); |
2071 | 0 | } |
2072 | | |
2073 | | static uint32_t init_buffer_from_samu_v4(uint8_t **buf, struct samu *sampass, bool size_only) |
2074 | 0 | { |
2075 | | /* nothing changed between V3 and V4 */ |
2076 | 0 | return init_buffer_from_samu_v3(buf, sampass, size_only); |
2077 | 0 | } |
2078 | | |
2079 | | /********************************************************************** |
2080 | | Initialize a struct samu struct from a BYTE buffer of size len |
2081 | | *********************************************************************/ |
2082 | | |
2083 | | bool init_samu_from_buffer(struct samu *sampass, uint32_t level, |
2084 | | uint8_t *buf, uint32_t buflen) |
2085 | 0 | { |
2086 | 0 | switch (level) { |
2087 | 0 | case SAMU_BUFFER_V0: |
2088 | 0 | return init_samu_from_buffer_v0(sampass, buf, buflen); |
2089 | 0 | case SAMU_BUFFER_V1: |
2090 | 0 | return init_samu_from_buffer_v1(sampass, buf, buflen); |
2091 | 0 | case SAMU_BUFFER_V2: |
2092 | 0 | return init_samu_from_buffer_v2(sampass, buf, buflen); |
2093 | 0 | case SAMU_BUFFER_V3: |
2094 | 0 | return init_samu_from_buffer_v3(sampass, buf, buflen); |
2095 | 0 | case SAMU_BUFFER_V4: |
2096 | 0 | return init_samu_from_buffer_v4(sampass, buf, buflen); |
2097 | 0 | } |
2098 | | |
2099 | 0 | return false; |
2100 | 0 | } |
2101 | | |
2102 | | /********************************************************************** |
2103 | | Initialize a BYTE buffer from a struct samu struct |
2104 | | *********************************************************************/ |
2105 | | |
2106 | | uint32_t init_buffer_from_samu (uint8_t **buf, struct samu *sampass, bool size_only) |
2107 | 0 | { |
2108 | 0 | return init_buffer_from_samu_v4(buf, sampass, size_only); |
2109 | 0 | } |
2110 | | |
2111 | | /********************************************************************* |
2112 | | *********************************************************************/ |
2113 | | |
2114 | | bool pdb_copy_sam_account(struct samu *dst, struct samu *src ) |
2115 | 0 | { |
2116 | 0 | uint8_t *buf = NULL; |
2117 | 0 | int len; |
2118 | |
|
2119 | 0 | len = init_buffer_from_samu(&buf, src, False); |
2120 | 0 | if (len == -1 || !buf) { |
2121 | 0 | SAFE_FREE(buf); |
2122 | 0 | return False; |
2123 | 0 | } |
2124 | | |
2125 | 0 | if (!init_samu_from_buffer( dst, SAMU_BUFFER_LATEST, buf, len )) { |
2126 | 0 | free(buf); |
2127 | 0 | return False; |
2128 | 0 | } |
2129 | | |
2130 | 0 | dst->methods = src->methods; |
2131 | |
|
2132 | 0 | if ( src->unix_pw ) { |
2133 | 0 | dst->unix_pw = tcopy_passwd( dst, src->unix_pw ); |
2134 | 0 | if (!dst->unix_pw) { |
2135 | 0 | free(buf); |
2136 | 0 | return False; |
2137 | 0 | } |
2138 | 0 | } |
2139 | | |
2140 | 0 | if (src->group_sid) { |
2141 | 0 | pdb_set_group_sid(dst, src->group_sid, PDB_SET); |
2142 | 0 | } |
2143 | |
|
2144 | 0 | free(buf); |
2145 | 0 | return True; |
2146 | 0 | } |
2147 | | |
2148 | | /********************************************************************* |
2149 | | Update the bad password count checking the PDB_POLICY_RESET_COUNT_TIME |
2150 | | *********************************************************************/ |
2151 | | |
2152 | | bool pdb_update_bad_password_count(struct samu *sampass, bool *updated) |
2153 | 0 | { |
2154 | 0 | time_t LastBadPassword; |
2155 | 0 | uint16_t BadPasswordCount; |
2156 | 0 | uint32_t resettime; |
2157 | 0 | bool res; |
2158 | |
|
2159 | 0 | BadPasswordCount = pdb_get_bad_password_count(sampass); |
2160 | 0 | if (!BadPasswordCount) { |
2161 | 0 | DEBUG(9, ("No bad password attempts.\n")); |
2162 | 0 | return True; |
2163 | 0 | } |
2164 | | |
2165 | 0 | become_root(); |
2166 | 0 | res = pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &resettime); |
2167 | 0 | unbecome_root(); |
2168 | |
|
2169 | 0 | if (!res) { |
2170 | 0 | DEBUG(0, ("pdb_update_bad_password_count: pdb_get_account_policy failed.\n")); |
2171 | 0 | return False; |
2172 | 0 | } |
2173 | | |
2174 | | /* First, check if there is a reset time to compare */ |
2175 | 0 | if ((resettime == (uint32_t) -1) || (resettime == 0)) { |
2176 | 0 | DEBUG(9, ("No reset time, can't reset bad pw count\n")); |
2177 | 0 | return True; |
2178 | 0 | } |
2179 | | |
2180 | 0 | LastBadPassword = pdb_get_bad_password_time(sampass); |
2181 | 0 | DBG_INFO("LastBadPassword=%" PRIu64 ", resettime=%d, " |
2182 | 0 | "current time=%" PRIu64 ".\n", |
2183 | 0 | (uint64_t)LastBadPassword, |
2184 | 0 | resettime, |
2185 | 0 | (uint64_t)time(NULL)); |
2186 | 0 | if (time(NULL) > (LastBadPassword + convert_uint32_t_to_time_t(resettime)*60)){ |
2187 | 0 | pdb_set_bad_password_count(sampass, 0, PDB_CHANGED); |
2188 | 0 | pdb_set_bad_password_time(sampass, 0, PDB_CHANGED); |
2189 | 0 | if (updated) { |
2190 | 0 | *updated = True; |
2191 | 0 | } |
2192 | 0 | } |
2193 | |
|
2194 | 0 | return True; |
2195 | 0 | } |
2196 | | |
2197 | | /********************************************************************* |
2198 | | Update the ACB_AUTOLOCK flag checking the PDB_POLICY_LOCK_ACCOUNT_DURATION |
2199 | | *********************************************************************/ |
2200 | | |
2201 | | bool pdb_update_autolock_flag(struct samu *sampass, bool *updated) |
2202 | 0 | { |
2203 | 0 | uint32_t duration; |
2204 | 0 | time_t LastBadPassword; |
2205 | 0 | bool res; |
2206 | |
|
2207 | 0 | if (!(pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK)) { |
2208 | 0 | DEBUG(9, ("pdb_update_autolock_flag: Account %s not autolocked, no check needed\n", |
2209 | 0 | pdb_get_username(sampass))); |
2210 | 0 | return True; |
2211 | 0 | } |
2212 | | |
2213 | 0 | become_root(); |
2214 | 0 | res = pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &duration); |
2215 | 0 | unbecome_root(); |
2216 | |
|
2217 | 0 | if (!res) { |
2218 | 0 | DEBUG(0, ("pdb_update_autolock_flag: pdb_get_account_policy failed.\n")); |
2219 | 0 | return False; |
2220 | 0 | } |
2221 | | |
2222 | | /* First, check if there is a duration to compare */ |
2223 | 0 | if ((duration == (uint32_t) -1) || (duration == 0)) { |
2224 | 0 | DEBUG(9, ("pdb_update_autolock_flag: No reset duration, can't reset autolock\n")); |
2225 | 0 | return True; |
2226 | 0 | } |
2227 | | |
2228 | 0 | LastBadPassword = pdb_get_bad_password_time(sampass); |
2229 | 0 | DEBUG(7, ("pdb_update_autolock_flag: Account %s, LastBadPassword=%ju, duration=%d, current time =%ju.\n", |
2230 | 0 | pdb_get_username(sampass), (uintmax_t)LastBadPassword, duration*60, (uintmax_t)time(NULL))); |
2231 | |
|
2232 | 0 | if (LastBadPassword == (time_t)0) { |
2233 | 0 | DEBUG(1,("pdb_update_autolock_flag: Account %s " |
2234 | 0 | "administratively locked out with no bad password " |
2235 | 0 | "time. Leaving locked out.\n", |
2236 | 0 | pdb_get_username(sampass) )); |
2237 | 0 | return True; |
2238 | 0 | } |
2239 | | |
2240 | 0 | if ((time(NULL) > (LastBadPassword + convert_uint32_t_to_time_t(duration) * 60))) { |
2241 | 0 | pdb_set_acct_ctrl(sampass, |
2242 | 0 | pdb_get_acct_ctrl(sampass) & ~ACB_AUTOLOCK, |
2243 | 0 | PDB_CHANGED); |
2244 | 0 | pdb_set_bad_password_count(sampass, 0, PDB_CHANGED); |
2245 | 0 | pdb_set_bad_password_time(sampass, 0, PDB_CHANGED); |
2246 | 0 | if (updated) { |
2247 | 0 | *updated = True; |
2248 | 0 | } |
2249 | 0 | } |
2250 | |
|
2251 | 0 | return True; |
2252 | 0 | } |
2253 | | |
2254 | | /********************************************************************* |
2255 | | Increment the bad_password_count |
2256 | | *********************************************************************/ |
2257 | | |
2258 | | bool pdb_increment_bad_password_count(struct samu *sampass) |
2259 | 0 | { |
2260 | 0 | uint32_t account_policy_lockout; |
2261 | 0 | bool autolock_updated = False, badpw_updated = False; |
2262 | 0 | bool ret; |
2263 | | |
2264 | | /* Retrieve the account lockout policy */ |
2265 | 0 | become_root(); |
2266 | 0 | ret = pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout); |
2267 | 0 | unbecome_root(); |
2268 | 0 | if ( !ret ) { |
2269 | 0 | DEBUG(0, ("pdb_increment_bad_password_count: pdb_get_account_policy failed.\n")); |
2270 | 0 | return False; |
2271 | 0 | } |
2272 | | |
2273 | | /* If there is no policy, we don't need to continue checking */ |
2274 | 0 | if (!account_policy_lockout) { |
2275 | 0 | DEBUG(9, ("No lockout policy, don't track bad passwords\n")); |
2276 | 0 | return True; |
2277 | 0 | } |
2278 | | |
2279 | | /* Check if the autolock needs to be cleared */ |
2280 | 0 | if (!pdb_update_autolock_flag(sampass, &autolock_updated)) |
2281 | 0 | return False; |
2282 | | |
2283 | | /* Check if the badpw count needs to be reset */ |
2284 | 0 | if (!pdb_update_bad_password_count(sampass, &badpw_updated)) |
2285 | 0 | return False; |
2286 | | |
2287 | | /* |
2288 | | Ok, now we can assume that any resetting that needs to be |
2289 | | done has been done, and just get on with incrementing |
2290 | | and autolocking if necessary |
2291 | | */ |
2292 | | |
2293 | 0 | pdb_set_bad_password_count(sampass, |
2294 | 0 | pdb_get_bad_password_count(sampass)+1, |
2295 | 0 | PDB_CHANGED); |
2296 | 0 | pdb_set_bad_password_time(sampass, time(NULL), PDB_CHANGED); |
2297 | | |
2298 | |
|
2299 | 0 | if (pdb_get_bad_password_count(sampass) < account_policy_lockout) |
2300 | 0 | return True; |
2301 | | |
2302 | 0 | if (!pdb_set_acct_ctrl(sampass, |
2303 | 0 | pdb_get_acct_ctrl(sampass) | ACB_AUTOLOCK, |
2304 | 0 | PDB_CHANGED)) { |
2305 | 0 | DEBUG(1, ("pdb_increment_bad_password_count:failed to set 'autolock' flag. \n")); |
2306 | 0 | return False; |
2307 | 0 | } |
2308 | | |
2309 | 0 | return True; |
2310 | 0 | } |
2311 | | |
2312 | | bool is_dc_trusted_domain_situation(const char *domain_name) |
2313 | 0 | { |
2314 | 0 | return IS_DC && !strequal(domain_name, lp_workgroup()); |
2315 | 0 | } |
2316 | | |
2317 | | /******************************************************************* |
2318 | | Wrapper around retrieving the clear text trust account password. |
2319 | | appropriate account name is stored in account_name. |
2320 | | Caller must free password, but not account_name. |
2321 | | *******************************************************************/ |
2322 | | |
2323 | | static bool get_trust_pw_clear2(const char *domain, |
2324 | | const char **account_name, |
2325 | | enum netr_SchannelType *channel, |
2326 | | char **cur_pw, |
2327 | | time_t *_last_set_time, |
2328 | | char **prev_pw) |
2329 | 0 | { |
2330 | 0 | char *pwd; |
2331 | 0 | time_t last_set_time; |
2332 | |
|
2333 | 0 | if (cur_pw != NULL) { |
2334 | 0 | *cur_pw = NULL; |
2335 | 0 | } |
2336 | 0 | if (_last_set_time != NULL) { |
2337 | 0 | *_last_set_time = 0; |
2338 | 0 | } |
2339 | 0 | if (prev_pw != NULL) { |
2340 | 0 | *prev_pw = NULL; |
2341 | 0 | } |
2342 | | |
2343 | | /* if we are a DC and this is not our domain, then lookup an account |
2344 | | * for the domain trust */ |
2345 | |
|
2346 | 0 | if (is_dc_trusted_domain_situation(domain)) { |
2347 | 0 | if (!lp_allow_trusted_domains()) { |
2348 | 0 | return false; |
2349 | 0 | } |
2350 | | |
2351 | 0 | if (!pdb_get_trusteddom_pw(domain, cur_pw, NULL, |
2352 | 0 | &last_set_time)) |
2353 | 0 | { |
2354 | 0 | DEBUG(0, ("get_trust_pw: could not fetch trust " |
2355 | 0 | "account password for trusted domain %s\n", |
2356 | 0 | domain)); |
2357 | 0 | return false; |
2358 | 0 | } |
2359 | | |
2360 | 0 | if (channel != NULL) { |
2361 | 0 | *channel = SEC_CHAN_DOMAIN; |
2362 | 0 | } |
2363 | |
|
2364 | 0 | if (account_name != NULL) { |
2365 | 0 | *account_name = lp_workgroup(); |
2366 | 0 | } |
2367 | |
|
2368 | 0 | if (_last_set_time != NULL) { |
2369 | 0 | *_last_set_time = last_set_time; |
2370 | 0 | } |
2371 | |
|
2372 | 0 | return true; |
2373 | 0 | } |
2374 | | |
2375 | | /* |
2376 | | * Since we can only be member of one single domain, we are now |
2377 | | * in a member situation: |
2378 | | * |
2379 | | * - Either we are a DC (selfjoined) and the domain is our |
2380 | | * own domain. |
2381 | | * - Or we are on a member and the domain is our own or some |
2382 | | * other (potentially trusted) domain. |
2383 | | * |
2384 | | * In both cases, we can only get the machine account password |
2385 | | * for our own domain to connect to our own dc. (For a member, |
2386 | | * request to trusted domains are performed through our dc.) |
2387 | | * |
2388 | | * So we simply use our own domain name to retrieve the |
2389 | | * machine account password and ignore the request domain here. |
2390 | | */ |
2391 | | |
2392 | 0 | pwd = secrets_fetch_machine_password(lp_workgroup(), &last_set_time, channel); |
2393 | |
|
2394 | 0 | if (pwd != NULL) { |
2395 | 0 | struct timeval expire; |
2396 | |
|
2397 | 0 | *cur_pw = pwd; |
2398 | |
|
2399 | 0 | if (account_name != NULL) { |
2400 | 0 | *account_name = lp_netbios_name(); |
2401 | 0 | } |
2402 | |
|
2403 | 0 | if (_last_set_time != NULL) { |
2404 | 0 | *_last_set_time = last_set_time; |
2405 | 0 | } |
2406 | |
|
2407 | 0 | if (prev_pw == NULL) { |
2408 | 0 | return true; |
2409 | 0 | } |
2410 | | |
2411 | 0 | ZERO_STRUCT(expire); |
2412 | 0 | expire.tv_sec = lp_machine_password_timeout(); |
2413 | 0 | expire.tv_sec /= 2; |
2414 | 0 | expire.tv_sec += last_set_time; |
2415 | 0 | if (timeval_expired(&expire)) { |
2416 | 0 | return true; |
2417 | 0 | } |
2418 | | |
2419 | 0 | pwd = secrets_fetch_prev_machine_password(lp_workgroup()); |
2420 | 0 | if (pwd != NULL) { |
2421 | 0 | *prev_pw = pwd; |
2422 | 0 | } |
2423 | |
|
2424 | 0 | return true; |
2425 | 0 | } |
2426 | | |
2427 | 0 | DEBUG(5, ("get_trust_pw_clear2: could not fetch clear text trust " |
2428 | 0 | "account password for domain %s\n", domain)); |
2429 | 0 | return false; |
2430 | 0 | } |
2431 | | |
2432 | | bool get_trust_pw_clear(const char *domain, char **ret_pwd, |
2433 | | const char **account_name, |
2434 | | enum netr_SchannelType *channel) |
2435 | 0 | { |
2436 | 0 | return get_trust_pw_clear2(domain, |
2437 | 0 | account_name, |
2438 | 0 | channel, |
2439 | 0 | ret_pwd, |
2440 | 0 | NULL, |
2441 | 0 | NULL); |
2442 | 0 | } |
2443 | | |
2444 | | /******************************************************************* |
2445 | | Wrapper around retrieving the trust account password. |
2446 | | appropriate account name is stored in account_name. |
2447 | | *******************************************************************/ |
2448 | | |
2449 | | static bool get_trust_pw_hash2(const char *domain, |
2450 | | const char **account_name, |
2451 | | enum netr_SchannelType *channel, |
2452 | | struct samr_Password *current_nt_hash, |
2453 | | time_t *last_set_time, |
2454 | | struct samr_Password **_previous_nt_hash) |
2455 | 0 | { |
2456 | 0 | char *cur_pw = NULL; |
2457 | 0 | char *prev_pw = NULL; |
2458 | 0 | char **_prev_pw = NULL; |
2459 | 0 | bool ok; |
2460 | |
|
2461 | 0 | if (_previous_nt_hash != NULL) { |
2462 | 0 | *_previous_nt_hash = NULL; |
2463 | 0 | _prev_pw = &prev_pw; |
2464 | 0 | } |
2465 | |
|
2466 | 0 | ok = get_trust_pw_clear2(domain, account_name, channel, |
2467 | 0 | &cur_pw, last_set_time, _prev_pw); |
2468 | 0 | if (ok) { |
2469 | 0 | struct samr_Password *previous_nt_hash = NULL; |
2470 | |
|
2471 | 0 | E_md4hash(cur_pw, current_nt_hash->hash); |
2472 | 0 | BURN_FREE_STR(cur_pw); |
2473 | |
|
2474 | 0 | if (prev_pw == NULL) { |
2475 | 0 | return true; |
2476 | 0 | } |
2477 | | |
2478 | 0 | previous_nt_hash = SMB_MALLOC_P(struct samr_Password); |
2479 | 0 | if (previous_nt_hash == NULL) { |
2480 | 0 | return false; |
2481 | 0 | } |
2482 | | |
2483 | 0 | E_md4hash(prev_pw, previous_nt_hash->hash); |
2484 | 0 | BURN_FREE_STR(prev_pw); |
2485 | |
|
2486 | 0 | *_previous_nt_hash = previous_nt_hash; |
2487 | 0 | return true; |
2488 | 0 | } else if (is_dc_trusted_domain_situation(domain)) { |
2489 | 0 | return false; |
2490 | 0 | } |
2491 | | |
2492 | | /* as a fallback, try to get the hashed pwd directly from the tdb... */ |
2493 | | |
2494 | 0 | if (secrets_fetch_trust_account_password_legacy(domain, |
2495 | 0 | current_nt_hash->hash, |
2496 | 0 | last_set_time, |
2497 | 0 | channel)) |
2498 | 0 | { |
2499 | 0 | if (account_name != NULL) { |
2500 | 0 | *account_name = lp_netbios_name(); |
2501 | 0 | } |
2502 | |
|
2503 | 0 | return true; |
2504 | 0 | } |
2505 | | |
2506 | 0 | DEBUG(5, ("get_trust_pw_hash: could not fetch trust account " |
2507 | 0 | "password for domain %s\n", domain)); |
2508 | 0 | return False; |
2509 | 0 | } |
2510 | | |
2511 | | bool get_trust_pw_hash(const char *domain, uint8_t ret_pwd[16], |
2512 | | const char **account_name, |
2513 | | enum netr_SchannelType *channel) |
2514 | 0 | { |
2515 | 0 | struct samr_Password current_nt_hash; |
2516 | 0 | bool ok; |
2517 | |
|
2518 | 0 | ok = get_trust_pw_hash2(domain, account_name, channel, |
2519 | 0 | ¤t_nt_hash, NULL, NULL); |
2520 | 0 | if (!ok) { |
2521 | 0 | return false; |
2522 | 0 | } |
2523 | | |
2524 | 0 | memcpy(ret_pwd, current_nt_hash.hash, sizeof(current_nt_hash.hash)); |
2525 | 0 | return true; |
2526 | 0 | } |
2527 | | |
2528 | | NTSTATUS pdb_get_trust_credentials(const char *netbios_domain, |
2529 | | const char *dns_domain, /* optional */ |
2530 | | TALLOC_CTX *mem_ctx, |
2531 | | struct cli_credentials **_creds) |
2532 | 0 | { |
2533 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
2534 | 0 | NTSTATUS status; |
2535 | 0 | struct loadparm_context *lp_ctx; |
2536 | 0 | enum netr_SchannelType channel; |
2537 | 0 | time_t last_set_time; |
2538 | 0 | const char *_account_name; |
2539 | 0 | const char *account_name; |
2540 | 0 | char *cur_pw = NULL; |
2541 | 0 | char *prev_pw = NULL; |
2542 | 0 | struct samr_Password cur_nt_hash; |
2543 | 0 | struct cli_credentials *creds = NULL; |
2544 | 0 | bool ok; |
2545 | | |
2546 | | /* |
2547 | | * If this is our primary trust relationship, use the common |
2548 | | * code to read the secrets.ldb or secrets.tdb file. |
2549 | | */ |
2550 | 0 | if (strequal(netbios_domain, lp_workgroup())) { |
2551 | 0 | struct db_context *db_ctx = secrets_db_ctx(); |
2552 | 0 | if (db_ctx == NULL) { |
2553 | 0 | DEBUG(1, ("failed to open secrets.tdb to obtain our trust credentials for %s\n", |
2554 | 0 | netbios_domain)); |
2555 | 0 | status = NT_STATUS_INTERNAL_ERROR; |
2556 | 0 | goto fail; |
2557 | 0 | } |
2558 | | |
2559 | 0 | lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); |
2560 | 0 | if (lp_ctx == NULL) { |
2561 | 0 | DEBUG(1, ("loadparm_init_s3 failed\n")); |
2562 | 0 | status = NT_STATUS_INTERNAL_ERROR; |
2563 | 0 | goto fail; |
2564 | 0 | } |
2565 | | |
2566 | 0 | creds = cli_credentials_init(mem_ctx); |
2567 | 0 | if (creds == NULL) { |
2568 | 0 | status = NT_STATUS_NO_MEMORY; |
2569 | 0 | goto fail; |
2570 | 0 | } |
2571 | | |
2572 | 0 | ok = cli_credentials_set_conf(creds, lp_ctx); |
2573 | 0 | if (!ok) { |
2574 | 0 | status = NT_STATUS_INTERNAL_ERROR; |
2575 | 0 | goto fail; |
2576 | 0 | } |
2577 | | |
2578 | 0 | ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED); |
2579 | 0 | if (!ok) { |
2580 | 0 | status = NT_STATUS_NO_MEMORY; |
2581 | 0 | goto fail; |
2582 | 0 | } |
2583 | | |
2584 | 0 | status = cli_credentials_set_machine_account_db_ctx(creds, |
2585 | 0 | lp_ctx, |
2586 | 0 | db_ctx); |
2587 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2588 | 0 | goto fail; |
2589 | 0 | } |
2590 | 0 | goto done; |
2591 | 0 | } else if (!IS_DC) { |
2592 | 0 | DEBUG(1, ("Refusing to get trust account info for %s, " |
2593 | 0 | "which is not our primary domain %s, " |
2594 | 0 | "as we are not a DC\n", |
2595 | 0 | netbios_domain, lp_workgroup())); |
2596 | 0 | status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; |
2597 | 0 | goto fail; |
2598 | 0 | } |
2599 | | |
2600 | 0 | status = pdb_get_trusteddom_creds(netbios_domain, mem_ctx, &creds); |
2601 | 0 | if (NT_STATUS_IS_OK(status)) { |
2602 | 0 | goto done; |
2603 | 0 | } |
2604 | 0 | if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) { |
2605 | 0 | goto fail; |
2606 | 0 | } |
2607 | | |
2608 | 0 | ok = get_trust_pw_clear2(netbios_domain, |
2609 | 0 | &_account_name, |
2610 | 0 | &channel, |
2611 | 0 | &cur_pw, |
2612 | 0 | &last_set_time, |
2613 | 0 | &prev_pw); |
2614 | 0 | if (!ok) { |
2615 | 0 | ok = get_trust_pw_hash2(netbios_domain, |
2616 | 0 | &_account_name, |
2617 | 0 | &channel, |
2618 | 0 | &cur_nt_hash, |
2619 | 0 | &last_set_time, |
2620 | 0 | NULL); |
2621 | 0 | if (!ok) { |
2622 | 0 | DEBUG(1, ("get_trust_pw_*2 failed for domain[%s]\n", |
2623 | 0 | netbios_domain)); |
2624 | 0 | status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; |
2625 | 0 | goto fail; |
2626 | 0 | } |
2627 | 0 | } |
2628 | | |
2629 | 0 | account_name = talloc_asprintf(frame, "%s$", _account_name); |
2630 | 0 | if (account_name == NULL) { |
2631 | 0 | status = NT_STATUS_NO_MEMORY; |
2632 | 0 | goto fail; |
2633 | 0 | } |
2634 | | |
2635 | 0 | lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); |
2636 | 0 | if (lp_ctx == NULL) { |
2637 | 0 | DEBUG(1, ("loadparm_init_s3 failed\n")); |
2638 | 0 | status = NT_STATUS_INTERNAL_ERROR; |
2639 | 0 | goto fail; |
2640 | 0 | } |
2641 | | |
2642 | 0 | creds = cli_credentials_init(mem_ctx); |
2643 | 0 | if (creds == NULL) { |
2644 | 0 | status = NT_STATUS_NO_MEMORY; |
2645 | 0 | goto fail; |
2646 | 0 | } |
2647 | | |
2648 | 0 | ok = cli_credentials_set_conf(creds, lp_ctx); |
2649 | 0 | if (!ok) { |
2650 | 0 | status = NT_STATUS_INTERNAL_ERROR; |
2651 | 0 | goto fail; |
2652 | 0 | } |
2653 | | |
2654 | 0 | cli_credentials_set_secure_channel_type(creds, channel); |
2655 | 0 | cli_credentials_set_password_last_changed_time(creds, last_set_time); |
2656 | |
|
2657 | 0 | ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED); |
2658 | 0 | if (!ok) { |
2659 | 0 | status = NT_STATUS_NO_MEMORY; |
2660 | 0 | goto fail; |
2661 | 0 | } |
2662 | | |
2663 | 0 | if (dns_domain != NULL) { |
2664 | 0 | ok = cli_credentials_set_realm(creds, dns_domain, CRED_SPECIFIED); |
2665 | 0 | if (!ok) { |
2666 | 0 | status = NT_STATUS_NO_MEMORY; |
2667 | 0 | goto fail; |
2668 | 0 | } |
2669 | | |
2670 | | /* |
2671 | | * It's not possible to use NTLMSSP with a domain trust account. |
2672 | | */ |
2673 | 0 | cli_credentials_set_kerberos_state(creds, |
2674 | 0 | CRED_USE_KERBEROS_REQUIRED, |
2675 | 0 | CRED_SPECIFIED); |
2676 | 0 | } else { |
2677 | | /* |
2678 | | * We can't use kerberos against an NT4 domain. |
2679 | | * |
2680 | | * We should have a mode that also disallows NTLMSSP here, |
2681 | | * as only NETLOGON SCHANNEL is possible. |
2682 | | */ |
2683 | 0 | cli_credentials_set_kerberos_state(creds, |
2684 | 0 | CRED_USE_KERBEROS_DISABLED, |
2685 | 0 | CRED_SPECIFIED); |
2686 | 0 | } |
2687 | | |
2688 | 0 | ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED); |
2689 | 0 | if (!ok) { |
2690 | 0 | status = NT_STATUS_NO_MEMORY; |
2691 | 0 | goto fail; |
2692 | 0 | } |
2693 | | |
2694 | 0 | if (cur_pw == NULL) { |
2695 | 0 | ok = cli_credentials_set_nt_hash(creds, &cur_nt_hash, CRED_SPECIFIED); |
2696 | 0 | if (!ok) { |
2697 | 0 | status = NT_STATUS_NO_MEMORY; |
2698 | 0 | goto fail; |
2699 | 0 | } |
2700 | | /* |
2701 | | * We currently can't do kerberos just with an NTHASH. |
2702 | | */ |
2703 | 0 | cli_credentials_set_kerberos_state(creds, |
2704 | 0 | CRED_USE_KERBEROS_DISABLED, |
2705 | 0 | CRED_SPECIFIED); |
2706 | 0 | goto done; |
2707 | 0 | } |
2708 | | |
2709 | 0 | ok = cli_credentials_set_password(creds, cur_pw, CRED_SPECIFIED); |
2710 | 0 | if (!ok) { |
2711 | 0 | status = NT_STATUS_NO_MEMORY; |
2712 | 0 | goto fail; |
2713 | 0 | } |
2714 | | |
2715 | 0 | if (prev_pw != NULL) { |
2716 | 0 | ok = cli_credentials_set_old_password(creds, prev_pw, CRED_SPECIFIED); |
2717 | 0 | if (!ok) { |
2718 | 0 | status = NT_STATUS_NO_MEMORY; |
2719 | 0 | goto fail; |
2720 | 0 | } |
2721 | 0 | } |
2722 | | |
2723 | 0 | done: |
2724 | 0 | *_creds = creds; |
2725 | 0 | creds = NULL; |
2726 | 0 | status = NT_STATUS_OK; |
2727 | 0 | fail: |
2728 | 0 | TALLOC_FREE(creds); |
2729 | 0 | SAFE_FREE(cur_pw); |
2730 | 0 | SAFE_FREE(prev_pw); |
2731 | | TALLOC_FREE(frame); |
2732 | 0 | return status; |
2733 | 0 | } |