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
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/>.
27 #if 0 /* when made a module use this */
29 static int tdbsam_debug_level = DBGC_ALL;
31 #define DBGC_CLASS tdbsam_debug_level
36 #define DBGC_CLASS DBGC_PASSDB
40 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
41 #define TDBSAM_VERSION_STRING "INFO/version"
42 #define PASSDB_FILE_NAME "passdb.tdb"
43 #define USERPREFIX "USER_"
44 #define USERPREFIX_LEN 5
45 #define RIDPREFIX "RID_"
46 #define PRIVPREFIX "PRIV_"
47 #define NEXT_RID_STRING "NEXT_RID"
49 /* GLOBAL TDB SAM CONTEXT */
51 static struct db_context *db_sam;
52 static char *tdbsam_filename;
54 struct tdbsam_convert_state {
59 static int tdbsam_convert_one(struct db_record *rec, void *priv)
61 struct tdbsam_convert_state *state =
62 (struct tdbsam_convert_state *)priv;
68 if (rec->key.dsize < USERPREFIX_LEN) {
71 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
75 user = samu_new(talloc_tos());
77 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
78 state->success = false;
82 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
83 "(version:%d)\n", rec->key.dptr, state->from));
85 switch (state->from) {
87 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
88 (uint8 *)rec->value.dptr,
92 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
93 (uint8 *)rec->value.dptr,
97 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
98 (uint8 *)rec->value.dptr,
102 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
103 (uint8 *)rec->value.dptr,
107 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
108 (uint8 *)rec->value.dptr,
112 /* unknown tdbsam version */
116 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
117 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
120 state->success = false;
124 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
127 if (data.dsize == -1) {
128 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
129 "the new format\n"));
130 state->success = false;
134 status = rec->store(rec, data, TDB_MODIFY);
135 if (!NT_STATUS_IS_OK(status)) {
136 DEBUG(0, ("Could not store the new record: %s\n",
138 state->success = false;
145 static bool tdbsam_upgrade_next_rid(struct db_context *db)
151 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
156 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
157 TDB_DEFAULT, O_RDONLY, 0644);
160 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
169 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
176 static bool tdbsam_convert(struct db_context *db, int32 from)
178 struct tdbsam_convert_state state;
182 state.success = true;
184 if (db->transaction_start(db) != 0) {
185 DEBUG(0, ("Could not start transaction\n"));
189 if (!tdbsam_upgrade_next_rid(db)) {
190 DEBUG(0, ("tdbsam_upgrade_next_rid failed\n"));
194 ret = db->traverse(db, tdbsam_convert_one, &state);
196 DEBUG(0, ("traverse failed\n"));
200 if (!state.success) {
201 DEBUG(0, ("Converting records failed\n"));
205 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
206 TDBSAM_VERSION) != 0) {
207 DEBUG(0, ("Could not store tdbsam version\n"));
211 if (db->transaction_commit(db) != 0) {
212 DEBUG(0, ("Could not commit transaction\n"));
219 if (db->transaction_cancel(db) != 0) {
220 smb_panic("transaction_cancel failed");
226 /*********************************************************************
227 Open the tdbsam file based on the absolute path specified.
228 Uses a reference count to allow multiple open calls.
229 *********************************************************************/
231 static bool tdbsam_open( const char *name )
235 /* check if we are already open */
241 /* Try to open tdb passwd. Create a new one if necessary */
243 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
244 if (db_sam == NULL) {
245 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
250 /* Check the version */
251 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
253 version = 0; /* Version not found, assume version 0 */
256 /* Compare the version */
257 if (version > TDBSAM_VERSION) {
258 /* Version more recent than the latest known */
259 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
264 if ( version < TDBSAM_VERSION ) {
265 DEBUG(1, ("tdbsam_open: Converting version %d database to "
266 "version %d.\n", version, TDBSAM_VERSION));
268 if ( !tdbsam_convert(db_sam, version) ) {
269 DEBUG(0, ("tdbsam_open: Error when trying to convert "
270 "tdbsam [%s]\n",name));
275 DEBUG(3, ("TDBSAM converted successfully.\n"));
278 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
283 /******************************************************************
284 Lookup a name in the SAM TDB
285 ******************************************************************/
287 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
288 struct samu *user, const char *sname)
295 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
296 return NT_STATUS_NO_MEMORY;
299 /* Data is stored in all lower-case */
300 fstrcpy(name, sname);
304 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
306 /* open the database */
308 if ( !tdbsam_open( tdbsam_filename ) ) {
309 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
310 return NT_STATUS_ACCESS_DENIED;
315 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
317 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
318 DEBUGADD(5, (" Key: %s\n", keystr));
319 return NT_STATUS_NO_SUCH_USER;
322 /* unpack the buffer */
324 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
325 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
326 SAFE_FREE(data.dptr);
327 return NT_STATUS_NO_MEMORY;
332 TALLOC_FREE(data.dptr);
337 /***************************************************************************
339 **************************************************************************/
341 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
342 struct samu *user, uint32 rid)
344 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
350 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
356 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
358 /* open the database */
360 if ( !tdbsam_open( tdbsam_filename ) ) {
361 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
362 return NT_STATUS_ACCESS_DENIED;
367 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
369 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
370 return NT_STATUS_UNSUCCESSFUL;
373 fstrcpy(name, (const char *)data.dptr);
374 TALLOC_FREE(data.dptr);
376 return tdbsam_getsampwnam (my_methods, user, name);
379 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
380 struct samu * user, const DOM_SID *sid)
384 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
385 return NT_STATUS_UNSUCCESSFUL;
387 return tdbsam_getsampwrid(my_methods, user, rid);
390 static bool tdb_delete_samacct_only( struct samu *sam_pass )
396 fstrcpy(name, pdb_get_username(sam_pass));
399 /* set the search key */
401 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
403 /* it's outaa here! 8^) */
404 if ( !tdbsam_open( tdbsam_filename ) ) {
405 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
410 status = dbwrap_delete_bystring(db_sam, keystr);
411 if (!NT_STATUS_IS_OK(status)) {
412 DEBUG(5, ("Error deleting entry from tdb passwd "
413 "database: %s!\n", nt_errstr(status)));
420 /***************************************************************************
421 Delete a struct samu records for the username and RID key
422 ****************************************************************************/
424 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
425 struct samu *sam_pass)
427 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
432 /* open the database */
434 if ( !tdbsam_open( tdbsam_filename ) ) {
435 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
437 return NT_STATUS_ACCESS_DENIED;
440 fstrcpy(name, pdb_get_username(sam_pass));
443 /* set the search key */
445 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
447 rid = pdb_get_user_rid(sam_pass);
449 /* it's outaa here! 8^) */
451 if (db_sam->transaction_start(db_sam) != 0) {
452 DEBUG(0, ("Could not start transaction\n"));
453 return NT_STATUS_UNSUCCESSFUL;
456 nt_status = dbwrap_delete_bystring(db_sam, keystr);
457 if (!NT_STATUS_IS_OK(nt_status)) {
458 DEBUG(5, ("Error deleting entry from tdb passwd "
459 "database: %s!\n", nt_errstr(nt_status)));
463 /* set the search key */
465 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
467 /* it's outaa here! 8^) */
469 nt_status = dbwrap_delete_bystring(db_sam, keystr);
470 if (!NT_STATUS_IS_OK(nt_status)) {
471 DEBUG(5, ("Error deleting entry from tdb rid "
472 "database: %s!\n", nt_errstr(nt_status)));
476 if (db_sam->transaction_commit(db_sam) != 0) {
477 DEBUG(0, ("Could not commit transaction\n"));
478 return NT_STATUS_INTERNAL_DB_CORRUPTION;
484 if (db_sam->transaction_cancel(db_sam) != 0) {
485 smb_panic("transaction_cancel failed");
492 /***************************************************************************
493 Update the TDB SAM account record only
494 Assumes that the tdbsam is already open
495 ****************************************************************************/
496 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
505 /* copy the struct samu struct into a BYTE buffer for storage */
507 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
508 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
513 fstrcpy(name, pdb_get_username(newpwd));
516 DEBUG(5, ("Storing %saccount %s with RID %d\n",
517 flag == TDB_INSERT ? "(new) " : "", name,
518 pdb_get_user_rid(newpwd)));
520 /* setup the USER index key */
521 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
523 /* add the account */
525 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
526 if (!NT_STATUS_IS_OK(status)) {
527 DEBUG(0, ("Unable to modify passwd TDB: %s!",
540 /***************************************************************************
541 Update the TDB SAM RID record only
542 Assumes that the tdbsam is already open
543 ****************************************************************************/
544 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
551 fstrcpy(name, pdb_get_username(newpwd));
555 data = string_term_tdb_data(name);
557 /* setup the RID index key */
558 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
559 pdb_get_user_rid(newpwd));
561 /* add the reference */
562 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
563 if (!NT_STATUS_IS_OK(status)) {
564 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
573 /***************************************************************************
575 ****************************************************************************/
577 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
580 if (!pdb_get_user_rid(newpwd)) {
581 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
582 pdb_get_username(newpwd)));
586 /* open the database */
588 if ( !tdbsam_open( tdbsam_filename ) ) {
589 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
593 if (db_sam->transaction_start(db_sam) != 0) {
594 DEBUG(0, ("Could not start transaction\n"));
598 if (!tdb_update_samacct_only(newpwd, flag)
599 || !tdb_update_ridrec_only(newpwd, flag)) {
603 if (db_sam->transaction_commit(db_sam) != 0) {
604 DEBUG(0, ("Could not commit transaction\n"));
611 if (db_sam->transaction_cancel(db_sam) != 0) {
612 smb_panic("transaction_cancel failed");
617 /***************************************************************************
618 Modifies an existing struct samu
619 ****************************************************************************/
621 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
623 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
624 return NT_STATUS_UNSUCCESSFUL;
629 /***************************************************************************
630 Adds an existing struct samu
631 ****************************************************************************/
633 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
635 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
636 return NT_STATUS_UNSUCCESSFUL;
641 /***************************************************************************
642 Renames a struct samu
643 - check for the posix user/rename user script
644 - Add and lock the new user record
645 - rename the posix user
646 - rewrite the rid->username record
647 - delete the old user
648 - unlock the new user record
649 ***************************************************************************/
650 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
651 struct samu *old_acct,
654 struct samu *new_acct = NULL;
655 char *rename_script = NULL;
657 fstring oldname_lower;
658 fstring newname_lower;
660 /* can't do anything without an external script */
662 if ( !(new_acct = samu_new( talloc_tos() )) ) {
663 return NT_STATUS_NO_MEMORY;
666 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
667 if (!rename_script) {
668 TALLOC_FREE(new_acct);
669 return NT_STATUS_NO_MEMORY;
671 if (!*rename_script) {
672 TALLOC_FREE(new_acct);
673 return NT_STATUS_ACCESS_DENIED;
676 if ( !pdb_copy_sam_account(new_acct, old_acct)
677 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
679 TALLOC_FREE(new_acct);
680 return NT_STATUS_NO_MEMORY;
683 /* open the database */
684 if ( !tdbsam_open( tdbsam_filename ) ) {
685 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
687 TALLOC_FREE(new_acct);
688 return NT_STATUS_ACCESS_DENIED;
691 if (db_sam->transaction_start(db_sam) != 0) {
692 DEBUG(0, ("Could not start transaction\n"));
693 TALLOC_FREE(new_acct);
694 return NT_STATUS_ACCESS_DENIED;
698 /* add the new account and lock it */
699 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
703 /* Rename the posix user. Follow the semantics of _samr_create_user()
704 so that we lower case the posix name but preserve the case in passdb */
706 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
707 strlower_m( oldname_lower );
709 fstrcpy( newname_lower, newname );
710 strlower_m( newname_lower );
712 rename_script = talloc_string_sub2(new_acct,
719 if (!rename_script) {
722 rename_script = talloc_string_sub2(new_acct,
729 if (!rename_script) {
732 rename_ret = smbrun(rename_script, NULL);
734 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
735 rename_script, rename_ret));
737 if (rename_ret != 0) {
741 smb_nscd_flush_user_cache();
743 /* rewrite the rid->username record */
745 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
749 tdb_delete_samacct_only( old_acct );
751 if (db_sam->transaction_commit(db_sam) != 0) {
753 * Ok, we're screwed. We've changed the posix account, but
754 * could not adapt passdb.tdb. Shall we change the posix
757 DEBUG(0, ("transaction_commit failed\n"));
758 TALLOC_FREE(new_acct);
759 return NT_STATUS_INTERNAL_DB_CORRUPTION;
762 TALLOC_FREE(new_acct );
766 if (db_sam->transaction_cancel(db_sam) != 0) {
767 smb_panic("transaction_cancel failed");
770 TALLOC_FREE(new_acct);
772 return NT_STATUS_ACCESS_DENIED;
775 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
780 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
784 rid = BASE_RID; /* Default if not set */
786 if (!tdbsam_open(tdbsam_filename)) {
787 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
792 if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
793 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
803 struct tdbsam_search_state {
804 struct pdb_methods *methods;
813 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
815 struct tdbsam_search_state *state = talloc_get_type_abort(
816 private_data, struct tdbsam_search_state);
817 size_t prefixlen = strlen(RIDPREFIX);
820 if ((rec->key.dsize < prefixlen)
821 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
825 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
827 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
833 static void tdbsam_search_end(struct pdb_search *search)
835 struct tdbsam_search_state *state = talloc_get_type_abort(
836 search->private_data, struct tdbsam_search_state);
840 static bool tdbsam_search_next_entry(struct pdb_search *search,
841 struct samr_displayentry *entry)
843 struct tdbsam_search_state *state = talloc_get_type_abort(
844 search->private_data, struct tdbsam_search_state);
845 struct samu *user = NULL;
851 user = samu_new(talloc_tos());
853 DEBUG(0, ("samu_new failed\n"));
857 if (state->current == state->num_rids) {
861 rid = state->rids[state->current++];
863 status = tdbsam_getsampwrid(state->methods, user, rid);
865 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
867 * Someone has deleted that user since we listed the RIDs
872 if (!NT_STATUS_IS_OK(status)) {
873 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
879 if ((state->acct_flags != 0) &&
880 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
884 entry->acct_flags = pdb_get_acct_ctrl(user);
886 entry->account_name = talloc_strdup(
887 search->mem_ctx, pdb_get_username(user));
888 entry->fullname = talloc_strdup(
889 search->mem_ctx, pdb_get_fullname(user));
890 entry->description = talloc_strdup(
891 search->mem_ctx, pdb_get_acct_desc(user));
895 if ((entry->account_name == NULL) || (entry->fullname == NULL)
896 || (entry->description == NULL)) {
897 DEBUG(0, ("talloc_strdup failed\n"));
904 static bool tdbsam_search_users(struct pdb_methods *methods,
905 struct pdb_search *search,
908 struct tdbsam_search_state *state;
910 if (!tdbsam_open(tdbsam_filename)) {
911 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
916 state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
918 DEBUG(0, ("talloc failed\n"));
921 state->acct_flags = acct_flags;
922 state->methods = methods;
924 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
926 search->private_data = state;
927 search->next_entry = tdbsam_search_next_entry;
928 search->search_end = tdbsam_search_end;
933 /*********************************************************************
934 Initialize the tdb sam backend. Setup the dispath table of methods,
936 *********************************************************************/
938 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
941 char *tdbfile = NULL;
942 const char *pfile = location;
944 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
948 (*pdb_method)->name = "tdbsam";
950 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
951 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
952 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
953 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
954 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
955 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
956 (*pdb_method)->search_users = tdbsam_search_users;
958 (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
959 (*pdb_method)->new_rid = tdbsam_new_rid;
961 /* save the path for later */
964 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
965 PASSDB_FILE_NAME) < 0) {
966 return NT_STATUS_NO_MEMORY;
970 tdbsam_filename = SMB_STRDUP(pfile);
971 if (!tdbsam_filename) {
972 return NT_STATUS_NO_MEMORY;
976 /* no private data */
978 (*pdb_method)->private_data = NULL;
979 (*pdb_method)->free_private_data = NULL;
984 NTSTATUS pdb_tdbsam_init(void)
986 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);