tdbsam: RID/SID change issue + patch

Jeremy Allison jra at samba.org
Thu Apr 2 03:17:25 GMT 2009


On Wed, Mar 18, 2009 at 08:44:51PM +0300, Alexander Zagrebin wrote:
> I'm using samba 3.3.2
> I have found, that, when using tdbsam, pdbedit refuses to change account's
> rid/sid.
> 
> # pdbedit -U 3000 -u test
> Unable to modify TDB passwd: NT_STATUS_UNSUCCESSFUL!
> Unable to modify entry!
> 
> Suppose we have changed RID from <old_rid> to <new_rid>.
> When updating account information with changed RID, pdbedit tries to update
> key USER_<username> and
> key RID_<new_rid>. But passdb.tdb contains RID_<old_rid>, but not
> RID_<new_rid>.
> That's a source of above described error.
> So instead of updating RID_<new_rid> pdbedit have to delete RID_<old_rid>
> and add 
> RID_<new_rid>.
> 
> The attached patch resolves this issue.

I modified this some to fit our current coding standards
(and fix a couple of memory leaks on error paths). This
is what I've committed to all trees.

Thanks a *lot* for the fix !

Jeremy.
-------------- next part --------------
diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c
index 73814ef..b35d209 100644
--- a/source/passdb/pdb_tdb.c
+++ b/source/passdb/pdb_tdb.c
@@ -817,12 +817,17 @@ static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
 			   int flag)
 {
-	if (!pdb_get_user_rid(newpwd)) {
+	uint32_t oldrid;
+	uint32_t newrid;
+
+	if (!(newrid = pdb_get_user_rid(newpwd))) {
 		DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
 			 pdb_get_username(newpwd)));
 		return False;
 	}
 
+	oldrid = newrid;
+
 	/* open the database */
 
 	if ( !tdbsam_open( tdbsam_filename ) ) {
@@ -835,11 +840,60 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
 		return false;
 	}
 
-	if (!tdb_update_samacct_only(newpwd, flag)
-	    || !tdb_update_ridrec_only(newpwd, flag)) {
+	/* If we are updating, we may be changing this users RID. Retrieve the old RID
+	   so we can check. */
+
+	if (flag == TDB_MODIFY) {
+		struct samu *account = samu_new(talloc_tos());
+		if (account == NULL) {
+			DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
+			goto cancel;
+		}
+		if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
+			DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
+				pdb_get_username(newpwd)));
+			TALLOC_FREE(account);
+			goto cancel;
+		}
+		if (!(oldrid = pdb_get_user_rid(account))) {
+			DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
+			TALLOC_FREE(account);
+			goto cancel;
+		}
+		TALLOC_FREE(account);
+	}
+
+	/* Update the new samu entry. */
+	if (!tdb_update_samacct_only(newpwd, flag)) {
 		goto cancel;
 	}
 
+	/* Now take care of the case where the RID changed. We need
+	 * to delete the old RID key and add the new. */
+
+	if (flag == TDB_MODIFY && newrid != oldrid) { 
+		fstring keystr;
+
+		/* Delete old RID key */
+		DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
+		slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
+		if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
+			DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
+			goto cancel;
+		}
+		/* Insert new RID key */
+		DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
+		if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
+			goto cancel;
+		}
+	} else {
+		DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
+			flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
+		if (!tdb_update_ridrec_only(newpwd, flag)) {
+			goto cancel;
+		}
+	}
+
 	if (db_sam->transaction_commit(db_sam) != 0) {
 		DEBUG(0, ("Could not commit transaction\n"));
 		return false;


More information about the samba-technical mailing list