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 DBWRAP_LOCK_ORDER_1
);
229 if (tmp_db
== NULL
) {
230 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
231 "[%s]\n", tmp_fname
));
236 if (dbwrap_transaction_start(orig_db
) != 0) {
237 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
243 if (dbwrap_transaction_start(tmp_db
) != 0) {
244 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
245 dbwrap_transaction_cancel(orig_db
);
255 status
= dbwrap_traverse(orig_db
, backup_copy_fn
, (void *)&bs
, NULL
);
256 if (!NT_STATUS_IS_OK(status
)) {
257 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
262 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
266 if (dbwrap_transaction_commit(orig_db
) != 0) {
267 smb_panic("tdbsam_convert_backup: orig commit failed\n");
269 if (dbwrap_transaction_commit(tmp_db
) != 0) {
270 smb_panic("tdbsam_convert_backup: orig commit failed\n");
273 /* be sure to close the DBs _before_ renaming the file */
275 TALLOC_FREE(orig_db
);
278 /* This is safe from other users as we know we're
279 * under a mutex here. */
281 if (rename(tmp_fname
, dbname
) == -1) {
282 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
286 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
291 /* re-open the converted TDB */
293 orig_db
= db_open(NULL
, dbname
, 0,
294 TDB_DEFAULT
, O_CREAT
|O_RDWR
, 0600,
295 DBWRAP_LOCK_ORDER_1
);
296 if (orig_db
== NULL
) {
297 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
298 "converted passdb TDB [%s]\n", dbname
));
302 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
305 /* Replace the global db pointer. */
311 if (dbwrap_transaction_cancel(orig_db
) != 0) {
312 smb_panic("tdbsam_convert: transaction_cancel failed");
315 if (dbwrap_transaction_cancel(tmp_db
) != 0) {
316 smb_panic("tdbsam_convert: transaction_cancel failed");
325 static bool tdbsam_upgrade_next_rid(struct db_context
*db
)
332 status
= dbwrap_fetch_uint32_bystring(db
, NEXT_RID_STRING
, &rid
);
333 if (NT_STATUS_IS_OK(status
)) {
337 tdb
= tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
338 TDB_DEFAULT
, O_RDONLY
, 0644);
341 ok
= tdb_fetch_uint32(tdb
, "RID_COUNTER", &rid
);
350 status
= dbwrap_store_uint32_bystring(db
, NEXT_RID_STRING
, rid
);
351 if (!NT_STATUS_IS_OK(status
)) {
358 static bool tdbsam_convert(struct db_context
**pp_db
, const char *name
, int32 from
)
360 struct tdbsam_convert_state state
;
361 struct db_context
*db
= NULL
;
364 /* We only need the update backup for local db's. */
365 if (db_is_local(name
) && !tdbsam_convert_backup(name
, pp_db
)) {
366 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name
));
372 state
.success
= true;
374 if (dbwrap_transaction_start(db
) != 0) {
375 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
379 if (!tdbsam_upgrade_next_rid(db
)) {
380 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
384 status
= dbwrap_traverse(db
, tdbsam_convert_one
, &state
, NULL
);
385 if (!NT_STATUS_IS_OK(status
)) {
386 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
390 if (!state
.success
) {
391 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
395 status
= dbwrap_store_int32_bystring(db
, TDBSAM_VERSION_STRING
,
397 if (!NT_STATUS_IS_OK(status
)) {
398 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
399 "%s\n", nt_errstr(status
)));
403 status
= dbwrap_store_int32_bystring(db
, TDBSAM_MINOR_VERSION_STRING
,
404 TDBSAM_MINOR_VERSION
);
405 if (!NT_STATUS_IS_OK(status
)) {
406 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
407 "version: %s\n", nt_errstr(status
)));
411 if (dbwrap_transaction_commit(db
) != 0) {
412 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
419 if (dbwrap_transaction_cancel(db
) != 0) {
420 smb_panic("tdbsam_convert: transaction_cancel failed");
426 /*********************************************************************
427 Open the tdbsam file based on the absolute path specified.
428 Uses a reference count to allow multiple open calls.
429 *********************************************************************/
431 static bool tdbsam_open( const char *name
)
437 /* check if we are already open */
443 /* Try to open tdb passwd. Create a new one if necessary */
445 db_sam
= db_open(NULL
, name
, 0, TDB_DEFAULT
, O_CREAT
|O_RDWR
, 0600,
446 DBWRAP_LOCK_ORDER_1
);
447 if (db_sam
== NULL
) {
448 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
453 /* Check the version */
454 status
= dbwrap_fetch_int32_bystring(db_sam
, TDBSAM_VERSION_STRING
,
456 if (!NT_STATUS_IS_OK(status
)) {
457 version
= 0; /* Version not found, assume version 0 */
460 /* Get the minor version */
461 status
= dbwrap_fetch_int32_bystring(
462 db_sam
, TDBSAM_MINOR_VERSION_STRING
, &minor_version
);
463 if (!NT_STATUS_IS_OK(status
)) {
464 minor_version
= 0; /* Minor version not found, assume 0 */
467 /* Compare the version */
468 if (version
> TDBSAM_VERSION
) {
469 /* Version more recent than the latest known */
470 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version
));
475 if ( version
< TDBSAM_VERSION
||
476 (version
== TDBSAM_VERSION
&&
477 minor_version
< TDBSAM_MINOR_VERSION
) ) {
479 * Ok - we think we're going to have to convert.
480 * Due to the backup process we now must do to
481 * upgrade we have to get a mutex and re-check
482 * the version. Someone else may have upgraded
483 * whilst we were checking.
486 struct named_mutex
*mtx
= grab_named_mutex(NULL
,
487 "tdbsam_upgrade_mutex",
491 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
496 /* Re-check the version */
497 status
= dbwrap_fetch_int32_bystring(
498 db_sam
, TDBSAM_VERSION_STRING
, &version
);
499 if (!NT_STATUS_IS_OK(status
)) {
500 version
= 0; /* Version not found, assume version 0 */
503 /* Re-check the minor version */
504 status
= dbwrap_fetch_int32_bystring(
505 db_sam
, TDBSAM_MINOR_VERSION_STRING
, &minor_version
);
506 if (!NT_STATUS_IS_OK(status
)) {
507 minor_version
= 0; /* Minor version not found, assume 0 */
510 /* Compare the version */
511 if (version
> TDBSAM_VERSION
) {
512 /* Version more recent than the latest known */
513 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version
));
519 if ( version
< TDBSAM_VERSION
||
520 (version
== TDBSAM_VERSION
&&
521 minor_version
< TDBSAM_MINOR_VERSION
) ) {
523 * Note that minor versions we read that are greater
524 * than the current minor version we have hard coded
525 * are assumed to be compatible if they have the same
526 * major version. That allows previous versions of the
527 * passdb code that don't know about minor versions to
528 * still use this database. JRA.
531 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
536 TDBSAM_MINOR_VERSION
));
538 if ( !tdbsam_convert(&db_sam
, name
, version
) ) {
539 DEBUG(0, ("tdbsam_open: Error when trying to convert "
540 "tdbsam [%s]\n",name
));
546 DEBUG(3, ("TDBSAM converted successfully.\n"));
551 DEBUG(4,("tdbsam_open: successfully opened %s\n", name
));
556 /******************************************************************
557 Lookup a name in the SAM TDB
558 ******************************************************************/
560 static NTSTATUS
tdbsam_getsampwnam (struct pdb_methods
*my_methods
,
561 struct samu
*user
, const char *sname
)
569 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
570 return NT_STATUS_NO_MEMORY
;
573 /* Data is stored in all lower-case */
574 fstrcpy(name
, sname
);
578 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
580 /* open the database */
582 if ( !tdbsam_open( tdbsam_filename
) ) {
583 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename
));
584 return NT_STATUS_ACCESS_DENIED
;
589 status
= dbwrap_fetch_bystring(db_sam
, talloc_tos(), keystr
, &data
);
590 if (!NT_STATUS_IS_OK(status
)) {
591 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
592 DEBUGADD(5, (" Key: %s\n", keystr
));
593 return NT_STATUS_NO_SUCH_USER
;
596 /* unpack the buffer */
598 if (!init_samu_from_buffer(user
, SAMU_BUFFER_LATEST
, data
.dptr
, data
.dsize
)) {
599 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
600 SAFE_FREE(data
.dptr
);
601 return NT_STATUS_NO_MEMORY
;
606 TALLOC_FREE(data
.dptr
);
611 /***************************************************************************
613 **************************************************************************/
615 static NTSTATUS
tdbsam_getsampwrid (struct pdb_methods
*my_methods
,
616 struct samu
*user
, uint32 rid
)
618 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
624 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
630 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
, rid
);
632 /* open the database */
634 if ( !tdbsam_open( tdbsam_filename
) ) {
635 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename
));
636 return NT_STATUS_ACCESS_DENIED
;
641 nt_status
= dbwrap_fetch_bystring(db_sam
, talloc_tos(), keystr
, &data
);
642 if (!NT_STATUS_IS_OK(nt_status
)) {
643 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid
, keystr
));
647 fstrcpy(name
, (const char *)data
.dptr
);
648 TALLOC_FREE(data
.dptr
);
650 return tdbsam_getsampwnam (my_methods
, user
, name
);
653 static NTSTATUS
tdbsam_getsampwsid(struct pdb_methods
*my_methods
,
654 struct samu
* user
, const struct dom_sid
*sid
)
658 if ( !sid_peek_check_rid(get_global_sam_sid(), sid
, &rid
) )
659 return NT_STATUS_UNSUCCESSFUL
;
661 return tdbsam_getsampwrid(my_methods
, user
, rid
);
664 static bool tdb_delete_samacct_only( struct samu
*sam_pass
)
670 fstrcpy(name
, pdb_get_username(sam_pass
));
673 /* set the search key */
675 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
677 /* it's outaa here! 8^) */
678 if ( !tdbsam_open( tdbsam_filename
) ) {
679 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
684 status
= dbwrap_delete_bystring(db_sam
, keystr
);
685 if (!NT_STATUS_IS_OK(status
)) {
686 DEBUG(5, ("Error deleting entry from tdb passwd "
687 "database: %s!\n", nt_errstr(status
)));
694 /***************************************************************************
695 Delete a struct samu records for the username and RID key
696 ****************************************************************************/
698 static NTSTATUS
tdbsam_delete_sam_account(struct pdb_methods
*my_methods
,
699 struct samu
*sam_pass
)
701 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
706 /* open the database */
708 if ( !tdbsam_open( tdbsam_filename
) ) {
709 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
711 return NT_STATUS_ACCESS_DENIED
;
714 fstrcpy(name
, pdb_get_username(sam_pass
));
717 /* set the search key */
719 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
721 rid
= pdb_get_user_rid(sam_pass
);
723 /* it's outaa here! 8^) */
725 if (dbwrap_transaction_start(db_sam
) != 0) {
726 DEBUG(0, ("Could not start transaction\n"));
727 return NT_STATUS_UNSUCCESSFUL
;
730 nt_status
= dbwrap_delete_bystring(db_sam
, keystr
);
731 if (!NT_STATUS_IS_OK(nt_status
)) {
732 DEBUG(5, ("Error deleting entry from tdb passwd "
733 "database: %s!\n", nt_errstr(nt_status
)));
737 /* set the search key */
739 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
, rid
);
741 /* it's outaa here! 8^) */
743 nt_status
= dbwrap_delete_bystring(db_sam
, keystr
);
744 if (!NT_STATUS_IS_OK(nt_status
)) {
745 DEBUG(5, ("Error deleting entry from tdb rid "
746 "database: %s!\n", nt_errstr(nt_status
)));
750 if (dbwrap_transaction_commit(db_sam
) != 0) {
751 DEBUG(0, ("Could not commit transaction\n"));
752 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
758 if (dbwrap_transaction_cancel(db_sam
) != 0) {
759 smb_panic("transaction_cancel failed");
766 /***************************************************************************
767 Update the TDB SAM account record only
768 Assumes that the tdbsam is already open
769 ****************************************************************************/
770 static bool tdb_update_samacct_only( struct samu
* newpwd
, int flag
)
779 /* copy the struct samu struct into a BYTE buffer for storage */
781 if ( (data
.dsize
=init_buffer_from_samu(&buf
, newpwd
, False
)) == -1 ) {
782 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
787 fstrcpy(name
, pdb_get_username(newpwd
));
790 DEBUG(5, ("Storing %saccount %s with RID %d\n",
791 flag
== TDB_INSERT
? "(new) " : "", name
,
792 pdb_get_user_rid(newpwd
)));
794 /* setup the USER index key */
795 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
797 /* add the account */
799 status
= dbwrap_store_bystring(db_sam
, keystr
, data
, flag
);
800 if (!NT_STATUS_IS_OK(status
)) {
801 DEBUG(0, ("Unable to modify passwd TDB: %s!",
814 /***************************************************************************
815 Update the TDB SAM RID record only
816 Assumes that the tdbsam is already open
817 ****************************************************************************/
818 static bool tdb_update_ridrec_only( struct samu
* newpwd
, int flag
)
825 fstrcpy(name
, pdb_get_username(newpwd
));
829 data
= string_term_tdb_data(name
);
831 /* setup the RID index key */
832 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
,
833 pdb_get_user_rid(newpwd
));
835 /* add the reference */
836 status
= dbwrap_store_bystring(db_sam
, keystr
, data
, flag
);
837 if (!NT_STATUS_IS_OK(status
)) {
838 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
847 /***************************************************************************
849 ****************************************************************************/
851 static bool tdb_update_sam(struct pdb_methods
*my_methods
, struct samu
* newpwd
,
857 if (!(newrid
= pdb_get_user_rid(newpwd
))) {
858 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
859 pdb_get_username(newpwd
)));
865 /* open the database */
867 if ( !tdbsam_open( tdbsam_filename
) ) {
868 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename
));
872 if (dbwrap_transaction_start(db_sam
) != 0) {
873 DEBUG(0, ("Could not start transaction\n"));
877 /* If we are updating, we may be changing this users RID. Retrieve the old RID
880 if (flag
== TDB_MODIFY
) {
881 struct samu
*account
= samu_new(talloc_tos());
882 if (account
== NULL
) {
883 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
886 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods
, account
, pdb_get_username(newpwd
)))) {
887 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
888 pdb_get_username(newpwd
)));
889 TALLOC_FREE(account
);
892 if (!(oldrid
= pdb_get_user_rid(account
))) {
893 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
894 TALLOC_FREE(account
);
897 TALLOC_FREE(account
);
900 /* Update the new samu entry. */
901 if (!tdb_update_samacct_only(newpwd
, flag
)) {
905 /* Now take care of the case where the RID changed. We need
906 * to delete the old RID key and add the new. */
908 if (flag
== TDB_MODIFY
&& newrid
!= oldrid
) {
911 /* Delete old RID key */
912 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid
));
913 slprintf(keystr
, sizeof(keystr
) - 1, "%s%.8x", RIDPREFIX
, oldrid
);
914 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam
, keystr
))) {
915 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr
));
918 /* Insert new RID key */
919 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid
));
920 if (!tdb_update_ridrec_only(newpwd
, TDB_INSERT
)) {
924 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
925 flag
== TDB_MODIFY
? "Updating" : "Inserting", newrid
));
926 if (!tdb_update_ridrec_only(newpwd
, flag
)) {
931 if (dbwrap_transaction_commit(db_sam
) != 0) {
932 DEBUG(0, ("Could not commit transaction\n"));
939 if (dbwrap_transaction_cancel(db_sam
) != 0) {
940 smb_panic("transaction_cancel failed");
945 /***************************************************************************
946 Modifies an existing struct samu
947 ****************************************************************************/
949 static NTSTATUS
tdbsam_update_sam_account (struct pdb_methods
*my_methods
, struct samu
*newpwd
)
951 if ( !tdb_update_sam(my_methods
, newpwd
, TDB_MODIFY
) )
952 return NT_STATUS_UNSUCCESSFUL
;
957 /***************************************************************************
958 Adds an existing struct samu
959 ****************************************************************************/
961 static NTSTATUS
tdbsam_add_sam_account (struct pdb_methods
*my_methods
, struct samu
*newpwd
)
963 if ( !tdb_update_sam(my_methods
, newpwd
, TDB_INSERT
) )
964 return NT_STATUS_UNSUCCESSFUL
;
969 /***************************************************************************
970 Renames a struct samu
971 - check for the posix user/rename user script
972 - Add and lock the new user record
973 - rename the posix user
974 - rewrite the rid->username record
975 - delete the old user
976 - unlock the new user record
977 ***************************************************************************/
978 static NTSTATUS
tdbsam_rename_sam_account(struct pdb_methods
*my_methods
,
979 struct samu
*old_acct
,
982 struct samu
*new_acct
= NULL
;
983 char *rename_script
= NULL
;
985 fstring oldname_lower
;
986 fstring newname_lower
;
988 /* can't do anything without an external script */
990 if ( !(new_acct
= samu_new( talloc_tos() )) ) {
991 return NT_STATUS_NO_MEMORY
;
994 rename_script
= lp_renameuser_script(new_acct
);
995 if (!rename_script
) {
996 TALLOC_FREE(new_acct
);
997 return NT_STATUS_NO_MEMORY
;
999 if (!*rename_script
) {
1000 TALLOC_FREE(new_acct
);
1001 return NT_STATUS_ACCESS_DENIED
;
1004 if ( !pdb_copy_sam_account(new_acct
, old_acct
)
1005 || !pdb_set_username(new_acct
, newname
, PDB_CHANGED
))
1007 TALLOC_FREE(new_acct
);
1008 return NT_STATUS_NO_MEMORY
;
1011 /* open the database */
1012 if ( !tdbsam_open( tdbsam_filename
) ) {
1013 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1015 TALLOC_FREE(new_acct
);
1016 return NT_STATUS_ACCESS_DENIED
;
1019 if (dbwrap_transaction_start(db_sam
) != 0) {
1020 DEBUG(0, ("Could not start transaction\n"));
1021 TALLOC_FREE(new_acct
);
1022 return NT_STATUS_ACCESS_DENIED
;
1026 /* add the new account and lock it */
1027 if ( !tdb_update_samacct_only(new_acct
, TDB_INSERT
) ) {
1031 /* Rename the posix user. Follow the semantics of _samr_create_user()
1032 so that we lower case the posix name but preserve the case in passdb */
1034 fstrcpy( oldname_lower
, pdb_get_username(old_acct
) );
1035 strlower_m( oldname_lower
);
1037 fstrcpy( newname_lower
, newname
);
1038 strlower_m( newname_lower
);
1040 rename_script
= talloc_string_sub2(new_acct
,
1047 if (!rename_script
) {
1050 rename_script
= talloc_string_sub2(new_acct
,
1057 if (!rename_script
) {
1060 rename_ret
= smbrun(rename_script
, NULL
);
1062 DEBUG(rename_ret
? 0 : 3,("Running the command `%s' gave %d\n",
1063 rename_script
, rename_ret
));
1065 if (rename_ret
!= 0) {
1069 smb_nscd_flush_user_cache();
1071 /* rewrite the rid->username record */
1073 if ( !tdb_update_ridrec_only( new_acct
, TDB_MODIFY
) ) {
1077 tdb_delete_samacct_only( old_acct
);
1079 if (dbwrap_transaction_commit(db_sam
) != 0) {
1081 * Ok, we're screwed. We've changed the posix account, but
1082 * could not adapt passdb.tdb. Shall we change the posix
1085 DEBUG(0, ("transaction_commit failed\n"));
1086 TALLOC_FREE(new_acct
);
1087 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1090 TALLOC_FREE(new_acct
);
1091 return NT_STATUS_OK
;
1094 if (dbwrap_transaction_cancel(db_sam
) != 0) {
1095 smb_panic("transaction_cancel failed");
1098 TALLOC_FREE(new_acct
);
1100 return NT_STATUS_ACCESS_DENIED
;
1103 static uint32_t tdbsam_capabilities(struct pdb_methods
*methods
)
1105 return PDB_CAP_STORE_RIDS
;
1108 static bool tdbsam_new_rid(struct pdb_methods
*methods
, uint32
*prid
)
1113 rid
= BASE_RID
; /* Default if not set */
1115 if (!tdbsam_open(tdbsam_filename
)) {
1116 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1121 status
= dbwrap_trans_change_uint32_atomic_bystring(
1122 db_sam
, NEXT_RID_STRING
, &rid
, 1);
1123 if (!NT_STATUS_IS_OK(status
)) {
1124 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1125 NEXT_RID_STRING
, nt_errstr(status
)));
1134 struct tdbsam_search_state
{
1135 struct pdb_methods
*methods
;
1136 uint32_t acct_flags
;
1144 static int tdbsam_collect_rids(struct db_record
*rec
, void *private_data
)
1146 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1147 private_data
, struct tdbsam_search_state
);
1148 size_t prefixlen
= strlen(RIDPREFIX
);
1152 key
= dbwrap_record_get_key(rec
);
1154 if ((key
.dsize
< prefixlen
)
1155 || (strncmp((char *)key
.dptr
, RIDPREFIX
, prefixlen
))) {
1159 rid
= strtoul((char *)key
.dptr
+prefixlen
, NULL
, 16);
1161 ADD_TO_LARGE_ARRAY(state
, uint32
, rid
, &state
->rids
, &state
->num_rids
,
1162 &state
->array_size
);
1167 static void tdbsam_search_end(struct pdb_search
*search
)
1169 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1170 search
->private_data
, struct tdbsam_search_state
);
1174 static bool tdbsam_search_next_entry(struct pdb_search
*search
,
1175 struct samr_displayentry
*entry
)
1177 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1178 search
->private_data
, struct tdbsam_search_state
);
1179 struct samu
*user
= NULL
;
1185 user
= samu_new(talloc_tos());
1187 DEBUG(0, ("samu_new failed\n"));
1191 if (state
->current
== state
->num_rids
) {
1195 rid
= state
->rids
[state
->current
++];
1197 status
= tdbsam_getsampwrid(state
->methods
, user
, rid
);
1199 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
1201 * Someone has deleted that user since we listed the RIDs
1206 if (!NT_STATUS_IS_OK(status
)) {
1207 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1208 nt_errstr(status
)));
1213 if ((state
->acct_flags
!= 0) &&
1214 ((state
->acct_flags
& pdb_get_acct_ctrl(user
)) == 0)) {
1218 entry
->acct_flags
= pdb_get_acct_ctrl(user
);
1220 entry
->account_name
= talloc_strdup(search
, pdb_get_username(user
));
1221 entry
->fullname
= talloc_strdup(search
, pdb_get_fullname(user
));
1222 entry
->description
= talloc_strdup(search
, pdb_get_acct_desc(user
));
1226 if ((entry
->account_name
== NULL
) || (entry
->fullname
== NULL
)
1227 || (entry
->description
== NULL
)) {
1228 DEBUG(0, ("talloc_strdup failed\n"));
1235 static bool tdbsam_search_users(struct pdb_methods
*methods
,
1236 struct pdb_search
*search
,
1239 struct tdbsam_search_state
*state
;
1241 if (!tdbsam_open(tdbsam_filename
)) {
1242 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1247 state
= talloc_zero(search
, struct tdbsam_search_state
);
1248 if (state
== NULL
) {
1249 DEBUG(0, ("talloc failed\n"));
1252 state
->acct_flags
= acct_flags
;
1253 state
->methods
= methods
;
1255 dbwrap_traverse_read(db_sam
, tdbsam_collect_rids
, state
, NULL
);
1257 search
->private_data
= state
;
1258 search
->next_entry
= tdbsam_search_next_entry
;
1259 search
->search_end
= tdbsam_search_end
;
1264 /*********************************************************************
1265 Initialize the tdb sam backend. Setup the dispath table of methods,
1266 open the tdb, etc...
1267 *********************************************************************/
1269 static NTSTATUS
pdb_init_tdbsam(struct pdb_methods
**pdb_method
, const char *location
)
1272 char *tdbfile
= NULL
;
1273 const char *pfile
= location
;
1275 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_method( pdb_method
))) {
1279 (*pdb_method
)->name
= "tdbsam";
1281 (*pdb_method
)->getsampwnam
= tdbsam_getsampwnam
;
1282 (*pdb_method
)->getsampwsid
= tdbsam_getsampwsid
;
1283 (*pdb_method
)->add_sam_account
= tdbsam_add_sam_account
;
1284 (*pdb_method
)->update_sam_account
= tdbsam_update_sam_account
;
1285 (*pdb_method
)->delete_sam_account
= tdbsam_delete_sam_account
;
1286 (*pdb_method
)->rename_sam_account
= tdbsam_rename_sam_account
;
1287 (*pdb_method
)->search_users
= tdbsam_search_users
;
1289 (*pdb_method
)->capabilities
= tdbsam_capabilities
;
1290 (*pdb_method
)->new_rid
= tdbsam_new_rid
;
1292 /* save the path for later */
1295 if (asprintf(&tdbfile
, "%s/%s", lp_private_dir(),
1296 PASSDB_FILE_NAME
) < 0) {
1297 return NT_STATUS_NO_MEMORY
;
1301 tdbsam_filename
= SMB_STRDUP(pfile
);
1302 if (!tdbsam_filename
) {
1303 return NT_STATUS_NO_MEMORY
;
1307 /* no private data */
1309 (*pdb_method
)->private_data
= NULL
;
1310 (*pdb_method
)->free_private_data
= NULL
;
1312 return NT_STATUS_OK
;
1315 NTSTATUS
pdb_tdbsam_init(void)
1317 return smb_register_passdb(PASSDB_INTERFACE_VERSION
, "tdbsam", pdb_init_tdbsam
);