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-2009
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)
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
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/>.
26 #include "system/filesys.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "../libcli/security/security.h"
32 #include "passdb/pdb_tdb.h"
34 #if 0 /* when made a module use this */
36 static int tdbsam_debug_level = DBGC_ALL;
38 #define DBGC_CLASS tdbsam_debug_level
43 #define DBGC_CLASS DBGC_PASSDB
47 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
48 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
49 #define TDBSAM_VERSION_STRING "INFO/version"
50 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
51 #define PASSDB_FILE_NAME "passdb.tdb"
52 #define USERPREFIX "USER_"
53 #define USERPREFIX_LEN 5
54 #define RIDPREFIX "RID_"
55 #define PRIVPREFIX "PRIV_"
56 #define NEXT_RID_STRING "NEXT_RID"
58 /* GLOBAL TDB SAM CONTEXT */
60 static struct db_context *db_sam;
61 static char *tdbsam_filename;
63 struct tdbsam_convert_state {
68 static int tdbsam_convert_one(struct db_record *rec, void *priv)
70 struct tdbsam_convert_state *state =
71 (struct tdbsam_convert_state *)priv;
79 key = dbwrap_record_get_key(rec);
81 if (key.dsize < USERPREFIX_LEN) {
84 if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
88 user = samu_new(talloc_tos());
90 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
91 state->success = false;
95 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
96 "(version:%d)\n", (char *)key.dptr, state->from));
98 value = dbwrap_record_get_value(rec);
100 switch (state->from) {
102 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
107 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
112 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
117 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
122 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
127 /* unknown tdbsam version */
131 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
132 "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
135 state->success = false;
139 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
142 if (data.dsize == -1) {
143 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
144 "the new format\n"));
145 state->success = false;
149 status = dbwrap_record_store(rec, data, TDB_MODIFY);
150 if (!NT_STATUS_IS_OK(status)) {
151 DEBUG(0, ("Could not store the new record: %s\n",
153 state->success = false;
160 /**********************************************************************
161 Struct and function to backup an old record.
162 *********************************************************************/
164 struct tdbsam_backup_state {
165 struct db_context *new_db;
169 static int backup_copy_fn(struct db_record *orig_rec, void *state)
171 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
172 struct db_record *new_rec;
177 key = dbwrap_record_get_key(orig_rec);
179 new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
180 if (new_rec == NULL) {
185 value = dbwrap_record_get_value(orig_rec);
187 status = dbwrap_record_store(new_rec, value, TDB_INSERT);
189 TALLOC_FREE(new_rec);
191 if (!NT_STATUS_IS_OK(status)) {
198 /**********************************************************************
199 Make a backup of an old passdb and replace the new one with it. We
200 have to do this as between 3.0.x and 3.2.x the hash function changed
201 by mistake (used unsigned char * instead of char *). This means the
202 previous simple update code will fail due to not being able to find
203 existing records to replace in the tdbsam_convert_one() function. JRA.
204 *********************************************************************/
206 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
208 TALLOC_CTX *frame = talloc_stackframe();
209 const char *tmp_fname = NULL;
210 struct db_context *tmp_db = NULL;
211 struct db_context *orig_db = *pp_db;
212 struct tdbsam_backup_state bs;
215 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
223 /* Remember to open this on the NULL context. We need
224 * it to stay around after we return from here. */
226 tmp_db = db_open(NULL, tmp_fname, 0,
227 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
228 if (tmp_db == NULL) {
229 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
230 "[%s]\n", tmp_fname));
235 if (dbwrap_transaction_start(orig_db) != 0) {
236 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
242 if (dbwrap_transaction_start(tmp_db) != 0) {
243 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
244 dbwrap_transaction_cancel(orig_db);
254 status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
255 if (!NT_STATUS_IS_OK(status)) {
256 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
261 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
265 if (dbwrap_transaction_commit(orig_db) != 0) {
266 smb_panic("tdbsam_convert_backup: orig commit failed\n");
268 if (dbwrap_transaction_commit(tmp_db) != 0) {
269 smb_panic("tdbsam_convert_backup: orig commit failed\n");
272 /* be sure to close the DBs _before_ renaming the file */
274 TALLOC_FREE(orig_db);
277 /* This is safe from other users as we know we're
278 * under a mutex here. */
280 if (rename(tmp_fname, dbname) == -1) {
281 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
285 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
290 /* re-open the converted TDB */
292 orig_db = db_open(NULL, dbname, 0,
293 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
294 if (orig_db == NULL) {
295 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
296 "converted passdb TDB [%s]\n", dbname));
300 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
303 /* Replace the global db pointer. */
309 if (dbwrap_transaction_cancel(orig_db) != 0) {
310 smb_panic("tdbsam_convert: transaction_cancel failed");
313 if (dbwrap_transaction_cancel(tmp_db) != 0) {
314 smb_panic("tdbsam_convert: transaction_cancel failed");
323 static bool tdbsam_upgrade_next_rid(struct db_context *db)
329 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
334 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
335 TDB_DEFAULT, O_RDONLY, 0644);
338 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
347 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
354 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
356 struct tdbsam_convert_state state;
357 struct db_context *db = NULL;
360 /* We only need the update backup for local db's. */
361 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
362 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
368 state.success = true;
370 if (dbwrap_transaction_start(db) != 0) {
371 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
375 if (!tdbsam_upgrade_next_rid(db)) {
376 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
380 status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
381 if (!NT_STATUS_IS_OK(status)) {
382 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
386 if (!state.success) {
387 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
391 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
392 TDBSAM_VERSION) != 0) {
393 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
397 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
398 TDBSAM_MINOR_VERSION) != 0) {
399 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
403 if (dbwrap_transaction_commit(db) != 0) {
404 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
411 if (dbwrap_transaction_cancel(db) != 0) {
412 smb_panic("tdbsam_convert: transaction_cancel failed");
418 /*********************************************************************
419 Open the tdbsam file based on the absolute path specified.
420 Uses a reference count to allow multiple open calls.
421 *********************************************************************/
423 static bool tdbsam_open( const char *name )
428 /* check if we are already open */
434 /* Try to open tdb passwd. Create a new one if necessary */
436 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
437 if (db_sam == NULL) {
438 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
443 /* Check the version */
444 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
446 version = 0; /* Version not found, assume version 0 */
449 /* Get the minor version */
450 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
451 if (minor_version == -1) {
452 minor_version = 0; /* Minor version not found, assume 0 */
455 /* Compare the version */
456 if (version > TDBSAM_VERSION) {
457 /* Version more recent than the latest known */
458 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
463 if ( version < TDBSAM_VERSION ||
464 (version == TDBSAM_VERSION &&
465 minor_version < TDBSAM_MINOR_VERSION) ) {
467 * Ok - we think we're going to have to convert.
468 * Due to the backup process we now must do to
469 * upgrade we have to get a mutex and re-check
470 * the version. Someone else may have upgraded
471 * whilst we were checking.
474 struct named_mutex *mtx = grab_named_mutex(NULL,
475 "tdbsam_upgrade_mutex",
479 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
484 /* Re-check the version */
485 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
487 version = 0; /* Version not found, assume version 0 */
490 /* Re-check the minor version */
491 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
492 if (minor_version == -1) {
493 minor_version = 0; /* Minor version not found, assume 0 */
496 /* Compare the version */
497 if (version > TDBSAM_VERSION) {
498 /* Version more recent than the latest known */
499 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
505 if ( version < TDBSAM_VERSION ||
506 (version == TDBSAM_VERSION &&
507 minor_version < TDBSAM_MINOR_VERSION) ) {
509 * Note that minor versions we read that are greater
510 * than the current minor version we have hard coded
511 * are assumed to be compatible if they have the same
512 * major version. That allows previous versions of the
513 * passdb code that don't know about minor versions to
514 * still use this database. JRA.
517 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
522 TDBSAM_MINOR_VERSION));
524 if ( !tdbsam_convert(&db_sam, name, version) ) {
525 DEBUG(0, ("tdbsam_open: Error when trying to convert "
526 "tdbsam [%s]\n",name));
532 DEBUG(3, ("TDBSAM converted successfully.\n"));
537 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
542 /******************************************************************
543 Lookup a name in the SAM TDB
544 ******************************************************************/
546 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
547 struct samu *user, const char *sname)
555 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
556 return NT_STATUS_NO_MEMORY;
559 /* Data is stored in all lower-case */
560 fstrcpy(name, sname);
564 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
566 /* open the database */
568 if ( !tdbsam_open( tdbsam_filename ) ) {
569 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
570 return NT_STATUS_ACCESS_DENIED;
575 status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
576 if (!NT_STATUS_IS_OK(status)) {
577 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
578 DEBUGADD(5, (" Key: %s\n", keystr));
579 return NT_STATUS_NO_SUCH_USER;
582 /* unpack the buffer */
584 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
585 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
586 SAFE_FREE(data.dptr);
587 return NT_STATUS_NO_MEMORY;
592 TALLOC_FREE(data.dptr);
597 /***************************************************************************
599 **************************************************************************/
601 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
602 struct samu *user, uint32 rid)
604 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
610 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
616 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
618 /* open the database */
620 if ( !tdbsam_open( tdbsam_filename ) ) {
621 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
622 return NT_STATUS_ACCESS_DENIED;
627 nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
628 if (!NT_STATUS_IS_OK(nt_status)) {
629 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
633 fstrcpy(name, (const char *)data.dptr);
634 TALLOC_FREE(data.dptr);
636 return tdbsam_getsampwnam (my_methods, user, name);
639 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
640 struct samu * user, const struct dom_sid *sid)
644 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
645 return NT_STATUS_UNSUCCESSFUL;
647 return tdbsam_getsampwrid(my_methods, user, rid);
650 static bool tdb_delete_samacct_only( struct samu *sam_pass )
656 fstrcpy(name, pdb_get_username(sam_pass));
659 /* set the search key */
661 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
663 /* it's outaa here! 8^) */
664 if ( !tdbsam_open( tdbsam_filename ) ) {
665 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
670 status = dbwrap_delete_bystring(db_sam, keystr);
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(5, ("Error deleting entry from tdb passwd "
673 "database: %s!\n", nt_errstr(status)));
680 /***************************************************************************
681 Delete a struct samu records for the username and RID key
682 ****************************************************************************/
684 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
685 struct samu *sam_pass)
687 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
692 /* open the database */
694 if ( !tdbsam_open( tdbsam_filename ) ) {
695 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
697 return NT_STATUS_ACCESS_DENIED;
700 fstrcpy(name, pdb_get_username(sam_pass));
703 /* set the search key */
705 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
707 rid = pdb_get_user_rid(sam_pass);
709 /* it's outaa here! 8^) */
711 if (dbwrap_transaction_start(db_sam) != 0) {
712 DEBUG(0, ("Could not start transaction\n"));
713 return NT_STATUS_UNSUCCESSFUL;
716 nt_status = dbwrap_delete_bystring(db_sam, keystr);
717 if (!NT_STATUS_IS_OK(nt_status)) {
718 DEBUG(5, ("Error deleting entry from tdb passwd "
719 "database: %s!\n", nt_errstr(nt_status)));
723 /* set the search key */
725 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
727 /* it's outaa here! 8^) */
729 nt_status = dbwrap_delete_bystring(db_sam, keystr);
730 if (!NT_STATUS_IS_OK(nt_status)) {
731 DEBUG(5, ("Error deleting entry from tdb rid "
732 "database: %s!\n", nt_errstr(nt_status)));
736 if (dbwrap_transaction_commit(db_sam) != 0) {
737 DEBUG(0, ("Could not commit transaction\n"));
738 return NT_STATUS_INTERNAL_DB_CORRUPTION;
744 if (dbwrap_transaction_cancel(db_sam) != 0) {
745 smb_panic("transaction_cancel failed");
752 /***************************************************************************
753 Update the TDB SAM account record only
754 Assumes that the tdbsam is already open
755 ****************************************************************************/
756 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
765 /* copy the struct samu struct into a BYTE buffer for storage */
767 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
768 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
773 fstrcpy(name, pdb_get_username(newpwd));
776 DEBUG(5, ("Storing %saccount %s with RID %d\n",
777 flag == TDB_INSERT ? "(new) " : "", name,
778 pdb_get_user_rid(newpwd)));
780 /* setup the USER index key */
781 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
783 /* add the account */
785 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
786 if (!NT_STATUS_IS_OK(status)) {
787 DEBUG(0, ("Unable to modify passwd TDB: %s!",
800 /***************************************************************************
801 Update the TDB SAM RID record only
802 Assumes that the tdbsam is already open
803 ****************************************************************************/
804 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
811 fstrcpy(name, pdb_get_username(newpwd));
815 data = string_term_tdb_data(name);
817 /* setup the RID index key */
818 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
819 pdb_get_user_rid(newpwd));
821 /* add the reference */
822 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
823 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
833 /***************************************************************************
835 ****************************************************************************/
837 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
843 if (!(newrid = pdb_get_user_rid(newpwd))) {
844 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
845 pdb_get_username(newpwd)));
851 /* open the database */
853 if ( !tdbsam_open( tdbsam_filename ) ) {
854 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
858 if (dbwrap_transaction_start(db_sam) != 0) {
859 DEBUG(0, ("Could not start transaction\n"));
863 /* If we are updating, we may be changing this users RID. Retrieve the old RID
866 if (flag == TDB_MODIFY) {
867 struct samu *account = samu_new(talloc_tos());
868 if (account == NULL) {
869 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
872 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
873 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
874 pdb_get_username(newpwd)));
875 TALLOC_FREE(account);
878 if (!(oldrid = pdb_get_user_rid(account))) {
879 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
880 TALLOC_FREE(account);
883 TALLOC_FREE(account);
886 /* Update the new samu entry. */
887 if (!tdb_update_samacct_only(newpwd, flag)) {
891 /* Now take care of the case where the RID changed. We need
892 * to delete the old RID key and add the new. */
894 if (flag == TDB_MODIFY && newrid != oldrid) {
897 /* Delete old RID key */
898 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
899 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
900 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
901 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
904 /* Insert new RID key */
905 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
906 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
910 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
911 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
912 if (!tdb_update_ridrec_only(newpwd, flag)) {
917 if (dbwrap_transaction_commit(db_sam) != 0) {
918 DEBUG(0, ("Could not commit transaction\n"));
925 if (dbwrap_transaction_cancel(db_sam) != 0) {
926 smb_panic("transaction_cancel failed");
931 /***************************************************************************
932 Modifies an existing struct samu
933 ****************************************************************************/
935 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
937 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
938 return NT_STATUS_UNSUCCESSFUL;
943 /***************************************************************************
944 Adds an existing struct samu
945 ****************************************************************************/
947 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
949 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
950 return NT_STATUS_UNSUCCESSFUL;
955 /***************************************************************************
956 Renames a struct samu
957 - check for the posix user/rename user script
958 - Add and lock the new user record
959 - rename the posix user
960 - rewrite the rid->username record
961 - delete the old user
962 - unlock the new user record
963 ***************************************************************************/
964 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
965 struct samu *old_acct,
968 struct samu *new_acct = NULL;
969 char *rename_script = NULL;
971 fstring oldname_lower;
972 fstring newname_lower;
974 /* can't do anything without an external script */
976 if ( !(new_acct = samu_new( talloc_tos() )) ) {
977 return NT_STATUS_NO_MEMORY;
980 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
981 if (!rename_script) {
982 TALLOC_FREE(new_acct);
983 return NT_STATUS_NO_MEMORY;
985 if (!*rename_script) {
986 TALLOC_FREE(new_acct);
987 return NT_STATUS_ACCESS_DENIED;
990 if ( !pdb_copy_sam_account(new_acct, old_acct)
991 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
993 TALLOC_FREE(new_acct);
994 return NT_STATUS_NO_MEMORY;
997 /* open the database */
998 if ( !tdbsam_open( tdbsam_filename ) ) {
999 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1001 TALLOC_FREE(new_acct);
1002 return NT_STATUS_ACCESS_DENIED;
1005 if (dbwrap_transaction_start(db_sam) != 0) {
1006 DEBUG(0, ("Could not start transaction\n"));
1007 TALLOC_FREE(new_acct);
1008 return NT_STATUS_ACCESS_DENIED;
1012 /* add the new account and lock it */
1013 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1017 /* Rename the posix user. Follow the semantics of _samr_create_user()
1018 so that we lower case the posix name but preserve the case in passdb */
1020 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1021 strlower_m( oldname_lower );
1023 fstrcpy( newname_lower, newname );
1024 strlower_m( newname_lower );
1026 rename_script = talloc_string_sub2(new_acct,
1033 if (!rename_script) {
1036 rename_script = talloc_string_sub2(new_acct,
1043 if (!rename_script) {
1046 rename_ret = smbrun(rename_script, NULL);
1048 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1049 rename_script, rename_ret));
1051 if (rename_ret != 0) {
1055 smb_nscd_flush_user_cache();
1057 /* rewrite the rid->username record */
1059 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1063 tdb_delete_samacct_only( old_acct );
1065 if (dbwrap_transaction_commit(db_sam) != 0) {
1067 * Ok, we're screwed. We've changed the posix account, but
1068 * could not adapt passdb.tdb. Shall we change the posix
1071 DEBUG(0, ("transaction_commit failed\n"));
1072 TALLOC_FREE(new_acct);
1073 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1076 TALLOC_FREE(new_acct );
1077 return NT_STATUS_OK;
1080 if (dbwrap_transaction_cancel(db_sam) != 0) {
1081 smb_panic("transaction_cancel failed");
1084 TALLOC_FREE(new_acct);
1086 return NT_STATUS_ACCESS_DENIED;
1089 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1091 return PDB_CAP_STORE_RIDS;
1094 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1099 rid = BASE_RID; /* Default if not set */
1101 if (!tdbsam_open(tdbsam_filename)) {
1102 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1107 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1109 if (!NT_STATUS_IS_OK(status)) {
1110 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1111 NEXT_RID_STRING, nt_errstr(status)));
1120 struct tdbsam_search_state {
1121 struct pdb_methods *methods;
1122 uint32_t acct_flags;
1130 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1132 struct tdbsam_search_state *state = talloc_get_type_abort(
1133 private_data, struct tdbsam_search_state);
1134 size_t prefixlen = strlen(RIDPREFIX);
1138 key = dbwrap_record_get_key(rec);
1140 if ((key.dsize < prefixlen)
1141 || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1145 rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1147 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1148 &state->array_size);
1153 static void tdbsam_search_end(struct pdb_search *search)
1155 struct tdbsam_search_state *state = talloc_get_type_abort(
1156 search->private_data, struct tdbsam_search_state);
1160 static bool tdbsam_search_next_entry(struct pdb_search *search,
1161 struct samr_displayentry *entry)
1163 struct tdbsam_search_state *state = talloc_get_type_abort(
1164 search->private_data, struct tdbsam_search_state);
1165 struct samu *user = NULL;
1171 user = samu_new(talloc_tos());
1173 DEBUG(0, ("samu_new failed\n"));
1177 if (state->current == state->num_rids) {
1181 rid = state->rids[state->current++];
1183 status = tdbsam_getsampwrid(state->methods, user, rid);
1185 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1187 * Someone has deleted that user since we listed the RIDs
1192 if (!NT_STATUS_IS_OK(status)) {
1193 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1194 nt_errstr(status)));
1199 if ((state->acct_flags != 0) &&
1200 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1204 entry->acct_flags = pdb_get_acct_ctrl(user);
1206 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1207 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1208 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1212 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1213 || (entry->description == NULL)) {
1214 DEBUG(0, ("talloc_strdup failed\n"));
1221 static bool tdbsam_search_users(struct pdb_methods *methods,
1222 struct pdb_search *search,
1225 struct tdbsam_search_state *state;
1227 if (!tdbsam_open(tdbsam_filename)) {
1228 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1233 state = talloc_zero(search, struct tdbsam_search_state);
1234 if (state == NULL) {
1235 DEBUG(0, ("talloc failed\n"));
1238 state->acct_flags = acct_flags;
1239 state->methods = methods;
1241 dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1243 search->private_data = state;
1244 search->next_entry = tdbsam_search_next_entry;
1245 search->search_end = tdbsam_search_end;
1250 /*********************************************************************
1251 Initialize the tdb sam backend. Setup the dispath table of methods,
1252 open the tdb, etc...
1253 *********************************************************************/
1255 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1258 char *tdbfile = NULL;
1259 const char *pfile = location;
1261 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1265 (*pdb_method)->name = "tdbsam";
1267 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1268 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1269 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1270 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1271 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1272 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1273 (*pdb_method)->search_users = tdbsam_search_users;
1275 (*pdb_method)->capabilities = tdbsam_capabilities;
1276 (*pdb_method)->new_rid = tdbsam_new_rid;
1278 /* save the path for later */
1281 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1282 PASSDB_FILE_NAME) < 0) {
1283 return NT_STATUS_NO_MEMORY;
1287 tdbsam_filename = SMB_STRDUP(pfile);
1288 if (!tdbsam_filename) {
1289 return NT_STATUS_NO_MEMORY;
1293 /* no private data */
1295 (*pdb_method)->private_data = NULL;
1296 (*pdb_method)->free_private_data = NULL;
1298 return NT_STATUS_OK;
1301 NTSTATUS pdb_tdbsam_init(void)
1303 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);