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"
29 #include "../libcli/security/security.h"
32 #if 0 /* when made a module use this */
34 static int tdbsam_debug_level
= DBGC_ALL
;
36 #define DBGC_CLASS tdbsam_debug_level
41 #define DBGC_CLASS DBGC_PASSDB
45 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
46 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
47 #define TDBSAM_VERSION_STRING "INFO/version"
48 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
49 #define PASSDB_FILE_NAME "passdb.tdb"
50 #define USERPREFIX "USER_"
51 #define USERPREFIX_LEN 5
52 #define RIDPREFIX "RID_"
53 #define PRIVPREFIX "PRIV_"
54 #define NEXT_RID_STRING "NEXT_RID"
56 /* GLOBAL TDB SAM CONTEXT */
58 static struct db_context
*db_sam
;
59 static char *tdbsam_filename
;
61 struct tdbsam_convert_state
{
66 static int tdbsam_convert_one(struct db_record
*rec
, void *priv
)
68 struct tdbsam_convert_state
*state
=
69 (struct tdbsam_convert_state
*)priv
;
75 if (rec
->key
.dsize
< USERPREFIX_LEN
) {
78 if (strncmp((char *)rec
->key
.dptr
, USERPREFIX
, USERPREFIX_LEN
) != 0) {
82 user
= samu_new(talloc_tos());
84 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
85 state
->success
= false;
89 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
90 "(version:%d)\n", rec
->key
.dptr
, state
->from
));
92 switch (state
->from
) {
94 ret
= init_samu_from_buffer(user
, SAMU_BUFFER_V0
,
95 (uint8
*)rec
->value
.dptr
,
99 ret
= init_samu_from_buffer(user
, SAMU_BUFFER_V1
,
100 (uint8
*)rec
->value
.dptr
,
104 ret
= init_samu_from_buffer(user
, SAMU_BUFFER_V2
,
105 (uint8
*)rec
->value
.dptr
,
109 ret
= init_samu_from_buffer(user
, SAMU_BUFFER_V3
,
110 (uint8
*)rec
->value
.dptr
,
114 ret
= init_samu_from_buffer(user
, SAMU_BUFFER_V4
,
115 (uint8
*)rec
->value
.dptr
,
119 /* unknown tdbsam version */
123 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
124 "from TDB (key:%s) (version:%d)\n", rec
->key
.dptr
,
127 state
->success
= false;
131 data
.dsize
= init_buffer_from_samu(&data
.dptr
, user
, false);
134 if (data
.dsize
== -1) {
135 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
136 "the new format\n"));
137 state
->success
= false;
141 status
= rec
->store(rec
, data
, TDB_MODIFY
);
142 if (!NT_STATUS_IS_OK(status
)) {
143 DEBUG(0, ("Could not store the new record: %s\n",
145 state
->success
= false;
152 /**********************************************************************
153 Struct and function to backup an old record.
154 *********************************************************************/
156 struct tdbsam_backup_state
{
157 struct db_context
*new_db
;
161 static int backup_copy_fn(struct db_record
*orig_rec
, void *state
)
163 struct tdbsam_backup_state
*bs
= (struct tdbsam_backup_state
*)state
;
164 struct db_record
*new_rec
;
167 new_rec
= bs
->new_db
->fetch_locked(bs
->new_db
, talloc_tos(), orig_rec
->key
);
168 if (new_rec
== NULL
) {
173 status
= new_rec
->store(new_rec
, orig_rec
->value
, TDB_INSERT
);
175 TALLOC_FREE(new_rec
);
177 if (!NT_STATUS_IS_OK(status
)) {
184 /**********************************************************************
185 Make a backup of an old passdb and replace the new one with it. We
186 have to do this as between 3.0.x and 3.2.x the hash function changed
187 by mistake (used unsigned char * instead of char *). This means the
188 previous simple update code will fail due to not being able to find
189 existing records to replace in the tdbsam_convert_one() function. JRA.
190 *********************************************************************/
192 static bool tdbsam_convert_backup(const char *dbname
, struct db_context
**pp_db
)
194 TALLOC_CTX
*frame
= talloc_stackframe();
195 const char *tmp_fname
= NULL
;
196 struct db_context
*tmp_db
= NULL
;
197 struct db_context
*orig_db
= *pp_db
;
198 struct tdbsam_backup_state bs
;
201 tmp_fname
= talloc_asprintf(frame
, "%s.tmp", dbname
);
209 /* Remember to open this on the NULL context. We need
210 * it to stay around after we return from here. */
212 tmp_db
= db_open(NULL
, tmp_fname
, 0,
213 TDB_DEFAULT
, O_CREAT
|O_RDWR
, 0600);
214 if (tmp_db
== NULL
) {
215 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
216 "[%s]\n", tmp_fname
));
221 if (orig_db
->transaction_start(orig_db
) != 0) {
222 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
228 if (tmp_db
->transaction_start(tmp_db
) != 0) {
229 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
230 orig_db
->transaction_cancel(orig_db
);
240 ret
= orig_db
->traverse(orig_db
, backup_copy_fn
, (void *)&bs
);
242 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
247 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
251 if (orig_db
->transaction_commit(orig_db
) != 0) {
252 smb_panic("tdbsam_convert_backup: orig commit failed\n");
254 if (tmp_db
->transaction_commit(tmp_db
) != 0) {
255 smb_panic("tdbsam_convert_backup: orig commit failed\n");
258 /* be sure to close the DBs _before_ renaming the file */
260 TALLOC_FREE(orig_db
);
263 /* This is safe from other users as we know we're
264 * under a mutex here. */
266 if (rename(tmp_fname
, dbname
) == -1) {
267 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
271 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
276 /* re-open the converted TDB */
278 orig_db
= db_open(NULL
, dbname
, 0,
279 TDB_DEFAULT
, O_CREAT
|O_RDWR
, 0600);
280 if (orig_db
== NULL
) {
281 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
282 "converted passdb TDB [%s]\n", dbname
));
286 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
289 /* Replace the global db pointer. */
295 if (orig_db
->transaction_cancel(orig_db
) != 0) {
296 smb_panic("tdbsam_convert: transaction_cancel failed");
299 if (tmp_db
->transaction_cancel(tmp_db
) != 0) {
300 smb_panic("tdbsam_convert: transaction_cancel failed");
309 static bool tdbsam_upgrade_next_rid(struct db_context
*db
)
315 ok
= dbwrap_fetch_uint32(db
, NEXT_RID_STRING
, &rid
);
320 tdb
= tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
321 TDB_DEFAULT
, O_RDONLY
, 0644);
324 ok
= tdb_fetch_uint32(tdb
, "RID_COUNTER", &rid
);
333 if (dbwrap_store_uint32(db
, NEXT_RID_STRING
, rid
) != 0) {
340 static bool tdbsam_convert(struct db_context
**pp_db
, const char *name
, int32 from
)
342 struct tdbsam_convert_state state
;
343 struct db_context
*db
= NULL
;
346 /* We only need the update backup for local db's. */
347 if (db_is_local(name
) && !tdbsam_convert_backup(name
, pp_db
)) {
348 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name
));
354 state
.success
= true;
356 if (db
->transaction_start(db
) != 0) {
357 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
361 if (!tdbsam_upgrade_next_rid(db
)) {
362 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
366 ret
= db
->traverse(db
, tdbsam_convert_one
, &state
);
368 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
372 if (!state
.success
) {
373 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
377 if (dbwrap_store_int32(db
, TDBSAM_VERSION_STRING
,
378 TDBSAM_VERSION
) != 0) {
379 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
383 if (dbwrap_store_int32(db
, TDBSAM_MINOR_VERSION_STRING
,
384 TDBSAM_MINOR_VERSION
) != 0) {
385 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
389 if (db
->transaction_commit(db
) != 0) {
390 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
397 if (db
->transaction_cancel(db
) != 0) {
398 smb_panic("tdbsam_convert: transaction_cancel failed");
404 /*********************************************************************
405 Open the tdbsam file based on the absolute path specified.
406 Uses a reference count to allow multiple open calls.
407 *********************************************************************/
409 static bool tdbsam_open( const char *name
)
414 /* check if we are already open */
420 /* Try to open tdb passwd. Create a new one if necessary */
422 db_sam
= db_open(NULL
, name
, 0, TDB_DEFAULT
, O_CREAT
|O_RDWR
, 0600);
423 if (db_sam
== NULL
) {
424 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
429 /* Check the version */
430 version
= dbwrap_fetch_int32(db_sam
, TDBSAM_VERSION_STRING
);
432 version
= 0; /* Version not found, assume version 0 */
435 /* Get the minor version */
436 minor_version
= dbwrap_fetch_int32(db_sam
, TDBSAM_MINOR_VERSION_STRING
);
437 if (minor_version
== -1) {
438 minor_version
= 0; /* Minor version not found, assume 0 */
441 /* Compare the version */
442 if (version
> TDBSAM_VERSION
) {
443 /* Version more recent than the latest known */
444 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version
));
449 if ( version
< TDBSAM_VERSION
||
450 (version
== TDBSAM_VERSION
&&
451 minor_version
< TDBSAM_MINOR_VERSION
) ) {
453 * Ok - we think we're going to have to convert.
454 * Due to the backup process we now must do to
455 * upgrade we have to get a mutex and re-check
456 * the version. Someone else may have upgraded
457 * whilst we were checking.
460 struct named_mutex
*mtx
= grab_named_mutex(NULL
,
461 "tdbsam_upgrade_mutex",
465 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
470 /* Re-check the version */
471 version
= dbwrap_fetch_int32(db_sam
, TDBSAM_VERSION_STRING
);
473 version
= 0; /* Version not found, assume version 0 */
476 /* Re-check the minor version */
477 minor_version
= dbwrap_fetch_int32(db_sam
, TDBSAM_MINOR_VERSION_STRING
);
478 if (minor_version
== -1) {
479 minor_version
= 0; /* Minor version not found, assume 0 */
482 /* Compare the version */
483 if (version
> TDBSAM_VERSION
) {
484 /* Version more recent than the latest known */
485 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version
));
491 if ( version
< TDBSAM_VERSION
||
492 (version
== TDBSAM_VERSION
&&
493 minor_version
< TDBSAM_MINOR_VERSION
) ) {
495 * Note that minor versions we read that are greater
496 * than the current minor version we have hard coded
497 * are assumed to be compatible if they have the same
498 * major version. That allows previous versions of the
499 * passdb code that don't know about minor versions to
500 * still use this database. JRA.
503 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
508 TDBSAM_MINOR_VERSION
));
510 if ( !tdbsam_convert(&db_sam
, name
, version
) ) {
511 DEBUG(0, ("tdbsam_open: Error when trying to convert "
512 "tdbsam [%s]\n",name
));
518 DEBUG(3, ("TDBSAM converted successfully.\n"));
523 DEBUG(4,("tdbsam_open: successfully opened %s\n", name
));
528 /******************************************************************
529 Lookup a name in the SAM TDB
530 ******************************************************************/
532 static NTSTATUS
tdbsam_getsampwnam (struct pdb_methods
*my_methods
,
533 struct samu
*user
, const char *sname
)
540 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
541 return NT_STATUS_NO_MEMORY
;
544 /* Data is stored in all lower-case */
545 fstrcpy(name
, sname
);
549 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
551 /* open the database */
553 if ( !tdbsam_open( tdbsam_filename
) ) {
554 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename
));
555 return NT_STATUS_ACCESS_DENIED
;
560 data
= dbwrap_fetch_bystring(db_sam
, talloc_tos(), keystr
);
562 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
563 DEBUGADD(5, (" Key: %s\n", keystr
));
564 return NT_STATUS_NO_SUCH_USER
;
567 /* unpack the buffer */
569 if (!init_samu_from_buffer(user
, SAMU_BUFFER_LATEST
, data
.dptr
, data
.dsize
)) {
570 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
571 SAFE_FREE(data
.dptr
);
572 return NT_STATUS_NO_MEMORY
;
577 TALLOC_FREE(data
.dptr
);
582 /***************************************************************************
584 **************************************************************************/
586 static NTSTATUS
tdbsam_getsampwrid (struct pdb_methods
*my_methods
,
587 struct samu
*user
, uint32 rid
)
589 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
595 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
601 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
, rid
);
603 /* open the database */
605 if ( !tdbsam_open( tdbsam_filename
) ) {
606 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename
));
607 return NT_STATUS_ACCESS_DENIED
;
612 data
= dbwrap_fetch_bystring(db_sam
, talloc_tos(), keystr
);
614 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid
, keystr
));
615 return NT_STATUS_UNSUCCESSFUL
;
618 fstrcpy(name
, (const char *)data
.dptr
);
619 TALLOC_FREE(data
.dptr
);
621 return tdbsam_getsampwnam (my_methods
, user
, name
);
624 static NTSTATUS
tdbsam_getsampwsid(struct pdb_methods
*my_methods
,
625 struct samu
* user
, const struct dom_sid
*sid
)
629 if ( !sid_peek_check_rid(get_global_sam_sid(), sid
, &rid
) )
630 return NT_STATUS_UNSUCCESSFUL
;
632 return tdbsam_getsampwrid(my_methods
, user
, rid
);
635 static bool tdb_delete_samacct_only( struct samu
*sam_pass
)
641 fstrcpy(name
, pdb_get_username(sam_pass
));
644 /* set the search key */
646 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
648 /* it's outaa here! 8^) */
649 if ( !tdbsam_open( tdbsam_filename
) ) {
650 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
655 status
= dbwrap_delete_bystring(db_sam
, keystr
);
656 if (!NT_STATUS_IS_OK(status
)) {
657 DEBUG(5, ("Error deleting entry from tdb passwd "
658 "database: %s!\n", nt_errstr(status
)));
665 /***************************************************************************
666 Delete a struct samu records for the username and RID key
667 ****************************************************************************/
669 static NTSTATUS
tdbsam_delete_sam_account(struct pdb_methods
*my_methods
,
670 struct samu
*sam_pass
)
672 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
677 /* open the database */
679 if ( !tdbsam_open( tdbsam_filename
) ) {
680 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
682 return NT_STATUS_ACCESS_DENIED
;
685 fstrcpy(name
, pdb_get_username(sam_pass
));
688 /* set the search key */
690 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
692 rid
= pdb_get_user_rid(sam_pass
);
694 /* it's outaa here! 8^) */
696 if (db_sam
->transaction_start(db_sam
) != 0) {
697 DEBUG(0, ("Could not start transaction\n"));
698 return NT_STATUS_UNSUCCESSFUL
;
701 nt_status
= dbwrap_delete_bystring(db_sam
, keystr
);
702 if (!NT_STATUS_IS_OK(nt_status
)) {
703 DEBUG(5, ("Error deleting entry from tdb passwd "
704 "database: %s!\n", nt_errstr(nt_status
)));
708 /* set the search key */
710 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
, rid
);
712 /* it's outaa here! 8^) */
714 nt_status
= dbwrap_delete_bystring(db_sam
, keystr
);
715 if (!NT_STATUS_IS_OK(nt_status
)) {
716 DEBUG(5, ("Error deleting entry from tdb rid "
717 "database: %s!\n", nt_errstr(nt_status
)));
721 if (db_sam
->transaction_commit(db_sam
) != 0) {
722 DEBUG(0, ("Could not commit transaction\n"));
723 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
729 if (db_sam
->transaction_cancel(db_sam
) != 0) {
730 smb_panic("transaction_cancel failed");
737 /***************************************************************************
738 Update the TDB SAM account record only
739 Assumes that the tdbsam is already open
740 ****************************************************************************/
741 static bool tdb_update_samacct_only( struct samu
* newpwd
, int flag
)
750 /* copy the struct samu struct into a BYTE buffer for storage */
752 if ( (data
.dsize
=init_buffer_from_samu(&buf
, newpwd
, False
)) == -1 ) {
753 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
758 fstrcpy(name
, pdb_get_username(newpwd
));
761 DEBUG(5, ("Storing %saccount %s with RID %d\n",
762 flag
== TDB_INSERT
? "(new) " : "", name
,
763 pdb_get_user_rid(newpwd
)));
765 /* setup the USER index key */
766 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", USERPREFIX
, name
);
768 /* add the account */
770 status
= dbwrap_store_bystring(db_sam
, keystr
, data
, flag
);
771 if (!NT_STATUS_IS_OK(status
)) {
772 DEBUG(0, ("Unable to modify passwd TDB: %s!",
785 /***************************************************************************
786 Update the TDB SAM RID record only
787 Assumes that the tdbsam is already open
788 ****************************************************************************/
789 static bool tdb_update_ridrec_only( struct samu
* newpwd
, int flag
)
796 fstrcpy(name
, pdb_get_username(newpwd
));
800 data
= string_term_tdb_data(name
);
802 /* setup the RID index key */
803 slprintf(keystr
, sizeof(keystr
)-1, "%s%.8x", RIDPREFIX
,
804 pdb_get_user_rid(newpwd
));
806 /* add the reference */
807 status
= dbwrap_store_bystring(db_sam
, keystr
, data
, flag
);
808 if (!NT_STATUS_IS_OK(status
)) {
809 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
818 /***************************************************************************
820 ****************************************************************************/
822 static bool tdb_update_sam(struct pdb_methods
*my_methods
, struct samu
* newpwd
,
828 if (!(newrid
= pdb_get_user_rid(newpwd
))) {
829 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
830 pdb_get_username(newpwd
)));
836 /* open the database */
838 if ( !tdbsam_open( tdbsam_filename
) ) {
839 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename
));
843 if (db_sam
->transaction_start(db_sam
) != 0) {
844 DEBUG(0, ("Could not start transaction\n"));
848 /* If we are updating, we may be changing this users RID. Retrieve the old RID
851 if (flag
== TDB_MODIFY
) {
852 struct samu
*account
= samu_new(talloc_tos());
853 if (account
== NULL
) {
854 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
857 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods
, account
, pdb_get_username(newpwd
)))) {
858 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
859 pdb_get_username(newpwd
)));
860 TALLOC_FREE(account
);
863 if (!(oldrid
= pdb_get_user_rid(account
))) {
864 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
865 TALLOC_FREE(account
);
868 TALLOC_FREE(account
);
871 /* Update the new samu entry. */
872 if (!tdb_update_samacct_only(newpwd
, flag
)) {
876 /* Now take care of the case where the RID changed. We need
877 * to delete the old RID key and add the new. */
879 if (flag
== TDB_MODIFY
&& newrid
!= oldrid
) {
882 /* Delete old RID key */
883 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid
));
884 slprintf(keystr
, sizeof(keystr
) - 1, "%s%.8x", RIDPREFIX
, oldrid
);
885 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam
, keystr
))) {
886 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr
));
889 /* Insert new RID key */
890 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid
));
891 if (!tdb_update_ridrec_only(newpwd
, TDB_INSERT
)) {
895 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
896 flag
== TDB_MODIFY
? "Updating" : "Inserting", newrid
));
897 if (!tdb_update_ridrec_only(newpwd
, flag
)) {
902 if (db_sam
->transaction_commit(db_sam
) != 0) {
903 DEBUG(0, ("Could not commit transaction\n"));
910 if (db_sam
->transaction_cancel(db_sam
) != 0) {
911 smb_panic("transaction_cancel failed");
916 /***************************************************************************
917 Modifies an existing struct samu
918 ****************************************************************************/
920 static NTSTATUS
tdbsam_update_sam_account (struct pdb_methods
*my_methods
, struct samu
*newpwd
)
922 if ( !tdb_update_sam(my_methods
, newpwd
, TDB_MODIFY
) )
923 return NT_STATUS_UNSUCCESSFUL
;
928 /***************************************************************************
929 Adds an existing struct samu
930 ****************************************************************************/
932 static NTSTATUS
tdbsam_add_sam_account (struct pdb_methods
*my_methods
, struct samu
*newpwd
)
934 if ( !tdb_update_sam(my_methods
, newpwd
, TDB_INSERT
) )
935 return NT_STATUS_UNSUCCESSFUL
;
940 /***************************************************************************
941 Renames a struct samu
942 - check for the posix user/rename user script
943 - Add and lock the new user record
944 - rename the posix user
945 - rewrite the rid->username record
946 - delete the old user
947 - unlock the new user record
948 ***************************************************************************/
949 static NTSTATUS
tdbsam_rename_sam_account(struct pdb_methods
*my_methods
,
950 struct samu
*old_acct
,
953 struct samu
*new_acct
= NULL
;
954 char *rename_script
= NULL
;
956 fstring oldname_lower
;
957 fstring newname_lower
;
959 /* can't do anything without an external script */
961 if ( !(new_acct
= samu_new( talloc_tos() )) ) {
962 return NT_STATUS_NO_MEMORY
;
965 rename_script
= talloc_strdup(new_acct
, lp_renameuser_script());
966 if (!rename_script
) {
967 TALLOC_FREE(new_acct
);
968 return NT_STATUS_NO_MEMORY
;
970 if (!*rename_script
) {
971 TALLOC_FREE(new_acct
);
972 return NT_STATUS_ACCESS_DENIED
;
975 if ( !pdb_copy_sam_account(new_acct
, old_acct
)
976 || !pdb_set_username(new_acct
, newname
, PDB_CHANGED
))
978 TALLOC_FREE(new_acct
);
979 return NT_STATUS_NO_MEMORY
;
982 /* open the database */
983 if ( !tdbsam_open( tdbsam_filename
) ) {
984 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
986 TALLOC_FREE(new_acct
);
987 return NT_STATUS_ACCESS_DENIED
;
990 if (db_sam
->transaction_start(db_sam
) != 0) {
991 DEBUG(0, ("Could not start transaction\n"));
992 TALLOC_FREE(new_acct
);
993 return NT_STATUS_ACCESS_DENIED
;
997 /* add the new account and lock it */
998 if ( !tdb_update_samacct_only(new_acct
, TDB_INSERT
) ) {
1002 /* Rename the posix user. Follow the semantics of _samr_create_user()
1003 so that we lower case the posix name but preserve the case in passdb */
1005 fstrcpy( oldname_lower
, pdb_get_username(old_acct
) );
1006 strlower_m( oldname_lower
);
1008 fstrcpy( newname_lower
, newname
);
1009 strlower_m( newname_lower
);
1011 rename_script
= talloc_string_sub2(new_acct
,
1018 if (!rename_script
) {
1021 rename_script
= talloc_string_sub2(new_acct
,
1028 if (!rename_script
) {
1031 rename_ret
= smbrun(rename_script
, NULL
);
1033 DEBUG(rename_ret
? 0 : 3,("Running the command `%s' gave %d\n",
1034 rename_script
, rename_ret
));
1036 if (rename_ret
!= 0) {
1040 smb_nscd_flush_user_cache();
1042 /* rewrite the rid->username record */
1044 if ( !tdb_update_ridrec_only( new_acct
, TDB_MODIFY
) ) {
1048 tdb_delete_samacct_only( old_acct
);
1050 if (db_sam
->transaction_commit(db_sam
) != 0) {
1052 * Ok, we're screwed. We've changed the posix account, but
1053 * could not adapt passdb.tdb. Shall we change the posix
1056 DEBUG(0, ("transaction_commit failed\n"));
1057 TALLOC_FREE(new_acct
);
1058 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1061 TALLOC_FREE(new_acct
);
1062 return NT_STATUS_OK
;
1065 if (db_sam
->transaction_cancel(db_sam
) != 0) {
1066 smb_panic("transaction_cancel failed");
1069 TALLOC_FREE(new_acct
);
1071 return NT_STATUS_ACCESS_DENIED
;
1074 static uint32_t tdbsam_capabilities(struct pdb_methods
*methods
)
1076 return PDB_CAP_STORE_RIDS
;
1079 static bool tdbsam_new_rid(struct pdb_methods
*methods
, uint32
*prid
)
1084 rid
= BASE_RID
; /* Default if not set */
1086 if (!tdbsam_open(tdbsam_filename
)) {
1087 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1092 status
= dbwrap_trans_change_uint32_atomic(db_sam
, NEXT_RID_STRING
,
1094 if (!NT_STATUS_IS_OK(status
)) {
1095 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1096 NEXT_RID_STRING
, nt_errstr(status
)));
1105 struct tdbsam_search_state
{
1106 struct pdb_methods
*methods
;
1107 uint32_t acct_flags
;
1115 static int tdbsam_collect_rids(struct db_record
*rec
, void *private_data
)
1117 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1118 private_data
, struct tdbsam_search_state
);
1119 size_t prefixlen
= strlen(RIDPREFIX
);
1122 if ((rec
->key
.dsize
< prefixlen
)
1123 || (strncmp((char *)rec
->key
.dptr
, RIDPREFIX
, prefixlen
))) {
1127 rid
= strtoul((char *)rec
->key
.dptr
+prefixlen
, NULL
, 16);
1129 ADD_TO_LARGE_ARRAY(state
, uint32
, rid
, &state
->rids
, &state
->num_rids
,
1130 &state
->array_size
);
1135 static void tdbsam_search_end(struct pdb_search
*search
)
1137 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1138 search
->private_data
, struct tdbsam_search_state
);
1142 static bool tdbsam_search_next_entry(struct pdb_search
*search
,
1143 struct samr_displayentry
*entry
)
1145 struct tdbsam_search_state
*state
= talloc_get_type_abort(
1146 search
->private_data
, struct tdbsam_search_state
);
1147 struct samu
*user
= NULL
;
1153 user
= samu_new(talloc_tos());
1155 DEBUG(0, ("samu_new failed\n"));
1159 if (state
->current
== state
->num_rids
) {
1163 rid
= state
->rids
[state
->current
++];
1165 status
= tdbsam_getsampwrid(state
->methods
, user
, rid
);
1167 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
1169 * Someone has deleted that user since we listed the RIDs
1174 if (!NT_STATUS_IS_OK(status
)) {
1175 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1176 nt_errstr(status
)));
1181 if ((state
->acct_flags
!= 0) &&
1182 ((state
->acct_flags
& pdb_get_acct_ctrl(user
)) == 0)) {
1186 entry
->acct_flags
= pdb_get_acct_ctrl(user
);
1188 entry
->account_name
= talloc_strdup(search
, pdb_get_username(user
));
1189 entry
->fullname
= talloc_strdup(search
, pdb_get_fullname(user
));
1190 entry
->description
= talloc_strdup(search
, pdb_get_acct_desc(user
));
1194 if ((entry
->account_name
== NULL
) || (entry
->fullname
== NULL
)
1195 || (entry
->description
== NULL
)) {
1196 DEBUG(0, ("talloc_strdup failed\n"));
1203 static bool tdbsam_search_users(struct pdb_methods
*methods
,
1204 struct pdb_search
*search
,
1207 struct tdbsam_search_state
*state
;
1209 if (!tdbsam_open(tdbsam_filename
)) {
1210 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1215 state
= talloc_zero(search
, struct tdbsam_search_state
);
1216 if (state
== NULL
) {
1217 DEBUG(0, ("talloc failed\n"));
1220 state
->acct_flags
= acct_flags
;
1221 state
->methods
= methods
;
1223 db_sam
->traverse_read(db_sam
, tdbsam_collect_rids
, state
);
1225 search
->private_data
= state
;
1226 search
->next_entry
= tdbsam_search_next_entry
;
1227 search
->search_end
= tdbsam_search_end
;
1232 /*********************************************************************
1233 Initialize the tdb sam backend. Setup the dispath table of methods,
1234 open the tdb, etc...
1235 *********************************************************************/
1237 static NTSTATUS
pdb_init_tdbsam(struct pdb_methods
**pdb_method
, const char *location
)
1240 char *tdbfile
= NULL
;
1241 const char *pfile
= location
;
1243 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_method( pdb_method
))) {
1247 (*pdb_method
)->name
= "tdbsam";
1249 (*pdb_method
)->getsampwnam
= tdbsam_getsampwnam
;
1250 (*pdb_method
)->getsampwsid
= tdbsam_getsampwsid
;
1251 (*pdb_method
)->add_sam_account
= tdbsam_add_sam_account
;
1252 (*pdb_method
)->update_sam_account
= tdbsam_update_sam_account
;
1253 (*pdb_method
)->delete_sam_account
= tdbsam_delete_sam_account
;
1254 (*pdb_method
)->rename_sam_account
= tdbsam_rename_sam_account
;
1255 (*pdb_method
)->search_users
= tdbsam_search_users
;
1257 (*pdb_method
)->capabilities
= tdbsam_capabilities
;
1258 (*pdb_method
)->new_rid
= tdbsam_new_rid
;
1260 /* save the path for later */
1263 if (asprintf(&tdbfile
, "%s/%s", lp_private_dir(),
1264 PASSDB_FILE_NAME
) < 0) {
1265 return NT_STATUS_NO_MEMORY
;
1269 tdbsam_filename
= SMB_STRDUP(pfile
);
1270 if (!tdbsam_filename
) {
1271 return NT_STATUS_NO_MEMORY
;
1275 /* no private data */
1277 (*pdb_method
)->private_data
= NULL
;
1278 (*pdb_method
)->free_private_data
= NULL
;
1280 return NT_STATUS_OK
;
1283 NTSTATUS
pdb_tdbsam_init(void)
1285 return smb_register_passdb(PASSDB_INTERFACE_VERSION
, "tdbsam", pdb_init_tdbsam
);