libcli/smb: move smb2cli_write.c from source3 to the toplevel
[Samba/gbeck.git] / source3 / passdb / pdb_tdb.c
bloba090fcd5bb4722d1304f43ec075a92ef69c2f237
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;
63 struct tdbsam_convert_state {
64 int32_t from;
65 bool success;
68 static int tdbsam_convert_one(struct db_record *rec, void *priv)
70 struct tdbsam_convert_state *state =
71 (struct tdbsam_convert_state *)priv;
72 struct samu *user;
73 TDB_DATA data;
74 NTSTATUS status;
75 bool ret;
76 TDB_DATA key;
77 TDB_DATA value;
79 key = dbwrap_record_get_key(rec);
81 if (key.dsize < USERPREFIX_LEN) {
82 return 0;
84 if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
85 return 0;
88 user = samu_new(talloc_tos());
89 if (user == NULL) {
90 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
91 state->success = false;
92 return -1;
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) {
101 case 0:
102 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
103 (uint8 *)value.dptr,
104 value.dsize);
105 break;
106 case 1:
107 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
108 (uint8 *)value.dptr,
109 value.dsize);
110 break;
111 case 2:
112 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
113 (uint8 *)value.dptr,
114 value.dsize);
115 break;
116 case 3:
117 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
118 (uint8 *)value.dptr,
119 value.dsize);
120 break;
121 case 4:
122 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
123 (uint8 *)value.dptr,
124 value.dsize);
125 break;
126 default:
127 /* unknown tdbsam version */
128 ret = False;
130 if (!ret) {
131 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
132 "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
133 state->from));
134 TALLOC_FREE(user);
135 state->success = false;
136 return -1;
139 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
140 TALLOC_FREE(user);
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;
146 return -1;
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",
152 nt_errstr(status)));
153 state->success = false;
154 return -1;
157 return 0;
160 /**********************************************************************
161 Struct and function to backup an old record.
162 *********************************************************************/
164 struct tdbsam_backup_state {
165 struct db_context *new_db;
166 bool success;
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;
173 NTSTATUS status;
174 TDB_DATA key;
175 TDB_DATA value;
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) {
181 bs->success = false;
182 return 1;
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)) {
192 bs->success = false;
193 return 1;
195 return 0;
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;
213 NTSTATUS status;
215 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
216 if (!tmp_fname) {
217 TALLOC_FREE(frame);
218 return false;
221 unlink(tmp_fname);
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));
232 TALLOC_FREE(frame);
233 return false;
236 if (dbwrap_transaction_start(orig_db) != 0) {
237 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
238 unlink(tmp_fname);
239 TALLOC_FREE(tmp_db);
240 TALLOC_FREE(frame);
241 return false;
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);
246 unlink(tmp_fname);
247 TALLOC_FREE(tmp_db);
248 TALLOC_FREE(frame);
249 return false;
252 bs.new_db = tmp_db;
253 bs.success = true;
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"));
258 goto cancel;
261 if (!bs.success) {
262 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
263 goto cancel;
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);
276 TALLOC_FREE(tmp_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",
283 tmp_fname,
284 dbname,
285 strerror(errno)));
286 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
289 TALLOC_FREE(frame);
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));
299 return false;
302 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
303 dbname ));
305 /* Replace the global db pointer. */
306 *pp_db = orig_db;
307 return true;
309 cancel:
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");
319 unlink(tmp_fname);
320 TALLOC_FREE(tmp_db);
321 TALLOC_FREE(frame);
322 return false;
325 static bool tdbsam_upgrade_next_rid(struct db_context *db)
327 TDB_CONTEXT *tdb;
328 uint32 rid;
329 bool ok = false;
330 NTSTATUS status;
332 status = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
333 if (NT_STATUS_IS_OK(status)) {
334 return true;
337 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
338 TDB_DEFAULT, O_RDONLY, 0644);
340 if (tdb) {
341 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
342 if (!ok) {
343 rid = BASE_RID;
345 tdb_close(tdb);
346 } else {
347 rid = BASE_RID;
350 status = dbwrap_store_uint32(db, NEXT_RID_STRING, rid);
351 if (!NT_STATUS_IS_OK(status)) {
352 return false;
355 return true;
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;
362 NTSTATUS status;
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));
367 return false;
370 db = *pp_db;
371 state.from = from;
372 state.success = true;
374 if (dbwrap_transaction_start(db) != 0) {
375 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
376 return false;
379 if (!tdbsam_upgrade_next_rid(db)) {
380 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
381 goto cancel;
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"));
387 goto cancel;
390 if (!state.success) {
391 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
392 goto cancel;
395 status = dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
396 TDBSAM_VERSION);
397 if (!NT_STATUS_IS_OK(status)) {
398 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
399 "%s\n", nt_errstr(status)));
400 goto cancel;
403 status = dbwrap_store_int32(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)));
408 goto cancel;
411 if (dbwrap_transaction_commit(db) != 0) {
412 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
413 return false;
416 return true;
418 cancel:
419 if (dbwrap_transaction_cancel(db) != 0) {
420 smb_panic("tdbsam_convert: transaction_cancel failed");
423 return false;
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 )
433 int32 version;
434 int32 minor_version;
435 NTSTATUS status;
437 /* check if we are already open */
439 if ( db_sam ) {
440 return true;
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 "
449 "[%s]\n", name));
450 return false;
453 /* Check the version */
454 status = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING, &version);
455 if (!NT_STATUS_IS_OK(status)) {
456 version = 0; /* Version not found, assume version 0 */
459 /* Get the minor version */
460 status = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING,
461 &minor_version);
462 if (!NT_STATUS_IS_OK(status)) {
463 minor_version = 0; /* Minor version not found, assume 0 */
466 /* Compare the version */
467 if (version > TDBSAM_VERSION) {
468 /* Version more recent than the latest known */
469 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
470 TALLOC_FREE(db_sam);
471 return false;
474 if ( version < TDBSAM_VERSION ||
475 (version == TDBSAM_VERSION &&
476 minor_version < TDBSAM_MINOR_VERSION) ) {
478 * Ok - we think we're going to have to convert.
479 * Due to the backup process we now must do to
480 * upgrade we have to get a mutex and re-check
481 * the version. Someone else may have upgraded
482 * whilst we were checking.
485 struct named_mutex *mtx = grab_named_mutex(NULL,
486 "tdbsam_upgrade_mutex",
487 600);
489 if (!mtx) {
490 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
491 TALLOC_FREE(db_sam);
492 return false;
495 /* Re-check the version */
496 status = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING,
497 &version);
498 if (!NT_STATUS_IS_OK(status)) {
499 version = 0; /* Version not found, assume version 0 */
502 /* Re-check the minor version */
503 status = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING,
504 &minor_version);
505 if (!NT_STATUS_IS_OK(status)) {
506 minor_version = 0; /* Minor version not found, assume 0 */
509 /* Compare the version */
510 if (version > TDBSAM_VERSION) {
511 /* Version more recent than the latest known */
512 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
513 TALLOC_FREE(db_sam);
514 TALLOC_FREE(mtx);
515 return false;
518 if ( version < TDBSAM_VERSION ||
519 (version == TDBSAM_VERSION &&
520 minor_version < TDBSAM_MINOR_VERSION) ) {
522 * Note that minor versions we read that are greater
523 * than the current minor version we have hard coded
524 * are assumed to be compatible if they have the same
525 * major version. That allows previous versions of the
526 * passdb code that don't know about minor versions to
527 * still use this database. JRA.
530 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
531 "version %d.%d.\n",
532 version,
533 minor_version,
534 TDBSAM_VERSION,
535 TDBSAM_MINOR_VERSION));
537 if ( !tdbsam_convert(&db_sam, name, version) ) {
538 DEBUG(0, ("tdbsam_open: Error when trying to convert "
539 "tdbsam [%s]\n",name));
540 TALLOC_FREE(db_sam);
541 TALLOC_FREE(mtx);
542 return false;
545 DEBUG(3, ("TDBSAM converted successfully.\n"));
547 TALLOC_FREE(mtx);
550 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
552 return true;
555 /******************************************************************
556 Lookup a name in the SAM TDB
557 ******************************************************************/
559 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
560 struct samu *user, const char *sname)
562 TDB_DATA data;
563 fstring keystr;
564 fstring name;
565 NTSTATUS status;
567 if ( !user ) {
568 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
569 return NT_STATUS_NO_MEMORY;
572 /* Data is stored in all lower-case */
573 fstrcpy(name, sname);
574 strlower_m(name);
576 /* set search key */
577 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
579 /* open the database */
581 if ( !tdbsam_open( tdbsam_filename ) ) {
582 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
583 return NT_STATUS_ACCESS_DENIED;
586 /* get the record */
588 status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
589 if (!NT_STATUS_IS_OK(status)) {
590 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
591 DEBUGADD(5, (" Key: %s\n", keystr));
592 return NT_STATUS_NO_SUCH_USER;
595 /* unpack the buffer */
597 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
598 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
599 SAFE_FREE(data.dptr);
600 return NT_STATUS_NO_MEMORY;
603 /* success */
605 TALLOC_FREE(data.dptr);
607 return NT_STATUS_OK;
610 /***************************************************************************
611 Search by rid
612 **************************************************************************/
614 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
615 struct samu *user, uint32 rid)
617 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
618 TDB_DATA data;
619 fstring keystr;
620 fstring name;
622 if ( !user ) {
623 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
624 return nt_status;
627 /* set search key */
629 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
631 /* open the database */
633 if ( !tdbsam_open( tdbsam_filename ) ) {
634 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
635 return NT_STATUS_ACCESS_DENIED;
638 /* get the record */
640 nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
641 if (!NT_STATUS_IS_OK(nt_status)) {
642 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
643 return nt_status;
646 fstrcpy(name, (const char *)data.dptr);
647 TALLOC_FREE(data.dptr);
649 return tdbsam_getsampwnam (my_methods, user, name);
652 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
653 struct samu * user, const struct dom_sid *sid)
655 uint32 rid;
657 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
658 return NT_STATUS_UNSUCCESSFUL;
660 return tdbsam_getsampwrid(my_methods, user, rid);
663 static bool tdb_delete_samacct_only( struct samu *sam_pass )
665 fstring keystr;
666 fstring name;
667 NTSTATUS status;
669 fstrcpy(name, pdb_get_username(sam_pass));
670 strlower_m(name);
672 /* set the search key */
674 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
676 /* it's outaa here! 8^) */
677 if ( !tdbsam_open( tdbsam_filename ) ) {
678 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
679 tdbsam_filename));
680 return false;
683 status = dbwrap_delete_bystring(db_sam, keystr);
684 if (!NT_STATUS_IS_OK(status)) {
685 DEBUG(5, ("Error deleting entry from tdb passwd "
686 "database: %s!\n", nt_errstr(status)));
687 return false;
690 return true;
693 /***************************************************************************
694 Delete a struct samu records for the username and RID key
695 ****************************************************************************/
697 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
698 struct samu *sam_pass)
700 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
701 fstring keystr;
702 uint32 rid;
703 fstring name;
705 /* open the database */
707 if ( !tdbsam_open( tdbsam_filename ) ) {
708 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
709 tdbsam_filename));
710 return NT_STATUS_ACCESS_DENIED;
713 fstrcpy(name, pdb_get_username(sam_pass));
714 strlower_m(name);
716 /* set the search key */
718 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
720 rid = pdb_get_user_rid(sam_pass);
722 /* it's outaa here! 8^) */
724 if (dbwrap_transaction_start(db_sam) != 0) {
725 DEBUG(0, ("Could not start transaction\n"));
726 return NT_STATUS_UNSUCCESSFUL;
729 nt_status = dbwrap_delete_bystring(db_sam, keystr);
730 if (!NT_STATUS_IS_OK(nt_status)) {
731 DEBUG(5, ("Error deleting entry from tdb passwd "
732 "database: %s!\n", nt_errstr(nt_status)));
733 goto cancel;
736 /* set the search key */
738 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
740 /* it's outaa here! 8^) */
742 nt_status = dbwrap_delete_bystring(db_sam, keystr);
743 if (!NT_STATUS_IS_OK(nt_status)) {
744 DEBUG(5, ("Error deleting entry from tdb rid "
745 "database: %s!\n", nt_errstr(nt_status)));
746 goto cancel;
749 if (dbwrap_transaction_commit(db_sam) != 0) {
750 DEBUG(0, ("Could not commit transaction\n"));
751 return NT_STATUS_INTERNAL_DB_CORRUPTION;
754 return NT_STATUS_OK;
756 cancel:
757 if (dbwrap_transaction_cancel(db_sam) != 0) {
758 smb_panic("transaction_cancel failed");
761 return nt_status;
765 /***************************************************************************
766 Update the TDB SAM account record only
767 Assumes that the tdbsam is already open
768 ****************************************************************************/
769 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
771 TDB_DATA data;
772 uint8 *buf = NULL;
773 fstring keystr;
774 fstring name;
775 bool ret = false;
776 NTSTATUS status;
778 /* copy the struct samu struct into a BYTE buffer for storage */
780 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
781 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
782 goto done;
784 data.dptr = buf;
786 fstrcpy(name, pdb_get_username(newpwd));
787 strlower_m(name);
789 DEBUG(5, ("Storing %saccount %s with RID %d\n",
790 flag == TDB_INSERT ? "(new) " : "", name,
791 pdb_get_user_rid(newpwd)));
793 /* setup the USER index key */
794 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
796 /* add the account */
798 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
799 if (!NT_STATUS_IS_OK(status)) {
800 DEBUG(0, ("Unable to modify passwd TDB: %s!",
801 nt_errstr(status)));
802 goto done;
805 ret = true;
807 done:
808 /* cleanup */
809 SAFE_FREE(buf);
810 return ret;
813 /***************************************************************************
814 Update the TDB SAM RID record only
815 Assumes that the tdbsam is already open
816 ****************************************************************************/
817 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
819 TDB_DATA data;
820 fstring keystr;
821 fstring name;
822 NTSTATUS status;
824 fstrcpy(name, pdb_get_username(newpwd));
825 strlower_m(name);
827 /* setup RID data */
828 data = string_term_tdb_data(name);
830 /* setup the RID index key */
831 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
832 pdb_get_user_rid(newpwd));
834 /* add the reference */
835 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
838 nt_errstr(status)));
839 return false;
842 return true;
846 /***************************************************************************
847 Update the TDB SAM
848 ****************************************************************************/
850 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
851 int flag)
853 uint32_t oldrid;
854 uint32_t newrid;
856 if (!(newrid = pdb_get_user_rid(newpwd))) {
857 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
858 pdb_get_username(newpwd)));
859 return False;
862 oldrid = newrid;
864 /* open the database */
866 if ( !tdbsam_open( tdbsam_filename ) ) {
867 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
868 return False;
871 if (dbwrap_transaction_start(db_sam) != 0) {
872 DEBUG(0, ("Could not start transaction\n"));
873 return false;
876 /* If we are updating, we may be changing this users RID. Retrieve the old RID
877 so we can check. */
879 if (flag == TDB_MODIFY) {
880 struct samu *account = samu_new(talloc_tos());
881 if (account == NULL) {
882 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
883 goto cancel;
885 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
886 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
887 pdb_get_username(newpwd)));
888 TALLOC_FREE(account);
889 goto cancel;
891 if (!(oldrid = pdb_get_user_rid(account))) {
892 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
893 TALLOC_FREE(account);
894 goto cancel;
896 TALLOC_FREE(account);
899 /* Update the new samu entry. */
900 if (!tdb_update_samacct_only(newpwd, flag)) {
901 goto cancel;
904 /* Now take care of the case where the RID changed. We need
905 * to delete the old RID key and add the new. */
907 if (flag == TDB_MODIFY && newrid != oldrid) {
908 fstring keystr;
910 /* Delete old RID key */
911 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
912 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
913 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
914 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
915 goto cancel;
917 /* Insert new RID key */
918 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
919 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
920 goto cancel;
922 } else {
923 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
924 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
925 if (!tdb_update_ridrec_only(newpwd, flag)) {
926 goto cancel;
930 if (dbwrap_transaction_commit(db_sam) != 0) {
931 DEBUG(0, ("Could not commit transaction\n"));
932 return false;
935 return true;
937 cancel:
938 if (dbwrap_transaction_cancel(db_sam) != 0) {
939 smb_panic("transaction_cancel failed");
941 return false;
944 /***************************************************************************
945 Modifies an existing struct samu
946 ****************************************************************************/
948 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
950 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
951 return NT_STATUS_UNSUCCESSFUL;
953 return NT_STATUS_OK;
956 /***************************************************************************
957 Adds an existing struct samu
958 ****************************************************************************/
960 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
962 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
963 return NT_STATUS_UNSUCCESSFUL;
965 return NT_STATUS_OK;
968 /***************************************************************************
969 Renames a struct samu
970 - check for the posix user/rename user script
971 - Add and lock the new user record
972 - rename the posix user
973 - rewrite the rid->username record
974 - delete the old user
975 - unlock the new user record
976 ***************************************************************************/
977 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
978 struct samu *old_acct,
979 const char *newname)
981 struct samu *new_acct = NULL;
982 char *rename_script = NULL;
983 int rename_ret;
984 fstring oldname_lower;
985 fstring newname_lower;
987 /* can't do anything without an external script */
989 if ( !(new_acct = samu_new( talloc_tos() )) ) {
990 return NT_STATUS_NO_MEMORY;
993 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
994 if (!rename_script) {
995 TALLOC_FREE(new_acct);
996 return NT_STATUS_NO_MEMORY;
998 if (!*rename_script) {
999 TALLOC_FREE(new_acct);
1000 return NT_STATUS_ACCESS_DENIED;
1003 if ( !pdb_copy_sam_account(new_acct, old_acct)
1004 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1006 TALLOC_FREE(new_acct);
1007 return NT_STATUS_NO_MEMORY;
1010 /* open the database */
1011 if ( !tdbsam_open( tdbsam_filename ) ) {
1012 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1013 tdbsam_filename));
1014 TALLOC_FREE(new_acct);
1015 return NT_STATUS_ACCESS_DENIED;
1018 if (dbwrap_transaction_start(db_sam) != 0) {
1019 DEBUG(0, ("Could not start transaction\n"));
1020 TALLOC_FREE(new_acct);
1021 return NT_STATUS_ACCESS_DENIED;
1025 /* add the new account and lock it */
1026 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1027 goto cancel;
1030 /* Rename the posix user. Follow the semantics of _samr_create_user()
1031 so that we lower case the posix name but preserve the case in passdb */
1033 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1034 strlower_m( oldname_lower );
1036 fstrcpy( newname_lower, newname );
1037 strlower_m( newname_lower );
1039 rename_script = talloc_string_sub2(new_acct,
1040 rename_script,
1041 "%unew",
1042 newname_lower,
1043 true,
1044 false,
1045 true);
1046 if (!rename_script) {
1047 goto cancel;
1049 rename_script = talloc_string_sub2(new_acct,
1050 rename_script,
1051 "%uold",
1052 oldname_lower,
1053 true,
1054 false,
1055 true);
1056 if (!rename_script) {
1057 goto cancel;
1059 rename_ret = smbrun(rename_script, NULL);
1061 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1062 rename_script, rename_ret));
1064 if (rename_ret != 0) {
1065 goto cancel;
1068 smb_nscd_flush_user_cache();
1070 /* rewrite the rid->username record */
1072 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1073 goto cancel;
1076 tdb_delete_samacct_only( old_acct );
1078 if (dbwrap_transaction_commit(db_sam) != 0) {
1080 * Ok, we're screwed. We've changed the posix account, but
1081 * could not adapt passdb.tdb. Shall we change the posix
1082 * account back?
1084 DEBUG(0, ("transaction_commit failed\n"));
1085 TALLOC_FREE(new_acct);
1086 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1089 TALLOC_FREE(new_acct );
1090 return NT_STATUS_OK;
1092 cancel:
1093 if (dbwrap_transaction_cancel(db_sam) != 0) {
1094 smb_panic("transaction_cancel failed");
1097 TALLOC_FREE(new_acct);
1099 return NT_STATUS_ACCESS_DENIED;
1102 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1104 return PDB_CAP_STORE_RIDS;
1107 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1109 uint32 rid;
1110 NTSTATUS status;
1112 rid = BASE_RID; /* Default if not set */
1114 if (!tdbsam_open(tdbsam_filename)) {
1115 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1116 tdbsam_filename));
1117 return false;
1120 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1121 &rid, 1);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1124 NEXT_RID_STRING, nt_errstr(status)));
1125 return false;
1128 *prid = rid;
1130 return true;
1133 struct tdbsam_search_state {
1134 struct pdb_methods *methods;
1135 uint32_t acct_flags;
1137 uint32_t *rids;
1138 uint32_t num_rids;
1139 ssize_t array_size;
1140 uint32_t current;
1143 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1145 struct tdbsam_search_state *state = talloc_get_type_abort(
1146 private_data, struct tdbsam_search_state);
1147 size_t prefixlen = strlen(RIDPREFIX);
1148 uint32 rid;
1149 TDB_DATA key;
1151 key = dbwrap_record_get_key(rec);
1153 if ((key.dsize < prefixlen)
1154 || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1155 return 0;
1158 rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1160 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1161 &state->array_size);
1163 return 0;
1166 static void tdbsam_search_end(struct pdb_search *search)
1168 struct tdbsam_search_state *state = talloc_get_type_abort(
1169 search->private_data, struct tdbsam_search_state);
1170 TALLOC_FREE(state);
1173 static bool tdbsam_search_next_entry(struct pdb_search *search,
1174 struct samr_displayentry *entry)
1176 struct tdbsam_search_state *state = talloc_get_type_abort(
1177 search->private_data, struct tdbsam_search_state);
1178 struct samu *user = NULL;
1179 NTSTATUS status;
1180 uint32_t rid;
1182 again:
1183 TALLOC_FREE(user);
1184 user = samu_new(talloc_tos());
1185 if (user == NULL) {
1186 DEBUG(0, ("samu_new failed\n"));
1187 return false;
1190 if (state->current == state->num_rids) {
1191 return false;
1194 rid = state->rids[state->current++];
1196 status = tdbsam_getsampwrid(state->methods, user, rid);
1198 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1200 * Someone has deleted that user since we listed the RIDs
1202 goto again;
1205 if (!NT_STATUS_IS_OK(status)) {
1206 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1207 nt_errstr(status)));
1208 TALLOC_FREE(user);
1209 return false;
1212 if ((state->acct_flags != 0) &&
1213 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1214 goto again;
1217 entry->acct_flags = pdb_get_acct_ctrl(user);
1218 entry->rid = rid;
1219 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1220 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1221 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1223 TALLOC_FREE(user);
1225 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1226 || (entry->description == NULL)) {
1227 DEBUG(0, ("talloc_strdup failed\n"));
1228 return false;
1231 return true;
1234 static bool tdbsam_search_users(struct pdb_methods *methods,
1235 struct pdb_search *search,
1236 uint32 acct_flags)
1238 struct tdbsam_search_state *state;
1240 if (!tdbsam_open(tdbsam_filename)) {
1241 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1242 tdbsam_filename));
1243 return false;
1246 state = talloc_zero(search, struct tdbsam_search_state);
1247 if (state == NULL) {
1248 DEBUG(0, ("talloc failed\n"));
1249 return false;
1251 state->acct_flags = acct_flags;
1252 state->methods = methods;
1254 dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1256 search->private_data = state;
1257 search->next_entry = tdbsam_search_next_entry;
1258 search->search_end = tdbsam_search_end;
1260 return true;
1263 /*********************************************************************
1264 Initialize the tdb sam backend. Setup the dispath table of methods,
1265 open the tdb, etc...
1266 *********************************************************************/
1268 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1270 NTSTATUS nt_status;
1271 char *tdbfile = NULL;
1272 const char *pfile = location;
1274 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1275 return nt_status;
1278 (*pdb_method)->name = "tdbsam";
1280 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1281 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1282 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1283 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1284 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1285 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1286 (*pdb_method)->search_users = tdbsam_search_users;
1288 (*pdb_method)->capabilities = tdbsam_capabilities;
1289 (*pdb_method)->new_rid = tdbsam_new_rid;
1291 /* save the path for later */
1293 if (!location) {
1294 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1295 PASSDB_FILE_NAME) < 0) {
1296 return NT_STATUS_NO_MEMORY;
1298 pfile = tdbfile;
1300 tdbsam_filename = SMB_STRDUP(pfile);
1301 if (!tdbsam_filename) {
1302 return NT_STATUS_NO_MEMORY;
1304 SAFE_FREE(tdbfile);
1306 /* no private data */
1308 (*pdb_method)->private_data = NULL;
1309 (*pdb_method)->free_private_data = NULL;
1311 return NT_STATUS_OK;
1314 NTSTATUS pdb_tdbsam_init(void)
1316 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);