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"
33 #if 0 /* when made a module use this */
35 static int tdbsam_debug_level = DBGC_ALL;
37 #define DBGC_CLASS tdbsam_debug_level
42 #define DBGC_CLASS DBGC_PASSDB
46 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
47 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
48 #define TDBSAM_VERSION_STRING "INFO/version"
49 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
50 #define PASSDB_FILE_NAME "passdb.tdb"
51 #define USERPREFIX "USER_"
52 #define USERPREFIX_LEN 5
53 #define RIDPREFIX "RID_"
54 #define PRIVPREFIX "PRIV_"
55 #define NEXT_RID_STRING "NEXT_RID"
57 /* GLOBAL TDB SAM CONTEXT */
59 static struct db_context *db_sam;
60 static char *tdbsam_filename;
62 struct tdbsam_convert_state {
67 static int tdbsam_convert_one(struct db_record *rec, void *priv)
69 struct tdbsam_convert_state *state =
70 (struct tdbsam_convert_state *)priv;
76 if (rec->key.dsize < USERPREFIX_LEN) {
79 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
83 user = samu_new(talloc_tos());
85 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
86 state->success = false;
90 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
91 "(version:%d)\n", rec->key.dptr, state->from));
93 switch (state->from) {
95 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
96 (uint8 *)rec->value.dptr,
100 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
101 (uint8 *)rec->value.dptr,
105 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
106 (uint8 *)rec->value.dptr,
110 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
111 (uint8 *)rec->value.dptr,
115 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
116 (uint8 *)rec->value.dptr,
120 /* unknown tdbsam version */
124 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
125 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
128 state->success = false;
132 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
135 if (data.dsize == -1) {
136 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
137 "the new format\n"));
138 state->success = false;
142 status = rec->store(rec, data, TDB_MODIFY);
143 if (!NT_STATUS_IS_OK(status)) {
144 DEBUG(0, ("Could not store the new record: %s\n",
146 state->success = false;
153 /**********************************************************************
154 Struct and function to backup an old record.
155 *********************************************************************/
157 struct tdbsam_backup_state {
158 struct db_context *new_db;
162 static int backup_copy_fn(struct db_record *orig_rec, void *state)
164 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
165 struct db_record *new_rec;
168 new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
169 if (new_rec == NULL) {
174 status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
176 TALLOC_FREE(new_rec);
178 if (!NT_STATUS_IS_OK(status)) {
185 /**********************************************************************
186 Make a backup of an old passdb and replace the new one with it. We
187 have to do this as between 3.0.x and 3.2.x the hash function changed
188 by mistake (used unsigned char * instead of char *). This means the
189 previous simple update code will fail due to not being able to find
190 existing records to replace in the tdbsam_convert_one() function. JRA.
191 *********************************************************************/
193 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
195 TALLOC_CTX *frame = talloc_stackframe();
196 const char *tmp_fname = NULL;
197 struct db_context *tmp_db = NULL;
198 struct db_context *orig_db = *pp_db;
199 struct tdbsam_backup_state bs;
202 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
210 /* Remember to open this on the NULL context. We need
211 * it to stay around after we return from here. */
213 tmp_db = db_open(NULL, tmp_fname, 0,
214 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
215 if (tmp_db == NULL) {
216 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
217 "[%s]\n", tmp_fname));
222 if (orig_db->transaction_start(orig_db) != 0) {
223 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
229 if (tmp_db->transaction_start(tmp_db) != 0) {
230 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
231 orig_db->transaction_cancel(orig_db);
241 ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
243 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
248 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
252 if (orig_db->transaction_commit(orig_db) != 0) {
253 smb_panic("tdbsam_convert_backup: orig commit failed\n");
255 if (tmp_db->transaction_commit(tmp_db) != 0) {
256 smb_panic("tdbsam_convert_backup: orig commit failed\n");
259 /* be sure to close the DBs _before_ renaming the file */
261 TALLOC_FREE(orig_db);
264 /* This is safe from other users as we know we're
265 * under a mutex here. */
267 if (rename(tmp_fname, dbname) == -1) {
268 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
272 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
277 /* re-open the converted TDB */
279 orig_db = db_open(NULL, dbname, 0,
280 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
281 if (orig_db == NULL) {
282 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
283 "converted passdb TDB [%s]\n", dbname));
287 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
290 /* Replace the global db pointer. */
296 if (orig_db->transaction_cancel(orig_db) != 0) {
297 smb_panic("tdbsam_convert: transaction_cancel failed");
300 if (tmp_db->transaction_cancel(tmp_db) != 0) {
301 smb_panic("tdbsam_convert: transaction_cancel failed");
310 static bool tdbsam_upgrade_next_rid(struct db_context *db)
316 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
321 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
322 TDB_DEFAULT, O_RDONLY, 0644);
325 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
334 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
341 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
343 struct tdbsam_convert_state state;
344 struct db_context *db = NULL;
347 /* We only need the update backup for local db's. */
348 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
349 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
355 state.success = true;
357 if (db->transaction_start(db) != 0) {
358 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
362 if (!tdbsam_upgrade_next_rid(db)) {
363 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
367 ret = db->traverse(db, tdbsam_convert_one, &state);
369 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
373 if (!state.success) {
374 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
378 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
379 TDBSAM_VERSION) != 0) {
380 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
384 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
385 TDBSAM_MINOR_VERSION) != 0) {
386 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
390 if (db->transaction_commit(db) != 0) {
391 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
398 if (db->transaction_cancel(db) != 0) {
399 smb_panic("tdbsam_convert: transaction_cancel failed");
405 /*********************************************************************
406 Open the tdbsam file based on the absolute path specified.
407 Uses a reference count to allow multiple open calls.
408 *********************************************************************/
410 static bool tdbsam_open( const char *name )
415 /* check if we are already open */
421 /* Try to open tdb passwd. Create a new one if necessary */
423 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
424 if (db_sam == NULL) {
425 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
430 /* Check the version */
431 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
433 version = 0; /* Version not found, assume version 0 */
436 /* Get the minor version */
437 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
438 if (minor_version == -1) {
439 minor_version = 0; /* Minor version not found, assume 0 */
442 /* Compare the version */
443 if (version > TDBSAM_VERSION) {
444 /* Version more recent than the latest known */
445 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
450 if ( version < TDBSAM_VERSION ||
451 (version == TDBSAM_VERSION &&
452 minor_version < TDBSAM_MINOR_VERSION) ) {
454 * Ok - we think we're going to have to convert.
455 * Due to the backup process we now must do to
456 * upgrade we have to get a mutex and re-check
457 * the version. Someone else may have upgraded
458 * whilst we were checking.
461 struct named_mutex *mtx = grab_named_mutex(NULL,
462 "tdbsam_upgrade_mutex",
466 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
471 /* Re-check the version */
472 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
474 version = 0; /* Version not found, assume version 0 */
477 /* Re-check the minor version */
478 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
479 if (minor_version == -1) {
480 minor_version = 0; /* Minor version not found, assume 0 */
483 /* Compare the version */
484 if (version > TDBSAM_VERSION) {
485 /* Version more recent than the latest known */
486 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
492 if ( version < TDBSAM_VERSION ||
493 (version == TDBSAM_VERSION &&
494 minor_version < TDBSAM_MINOR_VERSION) ) {
496 * Note that minor versions we read that are greater
497 * than the current minor version we have hard coded
498 * are assumed to be compatible if they have the same
499 * major version. That allows previous versions of the
500 * passdb code that don't know about minor versions to
501 * still use this database. JRA.
504 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
509 TDBSAM_MINOR_VERSION));
511 if ( !tdbsam_convert(&db_sam, name, version) ) {
512 DEBUG(0, ("tdbsam_open: Error when trying to convert "
513 "tdbsam [%s]\n",name));
519 DEBUG(3, ("TDBSAM converted successfully.\n"));
524 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
529 /******************************************************************
530 Lookup a name in the SAM TDB
531 ******************************************************************/
533 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
534 struct samu *user, const char *sname)
541 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
542 return NT_STATUS_NO_MEMORY;
545 /* Data is stored in all lower-case */
546 fstrcpy(name, sname);
550 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
552 /* open the database */
554 if ( !tdbsam_open( tdbsam_filename ) ) {
555 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
556 return NT_STATUS_ACCESS_DENIED;
561 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
563 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
564 DEBUGADD(5, (" Key: %s\n", keystr));
565 return NT_STATUS_NO_SUCH_USER;
568 /* unpack the buffer */
570 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
571 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
572 SAFE_FREE(data.dptr);
573 return NT_STATUS_NO_MEMORY;
578 TALLOC_FREE(data.dptr);
583 /***************************************************************************
585 **************************************************************************/
587 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
588 struct samu *user, uint32 rid)
590 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
596 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
602 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
604 /* open the database */
606 if ( !tdbsam_open( tdbsam_filename ) ) {
607 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
608 return NT_STATUS_ACCESS_DENIED;
613 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
615 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
616 return NT_STATUS_UNSUCCESSFUL;
619 fstrcpy(name, (const char *)data.dptr);
620 TALLOC_FREE(data.dptr);
622 return tdbsam_getsampwnam (my_methods, user, name);
625 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
626 struct samu * user, const struct dom_sid *sid)
630 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
631 return NT_STATUS_UNSUCCESSFUL;
633 return tdbsam_getsampwrid(my_methods, user, rid);
636 static bool tdb_delete_samacct_only( struct samu *sam_pass )
642 fstrcpy(name, pdb_get_username(sam_pass));
645 /* set the search key */
647 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
649 /* it's outaa here! 8^) */
650 if ( !tdbsam_open( tdbsam_filename ) ) {
651 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
656 status = dbwrap_delete_bystring(db_sam, keystr);
657 if (!NT_STATUS_IS_OK(status)) {
658 DEBUG(5, ("Error deleting entry from tdb passwd "
659 "database: %s!\n", nt_errstr(status)));
666 /***************************************************************************
667 Delete a struct samu records for the username and RID key
668 ****************************************************************************/
670 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
671 struct samu *sam_pass)
673 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
678 /* open the database */
680 if ( !tdbsam_open( tdbsam_filename ) ) {
681 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
683 return NT_STATUS_ACCESS_DENIED;
686 fstrcpy(name, pdb_get_username(sam_pass));
689 /* set the search key */
691 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
693 rid = pdb_get_user_rid(sam_pass);
695 /* it's outaa here! 8^) */
697 if (db_sam->transaction_start(db_sam) != 0) {
698 DEBUG(0, ("Could not start transaction\n"));
699 return NT_STATUS_UNSUCCESSFUL;
702 nt_status = dbwrap_delete_bystring(db_sam, keystr);
703 if (!NT_STATUS_IS_OK(nt_status)) {
704 DEBUG(5, ("Error deleting entry from tdb passwd "
705 "database: %s!\n", nt_errstr(nt_status)));
709 /* set the search key */
711 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
713 /* it's outaa here! 8^) */
715 nt_status = dbwrap_delete_bystring(db_sam, keystr);
716 if (!NT_STATUS_IS_OK(nt_status)) {
717 DEBUG(5, ("Error deleting entry from tdb rid "
718 "database: %s!\n", nt_errstr(nt_status)));
722 if (db_sam->transaction_commit(db_sam) != 0) {
723 DEBUG(0, ("Could not commit transaction\n"));
724 return NT_STATUS_INTERNAL_DB_CORRUPTION;
730 if (db_sam->transaction_cancel(db_sam) != 0) {
731 smb_panic("transaction_cancel failed");
738 /***************************************************************************
739 Update the TDB SAM account record only
740 Assumes that the tdbsam is already open
741 ****************************************************************************/
742 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
751 /* copy the struct samu struct into a BYTE buffer for storage */
753 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
754 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
759 fstrcpy(name, pdb_get_username(newpwd));
762 DEBUG(5, ("Storing %saccount %s with RID %d\n",
763 flag == TDB_INSERT ? "(new) " : "", name,
764 pdb_get_user_rid(newpwd)));
766 /* setup the USER index key */
767 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
769 /* add the account */
771 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
772 if (!NT_STATUS_IS_OK(status)) {
773 DEBUG(0, ("Unable to modify passwd TDB: %s!",
786 /***************************************************************************
787 Update the TDB SAM RID record only
788 Assumes that the tdbsam is already open
789 ****************************************************************************/
790 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
797 fstrcpy(name, pdb_get_username(newpwd));
801 data = string_term_tdb_data(name);
803 /* setup the RID index key */
804 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
805 pdb_get_user_rid(newpwd));
807 /* add the reference */
808 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
809 if (!NT_STATUS_IS_OK(status)) {
810 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
819 /***************************************************************************
821 ****************************************************************************/
823 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
829 if (!(newrid = pdb_get_user_rid(newpwd))) {
830 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
831 pdb_get_username(newpwd)));
837 /* open the database */
839 if ( !tdbsam_open( tdbsam_filename ) ) {
840 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
844 if (db_sam->transaction_start(db_sam) != 0) {
845 DEBUG(0, ("Could not start transaction\n"));
849 /* If we are updating, we may be changing this users RID. Retrieve the old RID
852 if (flag == TDB_MODIFY) {
853 struct samu *account = samu_new(talloc_tos());
854 if (account == NULL) {
855 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
858 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
859 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
860 pdb_get_username(newpwd)));
861 TALLOC_FREE(account);
864 if (!(oldrid = pdb_get_user_rid(account))) {
865 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
866 TALLOC_FREE(account);
869 TALLOC_FREE(account);
872 /* Update the new samu entry. */
873 if (!tdb_update_samacct_only(newpwd, flag)) {
877 /* Now take care of the case where the RID changed. We need
878 * to delete the old RID key and add the new. */
880 if (flag == TDB_MODIFY && newrid != oldrid) {
883 /* Delete old RID key */
884 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
885 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
886 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
887 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
890 /* Insert new RID key */
891 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
892 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
896 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
897 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
898 if (!tdb_update_ridrec_only(newpwd, flag)) {
903 if (db_sam->transaction_commit(db_sam) != 0) {
904 DEBUG(0, ("Could not commit transaction\n"));
911 if (db_sam->transaction_cancel(db_sam) != 0) {
912 smb_panic("transaction_cancel failed");
917 /***************************************************************************
918 Modifies an existing struct samu
919 ****************************************************************************/
921 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
923 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
924 return NT_STATUS_UNSUCCESSFUL;
929 /***************************************************************************
930 Adds an existing struct samu
931 ****************************************************************************/
933 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
935 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
936 return NT_STATUS_UNSUCCESSFUL;
941 /***************************************************************************
942 Renames a struct samu
943 - check for the posix user/rename user script
944 - Add and lock the new user record
945 - rename the posix user
946 - rewrite the rid->username record
947 - delete the old user
948 - unlock the new user record
949 ***************************************************************************/
950 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
951 struct samu *old_acct,
954 struct samu *new_acct = NULL;
955 char *rename_script = NULL;
957 fstring oldname_lower;
958 fstring newname_lower;
960 /* can't do anything without an external script */
962 if ( !(new_acct = samu_new( talloc_tos() )) ) {
963 return NT_STATUS_NO_MEMORY;
966 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
967 if (!rename_script) {
968 TALLOC_FREE(new_acct);
969 return NT_STATUS_NO_MEMORY;
971 if (!*rename_script) {
972 TALLOC_FREE(new_acct);
973 return NT_STATUS_ACCESS_DENIED;
976 if ( !pdb_copy_sam_account(new_acct, old_acct)
977 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
979 TALLOC_FREE(new_acct);
980 return NT_STATUS_NO_MEMORY;
983 /* open the database */
984 if ( !tdbsam_open( tdbsam_filename ) ) {
985 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
987 TALLOC_FREE(new_acct);
988 return NT_STATUS_ACCESS_DENIED;
991 if (db_sam->transaction_start(db_sam) != 0) {
992 DEBUG(0, ("Could not start transaction\n"));
993 TALLOC_FREE(new_acct);
994 return NT_STATUS_ACCESS_DENIED;
998 /* add the new account and lock it */
999 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1003 /* Rename the posix user. Follow the semantics of _samr_create_user()
1004 so that we lower case the posix name but preserve the case in passdb */
1006 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1007 strlower_m( oldname_lower );
1009 fstrcpy( newname_lower, newname );
1010 strlower_m( newname_lower );
1012 rename_script = talloc_string_sub2(new_acct,
1019 if (!rename_script) {
1022 rename_script = talloc_string_sub2(new_acct,
1029 if (!rename_script) {
1032 rename_ret = smbrun(rename_script, NULL);
1034 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1035 rename_script, rename_ret));
1037 if (rename_ret != 0) {
1041 smb_nscd_flush_user_cache();
1043 /* rewrite the rid->username record */
1045 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1049 tdb_delete_samacct_only( old_acct );
1051 if (db_sam->transaction_commit(db_sam) != 0) {
1053 * Ok, we're screwed. We've changed the posix account, but
1054 * could not adapt passdb.tdb. Shall we change the posix
1057 DEBUG(0, ("transaction_commit failed\n"));
1058 TALLOC_FREE(new_acct);
1059 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1062 TALLOC_FREE(new_acct );
1063 return NT_STATUS_OK;
1066 if (db_sam->transaction_cancel(db_sam) != 0) {
1067 smb_panic("transaction_cancel failed");
1070 TALLOC_FREE(new_acct);
1072 return NT_STATUS_ACCESS_DENIED;
1075 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1077 return PDB_CAP_STORE_RIDS;
1080 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1085 rid = BASE_RID; /* Default if not set */
1087 if (!tdbsam_open(tdbsam_filename)) {
1088 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1093 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1095 if (!NT_STATUS_IS_OK(status)) {
1096 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1097 NEXT_RID_STRING, nt_errstr(status)));
1106 struct tdbsam_search_state {
1107 struct pdb_methods *methods;
1108 uint32_t acct_flags;
1116 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1118 struct tdbsam_search_state *state = talloc_get_type_abort(
1119 private_data, struct tdbsam_search_state);
1120 size_t prefixlen = strlen(RIDPREFIX);
1123 if ((rec->key.dsize < prefixlen)
1124 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1128 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1130 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1131 &state->array_size);
1136 static void tdbsam_search_end(struct pdb_search *search)
1138 struct tdbsam_search_state *state = talloc_get_type_abort(
1139 search->private_data, struct tdbsam_search_state);
1143 static bool tdbsam_search_next_entry(struct pdb_search *search,
1144 struct samr_displayentry *entry)
1146 struct tdbsam_search_state *state = talloc_get_type_abort(
1147 search->private_data, struct tdbsam_search_state);
1148 struct samu *user = NULL;
1154 user = samu_new(talloc_tos());
1156 DEBUG(0, ("samu_new failed\n"));
1160 if (state->current == state->num_rids) {
1164 rid = state->rids[state->current++];
1166 status = tdbsam_getsampwrid(state->methods, user, rid);
1168 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1170 * Someone has deleted that user since we listed the RIDs
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1177 nt_errstr(status)));
1182 if ((state->acct_flags != 0) &&
1183 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1187 entry->acct_flags = pdb_get_acct_ctrl(user);
1189 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1190 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1191 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1195 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1196 || (entry->description == NULL)) {
1197 DEBUG(0, ("talloc_strdup failed\n"));
1204 static bool tdbsam_search_users(struct pdb_methods *methods,
1205 struct pdb_search *search,
1208 struct tdbsam_search_state *state;
1210 if (!tdbsam_open(tdbsam_filename)) {
1211 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1216 state = talloc_zero(search, struct tdbsam_search_state);
1217 if (state == NULL) {
1218 DEBUG(0, ("talloc failed\n"));
1221 state->acct_flags = acct_flags;
1222 state->methods = methods;
1224 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1226 search->private_data = state;
1227 search->next_entry = tdbsam_search_next_entry;
1228 search->search_end = tdbsam_search_end;
1233 /*********************************************************************
1234 Initialize the tdb sam backend. Setup the dispath table of methods,
1235 open the tdb, etc...
1236 *********************************************************************/
1238 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1241 char *tdbfile = NULL;
1242 const char *pfile = location;
1244 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1248 (*pdb_method)->name = "tdbsam";
1250 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1251 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1252 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1253 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1254 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1255 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1256 (*pdb_method)->search_users = tdbsam_search_users;
1258 (*pdb_method)->capabilities = tdbsam_capabilities;
1259 (*pdb_method)->new_rid = tdbsam_new_rid;
1261 /* save the path for later */
1264 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1265 PASSDB_FILE_NAME) < 0) {
1266 return NT_STATUS_NO_MEMORY;
1270 tdbsam_filename = SMB_STRDUP(pfile);
1271 if (!tdbsam_filename) {
1272 return NT_STATUS_NO_MEMORY;
1276 /* no private data */
1278 (*pdb_method)->private_data = NULL;
1279 (*pdb_method)->free_private_data = NULL;
1281 return NT_STATUS_OK;
1284 NTSTATUS pdb_tdbsam_init(void)
1286 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);