Samba 3: added Samba 3.0.24 sources
[tomato.git] / release / src / router / samba3 / source / passdb / pdb_tdb.c
blob262e68eb007c0ea5763bbc43a4058f78b1528cdc
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 2 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, write to the Free Software Foundation, Inc., 675
23 * Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
28 #if 0 /* when made a module use this */
30 static int tdbsam_debug_level = DBGC_ALL;
31 #undef DBGC_CLASS
32 #define DBGC_CLASS tdbsam_debug_level
34 #else
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_PASSDB
39 #endif
41 #define TDBSAM_VERSION 3 /* Most recent TDBSAM version */
42 #define TDBSAM_VERSION_STRING "INFO/version"
43 #define PASSDB_FILE_NAME "passdb.tdb"
44 #define USERPREFIX "USER_"
45 #define RIDPREFIX "RID_"
46 #define PRIVPREFIX "PRIV_"
48 struct pwent_list {
49 struct pwent_list *prev, *next;
50 TDB_DATA key;
52 static struct pwent_list *tdbsam_pwent_list;
53 static BOOL pwent_initialized;
55 /* GLOBAL TDB SAM CONTEXT */
57 static TDB_CONTEXT *tdbsam;
58 static int ref_count = 0;
59 static pstring tdbsam_filename;
61 /**********************************************************************
62 Marshall/unmarshall struct samu structs.
63 *********************************************************************/
65 #define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
66 #define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
67 #define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
69 /*********************************************************************
70 *********************************************************************/
72 static BOOL init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
75 /* times are stored as 32bit integer
76 take care on system with 64bit wide time_t
77 --SSS */
78 uint32 logon_time,
79 logoff_time,
80 kickoff_time,
81 pass_last_set_time,
82 pass_can_change_time,
83 pass_must_change_time;
84 char *username = NULL;
85 char *domain = NULL;
86 char *nt_username = NULL;
87 char *dir_drive = NULL;
88 char *unknown_str = NULL;
89 char *munged_dial = NULL;
90 char *fullname = NULL;
91 char *homedir = NULL;
92 char *logon_script = NULL;
93 char *profile_path = NULL;
94 char *acct_desc = NULL;
95 char *workstations = NULL;
96 uint32 username_len, domain_len, nt_username_len,
97 dir_drive_len, unknown_str_len, munged_dial_len,
98 fullname_len, homedir_len, logon_script_len,
99 profile_path_len, acct_desc_len, workstations_len;
101 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
102 uint16 acct_ctrl, logon_divs;
103 uint16 bad_password_count, logon_count;
104 uint8 *hours = NULL;
105 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
106 uint32 len = 0;
107 uint32 lm_pw_len, nt_pw_len, hourslen;
108 BOOL ret = True;
110 if(sampass == NULL || buf == NULL) {
111 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
112 return False;
115 /* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
117 /* unpack the buffer into variables */
118 len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V0,
119 &logon_time, /* d */
120 &logoff_time, /* d */
121 &kickoff_time, /* d */
122 &pass_last_set_time, /* d */
123 &pass_can_change_time, /* d */
124 &pass_must_change_time, /* d */
125 &username_len, &username, /* B */
126 &domain_len, &domain, /* B */
127 &nt_username_len, &nt_username, /* B */
128 &fullname_len, &fullname, /* B */
129 &homedir_len, &homedir, /* B */
130 &dir_drive_len, &dir_drive, /* B */
131 &logon_script_len, &logon_script, /* B */
132 &profile_path_len, &profile_path, /* B */
133 &acct_desc_len, &acct_desc, /* B */
134 &workstations_len, &workstations, /* B */
135 &unknown_str_len, &unknown_str, /* B */
136 &munged_dial_len, &munged_dial, /* B */
137 &user_rid, /* d */
138 &group_rid, /* d */
139 &lm_pw_len, &lm_pw_ptr, /* B */
140 &nt_pw_len, &nt_pw_ptr, /* B */
141 &acct_ctrl, /* w */
142 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
143 &logon_divs, /* w */
144 &hours_len, /* d */
145 &hourslen, &hours, /* B */
146 &bad_password_count, /* w */
147 &logon_count, /* w */
148 &unknown_6); /* d */
150 if (len == (uint32) -1) {
151 ret = False;
152 goto done;
155 pdb_set_logon_time(sampass, logon_time, PDB_SET);
156 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
157 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
158 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
159 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
160 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
162 pdb_set_username(sampass, username, PDB_SET);
163 pdb_set_domain(sampass, domain, PDB_SET);
164 pdb_set_nt_username(sampass, nt_username, PDB_SET);
165 pdb_set_fullname(sampass, fullname, PDB_SET);
167 if (homedir) {
168 pdb_set_homedir(sampass, homedir, PDB_SET);
170 else {
171 pdb_set_homedir(sampass,
172 talloc_sub_basic(sampass, username, 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, lp_logon_drive()),
181 PDB_DEFAULT);
184 if (logon_script)
185 pdb_set_logon_script(sampass, logon_script, PDB_SET);
186 else {
187 pdb_set_logon_script(sampass,
188 talloc_sub_basic(sampass, username, lp_logon_script()),
189 PDB_DEFAULT);
192 if (profile_path) {
193 pdb_set_profile_path(sampass, profile_path, PDB_SET);
194 } else {
195 pdb_set_profile_path(sampass,
196 talloc_sub_basic(sampass, username, lp_logon_path()),
197 PDB_DEFAULT);
200 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
201 pdb_set_workstations(sampass, workstations, PDB_SET);
202 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
204 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
205 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
206 ret = False;
207 goto done;
211 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
212 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
213 ret = False;
214 goto done;
218 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
219 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
220 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
221 pdb_set_hours_len(sampass, hours_len, PDB_SET);
222 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
223 pdb_set_logon_count(sampass, logon_count, PDB_SET);
224 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
225 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
226 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
227 pdb_set_hours(sampass, hours, PDB_SET);
229 done:
231 SAFE_FREE(username);
232 SAFE_FREE(domain);
233 SAFE_FREE(nt_username);
234 SAFE_FREE(fullname);
235 SAFE_FREE(homedir);
236 SAFE_FREE(dir_drive);
237 SAFE_FREE(logon_script);
238 SAFE_FREE(profile_path);
239 SAFE_FREE(acct_desc);
240 SAFE_FREE(workstations);
241 SAFE_FREE(munged_dial);
242 SAFE_FREE(unknown_str);
243 SAFE_FREE(lm_pw_ptr);
244 SAFE_FREE(nt_pw_ptr);
245 SAFE_FREE(hours);
247 return ret;
250 /*********************************************************************
251 *********************************************************************/
253 static BOOL init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
256 /* times are stored as 32bit integer
257 take care on system with 64bit wide time_t
258 --SSS */
259 uint32 logon_time,
260 logoff_time,
261 kickoff_time,
262 bad_password_time,
263 pass_last_set_time,
264 pass_can_change_time,
265 pass_must_change_time;
266 char *username = NULL;
267 char *domain = NULL;
268 char *nt_username = NULL;
269 char *dir_drive = NULL;
270 char *unknown_str = NULL;
271 char *munged_dial = NULL;
272 char *fullname = NULL;
273 char *homedir = NULL;
274 char *logon_script = NULL;
275 char *profile_path = NULL;
276 char *acct_desc = NULL;
277 char *workstations = NULL;
278 uint32 username_len, domain_len, nt_username_len,
279 dir_drive_len, unknown_str_len, munged_dial_len,
280 fullname_len, homedir_len, logon_script_len,
281 profile_path_len, acct_desc_len, workstations_len;
283 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
284 uint16 acct_ctrl, logon_divs;
285 uint16 bad_password_count, logon_count;
286 uint8 *hours = NULL;
287 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
288 uint32 len = 0;
289 uint32 lm_pw_len, nt_pw_len, hourslen;
290 BOOL ret = True;
292 if(sampass == NULL || buf == NULL) {
293 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
294 return False;
297 /* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
299 /* unpack the buffer into variables */
300 len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V1,
301 &logon_time, /* d */
302 &logoff_time, /* d */
303 &kickoff_time, /* d */
304 /* Change from V0 is addition of bad_password_time field. */
305 &bad_password_time, /* d */
306 &pass_last_set_time, /* d */
307 &pass_can_change_time, /* d */
308 &pass_must_change_time, /* d */
309 &username_len, &username, /* B */
310 &domain_len, &domain, /* B */
311 &nt_username_len, &nt_username, /* B */
312 &fullname_len, &fullname, /* B */
313 &homedir_len, &homedir, /* B */
314 &dir_drive_len, &dir_drive, /* B */
315 &logon_script_len, &logon_script, /* B */
316 &profile_path_len, &profile_path, /* B */
317 &acct_desc_len, &acct_desc, /* B */
318 &workstations_len, &workstations, /* B */
319 &unknown_str_len, &unknown_str, /* B */
320 &munged_dial_len, &munged_dial, /* B */
321 &user_rid, /* d */
322 &group_rid, /* d */
323 &lm_pw_len, &lm_pw_ptr, /* B */
324 &nt_pw_len, &nt_pw_ptr, /* B */
325 &acct_ctrl, /* w */
326 &remove_me, /* d */
327 &logon_divs, /* w */
328 &hours_len, /* d */
329 &hourslen, &hours, /* B */
330 &bad_password_count, /* w */
331 &logon_count, /* w */
332 &unknown_6); /* d */
334 if (len == (uint32) -1) {
335 ret = False;
336 goto done;
339 pdb_set_logon_time(sampass, logon_time, PDB_SET);
340 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
341 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
343 /* Change from V0 is addition of bad_password_time field. */
344 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
345 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
346 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
347 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
349 pdb_set_username(sampass, username, PDB_SET);
350 pdb_set_domain(sampass, domain, PDB_SET);
351 pdb_set_nt_username(sampass, nt_username, PDB_SET);
352 pdb_set_fullname(sampass, fullname, PDB_SET);
354 if (homedir) {
355 pdb_set_homedir(sampass, homedir, PDB_SET);
357 else {
358 pdb_set_homedir(sampass,
359 talloc_sub_basic(sampass, username, lp_logon_home()),
360 PDB_DEFAULT);
363 if (dir_drive)
364 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
365 else {
366 pdb_set_dir_drive(sampass,
367 talloc_sub_basic(sampass, username, lp_logon_drive()),
368 PDB_DEFAULT);
371 if (logon_script)
372 pdb_set_logon_script(sampass, logon_script, PDB_SET);
373 else {
374 pdb_set_logon_script(sampass,
375 talloc_sub_basic(sampass, username, lp_logon_script()),
376 PDB_DEFAULT);
379 if (profile_path) {
380 pdb_set_profile_path(sampass, profile_path, PDB_SET);
381 } else {
382 pdb_set_profile_path(sampass,
383 talloc_sub_basic(sampass, username, lp_logon_path()),
384 PDB_DEFAULT);
387 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
388 pdb_set_workstations(sampass, workstations, PDB_SET);
389 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
391 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
392 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
393 ret = False;
394 goto done;
398 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
399 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
400 ret = False;
401 goto done;
405 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
407 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
408 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
409 pdb_set_hours_len(sampass, hours_len, PDB_SET);
410 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
411 pdb_set_logon_count(sampass, logon_count, PDB_SET);
412 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
413 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
414 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
415 pdb_set_hours(sampass, hours, PDB_SET);
417 done:
419 SAFE_FREE(username);
420 SAFE_FREE(domain);
421 SAFE_FREE(nt_username);
422 SAFE_FREE(fullname);
423 SAFE_FREE(homedir);
424 SAFE_FREE(dir_drive);
425 SAFE_FREE(logon_script);
426 SAFE_FREE(profile_path);
427 SAFE_FREE(acct_desc);
428 SAFE_FREE(workstations);
429 SAFE_FREE(munged_dial);
430 SAFE_FREE(unknown_str);
431 SAFE_FREE(lm_pw_ptr);
432 SAFE_FREE(nt_pw_ptr);
433 SAFE_FREE(hours);
435 return ret;
438 BOOL init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen)
441 /* times are stored as 32bit integer
442 take care on system with 64bit wide time_t
443 --SSS */
444 uint32 logon_time,
445 logoff_time,
446 kickoff_time,
447 bad_password_time,
448 pass_last_set_time,
449 pass_can_change_time,
450 pass_must_change_time;
451 char *username = NULL;
452 char *domain = NULL;
453 char *nt_username = NULL;
454 char *dir_drive = NULL;
455 char *unknown_str = NULL;
456 char *munged_dial = NULL;
457 char *fullname = NULL;
458 char *homedir = NULL;
459 char *logon_script = NULL;
460 char *profile_path = NULL;
461 char *acct_desc = NULL;
462 char *workstations = NULL;
463 uint32 username_len, domain_len, nt_username_len,
464 dir_drive_len, unknown_str_len, munged_dial_len,
465 fullname_len, homedir_len, logon_script_len,
466 profile_path_len, acct_desc_len, workstations_len;
468 uint32 user_rid, group_rid, hours_len, unknown_6;
469 uint16 acct_ctrl, logon_divs;
470 uint16 bad_password_count, logon_count;
471 uint8 *hours = NULL;
472 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
473 uint32 len = 0;
474 uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
475 uint32 pwHistLen = 0;
476 BOOL ret = True;
477 fstring tmpstring;
478 BOOL expand_explicit = lp_passdb_expand_explicit();
480 if(sampass == NULL || buf == NULL) {
481 DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
482 return False;
485 /* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
487 /* unpack the buffer into variables */
488 len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V2,
489 &logon_time, /* d */
490 &logoff_time, /* d */
491 &kickoff_time, /* d */
492 &bad_password_time, /* d */
493 &pass_last_set_time, /* d */
494 &pass_can_change_time, /* d */
495 &pass_must_change_time, /* d */
496 &username_len, &username, /* B */
497 &domain_len, &domain, /* B */
498 &nt_username_len, &nt_username, /* B */
499 &fullname_len, &fullname, /* B */
500 &homedir_len, &homedir, /* B */
501 &dir_drive_len, &dir_drive, /* B */
502 &logon_script_len, &logon_script, /* B */
503 &profile_path_len, &profile_path, /* B */
504 &acct_desc_len, &acct_desc, /* B */
505 &workstations_len, &workstations, /* B */
506 &unknown_str_len, &unknown_str, /* B */
507 &munged_dial_len, &munged_dial, /* B */
508 &user_rid, /* d */
509 &group_rid, /* d */
510 &lm_pw_len, &lm_pw_ptr, /* B */
511 &nt_pw_len, &nt_pw_ptr, /* B */
512 /* Change from V1 is addition of password history field. */
513 &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
514 &acct_ctrl, /* w */
515 /* Also "remove_me" field was removed. */
516 &logon_divs, /* w */
517 &hours_len, /* d */
518 &hourslen, &hours, /* B */
519 &bad_password_count, /* w */
520 &logon_count, /* w */
521 &unknown_6); /* d */
523 if (len == (uint32) -1) {
524 ret = False;
525 goto done;
528 pdb_set_logon_time(sampass, logon_time, PDB_SET);
529 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
530 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
531 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
532 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
533 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
534 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
536 pdb_set_username(sampass, username, PDB_SET);
537 pdb_set_domain(sampass, domain, PDB_SET);
538 pdb_set_nt_username(sampass, nt_username, PDB_SET);
539 pdb_set_fullname(sampass, fullname, PDB_SET);
541 if (homedir) {
542 fstrcpy( tmpstring, homedir );
543 if (expand_explicit) {
544 standard_sub_basic( username, tmpstring,
545 sizeof(tmpstring) );
547 pdb_set_homedir(sampass, tmpstring, PDB_SET);
549 else {
550 pdb_set_homedir(sampass,
551 talloc_sub_basic(sampass, username, lp_logon_home()),
552 PDB_DEFAULT);
555 if (dir_drive)
556 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
557 else
558 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
560 if (logon_script) {
561 fstrcpy( tmpstring, logon_script );
562 if (expand_explicit) {
563 standard_sub_basic( username, tmpstring,
564 sizeof(tmpstring) );
566 pdb_set_logon_script(sampass, tmpstring, PDB_SET);
568 else {
569 pdb_set_logon_script(sampass,
570 talloc_sub_basic(sampass, username, lp_logon_script()),
571 PDB_DEFAULT);
574 if (profile_path) {
575 fstrcpy( tmpstring, profile_path );
576 if (expand_explicit) {
577 standard_sub_basic( username, tmpstring,
578 sizeof(tmpstring) );
580 pdb_set_profile_path(sampass, tmpstring, PDB_SET);
582 else {
583 pdb_set_profile_path(sampass,
584 talloc_sub_basic(sampass, username, lp_logon_path()),
585 PDB_DEFAULT);
588 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
589 pdb_set_workstations(sampass, workstations, PDB_SET);
590 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
592 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
593 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
594 ret = False;
595 goto done;
599 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
600 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
601 ret = False;
602 goto done;
606 /* Change from V1 is addition of password history field. */
607 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
608 if (pwHistLen) {
609 uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN);
610 if (!pw_hist) {
611 ret = False;
612 goto done;
614 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
615 if (nt_pw_hist_ptr && nt_pw_hist_len) {
616 int i;
617 SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
618 nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
619 for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
620 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
621 &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
622 PW_HISTORY_ENTRY_LEN);
625 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
626 SAFE_FREE(pw_hist);
627 ret = False;
628 goto done;
630 SAFE_FREE(pw_hist);
631 } else {
632 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
635 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
636 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
637 pdb_set_hours_len(sampass, hours_len, PDB_SET);
638 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
639 pdb_set_logon_count(sampass, logon_count, PDB_SET);
640 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
641 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
642 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
643 pdb_set_hours(sampass, hours, PDB_SET);
645 done:
647 SAFE_FREE(username);
648 SAFE_FREE(domain);
649 SAFE_FREE(nt_username);
650 SAFE_FREE(fullname);
651 SAFE_FREE(homedir);
652 SAFE_FREE(dir_drive);
653 SAFE_FREE(logon_script);
654 SAFE_FREE(profile_path);
655 SAFE_FREE(acct_desc);
656 SAFE_FREE(workstations);
657 SAFE_FREE(munged_dial);
658 SAFE_FREE(unknown_str);
659 SAFE_FREE(lm_pw_ptr);
660 SAFE_FREE(nt_pw_ptr);
661 SAFE_FREE(nt_pw_hist_ptr);
662 SAFE_FREE(hours);
664 return ret;
668 /**********************************************************************
669 Intialize a struct samu struct from a BYTE buffer of size len
670 *********************************************************************/
672 static BOOL init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
674 return init_sam_from_buffer_v3(sampass, buf, buflen);
677 /**********************************************************************
678 Intialize a BYTE buffer from a struct samu struct
679 *********************************************************************/
681 static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, BOOL size_only)
683 return init_buffer_from_sam_v3(buf, sampass, size_only);
686 /**********************************************************************
687 Intialize a BYTE buffer from a struct samu struct
688 *********************************************************************/
690 static BOOL tdbsam_convert(int32 from)
692 const char *vstring = TDBSAM_VERSION_STRING;
693 const char *prefix = USERPREFIX;
694 TDB_DATA data, key, old_key;
695 uint8 *buf = NULL;
696 BOOL ret;
698 /* handle a Samba upgrade */
699 tdb_lock_bystring(tdbsam, vstring);
701 /* Enumerate all records and convert them */
702 key = tdb_firstkey(tdbsam);
704 while (key.dptr) {
706 /* skip all non-USER entries (eg. RIDs) */
707 while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
708 old_key = key;
709 /* increment to next in line */
710 key = tdb_nextkey(tdbsam, key);
711 SAFE_FREE(old_key.dptr);
714 if (key.dptr) {
715 struct samu *user = NULL;
717 /* read from tdbsam */
718 data = tdb_fetch(tdbsam, key);
719 if (!data.dptr) {
720 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
721 return False;
724 /* unpack the buffer from the former format */
725 if ( !(user = samu_new( NULL )) ) {
726 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
727 SAFE_FREE( data.dptr );
728 return False;
730 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
731 switch (from) {
732 case 0:
733 ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
734 break;
735 case 1:
736 ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
737 break;
738 case 2:
739 ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
740 break;
741 case 3:
742 ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize);
743 break;
744 default:
745 /* unknown tdbsam version */
746 ret = False;
748 if (!ret) {
749 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
750 SAFE_FREE(data.dptr);
751 TALLOC_FREE(user );
752 return False;
755 /* We're finished with the old data. */
756 SAFE_FREE(data.dptr);
758 /* pack from the buffer into the new format */
760 DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
761 data.dsize = init_buffer_from_sam (&buf, user, False);
762 TALLOC_FREE(user );
764 if ( data.dsize == -1 ) {
765 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
766 return False;
768 data.dptr = (char *)buf;
770 /* Store the buffer inside the TDBSAM */
771 if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
772 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
773 SAFE_FREE(data.dptr);
774 return False;
777 SAFE_FREE(data.dptr);
779 /* increment to next in line */
780 old_key = key;
781 key = tdb_nextkey(tdbsam, key);
782 SAFE_FREE(old_key.dptr);
788 /* upgrade finished */
789 tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
790 tdb_unlock_bystring(tdbsam, vstring);
792 return(True);
795 /*********************************************************************
796 Open the tdbsam file based on the absolute path specified.
797 Uses a reference count to allow multiple open calls.
798 *********************************************************************/
800 static BOOL tdbsam_open( const char *name )
802 int32 version;
804 /* check if we are already open */
806 if ( tdbsam ) {
807 ref_count++;
808 DEBUG(8,("tdbsam_open: Incrementing open reference count. Ref count is now %d\n",
809 ref_count));
810 return True;
813 SMB_ASSERT( ref_count == 0 );
815 /* Try to open tdb passwd. Create a new one if necessary */
817 if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
818 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
819 return False;
822 /* set the initial reference count - must be done before tdbsam_convert
823 as that calls tdbsam_open()/tdbsam_close(). */
825 ref_count = 1;
827 /* Check the version */
828 version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
830 if (version == -1) {
831 version = 0; /* Version not found, assume version 0 */
834 /* Compare the version */
835 if (version > TDBSAM_VERSION) {
836 /* Version more recent than the latest known */
837 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
838 tdb_close( tdbsam );
839 ref_count = 0;
840 return False;
844 if ( version < TDBSAM_VERSION ) {
845 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n",
846 version, TDBSAM_VERSION));
848 if ( !tdbsam_convert(version) ) {
849 DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
850 tdb_close(tdbsam);
851 ref_count = 0;
852 return False;
855 DEBUG(3, ("TDBSAM converted successfully.\n"));
858 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
860 return True;
863 /****************************************************************************
864 wrapper atound tdb_close() to handle the reference count
865 ****************************************************************************/
867 void tdbsam_close( void )
869 ref_count--;
871 DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
873 SMB_ASSERT(ref_count >= 0 );
875 if ( ref_count == 0 ) {
876 tdb_close( tdbsam );
877 tdbsam = NULL;
880 return;
883 /****************************************************************************
884 creates a list of user keys
885 ****************************************************************************/
887 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
889 const char *prefix = USERPREFIX;
890 int prefixlen = strlen (prefix);
891 struct pwent_list *ptr;
893 if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
894 if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
895 DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
897 /* just return 0 and let the traversal continue */
898 return 0;
900 ZERO_STRUCTP(ptr);
902 /* save a copy of the key */
904 ptr->key.dptr = memdup( key.dptr, key.dsize );
905 if (!ptr->key.dptr) {
906 DEBUG(0,("tdbsam_traverse_setpwent: memdup failed\n"));
907 /* just return 0 and let the traversal continue */
908 SAFE_FREE(ptr);
909 return 0;
912 ptr->key.dsize = key.dsize;
914 DLIST_ADD( tdbsam_pwent_list, ptr );
918 return 0;
921 /***************************************************************
922 Open the TDB passwd database for SAM account enumeration.
923 Save a list of user keys for iteration.
924 ****************************************************************/
926 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint32 acb_mask)
928 if ( !tdbsam_open( tdbsam_filename ) ) {
929 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
930 return NT_STATUS_ACCESS_DENIED;
933 tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
934 pwent_initialized = True;
936 return NT_STATUS_OK;
940 /***************************************************************
941 End enumeration of the TDB passwd list.
942 ****************************************************************/
944 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
946 struct pwent_list *ptr, *ptr_next;
948 /* close the tdb only if we have a valid pwent state */
950 if ( pwent_initialized ) {
951 DEBUG(7, ("endtdbpwent: closed sam database.\n"));
952 tdbsam_close();
955 /* clear out any remaining entries in the list */
957 for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
958 ptr_next = ptr->next;
959 DLIST_REMOVE( tdbsam_pwent_list, ptr );
960 SAFE_FREE( ptr->key.dptr);
961 SAFE_FREE( ptr );
964 pwent_initialized = False;
967 /*****************************************************************
968 Get one struct samu from the TDB (next in line)
969 *****************************************************************/
971 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
973 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
974 TDB_DATA data;
975 struct pwent_list *pkey;
977 if ( !user ) {
978 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
979 return nt_status;
982 if ( !tdbsam_pwent_list ) {
983 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
984 return nt_status;
987 /* pull the next entry */
989 pkey = tdbsam_pwent_list;
990 DLIST_REMOVE( tdbsam_pwent_list, pkey );
992 data = tdb_fetch(tdbsam, pkey->key);
994 SAFE_FREE( pkey->key.dptr);
995 SAFE_FREE( pkey);
997 if ( !data.dptr ) {
998 DEBUG(5,("pdb_getsampwent: database entry not found. Was the user deleted?\n"));
999 return nt_status;
1002 if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
1003 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1006 SAFE_FREE( data.dptr );
1008 return NT_STATUS_OK;
1011 /******************************************************************
1012 Lookup a name in the SAM TDB
1013 ******************************************************************/
1015 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
1017 TDB_DATA data, key;
1018 fstring keystr;
1019 fstring name;
1021 if ( !user ) {
1022 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
1023 return NT_STATUS_NO_MEMORY;
1026 /* Data is stored in all lower-case */
1027 fstrcpy(name, sname);
1028 strlower_m(name);
1030 /* set search key */
1031 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1032 key.dptr = keystr;
1033 key.dsize = strlen(keystr) + 1;
1035 /* open the database */
1037 if ( !tdbsam_open( tdbsam_filename ) ) {
1038 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1039 return NT_STATUS_ACCESS_DENIED;
1042 /* get the record */
1044 data = tdb_fetch(tdbsam, key);
1045 if (!data.dptr) {
1046 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
1047 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1048 DEBUGADD(5, (" Key: %s\n", keystr));
1049 tdbsam_close();
1050 return NT_STATUS_NO_SUCH_USER;
1053 /* unpack the buffer */
1055 if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
1056 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1057 SAFE_FREE(data.dptr);
1058 tdbsam_close();
1059 return NT_STATUS_NO_MEMORY;
1062 /* success */
1064 SAFE_FREE(data.dptr);
1065 tdbsam_close();
1067 return NT_STATUS_OK;
1070 /***************************************************************************
1071 Search by rid
1072 **************************************************************************/
1074 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
1076 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1077 TDB_DATA data, key;
1078 fstring keystr;
1079 fstring name;
1081 if ( !user ) {
1082 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
1083 return nt_status;
1086 /* set search key */
1088 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1089 key.dptr = keystr;
1090 key.dsize = strlen (keystr) + 1;
1092 /* open the database */
1094 if ( !tdbsam_open( tdbsam_filename ) ) {
1095 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1096 return NT_STATUS_ACCESS_DENIED;
1099 /* get the record */
1101 data = tdb_fetch (tdbsam, key);
1102 if (!data.dptr) {
1103 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
1104 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1105 nt_status = NT_STATUS_UNSUCCESSFUL;
1106 goto done;
1109 fstrcpy(name, data.dptr);
1110 SAFE_FREE(data.dptr);
1112 nt_status = tdbsam_getsampwnam (my_methods, user, name);
1114 done:
1115 /* cleanup */
1117 tdbsam_close();
1119 return nt_status;
1122 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
1124 uint32 rid;
1126 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
1127 return NT_STATUS_UNSUCCESSFUL;
1129 return tdbsam_getsampwrid(my_methods, user, rid);
1132 static BOOL tdb_delete_samacct_only( struct samu *sam_pass )
1134 TDB_DATA key;
1135 fstring keystr;
1136 fstring name;
1138 fstrcpy(name, pdb_get_username(sam_pass));
1139 strlower_m(name);
1141 /* set the search key */
1143 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1144 key.dptr = keystr;
1145 key.dsize = strlen (keystr) + 1;
1147 /* it's outaa here! 8^) */
1149 if (tdb_delete(tdbsam, key) != TDB_SUCCESS) {
1150 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1151 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1152 return False;
1155 return True;
1158 /***************************************************************************
1159 Delete a struct samu records for the username and RID key
1160 ****************************************************************************/
1162 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
1164 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1165 TDB_DATA key;
1166 fstring keystr;
1167 uint32 rid;
1168 fstring name;
1170 /* open the database */
1172 if ( !tdbsam_open( tdbsam_filename ) ) {
1173 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1174 tdbsam_filename));
1175 return NT_STATUS_ACCESS_DENIED;
1178 fstrcpy(name, pdb_get_username(sam_pass));
1179 strlower_m(name);
1181 /* set the search key */
1183 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1184 key.dptr = keystr;
1185 key.dsize = strlen (keystr) + 1;
1187 rid = pdb_get_user_rid(sam_pass);
1189 /* it's outaa here! 8^) */
1191 if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1192 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1193 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1194 nt_status = NT_STATUS_UNSUCCESSFUL;
1195 goto done;
1198 /* set the search key */
1200 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1201 key.dptr = keystr;
1202 key.dsize = strlen (keystr) + 1;
1204 /* it's outaa here! 8^) */
1206 if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1207 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
1208 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1209 nt_status = NT_STATUS_UNSUCCESSFUL;
1210 goto done;
1213 nt_status = NT_STATUS_OK;
1215 done:
1216 tdbsam_close();
1218 return nt_status;
1222 /***************************************************************************
1223 Update the TDB SAM account record only
1224 Assumes that the tdbsam is already open
1225 ****************************************************************************/
1226 static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag )
1228 TDB_DATA key, data;
1229 uint8 *buf = NULL;
1230 fstring keystr;
1231 fstring name;
1232 BOOL ret = True;
1234 /* copy the struct samu struct into a BYTE buffer for storage */
1236 if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1237 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1238 ret = False;
1239 goto done;
1241 data.dptr = (char *)buf;
1243 fstrcpy(name, pdb_get_username(newpwd));
1244 strlower_m(name);
1246 DEBUG(5, ("Storing %saccount %s with RID %d\n",
1247 flag == TDB_INSERT ? "(new) " : "", name,
1248 pdb_get_user_rid(newpwd)));
1250 /* setup the USER index key */
1251 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1252 key.dptr = keystr;
1253 key.dsize = strlen(keystr) + 1;
1255 /* add the account */
1257 if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) {
1258 DEBUG(0, ("Unable to modify passwd TDB!"));
1259 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
1260 DEBUGADD(0, (" occured while storing the main record (%s)\n",
1261 keystr));
1262 ret = False;
1263 goto done;
1266 done:
1267 /* cleanup */
1268 SAFE_FREE(buf);
1270 return ret;
1273 /***************************************************************************
1274 Update the TDB SAM RID record only
1275 Assumes that the tdbsam is already open
1276 ****************************************************************************/
1277 static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag )
1279 TDB_DATA key, data;
1280 fstring keystr;
1281 fstring name;
1283 fstrcpy(name, pdb_get_username(newpwd));
1284 strlower_m(name);
1286 /* setup RID data */
1287 data.dsize = strlen(name) + 1;
1288 data.dptr = name;
1290 /* setup the RID index key */
1291 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
1292 key.dptr = keystr;
1293 key.dsize = strlen (keystr) + 1;
1295 /* add the reference */
1296 if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) {
1297 DEBUG(0, ("Unable to modify TDB passwd !"));
1298 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
1299 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
1300 return False;
1303 return True;
1307 /***************************************************************************
1308 Update the TDB SAM
1309 ****************************************************************************/
1311 static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
1313 BOOL result = True;
1315 /* invalidate the existing TDB iterator if it is open */
1317 tdbsam_endsampwent( my_methods );
1319 #if 0
1320 if ( !pdb_get_group_rid(newpwd) ) {
1321 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
1322 "without a primary group RID\n", pdb_get_username(newpwd)));
1323 return False;
1325 #endif
1327 if (!pdb_get_user_rid(newpwd)) {
1328 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
1329 return False;
1332 /* open the database */
1334 if ( !tdbsam_open( tdbsam_filename ) ) {
1335 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1336 return False;
1339 if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
1340 result = False;
1343 /* cleanup */
1345 tdbsam_close();
1347 return result;
1350 /***************************************************************************
1351 Modifies an existing struct samu
1352 ****************************************************************************/
1354 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1356 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1357 return NT_STATUS_UNSUCCESSFUL;
1359 return NT_STATUS_OK;
1362 /***************************************************************************
1363 Adds an existing struct samu
1364 ****************************************************************************/
1366 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1368 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1369 return NT_STATUS_UNSUCCESSFUL;
1371 return NT_STATUS_OK;
1374 /***************************************************************************
1375 Renames a struct samu
1376 - check for the posix user/rename user script
1377 - Add and lock the new user record
1378 - rename the posix user
1379 - rewrite the rid->username record
1380 - delete the old user
1381 - unlock the new user record
1382 ***************************************************************************/
1383 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1384 struct samu *old_acct,
1385 const char *newname)
1387 struct samu *new_acct = NULL;
1388 pstring rename_script;
1389 BOOL interim_account = False;
1390 int rename_ret;
1391 fstring oldname_lower;
1392 fstring newname_lower;
1394 /* can't do anything without an external script */
1396 pstrcpy(rename_script, lp_renameuser_script() );
1397 if ( ! *rename_script ) {
1398 return NT_STATUS_ACCESS_DENIED;
1401 /* invalidate the existing TDB iterator if it is open */
1403 tdbsam_endsampwent( my_methods );
1405 if ( !(new_acct = samu_new( NULL )) ) {
1406 return NT_STATUS_NO_MEMORY;
1409 if ( !pdb_copy_sam_account(new_acct, old_acct)
1410 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1412 TALLOC_FREE(new_acct );
1413 return NT_STATUS_NO_MEMORY;
1416 /* open the database */
1418 if ( !tdbsam_open( tdbsam_filename ) ) {
1419 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1420 TALLOC_FREE(new_acct );
1421 return NT_STATUS_ACCESS_DENIED;
1424 /* add the new account and lock it */
1426 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1427 goto done;
1430 interim_account = True;
1432 if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) {
1433 goto done;
1436 /* Rename the posix user. Follow the semantics of _samr_create_user()
1437 so that we lower case the posix name but preserve the case in passdb */
1439 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1440 strlower_m( oldname_lower );
1442 fstrcpy( newname_lower, newname );
1443 strlower_m( newname_lower );
1445 string_sub2(rename_script, "%unew", newname_lower, sizeof(pstring),
1446 True, False, True);
1447 string_sub2(rename_script, "%uold", oldname_lower, sizeof(pstring),
1448 True, False, True);
1449 rename_ret = smbrun(rename_script, NULL);
1451 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
1453 if (rename_ret == 0) {
1454 smb_nscd_flush_user_cache();
1457 if (rename_ret) {
1458 goto done;
1461 /* rewrite the rid->username record */
1463 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1464 goto done;
1466 interim_account = False;
1467 tdb_unlock_bystring( tdbsam, newname );
1469 tdb_delete_samacct_only( old_acct );
1471 tdbsam_close();
1473 TALLOC_FREE(new_acct );
1474 return NT_STATUS_OK;
1476 done:
1477 /* cleanup */
1478 if (interim_account) {
1479 tdb_unlock_bystring(tdbsam, newname);
1480 tdb_delete_samacct_only(new_acct);
1483 tdbsam_close();
1485 if (new_acct)
1486 TALLOC_FREE(new_acct);
1488 return NT_STATUS_ACCESS_DENIED;
1491 static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods)
1493 return False;
1497 * Historically, winbind was responsible for allocating RIDs, so the next RID
1498 * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1499 * but for compatibility reasons we still keep the the next RID counter in
1500 * winbindd_idmap.tdb.
1503 /*****************************************************************************
1504 Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1505 sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1506 winbind completely and store the RID counter in passdb.tdb.
1508 Dont' fully initialize with the HWM values, if it's new, we're only
1509 interested in the RID counter.
1510 *****************************************************************************/
1512 static BOOL init_idmap_tdb(TDB_CONTEXT *tdb)
1514 int32 version;
1516 if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1517 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1518 return False;
1521 version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1523 if (version == -1) {
1524 /* No key found, must be a new db */
1525 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1526 IDMAP_VERSION) != 0) {
1527 DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1528 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1529 return False;
1531 version = IDMAP_VERSION;
1534 if (version != IDMAP_VERSION) {
1535 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1536 "start winbind once\n", IDMAP_VERSION, version));
1537 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1538 return False;
1541 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1542 return True;
1545 static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1547 TDB_CONTEXT *tdb;
1548 uint32 rid;
1549 BOOL ret = False;
1551 tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
1552 TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1554 if (tdb == NULL) {
1555 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1556 goto done;
1559 if (!init_idmap_tdb(tdb)) {
1560 DEBUG(1, ("Could not init idmap\n"));
1561 goto done;
1564 rid = BASE_RID; /* Default if not set */
1566 if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1567 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1568 goto done;
1571 *prid = rid;
1572 ret = True;
1574 done:
1575 if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1576 smb_panic("tdb_close(idmap_tdb) failed\n");
1579 return ret;
1582 /*********************************************************************
1583 Initialize the tdb sam backend. Setup the dispath table of methods,
1584 open the tdb, etc...
1585 *********************************************************************/
1587 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1589 NTSTATUS nt_status;
1590 pstring tdbfile;
1591 const char *pfile = location;
1593 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1594 return nt_status;
1597 (*pdb_method)->name = "tdbsam";
1599 (*pdb_method)->setsampwent = tdbsam_setsampwent;
1600 (*pdb_method)->endsampwent = tdbsam_endsampwent;
1601 (*pdb_method)->getsampwent = tdbsam_getsampwent;
1602 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1603 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1604 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1605 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1606 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1607 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1609 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1610 (*pdb_method)->new_rid = tdbsam_new_rid;
1612 /* save the path for later */
1614 if ( !location ) {
1615 pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME );
1616 pfile = tdbfile;
1618 pstrcpy( tdbsam_filename, pfile );
1620 /* no private data */
1622 (*pdb_method)->private_data = NULL;
1623 (*pdb_method)->free_private_data = NULL;
1625 return NT_STATUS_OK;
1628 NTSTATUS pdb_tdbsam_init(void)
1630 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);