clean up lib64 linking paths the same way as lib
[Samba/gebeck_regimport.git] / source3 / passdb / pdb_tdb.c
blob3442561030845c5be68d3c05b9ee3cc7164d5c8e
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_getsampwrid: 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^) */
403 if ( !tdbsam_open( tdbsam_filename ) ) {
404 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
405 tdbsam_filename));
406 return false;
409 status = dbwrap_delete_bystring(db_sam, keystr);
410 if (!NT_STATUS_IS_OK(status)) {
411 DEBUG(5, ("Error deleting entry from tdb passwd "
412 "database: %s!\n", nt_errstr(status)));
413 return false;
416 return true;
419 /***************************************************************************
420 Delete a struct samu records for the username and RID key
421 ****************************************************************************/
423 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
424 struct samu *sam_pass)
426 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
427 fstring keystr;
428 uint32 rid;
429 fstring name;
431 /* open the database */
433 if ( !tdbsam_open( tdbsam_filename ) ) {
434 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
435 tdbsam_filename));
436 return NT_STATUS_ACCESS_DENIED;
439 fstrcpy(name, pdb_get_username(sam_pass));
440 strlower_m(name);
442 /* set the search key */
444 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
446 rid = pdb_get_user_rid(sam_pass);
448 /* it's outaa here! 8^) */
450 if (db_sam->transaction_start(db_sam) != 0) {
451 DEBUG(0, ("Could not start transaction\n"));
452 return NT_STATUS_UNSUCCESSFUL;
455 nt_status = dbwrap_delete_bystring(db_sam, keystr);
456 if (!NT_STATUS_IS_OK(nt_status)) {
457 DEBUG(5, ("Error deleting entry from tdb passwd "
458 "database: %s!\n", nt_errstr(nt_status)));
459 goto cancel;
462 /* set the search key */
464 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
466 /* it's outaa here! 8^) */
468 nt_status = dbwrap_delete_bystring(db_sam, keystr);
469 if (!NT_STATUS_IS_OK(nt_status)) {
470 DEBUG(5, ("Error deleting entry from tdb rid "
471 "database: %s!\n", nt_errstr(nt_status)));
472 goto cancel;
475 if (db_sam->transaction_commit(db_sam) != 0) {
476 DEBUG(0, ("Could not commit transaction\n"));
477 return NT_STATUS_INTERNAL_DB_CORRUPTION;
480 return NT_STATUS_OK;
482 cancel:
483 if (db_sam->transaction_cancel(db_sam) != 0) {
484 smb_panic("transaction_cancel failed");
487 return nt_status;
491 /***************************************************************************
492 Update the TDB SAM account record only
493 Assumes that the tdbsam is already open
494 ****************************************************************************/
495 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
497 TDB_DATA data;
498 uint8 *buf = NULL;
499 fstring keystr;
500 fstring name;
501 bool ret = false;
502 NTSTATUS status;
504 /* copy the struct samu struct into a BYTE buffer for storage */
506 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
507 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
508 goto done;
510 data.dptr = buf;
512 fstrcpy(name, pdb_get_username(newpwd));
513 strlower_m(name);
515 DEBUG(5, ("Storing %saccount %s with RID %d\n",
516 flag == TDB_INSERT ? "(new) " : "", name,
517 pdb_get_user_rid(newpwd)));
519 /* setup the USER index key */
520 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
522 /* add the account */
524 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(0, ("Unable to modify passwd TDB: %s!",
527 nt_errstr(status)));
528 goto done;
531 ret = true;
533 done:
534 /* cleanup */
535 SAFE_FREE(buf);
536 return ret;
539 /***************************************************************************
540 Update the TDB SAM RID record only
541 Assumes that the tdbsam is already open
542 ****************************************************************************/
543 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
545 TDB_DATA data;
546 fstring keystr;
547 fstring name;
548 NTSTATUS status;
550 fstrcpy(name, pdb_get_username(newpwd));
551 strlower_m(name);
553 /* setup RID data */
554 data = string_term_tdb_data(name);
556 /* setup the RID index key */
557 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
558 pdb_get_user_rid(newpwd));
560 /* add the reference */
561 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
562 if (!NT_STATUS_IS_OK(status)) {
563 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
564 nt_errstr(status)));
565 return false;
568 return true;
572 /***************************************************************************
573 Update the TDB SAM
574 ****************************************************************************/
576 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
577 int flag)
579 if (!pdb_get_user_rid(newpwd)) {
580 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
581 pdb_get_username(newpwd)));
582 return False;
585 /* open the database */
587 if ( !tdbsam_open( tdbsam_filename ) ) {
588 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
589 return False;
592 if (db_sam->transaction_start(db_sam) != 0) {
593 DEBUG(0, ("Could not start transaction\n"));
594 return false;
597 if (!tdb_update_samacct_only(newpwd, flag)
598 || !tdb_update_ridrec_only(newpwd, flag)) {
599 goto cancel;
602 if (db_sam->transaction_commit(db_sam) != 0) {
603 DEBUG(0, ("Could not commit transaction\n"));
604 return false;
607 return true;
609 cancel:
610 if (db_sam->transaction_cancel(db_sam) != 0) {
611 smb_panic("transaction_cancel failed");
613 return false;
616 /***************************************************************************
617 Modifies an existing struct samu
618 ****************************************************************************/
620 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
622 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
623 return NT_STATUS_UNSUCCESSFUL;
625 return NT_STATUS_OK;
628 /***************************************************************************
629 Adds an existing struct samu
630 ****************************************************************************/
632 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
634 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
635 return NT_STATUS_UNSUCCESSFUL;
637 return NT_STATUS_OK;
640 /***************************************************************************
641 Renames a struct samu
642 - check for the posix user/rename user script
643 - Add and lock the new user record
644 - rename the posix user
645 - rewrite the rid->username record
646 - delete the old user
647 - unlock the new user record
648 ***************************************************************************/
649 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
650 struct samu *old_acct,
651 const char *newname)
653 struct samu *new_acct = NULL;
654 char *rename_script = NULL;
655 int rename_ret;
656 fstring oldname_lower;
657 fstring newname_lower;
659 /* can't do anything without an external script */
661 if ( !(new_acct = samu_new( talloc_tos() )) ) {
662 return NT_STATUS_NO_MEMORY;
665 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
666 if (!rename_script) {
667 TALLOC_FREE(new_acct);
668 return NT_STATUS_NO_MEMORY;
670 if (!*rename_script) {
671 TALLOC_FREE(new_acct);
672 return NT_STATUS_ACCESS_DENIED;
675 if ( !pdb_copy_sam_account(new_acct, old_acct)
676 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
678 TALLOC_FREE(new_acct);
679 return NT_STATUS_NO_MEMORY;
682 /* open the database */
683 if ( !tdbsam_open( tdbsam_filename ) ) {
684 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
685 tdbsam_filename));
686 TALLOC_FREE(new_acct);
687 return NT_STATUS_ACCESS_DENIED;
690 if (db_sam->transaction_start(db_sam) != 0) {
691 DEBUG(0, ("Could not start transaction\n"));
692 TALLOC_FREE(new_acct);
693 return NT_STATUS_ACCESS_DENIED;
697 /* add the new account and lock it */
698 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
699 goto cancel;
702 /* Rename the posix user. Follow the semantics of _samr_create_user()
703 so that we lower case the posix name but preserve the case in passdb */
705 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
706 strlower_m( oldname_lower );
708 fstrcpy( newname_lower, newname );
709 strlower_m( newname_lower );
711 rename_script = talloc_string_sub2(new_acct,
712 rename_script,
713 "%unew",
714 newname_lower,
715 true,
716 false,
717 true);
718 if (!rename_script) {
719 goto cancel;
721 rename_script = talloc_string_sub2(new_acct,
722 rename_script,
723 "%uold",
724 oldname_lower,
725 true,
726 false,
727 true);
728 if (!rename_script) {
729 goto cancel;
731 rename_ret = smbrun(rename_script, NULL);
733 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
734 rename_script, rename_ret));
736 if (rename_ret != 0) {
737 goto cancel;
740 smb_nscd_flush_user_cache();
742 /* rewrite the rid->username record */
744 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
745 goto cancel;
748 tdb_delete_samacct_only( old_acct );
750 if (db_sam->transaction_commit(db_sam) != 0) {
752 * Ok, we're screwed. We've changed the posix account, but
753 * could not adapt passdb.tdb. Shall we change the posix
754 * account back?
756 DEBUG(0, ("transaction_commit failed\n"));
757 TALLOC_FREE(new_acct);
758 return NT_STATUS_INTERNAL_DB_CORRUPTION;
761 TALLOC_FREE(new_acct );
762 return NT_STATUS_OK;
764 cancel:
765 if (db_sam->transaction_cancel(db_sam) != 0) {
766 smb_panic("transaction_cancel failed");
769 TALLOC_FREE(new_acct);
771 return NT_STATUS_ACCESS_DENIED;
774 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
776 return False;
779 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
781 uint32 rid;
783 rid = BASE_RID; /* Default if not set */
785 if (!tdbsam_open(tdbsam_filename)) {
786 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
787 tdbsam_filename));
788 return false;
791 if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
792 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
793 NEXT_RID_STRING));
794 return false;
797 *prid = rid;
799 return true;
802 struct tdbsam_search_state {
803 struct pdb_methods *methods;
804 uint32_t acct_flags;
806 uint32_t *rids;
807 uint32_t num_rids;
808 ssize_t array_size;
809 uint32_t current;
812 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
814 struct tdbsam_search_state *state = talloc_get_type_abort(
815 private_data, struct tdbsam_search_state);
816 size_t prefixlen = strlen(RIDPREFIX);
817 uint32 rid;
819 if ((rec->key.dsize < prefixlen)
820 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
821 return 0;
824 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
826 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
827 &state->array_size);
829 return 0;
832 static void tdbsam_search_end(struct pdb_search *search)
834 struct tdbsam_search_state *state = talloc_get_type_abort(
835 search->private_data, struct tdbsam_search_state);
836 TALLOC_FREE(state);
839 static bool tdbsam_search_next_entry(struct pdb_search *search,
840 struct samr_displayentry *entry)
842 struct tdbsam_search_state *state = talloc_get_type_abort(
843 search->private_data, struct tdbsam_search_state);
844 struct samu *user = NULL;
845 NTSTATUS status;
846 uint32_t rid;
848 again:
849 TALLOC_FREE(user);
850 user = samu_new(talloc_tos());
851 if (user == NULL) {
852 DEBUG(0, ("samu_new failed\n"));
853 return false;
856 if (state->current == state->num_rids) {
857 return false;
860 rid = state->rids[state->current++];
862 status = tdbsam_getsampwrid(state->methods, user, rid);
864 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
866 * Someone has deleted that user since we listed the RIDs
868 goto again;
871 if (!NT_STATUS_IS_OK(status)) {
872 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
873 nt_errstr(status)));
874 TALLOC_FREE(user);
875 return false;
878 if ((state->acct_flags != 0) &&
879 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
880 goto again;
883 entry->acct_flags = pdb_get_acct_ctrl(user);
884 entry->rid = rid;
885 entry->account_name = talloc_strdup(search, pdb_get_username(user));
886 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
887 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
889 TALLOC_FREE(user);
891 if ((entry->account_name == NULL) || (entry->fullname == NULL)
892 || (entry->description == NULL)) {
893 DEBUG(0, ("talloc_strdup failed\n"));
894 return false;
897 return true;
900 static bool tdbsam_search_users(struct pdb_methods *methods,
901 struct pdb_search *search,
902 uint32 acct_flags)
904 struct tdbsam_search_state *state;
906 if (!tdbsam_open(tdbsam_filename)) {
907 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
908 tdbsam_filename));
909 return false;
912 state = talloc_zero(search, struct tdbsam_search_state);
913 if (state == NULL) {
914 DEBUG(0, ("talloc failed\n"));
915 return false;
917 state->acct_flags = acct_flags;
918 state->methods = methods;
920 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
922 search->private_data = state;
923 search->next_entry = tdbsam_search_next_entry;
924 search->search_end = tdbsam_search_end;
926 return true;
929 /*********************************************************************
930 Initialize the tdb sam backend. Setup the dispath table of methods,
931 open the tdb, etc...
932 *********************************************************************/
934 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
936 NTSTATUS nt_status;
937 char *tdbfile = NULL;
938 const char *pfile = location;
940 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
941 return nt_status;
944 (*pdb_method)->name = "tdbsam";
946 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
947 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
948 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
949 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
950 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
951 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
952 (*pdb_method)->search_users = tdbsam_search_users;
954 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
955 (*pdb_method)->new_rid = tdbsam_new_rid;
957 /* save the path for later */
959 if (!location) {
960 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
961 PASSDB_FILE_NAME) < 0) {
962 return NT_STATUS_NO_MEMORY;
964 pfile = tdbfile;
966 tdbsam_filename = SMB_STRDUP(pfile);
967 if (!tdbsam_filename) {
968 return NT_STATUS_NO_MEMORY;
970 SAFE_FREE(tdbfile);
972 /* no private data */
974 (*pdb_method)->private_data = NULL;
975 (*pdb_method)->free_private_data = NULL;
977 return NT_STATUS_OK;
980 NTSTATUS pdb_tdbsam_init(void)
982 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);