Tiny refactoring
[Samba.git] / source / passdb / pdb_tdb.c
blobfe8497c939393b5db2399d87b347196e7d13ed8a
1 /*
2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Copyright (C) Simo Sorce 2000-2003
6 * Copyright (C) Gerald Carter 2000-2006
7 * Copyright (C) Jeremy Allison 2001
8 * Copyright (C) Andrew Bartlett 2002
9 * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
11 * This program is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 3 of the License, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
21 * You should have received a copy of the GNU General Public License along with
22 * this program; if not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
27 #if 0 /* when made a module use this */
29 static int tdbsam_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS tdbsam_debug_level
33 #else
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_PASSDB
38 #endif
40 #define TDBSAM_VERSION 3 /* Most recent TDBSAM version */
41 #define TDBSAM_VERSION_STRING "INFO/version"
42 #define PASSDB_FILE_NAME "passdb.tdb"
43 #define USERPREFIX "USER_"
44 #define RIDPREFIX "RID_"
45 #define PRIVPREFIX "PRIV_"
47 struct pwent_list {
48 struct pwent_list *prev, *next;
49 TDB_DATA key;
51 static struct pwent_list *tdbsam_pwent_list;
52 static bool pwent_initialized;
54 /* GLOBAL TDB SAM CONTEXT */
56 static TDB_CONTEXT *tdbsam;
57 static int ref_count = 0;
58 static char *tdbsam_filename;
60 /**********************************************************************
61 Marshall/unmarshall struct samu structs.
62 *********************************************************************/
64 #define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
65 #define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
66 #define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
68 /*********************************************************************
69 *********************************************************************/
71 static bool init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
74 /* times are stored as 32bit integer
75 take care on system with 64bit wide time_t
76 --SSS */
77 uint32 logon_time,
78 logoff_time,
79 kickoff_time,
80 pass_last_set_time,
81 pass_can_change_time,
82 pass_must_change_time;
83 char *username = NULL;
84 char *domain = NULL;
85 char *nt_username = NULL;
86 char *dir_drive = NULL;
87 char *unknown_str = NULL;
88 char *munged_dial = NULL;
89 char *fullname = NULL;
90 char *homedir = NULL;
91 char *logon_script = NULL;
92 char *profile_path = NULL;
93 char *acct_desc = NULL;
94 char *workstations = NULL;
95 uint32 username_len, domain_len, nt_username_len,
96 dir_drive_len, unknown_str_len, munged_dial_len,
97 fullname_len, homedir_len, logon_script_len,
98 profile_path_len, acct_desc_len, workstations_len;
100 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
101 uint16 acct_ctrl, logon_divs;
102 uint16 bad_password_count, logon_count;
103 uint8 *hours = NULL;
104 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
105 uint32 len = 0;
106 uint32 lm_pw_len, nt_pw_len, hourslen;
107 bool ret = True;
109 if(sampass == NULL || buf == NULL) {
110 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
111 return False;
114 /* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
116 /* unpack the buffer into variables */
117 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V0,
118 &logon_time, /* d */
119 &logoff_time, /* d */
120 &kickoff_time, /* d */
121 &pass_last_set_time, /* d */
122 &pass_can_change_time, /* d */
123 &pass_must_change_time, /* d */
124 &username_len, &username, /* B */
125 &domain_len, &domain, /* B */
126 &nt_username_len, &nt_username, /* B */
127 &fullname_len, &fullname, /* B */
128 &homedir_len, &homedir, /* B */
129 &dir_drive_len, &dir_drive, /* B */
130 &logon_script_len, &logon_script, /* B */
131 &profile_path_len, &profile_path, /* B */
132 &acct_desc_len, &acct_desc, /* B */
133 &workstations_len, &workstations, /* B */
134 &unknown_str_len, &unknown_str, /* B */
135 &munged_dial_len, &munged_dial, /* B */
136 &user_rid, /* d */
137 &group_rid, /* d */
138 &lm_pw_len, &lm_pw_ptr, /* B */
139 &nt_pw_len, &nt_pw_ptr, /* B */
140 &acct_ctrl, /* w */
141 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
142 &logon_divs, /* w */
143 &hours_len, /* d */
144 &hourslen, &hours, /* B */
145 &bad_password_count, /* w */
146 &logon_count, /* w */
147 &unknown_6); /* d */
149 if (len == (uint32) -1) {
150 ret = False;
151 goto done;
154 pdb_set_logon_time(sampass, logon_time, PDB_SET);
155 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
156 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
157 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
158 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
159 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
161 pdb_set_username(sampass, username, PDB_SET);
162 pdb_set_domain(sampass, domain, PDB_SET);
163 pdb_set_nt_username(sampass, nt_username, PDB_SET);
164 pdb_set_fullname(sampass, fullname, PDB_SET);
166 if (homedir) {
167 pdb_set_homedir(sampass, homedir, PDB_SET);
169 else {
170 pdb_set_homedir(sampass,
171 talloc_sub_basic(sampass, username, domain,
172 lp_logon_home()),
173 PDB_DEFAULT);
176 if (dir_drive)
177 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
178 else {
179 pdb_set_dir_drive(sampass,
180 talloc_sub_basic(sampass, username, domain,
181 lp_logon_drive()),
182 PDB_DEFAULT);
185 if (logon_script)
186 pdb_set_logon_script(sampass, logon_script, PDB_SET);
187 else {
188 pdb_set_logon_script(sampass,
189 talloc_sub_basic(sampass, username, domain,
190 lp_logon_script()),
191 PDB_DEFAULT);
194 if (profile_path) {
195 pdb_set_profile_path(sampass, profile_path, PDB_SET);
196 } else {
197 pdb_set_profile_path(sampass,
198 talloc_sub_basic(sampass, username, domain,
199 lp_logon_path()),
200 PDB_DEFAULT);
203 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
204 pdb_set_workstations(sampass, workstations, PDB_SET);
205 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
207 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
208 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
209 ret = False;
210 goto done;
214 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
215 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
216 ret = False;
217 goto done;
221 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
222 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
223 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
224 pdb_set_hours_len(sampass, hours_len, PDB_SET);
225 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
226 pdb_set_logon_count(sampass, logon_count, PDB_SET);
227 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
228 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
229 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
230 pdb_set_hours(sampass, hours, PDB_SET);
232 done:
234 SAFE_FREE(username);
235 SAFE_FREE(domain);
236 SAFE_FREE(nt_username);
237 SAFE_FREE(fullname);
238 SAFE_FREE(homedir);
239 SAFE_FREE(dir_drive);
240 SAFE_FREE(logon_script);
241 SAFE_FREE(profile_path);
242 SAFE_FREE(acct_desc);
243 SAFE_FREE(workstations);
244 SAFE_FREE(munged_dial);
245 SAFE_FREE(unknown_str);
246 SAFE_FREE(lm_pw_ptr);
247 SAFE_FREE(nt_pw_ptr);
248 SAFE_FREE(hours);
250 return ret;
253 /*********************************************************************
254 *********************************************************************/
256 static bool init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
259 /* times are stored as 32bit integer
260 take care on system with 64bit wide time_t
261 --SSS */
262 uint32 logon_time,
263 logoff_time,
264 kickoff_time,
265 bad_password_time,
266 pass_last_set_time,
267 pass_can_change_time,
268 pass_must_change_time;
269 char *username = NULL;
270 char *domain = NULL;
271 char *nt_username = NULL;
272 char *dir_drive = NULL;
273 char *unknown_str = NULL;
274 char *munged_dial = NULL;
275 char *fullname = NULL;
276 char *homedir = NULL;
277 char *logon_script = NULL;
278 char *profile_path = NULL;
279 char *acct_desc = NULL;
280 char *workstations = NULL;
281 uint32 username_len, domain_len, nt_username_len,
282 dir_drive_len, unknown_str_len, munged_dial_len,
283 fullname_len, homedir_len, logon_script_len,
284 profile_path_len, acct_desc_len, workstations_len;
286 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
287 uint16 acct_ctrl, logon_divs;
288 uint16 bad_password_count, logon_count;
289 uint8 *hours = NULL;
290 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
291 uint32 len = 0;
292 uint32 lm_pw_len, nt_pw_len, hourslen;
293 bool ret = True;
295 if(sampass == NULL || buf == NULL) {
296 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
297 return False;
300 /* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
302 /* unpack the buffer into variables */
303 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V1,
304 &logon_time, /* d */
305 &logoff_time, /* d */
306 &kickoff_time, /* d */
307 /* Change from V0 is addition of bad_password_time field. */
308 &bad_password_time, /* d */
309 &pass_last_set_time, /* d */
310 &pass_can_change_time, /* d */
311 &pass_must_change_time, /* d */
312 &username_len, &username, /* B */
313 &domain_len, &domain, /* B */
314 &nt_username_len, &nt_username, /* B */
315 &fullname_len, &fullname, /* B */
316 &homedir_len, &homedir, /* B */
317 &dir_drive_len, &dir_drive, /* B */
318 &logon_script_len, &logon_script, /* B */
319 &profile_path_len, &profile_path, /* B */
320 &acct_desc_len, &acct_desc, /* B */
321 &workstations_len, &workstations, /* B */
322 &unknown_str_len, &unknown_str, /* B */
323 &munged_dial_len, &munged_dial, /* B */
324 &user_rid, /* d */
325 &group_rid, /* d */
326 &lm_pw_len, &lm_pw_ptr, /* B */
327 &nt_pw_len, &nt_pw_ptr, /* B */
328 &acct_ctrl, /* w */
329 &remove_me, /* d */
330 &logon_divs, /* w */
331 &hours_len, /* d */
332 &hourslen, &hours, /* B */
333 &bad_password_count, /* w */
334 &logon_count, /* w */
335 &unknown_6); /* d */
337 if (len == (uint32) -1) {
338 ret = False;
339 goto done;
342 pdb_set_logon_time(sampass, logon_time, PDB_SET);
343 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
344 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
346 /* Change from V0 is addition of bad_password_time field. */
347 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
348 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
349 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
350 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
352 pdb_set_username(sampass, username, PDB_SET);
353 pdb_set_domain(sampass, domain, PDB_SET);
354 pdb_set_nt_username(sampass, nt_username, PDB_SET);
355 pdb_set_fullname(sampass, fullname, PDB_SET);
357 if (homedir) {
358 pdb_set_homedir(sampass, homedir, PDB_SET);
360 else {
361 pdb_set_homedir(sampass,
362 talloc_sub_basic(sampass, username, domain,
363 lp_logon_home()),
364 PDB_DEFAULT);
367 if (dir_drive)
368 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
369 else {
370 pdb_set_dir_drive(sampass,
371 talloc_sub_basic(sampass, username, domain,
372 lp_logon_drive()),
373 PDB_DEFAULT);
376 if (logon_script)
377 pdb_set_logon_script(sampass, logon_script, PDB_SET);
378 else {
379 pdb_set_logon_script(sampass,
380 talloc_sub_basic(sampass, username, domain,
381 lp_logon_script()),
382 PDB_DEFAULT);
385 if (profile_path) {
386 pdb_set_profile_path(sampass, profile_path, PDB_SET);
387 } else {
388 pdb_set_profile_path(sampass,
389 talloc_sub_basic(sampass, username, domain,
390 lp_logon_path()),
391 PDB_DEFAULT);
394 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
395 pdb_set_workstations(sampass, workstations, PDB_SET);
396 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
398 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
399 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
400 ret = False;
401 goto done;
405 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
406 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
407 ret = False;
408 goto done;
412 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
414 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
415 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
416 pdb_set_hours_len(sampass, hours_len, PDB_SET);
417 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
418 pdb_set_logon_count(sampass, logon_count, PDB_SET);
419 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
420 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
421 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
422 pdb_set_hours(sampass, hours, PDB_SET);
424 done:
426 SAFE_FREE(username);
427 SAFE_FREE(domain);
428 SAFE_FREE(nt_username);
429 SAFE_FREE(fullname);
430 SAFE_FREE(homedir);
431 SAFE_FREE(dir_drive);
432 SAFE_FREE(logon_script);
433 SAFE_FREE(profile_path);
434 SAFE_FREE(acct_desc);
435 SAFE_FREE(workstations);
436 SAFE_FREE(munged_dial);
437 SAFE_FREE(unknown_str);
438 SAFE_FREE(lm_pw_ptr);
439 SAFE_FREE(nt_pw_ptr);
440 SAFE_FREE(hours);
442 return ret;
445 bool init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen)
448 /* times are stored as 32bit integer
449 take care on system with 64bit wide time_t
450 --SSS */
451 uint32 logon_time,
452 logoff_time,
453 kickoff_time,
454 bad_password_time,
455 pass_last_set_time,
456 pass_can_change_time,
457 pass_must_change_time;
458 char *username = NULL;
459 char *domain = NULL;
460 char *nt_username = NULL;
461 char *dir_drive = NULL;
462 char *unknown_str = NULL;
463 char *munged_dial = NULL;
464 char *fullname = NULL;
465 char *homedir = NULL;
466 char *logon_script = NULL;
467 char *profile_path = NULL;
468 char *acct_desc = NULL;
469 char *workstations = NULL;
470 uint32 username_len, domain_len, nt_username_len,
471 dir_drive_len, unknown_str_len, munged_dial_len,
472 fullname_len, homedir_len, logon_script_len,
473 profile_path_len, acct_desc_len, workstations_len;
475 uint32 user_rid, group_rid, hours_len, unknown_6;
476 uint16 acct_ctrl, logon_divs;
477 uint16 bad_password_count, logon_count;
478 uint8 *hours = NULL;
479 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
480 uint32 len = 0;
481 uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
482 uint32 pwHistLen = 0;
483 bool ret = True;
484 fstring tmp_string;
485 bool expand_explicit = lp_passdb_expand_explicit();
487 if(sampass == NULL || buf == NULL) {
488 DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
489 return False;
492 /* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
494 /* unpack the buffer into variables */
495 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V2,
496 &logon_time, /* d */
497 &logoff_time, /* d */
498 &kickoff_time, /* d */
499 &bad_password_time, /* d */
500 &pass_last_set_time, /* d */
501 &pass_can_change_time, /* d */
502 &pass_must_change_time, /* d */
503 &username_len, &username, /* B */
504 &domain_len, &domain, /* B */
505 &nt_username_len, &nt_username, /* B */
506 &fullname_len, &fullname, /* B */
507 &homedir_len, &homedir, /* B */
508 &dir_drive_len, &dir_drive, /* B */
509 &logon_script_len, &logon_script, /* B */
510 &profile_path_len, &profile_path, /* B */
511 &acct_desc_len, &acct_desc, /* B */
512 &workstations_len, &workstations, /* B */
513 &unknown_str_len, &unknown_str, /* B */
514 &munged_dial_len, &munged_dial, /* B */
515 &user_rid, /* d */
516 &group_rid, /* d */
517 &lm_pw_len, &lm_pw_ptr, /* B */
518 &nt_pw_len, &nt_pw_ptr, /* B */
519 /* Change from V1 is addition of password history field. */
520 &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
521 &acct_ctrl, /* w */
522 /* Also "remove_me" field was removed. */
523 &logon_divs, /* w */
524 &hours_len, /* d */
525 &hourslen, &hours, /* B */
526 &bad_password_count, /* w */
527 &logon_count, /* w */
528 &unknown_6); /* d */
530 if (len == (uint32) -1) {
531 ret = False;
532 goto done;
535 pdb_set_logon_time(sampass, logon_time, PDB_SET);
536 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
537 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
538 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
539 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
540 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
541 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
543 pdb_set_username(sampass, username, PDB_SET);
544 pdb_set_domain(sampass, domain, PDB_SET);
545 pdb_set_nt_username(sampass, nt_username, PDB_SET);
546 pdb_set_fullname(sampass, fullname, PDB_SET);
548 if (homedir) {
549 fstrcpy( tmp_string, homedir );
550 if (expand_explicit) {
551 standard_sub_basic( username, domain, tmp_string,
552 sizeof(tmp_string) );
554 pdb_set_homedir(sampass, tmp_string, PDB_SET);
556 else {
557 pdb_set_homedir(sampass,
558 talloc_sub_basic(sampass, username, domain,
559 lp_logon_home()),
560 PDB_DEFAULT);
563 if (dir_drive)
564 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
565 else
566 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
568 if (logon_script) {
569 fstrcpy( tmp_string, logon_script );
570 if (expand_explicit) {
571 standard_sub_basic( username, domain, tmp_string,
572 sizeof(tmp_string) );
574 pdb_set_logon_script(sampass, tmp_string, PDB_SET);
576 else {
577 pdb_set_logon_script(sampass,
578 talloc_sub_basic(sampass, username, domain,
579 lp_logon_script()),
580 PDB_DEFAULT);
583 if (profile_path) {
584 fstrcpy( tmp_string, profile_path );
585 if (expand_explicit) {
586 standard_sub_basic( username, domain, tmp_string,
587 sizeof(tmp_string) );
589 pdb_set_profile_path(sampass, tmp_string, PDB_SET);
591 else {
592 pdb_set_profile_path(sampass,
593 talloc_sub_basic(sampass, username, domain,
594 lp_logon_path()),
595 PDB_DEFAULT);
598 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
599 pdb_set_workstations(sampass, workstations, PDB_SET);
600 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
602 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
603 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
604 ret = False;
605 goto done;
609 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
610 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
611 ret = False;
612 goto done;
616 /* Change from V1 is addition of password history field. */
617 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
618 if (pwHistLen) {
619 uint8 *pw_hist = SMB_MALLOC_ARRAY(uint8, pwHistLen * PW_HISTORY_ENTRY_LEN);
620 if (!pw_hist) {
621 ret = False;
622 goto done;
624 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
625 if (nt_pw_hist_ptr && nt_pw_hist_len) {
626 int i;
627 SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
628 nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
629 for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
630 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
631 &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
632 PW_HISTORY_ENTRY_LEN);
635 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
636 SAFE_FREE(pw_hist);
637 ret = False;
638 goto done;
640 SAFE_FREE(pw_hist);
641 } else {
642 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
645 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
646 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
647 pdb_set_hours_len(sampass, hours_len, PDB_SET);
648 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
649 pdb_set_logon_count(sampass, logon_count, PDB_SET);
650 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
651 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
652 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
653 pdb_set_hours(sampass, hours, PDB_SET);
655 done:
657 SAFE_FREE(username);
658 SAFE_FREE(domain);
659 SAFE_FREE(nt_username);
660 SAFE_FREE(fullname);
661 SAFE_FREE(homedir);
662 SAFE_FREE(dir_drive);
663 SAFE_FREE(logon_script);
664 SAFE_FREE(profile_path);
665 SAFE_FREE(acct_desc);
666 SAFE_FREE(workstations);
667 SAFE_FREE(munged_dial);
668 SAFE_FREE(unknown_str);
669 SAFE_FREE(lm_pw_ptr);
670 SAFE_FREE(nt_pw_ptr);
671 SAFE_FREE(nt_pw_hist_ptr);
672 SAFE_FREE(hours);
674 return ret;
678 /**********************************************************************
679 Intialize a struct samu struct from a BYTE buffer of size len
680 *********************************************************************/
682 static bool init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
684 return init_sam_from_buffer_v3(sampass, buf, buflen);
687 /**********************************************************************
688 Intialize a BYTE buffer from a struct samu struct
689 *********************************************************************/
691 static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, bool size_only)
693 return init_buffer_from_sam_v3(buf, sampass, size_only);
696 /**********************************************************************
697 Intialize a BYTE buffer from a struct samu struct
698 *********************************************************************/
700 static bool tdbsam_convert(int32 from)
702 const char *vstring = TDBSAM_VERSION_STRING;
703 const char *prefix = USERPREFIX;
704 TDB_DATA data, key, old_key;
705 uint8 *buf = NULL;
706 bool ret;
708 /* handle a Samba upgrade */
709 tdb_lock_bystring(tdbsam, vstring);
711 /* Enumerate all records and convert them */
712 key = tdb_firstkey(tdbsam);
714 while (key.dptr) {
716 /* skip all non-USER entries (eg. RIDs) */
717 while ((key.dsize != 0) && (strncmp((const char *)key.dptr, prefix, strlen (prefix)))) {
718 old_key = key;
719 /* increment to next in line */
720 key = tdb_nextkey(tdbsam, key);
721 SAFE_FREE(old_key.dptr);
724 if (key.dptr) {
725 struct samu *user = NULL;
727 /* read from tdbsam */
728 data = tdb_fetch(tdbsam, key);
729 if (!data.dptr) {
730 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
731 return False;
734 /* unpack the buffer from the former format */
735 if ( !(user = samu_new( NULL )) ) {
736 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
737 SAFE_FREE( data.dptr );
738 return False;
740 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
741 switch (from) {
742 case 0:
743 ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
744 break;
745 case 1:
746 ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
747 break;
748 case 2:
749 ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
750 break;
751 case 3:
752 ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize);
753 break;
754 default:
755 /* unknown tdbsam version */
756 ret = False;
758 if (!ret) {
759 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
760 SAFE_FREE(data.dptr);
761 TALLOC_FREE(user );
762 return False;
765 /* We're finished with the old data. */
766 SAFE_FREE(data.dptr);
768 /* pack from the buffer into the new format */
770 DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n",
771 (const char *)key.dptr, from));
772 data.dsize = init_buffer_from_sam (&buf, user, False);
773 TALLOC_FREE(user );
775 if ( data.dsize == -1 ) {
776 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
777 return False;
779 data.dptr = buf;
781 /* Store the buffer inside the TDBSAM */
782 if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
783 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
784 SAFE_FREE(data.dptr);
785 return False;
788 SAFE_FREE(data.dptr);
790 /* increment to next in line */
791 old_key = key;
792 key = tdb_nextkey(tdbsam, key);
793 SAFE_FREE(old_key.dptr);
799 /* upgrade finished */
800 tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
801 tdb_unlock_bystring(tdbsam, vstring);
803 return(True);
806 /*********************************************************************
807 Open the tdbsam file based on the absolute path specified.
808 Uses a reference count to allow multiple open calls.
809 *********************************************************************/
811 static bool tdbsam_open( const char *name )
813 int32 version;
815 /* check if we are already open */
817 if ( tdbsam ) {
818 ref_count++;
819 DEBUG(8,("tdbsam_open: Incrementing open reference count. Ref count is now %d\n",
820 ref_count));
821 return True;
824 SMB_ASSERT( ref_count == 0 );
826 /* Try to open tdb passwd. Create a new one if necessary */
828 if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
829 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
830 return False;
833 /* set the initial reference count - must be done before tdbsam_convert
834 as that calls tdbsam_open()/tdbsam_close(). */
836 ref_count = 1;
838 /* Check the version */
839 version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
841 if (version == -1) {
842 version = 0; /* Version not found, assume version 0 */
845 /* Compare the version */
846 if (version > TDBSAM_VERSION) {
847 /* Version more recent than the latest known */
848 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
849 tdb_close( tdbsam );
850 ref_count = 0;
851 return False;
855 if ( version < TDBSAM_VERSION ) {
856 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n",
857 version, TDBSAM_VERSION));
859 if ( !tdbsam_convert(version) ) {
860 DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
861 tdb_close(tdbsam);
862 ref_count = 0;
863 return False;
866 DEBUG(3, ("TDBSAM converted successfully.\n"));
869 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
871 return True;
874 /****************************************************************************
875 wrapper atound tdb_close() to handle the reference count
876 ****************************************************************************/
878 void tdbsam_close( void )
880 ref_count--;
882 DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
884 SMB_ASSERT(ref_count >= 0 );
886 if ( ref_count == 0 ) {
887 tdb_close( tdbsam );
888 tdbsam = NULL;
891 return;
894 /****************************************************************************
895 creates a list of user keys
896 ****************************************************************************/
898 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
900 const char *prefix = USERPREFIX;
901 int prefixlen = strlen (prefix);
902 struct pwent_list *ptr;
904 if ( strncmp((const char *)key.dptr, prefix, prefixlen) == 0 ) {
905 if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
906 DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
908 /* just return 0 and let the traversal continue */
909 return 0;
911 ZERO_STRUCTP(ptr);
913 /* save a copy of the key */
915 ptr->key.dptr = (uint8 *)memdup( key.dptr, key.dsize );
916 if (!ptr->key.dptr) {
917 DEBUG(0,("tdbsam_traverse_setpwent: memdup failed\n"));
918 /* just return 0 and let the traversal continue */
919 SAFE_FREE(ptr);
920 return 0;
923 ptr->key.dsize = key.dsize;
925 DLIST_ADD( tdbsam_pwent_list, ptr );
929 return 0;
932 /***************************************************************
933 Open the TDB passwd database for SAM account enumeration.
934 Save a list of user keys for iteration.
935 ****************************************************************/
937 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, bool update, uint32 acb_mask)
939 if ( !tdbsam_open( tdbsam_filename ) ) {
940 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
941 return NT_STATUS_ACCESS_DENIED;
944 tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
945 pwent_initialized = True;
947 return NT_STATUS_OK;
951 /***************************************************************
952 End enumeration of the TDB passwd list.
953 ****************************************************************/
955 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
957 struct pwent_list *ptr, *ptr_next;
959 /* close the tdb only if we have a valid pwent state */
961 if ( pwent_initialized ) {
962 DEBUG(7, ("endtdbpwent: closed sam database.\n"));
963 tdbsam_close();
966 /* clear out any remaining entries in the list */
968 for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
969 ptr_next = ptr->next;
970 DLIST_REMOVE( tdbsam_pwent_list, ptr );
971 SAFE_FREE( ptr->key.dptr);
972 SAFE_FREE( ptr );
975 pwent_initialized = False;
978 /*****************************************************************
979 Get one struct samu from the TDB (next in line)
980 *****************************************************************/
982 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
984 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
985 TDB_DATA data;
986 struct pwent_list *pkey;
988 if ( !user ) {
989 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
990 return nt_status;
993 if ( !tdbsam_pwent_list ) {
994 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
995 return nt_status;
998 /* pull the next entry */
1000 pkey = tdbsam_pwent_list;
1001 DLIST_REMOVE( tdbsam_pwent_list, pkey );
1003 data = tdb_fetch(tdbsam, pkey->key);
1005 SAFE_FREE( pkey->key.dptr);
1006 SAFE_FREE( pkey);
1008 if ( !data.dptr ) {
1009 DEBUG(5,("pdb_getsampwent: database entry not found. Was the user deleted?\n"));
1010 return nt_status;
1013 if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
1014 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1017 SAFE_FREE( data.dptr );
1019 return NT_STATUS_OK;
1022 /******************************************************************
1023 Lookup a name in the SAM TDB
1024 ******************************************************************/
1026 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
1028 TDB_DATA data;
1029 fstring keystr;
1030 fstring name;
1032 if ( !user ) {
1033 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
1034 return NT_STATUS_NO_MEMORY;
1037 /* Data is stored in all lower-case */
1038 fstrcpy(name, sname);
1039 strlower_m(name);
1041 /* set search key */
1042 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1044 /* open the database */
1046 if ( !tdbsam_open( tdbsam_filename ) ) {
1047 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1048 return NT_STATUS_ACCESS_DENIED;
1051 /* get the record */
1053 data = tdb_fetch_bystring(tdbsam, keystr);
1054 if (!data.dptr) {
1055 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
1056 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1057 DEBUGADD(5, (" Key: %s\n", keystr));
1058 tdbsam_close();
1059 return NT_STATUS_NO_SUCH_USER;
1062 /* unpack the buffer */
1064 if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
1065 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1066 SAFE_FREE(data.dptr);
1067 tdbsam_close();
1068 return NT_STATUS_NO_MEMORY;
1071 /* success */
1073 SAFE_FREE(data.dptr);
1074 tdbsam_close();
1076 return NT_STATUS_OK;
1079 /***************************************************************************
1080 Search by rid
1081 **************************************************************************/
1083 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
1085 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1086 TDB_DATA data;
1087 fstring keystr;
1088 fstring name;
1090 if ( !user ) {
1091 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
1092 return nt_status;
1095 /* set search key */
1097 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1099 /* open the database */
1101 if ( !tdbsam_open( tdbsam_filename ) ) {
1102 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1103 return NT_STATUS_ACCESS_DENIED;
1106 /* get the record */
1108 data = tdb_fetch_bystring (tdbsam, keystr);
1109 if (!data.dptr) {
1110 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
1111 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1112 nt_status = NT_STATUS_UNSUCCESSFUL;
1113 goto done;
1116 fstrcpy(name, (const char *)data.dptr);
1117 SAFE_FREE(data.dptr);
1119 nt_status = tdbsam_getsampwnam (my_methods, user, name);
1121 done:
1122 /* cleanup */
1124 tdbsam_close();
1126 return nt_status;
1129 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
1131 uint32 rid;
1133 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
1134 return NT_STATUS_UNSUCCESSFUL;
1136 return tdbsam_getsampwrid(my_methods, user, rid);
1139 static bool tdb_delete_samacct_only( struct samu *sam_pass )
1141 fstring keystr;
1142 fstring name;
1144 fstrcpy(name, pdb_get_username(sam_pass));
1145 strlower_m(name);
1147 /* set the search key */
1149 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1151 /* it's outaa here! 8^) */
1153 if (tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS) {
1154 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1155 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1156 return False;
1159 return True;
1162 /***************************************************************************
1163 Delete a struct samu records for the username and RID key
1164 ****************************************************************************/
1166 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
1168 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1169 fstring keystr;
1170 uint32 rid;
1171 fstring name;
1173 /* open the database */
1175 if ( !tdbsam_open( tdbsam_filename ) ) {
1176 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1177 tdbsam_filename));
1178 return NT_STATUS_ACCESS_DENIED;
1181 fstrcpy(name, pdb_get_username(sam_pass));
1182 strlower_m(name);
1184 /* set the search key */
1186 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1188 rid = pdb_get_user_rid(sam_pass);
1190 /* it's outaa here! 8^) */
1192 if ( tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS ) {
1193 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1194 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1195 nt_status = NT_STATUS_UNSUCCESSFUL;
1196 goto done;
1199 /* set the search key */
1201 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1203 /* it's outaa here! 8^) */
1205 if ( tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS ) {
1206 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
1207 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1208 nt_status = NT_STATUS_UNSUCCESSFUL;
1209 goto done;
1212 nt_status = NT_STATUS_OK;
1214 done:
1215 tdbsam_close();
1217 return nt_status;
1221 /***************************************************************************
1222 Update the TDB SAM account record only
1223 Assumes that the tdbsam is already open
1224 ****************************************************************************/
1225 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
1227 TDB_DATA data;
1228 uint8 *buf = NULL;
1229 fstring keystr;
1230 fstring name;
1231 bool ret = True;
1233 /* copy the struct samu struct into a BYTE buffer for storage */
1235 if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1236 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1237 ret = False;
1238 goto done;
1240 data.dptr = buf;
1242 fstrcpy(name, pdb_get_username(newpwd));
1243 strlower_m(name);
1245 DEBUG(5, ("Storing %saccount %s with RID %d\n",
1246 flag == TDB_INSERT ? "(new) " : "", name,
1247 pdb_get_user_rid(newpwd)));
1249 /* setup the USER index key */
1250 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1252 /* add the account */
1254 if ( tdb_store_bystring(tdbsam, keystr, data, flag) != TDB_SUCCESS ) {
1255 DEBUG(0, ("Unable to modify passwd TDB!"));
1256 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
1257 DEBUGADD(0, (" occured while storing the main record (%s)\n",
1258 keystr));
1259 ret = False;
1260 goto done;
1263 done:
1264 /* cleanup */
1265 SAFE_FREE(buf);
1267 return ret;
1270 /***************************************************************************
1271 Update the TDB SAM RID record only
1272 Assumes that the tdbsam is already open
1273 ****************************************************************************/
1274 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
1276 TDB_DATA data;
1277 fstring keystr;
1278 fstring name;
1280 fstrcpy(name, pdb_get_username(newpwd));
1281 strlower_m(name);
1283 /* setup RID data */
1284 data = string_term_tdb_data(name);
1286 /* setup the RID index key */
1287 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
1289 /* add the reference */
1290 if (tdb_store_bystring(tdbsam, keystr, data, flag) != TDB_SUCCESS) {
1291 DEBUG(0, ("Unable to modify TDB passwd !"));
1292 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
1293 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
1294 return False;
1297 return True;
1301 /***************************************************************************
1302 Update the TDB SAM
1303 ****************************************************************************/
1305 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
1307 bool result = True;
1309 /* invalidate the existing TDB iterator if it is open */
1311 tdbsam_endsampwent( my_methods );
1313 #if 0
1314 if ( !pdb_get_group_rid(newpwd) ) {
1315 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
1316 "without a primary group RID\n", pdb_get_username(newpwd)));
1317 return False;
1319 #endif
1321 if (!pdb_get_user_rid(newpwd)) {
1322 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
1323 return False;
1326 /* open the database */
1328 if ( !tdbsam_open( tdbsam_filename ) ) {
1329 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1330 return False;
1333 if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
1334 result = False;
1337 /* cleanup */
1339 tdbsam_close();
1341 return result;
1344 /***************************************************************************
1345 Modifies an existing struct samu
1346 ****************************************************************************/
1348 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1350 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1351 return NT_STATUS_UNSUCCESSFUL;
1353 return NT_STATUS_OK;
1356 /***************************************************************************
1357 Adds an existing struct samu
1358 ****************************************************************************/
1360 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1362 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1363 return NT_STATUS_UNSUCCESSFUL;
1365 return NT_STATUS_OK;
1368 /***************************************************************************
1369 Renames a struct samu
1370 - check for the posix user/rename user script
1371 - Add and lock the new user record
1372 - rename the posix user
1373 - rewrite the rid->username record
1374 - delete the old user
1375 - unlock the new user record
1376 ***************************************************************************/
1377 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1378 struct samu *old_acct,
1379 const char *newname)
1381 TALLOC_CTX *ctx = talloc_tos();
1382 struct samu *new_acct = NULL;
1383 char *rename_script = NULL;
1384 bool interim_account = False;
1385 int rename_ret;
1386 fstring oldname_lower;
1387 fstring newname_lower;
1389 /* can't do anything without an external script */
1391 rename_script = talloc_strdup(ctx, lp_renameuser_script());
1392 if (!rename_script) {
1393 return NT_STATUS_NO_MEMORY;
1395 if (!*rename_script) {
1396 return NT_STATUS_ACCESS_DENIED;
1399 /* invalidate the existing TDB iterator if it is open */
1401 tdbsam_endsampwent( my_methods );
1403 if ( !(new_acct = samu_new( NULL )) ) {
1404 return NT_STATUS_NO_MEMORY;
1407 if ( !pdb_copy_sam_account(new_acct, old_acct)
1408 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1410 TALLOC_FREE(new_acct );
1411 return NT_STATUS_NO_MEMORY;
1414 /* open the database */
1415 if ( !tdbsam_open( tdbsam_filename ) ) {
1416 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1417 TALLOC_FREE(new_acct );
1418 return NT_STATUS_ACCESS_DENIED;
1421 /* add the new account and lock it */
1422 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1423 goto done;
1426 interim_account = True;
1428 if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) {
1429 goto done;
1432 /* Rename the posix user. Follow the semantics of _samr_create_user()
1433 so that we lower case the posix name but preserve the case in passdb */
1435 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1436 strlower_m( oldname_lower );
1438 fstrcpy( newname_lower, newname );
1439 strlower_m( newname_lower );
1441 rename_script = talloc_string_sub2(ctx,
1442 rename_script,
1443 "%unew",
1444 newname_lower,
1445 true,
1446 false,
1447 true);
1448 if (!rename_script) {
1449 goto done;
1451 rename_script = talloc_string_sub2(ctx,
1452 rename_script,
1453 "%uold",
1454 oldname_lower,
1455 true,
1456 false,
1457 true);
1458 if (!rename_script) {
1459 goto done;
1461 rename_ret = smbrun(rename_script, NULL);
1463 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1464 rename_script, rename_ret));
1466 if (rename_ret == 0) {
1467 smb_nscd_flush_user_cache();
1470 if (rename_ret) {
1471 goto done;
1474 /* rewrite the rid->username record */
1476 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1477 goto done;
1479 interim_account = False;
1480 tdb_unlock_bystring( tdbsam, newname );
1482 tdb_delete_samacct_only( old_acct );
1484 tdbsam_close();
1486 TALLOC_FREE(new_acct );
1487 return NT_STATUS_OK;
1489 done:
1490 /* cleanup */
1491 if (interim_account) {
1492 tdb_unlock_bystring(tdbsam, newname);
1493 tdb_delete_samacct_only(new_acct);
1496 tdbsam_close();
1498 if (new_acct)
1499 TALLOC_FREE(new_acct);
1501 return NT_STATUS_ACCESS_DENIED;
1504 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
1506 return False;
1510 * Historically, winbind was responsible for allocating RIDs, so the next RID
1511 * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1512 * but for compatibility reasons we still keep the the next RID counter in
1513 * winbindd_idmap.tdb.
1516 /*****************************************************************************
1517 Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1518 sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1519 winbind completely and store the RID counter in passdb.tdb.
1521 Dont' fully initialize with the HWM values, if it's new, we're only
1522 interested in the RID counter.
1523 *****************************************************************************/
1525 static bool init_idmap_tdb(TDB_CONTEXT *tdb)
1527 int32 version;
1529 if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1530 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1531 return False;
1534 version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1536 if (version == -1) {
1537 /* No key found, must be a new db */
1538 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1539 IDMAP_VERSION) != 0) {
1540 DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1541 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1542 return False;
1544 version = IDMAP_VERSION;
1547 if (version != IDMAP_VERSION) {
1548 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1549 "start winbind once\n", IDMAP_VERSION, version));
1550 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1551 return False;
1554 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1555 return True;
1558 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1560 TDB_CONTEXT *tdb;
1561 uint32 rid;
1562 bool ret = False;
1564 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
1565 TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1567 if (tdb == NULL) {
1568 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1569 goto done;
1572 if (!init_idmap_tdb(tdb)) {
1573 DEBUG(1, ("Could not init idmap\n"));
1574 goto done;
1577 rid = BASE_RID; /* Default if not set */
1579 if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1580 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1581 goto done;
1584 *prid = rid;
1585 ret = True;
1587 done:
1588 if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1589 smb_panic("tdb_close(idmap_tdb) failed");
1592 return ret;
1595 /*********************************************************************
1596 Initialize the tdb sam backend. Setup the dispath table of methods,
1597 open the tdb, etc...
1598 *********************************************************************/
1600 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1602 NTSTATUS nt_status;
1603 char *tdbfile = NULL;
1604 const char *pfile = location;
1606 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1607 return nt_status;
1610 (*pdb_method)->name = "tdbsam";
1612 (*pdb_method)->setsampwent = tdbsam_setsampwent;
1613 (*pdb_method)->endsampwent = tdbsam_endsampwent;
1614 (*pdb_method)->getsampwent = tdbsam_getsampwent;
1615 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1616 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1617 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1618 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1619 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1620 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1622 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1623 (*pdb_method)->new_rid = tdbsam_new_rid;
1625 /* save the path for later */
1627 if (!location) {
1628 if (asprintf(&tdbfile, "%s/%s", dyn_STATEDIR(), PASSDB_FILE_NAME) < 0) {
1629 return NT_STATUS_NO_MEMORY;
1631 pfile = tdbfile;
1633 tdbsam_filename = SMB_STRDUP(pfile);
1634 if (!tdbsam_filename) {
1635 return NT_STATUS_NO_MEMORY;
1637 SAFE_FREE(tdbfile);
1639 /* no private data */
1641 (*pdb_method)->private_data = NULL;
1642 (*pdb_method)->free_private_data = NULL;
1644 return NT_STATUS_OK;
1647 NTSTATUS pdb_tdbsam_init(void)
1649 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);