Typos in wintest
[Samba.git] / source3 / passdb / pdb_tdb.c
blobda61e48a99d3bb48f86423b32db1d3ffa75ac93a
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"
27 #include "../libcli/security/security.h"
29 #if 0 /* when made a module use this */
31 static int tdbsam_debug_level = DBGC_ALL;
32 #undef DBGC_CLASS
33 #define DBGC_CLASS tdbsam_debug_level
35 #else
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_PASSDB
40 #endif
42 #define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
43 #define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
44 #define TDBSAM_VERSION_STRING "INFO/version"
45 #define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
46 #define PASSDB_FILE_NAME "passdb.tdb"
47 #define USERPREFIX "USER_"
48 #define USERPREFIX_LEN 5
49 #define RIDPREFIX "RID_"
50 #define PRIVPREFIX "PRIV_"
51 #define NEXT_RID_STRING "NEXT_RID"
53 /* GLOBAL TDB SAM CONTEXT */
55 static struct db_context *db_sam;
56 static char *tdbsam_filename;
58 struct tdbsam_convert_state {
59 int32_t from;
60 bool success;
63 static int tdbsam_convert_one(struct db_record *rec, void *priv)
65 struct tdbsam_convert_state *state =
66 (struct tdbsam_convert_state *)priv;
67 struct samu *user;
68 TDB_DATA data;
69 NTSTATUS status;
70 bool ret;
72 if (rec->key.dsize < USERPREFIX_LEN) {
73 return 0;
75 if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
76 return 0;
79 user = samu_new(talloc_tos());
80 if (user == NULL) {
81 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
82 state->success = false;
83 return -1;
86 DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
87 "(version:%d)\n", rec->key.dptr, state->from));
89 switch (state->from) {
90 case 0:
91 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
92 (uint8 *)rec->value.dptr,
93 rec->value.dsize);
94 break;
95 case 1:
96 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
97 (uint8 *)rec->value.dptr,
98 rec->value.dsize);
99 break;
100 case 2:
101 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
102 (uint8 *)rec->value.dptr,
103 rec->value.dsize);
104 break;
105 case 3:
106 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
107 (uint8 *)rec->value.dptr,
108 rec->value.dsize);
109 break;
110 case 4:
111 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
112 (uint8 *)rec->value.dptr,
113 rec->value.dsize);
114 break;
115 default:
116 /* unknown tdbsam version */
117 ret = False;
119 if (!ret) {
120 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
121 "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
122 state->from));
123 TALLOC_FREE(user);
124 state->success = false;
125 return -1;
128 data.dsize = init_buffer_from_samu(&data.dptr, user, false);
129 TALLOC_FREE(user);
131 if (data.dsize == -1) {
132 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
133 "the new format\n"));
134 state->success = false;
135 return -1;
138 status = rec->store(rec, data, TDB_MODIFY);
139 if (!NT_STATUS_IS_OK(status)) {
140 DEBUG(0, ("Could not store the new record: %s\n",
141 nt_errstr(status)));
142 state->success = false;
143 return -1;
146 return 0;
149 /**********************************************************************
150 Struct and function to backup an old record.
151 *********************************************************************/
153 struct tdbsam_backup_state {
154 struct db_context *new_db;
155 bool success;
158 static int backup_copy_fn(struct db_record *orig_rec, void *state)
160 struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
161 struct db_record *new_rec;
162 NTSTATUS status;
164 new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
165 if (new_rec == NULL) {
166 bs->success = false;
167 return 1;
170 status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
172 TALLOC_FREE(new_rec);
174 if (!NT_STATUS_IS_OK(status)) {
175 bs->success = false;
176 return 1;
178 return 0;
181 /**********************************************************************
182 Make a backup of an old passdb and replace the new one with it. We
183 have to do this as between 3.0.x and 3.2.x the hash function changed
184 by mistake (used unsigned char * instead of char *). This means the
185 previous simple update code will fail due to not being able to find
186 existing records to replace in the tdbsam_convert_one() function. JRA.
187 *********************************************************************/
189 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
191 TALLOC_CTX *frame = talloc_stackframe();
192 const char *tmp_fname = NULL;
193 struct db_context *tmp_db = NULL;
194 struct db_context *orig_db = *pp_db;
195 struct tdbsam_backup_state bs;
196 int ret;
198 tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
199 if (!tmp_fname) {
200 TALLOC_FREE(frame);
201 return false;
204 unlink(tmp_fname);
206 /* Remember to open this on the NULL context. We need
207 * it to stay around after we return from here. */
209 tmp_db = db_open(NULL, tmp_fname, 0,
210 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
211 if (tmp_db == NULL) {
212 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
213 "[%s]\n", tmp_fname));
214 TALLOC_FREE(frame);
215 return false;
218 if (orig_db->transaction_start(orig_db) != 0) {
219 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
220 unlink(tmp_fname);
221 TALLOC_FREE(tmp_db);
222 TALLOC_FREE(frame);
223 return false;
225 if (tmp_db->transaction_start(tmp_db) != 0) {
226 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
227 orig_db->transaction_cancel(orig_db);
228 unlink(tmp_fname);
229 TALLOC_FREE(tmp_db);
230 TALLOC_FREE(frame);
231 return false;
234 bs.new_db = tmp_db;
235 bs.success = true;
237 ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
238 if (ret < 0) {
239 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
240 goto cancel;
243 if (!bs.success) {
244 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
245 goto cancel;
248 if (orig_db->transaction_commit(orig_db) != 0) {
249 smb_panic("tdbsam_convert_backup: orig commit failed\n");
251 if (tmp_db->transaction_commit(tmp_db) != 0) {
252 smb_panic("tdbsam_convert_backup: orig commit failed\n");
255 /* be sure to close the DBs _before_ renaming the file */
257 TALLOC_FREE(orig_db);
258 TALLOC_FREE(tmp_db);
260 /* This is safe from other users as we know we're
261 * under a mutex here. */
263 if (rename(tmp_fname, dbname) == -1) {
264 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
265 tmp_fname,
266 dbname,
267 strerror(errno)));
268 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
271 TALLOC_FREE(frame);
273 /* re-open the converted TDB */
275 orig_db = db_open(NULL, dbname, 0,
276 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
277 if (orig_db == NULL) {
278 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
279 "converted passdb TDB [%s]\n", dbname));
280 return false;
283 DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
284 dbname ));
286 /* Replace the global db pointer. */
287 *pp_db = orig_db;
288 return true;
290 cancel:
292 if (orig_db->transaction_cancel(orig_db) != 0) {
293 smb_panic("tdbsam_convert: transaction_cancel failed");
296 if (tmp_db->transaction_cancel(tmp_db) != 0) {
297 smb_panic("tdbsam_convert: transaction_cancel failed");
300 unlink(tmp_fname);
301 TALLOC_FREE(tmp_db);
302 TALLOC_FREE(frame);
303 return false;
306 static bool tdbsam_upgrade_next_rid(struct db_context *db)
308 TDB_CONTEXT *tdb;
309 uint32 rid;
310 bool ok = false;
312 ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
313 if (ok) {
314 return true;
317 tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
318 TDB_DEFAULT, O_RDONLY, 0644);
320 if (tdb) {
321 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
322 if (!ok) {
323 rid = BASE_RID;
325 tdb_close(tdb);
326 } else {
327 rid = BASE_RID;
330 if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
331 return false;
334 return true;
337 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
339 struct tdbsam_convert_state state;
340 struct db_context *db = NULL;
341 int ret;
343 /* We only need the update backup for local db's. */
344 if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
345 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
346 return false;
349 db = *pp_db;
350 state.from = from;
351 state.success = true;
353 if (db->transaction_start(db) != 0) {
354 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
355 return false;
358 if (!tdbsam_upgrade_next_rid(db)) {
359 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
360 goto cancel;
363 ret = db->traverse(db, tdbsam_convert_one, &state);
364 if (ret < 0) {
365 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
366 goto cancel;
369 if (!state.success) {
370 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
371 goto cancel;
374 if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
375 TDBSAM_VERSION) != 0) {
376 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
377 goto cancel;
380 if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
381 TDBSAM_MINOR_VERSION) != 0) {
382 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
383 goto cancel;
386 if (db->transaction_commit(db) != 0) {
387 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
388 return false;
391 return true;
393 cancel:
394 if (db->transaction_cancel(db) != 0) {
395 smb_panic("tdbsam_convert: transaction_cancel failed");
398 return false;
401 /*********************************************************************
402 Open the tdbsam file based on the absolute path specified.
403 Uses a reference count to allow multiple open calls.
404 *********************************************************************/
406 static bool tdbsam_open( const char *name )
408 int32 version;
409 int32 minor_version;
411 /* check if we are already open */
413 if ( db_sam ) {
414 return true;
417 /* Try to open tdb passwd. Create a new one if necessary */
419 db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
420 if (db_sam == NULL) {
421 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
422 "[%s]\n", name));
423 return false;
426 /* Check the version */
427 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
428 if (version == -1) {
429 version = 0; /* Version not found, assume version 0 */
432 /* Get the minor version */
433 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
434 if (minor_version == -1) {
435 minor_version = 0; /* Minor version not found, assume 0 */
438 /* Compare the version */
439 if (version > TDBSAM_VERSION) {
440 /* Version more recent than the latest known */
441 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
442 TALLOC_FREE(db_sam);
443 return false;
446 if ( version < TDBSAM_VERSION ||
447 (version == TDBSAM_VERSION &&
448 minor_version < TDBSAM_MINOR_VERSION) ) {
450 * Ok - we think we're going to have to convert.
451 * Due to the backup process we now must do to
452 * upgrade we have to get a mutex and re-check
453 * the version. Someone else may have upgraded
454 * whilst we were checking.
457 struct named_mutex *mtx = grab_named_mutex(NULL,
458 "tdbsam_upgrade_mutex",
459 600);
461 if (!mtx) {
462 DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
463 TALLOC_FREE(db_sam);
464 return false;
467 /* Re-check the version */
468 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
469 if (version == -1) {
470 version = 0; /* Version not found, assume version 0 */
473 /* Re-check the minor version */
474 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
475 if (minor_version == -1) {
476 minor_version = 0; /* Minor version not found, assume 0 */
479 /* Compare the version */
480 if (version > TDBSAM_VERSION) {
481 /* Version more recent than the latest known */
482 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
483 TALLOC_FREE(db_sam);
484 TALLOC_FREE(mtx);
485 return false;
488 if ( version < TDBSAM_VERSION ||
489 (version == TDBSAM_VERSION &&
490 minor_version < TDBSAM_MINOR_VERSION) ) {
492 * Note that minor versions we read that are greater
493 * than the current minor version we have hard coded
494 * are assumed to be compatible if they have the same
495 * major version. That allows previous versions of the
496 * passdb code that don't know about minor versions to
497 * still use this database. JRA.
500 DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
501 "version %d.%d.\n",
502 version,
503 minor_version,
504 TDBSAM_VERSION,
505 TDBSAM_MINOR_VERSION));
507 if ( !tdbsam_convert(&db_sam, name, version) ) {
508 DEBUG(0, ("tdbsam_open: Error when trying to convert "
509 "tdbsam [%s]\n",name));
510 TALLOC_FREE(db_sam);
511 TALLOC_FREE(mtx);
512 return false;
515 DEBUG(3, ("TDBSAM converted successfully.\n"));
517 TALLOC_FREE(mtx);
520 DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
522 return true;
525 /******************************************************************
526 Lookup a name in the SAM TDB
527 ******************************************************************/
529 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
530 struct samu *user, const char *sname)
532 TDB_DATA data;
533 fstring keystr;
534 fstring name;
536 if ( !user ) {
537 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
538 return NT_STATUS_NO_MEMORY;
541 /* Data is stored in all lower-case */
542 fstrcpy(name, sname);
543 strlower_m(name);
545 /* set search key */
546 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
548 /* open the database */
550 if ( !tdbsam_open( tdbsam_filename ) ) {
551 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
552 return NT_STATUS_ACCESS_DENIED;
555 /* get the record */
557 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
558 if (!data.dptr) {
559 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
560 DEBUGADD(5, (" Key: %s\n", keystr));
561 return NT_STATUS_NO_SUCH_USER;
564 /* unpack the buffer */
566 if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
567 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
568 SAFE_FREE(data.dptr);
569 return NT_STATUS_NO_MEMORY;
572 /* success */
574 TALLOC_FREE(data.dptr);
576 return NT_STATUS_OK;
579 /***************************************************************************
580 Search by rid
581 **************************************************************************/
583 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
584 struct samu *user, uint32 rid)
586 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
587 TDB_DATA data;
588 fstring keystr;
589 fstring name;
591 if ( !user ) {
592 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
593 return nt_status;
596 /* set search key */
598 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
600 /* open the database */
602 if ( !tdbsam_open( tdbsam_filename ) ) {
603 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
604 return NT_STATUS_ACCESS_DENIED;
607 /* get the record */
609 data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
610 if (!data.dptr) {
611 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
612 return NT_STATUS_UNSUCCESSFUL;
615 fstrcpy(name, (const char *)data.dptr);
616 TALLOC_FREE(data.dptr);
618 return tdbsam_getsampwnam (my_methods, user, name);
621 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
622 struct samu * user, const struct dom_sid *sid)
624 uint32 rid;
626 if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
627 return NT_STATUS_UNSUCCESSFUL;
629 return tdbsam_getsampwrid(my_methods, user, rid);
632 static bool tdb_delete_samacct_only( struct samu *sam_pass )
634 fstring keystr;
635 fstring name;
636 NTSTATUS status;
638 fstrcpy(name, pdb_get_username(sam_pass));
639 strlower_m(name);
641 /* set the search key */
643 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
645 /* it's outaa here! 8^) */
646 if ( !tdbsam_open( tdbsam_filename ) ) {
647 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
648 tdbsam_filename));
649 return false;
652 status = dbwrap_delete_bystring(db_sam, keystr);
653 if (!NT_STATUS_IS_OK(status)) {
654 DEBUG(5, ("Error deleting entry from tdb passwd "
655 "database: %s!\n", nt_errstr(status)));
656 return false;
659 return true;
662 /***************************************************************************
663 Delete a struct samu records for the username and RID key
664 ****************************************************************************/
666 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
667 struct samu *sam_pass)
669 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
670 fstring keystr;
671 uint32 rid;
672 fstring name;
674 /* open the database */
676 if ( !tdbsam_open( tdbsam_filename ) ) {
677 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
678 tdbsam_filename));
679 return NT_STATUS_ACCESS_DENIED;
682 fstrcpy(name, pdb_get_username(sam_pass));
683 strlower_m(name);
685 /* set the search key */
687 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
689 rid = pdb_get_user_rid(sam_pass);
691 /* it's outaa here! 8^) */
693 if (db_sam->transaction_start(db_sam) != 0) {
694 DEBUG(0, ("Could not start transaction\n"));
695 return NT_STATUS_UNSUCCESSFUL;
698 nt_status = dbwrap_delete_bystring(db_sam, keystr);
699 if (!NT_STATUS_IS_OK(nt_status)) {
700 DEBUG(5, ("Error deleting entry from tdb passwd "
701 "database: %s!\n", nt_errstr(nt_status)));
702 goto cancel;
705 /* set the search key */
707 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
709 /* it's outaa here! 8^) */
711 nt_status = dbwrap_delete_bystring(db_sam, keystr);
712 if (!NT_STATUS_IS_OK(nt_status)) {
713 DEBUG(5, ("Error deleting entry from tdb rid "
714 "database: %s!\n", nt_errstr(nt_status)));
715 goto cancel;
718 if (db_sam->transaction_commit(db_sam) != 0) {
719 DEBUG(0, ("Could not commit transaction\n"));
720 return NT_STATUS_INTERNAL_DB_CORRUPTION;
723 return NT_STATUS_OK;
725 cancel:
726 if (db_sam->transaction_cancel(db_sam) != 0) {
727 smb_panic("transaction_cancel failed");
730 return nt_status;
734 /***************************************************************************
735 Update the TDB SAM account record only
736 Assumes that the tdbsam is already open
737 ****************************************************************************/
738 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
740 TDB_DATA data;
741 uint8 *buf = NULL;
742 fstring keystr;
743 fstring name;
744 bool ret = false;
745 NTSTATUS status;
747 /* copy the struct samu struct into a BYTE buffer for storage */
749 if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
750 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
751 goto done;
753 data.dptr = buf;
755 fstrcpy(name, pdb_get_username(newpwd));
756 strlower_m(name);
758 DEBUG(5, ("Storing %saccount %s with RID %d\n",
759 flag == TDB_INSERT ? "(new) " : "", name,
760 pdb_get_user_rid(newpwd)));
762 /* setup the USER index key */
763 slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
765 /* add the account */
767 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
768 if (!NT_STATUS_IS_OK(status)) {
769 DEBUG(0, ("Unable to modify passwd TDB: %s!",
770 nt_errstr(status)));
771 goto done;
774 ret = true;
776 done:
777 /* cleanup */
778 SAFE_FREE(buf);
779 return ret;
782 /***************************************************************************
783 Update the TDB SAM RID record only
784 Assumes that the tdbsam is already open
785 ****************************************************************************/
786 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
788 TDB_DATA data;
789 fstring keystr;
790 fstring name;
791 NTSTATUS status;
793 fstrcpy(name, pdb_get_username(newpwd));
794 strlower_m(name);
796 /* setup RID data */
797 data = string_term_tdb_data(name);
799 /* setup the RID index key */
800 slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
801 pdb_get_user_rid(newpwd));
803 /* add the reference */
804 status = dbwrap_store_bystring(db_sam, keystr, data, flag);
805 if (!NT_STATUS_IS_OK(status)) {
806 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
807 nt_errstr(status)));
808 return false;
811 return true;
815 /***************************************************************************
816 Update the TDB SAM
817 ****************************************************************************/
819 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
820 int flag)
822 uint32_t oldrid;
823 uint32_t newrid;
825 if (!(newrid = pdb_get_user_rid(newpwd))) {
826 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
827 pdb_get_username(newpwd)));
828 return False;
831 oldrid = newrid;
833 /* open the database */
835 if ( !tdbsam_open( tdbsam_filename ) ) {
836 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
837 return False;
840 if (db_sam->transaction_start(db_sam) != 0) {
841 DEBUG(0, ("Could not start transaction\n"));
842 return false;
845 /* If we are updating, we may be changing this users RID. Retrieve the old RID
846 so we can check. */
848 if (flag == TDB_MODIFY) {
849 struct samu *account = samu_new(talloc_tos());
850 if (account == NULL) {
851 DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
852 goto cancel;
854 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
855 DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
856 pdb_get_username(newpwd)));
857 TALLOC_FREE(account);
858 goto cancel;
860 if (!(oldrid = pdb_get_user_rid(account))) {
861 DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
862 TALLOC_FREE(account);
863 goto cancel;
865 TALLOC_FREE(account);
868 /* Update the new samu entry. */
869 if (!tdb_update_samacct_only(newpwd, flag)) {
870 goto cancel;
873 /* Now take care of the case where the RID changed. We need
874 * to delete the old RID key and add the new. */
876 if (flag == TDB_MODIFY && newrid != oldrid) {
877 fstring keystr;
879 /* Delete old RID key */
880 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
881 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
882 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
883 DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
884 goto cancel;
886 /* Insert new RID key */
887 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
888 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
889 goto cancel;
891 } else {
892 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
893 flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
894 if (!tdb_update_ridrec_only(newpwd, flag)) {
895 goto cancel;
899 if (db_sam->transaction_commit(db_sam) != 0) {
900 DEBUG(0, ("Could not commit transaction\n"));
901 return false;
904 return true;
906 cancel:
907 if (db_sam->transaction_cancel(db_sam) != 0) {
908 smb_panic("transaction_cancel failed");
910 return false;
913 /***************************************************************************
914 Modifies an existing struct samu
915 ****************************************************************************/
917 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
919 if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
920 return NT_STATUS_UNSUCCESSFUL;
922 return NT_STATUS_OK;
925 /***************************************************************************
926 Adds an existing struct samu
927 ****************************************************************************/
929 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
931 if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
932 return NT_STATUS_UNSUCCESSFUL;
934 return NT_STATUS_OK;
937 /***************************************************************************
938 Renames a struct samu
939 - check for the posix user/rename user script
940 - Add and lock the new user record
941 - rename the posix user
942 - rewrite the rid->username record
943 - delete the old user
944 - unlock the new user record
945 ***************************************************************************/
946 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
947 struct samu *old_acct,
948 const char *newname)
950 struct samu *new_acct = NULL;
951 char *rename_script = NULL;
952 int rename_ret;
953 fstring oldname_lower;
954 fstring newname_lower;
956 /* can't do anything without an external script */
958 if ( !(new_acct = samu_new( talloc_tos() )) ) {
959 return NT_STATUS_NO_MEMORY;
962 rename_script = talloc_strdup(new_acct, lp_renameuser_script());
963 if (!rename_script) {
964 TALLOC_FREE(new_acct);
965 return NT_STATUS_NO_MEMORY;
967 if (!*rename_script) {
968 TALLOC_FREE(new_acct);
969 return NT_STATUS_ACCESS_DENIED;
972 if ( !pdb_copy_sam_account(new_acct, old_acct)
973 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
975 TALLOC_FREE(new_acct);
976 return NT_STATUS_NO_MEMORY;
979 /* open the database */
980 if ( !tdbsam_open( tdbsam_filename ) ) {
981 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
982 tdbsam_filename));
983 TALLOC_FREE(new_acct);
984 return NT_STATUS_ACCESS_DENIED;
987 if (db_sam->transaction_start(db_sam) != 0) {
988 DEBUG(0, ("Could not start transaction\n"));
989 TALLOC_FREE(new_acct);
990 return NT_STATUS_ACCESS_DENIED;
994 /* add the new account and lock it */
995 if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
996 goto cancel;
999 /* Rename the posix user. Follow the semantics of _samr_create_user()
1000 so that we lower case the posix name but preserve the case in passdb */
1002 fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1003 strlower_m( oldname_lower );
1005 fstrcpy( newname_lower, newname );
1006 strlower_m( newname_lower );
1008 rename_script = talloc_string_sub2(new_acct,
1009 rename_script,
1010 "%unew",
1011 newname_lower,
1012 true,
1013 false,
1014 true);
1015 if (!rename_script) {
1016 goto cancel;
1018 rename_script = talloc_string_sub2(new_acct,
1019 rename_script,
1020 "%uold",
1021 oldname_lower,
1022 true,
1023 false,
1024 true);
1025 if (!rename_script) {
1026 goto cancel;
1028 rename_ret = smbrun(rename_script, NULL);
1030 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1031 rename_script, rename_ret));
1033 if (rename_ret != 0) {
1034 goto cancel;
1037 smb_nscd_flush_user_cache();
1039 /* rewrite the rid->username record */
1041 if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1042 goto cancel;
1045 tdb_delete_samacct_only( old_acct );
1047 if (db_sam->transaction_commit(db_sam) != 0) {
1049 * Ok, we're screwed. We've changed the posix account, but
1050 * could not adapt passdb.tdb. Shall we change the posix
1051 * account back?
1053 DEBUG(0, ("transaction_commit failed\n"));
1054 TALLOC_FREE(new_acct);
1055 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1058 TALLOC_FREE(new_acct );
1059 return NT_STATUS_OK;
1061 cancel:
1062 if (db_sam->transaction_cancel(db_sam) != 0) {
1063 smb_panic("transaction_cancel failed");
1066 TALLOC_FREE(new_acct);
1068 return NT_STATUS_ACCESS_DENIED;
1071 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1073 return PDB_CAP_STORE_RIDS;
1076 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1078 uint32 rid;
1079 NTSTATUS status;
1081 rid = BASE_RID; /* Default if not set */
1083 if (!tdbsam_open(tdbsam_filename)) {
1084 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1085 tdbsam_filename));
1086 return false;
1089 status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1090 &rid, 1);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1093 NEXT_RID_STRING, nt_errstr(status)));
1094 return false;
1097 *prid = rid;
1099 return true;
1102 struct tdbsam_search_state {
1103 struct pdb_methods *methods;
1104 uint32_t acct_flags;
1106 uint32_t *rids;
1107 uint32_t num_rids;
1108 ssize_t array_size;
1109 uint32_t current;
1112 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1114 struct tdbsam_search_state *state = talloc_get_type_abort(
1115 private_data, struct tdbsam_search_state);
1116 size_t prefixlen = strlen(RIDPREFIX);
1117 uint32 rid;
1119 if ((rec->key.dsize < prefixlen)
1120 || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1121 return 0;
1124 rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1126 ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1127 &state->array_size);
1129 return 0;
1132 static void tdbsam_search_end(struct pdb_search *search)
1134 struct tdbsam_search_state *state = talloc_get_type_abort(
1135 search->private_data, struct tdbsam_search_state);
1136 TALLOC_FREE(state);
1139 static bool tdbsam_search_next_entry(struct pdb_search *search,
1140 struct samr_displayentry *entry)
1142 struct tdbsam_search_state *state = talloc_get_type_abort(
1143 search->private_data, struct tdbsam_search_state);
1144 struct samu *user = NULL;
1145 NTSTATUS status;
1146 uint32_t rid;
1148 again:
1149 TALLOC_FREE(user);
1150 user = samu_new(talloc_tos());
1151 if (user == NULL) {
1152 DEBUG(0, ("samu_new failed\n"));
1153 return false;
1156 if (state->current == state->num_rids) {
1157 return false;
1160 rid = state->rids[state->current++];
1162 status = tdbsam_getsampwrid(state->methods, user, rid);
1164 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1166 * Someone has deleted that user since we listed the RIDs
1168 goto again;
1171 if (!NT_STATUS_IS_OK(status)) {
1172 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1173 nt_errstr(status)));
1174 TALLOC_FREE(user);
1175 return false;
1178 if ((state->acct_flags != 0) &&
1179 ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1180 goto again;
1183 entry->acct_flags = pdb_get_acct_ctrl(user);
1184 entry->rid = rid;
1185 entry->account_name = talloc_strdup(search, pdb_get_username(user));
1186 entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1187 entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1189 TALLOC_FREE(user);
1191 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1192 || (entry->description == NULL)) {
1193 DEBUG(0, ("talloc_strdup failed\n"));
1194 return false;
1197 return true;
1200 static bool tdbsam_search_users(struct pdb_methods *methods,
1201 struct pdb_search *search,
1202 uint32 acct_flags)
1204 struct tdbsam_search_state *state;
1206 if (!tdbsam_open(tdbsam_filename)) {
1207 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1208 tdbsam_filename));
1209 return false;
1212 state = talloc_zero(search, struct tdbsam_search_state);
1213 if (state == NULL) {
1214 DEBUG(0, ("talloc failed\n"));
1215 return false;
1217 state->acct_flags = acct_flags;
1218 state->methods = methods;
1220 db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1222 search->private_data = state;
1223 search->next_entry = tdbsam_search_next_entry;
1224 search->search_end = tdbsam_search_end;
1226 return true;
1229 /*********************************************************************
1230 Initialize the tdb sam backend. Setup the dispath table of methods,
1231 open the tdb, etc...
1232 *********************************************************************/
1234 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1236 NTSTATUS nt_status;
1237 char *tdbfile = NULL;
1238 const char *pfile = location;
1240 if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1241 return nt_status;
1244 (*pdb_method)->name = "tdbsam";
1246 (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1247 (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1248 (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1249 (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1250 (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1251 (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1252 (*pdb_method)->search_users = tdbsam_search_users;
1254 (*pdb_method)->capabilities = tdbsam_capabilities;
1255 (*pdb_method)->new_rid = tdbsam_new_rid;
1257 /* save the path for later */
1259 if (!location) {
1260 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1261 PASSDB_FILE_NAME) < 0) {
1262 return NT_STATUS_NO_MEMORY;
1264 pfile = tdbfile;
1266 tdbsam_filename = SMB_STRDUP(pfile);
1267 if (!tdbsam_filename) {
1268 return NT_STATUS_NO_MEMORY;
1270 SAFE_FREE(tdbfile);
1272 /* no private data */
1274 (*pdb_method)->private_data = NULL;
1275 (*pdb_method)->free_private_data = NULL;
1277 return NT_STATUS_OK;
1280 NTSTATUS pdb_tdbsam_init(void)
1282 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);