samba-tool tests: rename 'group create' to 'group add'
[Samba.git] / source3 / passdb / pdb_tdb.c
blob161030fed8b9aba4096a75f9191b6e9998b25a94
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"
33 #include "lib/util/smb_strtox.h"
34 #include "lib/util/string_wrappers.h"
36 #if 0 /* when made a module use this */
38 static int tdbsam_debug_level = DBGC_ALL;
39 #undef DBGC_CLASS
40 #define DBGC_CLASS tdbsam_debug_level
42 #else
44 #undef DBGC_CLASS
45 #define DBGC_CLASS DBGC_PASSDB
47 #endif
49 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
50 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
51 #define TDBSAM_VERSION_STRING "INFO/version"
52 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
53 #define PASSDB_FILE_NAME "passdb.tdb"
54 #define USERPREFIX "USER_"
55 #define USERPREFIX_LEN 5
56 #define RIDPREFIX "RID_"
57 #define PRIVPREFIX "PRIV_"
58 #define NEXT_RID_STRING "NEXT_RID"
60 /* GLOBAL TDB SAM CONTEXT */
62 static struct db_context *db_sam;
63 static char *tdbsam_filename;
64 static bool map_builtin;
66 struct tdbsam_convert_state {
67 int32_t from;
68 bool success;
71 static int tdbsam_convert_one(struct db_record *rec, void *priv)
73 struct tdbsam_convert_state *state =
74 (struct tdbsam_convert_state *)priv;
75 struct samu *user;
76 TDB_DATA data;
77 NTSTATUS status;
78 bool ret;
79 TDB_DATA key;
80 TDB_DATA value;
82 key = dbwrap_record_get_key(rec);
84 if (key.dsize < USERPREFIX_LEN) {
85 return 0;
87 if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
88 return 0;
91 user = samu_new(talloc_tos());
92 if (user == NULL) {
93 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
94 state->success = false;
95 return -1;
98 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
99 "(version:%d)\n", (char *)key.dptr, state->from));
101 value = dbwrap_record_get_value(rec);
103 switch (state->from) {
104 case 0:
105 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
106 (uint8_t *)value.dptr,
107 value.dsize);
108 break;
109 case 1:
110 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
111 (uint8_t *)value.dptr,
112 value.dsize);
113 break;
114 case 2:
115 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
116 (uint8_t *)value.dptr,
117 value.dsize);
118 break;
119 case 3:
120 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
121 (uint8_t *)value.dptr,
122 value.dsize);
123 break;
124 case 4:
125 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
126 (uint8_t *)value.dptr,
127 value.dsize);
128 break;
129 default:
130 /* unknown tdbsam version */
131 ret = False;
133 if (!ret) {
134 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
135 "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
136 state->from));
137 TALLOC_FREE(user);
138 state->success = false;
139 return -1;
142 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
143 TALLOC_FREE(user);
145 if (data.dsize == -1) {
146 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
147 "the new format\n"));
148 state->success = false;
149 return -1;
152 status = dbwrap_record_store(rec, data, TDB_MODIFY);
153 if (!NT_STATUS_IS_OK(status)) {
154 DEBUG(0, ("Could not store the new record: %s\n",
155 nt_errstr(status)));
156 state->success = false;
157 return -1;
160 return 0;
163 /**********************************************************************
164 Struct and function to backup an old record.
165 *********************************************************************/
167 struct tdbsam_backup_state {
168 struct db_context *new_db;
169 bool success;
172 static int backup_copy_fn(struct db_record *orig_rec, void *state)
174 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
175 struct db_record *new_rec;
176 NTSTATUS status;
177 TDB_DATA key;
178 TDB_DATA value;
180 key = dbwrap_record_get_key(orig_rec);
182 new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
183 if (new_rec == NULL) {
184 bs->success = false;
185 return 1;
188 value = dbwrap_record_get_value(orig_rec);
190 status = dbwrap_record_store(new_rec, value, TDB_INSERT);
192 TALLOC_FREE(new_rec);
194 if (!NT_STATUS_IS_OK(status)) {
195 bs->success = false;
196 return 1;
198 return 0;
201 /**********************************************************************
202 Make a backup of an old passdb and replace the new one with it. We
203 have to do this as between 3.0.x and 3.2.x the hash function changed
204 by mistake (used unsigned char * instead of char *). This means the
205 previous simple update code will fail due to not being able to find
206 existing records to replace in the tdbsam_convert_one() function. JRA.
207 *********************************************************************/
209 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
211 TALLOC_CTX *frame = talloc_stackframe();
212 const char *tmp_fname = NULL;
213 struct db_context *tmp_db = NULL;
214 struct db_context *orig_db = *pp_db;
215 struct tdbsam_backup_state bs;
216 NTSTATUS status;
218 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
219 if (!tmp_fname) {
220 TALLOC_FREE(frame);
221 return false;
224 unlink(tmp_fname);
226 /* Remember to open this on the NULL context. We need
227 * it to stay around after we return from here. */
229 tmp_db = db_open(NULL, tmp_fname, 0,
230 TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
231 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
232 if (tmp_db == NULL) {
233 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
234 "[%s]\n", tmp_fname));
235 TALLOC_FREE(frame);
236 return false;
239 if (dbwrap_transaction_start(orig_db) != 0) {
240 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
241 unlink(tmp_fname);
242 TALLOC_FREE(tmp_db);
243 TALLOC_FREE(frame);
244 return false;
246 if (dbwrap_transaction_start(tmp_db) != 0) {
247 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
248 dbwrap_transaction_cancel(orig_db);
249 unlink(tmp_fname);
250 TALLOC_FREE(tmp_db);
251 TALLOC_FREE(frame);
252 return false;
255 bs.new_db = tmp_db;
256 bs.success = true;
258 status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
259 if (!NT_STATUS_IS_OK(status)) {
260 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
261 goto cancel;
264 if (!bs.success) {
265 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
266 goto cancel;
269 if (dbwrap_transaction_commit(orig_db) != 0) {
270 smb_panic("tdbsam_convert_backup: orig commit failed\n");
272 if (dbwrap_transaction_commit(tmp_db) != 0) {
273 smb_panic("tdbsam_convert_backup: orig commit failed\n");
276 /* be sure to close the DBs _before_ renaming the file */
278 TALLOC_FREE(orig_db);
279 TALLOC_FREE(tmp_db);
281 /* This is safe from other users as we know we're
282 * under a mutex here. */
284 if (rename(tmp_fname, dbname) == -1) {
285 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
286 tmp_fname,
287 dbname,
288 strerror(errno)));
289 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
292 TALLOC_FREE(frame);
294 /* re-open the converted TDB */
296 orig_db = db_open(NULL, dbname, 0,
297 TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
298 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
299 if (orig_db == NULL) {
300 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
301 "converted passdb TDB [%s]\n", dbname));
302 return false;
305 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
306 dbname ));
308 /* Replace the global db pointer. */
309 *pp_db = orig_db;
310 return true;
312 cancel:
314 if (dbwrap_transaction_cancel(orig_db) != 0) {
315 smb_panic("tdbsam_convert: transaction_cancel failed");
318 if (dbwrap_transaction_cancel(tmp_db) != 0) {
319 smb_panic("tdbsam_convert: transaction_cancel failed");
322 unlink(tmp_fname);
323 TALLOC_FREE(tmp_db);
324 TALLOC_FREE(frame);
325 return false;
328 static bool tdbsam_upgrade_next_rid(struct db_context *db)
330 TDB_CONTEXT *tdb;
331 uint32_t rid;
332 bool ok = false;
333 NTSTATUS status;
334 char *db_path;
336 status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
337 if (NT_STATUS_IS_OK(status)) {
338 return true;
341 db_path = state_path(talloc_tos(), "winbindd_idmap.tdb");
342 if (db_path == NULL) {
343 return false;
346 tdb = tdb_open_log(db_path, 0,
347 TDB_DEFAULT, O_RDONLY, 0644);
348 TALLOC_FREE(db_path);
349 if (tdb) {
350 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
351 if (!ok) {
352 rid = BASE_RID;
354 tdb_close(tdb);
355 } else {
356 rid = BASE_RID;
359 status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
360 if (!NT_STATUS_IS_OK(status)) {
361 return false;
364 return true;
367 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32_t from)
369 struct tdbsam_convert_state state;
370 struct db_context *db = NULL;
371 NTSTATUS status;
373 /* We only need the update backup for local db's. */
374 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
375 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
376 return false;
379 db = *pp_db;
380 state.from = from;
381 state.success = true;
383 if (dbwrap_transaction_start(db) != 0) {
384 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
385 return false;
388 if (!tdbsam_upgrade_next_rid(db)) {
389 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
390 goto cancel;
393 status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
394 if (!NT_STATUS_IS_OK(status)) {
395 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
396 goto cancel;
399 if (!state.success) {
400 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
401 goto cancel;
404 status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
405 TDBSAM_VERSION);
406 if (!NT_STATUS_IS_OK(status)) {
407 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
408 "%s\n", nt_errstr(status)));
409 goto cancel;
412 status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
413 TDBSAM_MINOR_VERSION);
414 if (!NT_STATUS_IS_OK(status)) {
415 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
416 "version: %s\n", nt_errstr(status)));
417 goto cancel;
420 if (dbwrap_transaction_commit(db) != 0) {
421 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
422 return false;
425 return true;
427 cancel:
428 if (dbwrap_transaction_cancel(db) != 0) {
429 smb_panic("tdbsam_convert: transaction_cancel failed");
432 return false;
435 /*********************************************************************
436 Open the tdbsam file based on the absolute path specified.
437 Uses a reference count to allow multiple open calls.
438 *********************************************************************/
440 static bool tdbsam_open( const char *name )
442 int32_t version;
443 int32_t minor_version;
444 NTSTATUS status;
446 /* check if we are already open */
448 if ( db_sam ) {
449 return true;
452 /* Try to open tdb passwd. Create a new one if necessary */
454 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
455 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
456 if (db_sam == NULL) {
457 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
458 "[%s]\n", name));
459 return false;
462 /* Check the version */
463 status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
464 &version);
465 if (!NT_STATUS_IS_OK(status)) {
466 version = 0; /* Version not found, assume version 0 */
469 /* Get the minor version */
470 status = dbwrap_fetch_int32_bystring(
471 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
472 if (!NT_STATUS_IS_OK(status)) {
473 minor_version = 0; /* Minor version not found, assume 0 */
476 /* Compare the version */
477 if (version > TDBSAM_VERSION) {
478 /* Version more recent than the latest known */
479 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
480 TALLOC_FREE(db_sam);
481 return false;
484 if ( version < TDBSAM_VERSION ||
485 (version == TDBSAM_VERSION &&
486 minor_version < TDBSAM_MINOR_VERSION) ) {
488 * Ok - we think we're going to have to convert.
489 * Due to the backup process we now must do to
490 * upgrade we have to get a mutex and re-check
491 * the version. Someone else may have upgraded
492 * whilst we were checking.
495 struct named_mutex *mtx = grab_named_mutex(NULL,
496 "tdbsam_upgrade_mutex",
497 600);
499 if (!mtx) {
500 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
501 TALLOC_FREE(db_sam);
502 return false;
505 /* Re-check the version */
506 status = dbwrap_fetch_int32_bystring(
507 db_sam, TDBSAM_VERSION_STRING, &version);
508 if (!NT_STATUS_IS_OK(status)) {
509 version = 0; /* Version not found, assume version 0 */
512 /* Re-check the minor version */
513 status = dbwrap_fetch_int32_bystring(
514 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
515 if (!NT_STATUS_IS_OK(status)) {
516 minor_version = 0; /* Minor version not found, assume 0 */
519 /* Compare the version */
520 if (version > TDBSAM_VERSION) {
521 /* Version more recent than the latest known */
522 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
523 TALLOC_FREE(db_sam);
524 TALLOC_FREE(mtx);
525 return false;
528 if ( version < TDBSAM_VERSION ||
529 (version == TDBSAM_VERSION &&
530 minor_version < TDBSAM_MINOR_VERSION) ) {
532 * Note that minor versions we read that are greater
533 * than the current minor version we have hard coded
534 * are assumed to be compatible if they have the same
535 * major version. That allows previous versions of the
536 * passdb code that don't know about minor versions to
537 * still use this database. JRA.
540 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
541 "version %d.%d.\n",
542 version,
543 minor_version,
544 TDBSAM_VERSION,
545 TDBSAM_MINOR_VERSION));
547 if ( !tdbsam_convert(&db_sam, name, version) ) {
548 DEBUG(0, ("tdbsam_open: Error when trying to convert "
549 "tdbsam [%s]\n",name));
550 TALLOC_FREE(db_sam);
551 TALLOC_FREE(mtx);
552 return false;
555 DEBUG(3, ("TDBSAM converted successfully.\n"));
557 TALLOC_FREE(mtx);
560 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
562 return true;
565 /******************************************************************
566 Lookup a name in the SAM TDB
567 ******************************************************************/
569 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
570 struct samu *user, const char *sname)
572 TDB_DATA data;
573 fstring keystr;
574 fstring name;
575 NTSTATUS status;
577 if ( !user ) {
578 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
579 return NT_STATUS_NO_MEMORY;
582 /* Data is stored in all lower-case */
583 fstrcpy(name, sname);
584 if (!strlower_m(name)) {
585 return NT_STATUS_INVALID_PARAMETER;
588 /* set search key */
589 fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
591 /* open the database */
593 if ( !tdbsam_open( tdbsam_filename ) ) {
594 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
595 return NT_STATUS_ACCESS_DENIED;
598 /* get the record */
600 status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
601 if (!NT_STATUS_IS_OK(status)) {
602 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
603 DEBUGADD(5, (" Key: %s\n", keystr));
604 return NT_STATUS_NO_SUCH_USER;
607 if (data.dsize == 0) {
608 DEBUG(5, ("%s: Got 0-sized record for key %s\n", __func__,
609 keystr));
610 return NT_STATUS_NO_SUCH_USER;
613 /* unpack the buffer */
615 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
616 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
617 TALLOC_FREE(data.dptr);
618 return NT_STATUS_NO_MEMORY;
621 /* success */
623 TALLOC_FREE(data.dptr);
625 return NT_STATUS_OK;
628 /***************************************************************************
629 Search by rid
630 **************************************************************************/
632 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
633 struct samu *user, uint32_t rid)
635 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
636 TDB_DATA data;
637 fstring keystr;
638 fstring name;
640 if ( !user ) {
641 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
642 return nt_status;
645 /* set search key */
647 fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
649 /* open the database */
651 if ( !tdbsam_open( tdbsam_filename ) ) {
652 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
653 return NT_STATUS_ACCESS_DENIED;
656 /* get the record */
658 nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
659 if (!NT_STATUS_IS_OK(nt_status)) {
660 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
661 return nt_status;
664 fstrcpy(name, (const char *)data.dptr);
665 TALLOC_FREE(data.dptr);
667 return tdbsam_getsampwnam (my_methods, user, name);
670 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
671 struct samu * user, const struct dom_sid *sid)
673 uint32_t rid;
675 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
676 return NT_STATUS_UNSUCCESSFUL;
678 return tdbsam_getsampwrid(my_methods, user, rid);
681 static bool tdb_delete_samacct_only( struct samu *sam_pass )
683 fstring keystr;
684 fstring name;
685 NTSTATUS status;
687 fstrcpy(name, pdb_get_username(sam_pass));
688 if (!strlower_m(name)) {
689 return false;
692 /* set the search key */
694 fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
696 /* it's outaa here! 8^) */
697 if ( !tdbsam_open( tdbsam_filename ) ) {
698 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
699 tdbsam_filename));
700 return false;
703 status = dbwrap_delete_bystring(db_sam, keystr);
704 if (!NT_STATUS_IS_OK(status)) {
705 DEBUG(5, ("Error deleting entry from tdb passwd "
706 "database: %s!\n", nt_errstr(status)));
707 return false;
710 return true;
713 /***************************************************************************
714 Delete a struct samu records for the username and RID key
715 ****************************************************************************/
717 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
718 struct samu *sam_pass)
720 NTSTATUS nt_status;
721 fstring keystr;
722 uint32_t rid;
723 fstring name;
725 /* open the database */
727 if ( !tdbsam_open( tdbsam_filename ) ) {
728 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
729 tdbsam_filename));
730 return NT_STATUS_ACCESS_DENIED;
733 fstrcpy(name, pdb_get_username(sam_pass));
734 if (!strlower_m(name)) {
735 return NT_STATUS_INVALID_PARAMETER;
738 /* set the search key */
740 fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
742 rid = pdb_get_user_rid(sam_pass);
744 /* it's outaa here! 8^) */
746 if (dbwrap_transaction_start(db_sam) != 0) {
747 DEBUG(0, ("Could not start transaction\n"));
748 return NT_STATUS_UNSUCCESSFUL;
751 nt_status = dbwrap_delete_bystring(db_sam, keystr);
752 if (!NT_STATUS_IS_OK(nt_status)) {
753 DEBUG(5, ("Error deleting entry from tdb passwd "
754 "database: %s!\n", nt_errstr(nt_status)));
755 goto cancel;
758 /* set the search key */
760 fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
762 /* it's outaa here! 8^) */
764 nt_status = dbwrap_delete_bystring(db_sam, keystr);
765 if (!NT_STATUS_IS_OK(nt_status)) {
766 DEBUG(5, ("Error deleting entry from tdb rid "
767 "database: %s!\n", nt_errstr(nt_status)));
768 goto cancel;
771 if (dbwrap_transaction_commit(db_sam) != 0) {
772 DEBUG(0, ("Could not commit transaction\n"));
773 return NT_STATUS_INTERNAL_DB_CORRUPTION;
776 return NT_STATUS_OK;
778 cancel:
779 if (dbwrap_transaction_cancel(db_sam) != 0) {
780 smb_panic("transaction_cancel failed");
783 return nt_status;
787 /***************************************************************************
788 Update the TDB SAM account record only
789 Assumes that the tdbsam is already open
790 ****************************************************************************/
791 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
793 TDB_DATA data;
794 uint8_t *buf = NULL;
795 fstring keystr;
796 fstring name;
797 bool ret = false;
798 NTSTATUS status;
800 /* copy the struct samu struct into a BYTE buffer for storage */
802 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
803 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
804 goto done;
806 data.dptr = buf;
808 fstrcpy(name, pdb_get_username(newpwd));
809 if (!strlower_m(name)) {
810 goto done;
813 DEBUG(5, ("Storing %saccount %s with RID %d\n",
814 flag == TDB_INSERT ? "(new) " : "", name,
815 pdb_get_user_rid(newpwd)));
817 /* setup the USER index key */
818 fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
820 /* add the account */
822 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
823 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(0, ("Unable to modify passwd TDB: %s!",
825 nt_errstr(status)));
826 goto done;
829 ret = true;
831 done:
832 /* cleanup */
833 SAFE_FREE(buf);
834 return ret;
837 /***************************************************************************
838 Update the TDB SAM RID record only
839 Assumes that the tdbsam is already open
840 ****************************************************************************/
841 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
843 TDB_DATA data;
844 fstring keystr;
845 fstring name;
846 NTSTATUS status;
848 fstrcpy(name, pdb_get_username(newpwd));
849 if (!strlower_m(name)) {
850 return false;
853 /* setup RID data */
854 data = string_term_tdb_data(name);
856 /* setup the RID index key */
857 fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
859 /* add the reference */
860 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
861 if (!NT_STATUS_IS_OK(status)) {
862 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
863 nt_errstr(status)));
864 return false;
867 return true;
871 /***************************************************************************
872 Update the TDB SAM
873 ****************************************************************************/
875 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
876 int flag)
878 uint32_t oldrid;
879 uint32_t newrid;
881 if (!(newrid = pdb_get_user_rid(newpwd))) {
882 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
883 pdb_get_username(newpwd)));
884 return False;
887 oldrid = newrid;
889 /* open the database */
891 if ( !tdbsam_open( tdbsam_filename ) ) {
892 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
893 return False;
896 if (dbwrap_transaction_start(db_sam) != 0) {
897 DEBUG(0, ("Could not start transaction\n"));
898 return false;
901 /* If we are updating, we may be changing this users RID. Retrieve the old RID
902 so we can check. */
904 if (flag == TDB_MODIFY) {
905 struct samu *account = samu_new(talloc_tos());
906 if (account == NULL) {
907 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
908 goto cancel;
910 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
911 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
912 pdb_get_username(newpwd)));
913 TALLOC_FREE(account);
914 goto cancel;
916 if (!(oldrid = pdb_get_user_rid(account))) {
917 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
918 TALLOC_FREE(account);
919 goto cancel;
921 TALLOC_FREE(account);
924 /* Update the new samu entry. */
925 if (!tdb_update_samacct_only(newpwd, flag)) {
926 goto cancel;
929 /* Now take care of the case where the RID changed. We need
930 * to delete the old RID key and add the new. */
932 if (flag == TDB_MODIFY && newrid != oldrid) {
933 fstring keystr;
935 /* Delete old RID key */
936 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
937 fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, oldrid);
938 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
939 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
940 goto cancel;
942 /* Insert new RID key */
943 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
944 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
945 goto cancel;
947 } else {
948 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
949 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
950 if (!tdb_update_ridrec_only(newpwd, flag)) {
951 goto cancel;
955 if (dbwrap_transaction_commit(db_sam) != 0) {
956 DEBUG(0, ("Could not commit transaction\n"));
957 return false;
960 return true;
962 cancel:
963 if (dbwrap_transaction_cancel(db_sam) != 0) {
964 smb_panic("transaction_cancel failed");
966 return false;
969 /***************************************************************************
970 Modifies an existing struct samu
971 ****************************************************************************/
973 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
975 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
976 return NT_STATUS_UNSUCCESSFUL;
978 return NT_STATUS_OK;
981 /***************************************************************************
982 Adds an existing struct samu
983 ****************************************************************************/
985 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
987 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
988 return NT_STATUS_UNSUCCESSFUL;
990 return NT_STATUS_OK;
993 /***************************************************************************
994 Renames a struct samu
995 - check for the posix user/rename user script
996 - Add and lock the new user record
997 - rename the posix user
998 - rewrite the rid->username record
999 - delete the old user
1000 - unlock the new user record
1001 ***************************************************************************/
1002 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1003 struct samu *old_acct,
1004 const char *newname)
1006 const struct loadparm_substitution *lp_sub =
1007 loadparm_s3_global_substitution();
1008 struct samu *new_acct = NULL;
1009 char *rename_script = NULL;
1010 int rename_ret;
1011 fstring oldname_lower;
1012 fstring newname_lower;
1014 /* can't do anything without an external script */
1016 if ( !(new_acct = samu_new( talloc_tos() )) ) {
1017 return NT_STATUS_NO_MEMORY;
1020 rename_script = lp_rename_user_script(new_acct, lp_sub);
1021 if (!rename_script) {
1022 TALLOC_FREE(new_acct);
1023 return NT_STATUS_NO_MEMORY;
1025 if (!*rename_script) {
1026 TALLOC_FREE(new_acct);
1027 return NT_STATUS_ACCESS_DENIED;
1030 if ( !pdb_copy_sam_account(new_acct, old_acct)
1031 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1033 TALLOC_FREE(new_acct);
1034 return NT_STATUS_NO_MEMORY;
1037 /* open the database */
1038 if ( !tdbsam_open( tdbsam_filename ) ) {
1039 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1040 tdbsam_filename));
1041 TALLOC_FREE(new_acct);
1042 return NT_STATUS_ACCESS_DENIED;
1045 if (dbwrap_transaction_start(db_sam) != 0) {
1046 DEBUG(0, ("Could not start transaction\n"));
1047 TALLOC_FREE(new_acct);
1048 return NT_STATUS_ACCESS_DENIED;
1052 /* add the new account and lock it */
1053 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1054 goto cancel;
1057 /* Rename the posix user. Follow the semantics of _samr_create_user()
1058 so that we lower case the posix name but preserve the case in passdb */
1060 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1061 if (!strlower_m( oldname_lower )) {
1062 goto cancel;
1065 fstrcpy( newname_lower, newname );
1066 if (!strlower_m( newname_lower )) {
1067 goto cancel;
1070 rename_script = talloc_string_sub2(new_acct,
1071 rename_script,
1072 "%unew",
1073 newname_lower,
1074 true,
1075 false,
1076 true);
1077 if (!rename_script) {
1078 goto cancel;
1080 rename_script = talloc_string_sub2(new_acct,
1081 rename_script,
1082 "%uold",
1083 oldname_lower,
1084 true,
1085 false,
1086 true);
1087 if (!rename_script) {
1088 goto cancel;
1090 rename_ret = smbrun(rename_script, NULL, NULL);
1092 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1093 rename_script, rename_ret));
1095 if (rename_ret != 0) {
1096 goto cancel;
1099 smb_nscd_flush_user_cache();
1101 /* rewrite the rid->username record */
1103 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1104 goto cancel;
1107 tdb_delete_samacct_only( old_acct );
1109 if (dbwrap_transaction_commit(db_sam) != 0) {
1111 * Ok, we're screwed. We've changed the posix account, but
1112 * could not adapt passdb.tdb. Shall we change the posix
1113 * account back?
1115 DEBUG(0, ("transaction_commit failed\n"));
1116 TALLOC_FREE(new_acct);
1117 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1120 TALLOC_FREE(new_acct );
1121 return NT_STATUS_OK;
1123 cancel:
1124 if (dbwrap_transaction_cancel(db_sam) != 0) {
1125 smb_panic("transaction_cancel failed");
1128 TALLOC_FREE(new_acct);
1130 return NT_STATUS_ACCESS_DENIED;
1133 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1135 return PDB_CAP_STORE_RIDS;
1138 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32_t *prid)
1140 uint32_t rid;
1141 NTSTATUS status;
1143 rid = BASE_RID; /* Default if not set */
1145 if (!tdbsam_open(tdbsam_filename)) {
1146 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1147 tdbsam_filename));
1148 return false;
1151 status = dbwrap_trans_change_uint32_atomic_bystring(
1152 db_sam, NEXT_RID_STRING, &rid, 1);
1153 if (!NT_STATUS_IS_OK(status)) {
1154 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1155 NEXT_RID_STRING, nt_errstr(status)));
1156 return false;
1159 *prid = rid;
1161 return true;
1164 struct tdbsam_search_state {
1165 struct pdb_methods *methods;
1166 uint32_t acct_flags;
1168 uint32_t *rids;
1169 uint32_t num_rids;
1170 ssize_t array_size;
1171 uint32_t current;
1174 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1176 struct tdbsam_search_state *state = talloc_get_type_abort(
1177 private_data, struct tdbsam_search_state);
1178 size_t prefixlen = strlen(RIDPREFIX);
1179 uint32_t rid;
1180 int error = 0;
1181 TDB_DATA key;
1183 key = dbwrap_record_get_key(rec);
1185 if ((key.dsize < prefixlen)
1186 || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1187 return 0;
1190 rid = smb_strtoul((char *)key.dptr+prefixlen,
1191 NULL,
1193 &error,
1194 SMB_STR_STANDARD);
1195 if (error != 0) {
1196 return 0;
1199 ADD_TO_LARGE_ARRAY(state, uint32_t, rid, &state->rids, &state->num_rids,
1200 &state->array_size);
1202 return 0;
1205 static void tdbsam_search_end(struct pdb_search *search)
1207 struct tdbsam_search_state *state = talloc_get_type_abort(
1208 search->private_data, struct tdbsam_search_state);
1209 TALLOC_FREE(state);
1212 static bool tdbsam_search_next_entry(struct pdb_search *search,
1213 struct samr_displayentry *entry)
1215 struct tdbsam_search_state *state = talloc_get_type_abort(
1216 search->private_data, struct tdbsam_search_state);
1217 struct samu *user = NULL;
1218 NTSTATUS status;
1219 uint32_t rid;
1221 again:
1222 TALLOC_FREE(user);
1223 user = samu_new(talloc_tos());
1224 if (user == NULL) {
1225 DEBUG(0, ("samu_new failed\n"));
1226 return false;
1229 if (state->current == state->num_rids) {
1230 TALLOC_FREE(user);
1231 return false;
1234 rid = state->rids[state->current++];
1236 status = tdbsam_getsampwrid(state->methods, user, rid);
1238 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1240 * Someone has deleted that user since we listed the RIDs
1242 goto again;
1245 if (!NT_STATUS_IS_OK(status)) {
1246 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1247 nt_errstr(status)));
1248 TALLOC_FREE(user);
1249 return false;
1252 if ((state->acct_flags != 0) &&
1253 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1254 goto again;
1257 entry->acct_flags = pdb_get_acct_ctrl(user);
1258 entry->rid = rid;
1259 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1260 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1261 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1263 TALLOC_FREE(user);
1265 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1266 || (entry->description == NULL)) {
1267 DEBUG(0, ("talloc_strdup failed\n"));
1268 return false;
1271 return true;
1274 static bool tdbsam_search_users(struct pdb_methods *methods,
1275 struct pdb_search *search,
1276 uint32_t acct_flags)
1278 struct tdbsam_search_state *state;
1280 if (!tdbsam_open(tdbsam_filename)) {
1281 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1282 tdbsam_filename));
1283 return false;
1286 state = talloc_zero(search, struct tdbsam_search_state);
1287 if (state == NULL) {
1288 DEBUG(0, ("talloc failed\n"));
1289 return false;
1291 state->acct_flags = acct_flags;
1292 state->methods = methods;
1294 dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1296 search->private_data = state;
1297 search->next_entry = tdbsam_search_next_entry;
1298 search->search_end = tdbsam_search_end;
1300 return true;
1303 static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
1305 return map_builtin;
1308 /*********************************************************************
1309 Initialize the tdb sam backend. Setup the dispath table of methods,
1310 open the tdb, etc...
1311 *********************************************************************/
1313 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1315 NTSTATUS nt_status;
1316 char *tdbfile = NULL;
1317 const char *pfile = location;
1319 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1320 return nt_status;
1323 (*pdb_method)->name = "tdbsam";
1325 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1326 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1327 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1328 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1329 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1330 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1331 (*pdb_method)->search_users = tdbsam_search_users;
1333 (*pdb_method)->capabilities = tdbsam_capabilities;
1334 (*pdb_method)->new_rid = tdbsam_new_rid;
1336 (*pdb_method)->is_responsible_for_builtin =
1337 tdbsam_is_responsible_for_builtin;
1338 map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
1340 /* save the path for later */
1342 if (!location) {
1343 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1344 PASSDB_FILE_NAME) < 0) {
1345 return NT_STATUS_NO_MEMORY;
1347 pfile = tdbfile;
1349 tdbsam_filename = SMB_STRDUP(pfile);
1350 if (!tdbsam_filename) {
1351 return NT_STATUS_NO_MEMORY;
1353 SAFE_FREE(tdbfile);
1355 /* no private data */
1357 (*pdb_method)->private_data = NULL;
1358 (*pdb_method)->free_private_data = NULL;
1360 return NT_STATUS_OK;
1363 NTSTATUS pdb_tdbsam_init(TALLOC_CTX *ctx)
1365 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);