Do not start a transaction this way.
[Samba.git] / source3 / passdb / pdb_tdb.c
blobeab91100fdd08ee67878f31f6ab104d8253e0b6e
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 4 /* 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_"
47 #define NEXT_RID_STRING "NEXT_RID"
49 /* GLOBAL TDB SAM CONTEXT */
51 static struct db_context *db_sam;
52 static char *tdbsam_filename;
54 struct tdbsam_convert_state {
55 int32_t from;
56 bool success;
59 static int tdbsam_convert_one(struct db_record *rec, void *priv)
61 struct tdbsam_convert_state *state =
62 (struct tdbsam_convert_state *)priv;
63 struct samu *user;
64 TDB_DATA data;
65 NTSTATUS status;
66 bool ret;
68 if (rec->key.dsize < USERPREFIX_LEN) {
69 return 0;
71 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
72 return 0;
75 user = samu_new(talloc_tos());
76 if (user == NULL) {
77 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
78 state->success = false;
79 return -1;
82 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
83 "(version:%d)\n", rec->key.dptr, state->from));
85 switch (state->from) {
86 case 0:
87 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
88 (uint8 *)rec->value.dptr,
89 rec->value.dsize);
90 break;
91 case 1:
92 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
93 (uint8 *)rec->value.dptr,
94 rec->value.dsize);
95 break;
96 case 2:
97 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
98 (uint8 *)rec->value.dptr,
99 rec->value.dsize);
100 break;
101 case 3:
102 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
103 (uint8 *)rec->value.dptr,
104 rec->value.dsize);
105 case 4:
106 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
107 (uint8 *)rec->value.dptr,
108 rec->value.dsize);
109 break;
110 default:
111 /* unknown tdbsam version */
112 ret = False;
114 if (!ret) {
115 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
116 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
117 state->from));
118 TALLOC_FREE(user);
119 state->success = false;
120 return -1;
123 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
124 TALLOC_FREE(user);
126 if (data.dsize == -1) {
127 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
128 "the new format\n"));
129 state->success = false;
130 return -1;
133 status = rec->store(rec, data, TDB_MODIFY);
134 if (!NT_STATUS_IS_OK(status)) {
135 DEBUG(0, ("Could not store the new record: %s\n",
136 nt_errstr(status)));
137 state->success = false;
138 return -1;
141 return 0;
144 static bool tdbsam_upgrade_next_rid(struct db_context *db)
146 TDB_CONTEXT *tdb;
147 uint32 rid;
148 bool ok = false;
150 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
151 if (ok) {
152 return true;
155 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
156 TDB_DEFAULT, O_RDONLY, 0644);
158 if (tdb) {
159 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
160 if (!ok) {
161 rid = BASE_RID;
163 tdb_close(tdb);
164 } else {
165 rid = BASE_RID;
168 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
169 return false;
172 return true;
175 static bool tdbsam_convert(struct db_context *db, int32 from)
177 struct tdbsam_convert_state state;
178 int ret;
180 state.from = from;
181 state.success = true;
183 if (db->transaction_start(db) != 0) {
184 DEBUG(0, ("Could not start transaction\n"));
185 return false;
188 if (!tdbsam_upgrade_next_rid(db)) {
189 DEBUG(0, ("tdbsam_upgrade_next_rid failed\n"));
190 goto cancel;
193 ret = db->traverse(db, tdbsam_convert_one, &state);
194 if (ret < 0) {
195 DEBUG(0, ("traverse failed\n"));
196 goto cancel;
199 if (!state.success) {
200 DEBUG(0, ("Converting records failed\n"));
201 goto cancel;
204 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
205 TDBSAM_VERSION) != 0) {
206 DEBUG(0, ("Could not store tdbsam version\n"));
207 goto cancel;
210 if (db->transaction_commit(db) != 0) {
211 DEBUG(0, ("Could not commit transaction\n"));
212 return false;
215 return true;
217 cancel:
218 if (db->transaction_cancel(db) != 0) {
219 smb_panic("transaction_cancel failed");
222 return false;
225 /*********************************************************************
226 Open the tdbsam file based on the absolute path specified.
227 Uses a reference count to allow multiple open calls.
228 *********************************************************************/
230 static bool tdbsam_open( const char *name )
232 int32 version;
234 /* check if we are already open */
236 if ( db_sam ) {
237 return true;
240 /* Try to open tdb passwd. Create a new one if necessary */
242 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
243 if (db_sam == NULL) {
244 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
245 "[%s]\n", name));
246 return false;
249 /* Check the version */
250 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
251 if (version == -1) {
252 version = 0; /* Version not found, assume version 0 */
255 /* Compare the version */
256 if (version > TDBSAM_VERSION) {
257 /* Version more recent than the latest known */
258 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
259 TALLOC_FREE(db_sam);
260 return false;
263 if ( version < TDBSAM_VERSION ) {
264 DEBUG(1, ("tdbsam_open: Converting version %d database to "
265 "version %d.\n", version, TDBSAM_VERSION));
267 if ( !tdbsam_convert(db_sam, version) ) {
268 DEBUG(0, ("tdbsam_open: Error when trying to convert "
269 "tdbsam [%s]\n",name));
270 TALLOC_FREE(db_sam);
271 return false;
274 DEBUG(3, ("TDBSAM converted successfully.\n"));
277 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
279 return true;
282 /******************************************************************
283 Lookup a name in the SAM TDB
284 ******************************************************************/
286 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
287 struct samu *user, const char *sname)
289 TDB_DATA data;
290 fstring keystr;
291 fstring name;
293 if ( !user ) {
294 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
295 return NT_STATUS_NO_MEMORY;
298 /* Data is stored in all lower-case */
299 fstrcpy(name, sname);
300 strlower_m(name);
302 /* set search key */
303 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
305 /* open the database */
307 if ( !tdbsam_open( tdbsam_filename ) ) {
308 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
309 return NT_STATUS_ACCESS_DENIED;
312 /* get the record */
314 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
315 if (!data.dptr) {
316 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
317 DEBUGADD(5, (" Key: %s\n", keystr));
318 return NT_STATUS_NO_SUCH_USER;
321 /* unpack the buffer */
323 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
324 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
325 SAFE_FREE(data.dptr);
326 return NT_STATUS_NO_MEMORY;
329 /* success */
331 TALLOC_FREE(data.dptr);
333 return NT_STATUS_OK;
336 /***************************************************************************
337 Search by rid
338 **************************************************************************/
340 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
341 struct samu *user, uint32 rid)
343 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
344 TDB_DATA data;
345 fstring keystr;
346 fstring name;
348 if ( !user ) {
349 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
350 return nt_status;
353 /* set search key */
355 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
357 /* open the database */
359 if ( !tdbsam_open( tdbsam_filename ) ) {
360 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
361 return NT_STATUS_ACCESS_DENIED;
364 /* get the record */
366 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
367 if (!data.dptr) {
368 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
369 return NT_STATUS_UNSUCCESSFUL;
372 fstrcpy(name, (const char *)data.dptr);
373 TALLOC_FREE(data.dptr);
375 return tdbsam_getsampwnam (my_methods, user, name);
378 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
379 struct samu * user, const DOM_SID *sid)
381 uint32 rid;
383 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
384 return NT_STATUS_UNSUCCESSFUL;
386 return tdbsam_getsampwrid(my_methods, user, rid);
389 static bool tdb_delete_samacct_only( struct samu *sam_pass )
391 fstring keystr;
392 fstring name;
393 NTSTATUS status;
395 fstrcpy(name, pdb_get_username(sam_pass));
396 strlower_m(name);
398 /* set the search key */
400 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
402 /* it's outaa here! 8^) */
404 status = dbwrap_delete_bystring(db_sam, keystr);
405 if (!NT_STATUS_IS_OK(status)) {
406 DEBUG(5, ("Error deleting entry from tdb passwd "
407 "database: %s!\n", nt_errstr(status)));
408 return false;
411 return true;
414 /***************************************************************************
415 Delete a struct samu records for the username and RID key
416 ****************************************************************************/
418 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
419 struct samu *sam_pass)
421 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
422 fstring keystr;
423 uint32 rid;
424 fstring name;
426 /* open the database */
428 if ( !tdbsam_open( tdbsam_filename ) ) {
429 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
430 tdbsam_filename));
431 return NT_STATUS_ACCESS_DENIED;
434 fstrcpy(name, pdb_get_username(sam_pass));
435 strlower_m(name);
437 /* set the search key */
439 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
441 rid = pdb_get_user_rid(sam_pass);
443 /* it's outaa here! 8^) */
445 if (db_sam->transaction_start(db_sam) != 0) {
446 DEBUG(0, ("Could not start transaction\n"));
447 return NT_STATUS_UNSUCCESSFUL;
450 nt_status = dbwrap_delete_bystring(db_sam, keystr);
451 if (!NT_STATUS_IS_OK(nt_status)) {
452 DEBUG(5, ("Error deleting entry from tdb passwd "
453 "database: %s!\n", nt_errstr(nt_status)));
454 goto cancel;
457 /* set the search key */
459 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
461 /* it's outaa here! 8^) */
463 nt_status = dbwrap_delete_bystring(db_sam, keystr);
464 if (!NT_STATUS_IS_OK(nt_status)) {
465 DEBUG(5, ("Error deleting entry from tdb rid "
466 "database: %s!\n", nt_errstr(nt_status)));
467 goto cancel;
470 if (db_sam->transaction_commit(db_sam) != 0) {
471 DEBUG(0, ("Could not commit transaction\n"));
472 return NT_STATUS_INTERNAL_DB_CORRUPTION;
475 return NT_STATUS_OK;
477 cancel:
478 if (db_sam->transaction_cancel(db_sam) != 0) {
479 smb_panic("transaction_cancel failed");
482 return nt_status;
486 /***************************************************************************
487 Update the TDB SAM account record only
488 Assumes that the tdbsam is already open
489 ****************************************************************************/
490 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
492 TDB_DATA data;
493 uint8 *buf = NULL;
494 fstring keystr;
495 fstring name;
496 bool ret = false;
497 NTSTATUS status;
499 /* copy the struct samu struct into a BYTE buffer for storage */
501 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
502 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
503 goto done;
505 data.dptr = buf;
507 fstrcpy(name, pdb_get_username(newpwd));
508 strlower_m(name);
510 DEBUG(5, ("Storing %saccount %s with RID %d\n",
511 flag == TDB_INSERT ? "(new) " : "", name,
512 pdb_get_user_rid(newpwd)));
514 /* setup the USER index key */
515 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
517 /* add the account */
519 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
520 if (!NT_STATUS_IS_OK(status)) {
521 DEBUG(0, ("Unable to modify passwd TDB: %s!",
522 nt_errstr(status)));
523 goto done;
526 ret = true;
528 done:
529 /* cleanup */
530 SAFE_FREE(buf);
531 return ret;
534 /***************************************************************************
535 Update the TDB SAM RID record only
536 Assumes that the tdbsam is already open
537 ****************************************************************************/
538 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
540 TDB_DATA data;
541 fstring keystr;
542 fstring name;
543 NTSTATUS status;
545 fstrcpy(name, pdb_get_username(newpwd));
546 strlower_m(name);
548 /* setup RID data */
549 data = string_term_tdb_data(name);
551 /* setup the RID index key */
552 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
553 pdb_get_user_rid(newpwd));
555 /* add the reference */
556 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
557 if (!NT_STATUS_IS_OK(status)) {
558 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
559 nt_errstr(status)));
560 return false;
563 return true;
567 /***************************************************************************
568 Update the TDB SAM
569 ****************************************************************************/
571 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
572 int flag)
574 if (!pdb_get_user_rid(newpwd)) {
575 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
576 pdb_get_username(newpwd)));
577 return False;
580 /* open the database */
582 if ( !tdbsam_open( tdbsam_filename ) ) {
583 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
584 return False;
587 if (db_sam->transaction_start(db_sam) != 0) {
588 DEBUG(0, ("Could not start transaction\n"));
589 return false;
592 if (!tdb_update_samacct_only(newpwd, flag)
593 || !tdb_update_ridrec_only(newpwd, flag)) {
594 goto cancel;
597 if (db_sam->transaction_commit(db_sam) != 0) {
598 DEBUG(0, ("Could not commit transaction\n"));
599 return false;
602 return true;
604 cancel:
605 if (db_sam->transaction_cancel(db_sam) != 0) {
606 smb_panic("transaction_cancel failed");
608 return false;
611 /***************************************************************************
612 Modifies an existing struct samu
613 ****************************************************************************/
615 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
617 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
618 return NT_STATUS_UNSUCCESSFUL;
620 return NT_STATUS_OK;
623 /***************************************************************************
624 Adds an existing struct samu
625 ****************************************************************************/
627 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
629 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
630 return NT_STATUS_UNSUCCESSFUL;
632 return NT_STATUS_OK;
635 /***************************************************************************
636 Renames a struct samu
637 - check for the posix user/rename user script
638 - Add and lock the new user record
639 - rename the posix user
640 - rewrite the rid->username record
641 - delete the old user
642 - unlock the new user record
643 ***************************************************************************/
644 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
645 struct samu *old_acct,
646 const char *newname)
648 struct samu *new_acct = NULL;
649 char *rename_script = NULL;
650 int rename_ret;
651 fstring oldname_lower;
652 fstring newname_lower;
654 /* can't do anything without an external script */
656 if ( !(new_acct = samu_new( talloc_tos() )) ) {
657 return NT_STATUS_NO_MEMORY;
660 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
661 if (!rename_script) {
662 TALLOC_FREE(new_acct);
663 return NT_STATUS_NO_MEMORY;
665 if (!*rename_script) {
666 TALLOC_FREE(new_acct);
667 return NT_STATUS_ACCESS_DENIED;
670 if ( !pdb_copy_sam_account(new_acct, old_acct)
671 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
673 TALLOC_FREE(new_acct);
674 return NT_STATUS_NO_MEMORY;
677 /* open the database */
678 if ( !tdbsam_open( tdbsam_filename ) ) {
679 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
680 tdbsam_filename));
681 TALLOC_FREE(new_acct);
682 return NT_STATUS_ACCESS_DENIED;
685 if (db_sam->transaction_start(db_sam) != 0) {
686 DEBUG(0, ("Could not start transaction\n"));
687 TALLOC_FREE(new_acct);
688 return NT_STATUS_ACCESS_DENIED;
692 /* add the new account and lock it */
693 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
694 goto cancel;
697 /* Rename the posix user. Follow the semantics of _samr_create_user()
698 so that we lower case the posix name but preserve the case in passdb */
700 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
701 strlower_m( oldname_lower );
703 fstrcpy( newname_lower, newname );
704 strlower_m( newname_lower );
706 rename_script = talloc_string_sub2(new_acct,
707 rename_script,
708 "%unew",
709 newname_lower,
710 true,
711 false,
712 true);
713 if (!rename_script) {
714 goto cancel;
716 rename_script = talloc_string_sub2(new_acct,
717 rename_script,
718 "%uold",
719 oldname_lower,
720 true,
721 false,
722 true);
723 if (!rename_script) {
724 goto cancel;
726 rename_ret = smbrun(rename_script, NULL);
728 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
729 rename_script, rename_ret));
731 if (rename_ret != 0) {
732 goto cancel;
735 smb_nscd_flush_user_cache();
737 /* rewrite the rid->username record */
739 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
740 goto cancel;
743 tdb_delete_samacct_only( old_acct );
745 if (db_sam->transaction_commit(db_sam) != 0) {
747 * Ok, we're screwed. We've changed the posix account, but
748 * could not adapt passdb.tdb. Shall we change the posix
749 * account back?
751 DEBUG(0, ("transaction_commit failed\n"));
752 TALLOC_FREE(new_acct);
753 return NT_STATUS_INTERNAL_DB_CORRUPTION;
756 TALLOC_FREE(new_acct );
757 return NT_STATUS_OK;
759 cancel:
760 if (db_sam->transaction_cancel(db_sam) != 0) {
761 smb_panic("transaction_cancel failed");
764 TALLOC_FREE(new_acct);
766 return NT_STATUS_ACCESS_DENIED;
769 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
771 return False;
774 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
776 uint32 rid;
778 rid = BASE_RID; /* Default if not set */
780 if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
781 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
782 NEXT_RID_STRING));
783 return false;
786 *prid = rid;
788 return true;
791 struct tdbsam_search_state {
792 struct pdb_methods *methods;
793 uint32_t acct_flags;
795 uint32_t *rids;
796 uint32_t num_rids;
797 ssize_t array_size;
798 uint32_t current;
801 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
803 struct tdbsam_search_state *state = talloc_get_type_abort(
804 private_data, struct tdbsam_search_state);
805 size_t prefixlen = strlen(RIDPREFIX);
806 uint32 rid;
808 if ((rec->key.dsize < prefixlen)
809 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
810 return 0;
813 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
815 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
816 &state->array_size);
818 return 0;
821 static void tdbsam_search_end(struct pdb_search *search)
823 struct tdbsam_search_state *state = talloc_get_type_abort(
824 search->private_data, struct tdbsam_search_state);
825 TALLOC_FREE(state);
828 static bool tdbsam_search_next_entry(struct pdb_search *search,
829 struct samr_displayentry *entry)
831 struct tdbsam_search_state *state = talloc_get_type_abort(
832 search->private_data, struct tdbsam_search_state);
833 struct samu *user = NULL;
834 NTSTATUS status;
835 uint32_t rid;
837 again:
838 TALLOC_FREE(user);
839 user = samu_new(talloc_tos());
840 if (user == NULL) {
841 DEBUG(0, ("samu_new failed\n"));
842 return false;
845 if (state->current == state->num_rids) {
846 return false;
849 rid = state->rids[state->current++];
851 status = tdbsam_getsampwrid(state->methods, user, rid);
853 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
855 * Someone has deleted that user since we listed the RIDs
857 goto again;
860 if (!NT_STATUS_IS_OK(status)) {
861 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
862 nt_errstr(status)));
863 TALLOC_FREE(user);
864 return false;
867 if ((state->acct_flags != 0) &&
868 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
869 goto again;
872 entry->acct_flags = pdb_get_acct_ctrl(user);
873 entry->rid = rid;
874 entry->account_name = talloc_strdup(
875 search->mem_ctx, pdb_get_username(user));
876 entry->fullname = talloc_strdup(
877 search->mem_ctx, pdb_get_fullname(user));
878 entry->description = talloc_strdup(
879 search->mem_ctx, pdb_get_acct_desc(user));
881 TALLOC_FREE(user);
883 if ((entry->account_name == NULL) || (entry->fullname == NULL)
884 || (entry->description == NULL)) {
885 DEBUG(0, ("talloc_strdup failed\n"));
886 return false;
889 return true;
892 static bool tdbsam_search_users(struct pdb_methods *methods,
893 struct pdb_search *search,
894 uint32 acct_flags)
896 struct tdbsam_search_state *state;
898 if (!tdbsam_open(tdbsam_filename)) {
899 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
900 tdbsam_filename));
901 return false;
904 state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
905 if (state == NULL) {
906 DEBUG(0, ("talloc failed\n"));
907 return false;
909 state->acct_flags = acct_flags;
910 state->methods = methods;
912 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
914 search->private_data = state;
915 search->next_entry = tdbsam_search_next_entry;
916 search->search_end = tdbsam_search_end;
918 return true;
921 /*********************************************************************
922 Initialize the tdb sam backend. Setup the dispath table of methods,
923 open the tdb, etc...
924 *********************************************************************/
926 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
928 NTSTATUS nt_status;
929 char *tdbfile = NULL;
930 const char *pfile = location;
932 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
933 return nt_status;
936 (*pdb_method)->name = "tdbsam";
938 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
939 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
940 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
941 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
942 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
943 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
944 (*pdb_method)->search_users = tdbsam_search_users;
946 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
947 (*pdb_method)->new_rid = tdbsam_new_rid;
949 /* save the path for later */
951 if (!location) {
952 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
953 PASSDB_FILE_NAME) < 0) {
954 return NT_STATUS_NO_MEMORY;
956 pfile = tdbfile;
958 tdbsam_filename = SMB_STRDUP(pfile);
959 if (!tdbsam_filename) {
960 return NT_STATUS_NO_MEMORY;
962 SAFE_FREE(tdbfile);
964 /* no private data */
966 (*pdb_method)->private_data = NULL;
967 (*pdb_method)->free_private_data = NULL;
969 return NT_STATUS_OK;
972 NTSTATUS pdb_tdbsam_init(void)
974 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);