netapi: implement NetShareAdd_r.
[Samba.git] / source / passdb / pdb_tdb.c
blobe40f4bbab8a25c41df79530ee5606ee9b977e91e
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 USERPREFIX_LEN 5
45 #define RIDPREFIX "RID_"
46 #define PRIVPREFIX "PRIV_"
48 /* GLOBAL TDB SAM CONTEXT */
50 static struct db_context *db_sam;
51 static char *tdbsam_filename;
53 /**********************************************************************
54 Marshall/unmarshall struct samu structs.
55 *********************************************************************/
57 #define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
58 #define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
59 #define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
61 /*********************************************************************
62 *********************************************************************/
64 static bool init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
67 /* times are stored as 32bit integer
68 take care on system with 64bit wide time_t
69 --SSS */
70 uint32 logon_time,
71 logoff_time,
72 kickoff_time,
73 pass_last_set_time,
74 pass_can_change_time,
75 pass_must_change_time;
76 char *username = NULL;
77 char *domain = NULL;
78 char *nt_username = NULL;
79 char *dir_drive = NULL;
80 char *unknown_str = NULL;
81 char *munged_dial = NULL;
82 char *fullname = NULL;
83 char *homedir = NULL;
84 char *logon_script = NULL;
85 char *profile_path = NULL;
86 char *acct_desc = NULL;
87 char *workstations = NULL;
88 uint32 username_len, domain_len, nt_username_len,
89 dir_drive_len, unknown_str_len, munged_dial_len,
90 fullname_len, homedir_len, logon_script_len,
91 profile_path_len, acct_desc_len, workstations_len;
93 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
94 uint16 acct_ctrl, logon_divs;
95 uint16 bad_password_count, logon_count;
96 uint8 *hours = NULL;
97 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
98 uint32 len = 0;
99 uint32 lm_pw_len, nt_pw_len, hourslen;
100 bool ret = True;
102 if(sampass == NULL || buf == NULL) {
103 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
104 return False;
107 /* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
109 /* unpack the buffer into variables */
110 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V0,
111 &logon_time, /* d */
112 &logoff_time, /* d */
113 &kickoff_time, /* d */
114 &pass_last_set_time, /* d */
115 &pass_can_change_time, /* d */
116 &pass_must_change_time, /* d */
117 &username_len, &username, /* B */
118 &domain_len, &domain, /* B */
119 &nt_username_len, &nt_username, /* B */
120 &fullname_len, &fullname, /* B */
121 &homedir_len, &homedir, /* B */
122 &dir_drive_len, &dir_drive, /* B */
123 &logon_script_len, &logon_script, /* B */
124 &profile_path_len, &profile_path, /* B */
125 &acct_desc_len, &acct_desc, /* B */
126 &workstations_len, &workstations, /* B */
127 &unknown_str_len, &unknown_str, /* B */
128 &munged_dial_len, &munged_dial, /* B */
129 &user_rid, /* d */
130 &group_rid, /* d */
131 &lm_pw_len, &lm_pw_ptr, /* B */
132 &nt_pw_len, &nt_pw_ptr, /* B */
133 &acct_ctrl, /* w */
134 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
135 &logon_divs, /* w */
136 &hours_len, /* d */
137 &hourslen, &hours, /* B */
138 &bad_password_count, /* w */
139 &logon_count, /* w */
140 &unknown_6); /* d */
142 if (len == (uint32) -1) {
143 ret = False;
144 goto done;
147 pdb_set_logon_time(sampass, logon_time, PDB_SET);
148 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
149 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
150 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
151 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
152 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
154 pdb_set_username(sampass, username, PDB_SET);
155 pdb_set_domain(sampass, domain, PDB_SET);
156 pdb_set_nt_username(sampass, nt_username, PDB_SET);
157 pdb_set_fullname(sampass, fullname, PDB_SET);
159 if (homedir) {
160 pdb_set_homedir(sampass, homedir, PDB_SET);
162 else {
163 pdb_set_homedir(sampass,
164 talloc_sub_basic(sampass, username, domain,
165 lp_logon_home()),
166 PDB_DEFAULT);
169 if (dir_drive)
170 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
171 else {
172 pdb_set_dir_drive(sampass,
173 talloc_sub_basic(sampass, username, domain,
174 lp_logon_drive()),
175 PDB_DEFAULT);
178 if (logon_script)
179 pdb_set_logon_script(sampass, logon_script, PDB_SET);
180 else {
181 pdb_set_logon_script(sampass,
182 talloc_sub_basic(sampass, username, domain,
183 lp_logon_script()),
184 PDB_DEFAULT);
187 if (profile_path) {
188 pdb_set_profile_path(sampass, profile_path, PDB_SET);
189 } else {
190 pdb_set_profile_path(sampass,
191 talloc_sub_basic(sampass, username, domain,
192 lp_logon_path()),
193 PDB_DEFAULT);
196 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
197 pdb_set_workstations(sampass, workstations, PDB_SET);
198 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
200 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
201 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
202 ret = False;
203 goto done;
207 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
208 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
209 ret = False;
210 goto done;
214 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
215 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
216 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
217 pdb_set_hours_len(sampass, hours_len, PDB_SET);
218 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
219 pdb_set_logon_count(sampass, logon_count, PDB_SET);
220 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
221 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
222 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
223 pdb_set_hours(sampass, hours, PDB_SET);
225 done:
227 SAFE_FREE(username);
228 SAFE_FREE(domain);
229 SAFE_FREE(nt_username);
230 SAFE_FREE(fullname);
231 SAFE_FREE(homedir);
232 SAFE_FREE(dir_drive);
233 SAFE_FREE(logon_script);
234 SAFE_FREE(profile_path);
235 SAFE_FREE(acct_desc);
236 SAFE_FREE(workstations);
237 SAFE_FREE(munged_dial);
238 SAFE_FREE(unknown_str);
239 SAFE_FREE(lm_pw_ptr);
240 SAFE_FREE(nt_pw_ptr);
241 SAFE_FREE(hours);
243 return ret;
246 /*********************************************************************
247 *********************************************************************/
249 static bool init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
252 /* times are stored as 32bit integer
253 take care on system with 64bit wide time_t
254 --SSS */
255 uint32 logon_time,
256 logoff_time,
257 kickoff_time,
258 bad_password_time,
259 pass_last_set_time,
260 pass_can_change_time,
261 pass_must_change_time;
262 char *username = NULL;
263 char *domain = NULL;
264 char *nt_username = NULL;
265 char *dir_drive = NULL;
266 char *unknown_str = NULL;
267 char *munged_dial = NULL;
268 char *fullname = NULL;
269 char *homedir = NULL;
270 char *logon_script = NULL;
271 char *profile_path = NULL;
272 char *acct_desc = NULL;
273 char *workstations = NULL;
274 uint32 username_len, domain_len, nt_username_len,
275 dir_drive_len, unknown_str_len, munged_dial_len,
276 fullname_len, homedir_len, logon_script_len,
277 profile_path_len, acct_desc_len, workstations_len;
279 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
280 uint16 acct_ctrl, logon_divs;
281 uint16 bad_password_count, logon_count;
282 uint8 *hours = NULL;
283 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
284 uint32 len = 0;
285 uint32 lm_pw_len, nt_pw_len, hourslen;
286 bool ret = True;
288 if(sampass == NULL || buf == NULL) {
289 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
290 return False;
293 /* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
295 /* unpack the buffer into variables */
296 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V1,
297 &logon_time, /* d */
298 &logoff_time, /* d */
299 &kickoff_time, /* d */
300 /* Change from V0 is addition of bad_password_time field. */
301 &bad_password_time, /* d */
302 &pass_last_set_time, /* d */
303 &pass_can_change_time, /* d */
304 &pass_must_change_time, /* d */
305 &username_len, &username, /* B */
306 &domain_len, &domain, /* B */
307 &nt_username_len, &nt_username, /* B */
308 &fullname_len, &fullname, /* B */
309 &homedir_len, &homedir, /* B */
310 &dir_drive_len, &dir_drive, /* B */
311 &logon_script_len, &logon_script, /* B */
312 &profile_path_len, &profile_path, /* B */
313 &acct_desc_len, &acct_desc, /* B */
314 &workstations_len, &workstations, /* B */
315 &unknown_str_len, &unknown_str, /* B */
316 &munged_dial_len, &munged_dial, /* B */
317 &user_rid, /* d */
318 &group_rid, /* d */
319 &lm_pw_len, &lm_pw_ptr, /* B */
320 &nt_pw_len, &nt_pw_ptr, /* B */
321 &acct_ctrl, /* w */
322 &remove_me, /* d */
323 &logon_divs, /* w */
324 &hours_len, /* d */
325 &hourslen, &hours, /* B */
326 &bad_password_count, /* w */
327 &logon_count, /* w */
328 &unknown_6); /* d */
330 if (len == (uint32) -1) {
331 ret = False;
332 goto done;
335 pdb_set_logon_time(sampass, logon_time, PDB_SET);
336 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
337 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
339 /* Change from V0 is addition of bad_password_time field. */
340 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
341 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
342 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
343 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
345 pdb_set_username(sampass, username, PDB_SET);
346 pdb_set_domain(sampass, domain, PDB_SET);
347 pdb_set_nt_username(sampass, nt_username, PDB_SET);
348 pdb_set_fullname(sampass, fullname, PDB_SET);
350 if (homedir) {
351 pdb_set_homedir(sampass, homedir, PDB_SET);
353 else {
354 pdb_set_homedir(sampass,
355 talloc_sub_basic(sampass, username, domain,
356 lp_logon_home()),
357 PDB_DEFAULT);
360 if (dir_drive)
361 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
362 else {
363 pdb_set_dir_drive(sampass,
364 talloc_sub_basic(sampass, username, domain,
365 lp_logon_drive()),
366 PDB_DEFAULT);
369 if (logon_script)
370 pdb_set_logon_script(sampass, logon_script, PDB_SET);
371 else {
372 pdb_set_logon_script(sampass,
373 talloc_sub_basic(sampass, username, domain,
374 lp_logon_script()),
375 PDB_DEFAULT);
378 if (profile_path) {
379 pdb_set_profile_path(sampass, profile_path, PDB_SET);
380 } else {
381 pdb_set_profile_path(sampass,
382 talloc_sub_basic(sampass, username, domain,
383 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 tmp_string;
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 (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( tmp_string, homedir );
543 if (expand_explicit) {
544 standard_sub_basic( username, domain, tmp_string,
545 sizeof(tmp_string) );
547 pdb_set_homedir(sampass, tmp_string, PDB_SET);
549 else {
550 pdb_set_homedir(sampass,
551 talloc_sub_basic(sampass, username, domain,
552 lp_logon_home()),
553 PDB_DEFAULT);
556 if (dir_drive)
557 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
558 else
559 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
561 if (logon_script) {
562 fstrcpy( tmp_string, logon_script );
563 if (expand_explicit) {
564 standard_sub_basic( username, domain, tmp_string,
565 sizeof(tmp_string) );
567 pdb_set_logon_script(sampass, tmp_string, PDB_SET);
569 else {
570 pdb_set_logon_script(sampass,
571 talloc_sub_basic(sampass, username, domain,
572 lp_logon_script()),
573 PDB_DEFAULT);
576 if (profile_path) {
577 fstrcpy( tmp_string, profile_path );
578 if (expand_explicit) {
579 standard_sub_basic( username, domain, tmp_string,
580 sizeof(tmp_string) );
582 pdb_set_profile_path(sampass, tmp_string, PDB_SET);
584 else {
585 pdb_set_profile_path(sampass,
586 talloc_sub_basic(sampass, username, domain,
587 lp_logon_path()),
588 PDB_DEFAULT);
591 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
592 pdb_set_workstations(sampass, workstations, PDB_SET);
593 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
595 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
596 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
597 ret = False;
598 goto done;
602 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
603 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
604 ret = False;
605 goto done;
609 /* Change from V1 is addition of password history field. */
610 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
611 if (pwHistLen) {
612 uint8 *pw_hist = SMB_MALLOC_ARRAY(uint8, pwHistLen * PW_HISTORY_ENTRY_LEN);
613 if (!pw_hist) {
614 ret = False;
615 goto done;
617 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
618 if (nt_pw_hist_ptr && nt_pw_hist_len) {
619 int i;
620 SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
621 nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
622 for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
623 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
624 &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
625 PW_HISTORY_ENTRY_LEN);
628 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
629 SAFE_FREE(pw_hist);
630 ret = False;
631 goto done;
633 SAFE_FREE(pw_hist);
634 } else {
635 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
638 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
639 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
640 pdb_set_hours_len(sampass, hours_len, PDB_SET);
641 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
642 pdb_set_logon_count(sampass, logon_count, PDB_SET);
643 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
644 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
645 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
646 pdb_set_hours(sampass, hours, PDB_SET);
648 done:
650 SAFE_FREE(username);
651 SAFE_FREE(domain);
652 SAFE_FREE(nt_username);
653 SAFE_FREE(fullname);
654 SAFE_FREE(homedir);
655 SAFE_FREE(dir_drive);
656 SAFE_FREE(logon_script);
657 SAFE_FREE(profile_path);
658 SAFE_FREE(acct_desc);
659 SAFE_FREE(workstations);
660 SAFE_FREE(munged_dial);
661 SAFE_FREE(unknown_str);
662 SAFE_FREE(lm_pw_ptr);
663 SAFE_FREE(nt_pw_ptr);
664 SAFE_FREE(nt_pw_hist_ptr);
665 SAFE_FREE(hours);
667 return ret;
671 /**********************************************************************
672 Intialize a struct samu struct from a BYTE buffer of size len
673 *********************************************************************/
675 static bool init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
677 return init_sam_from_buffer_v3(sampass, buf, buflen);
680 /**********************************************************************
681 Intialize a BYTE buffer from a struct samu struct
682 *********************************************************************/
684 static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, bool size_only)
686 return init_buffer_from_sam_v3(buf, sampass, size_only);
689 /**********************************************************************
690 Intialize a BYTE buffer from a struct samu struct
691 *********************************************************************/
693 struct tdbsam_convert_state {
694 int32_t from;
695 bool success;
698 static int tdbsam_convert_one(struct db_record *rec, void *priv)
700 struct tdbsam_convert_state *state =
701 (struct tdbsam_convert_state *)priv;
702 struct samu *user;
703 TDB_DATA data;
704 NTSTATUS status;
705 bool ret;
707 if (rec->key.dsize < USERPREFIX_LEN) {
708 return 0;
710 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
711 return 0;
714 user = samu_new(talloc_tos());
715 if (user == NULL) {
716 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
717 state->success = false;
718 return -1;
721 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
722 "(version:%d)\n", rec->key.dptr, state->from));
724 switch (state->from) {
725 case 0:
726 ret = init_sam_from_buffer_v0(user, (uint8 *)rec->value.dptr,
727 rec->value.dsize);
728 break;
729 case 1:
730 ret = init_sam_from_buffer_v1(user, (uint8 *)rec->value.dptr,
731 rec->value.dsize);
732 break;
733 case 2:
734 ret = init_sam_from_buffer_v2(user, (uint8 *)rec->value.dptr,
735 rec->value.dsize);
736 break;
737 case 3:
738 ret = init_sam_from_buffer_v3(user, (uint8 *)rec->value.dptr,
739 rec->value.dsize);
740 break;
741 default:
742 /* unknown tdbsam version */
743 ret = False;
745 if (!ret) {
746 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
747 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
748 state->from));
749 TALLOC_FREE(user);
750 state->success = false;
751 return -1;
754 data.dsize = init_buffer_from_sam(&data.dptr, user, false);
755 TALLOC_FREE(user);
757 if (data.dsize == -1) {
758 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
759 "the new format\n"));
760 state->success = false;
761 return -1;
764 status = rec->store(rec, data, TDB_MODIFY);
765 if (!NT_STATUS_IS_OK(status)) {
766 DEBUG(0, ("Could not store the new record: %s\n",
767 nt_errstr(status)));
768 state->success = false;
769 return -1;
772 return 0;
775 static bool tdbsam_convert(struct db_context *db, int32 from)
777 struct tdbsam_convert_state state;
778 int ret;
780 state.from = from;
781 state.success = true;
783 if (db->transaction_start(db) != 0) {
784 DEBUG(0, ("Could not start transaction\n"));
785 return false;
788 ret = db->traverse(db, tdbsam_convert_one, &state);
789 if (ret < 0) {
790 DEBUG(0, ("traverse failed\n"));
791 goto cancel;
794 if (!state.success) {
795 DEBUG(0, ("Converting records failed\n"));
796 goto cancel;
799 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
800 TDBSAM_VERSION) != 0) {
801 DEBUG(0, ("Could not store tdbsam version\n"));
802 goto cancel;
805 if (db->transaction_commit(db) != 0) {
806 DEBUG(0, ("Could not commit transaction\n"));
807 return false;
810 return true;
812 cancel:
813 if (db->transaction_cancel(db) != 0) {
814 smb_panic("transaction_cancel failed");
817 return false;
820 /*********************************************************************
821 Open the tdbsam file based on the absolute path specified.
822 Uses a reference count to allow multiple open calls.
823 *********************************************************************/
825 static bool tdbsam_open( const char *name )
827 int32 version;
829 /* check if we are already open */
831 if ( db_sam ) {
832 return true;
835 /* Try to open tdb passwd. Create a new one if necessary */
837 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
838 if (db_sam == NULL) {
839 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
840 "[%s]\n", name));
841 return false;
844 /* Check the version */
845 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
846 if (version == -1) {
847 version = 0; /* Version not found, assume version 0 */
850 /* Compare the version */
851 if (version > TDBSAM_VERSION) {
852 /* Version more recent than the latest known */
853 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
854 TALLOC_FREE(db_sam);
855 return false;
858 if ( version < TDBSAM_VERSION ) {
859 DEBUG(1, ("tdbsam_open: Converting version %d database to "
860 "version %d.\n", version, TDBSAM_VERSION));
862 if ( !tdbsam_convert(db_sam, version) ) {
863 DEBUG(0, ("tdbsam_open: Error when trying to convert "
864 "tdbsam [%s]\n",name));
865 TALLOC_FREE(db_sam);
866 return false;
869 DEBUG(3, ("TDBSAM converted successfully.\n"));
872 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
874 return true;
877 /******************************************************************
878 Lookup a name in the SAM TDB
879 ******************************************************************/
881 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
882 struct samu *user, const char *sname)
884 TDB_DATA data;
885 fstring keystr;
886 fstring name;
888 if ( !user ) {
889 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
890 return NT_STATUS_NO_MEMORY;
893 /* Data is stored in all lower-case */
894 fstrcpy(name, sname);
895 strlower_m(name);
897 /* set search key */
898 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
900 /* open the database */
902 if ( !tdbsam_open( tdbsam_filename ) ) {
903 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
904 return NT_STATUS_ACCESS_DENIED;
907 /* get the record */
909 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
910 if (!data.dptr) {
911 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
912 DEBUGADD(5, (" Key: %s\n", keystr));
913 return NT_STATUS_NO_SUCH_USER;
916 /* unpack the buffer */
918 if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
919 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
920 SAFE_FREE(data.dptr);
921 return NT_STATUS_NO_MEMORY;
924 /* success */
926 TALLOC_FREE(data.dptr);
928 return NT_STATUS_OK;
931 /***************************************************************************
932 Search by rid
933 **************************************************************************/
935 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
936 struct samu *user, uint32 rid)
938 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
939 TDB_DATA data;
940 fstring keystr;
941 fstring name;
943 if ( !user ) {
944 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
945 return nt_status;
948 /* set search key */
950 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
952 /* open the database */
954 if ( !tdbsam_open( tdbsam_filename ) ) {
955 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
956 return NT_STATUS_ACCESS_DENIED;
959 /* get the record */
961 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
962 if (!data.dptr) {
963 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
964 return NT_STATUS_UNSUCCESSFUL;
967 fstrcpy(name, (const char *)data.dptr);
968 TALLOC_FREE(data.dptr);
970 return tdbsam_getsampwnam (my_methods, user, name);
973 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
974 struct samu * user, const DOM_SID *sid)
976 uint32 rid;
978 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
979 return NT_STATUS_UNSUCCESSFUL;
981 return tdbsam_getsampwrid(my_methods, user, rid);
984 static bool tdb_delete_samacct_only( struct samu *sam_pass )
986 fstring keystr;
987 fstring name;
988 NTSTATUS status;
990 fstrcpy(name, pdb_get_username(sam_pass));
991 strlower_m(name);
993 /* set the search key */
995 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
997 /* it's outaa here! 8^) */
999 status = dbwrap_delete_bystring(db_sam, keystr);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(5, ("Error deleting entry from tdb passwd "
1002 "database: %s!\n", nt_errstr(status)));
1003 return false;
1006 return true;
1009 /***************************************************************************
1010 Delete a struct samu records for the username and RID key
1011 ****************************************************************************/
1013 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
1014 struct samu *sam_pass)
1016 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1017 fstring keystr;
1018 uint32 rid;
1019 fstring name;
1021 /* open the database */
1023 if ( !tdbsam_open( tdbsam_filename ) ) {
1024 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1025 tdbsam_filename));
1026 return NT_STATUS_ACCESS_DENIED;
1029 fstrcpy(name, pdb_get_username(sam_pass));
1030 strlower_m(name);
1032 /* set the search key */
1034 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1036 rid = pdb_get_user_rid(sam_pass);
1038 /* it's outaa here! 8^) */
1040 if (db_sam->transaction_start(db_sam) != 0) {
1041 DEBUG(0, ("Could not start transaction\n"));
1042 return NT_STATUS_UNSUCCESSFUL;
1045 nt_status = dbwrap_delete_bystring(db_sam, keystr);
1046 if (!NT_STATUS_IS_OK(nt_status)) {
1047 DEBUG(5, ("Error deleting entry from tdb passwd "
1048 "database: %s!\n", nt_errstr(nt_status)));
1049 goto cancel;
1052 /* set the search key */
1054 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1056 /* it's outaa here! 8^) */
1058 nt_status = dbwrap_delete_bystring(db_sam, keystr);
1059 if (!NT_STATUS_IS_OK(nt_status)) {
1060 DEBUG(5, ("Error deleting entry from tdb rid "
1061 "database: %s!\n", nt_errstr(nt_status)));
1062 goto cancel;
1065 if (db_sam->transaction_commit(db_sam) != 0) {
1066 DEBUG(0, ("Could not commit transaction\n"));
1067 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1070 return NT_STATUS_OK;
1072 cancel:
1073 if (db_sam->transaction_cancel(db_sam) != 0) {
1074 smb_panic("transaction_cancel failed");
1077 return nt_status;
1081 /***************************************************************************
1082 Update the TDB SAM account record only
1083 Assumes that the tdbsam is already open
1084 ****************************************************************************/
1085 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
1087 TDB_DATA data;
1088 uint8 *buf = NULL;
1089 fstring keystr;
1090 fstring name;
1091 bool ret = false;
1092 NTSTATUS status;
1094 /* copy the struct samu struct into a BYTE buffer for storage */
1096 if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1097 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1098 goto done;
1100 data.dptr = buf;
1102 fstrcpy(name, pdb_get_username(newpwd));
1103 strlower_m(name);
1105 DEBUG(5, ("Storing %saccount %s with RID %d\n",
1106 flag == TDB_INSERT ? "(new) " : "", name,
1107 pdb_get_user_rid(newpwd)));
1109 /* setup the USER index key */
1110 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1112 /* add the account */
1114 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 DEBUG(0, ("Unable to modify passwd TDB: %s!",
1117 nt_errstr(status)));
1118 goto done;
1121 ret = true;
1123 done:
1124 /* cleanup */
1125 SAFE_FREE(buf);
1126 return ret;
1129 /***************************************************************************
1130 Update the TDB SAM RID record only
1131 Assumes that the tdbsam is already open
1132 ****************************************************************************/
1133 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
1135 TDB_DATA data;
1136 fstring keystr;
1137 fstring name;
1138 NTSTATUS status;
1140 fstrcpy(name, pdb_get_username(newpwd));
1141 strlower_m(name);
1143 /* setup RID data */
1144 data = string_term_tdb_data(name);
1146 /* setup the RID index key */
1147 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
1148 pdb_get_user_rid(newpwd));
1150 /* add the reference */
1151 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
1154 nt_errstr(status)));
1155 return false;
1158 return true;
1162 /***************************************************************************
1163 Update the TDB SAM
1164 ****************************************************************************/
1166 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
1167 int flag)
1169 if (!pdb_get_user_rid(newpwd)) {
1170 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
1171 pdb_get_username(newpwd)));
1172 return False;
1175 /* open the database */
1177 if ( !tdbsam_open( tdbsam_filename ) ) {
1178 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1179 return False;
1182 if (db_sam->transaction_start(db_sam) != 0) {
1183 DEBUG(0, ("Could not start transaction\n"));
1184 return false;
1187 if (!tdb_update_samacct_only(newpwd, flag)
1188 || !tdb_update_ridrec_only(newpwd, flag)) {
1189 goto cancel;
1192 if (db_sam->transaction_commit(db_sam) != 0) {
1193 DEBUG(0, ("Could not commit transaction\n"));
1194 return false;
1197 return true;
1199 cancel:
1200 if (db_sam->transaction_cancel(db_sam) != 0) {
1201 smb_panic("transaction_cancel failed");
1203 return false;
1206 /***************************************************************************
1207 Modifies an existing struct samu
1208 ****************************************************************************/
1210 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1212 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1213 return NT_STATUS_UNSUCCESSFUL;
1215 return NT_STATUS_OK;
1218 /***************************************************************************
1219 Adds an existing struct samu
1220 ****************************************************************************/
1222 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1224 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1225 return NT_STATUS_UNSUCCESSFUL;
1227 return NT_STATUS_OK;
1230 /***************************************************************************
1231 Renames a struct samu
1232 - check for the posix user/rename user script
1233 - Add and lock the new user record
1234 - rename the posix user
1235 - rewrite the rid->username record
1236 - delete the old user
1237 - unlock the new user record
1238 ***************************************************************************/
1239 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1240 struct samu *old_acct,
1241 const char *newname)
1243 struct samu *new_acct = NULL;
1244 char *rename_script = NULL;
1245 int rename_ret;
1246 fstring oldname_lower;
1247 fstring newname_lower;
1249 /* can't do anything without an external script */
1251 if ( !(new_acct = samu_new( talloc_tos() )) ) {
1252 return NT_STATUS_NO_MEMORY;
1255 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
1256 if (!rename_script) {
1257 TALLOC_FREE(new_acct);
1258 return NT_STATUS_NO_MEMORY;
1260 if (!*rename_script) {
1261 TALLOC_FREE(new_acct);
1262 return NT_STATUS_ACCESS_DENIED;
1265 if ( !pdb_copy_sam_account(new_acct, old_acct)
1266 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1268 TALLOC_FREE(new_acct);
1269 return NT_STATUS_NO_MEMORY;
1272 /* open the database */
1273 if ( !tdbsam_open( tdbsam_filename ) ) {
1274 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1275 tdbsam_filename));
1276 TALLOC_FREE(new_acct);
1277 return NT_STATUS_ACCESS_DENIED;
1280 if (db_sam->transaction_start(db_sam) != 0) {
1281 DEBUG(0, ("Could not start transaction\n"));
1282 TALLOC_FREE(new_acct);
1283 return NT_STATUS_ACCESS_DENIED;
1287 /* add the new account and lock it */
1288 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1289 goto cancel;
1292 /* Rename the posix user. Follow the semantics of _samr_create_user()
1293 so that we lower case the posix name but preserve the case in passdb */
1295 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1296 strlower_m( oldname_lower );
1298 fstrcpy( newname_lower, newname );
1299 strlower_m( newname_lower );
1301 rename_script = talloc_string_sub2(new_acct,
1302 rename_script,
1303 "%unew",
1304 newname_lower,
1305 true,
1306 false,
1307 true);
1308 if (!rename_script) {
1309 goto cancel;
1311 rename_script = talloc_string_sub2(new_acct,
1312 rename_script,
1313 "%uold",
1314 oldname_lower,
1315 true,
1316 false,
1317 true);
1318 if (!rename_script) {
1319 goto cancel;
1321 rename_ret = smbrun(rename_script, NULL);
1323 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1324 rename_script, rename_ret));
1326 if (rename_ret != 0) {
1327 goto cancel;
1330 smb_nscd_flush_user_cache();
1332 /* rewrite the rid->username record */
1334 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1335 goto cancel;
1338 tdb_delete_samacct_only( old_acct );
1340 if (db_sam->transaction_commit(db_sam) != 0) {
1342 * Ok, we're screwed. We've changed the posix account, but
1343 * could not adapt passdb.tdb. Shall we change the posix
1344 * account back?
1346 DEBUG(0, ("transaction_commit failed\n"));
1347 TALLOC_FREE(new_acct);
1348 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1351 TALLOC_FREE(new_acct );
1352 return NT_STATUS_OK;
1354 cancel:
1355 if (db_sam->transaction_cancel(db_sam) != 0) {
1356 smb_panic("transaction_cancel failed");
1359 TALLOC_FREE(new_acct);
1361 return NT_STATUS_ACCESS_DENIED;
1364 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
1366 return False;
1370 * Historically, winbind was responsible for allocating RIDs, so the next RID
1371 * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1372 * but for compatibility reasons we still keep the the next RID counter in
1373 * winbindd_idmap.tdb.
1376 /*****************************************************************************
1377 Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1378 sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1379 winbind completely and store the RID counter in passdb.tdb.
1381 Dont' fully initialize with the HWM values, if it's new, we're only
1382 interested in the RID counter.
1383 *****************************************************************************/
1385 static bool init_idmap_tdb(TDB_CONTEXT *tdb)
1387 int32 version;
1389 if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1390 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1391 return False;
1394 version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1396 if (version == -1) {
1397 /* No key found, must be a new db */
1398 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1399 IDMAP_VERSION) != 0) {
1400 DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1401 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1402 return False;
1404 version = IDMAP_VERSION;
1407 if (version != IDMAP_VERSION) {
1408 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1409 "start winbind once\n", IDMAP_VERSION, version));
1410 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1411 return False;
1414 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1415 return True;
1418 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1420 TDB_CONTEXT *tdb;
1421 uint32 rid;
1422 bool ret = False;
1424 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
1425 TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1427 if (tdb == NULL) {
1428 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1429 goto done;
1432 if (!init_idmap_tdb(tdb)) {
1433 DEBUG(1, ("Could not init idmap\n"));
1434 goto done;
1437 rid = BASE_RID; /* Default if not set */
1439 if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1440 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1441 goto done;
1444 *prid = rid;
1445 ret = True;
1447 done:
1448 if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1449 smb_panic("tdb_close(idmap_tdb) failed");
1452 return ret;
1455 struct tdbsam_search_state {
1456 struct pdb_methods *methods;
1457 uint32_t acct_flags;
1459 uint32_t *rids;
1460 uint32_t num_rids;
1461 ssize_t array_size;
1462 uint32_t current;
1465 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1467 struct tdbsam_search_state *state = talloc_get_type_abort(
1468 private_data, struct tdbsam_search_state);
1469 size_t prefixlen = strlen(RIDPREFIX);
1470 uint32 rid;
1472 if ((rec->key.dsize < prefixlen)
1473 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1474 return 0;
1477 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1479 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1480 &state->array_size);
1482 return 0;
1485 static void tdbsam_search_end(struct pdb_search *search)
1487 struct tdbsam_search_state *state = talloc_get_type_abort(
1488 search->private_data, struct tdbsam_search_state);
1489 TALLOC_FREE(state);
1492 static bool tdbsam_search_next_entry(struct pdb_search *search,
1493 struct samr_displayentry *entry)
1495 struct tdbsam_search_state *state = talloc_get_type_abort(
1496 search->private_data, struct tdbsam_search_state);
1497 struct samu *user = NULL;
1498 NTSTATUS status;
1499 uint32_t rid;
1501 again:
1502 TALLOC_FREE(user);
1503 user = samu_new(talloc_tos());
1504 if (user == NULL) {
1505 DEBUG(0, ("samu_new failed\n"));
1506 return false;
1509 if (state->current == state->num_rids) {
1510 return false;
1513 rid = state->rids[state->current++];
1515 status = tdbsam_getsampwrid(state->methods, user, rid);
1517 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1519 * Someone has deleted that user since we listed the RIDs
1521 goto again;
1524 if (!NT_STATUS_IS_OK(status)) {
1525 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1526 nt_errstr(status)));
1527 TALLOC_FREE(user);
1528 return false;
1531 if ((state->acct_flags != 0) &&
1532 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1533 goto again;
1536 entry->acct_flags = pdb_get_acct_ctrl(user);
1537 entry->rid = rid;
1538 entry->account_name = talloc_strdup(
1539 search->mem_ctx, pdb_get_username(user));
1540 entry->fullname = talloc_strdup(
1541 search->mem_ctx, pdb_get_fullname(user));
1542 entry->description = talloc_strdup(
1543 search->mem_ctx, pdb_get_acct_desc(user));
1545 TALLOC_FREE(user);
1547 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1548 || (entry->description == NULL)) {
1549 DEBUG(0, ("talloc_strdup failed\n"));
1550 return false;
1553 return true;
1556 static bool tdbsam_search_users(struct pdb_methods *methods,
1557 struct pdb_search *search,
1558 uint32 acct_flags)
1560 struct tdbsam_search_state *state;
1562 if (!tdbsam_open(tdbsam_filename)) {
1563 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1564 tdbsam_filename));
1565 return false;
1568 state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
1569 if (state == NULL) {
1570 DEBUG(0, ("talloc failed\n"));
1571 return false;
1573 state->acct_flags = acct_flags;
1574 state->methods = methods;
1576 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1578 search->private_data = state;
1579 search->next_entry = tdbsam_search_next_entry;
1580 search->search_end = tdbsam_search_end;
1582 return true;
1585 /*********************************************************************
1586 Initialize the tdb sam backend. Setup the dispath table of methods,
1587 open the tdb, etc...
1588 *********************************************************************/
1590 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1592 NTSTATUS nt_status;
1593 char *tdbfile = NULL;
1594 const char *pfile = location;
1596 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1597 return nt_status;
1600 (*pdb_method)->name = "tdbsam";
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;
1608 (*pdb_method)->search_users = tdbsam_search_users;
1610 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1611 (*pdb_method)->new_rid = tdbsam_new_rid;
1613 /* save the path for later */
1615 if (!location) {
1616 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1617 PASSDB_FILE_NAME) < 0) {
1618 return NT_STATUS_NO_MEMORY;
1620 pfile = tdbfile;
1622 tdbsam_filename = SMB_STRDUP(pfile);
1623 if (!tdbsam_filename) {
1624 return NT_STATUS_NO_MEMORY;
1626 SAFE_FREE(tdbfile);
1628 /* no private data */
1630 (*pdb_method)->private_data = NULL;
1631 (*pdb_method)->free_private_data = NULL;
1633 return NT_STATUS_OK;
1636 NTSTATUS pdb_tdbsam_init(void)
1638 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);