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 "../libcli/security/security.h"
30 #if 0 /* when made a module use this */
32 static int tdbsam_debug_level = DBGC_ALL;
34 #define DBGC_CLASS tdbsam_debug_level
39 #define DBGC_CLASS DBGC_PASSDB
43 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
44 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
45 #define TDBSAM_VERSION_STRING "INFO/version"
46 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
47 #define PASSDB_FILE_NAME "passdb.tdb"
48 #define USERPREFIX "USER_"
49 #define USERPREFIX_LEN 5
50 #define RIDPREFIX "RID_"
51 #define PRIVPREFIX "PRIV_"
52 #define NEXT_RID_STRING "NEXT_RID"
54 /* GLOBAL TDB SAM CONTEXT */
56 static struct db_context *db_sam;
57 static char *tdbsam_filename;
59 struct tdbsam_convert_state {
64 static int tdbsam_convert_one(struct db_record *rec, void *priv)
66 struct tdbsam_convert_state *state =
67 (struct tdbsam_convert_state *)priv;
73 if (rec->key.dsize < USERPREFIX_LEN) {
76 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
80 user = samu_new(talloc_tos());
82 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
83 state->success = false;
87 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
88 "(version:%d)\n", rec->key.dptr, state->from));
90 switch (state->from) {
92 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
93 (uint8 *)rec->value.dptr,
97 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
98 (uint8 *)rec->value.dptr,
102 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
103 (uint8 *)rec->value.dptr,
107 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
108 (uint8 *)rec->value.dptr,
112 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
113 (uint8 *)rec->value.dptr,
117 /* unknown tdbsam version */
121 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
122 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
125 state->success = false;
129 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
132 if (data.dsize == -1) {
133 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
134 "the new format\n"));
135 state->success = false;
139 status = rec->store(rec, data, TDB_MODIFY);
140 if (!NT_STATUS_IS_OK(status)) {
141 DEBUG(0, ("Could not store the new record: %s\n",
143 state->success = false;
150 /**********************************************************************
151 Struct and function to backup an old record.
152 *********************************************************************/
154 struct tdbsam_backup_state {
155 struct db_context *new_db;
159 static int backup_copy_fn(struct db_record *orig_rec, void *state)
161 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
162 struct db_record *new_rec;
165 new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
166 if (new_rec == NULL) {
171 status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
173 TALLOC_FREE(new_rec);
175 if (!NT_STATUS_IS_OK(status)) {
182 /**********************************************************************
183 Make a backup of an old passdb and replace the new one with it. We
184 have to do this as between 3.0.x and 3.2.x the hash function changed
185 by mistake (used unsigned char * instead of char *). This means the
186 previous simple update code will fail due to not being able to find
187 existing records to replace in the tdbsam_convert_one() function. JRA.
188 *********************************************************************/
190 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
192 TALLOC_CTX *frame = talloc_stackframe();
193 const char *tmp_fname = NULL;
194 struct db_context *tmp_db = NULL;
195 struct db_context *orig_db = *pp_db;
196 struct tdbsam_backup_state bs;
199 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
207 /* Remember to open this on the NULL context. We need
208 * it to stay around after we return from here. */
210 tmp_db = db_open(NULL, tmp_fname, 0,
211 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
212 if (tmp_db == NULL) {
213 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
214 "[%s]\n", tmp_fname));
219 if (orig_db->transaction_start(orig_db) != 0) {
220 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
226 if (tmp_db->transaction_start(tmp_db) != 0) {
227 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
228 orig_db->transaction_cancel(orig_db);
238 ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
240 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
245 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
249 if (orig_db->transaction_commit(orig_db) != 0) {
250 smb_panic("tdbsam_convert_backup: orig commit failed\n");
252 if (tmp_db->transaction_commit(tmp_db) != 0) {
253 smb_panic("tdbsam_convert_backup: orig commit failed\n");
256 /* be sure to close the DBs _before_ renaming the file */
258 TALLOC_FREE(orig_db);
261 /* This is safe from other users as we know we're
262 * under a mutex here. */
264 if (rename(tmp_fname, dbname) == -1) {
265 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
269 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
274 /* re-open the converted TDB */
276 orig_db = db_open(NULL, dbname, 0,
277 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
278 if (orig_db == NULL) {
279 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
280 "converted passdb TDB [%s]\n", dbname));
284 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
287 /* Replace the global db pointer. */
293 if (orig_db->transaction_cancel(orig_db) != 0) {
294 smb_panic("tdbsam_convert: transaction_cancel failed");
297 if (tmp_db->transaction_cancel(tmp_db) != 0) {
298 smb_panic("tdbsam_convert: transaction_cancel failed");
307 static bool tdbsam_upgrade_next_rid(struct db_context *db)
313 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
318 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
319 TDB_DEFAULT, O_RDONLY, 0644);
322 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
331 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
338 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
340 struct tdbsam_convert_state state;
341 struct db_context *db = NULL;
344 /* We only need the update backup for local db's. */
345 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
346 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
352 state.success = true;
354 if (db->transaction_start(db) != 0) {
355 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
359 if (!tdbsam_upgrade_next_rid(db)) {
360 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
364 ret = db->traverse(db, tdbsam_convert_one, &state);
366 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
370 if (!state.success) {
371 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
375 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
376 TDBSAM_VERSION) != 0) {
377 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
381 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
382 TDBSAM_MINOR_VERSION) != 0) {
383 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
387 if (db->transaction_commit(db) != 0) {
388 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
395 if (db->transaction_cancel(db) != 0) {
396 smb_panic("tdbsam_convert: transaction_cancel failed");
402 /*********************************************************************
403 Open the tdbsam file based on the absolute path specified.
404 Uses a reference count to allow multiple open calls.
405 *********************************************************************/
407 static bool tdbsam_open( const char *name )
412 /* check if we are already open */
418 /* Try to open tdb passwd. Create a new one if necessary */
420 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
421 if (db_sam == NULL) {
422 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
427 /* Check the version */
428 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
430 version = 0; /* Version not found, assume version 0 */
433 /* Get the minor version */
434 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
435 if (minor_version == -1) {
436 minor_version = 0; /* Minor version not found, assume 0 */
439 /* Compare the version */
440 if (version > TDBSAM_VERSION) {
441 /* Version more recent than the latest known */
442 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
447 if ( version < TDBSAM_VERSION ||
448 (version == TDBSAM_VERSION &&
449 minor_version < TDBSAM_MINOR_VERSION) ) {
451 * Ok - we think we're going to have to convert.
452 * Due to the backup process we now must do to
453 * upgrade we have to get a mutex and re-check
454 * the version. Someone else may have upgraded
455 * whilst we were checking.
458 struct named_mutex *mtx = grab_named_mutex(NULL,
459 "tdbsam_upgrade_mutex",
463 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
468 /* Re-check the version */
469 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
471 version = 0; /* Version not found, assume version 0 */
474 /* Re-check the minor version */
475 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
476 if (minor_version == -1) {
477 minor_version = 0; /* Minor version not found, assume 0 */
480 /* Compare the version */
481 if (version > TDBSAM_VERSION) {
482 /* Version more recent than the latest known */
483 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
489 if ( version < TDBSAM_VERSION ||
490 (version == TDBSAM_VERSION &&
491 minor_version < TDBSAM_MINOR_VERSION) ) {
493 * Note that minor versions we read that are greater
494 * than the current minor version we have hard coded
495 * are assumed to be compatible if they have the same
496 * major version. That allows previous versions of the
497 * passdb code that don't know about minor versions to
498 * still use this database. JRA.
501 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
506 TDBSAM_MINOR_VERSION));
508 if ( !tdbsam_convert(&db_sam, name, version) ) {
509 DEBUG(0, ("tdbsam_open: Error when trying to convert "
510 "tdbsam [%s]\n",name));
516 DEBUG(3, ("TDBSAM converted successfully.\n"));
521 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
526 /******************************************************************
527 Lookup a name in the SAM TDB
528 ******************************************************************/
530 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
531 struct samu *user, const char *sname)
538 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
539 return NT_STATUS_NO_MEMORY;
542 /* Data is stored in all lower-case */
543 fstrcpy(name, sname);
547 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
549 /* open the database */
551 if ( !tdbsam_open( tdbsam_filename ) ) {
552 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
553 return NT_STATUS_ACCESS_DENIED;
558 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
560 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
561 DEBUGADD(5, (" Key: %s\n", keystr));
562 return NT_STATUS_NO_SUCH_USER;
565 /* unpack the buffer */
567 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
568 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
569 SAFE_FREE(data.dptr);
570 return NT_STATUS_NO_MEMORY;
575 TALLOC_FREE(data.dptr);
580 /***************************************************************************
582 **************************************************************************/
584 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
585 struct samu *user, uint32 rid)
587 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
593 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
599 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
601 /* open the database */
603 if ( !tdbsam_open( tdbsam_filename ) ) {
604 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
605 return NT_STATUS_ACCESS_DENIED;
610 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
612 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
613 return NT_STATUS_UNSUCCESSFUL;
616 fstrcpy(name, (const char *)data.dptr);
617 TALLOC_FREE(data.dptr);
619 return tdbsam_getsampwnam (my_methods, user, name);
622 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
623 struct samu * user, const struct dom_sid *sid)
627 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
628 return NT_STATUS_UNSUCCESSFUL;
630 return tdbsam_getsampwrid(my_methods, user, rid);
633 static bool tdb_delete_samacct_only( struct samu *sam_pass )
639 fstrcpy(name, pdb_get_username(sam_pass));
642 /* set the search key */
644 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
646 /* it's outaa here! 8^) */
647 if ( !tdbsam_open( tdbsam_filename ) ) {
648 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
653 status = dbwrap_delete_bystring(db_sam, keystr);
654 if (!NT_STATUS_IS_OK(status)) {
655 DEBUG(5, ("Error deleting entry from tdb passwd "
656 "database: %s!\n", nt_errstr(status)));
663 /***************************************************************************
664 Delete a struct samu records for the username and RID key
665 ****************************************************************************/
667 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
668 struct samu *sam_pass)
670 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
675 /* open the database */
677 if ( !tdbsam_open( tdbsam_filename ) ) {
678 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
680 return NT_STATUS_ACCESS_DENIED;
683 fstrcpy(name, pdb_get_username(sam_pass));
686 /* set the search key */
688 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
690 rid = pdb_get_user_rid(sam_pass);
692 /* it's outaa here! 8^) */
694 if (db_sam->transaction_start(db_sam) != 0) {
695 DEBUG(0, ("Could not start transaction\n"));
696 return NT_STATUS_UNSUCCESSFUL;
699 nt_status = dbwrap_delete_bystring(db_sam, keystr);
700 if (!NT_STATUS_IS_OK(nt_status)) {
701 DEBUG(5, ("Error deleting entry from tdb passwd "
702 "database: %s!\n", nt_errstr(nt_status)));
706 /* set the search key */
708 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
710 /* it's outaa here! 8^) */
712 nt_status = dbwrap_delete_bystring(db_sam, keystr);
713 if (!NT_STATUS_IS_OK(nt_status)) {
714 DEBUG(5, ("Error deleting entry from tdb rid "
715 "database: %s!\n", nt_errstr(nt_status)));
719 if (db_sam->transaction_commit(db_sam) != 0) {
720 DEBUG(0, ("Could not commit transaction\n"));
721 return NT_STATUS_INTERNAL_DB_CORRUPTION;
727 if (db_sam->transaction_cancel(db_sam) != 0) {
728 smb_panic("transaction_cancel failed");
735 /***************************************************************************
736 Update the TDB SAM account record only
737 Assumes that the tdbsam is already open
738 ****************************************************************************/
739 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
748 /* copy the struct samu struct into a BYTE buffer for storage */
750 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
751 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
756 fstrcpy(name, pdb_get_username(newpwd));
759 DEBUG(5, ("Storing %saccount %s with RID %d\n",
760 flag == TDB_INSERT ? "(new) " : "", name,
761 pdb_get_user_rid(newpwd)));
763 /* setup the USER index key */
764 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
766 /* add the account */
768 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
769 if (!NT_STATUS_IS_OK(status)) {
770 DEBUG(0, ("Unable to modify passwd TDB: %s!",
783 /***************************************************************************
784 Update the TDB SAM RID record only
785 Assumes that the tdbsam is already open
786 ****************************************************************************/
787 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
794 fstrcpy(name, pdb_get_username(newpwd));
798 data = string_term_tdb_data(name);
800 /* setup the RID index key */
801 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
802 pdb_get_user_rid(newpwd));
804 /* add the reference */
805 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
806 if (!NT_STATUS_IS_OK(status)) {
807 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
816 /***************************************************************************
818 ****************************************************************************/
820 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
826 if (!(newrid = pdb_get_user_rid(newpwd))) {
827 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
828 pdb_get_username(newpwd)));
834 /* open the database */
836 if ( !tdbsam_open( tdbsam_filename ) ) {
837 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
841 if (db_sam->transaction_start(db_sam) != 0) {
842 DEBUG(0, ("Could not start transaction\n"));
846 /* If we are updating, we may be changing this users RID. Retrieve the old RID
849 if (flag == TDB_MODIFY) {
850 struct samu *account = samu_new(talloc_tos());
851 if (account == NULL) {
852 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
855 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
856 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
857 pdb_get_username(newpwd)));
858 TALLOC_FREE(account);
861 if (!(oldrid = pdb_get_user_rid(account))) {
862 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
863 TALLOC_FREE(account);
866 TALLOC_FREE(account);
869 /* Update the new samu entry. */
870 if (!tdb_update_samacct_only(newpwd, flag)) {
874 /* Now take care of the case where the RID changed. We need
875 * to delete the old RID key and add the new. */
877 if (flag == TDB_MODIFY && newrid != oldrid) {
880 /* Delete old RID key */
881 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
882 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
883 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
884 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
887 /* Insert new RID key */
888 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
889 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
893 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
894 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
895 if (!tdb_update_ridrec_only(newpwd, flag)) {
900 if (db_sam->transaction_commit(db_sam) != 0) {
901 DEBUG(0, ("Could not commit transaction\n"));
908 if (db_sam->transaction_cancel(db_sam) != 0) {
909 smb_panic("transaction_cancel failed");
914 /***************************************************************************
915 Modifies an existing struct samu
916 ****************************************************************************/
918 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
920 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
921 return NT_STATUS_UNSUCCESSFUL;
926 /***************************************************************************
927 Adds an existing struct samu
928 ****************************************************************************/
930 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
932 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
933 return NT_STATUS_UNSUCCESSFUL;
938 /***************************************************************************
939 Renames a struct samu
940 - check for the posix user/rename user script
941 - Add and lock the new user record
942 - rename the posix user
943 - rewrite the rid->username record
944 - delete the old user
945 - unlock the new user record
946 ***************************************************************************/
947 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
948 struct samu *old_acct,
951 struct samu *new_acct = NULL;
952 char *rename_script = NULL;
954 fstring oldname_lower;
955 fstring newname_lower;
957 /* can't do anything without an external script */
959 if ( !(new_acct = samu_new( talloc_tos() )) ) {
960 return NT_STATUS_NO_MEMORY;
963 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
964 if (!rename_script) {
965 TALLOC_FREE(new_acct);
966 return NT_STATUS_NO_MEMORY;
968 if (!*rename_script) {
969 TALLOC_FREE(new_acct);
970 return NT_STATUS_ACCESS_DENIED;
973 if ( !pdb_copy_sam_account(new_acct, old_acct)
974 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
976 TALLOC_FREE(new_acct);
977 return NT_STATUS_NO_MEMORY;
980 /* open the database */
981 if ( !tdbsam_open( tdbsam_filename ) ) {
982 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
984 TALLOC_FREE(new_acct);
985 return NT_STATUS_ACCESS_DENIED;
988 if (db_sam->transaction_start(db_sam) != 0) {
989 DEBUG(0, ("Could not start transaction\n"));
990 TALLOC_FREE(new_acct);
991 return NT_STATUS_ACCESS_DENIED;
995 /* add the new account and lock it */
996 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1000 /* Rename the posix user. Follow the semantics of _samr_create_user()
1001 so that we lower case the posix name but preserve the case in passdb */
1003 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1004 strlower_m( oldname_lower );
1006 fstrcpy( newname_lower, newname );
1007 strlower_m( newname_lower );
1009 rename_script = talloc_string_sub2(new_acct,
1016 if (!rename_script) {
1019 rename_script = talloc_string_sub2(new_acct,
1026 if (!rename_script) {
1029 rename_ret = smbrun(rename_script, NULL);
1031 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1032 rename_script, rename_ret));
1034 if (rename_ret != 0) {
1038 smb_nscd_flush_user_cache();
1040 /* rewrite the rid->username record */
1042 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1046 tdb_delete_samacct_only( old_acct );
1048 if (db_sam->transaction_commit(db_sam) != 0) {
1050 * Ok, we're screwed. We've changed the posix account, but
1051 * could not adapt passdb.tdb. Shall we change the posix
1054 DEBUG(0, ("transaction_commit failed\n"));
1055 TALLOC_FREE(new_acct);
1056 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1059 TALLOC_FREE(new_acct );
1060 return NT_STATUS_OK;
1063 if (db_sam->transaction_cancel(db_sam) != 0) {
1064 smb_panic("transaction_cancel failed");
1067 TALLOC_FREE(new_acct);
1069 return NT_STATUS_ACCESS_DENIED;
1072 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1074 return PDB_CAP_STORE_RIDS;
1077 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1082 rid = BASE_RID; /* Default if not set */
1084 if (!tdbsam_open(tdbsam_filename)) {
1085 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1090 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1092 if (!NT_STATUS_IS_OK(status)) {
1093 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1094 NEXT_RID_STRING, nt_errstr(status)));
1103 struct tdbsam_search_state {
1104 struct pdb_methods *methods;
1105 uint32_t acct_flags;
1113 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1115 struct tdbsam_search_state *state = talloc_get_type_abort(
1116 private_data, struct tdbsam_search_state);
1117 size_t prefixlen = strlen(RIDPREFIX);
1120 if ((rec->key.dsize < prefixlen)
1121 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1125 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1127 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1128 &state->array_size);
1133 static void tdbsam_search_end(struct pdb_search *search)
1135 struct tdbsam_search_state *state = talloc_get_type_abort(
1136 search->private_data, struct tdbsam_search_state);
1140 static bool tdbsam_search_next_entry(struct pdb_search *search,
1141 struct samr_displayentry *entry)
1143 struct tdbsam_search_state *state = talloc_get_type_abort(
1144 search->private_data, struct tdbsam_search_state);
1145 struct samu *user = NULL;
1151 user = samu_new(talloc_tos());
1153 DEBUG(0, ("samu_new failed\n"));
1157 if (state->current == state->num_rids) {
1161 rid = state->rids[state->current++];
1163 status = tdbsam_getsampwrid(state->methods, user, rid);
1165 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1167 * Someone has deleted that user since we listed the RIDs
1172 if (!NT_STATUS_IS_OK(status)) {
1173 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1174 nt_errstr(status)));
1179 if ((state->acct_flags != 0) &&
1180 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1184 entry->acct_flags = pdb_get_acct_ctrl(user);
1186 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1187 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1188 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1192 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1193 || (entry->description == NULL)) {
1194 DEBUG(0, ("talloc_strdup failed\n"));
1201 static bool tdbsam_search_users(struct pdb_methods *methods,
1202 struct pdb_search *search,
1205 struct tdbsam_search_state *state;
1207 if (!tdbsam_open(tdbsam_filename)) {
1208 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1213 state = talloc_zero(search, struct tdbsam_search_state);
1214 if (state == NULL) {
1215 DEBUG(0, ("talloc failed\n"));
1218 state->acct_flags = acct_flags;
1219 state->methods = methods;
1221 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1223 search->private_data = state;
1224 search->next_entry = tdbsam_search_next_entry;
1225 search->search_end = tdbsam_search_end;
1230 /*********************************************************************
1231 Initialize the tdb sam backend. Setup the dispath table of methods,
1232 open the tdb, etc...
1233 *********************************************************************/
1235 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1238 char *tdbfile = NULL;
1239 const char *pfile = location;
1241 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1245 (*pdb_method)->name = "tdbsam";
1247 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1248 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1249 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1250 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1251 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1252 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1253 (*pdb_method)->search_users = tdbsam_search_users;
1255 (*pdb_method)->capabilities = tdbsam_capabilities;
1256 (*pdb_method)->new_rid = tdbsam_new_rid;
1258 /* save the path for later */
1261 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1262 PASSDB_FILE_NAME) < 0) {
1263 return NT_STATUS_NO_MEMORY;
1267 tdbsam_filename = SMB_STRDUP(pfile);
1268 if (!tdbsam_filename) {
1269 return NT_STATUS_NO_MEMORY;
1273 /* no private data */
1275 (*pdb_method)->private_data = NULL;
1276 (*pdb_method)->free_private_data = NULL;
1278 return NT_STATUS_OK;
1281 NTSTATUS pdb_tdbsam_init(void)
1283 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);