lib/smbconf: remove const warning
[Samba.git] / source3 / passdb / pdb_tdb.c
blobd1ff006f797f9f0dd7ad8d34583b3bacc6b1ec16
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, DBWRAP_FLAG_NONE);
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, DBWRAP_FLAG_NONE);
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;
332 char *db_path;
334 status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
335 if (NT_STATUS_IS_OK(status)) {
336 return true;
339 db_path = state_path("winbindd_idmap.tdb");
340 if (db_path == NULL) {
341 return false;
344 tdb = tdb_open_log(db_path, 0,
345 TDB_DEFAULT, O_RDONLY, 0644);
346 TALLOC_FREE(db_path);
347 if (tdb) {
348 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
349 if (!ok) {
350 rid = BASE_RID;
352 tdb_close(tdb);
353 } else {
354 rid = BASE_RID;
357 status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
358 if (!NT_STATUS_IS_OK(status)) {
359 return false;
362 return true;
365 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
367 struct tdbsam_convert_state state;
368 struct db_context *db = NULL;
369 NTSTATUS status;
371 /* We only need the update backup for local db's. */
372 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
373 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
374 return false;
377 db = *pp_db;
378 state.from = from;
379 state.success = true;
381 if (dbwrap_transaction_start(db) != 0) {
382 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
383 return false;
386 if (!tdbsam_upgrade_next_rid(db)) {
387 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
388 goto cancel;
391 status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
392 if (!NT_STATUS_IS_OK(status)) {
393 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
394 goto cancel;
397 if (!state.success) {
398 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
399 goto cancel;
402 status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
403 TDBSAM_VERSION);
404 if (!NT_STATUS_IS_OK(status)) {
405 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
406 "%s\n", nt_errstr(status)));
407 goto cancel;
410 status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
411 TDBSAM_MINOR_VERSION);
412 if (!NT_STATUS_IS_OK(status)) {
413 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
414 "version: %s\n", nt_errstr(status)));
415 goto cancel;
418 if (dbwrap_transaction_commit(db) != 0) {
419 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
420 return false;
423 return true;
425 cancel:
426 if (dbwrap_transaction_cancel(db) != 0) {
427 smb_panic("tdbsam_convert: transaction_cancel failed");
430 return false;
433 /*********************************************************************
434 Open the tdbsam file based on the absolute path specified.
435 Uses a reference count to allow multiple open calls.
436 *********************************************************************/
438 static bool tdbsam_open( const char *name )
440 int32 version;
441 int32 minor_version;
442 NTSTATUS status;
444 /* check if we are already open */
446 if ( db_sam ) {
447 return true;
450 /* Try to open tdb passwd. Create a new one if necessary */
452 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
453 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
454 if (db_sam == NULL) {
455 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
456 "[%s]\n", name));
457 return false;
460 /* Check the version */
461 status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
462 &version);
463 if (!NT_STATUS_IS_OK(status)) {
464 version = 0; /* Version not found, assume version 0 */
467 /* Get the minor version */
468 status = dbwrap_fetch_int32_bystring(
469 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
470 if (!NT_STATUS_IS_OK(status)) {
471 minor_version = 0; /* Minor version not found, assume 0 */
474 /* Compare the version */
475 if (version > TDBSAM_VERSION) {
476 /* Version more recent than the latest known */
477 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
478 TALLOC_FREE(db_sam);
479 return false;
482 if ( version < TDBSAM_VERSION ||
483 (version == TDBSAM_VERSION &&
484 minor_version < TDBSAM_MINOR_VERSION) ) {
486 * Ok - we think we're going to have to convert.
487 * Due to the backup process we now must do to
488 * upgrade we have to get a mutex and re-check
489 * the version. Someone else may have upgraded
490 * whilst we were checking.
493 struct named_mutex *mtx = grab_named_mutex(NULL,
494 "tdbsam_upgrade_mutex",
495 600);
497 if (!mtx) {
498 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
499 TALLOC_FREE(db_sam);
500 return false;
503 /* Re-check the version */
504 status = dbwrap_fetch_int32_bystring(
505 db_sam, TDBSAM_VERSION_STRING, &version);
506 if (!NT_STATUS_IS_OK(status)) {
507 version = 0; /* Version not found, assume version 0 */
510 /* Re-check the minor version */
511 status = dbwrap_fetch_int32_bystring(
512 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
513 if (!NT_STATUS_IS_OK(status)) {
514 minor_version = 0; /* Minor version not found, assume 0 */
517 /* Compare the version */
518 if (version > TDBSAM_VERSION) {
519 /* Version more recent than the latest known */
520 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
521 TALLOC_FREE(db_sam);
522 TALLOC_FREE(mtx);
523 return false;
526 if ( version < TDBSAM_VERSION ||
527 (version == TDBSAM_VERSION &&
528 minor_version < TDBSAM_MINOR_VERSION) ) {
530 * Note that minor versions we read that are greater
531 * than the current minor version we have hard coded
532 * are assumed to be compatible if they have the same
533 * major version. That allows previous versions of the
534 * passdb code that don't know about minor versions to
535 * still use this database. JRA.
538 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
539 "version %d.%d.\n",
540 version,
541 minor_version,
542 TDBSAM_VERSION,
543 TDBSAM_MINOR_VERSION));
545 if ( !tdbsam_convert(&db_sam, name, version) ) {
546 DEBUG(0, ("tdbsam_open: Error when trying to convert "
547 "tdbsam [%s]\n",name));
548 TALLOC_FREE(db_sam);
549 TALLOC_FREE(mtx);
550 return false;
553 DEBUG(3, ("TDBSAM converted successfully.\n"));
555 TALLOC_FREE(mtx);
558 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
560 return true;
563 /******************************************************************
564 Lookup a name in the SAM TDB
565 ******************************************************************/
567 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
568 struct samu *user, const char *sname)
570 TDB_DATA data;
571 fstring keystr;
572 fstring name;
573 NTSTATUS status;
575 if ( !user ) {
576 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
577 return NT_STATUS_NO_MEMORY;
580 /* Data is stored in all lower-case */
581 fstrcpy(name, sname);
582 if (!strlower_m(name)) {
583 return NT_STATUS_INVALID_PARAMETER;
586 /* set search key */
587 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
589 /* open the database */
591 if ( !tdbsam_open( tdbsam_filename ) ) {
592 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
593 return NT_STATUS_ACCESS_DENIED;
596 /* get the record */
598 status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
599 if (!NT_STATUS_IS_OK(status)) {
600 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
601 DEBUGADD(5, (" Key: %s\n", keystr));
602 return NT_STATUS_NO_SUCH_USER;
605 if (data.dsize == 0) {
606 DEBUG(5, ("%s: Got 0-sized record for key %s\n", __func__,
607 keystr));
608 return NT_STATUS_NO_SUCH_USER;
611 /* unpack the buffer */
613 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
614 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
615 TALLOC_FREE(data.dptr);
616 return NT_STATUS_NO_MEMORY;
619 /* success */
621 TALLOC_FREE(data.dptr);
623 return NT_STATUS_OK;
626 /***************************************************************************
627 Search by rid
628 **************************************************************************/
630 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
631 struct samu *user, uint32 rid)
633 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
634 TDB_DATA data;
635 fstring keystr;
636 fstring name;
638 if ( !user ) {
639 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
640 return nt_status;
643 /* set search key */
645 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
647 /* open the database */
649 if ( !tdbsam_open( tdbsam_filename ) ) {
650 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
651 return NT_STATUS_ACCESS_DENIED;
654 /* get the record */
656 nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
657 if (!NT_STATUS_IS_OK(nt_status)) {
658 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
659 return nt_status;
662 fstrcpy(name, (const char *)data.dptr);
663 TALLOC_FREE(data.dptr);
665 return tdbsam_getsampwnam (my_methods, user, name);
668 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
669 struct samu * user, const struct dom_sid *sid)
671 uint32 rid;
673 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
674 return NT_STATUS_UNSUCCESSFUL;
676 return tdbsam_getsampwrid(my_methods, user, rid);
679 static bool tdb_delete_samacct_only( struct samu *sam_pass )
681 fstring keystr;
682 fstring name;
683 NTSTATUS status;
685 fstrcpy(name, pdb_get_username(sam_pass));
686 if (!strlower_m(name)) {
687 return false;
690 /* set the search key */
692 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
694 /* it's outaa here! 8^) */
695 if ( !tdbsam_open( tdbsam_filename ) ) {
696 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
697 tdbsam_filename));
698 return false;
701 status = dbwrap_delete_bystring(db_sam, keystr);
702 if (!NT_STATUS_IS_OK(status)) {
703 DEBUG(5, ("Error deleting entry from tdb passwd "
704 "database: %s!\n", nt_errstr(status)));
705 return false;
708 return true;
711 /***************************************************************************
712 Delete a struct samu records for the username and RID key
713 ****************************************************************************/
715 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
716 struct samu *sam_pass)
718 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
719 fstring keystr;
720 uint32 rid;
721 fstring name;
723 /* open the database */
725 if ( !tdbsam_open( tdbsam_filename ) ) {
726 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
727 tdbsam_filename));
728 return NT_STATUS_ACCESS_DENIED;
731 fstrcpy(name, pdb_get_username(sam_pass));
732 if (!strlower_m(name)) {
733 return NT_STATUS_INVALID_PARAMETER;
736 /* set the search key */
738 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
740 rid = pdb_get_user_rid(sam_pass);
742 /* it's outaa here! 8^) */
744 if (dbwrap_transaction_start(db_sam) != 0) {
745 DEBUG(0, ("Could not start transaction\n"));
746 return NT_STATUS_UNSUCCESSFUL;
749 nt_status = dbwrap_delete_bystring(db_sam, keystr);
750 if (!NT_STATUS_IS_OK(nt_status)) {
751 DEBUG(5, ("Error deleting entry from tdb passwd "
752 "database: %s!\n", nt_errstr(nt_status)));
753 goto cancel;
756 /* set the search key */
758 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
760 /* it's outaa here! 8^) */
762 nt_status = dbwrap_delete_bystring(db_sam, keystr);
763 if (!NT_STATUS_IS_OK(nt_status)) {
764 DEBUG(5, ("Error deleting entry from tdb rid "
765 "database: %s!\n", nt_errstr(nt_status)));
766 goto cancel;
769 if (dbwrap_transaction_commit(db_sam) != 0) {
770 DEBUG(0, ("Could not commit transaction\n"));
771 return NT_STATUS_INTERNAL_DB_CORRUPTION;
774 return NT_STATUS_OK;
776 cancel:
777 if (dbwrap_transaction_cancel(db_sam) != 0) {
778 smb_panic("transaction_cancel failed");
781 return nt_status;
785 /***************************************************************************
786 Update the TDB SAM account record only
787 Assumes that the tdbsam is already open
788 ****************************************************************************/
789 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
791 TDB_DATA data;
792 uint8 *buf = NULL;
793 fstring keystr;
794 fstring name;
795 bool ret = false;
796 NTSTATUS status;
798 /* copy the struct samu struct into a BYTE buffer for storage */
800 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
801 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
802 goto done;
804 data.dptr = buf;
806 fstrcpy(name, pdb_get_username(newpwd));
807 if (!strlower_m(name)) {
808 goto done;
811 DEBUG(5, ("Storing %saccount %s with RID %d\n",
812 flag == TDB_INSERT ? "(new) " : "", name,
813 pdb_get_user_rid(newpwd)));
815 /* setup the USER index key */
816 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
818 /* add the account */
820 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
821 if (!NT_STATUS_IS_OK(status)) {
822 DEBUG(0, ("Unable to modify passwd TDB: %s!",
823 nt_errstr(status)));
824 goto done;
827 ret = true;
829 done:
830 /* cleanup */
831 SAFE_FREE(buf);
832 return ret;
835 /***************************************************************************
836 Update the TDB SAM RID record only
837 Assumes that the tdbsam is already open
838 ****************************************************************************/
839 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
841 TDB_DATA data;
842 fstring keystr;
843 fstring name;
844 NTSTATUS status;
846 fstrcpy(name, pdb_get_username(newpwd));
847 if (!strlower_m(name)) {
848 return false;
851 /* setup RID data */
852 data = string_term_tdb_data(name);
854 /* setup the RID index key */
855 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
856 pdb_get_user_rid(newpwd));
858 /* add the reference */
859 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
860 if (!NT_STATUS_IS_OK(status)) {
861 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
862 nt_errstr(status)));
863 return false;
866 return true;
870 /***************************************************************************
871 Update the TDB SAM
872 ****************************************************************************/
874 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
875 int flag)
877 uint32_t oldrid;
878 uint32_t newrid;
880 if (!(newrid = pdb_get_user_rid(newpwd))) {
881 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
882 pdb_get_username(newpwd)));
883 return False;
886 oldrid = newrid;
888 /* open the database */
890 if ( !tdbsam_open( tdbsam_filename ) ) {
891 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
892 return False;
895 if (dbwrap_transaction_start(db_sam) != 0) {
896 DEBUG(0, ("Could not start transaction\n"));
897 return false;
900 /* If we are updating, we may be changing this users RID. Retrieve the old RID
901 so we can check. */
903 if (flag == TDB_MODIFY) {
904 struct samu *account = samu_new(talloc_tos());
905 if (account == NULL) {
906 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
907 goto cancel;
909 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
910 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
911 pdb_get_username(newpwd)));
912 TALLOC_FREE(account);
913 goto cancel;
915 if (!(oldrid = pdb_get_user_rid(account))) {
916 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
917 TALLOC_FREE(account);
918 goto cancel;
920 TALLOC_FREE(account);
923 /* Update the new samu entry. */
924 if (!tdb_update_samacct_only(newpwd, flag)) {
925 goto cancel;
928 /* Now take care of the case where the RID changed. We need
929 * to delete the old RID key and add the new. */
931 if (flag == TDB_MODIFY && newrid != oldrid) {
932 fstring keystr;
934 /* Delete old RID key */
935 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
936 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
937 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
938 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
939 goto cancel;
941 /* Insert new RID key */
942 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
943 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
944 goto cancel;
946 } else {
947 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
948 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
949 if (!tdb_update_ridrec_only(newpwd, flag)) {
950 goto cancel;
954 if (dbwrap_transaction_commit(db_sam) != 0) {
955 DEBUG(0, ("Could not commit transaction\n"));
956 return false;
959 return true;
961 cancel:
962 if (dbwrap_transaction_cancel(db_sam) != 0) {
963 smb_panic("transaction_cancel failed");
965 return false;
968 /***************************************************************************
969 Modifies an existing struct samu
970 ****************************************************************************/
972 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
974 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
975 return NT_STATUS_UNSUCCESSFUL;
977 return NT_STATUS_OK;
980 /***************************************************************************
981 Adds an existing struct samu
982 ****************************************************************************/
984 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
986 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
987 return NT_STATUS_UNSUCCESSFUL;
989 return NT_STATUS_OK;
992 /***************************************************************************
993 Renames a struct samu
994 - check for the posix user/rename user script
995 - Add and lock the new user record
996 - rename the posix user
997 - rewrite the rid->username record
998 - delete the old user
999 - unlock the new user record
1000 ***************************************************************************/
1001 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1002 struct samu *old_acct,
1003 const char *newname)
1005 struct samu *new_acct = NULL;
1006 char *rename_script = NULL;
1007 int rename_ret;
1008 fstring oldname_lower;
1009 fstring newname_lower;
1011 /* can't do anything without an external script */
1013 if ( !(new_acct = samu_new( talloc_tos() )) ) {
1014 return NT_STATUS_NO_MEMORY;
1017 rename_script = lp_rename_user_script(new_acct);
1018 if (!rename_script) {
1019 TALLOC_FREE(new_acct);
1020 return NT_STATUS_NO_MEMORY;
1022 if (!*rename_script) {
1023 TALLOC_FREE(new_acct);
1024 return NT_STATUS_ACCESS_DENIED;
1027 if ( !pdb_copy_sam_account(new_acct, old_acct)
1028 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1030 TALLOC_FREE(new_acct);
1031 return NT_STATUS_NO_MEMORY;
1034 /* open the database */
1035 if ( !tdbsam_open( tdbsam_filename ) ) {
1036 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1037 tdbsam_filename));
1038 TALLOC_FREE(new_acct);
1039 return NT_STATUS_ACCESS_DENIED;
1042 if (dbwrap_transaction_start(db_sam) != 0) {
1043 DEBUG(0, ("Could not start transaction\n"));
1044 TALLOC_FREE(new_acct);
1045 return NT_STATUS_ACCESS_DENIED;
1049 /* add the new account and lock it */
1050 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1051 goto cancel;
1054 /* Rename the posix user. Follow the semantics of _samr_create_user()
1055 so that we lower case the posix name but preserve the case in passdb */
1057 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1058 if (!strlower_m( oldname_lower )) {
1059 goto cancel;
1062 fstrcpy( newname_lower, newname );
1063 if (!strlower_m( newname_lower )) {
1064 goto cancel;
1067 rename_script = talloc_string_sub2(new_acct,
1068 rename_script,
1069 "%unew",
1070 newname_lower,
1071 true,
1072 false,
1073 true);
1074 if (!rename_script) {
1075 goto cancel;
1077 rename_script = talloc_string_sub2(new_acct,
1078 rename_script,
1079 "%uold",
1080 oldname_lower,
1081 true,
1082 false,
1083 true);
1084 if (!rename_script) {
1085 goto cancel;
1087 rename_ret = smbrun(rename_script, NULL);
1089 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1090 rename_script, rename_ret));
1092 if (rename_ret != 0) {
1093 goto cancel;
1096 smb_nscd_flush_user_cache();
1098 /* rewrite the rid->username record */
1100 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1101 goto cancel;
1104 tdb_delete_samacct_only( old_acct );
1106 if (dbwrap_transaction_commit(db_sam) != 0) {
1108 * Ok, we're screwed. We've changed the posix account, but
1109 * could not adapt passdb.tdb. Shall we change the posix
1110 * account back?
1112 DEBUG(0, ("transaction_commit failed\n"));
1113 TALLOC_FREE(new_acct);
1114 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1117 TALLOC_FREE(new_acct );
1118 return NT_STATUS_OK;
1120 cancel:
1121 if (dbwrap_transaction_cancel(db_sam) != 0) {
1122 smb_panic("transaction_cancel failed");
1125 TALLOC_FREE(new_acct);
1127 return NT_STATUS_ACCESS_DENIED;
1130 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1132 return PDB_CAP_STORE_RIDS;
1135 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1137 uint32 rid;
1138 NTSTATUS status;
1140 rid = BASE_RID; /* Default if not set */
1142 if (!tdbsam_open(tdbsam_filename)) {
1143 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1144 tdbsam_filename));
1145 return false;
1148 status = dbwrap_trans_change_uint32_atomic_bystring(
1149 db_sam, NEXT_RID_STRING, &rid, 1);
1150 if (!NT_STATUS_IS_OK(status)) {
1151 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1152 NEXT_RID_STRING, nt_errstr(status)));
1153 return false;
1156 *prid = rid;
1158 return true;
1161 struct tdbsam_search_state {
1162 struct pdb_methods *methods;
1163 uint32_t acct_flags;
1165 uint32_t *rids;
1166 uint32_t num_rids;
1167 ssize_t array_size;
1168 uint32_t current;
1171 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1173 struct tdbsam_search_state *state = talloc_get_type_abort(
1174 private_data, struct tdbsam_search_state);
1175 size_t prefixlen = strlen(RIDPREFIX);
1176 uint32 rid;
1177 TDB_DATA key;
1179 key = dbwrap_record_get_key(rec);
1181 if ((key.dsize < prefixlen)
1182 || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1183 return 0;
1186 rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1188 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1189 &state->array_size);
1191 return 0;
1194 static void tdbsam_search_end(struct pdb_search *search)
1196 struct tdbsam_search_state *state = talloc_get_type_abort(
1197 search->private_data, struct tdbsam_search_state);
1198 TALLOC_FREE(state);
1201 static bool tdbsam_search_next_entry(struct pdb_search *search,
1202 struct samr_displayentry *entry)
1204 struct tdbsam_search_state *state = talloc_get_type_abort(
1205 search->private_data, struct tdbsam_search_state);
1206 struct samu *user = NULL;
1207 NTSTATUS status;
1208 uint32_t rid;
1210 again:
1211 TALLOC_FREE(user);
1212 user = samu_new(talloc_tos());
1213 if (user == NULL) {
1214 DEBUG(0, ("samu_new failed\n"));
1215 return false;
1218 if (state->current == state->num_rids) {
1219 TALLOC_FREE(user);
1220 return false;
1223 rid = state->rids[state->current++];
1225 status = tdbsam_getsampwrid(state->methods, user, rid);
1227 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1229 * Someone has deleted that user since we listed the RIDs
1231 goto again;
1234 if (!NT_STATUS_IS_OK(status)) {
1235 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1236 nt_errstr(status)));
1237 TALLOC_FREE(user);
1238 return false;
1241 if ((state->acct_flags != 0) &&
1242 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1243 goto again;
1246 entry->acct_flags = pdb_get_acct_ctrl(user);
1247 entry->rid = rid;
1248 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1249 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1250 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1252 TALLOC_FREE(user);
1254 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1255 || (entry->description == NULL)) {
1256 DEBUG(0, ("talloc_strdup failed\n"));
1257 return false;
1260 return true;
1263 static bool tdbsam_search_users(struct pdb_methods *methods,
1264 struct pdb_search *search,
1265 uint32 acct_flags)
1267 struct tdbsam_search_state *state;
1269 if (!tdbsam_open(tdbsam_filename)) {
1270 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1271 tdbsam_filename));
1272 return false;
1275 state = talloc_zero(search, struct tdbsam_search_state);
1276 if (state == NULL) {
1277 DEBUG(0, ("talloc failed\n"));
1278 return false;
1280 state->acct_flags = acct_flags;
1281 state->methods = methods;
1283 dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1285 search->private_data = state;
1286 search->next_entry = tdbsam_search_next_entry;
1287 search->search_end = tdbsam_search_end;
1289 return true;
1292 static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
1294 return map_builtin;
1297 /*********************************************************************
1298 Initialize the tdb sam backend. Setup the dispath table of methods,
1299 open the tdb, etc...
1300 *********************************************************************/
1302 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1304 NTSTATUS nt_status;
1305 char *tdbfile = NULL;
1306 const char *pfile = location;
1308 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1309 return nt_status;
1312 (*pdb_method)->name = "tdbsam";
1314 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1315 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1316 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1317 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1318 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1319 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1320 (*pdb_method)->search_users = tdbsam_search_users;
1322 (*pdb_method)->capabilities = tdbsam_capabilities;
1323 (*pdb_method)->new_rid = tdbsam_new_rid;
1325 (*pdb_method)->is_responsible_for_builtin =
1326 tdbsam_is_responsible_for_builtin;
1327 map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
1329 /* save the path for later */
1331 if (!location) {
1332 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1333 PASSDB_FILE_NAME) < 0) {
1334 return NT_STATUS_NO_MEMORY;
1336 pfile = tdbfile;
1338 tdbsam_filename = SMB_STRDUP(pfile);
1339 if (!tdbsam_filename) {
1340 return NT_STATUS_NO_MEMORY;
1342 SAFE_FREE(tdbfile);
1344 /* no private data */
1346 (*pdb_method)->private_data = NULL;
1347 (*pdb_method)->free_private_data = NULL;
1349 return NT_STATUS_OK;
1352 NTSTATUS pdb_tdbsam_init(void)
1354 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);