s3: Add winbindd_lookupsids
[Samba.git] / source3 / passdb / pdb_tdb.c
blob79c0ed196afb2f51980d70b4f0e17b223d96422d
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.h"
29 #include "../libcli/security/security.h"
31 #if 0 /* when made a module use this */
33 static int tdbsam_debug_level = DBGC_ALL;
34 #undef DBGC_CLASS
35 #define DBGC_CLASS tdbsam_debug_level
37 #else
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_PASSDB
42 #endif
44 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
45 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
46 #define TDBSAM_VERSION_STRING "INFO/version"
47 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
48 #define PASSDB_FILE_NAME "passdb.tdb"
49 #define USERPREFIX "USER_"
50 #define USERPREFIX_LEN 5
51 #define RIDPREFIX "RID_"
52 #define PRIVPREFIX "PRIV_"
53 #define NEXT_RID_STRING "NEXT_RID"
55 /* GLOBAL TDB SAM CONTEXT */
57 static struct db_context *db_sam;
58 static char *tdbsam_filename;
60 struct tdbsam_convert_state {
61 int32_t from;
62 bool success;
65 static int tdbsam_convert_one(struct db_record *rec, void *priv)
67 struct tdbsam_convert_state *state =
68 (struct tdbsam_convert_state *)priv;
69 struct samu *user;
70 TDB_DATA data;
71 NTSTATUS status;
72 bool ret;
74 if (rec->key.dsize < USERPREFIX_LEN) {
75 return 0;
77 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
78 return 0;
81 user = samu_new(talloc_tos());
82 if (user == NULL) {
83 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
84 state->success = false;
85 return -1;
88 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
89 "(version:%d)\n", rec->key.dptr, state->from));
91 switch (state->from) {
92 case 0:
93 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
94 (uint8 *)rec->value.dptr,
95 rec->value.dsize);
96 break;
97 case 1:
98 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
99 (uint8 *)rec->value.dptr,
100 rec->value.dsize);
101 break;
102 case 2:
103 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
104 (uint8 *)rec->value.dptr,
105 rec->value.dsize);
106 break;
107 case 3:
108 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
109 (uint8 *)rec->value.dptr,
110 rec->value.dsize);
111 break;
112 case 4:
113 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
114 (uint8 *)rec->value.dptr,
115 rec->value.dsize);
116 break;
117 default:
118 /* unknown tdbsam version */
119 ret = False;
121 if (!ret) {
122 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
123 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
124 state->from));
125 TALLOC_FREE(user);
126 state->success = false;
127 return -1;
130 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
131 TALLOC_FREE(user);
133 if (data.dsize == -1) {
134 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
135 "the new format\n"));
136 state->success = false;
137 return -1;
140 status = rec->store(rec, data, TDB_MODIFY);
141 if (!NT_STATUS_IS_OK(status)) {
142 DEBUG(0, ("Could not store the new record: %s\n",
143 nt_errstr(status)));
144 state->success = false;
145 return -1;
148 return 0;
151 /**********************************************************************
152 Struct and function to backup an old record.
153 *********************************************************************/
155 struct tdbsam_backup_state {
156 struct db_context *new_db;
157 bool success;
160 static int backup_copy_fn(struct db_record *orig_rec, void *state)
162 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
163 struct db_record *new_rec;
164 NTSTATUS status;
166 new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
167 if (new_rec == NULL) {
168 bs->success = false;
169 return 1;
172 status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
174 TALLOC_FREE(new_rec);
176 if (!NT_STATUS_IS_OK(status)) {
177 bs->success = false;
178 return 1;
180 return 0;
183 /**********************************************************************
184 Make a backup of an old passdb and replace the new one with it. We
185 have to do this as between 3.0.x and 3.2.x the hash function changed
186 by mistake (used unsigned char * instead of char *). This means the
187 previous simple update code will fail due to not being able to find
188 existing records to replace in the tdbsam_convert_one() function. JRA.
189 *********************************************************************/
191 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
193 TALLOC_CTX *frame = talloc_stackframe();
194 const char *tmp_fname = NULL;
195 struct db_context *tmp_db = NULL;
196 struct db_context *orig_db = *pp_db;
197 struct tdbsam_backup_state bs;
198 int ret;
200 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
201 if (!tmp_fname) {
202 TALLOC_FREE(frame);
203 return false;
206 unlink(tmp_fname);
208 /* Remember to open this on the NULL context. We need
209 * it to stay around after we return from here. */
211 tmp_db = db_open(NULL, tmp_fname, 0,
212 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
213 if (tmp_db == NULL) {
214 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
215 "[%s]\n", tmp_fname));
216 TALLOC_FREE(frame);
217 return false;
220 if (orig_db->transaction_start(orig_db) != 0) {
221 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
222 unlink(tmp_fname);
223 TALLOC_FREE(tmp_db);
224 TALLOC_FREE(frame);
225 return false;
227 if (tmp_db->transaction_start(tmp_db) != 0) {
228 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
229 orig_db->transaction_cancel(orig_db);
230 unlink(tmp_fname);
231 TALLOC_FREE(tmp_db);
232 TALLOC_FREE(frame);
233 return false;
236 bs.new_db = tmp_db;
237 bs.success = true;
239 ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
240 if (ret < 0) {
241 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
242 goto cancel;
245 if (!bs.success) {
246 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
247 goto cancel;
250 if (orig_db->transaction_commit(orig_db) != 0) {
251 smb_panic("tdbsam_convert_backup: orig commit failed\n");
253 if (tmp_db->transaction_commit(tmp_db) != 0) {
254 smb_panic("tdbsam_convert_backup: orig commit failed\n");
257 /* be sure to close the DBs _before_ renaming the file */
259 TALLOC_FREE(orig_db);
260 TALLOC_FREE(tmp_db);
262 /* This is safe from other users as we know we're
263 * under a mutex here. */
265 if (rename(tmp_fname, dbname) == -1) {
266 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
267 tmp_fname,
268 dbname,
269 strerror(errno)));
270 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
273 TALLOC_FREE(frame);
275 /* re-open the converted TDB */
277 orig_db = db_open(NULL, dbname, 0,
278 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
279 if (orig_db == NULL) {
280 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
281 "converted passdb TDB [%s]\n", dbname));
282 return false;
285 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
286 dbname ));
288 /* Replace the global db pointer. */
289 *pp_db = orig_db;
290 return true;
292 cancel:
294 if (orig_db->transaction_cancel(orig_db) != 0) {
295 smb_panic("tdbsam_convert: transaction_cancel failed");
298 if (tmp_db->transaction_cancel(tmp_db) != 0) {
299 smb_panic("tdbsam_convert: transaction_cancel failed");
302 unlink(tmp_fname);
303 TALLOC_FREE(tmp_db);
304 TALLOC_FREE(frame);
305 return false;
308 static bool tdbsam_upgrade_next_rid(struct db_context *db)
310 TDB_CONTEXT *tdb;
311 uint32 rid;
312 bool ok = false;
314 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
315 if (ok) {
316 return true;
319 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
320 TDB_DEFAULT, O_RDONLY, 0644);
322 if (tdb) {
323 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
324 if (!ok) {
325 rid = BASE_RID;
327 tdb_close(tdb);
328 } else {
329 rid = BASE_RID;
332 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
333 return false;
336 return true;
339 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
341 struct tdbsam_convert_state state;
342 struct db_context *db = NULL;
343 int ret;
345 /* We only need the update backup for local db's. */
346 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
347 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
348 return false;
351 db = *pp_db;
352 state.from = from;
353 state.success = true;
355 if (db->transaction_start(db) != 0) {
356 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
357 return false;
360 if (!tdbsam_upgrade_next_rid(db)) {
361 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
362 goto cancel;
365 ret = db->traverse(db, tdbsam_convert_one, &state);
366 if (ret < 0) {
367 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
368 goto cancel;
371 if (!state.success) {
372 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
373 goto cancel;
376 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
377 TDBSAM_VERSION) != 0) {
378 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
379 goto cancel;
382 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
383 TDBSAM_MINOR_VERSION) != 0) {
384 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
385 goto cancel;
388 if (db->transaction_commit(db) != 0) {
389 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
390 return false;
393 return true;
395 cancel:
396 if (db->transaction_cancel(db) != 0) {
397 smb_panic("tdbsam_convert: transaction_cancel failed");
400 return false;
403 /*********************************************************************
404 Open the tdbsam file based on the absolute path specified.
405 Uses a reference count to allow multiple open calls.
406 *********************************************************************/
408 static bool tdbsam_open( const char *name )
410 int32 version;
411 int32 minor_version;
413 /* check if we are already open */
415 if ( db_sam ) {
416 return true;
419 /* Try to open tdb passwd. Create a new one if necessary */
421 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
422 if (db_sam == NULL) {
423 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
424 "[%s]\n", name));
425 return false;
428 /* Check the version */
429 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
430 if (version == -1) {
431 version = 0; /* Version not found, assume version 0 */
434 /* Get the minor version */
435 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
436 if (minor_version == -1) {
437 minor_version = 0; /* Minor version not found, assume 0 */
440 /* Compare the version */
441 if (version > TDBSAM_VERSION) {
442 /* Version more recent than the latest known */
443 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
444 TALLOC_FREE(db_sam);
445 return false;
448 if ( version < TDBSAM_VERSION ||
449 (version == TDBSAM_VERSION &&
450 minor_version < TDBSAM_MINOR_VERSION) ) {
452 * Ok - we think we're going to have to convert.
453 * Due to the backup process we now must do to
454 * upgrade we have to get a mutex and re-check
455 * the version. Someone else may have upgraded
456 * whilst we were checking.
459 struct named_mutex *mtx = grab_named_mutex(NULL,
460 "tdbsam_upgrade_mutex",
461 600);
463 if (!mtx) {
464 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
465 TALLOC_FREE(db_sam);
466 return false;
469 /* Re-check the version */
470 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
471 if (version == -1) {
472 version = 0; /* Version not found, assume version 0 */
475 /* Re-check the minor version */
476 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
477 if (minor_version == -1) {
478 minor_version = 0; /* Minor version not found, assume 0 */
481 /* Compare the version */
482 if (version > TDBSAM_VERSION) {
483 /* Version more recent than the latest known */
484 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
485 TALLOC_FREE(db_sam);
486 TALLOC_FREE(mtx);
487 return false;
490 if ( version < TDBSAM_VERSION ||
491 (version == TDBSAM_VERSION &&
492 minor_version < TDBSAM_MINOR_VERSION) ) {
494 * Note that minor versions we read that are greater
495 * than the current minor version we have hard coded
496 * are assumed to be compatible if they have the same
497 * major version. That allows previous versions of the
498 * passdb code that don't know about minor versions to
499 * still use this database. JRA.
502 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
503 "version %d.%d.\n",
504 version,
505 minor_version,
506 TDBSAM_VERSION,
507 TDBSAM_MINOR_VERSION));
509 if ( !tdbsam_convert(&db_sam, name, version) ) {
510 DEBUG(0, ("tdbsam_open: Error when trying to convert "
511 "tdbsam [%s]\n",name));
512 TALLOC_FREE(db_sam);
513 TALLOC_FREE(mtx);
514 return false;
517 DEBUG(3, ("TDBSAM converted successfully.\n"));
519 TALLOC_FREE(mtx);
522 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
524 return true;
527 /******************************************************************
528 Lookup a name in the SAM TDB
529 ******************************************************************/
531 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
532 struct samu *user, const char *sname)
534 TDB_DATA data;
535 fstring keystr;
536 fstring name;
538 if ( !user ) {
539 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
540 return NT_STATUS_NO_MEMORY;
543 /* Data is stored in all lower-case */
544 fstrcpy(name, sname);
545 strlower_m(name);
547 /* set search key */
548 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
550 /* open the database */
552 if ( !tdbsam_open( tdbsam_filename ) ) {
553 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
554 return NT_STATUS_ACCESS_DENIED;
557 /* get the record */
559 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
560 if (!data.dptr) {
561 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
562 DEBUGADD(5, (" Key: %s\n", keystr));
563 return NT_STATUS_NO_SUCH_USER;
566 /* unpack the buffer */
568 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
569 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
570 SAFE_FREE(data.dptr);
571 return NT_STATUS_NO_MEMORY;
574 /* success */
576 TALLOC_FREE(data.dptr);
578 return NT_STATUS_OK;
581 /***************************************************************************
582 Search by rid
583 **************************************************************************/
585 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
586 struct samu *user, uint32 rid)
588 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
589 TDB_DATA data;
590 fstring keystr;
591 fstring name;
593 if ( !user ) {
594 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
595 return nt_status;
598 /* set search key */
600 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
602 /* open the database */
604 if ( !tdbsam_open( tdbsam_filename ) ) {
605 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
606 return NT_STATUS_ACCESS_DENIED;
609 /* get the record */
611 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
612 if (!data.dptr) {
613 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
614 return NT_STATUS_UNSUCCESSFUL;
617 fstrcpy(name, (const char *)data.dptr);
618 TALLOC_FREE(data.dptr);
620 return tdbsam_getsampwnam (my_methods, user, name);
623 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
624 struct samu * user, const struct dom_sid *sid)
626 uint32 rid;
628 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
629 return NT_STATUS_UNSUCCESSFUL;
631 return tdbsam_getsampwrid(my_methods, user, rid);
634 static bool tdb_delete_samacct_only( struct samu *sam_pass )
636 fstring keystr;
637 fstring name;
638 NTSTATUS status;
640 fstrcpy(name, pdb_get_username(sam_pass));
641 strlower_m(name);
643 /* set the search key */
645 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
647 /* it's outaa here! 8^) */
648 if ( !tdbsam_open( tdbsam_filename ) ) {
649 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
650 tdbsam_filename));
651 return false;
654 status = dbwrap_delete_bystring(db_sam, keystr);
655 if (!NT_STATUS_IS_OK(status)) {
656 DEBUG(5, ("Error deleting entry from tdb passwd "
657 "database: %s!\n", nt_errstr(status)));
658 return false;
661 return true;
664 /***************************************************************************
665 Delete a struct samu records for the username and RID key
666 ****************************************************************************/
668 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
669 struct samu *sam_pass)
671 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
672 fstring keystr;
673 uint32 rid;
674 fstring name;
676 /* open the database */
678 if ( !tdbsam_open( tdbsam_filename ) ) {
679 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
680 tdbsam_filename));
681 return NT_STATUS_ACCESS_DENIED;
684 fstrcpy(name, pdb_get_username(sam_pass));
685 strlower_m(name);
687 /* set the search key */
689 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
691 rid = pdb_get_user_rid(sam_pass);
693 /* it's outaa here! 8^) */
695 if (db_sam->transaction_start(db_sam) != 0) {
696 DEBUG(0, ("Could not start transaction\n"));
697 return NT_STATUS_UNSUCCESSFUL;
700 nt_status = dbwrap_delete_bystring(db_sam, keystr);
701 if (!NT_STATUS_IS_OK(nt_status)) {
702 DEBUG(5, ("Error deleting entry from tdb passwd "
703 "database: %s!\n", nt_errstr(nt_status)));
704 goto cancel;
707 /* set the search key */
709 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
711 /* it's outaa here! 8^) */
713 nt_status = dbwrap_delete_bystring(db_sam, keystr);
714 if (!NT_STATUS_IS_OK(nt_status)) {
715 DEBUG(5, ("Error deleting entry from tdb rid "
716 "database: %s!\n", nt_errstr(nt_status)));
717 goto cancel;
720 if (db_sam->transaction_commit(db_sam) != 0) {
721 DEBUG(0, ("Could not commit transaction\n"));
722 return NT_STATUS_INTERNAL_DB_CORRUPTION;
725 return NT_STATUS_OK;
727 cancel:
728 if (db_sam->transaction_cancel(db_sam) != 0) {
729 smb_panic("transaction_cancel failed");
732 return nt_status;
736 /***************************************************************************
737 Update the TDB SAM account record only
738 Assumes that the tdbsam is already open
739 ****************************************************************************/
740 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
742 TDB_DATA data;
743 uint8 *buf = NULL;
744 fstring keystr;
745 fstring name;
746 bool ret = false;
747 NTSTATUS status;
749 /* copy the struct samu struct into a BYTE buffer for storage */
751 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
752 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
753 goto done;
755 data.dptr = buf;
757 fstrcpy(name, pdb_get_username(newpwd));
758 strlower_m(name);
760 DEBUG(5, ("Storing %saccount %s with RID %d\n",
761 flag == TDB_INSERT ? "(new) " : "", name,
762 pdb_get_user_rid(newpwd)));
764 /* setup the USER index key */
765 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
767 /* add the account */
769 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
770 if (!NT_STATUS_IS_OK(status)) {
771 DEBUG(0, ("Unable to modify passwd TDB: %s!",
772 nt_errstr(status)));
773 goto done;
776 ret = true;
778 done:
779 /* cleanup */
780 SAFE_FREE(buf);
781 return ret;
784 /***************************************************************************
785 Update the TDB SAM RID record only
786 Assumes that the tdbsam is already open
787 ****************************************************************************/
788 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
790 TDB_DATA data;
791 fstring keystr;
792 fstring name;
793 NTSTATUS status;
795 fstrcpy(name, pdb_get_username(newpwd));
796 strlower_m(name);
798 /* setup RID data */
799 data = string_term_tdb_data(name);
801 /* setup the RID index key */
802 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
803 pdb_get_user_rid(newpwd));
805 /* add the reference */
806 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
807 if (!NT_STATUS_IS_OK(status)) {
808 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
809 nt_errstr(status)));
810 return false;
813 return true;
817 /***************************************************************************
818 Update the TDB SAM
819 ****************************************************************************/
821 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
822 int flag)
824 uint32_t oldrid;
825 uint32_t newrid;
827 if (!(newrid = pdb_get_user_rid(newpwd))) {
828 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
829 pdb_get_username(newpwd)));
830 return False;
833 oldrid = newrid;
835 /* open the database */
837 if ( !tdbsam_open( tdbsam_filename ) ) {
838 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
839 return False;
842 if (db_sam->transaction_start(db_sam) != 0) {
843 DEBUG(0, ("Could not start transaction\n"));
844 return false;
847 /* If we are updating, we may be changing this users RID. Retrieve the old RID
848 so we can check. */
850 if (flag == TDB_MODIFY) {
851 struct samu *account = samu_new(talloc_tos());
852 if (account == NULL) {
853 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
854 goto cancel;
856 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
857 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
858 pdb_get_username(newpwd)));
859 TALLOC_FREE(account);
860 goto cancel;
862 if (!(oldrid = pdb_get_user_rid(account))) {
863 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
864 TALLOC_FREE(account);
865 goto cancel;
867 TALLOC_FREE(account);
870 /* Update the new samu entry. */
871 if (!tdb_update_samacct_only(newpwd, flag)) {
872 goto cancel;
875 /* Now take care of the case where the RID changed. We need
876 * to delete the old RID key and add the new. */
878 if (flag == TDB_MODIFY && newrid != oldrid) {
879 fstring keystr;
881 /* Delete old RID key */
882 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
883 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
884 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
885 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
886 goto cancel;
888 /* Insert new RID key */
889 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
890 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
891 goto cancel;
893 } else {
894 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
895 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
896 if (!tdb_update_ridrec_only(newpwd, flag)) {
897 goto cancel;
901 if (db_sam->transaction_commit(db_sam) != 0) {
902 DEBUG(0, ("Could not commit transaction\n"));
903 return false;
906 return true;
908 cancel:
909 if (db_sam->transaction_cancel(db_sam) != 0) {
910 smb_panic("transaction_cancel failed");
912 return false;
915 /***************************************************************************
916 Modifies an existing struct samu
917 ****************************************************************************/
919 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
921 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
922 return NT_STATUS_UNSUCCESSFUL;
924 return NT_STATUS_OK;
927 /***************************************************************************
928 Adds an existing struct samu
929 ****************************************************************************/
931 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
933 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
934 return NT_STATUS_UNSUCCESSFUL;
936 return NT_STATUS_OK;
939 /***************************************************************************
940 Renames a struct samu
941 - check for the posix user/rename user script
942 - Add and lock the new user record
943 - rename the posix user
944 - rewrite the rid->username record
945 - delete the old user
946 - unlock the new user record
947 ***************************************************************************/
948 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
949 struct samu *old_acct,
950 const char *newname)
952 struct samu *new_acct = NULL;
953 char *rename_script = NULL;
954 int rename_ret;
955 fstring oldname_lower;
956 fstring newname_lower;
958 /* can't do anything without an external script */
960 if ( !(new_acct = samu_new( talloc_tos() )) ) {
961 return NT_STATUS_NO_MEMORY;
964 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
965 if (!rename_script) {
966 TALLOC_FREE(new_acct);
967 return NT_STATUS_NO_MEMORY;
969 if (!*rename_script) {
970 TALLOC_FREE(new_acct);
971 return NT_STATUS_ACCESS_DENIED;
974 if ( !pdb_copy_sam_account(new_acct, old_acct)
975 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
977 TALLOC_FREE(new_acct);
978 return NT_STATUS_NO_MEMORY;
981 /* open the database */
982 if ( !tdbsam_open( tdbsam_filename ) ) {
983 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
984 tdbsam_filename));
985 TALLOC_FREE(new_acct);
986 return NT_STATUS_ACCESS_DENIED;
989 if (db_sam->transaction_start(db_sam) != 0) {
990 DEBUG(0, ("Could not start transaction\n"));
991 TALLOC_FREE(new_acct);
992 return NT_STATUS_ACCESS_DENIED;
996 /* add the new account and lock it */
997 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
998 goto cancel;
1001 /* Rename the posix user. Follow the semantics of _samr_create_user()
1002 so that we lower case the posix name but preserve the case in passdb */
1004 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1005 strlower_m( oldname_lower );
1007 fstrcpy( newname_lower, newname );
1008 strlower_m( newname_lower );
1010 rename_script = talloc_string_sub2(new_acct,
1011 rename_script,
1012 "%unew",
1013 newname_lower,
1014 true,
1015 false,
1016 true);
1017 if (!rename_script) {
1018 goto cancel;
1020 rename_script = talloc_string_sub2(new_acct,
1021 rename_script,
1022 "%uold",
1023 oldname_lower,
1024 true,
1025 false,
1026 true);
1027 if (!rename_script) {
1028 goto cancel;
1030 rename_ret = smbrun(rename_script, NULL);
1032 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1033 rename_script, rename_ret));
1035 if (rename_ret != 0) {
1036 goto cancel;
1039 smb_nscd_flush_user_cache();
1041 /* rewrite the rid->username record */
1043 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1044 goto cancel;
1047 tdb_delete_samacct_only( old_acct );
1049 if (db_sam->transaction_commit(db_sam) != 0) {
1051 * Ok, we're screwed. We've changed the posix account, but
1052 * could not adapt passdb.tdb. Shall we change the posix
1053 * account back?
1055 DEBUG(0, ("transaction_commit failed\n"));
1056 TALLOC_FREE(new_acct);
1057 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1060 TALLOC_FREE(new_acct );
1061 return NT_STATUS_OK;
1063 cancel:
1064 if (db_sam->transaction_cancel(db_sam) != 0) {
1065 smb_panic("transaction_cancel failed");
1068 TALLOC_FREE(new_acct);
1070 return NT_STATUS_ACCESS_DENIED;
1073 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1075 return PDB_CAP_STORE_RIDS;
1078 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1080 uint32 rid;
1081 NTSTATUS status;
1083 rid = BASE_RID; /* Default if not set */
1085 if (!tdbsam_open(tdbsam_filename)) {
1086 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1087 tdbsam_filename));
1088 return false;
1091 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1092 &rid, 1);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1095 NEXT_RID_STRING, nt_errstr(status)));
1096 return false;
1099 *prid = rid;
1101 return true;
1104 struct tdbsam_search_state {
1105 struct pdb_methods *methods;
1106 uint32_t acct_flags;
1108 uint32_t *rids;
1109 uint32_t num_rids;
1110 ssize_t array_size;
1111 uint32_t current;
1114 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1116 struct tdbsam_search_state *state = talloc_get_type_abort(
1117 private_data, struct tdbsam_search_state);
1118 size_t prefixlen = strlen(RIDPREFIX);
1119 uint32 rid;
1121 if ((rec->key.dsize < prefixlen)
1122 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1123 return 0;
1126 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1128 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1129 &state->array_size);
1131 return 0;
1134 static void tdbsam_search_end(struct pdb_search *search)
1136 struct tdbsam_search_state *state = talloc_get_type_abort(
1137 search->private_data, struct tdbsam_search_state);
1138 TALLOC_FREE(state);
1141 static bool tdbsam_search_next_entry(struct pdb_search *search,
1142 struct samr_displayentry *entry)
1144 struct tdbsam_search_state *state = talloc_get_type_abort(
1145 search->private_data, struct tdbsam_search_state);
1146 struct samu *user = NULL;
1147 NTSTATUS status;
1148 uint32_t rid;
1150 again:
1151 TALLOC_FREE(user);
1152 user = samu_new(talloc_tos());
1153 if (user == NULL) {
1154 DEBUG(0, ("samu_new failed\n"));
1155 return false;
1158 if (state->current == state->num_rids) {
1159 return false;
1162 rid = state->rids[state->current++];
1164 status = tdbsam_getsampwrid(state->methods, user, rid);
1166 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1168 * Someone has deleted that user since we listed the RIDs
1170 goto again;
1173 if (!NT_STATUS_IS_OK(status)) {
1174 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1175 nt_errstr(status)));
1176 TALLOC_FREE(user);
1177 return false;
1180 if ((state->acct_flags != 0) &&
1181 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1182 goto again;
1185 entry->acct_flags = pdb_get_acct_ctrl(user);
1186 entry->rid = rid;
1187 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1188 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1189 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1191 TALLOC_FREE(user);
1193 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1194 || (entry->description == NULL)) {
1195 DEBUG(0, ("talloc_strdup failed\n"));
1196 return false;
1199 return true;
1202 static bool tdbsam_search_users(struct pdb_methods *methods,
1203 struct pdb_search *search,
1204 uint32 acct_flags)
1206 struct tdbsam_search_state *state;
1208 if (!tdbsam_open(tdbsam_filename)) {
1209 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1210 tdbsam_filename));
1211 return false;
1214 state = talloc_zero(search, struct tdbsam_search_state);
1215 if (state == NULL) {
1216 DEBUG(0, ("talloc failed\n"));
1217 return false;
1219 state->acct_flags = acct_flags;
1220 state->methods = methods;
1222 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1224 search->private_data = state;
1225 search->next_entry = tdbsam_search_next_entry;
1226 search->search_end = tdbsam_search_end;
1228 return true;
1231 /*********************************************************************
1232 Initialize the tdb sam backend. Setup the dispath table of methods,
1233 open the tdb, etc...
1234 *********************************************************************/
1236 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1238 NTSTATUS nt_status;
1239 char *tdbfile = NULL;
1240 const char *pfile = location;
1242 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1243 return nt_status;
1246 (*pdb_method)->name = "tdbsam";
1248 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1249 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1250 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1251 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1252 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1253 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1254 (*pdb_method)->search_users = tdbsam_search_users;
1256 (*pdb_method)->capabilities = tdbsam_capabilities;
1257 (*pdb_method)->new_rid = tdbsam_new_rid;
1259 /* save the path for later */
1261 if (!location) {
1262 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1263 PASSDB_FILE_NAME) < 0) {
1264 return NT_STATUS_NO_MEMORY;
1266 pfile = tdbfile;
1268 tdbsam_filename = SMB_STRDUP(pfile);
1269 if (!tdbsam_filename) {
1270 return NT_STATUS_NO_MEMORY;
1272 SAFE_FREE(tdbfile);
1274 /* no private data */
1276 (*pdb_method)->private_data = NULL;
1277 (*pdb_method)->free_private_data = NULL;
1279 return NT_STATUS_OK;
1282 NTSTATUS pdb_tdbsam_init(void)
1284 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);