dsdb/repl_meta_data: split out replmd_deletion_state()
[Samba.git] / source3 / passdb / pdb_tdb.c
blobf256e6c7fb323c2220d409efeed0f903e1427fc8
1 /*
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)
14 * any later version.
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
19 * more details.
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/>.
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "passdb.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "../libcli/security/security.h"
31 #include "util_tdb.h"
32 #include "passdb/pdb_tdb.h"
34 #if 0 /* when made a module use this */
36 static int tdbsam_debug_level = DBGC_ALL;
37 #undef DBGC_CLASS
38 #define DBGC_CLASS tdbsam_debug_level
40 #else
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_PASSDB
45 #endif
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;
62 static bool map_builtin;
64 struct tdbsam_convert_state {
65 int32_t from;
66 bool success;
69 static int tdbsam_convert_one(struct db_record *rec, void *priv)
71 struct tdbsam_convert_state *state =
72 (struct tdbsam_convert_state *)priv;
73 struct samu *user;
74 TDB_DATA data;
75 NTSTATUS status;
76 bool ret;
77 TDB_DATA key;
78 TDB_DATA value;
80 key = dbwrap_record_get_key(rec);
82 if (key.dsize < USERPREFIX_LEN) {
83 return 0;
85 if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
86 return 0;
89 user = samu_new(talloc_tos());
90 if (user == NULL) {
91 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
92 state->success = false;
93 return -1;
96 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
97 "(version:%d)\n", (char *)key.dptr, state->from));
99 value = dbwrap_record_get_value(rec);
101 switch (state->from) {
102 case 0:
103 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
104 (uint8 *)value.dptr,
105 value.dsize);
106 break;
107 case 1:
108 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
109 (uint8 *)value.dptr,
110 value.dsize);
111 break;
112 case 2:
113 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
114 (uint8 *)value.dptr,
115 value.dsize);
116 break;
117 case 3:
118 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
119 (uint8 *)value.dptr,
120 value.dsize);
121 break;
122 case 4:
123 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
124 (uint8 *)value.dptr,
125 value.dsize);
126 break;
127 default:
128 /* unknown tdbsam version */
129 ret = False;
131 if (!ret) {
132 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
133 "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
134 state->from));
135 TALLOC_FREE(user);
136 state->success = false;
137 return -1;
140 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
141 TALLOC_FREE(user);
143 if (data.dsize == -1) {
144 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
145 "the new format\n"));
146 state->success = false;
147 return -1;
150 status = dbwrap_record_store(rec, data, TDB_MODIFY);
151 if (!NT_STATUS_IS_OK(status)) {
152 DEBUG(0, ("Could not store the new record: %s\n",
153 nt_errstr(status)));
154 state->success = false;
155 return -1;
158 return 0;
161 /**********************************************************************
162 Struct and function to backup an old record.
163 *********************************************************************/
165 struct tdbsam_backup_state {
166 struct db_context *new_db;
167 bool success;
170 static int backup_copy_fn(struct db_record *orig_rec, void *state)
172 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
173 struct db_record *new_rec;
174 NTSTATUS status;
175 TDB_DATA key;
176 TDB_DATA value;
178 key = dbwrap_record_get_key(orig_rec);
180 new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
181 if (new_rec == NULL) {
182 bs->success = false;
183 return 1;
186 value = dbwrap_record_get_value(orig_rec);
188 status = dbwrap_record_store(new_rec, value, TDB_INSERT);
190 TALLOC_FREE(new_rec);
192 if (!NT_STATUS_IS_OK(status)) {
193 bs->success = false;
194 return 1;
196 return 0;
199 /**********************************************************************
200 Make a backup of an old passdb and replace the new one with it. We
201 have to do this as between 3.0.x and 3.2.x the hash function changed
202 by mistake (used unsigned char * instead of char *). This means the
203 previous simple update code will fail due to not being able to find
204 existing records to replace in the tdbsam_convert_one() function. JRA.
205 *********************************************************************/
207 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
209 TALLOC_CTX *frame = talloc_stackframe();
210 const char *tmp_fname = NULL;
211 struct db_context *tmp_db = NULL;
212 struct db_context *orig_db = *pp_db;
213 struct tdbsam_backup_state bs;
214 NTSTATUS status;
216 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
217 if (!tmp_fname) {
218 TALLOC_FREE(frame);
219 return false;
222 unlink(tmp_fname);
224 /* Remember to open this on the NULL context. We need
225 * it to stay around after we return from here. */
227 tmp_db = db_open(NULL, tmp_fname, 0,
228 TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
229 DBWRAP_LOCK_ORDER_1);
230 if (tmp_db == NULL) {
231 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
232 "[%s]\n", tmp_fname));
233 TALLOC_FREE(frame);
234 return false;
237 if (dbwrap_transaction_start(orig_db) != 0) {
238 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
239 unlink(tmp_fname);
240 TALLOC_FREE(tmp_db);
241 TALLOC_FREE(frame);
242 return false;
244 if (dbwrap_transaction_start(tmp_db) != 0) {
245 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
246 dbwrap_transaction_cancel(orig_db);
247 unlink(tmp_fname);
248 TALLOC_FREE(tmp_db);
249 TALLOC_FREE(frame);
250 return false;
253 bs.new_db = tmp_db;
254 bs.success = true;
256 status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
257 if (!NT_STATUS_IS_OK(status)) {
258 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
259 goto cancel;
262 if (!bs.success) {
263 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
264 goto cancel;
267 if (dbwrap_transaction_commit(orig_db) != 0) {
268 smb_panic("tdbsam_convert_backup: orig commit failed\n");
270 if (dbwrap_transaction_commit(tmp_db) != 0) {
271 smb_panic("tdbsam_convert_backup: orig commit failed\n");
274 /* be sure to close the DBs _before_ renaming the file */
276 TALLOC_FREE(orig_db);
277 TALLOC_FREE(tmp_db);
279 /* This is safe from other users as we know we're
280 * under a mutex here. */
282 if (rename(tmp_fname, dbname) == -1) {
283 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
284 tmp_fname,
285 dbname,
286 strerror(errno)));
287 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
290 TALLOC_FREE(frame);
292 /* re-open the converted TDB */
294 orig_db = db_open(NULL, dbname, 0,
295 TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
296 DBWRAP_LOCK_ORDER_1);
297 if (orig_db == NULL) {
298 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
299 "converted passdb TDB [%s]\n", dbname));
300 return false;
303 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
304 dbname ));
306 /* Replace the global db pointer. */
307 *pp_db = orig_db;
308 return true;
310 cancel:
312 if (dbwrap_transaction_cancel(orig_db) != 0) {
313 smb_panic("tdbsam_convert: transaction_cancel failed");
316 if (dbwrap_transaction_cancel(tmp_db) != 0) {
317 smb_panic("tdbsam_convert: transaction_cancel failed");
320 unlink(tmp_fname);
321 TALLOC_FREE(tmp_db);
322 TALLOC_FREE(frame);
323 return false;
326 static bool tdbsam_upgrade_next_rid(struct db_context *db)
328 TDB_CONTEXT *tdb;
329 uint32 rid;
330 bool ok = false;
331 NTSTATUS status;
333 status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
334 if (NT_STATUS_IS_OK(status)) {
335 return true;
338 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
339 TDB_DEFAULT, O_RDONLY, 0644);
341 if (tdb) {
342 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
343 if (!ok) {
344 rid = BASE_RID;
346 tdb_close(tdb);
347 } else {
348 rid = BASE_RID;
351 status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
352 if (!NT_STATUS_IS_OK(status)) {
353 return false;
356 return true;
359 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
361 struct tdbsam_convert_state state;
362 struct db_context *db = NULL;
363 NTSTATUS status;
365 /* We only need the update backup for local db's. */
366 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
367 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
368 return false;
371 db = *pp_db;
372 state.from = from;
373 state.success = true;
375 if (dbwrap_transaction_start(db) != 0) {
376 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
377 return false;
380 if (!tdbsam_upgrade_next_rid(db)) {
381 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
382 goto cancel;
385 status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
386 if (!NT_STATUS_IS_OK(status)) {
387 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
388 goto cancel;
391 if (!state.success) {
392 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
393 goto cancel;
396 status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
397 TDBSAM_VERSION);
398 if (!NT_STATUS_IS_OK(status)) {
399 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
400 "%s\n", nt_errstr(status)));
401 goto cancel;
404 status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
405 TDBSAM_MINOR_VERSION);
406 if (!NT_STATUS_IS_OK(status)) {
407 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
408 "version: %s\n", nt_errstr(status)));
409 goto cancel;
412 if (dbwrap_transaction_commit(db) != 0) {
413 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
414 return false;
417 return true;
419 cancel:
420 if (dbwrap_transaction_cancel(db) != 0) {
421 smb_panic("tdbsam_convert: transaction_cancel failed");
424 return false;
427 /*********************************************************************
428 Open the tdbsam file based on the absolute path specified.
429 Uses a reference count to allow multiple open calls.
430 *********************************************************************/
432 static bool tdbsam_open( const char *name )
434 int32 version;
435 int32 minor_version;
436 NTSTATUS status;
438 /* check if we are already open */
440 if ( db_sam ) {
441 return true;
444 /* Try to open tdb passwd. Create a new one if necessary */
446 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
447 DBWRAP_LOCK_ORDER_1);
448 if (db_sam == NULL) {
449 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
450 "[%s]\n", name));
451 return false;
454 /* Check the version */
455 status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
456 &version);
457 if (!NT_STATUS_IS_OK(status)) {
458 version = 0; /* Version not found, assume version 0 */
461 /* Get the minor version */
462 status = dbwrap_fetch_int32_bystring(
463 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
464 if (!NT_STATUS_IS_OK(status)) {
465 minor_version = 0; /* Minor version not found, assume 0 */
468 /* Compare the version */
469 if (version > TDBSAM_VERSION) {
470 /* Version more recent than the latest known */
471 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
472 TALLOC_FREE(db_sam);
473 return false;
476 if ( version < TDBSAM_VERSION ||
477 (version == TDBSAM_VERSION &&
478 minor_version < TDBSAM_MINOR_VERSION) ) {
480 * Ok - we think we're going to have to convert.
481 * Due to the backup process we now must do to
482 * upgrade we have to get a mutex and re-check
483 * the version. Someone else may have upgraded
484 * whilst we were checking.
487 struct named_mutex *mtx = grab_named_mutex(NULL,
488 "tdbsam_upgrade_mutex",
489 600);
491 if (!mtx) {
492 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
493 TALLOC_FREE(db_sam);
494 return false;
497 /* Re-check the version */
498 status = dbwrap_fetch_int32_bystring(
499 db_sam, TDBSAM_VERSION_STRING, &version);
500 if (!NT_STATUS_IS_OK(status)) {
501 version = 0; /* Version not found, assume version 0 */
504 /* Re-check the minor version */
505 status = dbwrap_fetch_int32_bystring(
506 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
507 if (!NT_STATUS_IS_OK(status)) {
508 minor_version = 0; /* Minor version not found, assume 0 */
511 /* Compare the version */
512 if (version > TDBSAM_VERSION) {
513 /* Version more recent than the latest known */
514 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
515 TALLOC_FREE(db_sam);
516 TALLOC_FREE(mtx);
517 return false;
520 if ( version < TDBSAM_VERSION ||
521 (version == TDBSAM_VERSION &&
522 minor_version < TDBSAM_MINOR_VERSION) ) {
524 * Note that minor versions we read that are greater
525 * than the current minor version we have hard coded
526 * are assumed to be compatible if they have the same
527 * major version. That allows previous versions of the
528 * passdb code that don't know about minor versions to
529 * still use this database. JRA.
532 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
533 "version %d.%d.\n",
534 version,
535 minor_version,
536 TDBSAM_VERSION,
537 TDBSAM_MINOR_VERSION));
539 if ( !tdbsam_convert(&db_sam, name, version) ) {
540 DEBUG(0, ("tdbsam_open: Error when trying to convert "
541 "tdbsam [%s]\n",name));
542 TALLOC_FREE(db_sam);
543 TALLOC_FREE(mtx);
544 return false;
547 DEBUG(3, ("TDBSAM converted successfully.\n"));
549 TALLOC_FREE(mtx);
552 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
554 return true;
557 /******************************************************************
558 Lookup a name in the SAM TDB
559 ******************************************************************/
561 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
562 struct samu *user, const char *sname)
564 TDB_DATA data;
565 fstring keystr;
566 fstring name;
567 NTSTATUS status;
569 if ( !user ) {
570 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
571 return NT_STATUS_NO_MEMORY;
574 /* Data is stored in all lower-case */
575 fstrcpy(name, sname);
576 if (!strlower_m(name)) {
577 return NT_STATUS_INVALID_PARAMETER;
580 /* set search key */
581 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
583 /* open the database */
585 if ( !tdbsam_open( tdbsam_filename ) ) {
586 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
587 return NT_STATUS_ACCESS_DENIED;
590 /* get the record */
592 status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
593 if (!NT_STATUS_IS_OK(status)) {
594 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
595 DEBUGADD(5, (" Key: %s\n", keystr));
596 return NT_STATUS_NO_SUCH_USER;
599 /* unpack the buffer */
601 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
602 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
603 SAFE_FREE(data.dptr);
604 return NT_STATUS_NO_MEMORY;
607 /* success */
609 TALLOC_FREE(data.dptr);
611 return NT_STATUS_OK;
614 /***************************************************************************
615 Search by rid
616 **************************************************************************/
618 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
619 struct samu *user, uint32 rid)
621 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
622 TDB_DATA data;
623 fstring keystr;
624 fstring name;
626 if ( !user ) {
627 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
628 return nt_status;
631 /* set search key */
633 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
635 /* open the database */
637 if ( !tdbsam_open( tdbsam_filename ) ) {
638 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
639 return NT_STATUS_ACCESS_DENIED;
642 /* get the record */
644 nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
645 if (!NT_STATUS_IS_OK(nt_status)) {
646 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
647 return nt_status;
650 fstrcpy(name, (const char *)data.dptr);
651 TALLOC_FREE(data.dptr);
653 return tdbsam_getsampwnam (my_methods, user, name);
656 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
657 struct samu * user, const struct dom_sid *sid)
659 uint32 rid;
661 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
662 return NT_STATUS_UNSUCCESSFUL;
664 return tdbsam_getsampwrid(my_methods, user, rid);
667 static bool tdb_delete_samacct_only( struct samu *sam_pass )
669 fstring keystr;
670 fstring name;
671 NTSTATUS status;
673 fstrcpy(name, pdb_get_username(sam_pass));
674 if (!strlower_m(name)) {
675 return false;
678 /* set the search key */
680 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
682 /* it's outaa here! 8^) */
683 if ( !tdbsam_open( tdbsam_filename ) ) {
684 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
685 tdbsam_filename));
686 return false;
689 status = dbwrap_delete_bystring(db_sam, keystr);
690 if (!NT_STATUS_IS_OK(status)) {
691 DEBUG(5, ("Error deleting entry from tdb passwd "
692 "database: %s!\n", nt_errstr(status)));
693 return false;
696 return true;
699 /***************************************************************************
700 Delete a struct samu records for the username and RID key
701 ****************************************************************************/
703 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
704 struct samu *sam_pass)
706 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
707 fstring keystr;
708 uint32 rid;
709 fstring name;
711 /* open the database */
713 if ( !tdbsam_open( tdbsam_filename ) ) {
714 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
715 tdbsam_filename));
716 return NT_STATUS_ACCESS_DENIED;
719 fstrcpy(name, pdb_get_username(sam_pass));
720 if (!strlower_m(name)) {
721 return NT_STATUS_INVALID_PARAMETER;
724 /* set the search key */
726 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
728 rid = pdb_get_user_rid(sam_pass);
730 /* it's outaa here! 8^) */
732 if (dbwrap_transaction_start(db_sam) != 0) {
733 DEBUG(0, ("Could not start transaction\n"));
734 return NT_STATUS_UNSUCCESSFUL;
737 nt_status = dbwrap_delete_bystring(db_sam, keystr);
738 if (!NT_STATUS_IS_OK(nt_status)) {
739 DEBUG(5, ("Error deleting entry from tdb passwd "
740 "database: %s!\n", nt_errstr(nt_status)));
741 goto cancel;
744 /* set the search key */
746 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
748 /* it's outaa here! 8^) */
750 nt_status = dbwrap_delete_bystring(db_sam, keystr);
751 if (!NT_STATUS_IS_OK(nt_status)) {
752 DEBUG(5, ("Error deleting entry from tdb rid "
753 "database: %s!\n", nt_errstr(nt_status)));
754 goto cancel;
757 if (dbwrap_transaction_commit(db_sam) != 0) {
758 DEBUG(0, ("Could not commit transaction\n"));
759 return NT_STATUS_INTERNAL_DB_CORRUPTION;
762 return NT_STATUS_OK;
764 cancel:
765 if (dbwrap_transaction_cancel(db_sam) != 0) {
766 smb_panic("transaction_cancel failed");
769 return nt_status;
773 /***************************************************************************
774 Update the TDB SAM account record only
775 Assumes that the tdbsam is already open
776 ****************************************************************************/
777 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
779 TDB_DATA data;
780 uint8 *buf = NULL;
781 fstring keystr;
782 fstring name;
783 bool ret = false;
784 NTSTATUS status;
786 /* copy the struct samu struct into a BYTE buffer for storage */
788 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
789 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
790 goto done;
792 data.dptr = buf;
794 fstrcpy(name, pdb_get_username(newpwd));
795 if (!strlower_m(name)) {
796 goto done;
799 DEBUG(5, ("Storing %saccount %s with RID %d\n",
800 flag == TDB_INSERT ? "(new) " : "", name,
801 pdb_get_user_rid(newpwd)));
803 /* setup the USER index key */
804 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
806 /* add the account */
808 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
809 if (!NT_STATUS_IS_OK(status)) {
810 DEBUG(0, ("Unable to modify passwd TDB: %s!",
811 nt_errstr(status)));
812 goto done;
815 ret = true;
817 done:
818 /* cleanup */
819 SAFE_FREE(buf);
820 return ret;
823 /***************************************************************************
824 Update the TDB SAM RID record only
825 Assumes that the tdbsam is already open
826 ****************************************************************************/
827 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
829 TDB_DATA data;
830 fstring keystr;
831 fstring name;
832 NTSTATUS status;
834 fstrcpy(name, pdb_get_username(newpwd));
835 if (!strlower_m(name)) {
836 return false;
839 /* setup RID data */
840 data = string_term_tdb_data(name);
842 /* setup the RID index key */
843 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
844 pdb_get_user_rid(newpwd));
846 /* add the reference */
847 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
848 if (!NT_STATUS_IS_OK(status)) {
849 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
850 nt_errstr(status)));
851 return false;
854 return true;
858 /***************************************************************************
859 Update the TDB SAM
860 ****************************************************************************/
862 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
863 int flag)
865 uint32_t oldrid;
866 uint32_t newrid;
868 if (!(newrid = pdb_get_user_rid(newpwd))) {
869 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
870 pdb_get_username(newpwd)));
871 return False;
874 oldrid = newrid;
876 /* open the database */
878 if ( !tdbsam_open( tdbsam_filename ) ) {
879 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
880 return False;
883 if (dbwrap_transaction_start(db_sam) != 0) {
884 DEBUG(0, ("Could not start transaction\n"));
885 return false;
888 /* If we are updating, we may be changing this users RID. Retrieve the old RID
889 so we can check. */
891 if (flag == TDB_MODIFY) {
892 struct samu *account = samu_new(talloc_tos());
893 if (account == NULL) {
894 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
895 goto cancel;
897 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
898 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
899 pdb_get_username(newpwd)));
900 TALLOC_FREE(account);
901 goto cancel;
903 if (!(oldrid = pdb_get_user_rid(account))) {
904 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
905 TALLOC_FREE(account);
906 goto cancel;
908 TALLOC_FREE(account);
911 /* Update the new samu entry. */
912 if (!tdb_update_samacct_only(newpwd, flag)) {
913 goto cancel;
916 /* Now take care of the case where the RID changed. We need
917 * to delete the old RID key and add the new. */
919 if (flag == TDB_MODIFY && newrid != oldrid) {
920 fstring keystr;
922 /* Delete old RID key */
923 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
924 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
925 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
926 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
927 goto cancel;
929 /* Insert new RID key */
930 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
931 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
932 goto cancel;
934 } else {
935 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
936 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
937 if (!tdb_update_ridrec_only(newpwd, flag)) {
938 goto cancel;
942 if (dbwrap_transaction_commit(db_sam) != 0) {
943 DEBUG(0, ("Could not commit transaction\n"));
944 return false;
947 return true;
949 cancel:
950 if (dbwrap_transaction_cancel(db_sam) != 0) {
951 smb_panic("transaction_cancel failed");
953 return false;
956 /***************************************************************************
957 Modifies an existing struct samu
958 ****************************************************************************/
960 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
962 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
963 return NT_STATUS_UNSUCCESSFUL;
965 return NT_STATUS_OK;
968 /***************************************************************************
969 Adds an existing struct samu
970 ****************************************************************************/
972 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
974 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
975 return NT_STATUS_UNSUCCESSFUL;
977 return NT_STATUS_OK;
980 /***************************************************************************
981 Renames a struct samu
982 - check for the posix user/rename user script
983 - Add and lock the new user record
984 - rename the posix user
985 - rewrite the rid->username record
986 - delete the old user
987 - unlock the new user record
988 ***************************************************************************/
989 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
990 struct samu *old_acct,
991 const char *newname)
993 struct samu *new_acct = NULL;
994 char *rename_script = NULL;
995 int rename_ret;
996 fstring oldname_lower;
997 fstring newname_lower;
999 /* can't do anything without an external script */
1001 if ( !(new_acct = samu_new( talloc_tos() )) ) {
1002 return NT_STATUS_NO_MEMORY;
1005 rename_script = lp_renameuser_script(new_acct);
1006 if (!rename_script) {
1007 TALLOC_FREE(new_acct);
1008 return NT_STATUS_NO_MEMORY;
1010 if (!*rename_script) {
1011 TALLOC_FREE(new_acct);
1012 return NT_STATUS_ACCESS_DENIED;
1015 if ( !pdb_copy_sam_account(new_acct, old_acct)
1016 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1018 TALLOC_FREE(new_acct);
1019 return NT_STATUS_NO_MEMORY;
1022 /* open the database */
1023 if ( !tdbsam_open( tdbsam_filename ) ) {
1024 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1025 tdbsam_filename));
1026 TALLOC_FREE(new_acct);
1027 return NT_STATUS_ACCESS_DENIED;
1030 if (dbwrap_transaction_start(db_sam) != 0) {
1031 DEBUG(0, ("Could not start transaction\n"));
1032 TALLOC_FREE(new_acct);
1033 return NT_STATUS_ACCESS_DENIED;
1037 /* add the new account and lock it */
1038 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1039 goto cancel;
1042 /* Rename the posix user. Follow the semantics of _samr_create_user()
1043 so that we lower case the posix name but preserve the case in passdb */
1045 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1046 if (!strlower_m( oldname_lower )) {
1047 goto cancel;
1050 fstrcpy( newname_lower, newname );
1051 if (!strlower_m( newname_lower )) {
1052 goto cancel;
1055 rename_script = talloc_string_sub2(new_acct,
1056 rename_script,
1057 "%unew",
1058 newname_lower,
1059 true,
1060 false,
1061 true);
1062 if (!rename_script) {
1063 goto cancel;
1065 rename_script = talloc_string_sub2(new_acct,
1066 rename_script,
1067 "%uold",
1068 oldname_lower,
1069 true,
1070 false,
1071 true);
1072 if (!rename_script) {
1073 goto cancel;
1075 rename_ret = smbrun(rename_script, NULL);
1077 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1078 rename_script, rename_ret));
1080 if (rename_ret != 0) {
1081 goto cancel;
1084 smb_nscd_flush_user_cache();
1086 /* rewrite the rid->username record */
1088 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1089 goto cancel;
1092 tdb_delete_samacct_only( old_acct );
1094 if (dbwrap_transaction_commit(db_sam) != 0) {
1096 * Ok, we're screwed. We've changed the posix account, but
1097 * could not adapt passdb.tdb. Shall we change the posix
1098 * account back?
1100 DEBUG(0, ("transaction_commit failed\n"));
1101 TALLOC_FREE(new_acct);
1102 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1105 TALLOC_FREE(new_acct );
1106 return NT_STATUS_OK;
1108 cancel:
1109 if (dbwrap_transaction_cancel(db_sam) != 0) {
1110 smb_panic("transaction_cancel failed");
1113 TALLOC_FREE(new_acct);
1115 return NT_STATUS_ACCESS_DENIED;
1118 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1120 return PDB_CAP_STORE_RIDS;
1123 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1125 uint32 rid;
1126 NTSTATUS status;
1128 rid = BASE_RID; /* Default if not set */
1130 if (!tdbsam_open(tdbsam_filename)) {
1131 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1132 tdbsam_filename));
1133 return false;
1136 status = dbwrap_trans_change_uint32_atomic_bystring(
1137 db_sam, NEXT_RID_STRING, &rid, 1);
1138 if (!NT_STATUS_IS_OK(status)) {
1139 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1140 NEXT_RID_STRING, nt_errstr(status)));
1141 return false;
1144 *prid = rid;
1146 return true;
1149 struct tdbsam_search_state {
1150 struct pdb_methods *methods;
1151 uint32_t acct_flags;
1153 uint32_t *rids;
1154 uint32_t num_rids;
1155 ssize_t array_size;
1156 uint32_t current;
1159 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1161 struct tdbsam_search_state *state = talloc_get_type_abort(
1162 private_data, struct tdbsam_search_state);
1163 size_t prefixlen = strlen(RIDPREFIX);
1164 uint32 rid;
1165 TDB_DATA key;
1167 key = dbwrap_record_get_key(rec);
1169 if ((key.dsize < prefixlen)
1170 || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1171 return 0;
1174 rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1176 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1177 &state->array_size);
1179 return 0;
1182 static void tdbsam_search_end(struct pdb_search *search)
1184 struct tdbsam_search_state *state = talloc_get_type_abort(
1185 search->private_data, struct tdbsam_search_state);
1186 TALLOC_FREE(state);
1189 static bool tdbsam_search_next_entry(struct pdb_search *search,
1190 struct samr_displayentry *entry)
1192 struct tdbsam_search_state *state = talloc_get_type_abort(
1193 search->private_data, struct tdbsam_search_state);
1194 struct samu *user = NULL;
1195 NTSTATUS status;
1196 uint32_t rid;
1198 again:
1199 TALLOC_FREE(user);
1200 user = samu_new(talloc_tos());
1201 if (user == NULL) {
1202 DEBUG(0, ("samu_new failed\n"));
1203 return false;
1206 if (state->current == state->num_rids) {
1207 TALLOC_FREE(user);
1208 return false;
1211 rid = state->rids[state->current++];
1213 status = tdbsam_getsampwrid(state->methods, user, rid);
1215 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1217 * Someone has deleted that user since we listed the RIDs
1219 goto again;
1222 if (!NT_STATUS_IS_OK(status)) {
1223 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1224 nt_errstr(status)));
1225 TALLOC_FREE(user);
1226 return false;
1229 if ((state->acct_flags != 0) &&
1230 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1231 goto again;
1234 entry->acct_flags = pdb_get_acct_ctrl(user);
1235 entry->rid = rid;
1236 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1237 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1238 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1240 TALLOC_FREE(user);
1242 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1243 || (entry->description == NULL)) {
1244 DEBUG(0, ("talloc_strdup failed\n"));
1245 return false;
1248 return true;
1251 static bool tdbsam_search_users(struct pdb_methods *methods,
1252 struct pdb_search *search,
1253 uint32 acct_flags)
1255 struct tdbsam_search_state *state;
1257 if (!tdbsam_open(tdbsam_filename)) {
1258 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1259 tdbsam_filename));
1260 return false;
1263 state = talloc_zero(search, struct tdbsam_search_state);
1264 if (state == NULL) {
1265 DEBUG(0, ("talloc failed\n"));
1266 return false;
1268 state->acct_flags = acct_flags;
1269 state->methods = methods;
1271 dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1273 search->private_data = state;
1274 search->next_entry = tdbsam_search_next_entry;
1275 search->search_end = tdbsam_search_end;
1277 return true;
1280 static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
1282 return map_builtin;
1285 /*********************************************************************
1286 Initialize the tdb sam backend. Setup the dispath table of methods,
1287 open the tdb, etc...
1288 *********************************************************************/
1290 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1292 NTSTATUS nt_status;
1293 char *tdbfile = NULL;
1294 const char *pfile = location;
1296 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1297 return nt_status;
1300 (*pdb_method)->name = "tdbsam";
1302 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1303 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1304 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1305 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1306 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1307 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1308 (*pdb_method)->search_users = tdbsam_search_users;
1310 (*pdb_method)->capabilities = tdbsam_capabilities;
1311 (*pdb_method)->new_rid = tdbsam_new_rid;
1313 (*pdb_method)->is_responsible_for_builtin =
1314 tdbsam_is_responsible_for_builtin;
1315 map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
1317 /* save the path for later */
1319 if (!location) {
1320 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1321 PASSDB_FILE_NAME) < 0) {
1322 return NT_STATUS_NO_MEMORY;
1324 pfile = tdbfile;
1326 tdbsam_filename = SMB_STRDUP(pfile);
1327 if (!tdbsam_filename) {
1328 return NT_STATUS_NO_MEMORY;
1330 SAFE_FREE(tdbfile);
1332 /* no private data */
1334 (*pdb_method)->private_data = NULL;
1335 (*pdb_method)->free_private_data = NULL;
1337 return NT_STATUS_OK;
1340 NTSTATUS pdb_tdbsam_init(void)
1342 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);