s3-net: let rpccli_winreg_Connect optionally return WERROR
[Samba.git] / source3 / passdb / pdb_tdb.c
blobe1c2c437ff690a4e2d16adb2957d65e57d00b21c
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 "dbwrap.h"
28 #if 0 /* when made a module use this */
30 static int tdbsam_debug_level = DBGC_ALL;
31 #undef DBGC_CLASS
32 #define DBGC_CLASS tdbsam_debug_level
34 #else
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_PASSDB
39 #endif
41 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
42 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
43 #define TDBSAM_VERSION_STRING "INFO/version"
44 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
45 #define PASSDB_FILE_NAME "passdb.tdb"
46 #define USERPREFIX "USER_"
47 #define USERPREFIX_LEN 5
48 #define RIDPREFIX "RID_"
49 #define PRIVPREFIX "PRIV_"
50 #define NEXT_RID_STRING "NEXT_RID"
52 /* GLOBAL TDB SAM CONTEXT */
54 static struct db_context *db_sam;
55 static char *tdbsam_filename;
57 struct tdbsam_convert_state {
58 int32_t from;
59 bool success;
62 static int tdbsam_convert_one(struct db_record *rec, void *priv)
64 struct tdbsam_convert_state *state =
65 (struct tdbsam_convert_state *)priv;
66 struct samu *user;
67 TDB_DATA data;
68 NTSTATUS status;
69 bool ret;
71 if (rec->key.dsize < USERPREFIX_LEN) {
72 return 0;
74 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
75 return 0;
78 user = samu_new(talloc_tos());
79 if (user == NULL) {
80 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
81 state->success = false;
82 return -1;
85 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
86 "(version:%d)\n", rec->key.dptr, state->from));
88 switch (state->from) {
89 case 0:
90 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
91 (uint8 *)rec->value.dptr,
92 rec->value.dsize);
93 break;
94 case 1:
95 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
96 (uint8 *)rec->value.dptr,
97 rec->value.dsize);
98 break;
99 case 2:
100 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
101 (uint8 *)rec->value.dptr,
102 rec->value.dsize);
103 break;
104 case 3:
105 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
106 (uint8 *)rec->value.dptr,
107 rec->value.dsize);
108 break;
109 case 4:
110 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
111 (uint8 *)rec->value.dptr,
112 rec->value.dsize);
113 break;
114 default:
115 /* unknown tdbsam version */
116 ret = False;
118 if (!ret) {
119 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
120 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
121 state->from));
122 TALLOC_FREE(user);
123 state->success = false;
124 return -1;
127 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
128 TALLOC_FREE(user);
130 if (data.dsize == -1) {
131 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
132 "the new format\n"));
133 state->success = false;
134 return -1;
137 status = rec->store(rec, data, TDB_MODIFY);
138 if (!NT_STATUS_IS_OK(status)) {
139 DEBUG(0, ("Could not store the new record: %s\n",
140 nt_errstr(status)));
141 state->success = false;
142 return -1;
145 return 0;
148 /**********************************************************************
149 Struct and function to backup an old record.
150 *********************************************************************/
152 struct tdbsam_backup_state {
153 struct db_context *new_db;
154 bool success;
157 static int backup_copy_fn(struct db_record *orig_rec, void *state)
159 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
160 struct db_record *new_rec;
161 NTSTATUS status;
163 new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
164 if (new_rec == NULL) {
165 bs->success = false;
166 return 1;
169 status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
171 TALLOC_FREE(new_rec);
173 if (!NT_STATUS_IS_OK(status)) {
174 bs->success = false;
175 return 1;
177 return 0;
180 /**********************************************************************
181 Make a backup of an old passdb and replace the new one with it. We
182 have to do this as between 3.0.x and 3.2.x the hash function changed
183 by mistake (used unsigned char * instead of char *). This means the
184 previous simple update code will fail due to not being able to find
185 existing records to replace in the tdbsam_convert_one() function. JRA.
186 *********************************************************************/
188 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
190 TALLOC_CTX *frame = talloc_stackframe();
191 const char *tmp_fname = NULL;
192 struct db_context *tmp_db = NULL;
193 struct db_context *orig_db = *pp_db;
194 struct tdbsam_backup_state bs;
195 int ret;
197 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
198 if (!tmp_fname) {
199 TALLOC_FREE(frame);
200 return false;
203 unlink(tmp_fname);
205 /* Remember to open this on the NULL context. We need
206 * it to stay around after we return from here. */
208 tmp_db = db_open(NULL, tmp_fname, 0,
209 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
210 if (tmp_db == NULL) {
211 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
212 "[%s]\n", tmp_fname));
213 TALLOC_FREE(frame);
214 return false;
217 if (orig_db->transaction_start(orig_db) != 0) {
218 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
219 unlink(tmp_fname);
220 TALLOC_FREE(tmp_db);
221 TALLOC_FREE(frame);
222 return false;
224 if (tmp_db->transaction_start(tmp_db) != 0) {
225 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
226 orig_db->transaction_cancel(orig_db);
227 unlink(tmp_fname);
228 TALLOC_FREE(tmp_db);
229 TALLOC_FREE(frame);
230 return false;
233 bs.new_db = tmp_db;
234 bs.success = true;
236 ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
237 if (ret < 0) {
238 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
239 goto cancel;
242 if (!bs.success) {
243 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
244 goto cancel;
247 if (orig_db->transaction_commit(orig_db) != 0) {
248 smb_panic("tdbsam_convert_backup: orig commit failed\n");
250 if (tmp_db->transaction_commit(tmp_db) != 0) {
251 smb_panic("tdbsam_convert_backup: orig commit failed\n");
254 /* be sure to close the DBs _before_ renaming the file */
256 TALLOC_FREE(orig_db);
257 TALLOC_FREE(tmp_db);
259 /* This is safe from other users as we know we're
260 * under a mutex here. */
262 if (rename(tmp_fname, dbname) == -1) {
263 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
264 tmp_fname,
265 dbname,
266 strerror(errno)));
267 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
270 TALLOC_FREE(frame);
272 /* re-open the converted TDB */
274 orig_db = db_open(NULL, dbname, 0,
275 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
276 if (orig_db == NULL) {
277 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
278 "converted passdb TDB [%s]\n", dbname));
279 return false;
282 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
283 dbname ));
285 /* Replace the global db pointer. */
286 *pp_db = orig_db;
287 return true;
289 cancel:
291 if (orig_db->transaction_cancel(orig_db) != 0) {
292 smb_panic("tdbsam_convert: transaction_cancel failed");
295 if (tmp_db->transaction_cancel(tmp_db) != 0) {
296 smb_panic("tdbsam_convert: transaction_cancel failed");
299 unlink(tmp_fname);
300 TALLOC_FREE(tmp_db);
301 TALLOC_FREE(frame);
302 return false;
305 static bool tdbsam_upgrade_next_rid(struct db_context *db)
307 TDB_CONTEXT *tdb;
308 uint32 rid;
309 bool ok = false;
311 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
312 if (ok) {
313 return true;
316 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
317 TDB_DEFAULT, O_RDONLY, 0644);
319 if (tdb) {
320 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
321 if (!ok) {
322 rid = BASE_RID;
324 tdb_close(tdb);
325 } else {
326 rid = BASE_RID;
329 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
330 return false;
333 return true;
336 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
338 struct tdbsam_convert_state state;
339 struct db_context *db = NULL;
340 int ret;
342 /* We only need the update backup for local db's. */
343 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
344 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
345 return false;
348 db = *pp_db;
349 state.from = from;
350 state.success = true;
352 if (db->transaction_start(db) != 0) {
353 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
354 return false;
357 if (!tdbsam_upgrade_next_rid(db)) {
358 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
359 goto cancel;
362 ret = db->traverse(db, tdbsam_convert_one, &state);
363 if (ret < 0) {
364 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
365 goto cancel;
368 if (!state.success) {
369 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
370 goto cancel;
373 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
374 TDBSAM_VERSION) != 0) {
375 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
376 goto cancel;
379 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
380 TDBSAM_MINOR_VERSION) != 0) {
381 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
382 goto cancel;
385 if (db->transaction_commit(db) != 0) {
386 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
387 return false;
390 return true;
392 cancel:
393 if (db->transaction_cancel(db) != 0) {
394 smb_panic("tdbsam_convert: transaction_cancel failed");
397 return false;
400 /*********************************************************************
401 Open the tdbsam file based on the absolute path specified.
402 Uses a reference count to allow multiple open calls.
403 *********************************************************************/
405 static bool tdbsam_open( const char *name )
407 int32 version;
408 int32 minor_version;
410 /* check if we are already open */
412 if ( db_sam ) {
413 return true;
416 /* Try to open tdb passwd. Create a new one if necessary */
418 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
419 if (db_sam == NULL) {
420 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
421 "[%s]\n", name));
422 return false;
425 /* Check the version */
426 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
427 if (version == -1) {
428 version = 0; /* Version not found, assume version 0 */
431 /* Get the minor version */
432 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
433 if (minor_version == -1) {
434 minor_version = 0; /* Minor version not found, assume 0 */
437 /* Compare the version */
438 if (version > TDBSAM_VERSION) {
439 /* Version more recent than the latest known */
440 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
441 TALLOC_FREE(db_sam);
442 return false;
445 if ( version < TDBSAM_VERSION ||
446 (version == TDBSAM_VERSION &&
447 minor_version < TDBSAM_MINOR_VERSION) ) {
449 * Ok - we think we're going to have to convert.
450 * Due to the backup process we now must do to
451 * upgrade we have to get a mutex and re-check
452 * the version. Someone else may have upgraded
453 * whilst we were checking.
456 struct named_mutex *mtx = grab_named_mutex(NULL,
457 "tdbsam_upgrade_mutex",
458 600);
460 if (!mtx) {
461 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
462 TALLOC_FREE(db_sam);
463 return false;
466 /* Re-check the version */
467 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
468 if (version == -1) {
469 version = 0; /* Version not found, assume version 0 */
472 /* Re-check the minor version */
473 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
474 if (minor_version == -1) {
475 minor_version = 0; /* Minor version not found, assume 0 */
478 /* Compare the version */
479 if (version > TDBSAM_VERSION) {
480 /* Version more recent than the latest known */
481 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
482 TALLOC_FREE(db_sam);
483 TALLOC_FREE(mtx);
484 return false;
487 if ( version < TDBSAM_VERSION ||
488 (version == TDBSAM_VERSION &&
489 minor_version < TDBSAM_MINOR_VERSION) ) {
491 * Note that minor versions we read that are greater
492 * than the current minor version we have hard coded
493 * are assumed to be compatible if they have the same
494 * major version. That allows previous versions of the
495 * passdb code that don't know about minor versions to
496 * still use this database. JRA.
499 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
500 "version %d.%d.\n",
501 version,
502 minor_version,
503 TDBSAM_VERSION,
504 TDBSAM_MINOR_VERSION));
506 if ( !tdbsam_convert(&db_sam, name, version) ) {
507 DEBUG(0, ("tdbsam_open: Error when trying to convert "
508 "tdbsam [%s]\n",name));
509 TALLOC_FREE(db_sam);
510 TALLOC_FREE(mtx);
511 return false;
514 DEBUG(3, ("TDBSAM converted successfully.\n"));
516 TALLOC_FREE(mtx);
519 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
521 return true;
524 /******************************************************************
525 Lookup a name in the SAM TDB
526 ******************************************************************/
528 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
529 struct samu *user, const char *sname)
531 TDB_DATA data;
532 fstring keystr;
533 fstring name;
535 if ( !user ) {
536 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
537 return NT_STATUS_NO_MEMORY;
540 /* Data is stored in all lower-case */
541 fstrcpy(name, sname);
542 strlower_m(name);
544 /* set search key */
545 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
547 /* open the database */
549 if ( !tdbsam_open( tdbsam_filename ) ) {
550 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
551 return NT_STATUS_ACCESS_DENIED;
554 /* get the record */
556 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
557 if (!data.dptr) {
558 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
559 DEBUGADD(5, (" Key: %s\n", keystr));
560 return NT_STATUS_NO_SUCH_USER;
563 /* unpack the buffer */
565 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
566 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
567 SAFE_FREE(data.dptr);
568 return NT_STATUS_NO_MEMORY;
571 /* success */
573 TALLOC_FREE(data.dptr);
575 return NT_STATUS_OK;
578 /***************************************************************************
579 Search by rid
580 **************************************************************************/
582 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
583 struct samu *user, uint32 rid)
585 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
586 TDB_DATA data;
587 fstring keystr;
588 fstring name;
590 if ( !user ) {
591 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
592 return nt_status;
595 /* set search key */
597 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
599 /* open the database */
601 if ( !tdbsam_open( tdbsam_filename ) ) {
602 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
603 return NT_STATUS_ACCESS_DENIED;
606 /* get the record */
608 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
609 if (!data.dptr) {
610 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
611 return NT_STATUS_UNSUCCESSFUL;
614 fstrcpy(name, (const char *)data.dptr);
615 TALLOC_FREE(data.dptr);
617 return tdbsam_getsampwnam (my_methods, user, name);
620 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
621 struct samu * user, const struct dom_sid *sid)
623 uint32 rid;
625 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
626 return NT_STATUS_UNSUCCESSFUL;
628 return tdbsam_getsampwrid(my_methods, user, rid);
631 static bool tdb_delete_samacct_only( struct samu *sam_pass )
633 fstring keystr;
634 fstring name;
635 NTSTATUS status;
637 fstrcpy(name, pdb_get_username(sam_pass));
638 strlower_m(name);
640 /* set the search key */
642 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
644 /* it's outaa here! 8^) */
645 if ( !tdbsam_open( tdbsam_filename ) ) {
646 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
647 tdbsam_filename));
648 return false;
651 status = dbwrap_delete_bystring(db_sam, keystr);
652 if (!NT_STATUS_IS_OK(status)) {
653 DEBUG(5, ("Error deleting entry from tdb passwd "
654 "database: %s!\n", nt_errstr(status)));
655 return false;
658 return true;
661 /***************************************************************************
662 Delete a struct samu records for the username and RID key
663 ****************************************************************************/
665 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
666 struct samu *sam_pass)
668 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
669 fstring keystr;
670 uint32 rid;
671 fstring name;
673 /* open the database */
675 if ( !tdbsam_open( tdbsam_filename ) ) {
676 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
677 tdbsam_filename));
678 return NT_STATUS_ACCESS_DENIED;
681 fstrcpy(name, pdb_get_username(sam_pass));
682 strlower_m(name);
684 /* set the search key */
686 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
688 rid = pdb_get_user_rid(sam_pass);
690 /* it's outaa here! 8^) */
692 if (db_sam->transaction_start(db_sam) != 0) {
693 DEBUG(0, ("Could not start transaction\n"));
694 return NT_STATUS_UNSUCCESSFUL;
697 nt_status = dbwrap_delete_bystring(db_sam, keystr);
698 if (!NT_STATUS_IS_OK(nt_status)) {
699 DEBUG(5, ("Error deleting entry from tdb passwd "
700 "database: %s!\n", nt_errstr(nt_status)));
701 goto cancel;
704 /* set the search key */
706 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
708 /* it's outaa here! 8^) */
710 nt_status = dbwrap_delete_bystring(db_sam, keystr);
711 if (!NT_STATUS_IS_OK(nt_status)) {
712 DEBUG(5, ("Error deleting entry from tdb rid "
713 "database: %s!\n", nt_errstr(nt_status)));
714 goto cancel;
717 if (db_sam->transaction_commit(db_sam) != 0) {
718 DEBUG(0, ("Could not commit transaction\n"));
719 return NT_STATUS_INTERNAL_DB_CORRUPTION;
722 return NT_STATUS_OK;
724 cancel:
725 if (db_sam->transaction_cancel(db_sam) != 0) {
726 smb_panic("transaction_cancel failed");
729 return nt_status;
733 /***************************************************************************
734 Update the TDB SAM account record only
735 Assumes that the tdbsam is already open
736 ****************************************************************************/
737 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
739 TDB_DATA data;
740 uint8 *buf = NULL;
741 fstring keystr;
742 fstring name;
743 bool ret = false;
744 NTSTATUS status;
746 /* copy the struct samu struct into a BYTE buffer for storage */
748 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
749 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
750 goto done;
752 data.dptr = buf;
754 fstrcpy(name, pdb_get_username(newpwd));
755 strlower_m(name);
757 DEBUG(5, ("Storing %saccount %s with RID %d\n",
758 flag == TDB_INSERT ? "(new) " : "", name,
759 pdb_get_user_rid(newpwd)));
761 /* setup the USER index key */
762 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
764 /* add the account */
766 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
767 if (!NT_STATUS_IS_OK(status)) {
768 DEBUG(0, ("Unable to modify passwd TDB: %s!",
769 nt_errstr(status)));
770 goto done;
773 ret = true;
775 done:
776 /* cleanup */
777 SAFE_FREE(buf);
778 return ret;
781 /***************************************************************************
782 Update the TDB SAM RID record only
783 Assumes that the tdbsam is already open
784 ****************************************************************************/
785 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
787 TDB_DATA data;
788 fstring keystr;
789 fstring name;
790 NTSTATUS status;
792 fstrcpy(name, pdb_get_username(newpwd));
793 strlower_m(name);
795 /* setup RID data */
796 data = string_term_tdb_data(name);
798 /* setup the RID index key */
799 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
800 pdb_get_user_rid(newpwd));
802 /* add the reference */
803 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
804 if (!NT_STATUS_IS_OK(status)) {
805 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
806 nt_errstr(status)));
807 return false;
810 return true;
814 /***************************************************************************
815 Update the TDB SAM
816 ****************************************************************************/
818 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
819 int flag)
821 uint32_t oldrid;
822 uint32_t newrid;
824 if (!(newrid = pdb_get_user_rid(newpwd))) {
825 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
826 pdb_get_username(newpwd)));
827 return False;
830 oldrid = newrid;
832 /* open the database */
834 if ( !tdbsam_open( tdbsam_filename ) ) {
835 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
836 return False;
839 if (db_sam->transaction_start(db_sam) != 0) {
840 DEBUG(0, ("Could not start transaction\n"));
841 return false;
844 /* If we are updating, we may be changing this users RID. Retrieve the old RID
845 so we can check. */
847 if (flag == TDB_MODIFY) {
848 struct samu *account = samu_new(talloc_tos());
849 if (account == NULL) {
850 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
851 goto cancel;
853 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
854 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
855 pdb_get_username(newpwd)));
856 TALLOC_FREE(account);
857 goto cancel;
859 if (!(oldrid = pdb_get_user_rid(account))) {
860 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
861 TALLOC_FREE(account);
862 goto cancel;
864 TALLOC_FREE(account);
867 /* Update the new samu entry. */
868 if (!tdb_update_samacct_only(newpwd, flag)) {
869 goto cancel;
872 /* Now take care of the case where the RID changed. We need
873 * to delete the old RID key and add the new. */
875 if (flag == TDB_MODIFY && newrid != oldrid) {
876 fstring keystr;
878 /* Delete old RID key */
879 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
880 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
881 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
882 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
883 goto cancel;
885 /* Insert new RID key */
886 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
887 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
888 goto cancel;
890 } else {
891 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
892 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
893 if (!tdb_update_ridrec_only(newpwd, flag)) {
894 goto cancel;
898 if (db_sam->transaction_commit(db_sam) != 0) {
899 DEBUG(0, ("Could not commit transaction\n"));
900 return false;
903 return true;
905 cancel:
906 if (db_sam->transaction_cancel(db_sam) != 0) {
907 smb_panic("transaction_cancel failed");
909 return false;
912 /***************************************************************************
913 Modifies an existing struct samu
914 ****************************************************************************/
916 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
918 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
919 return NT_STATUS_UNSUCCESSFUL;
921 return NT_STATUS_OK;
924 /***************************************************************************
925 Adds an existing struct samu
926 ****************************************************************************/
928 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
930 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
931 return NT_STATUS_UNSUCCESSFUL;
933 return NT_STATUS_OK;
936 /***************************************************************************
937 Renames a struct samu
938 - check for the posix user/rename user script
939 - Add and lock the new user record
940 - rename the posix user
941 - rewrite the rid->username record
942 - delete the old user
943 - unlock the new user record
944 ***************************************************************************/
945 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
946 struct samu *old_acct,
947 const char *newname)
949 struct samu *new_acct = NULL;
950 char *rename_script = NULL;
951 int rename_ret;
952 fstring oldname_lower;
953 fstring newname_lower;
955 /* can't do anything without an external script */
957 if ( !(new_acct = samu_new( talloc_tos() )) ) {
958 return NT_STATUS_NO_MEMORY;
961 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
962 if (!rename_script) {
963 TALLOC_FREE(new_acct);
964 return NT_STATUS_NO_MEMORY;
966 if (!*rename_script) {
967 TALLOC_FREE(new_acct);
968 return NT_STATUS_ACCESS_DENIED;
971 if ( !pdb_copy_sam_account(new_acct, old_acct)
972 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
974 TALLOC_FREE(new_acct);
975 return NT_STATUS_NO_MEMORY;
978 /* open the database */
979 if ( !tdbsam_open( tdbsam_filename ) ) {
980 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
981 tdbsam_filename));
982 TALLOC_FREE(new_acct);
983 return NT_STATUS_ACCESS_DENIED;
986 if (db_sam->transaction_start(db_sam) != 0) {
987 DEBUG(0, ("Could not start transaction\n"));
988 TALLOC_FREE(new_acct);
989 return NT_STATUS_ACCESS_DENIED;
993 /* add the new account and lock it */
994 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
995 goto cancel;
998 /* Rename the posix user. Follow the semantics of _samr_create_user()
999 so that we lower case the posix name but preserve the case in passdb */
1001 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1002 strlower_m( oldname_lower );
1004 fstrcpy( newname_lower, newname );
1005 strlower_m( newname_lower );
1007 rename_script = talloc_string_sub2(new_acct,
1008 rename_script,
1009 "%unew",
1010 newname_lower,
1011 true,
1012 false,
1013 true);
1014 if (!rename_script) {
1015 goto cancel;
1017 rename_script = talloc_string_sub2(new_acct,
1018 rename_script,
1019 "%uold",
1020 oldname_lower,
1021 true,
1022 false,
1023 true);
1024 if (!rename_script) {
1025 goto cancel;
1027 rename_ret = smbrun(rename_script, NULL);
1029 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1030 rename_script, rename_ret));
1032 if (rename_ret != 0) {
1033 goto cancel;
1036 smb_nscd_flush_user_cache();
1038 /* rewrite the rid->username record */
1040 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1041 goto cancel;
1044 tdb_delete_samacct_only( old_acct );
1046 if (db_sam->transaction_commit(db_sam) != 0) {
1048 * Ok, we're screwed. We've changed the posix account, but
1049 * could not adapt passdb.tdb. Shall we change the posix
1050 * account back?
1052 DEBUG(0, ("transaction_commit failed\n"));
1053 TALLOC_FREE(new_acct);
1054 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1057 TALLOC_FREE(new_acct );
1058 return NT_STATUS_OK;
1060 cancel:
1061 if (db_sam->transaction_cancel(db_sam) != 0) {
1062 smb_panic("transaction_cancel failed");
1065 TALLOC_FREE(new_acct);
1067 return NT_STATUS_ACCESS_DENIED;
1070 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1072 return PDB_CAP_STORE_RIDS;
1075 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1077 uint32 rid;
1078 NTSTATUS status;
1080 rid = BASE_RID; /* Default if not set */
1082 if (!tdbsam_open(tdbsam_filename)) {
1083 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1084 tdbsam_filename));
1085 return false;
1088 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1089 &rid, 1);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1092 NEXT_RID_STRING, nt_errstr(status)));
1093 return false;
1096 *prid = rid;
1098 return true;
1101 struct tdbsam_search_state {
1102 struct pdb_methods *methods;
1103 uint32_t acct_flags;
1105 uint32_t *rids;
1106 uint32_t num_rids;
1107 ssize_t array_size;
1108 uint32_t current;
1111 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1113 struct tdbsam_search_state *state = talloc_get_type_abort(
1114 private_data, struct tdbsam_search_state);
1115 size_t prefixlen = strlen(RIDPREFIX);
1116 uint32 rid;
1118 if ((rec->key.dsize < prefixlen)
1119 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1120 return 0;
1123 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1125 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1126 &state->array_size);
1128 return 0;
1131 static void tdbsam_search_end(struct pdb_search *search)
1133 struct tdbsam_search_state *state = talloc_get_type_abort(
1134 search->private_data, struct tdbsam_search_state);
1135 TALLOC_FREE(state);
1138 static bool tdbsam_search_next_entry(struct pdb_search *search,
1139 struct samr_displayentry *entry)
1141 struct tdbsam_search_state *state = talloc_get_type_abort(
1142 search->private_data, struct tdbsam_search_state);
1143 struct samu *user = NULL;
1144 NTSTATUS status;
1145 uint32_t rid;
1147 again:
1148 TALLOC_FREE(user);
1149 user = samu_new(talloc_tos());
1150 if (user == NULL) {
1151 DEBUG(0, ("samu_new failed\n"));
1152 return false;
1155 if (state->current == state->num_rids) {
1156 return false;
1159 rid = state->rids[state->current++];
1161 status = tdbsam_getsampwrid(state->methods, user, rid);
1163 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1165 * Someone has deleted that user since we listed the RIDs
1167 goto again;
1170 if (!NT_STATUS_IS_OK(status)) {
1171 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1172 nt_errstr(status)));
1173 TALLOC_FREE(user);
1174 return false;
1177 if ((state->acct_flags != 0) &&
1178 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1179 goto again;
1182 entry->acct_flags = pdb_get_acct_ctrl(user);
1183 entry->rid = rid;
1184 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1185 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1186 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1188 TALLOC_FREE(user);
1190 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1191 || (entry->description == NULL)) {
1192 DEBUG(0, ("talloc_strdup failed\n"));
1193 return false;
1196 return true;
1199 static bool tdbsam_search_users(struct pdb_methods *methods,
1200 struct pdb_search *search,
1201 uint32 acct_flags)
1203 struct tdbsam_search_state *state;
1205 if (!tdbsam_open(tdbsam_filename)) {
1206 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1207 tdbsam_filename));
1208 return false;
1211 state = talloc_zero(search, struct tdbsam_search_state);
1212 if (state == NULL) {
1213 DEBUG(0, ("talloc failed\n"));
1214 return false;
1216 state->acct_flags = acct_flags;
1217 state->methods = methods;
1219 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1221 search->private_data = state;
1222 search->next_entry = tdbsam_search_next_entry;
1223 search->search_end = tdbsam_search_end;
1225 return true;
1228 /*********************************************************************
1229 Initialize the tdb sam backend. Setup the dispath table of methods,
1230 open the tdb, etc...
1231 *********************************************************************/
1233 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1235 NTSTATUS nt_status;
1236 char *tdbfile = NULL;
1237 const char *pfile = location;
1239 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1240 return nt_status;
1243 (*pdb_method)->name = "tdbsam";
1245 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1246 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1247 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1248 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1249 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1250 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1251 (*pdb_method)->search_users = tdbsam_search_users;
1253 (*pdb_method)->capabilities = tdbsam_capabilities;
1254 (*pdb_method)->new_rid = tdbsam_new_rid;
1256 /* save the path for later */
1258 if (!location) {
1259 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1260 PASSDB_FILE_NAME) < 0) {
1261 return NT_STATUS_NO_MEMORY;
1263 pfile = tdbfile;
1265 tdbsam_filename = SMB_STRDUP(pfile);
1266 if (!tdbsam_filename) {
1267 return NT_STATUS_NO_MEMORY;
1269 SAFE_FREE(tdbfile);
1271 /* no private data */
1273 (*pdb_method)->private_data = NULL;
1274 (*pdb_method)->free_private_data = NULL;
1276 return NT_STATUS_OK;
1279 NTSTATUS pdb_tdbsam_init(void)
1281 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);