LCOV - code coverage report
Current view: top level - source3/passdb - pdb_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 340 645 52.7 %
Date: 2024-04-21 15:09:00 Functions: 24 26 92.3 %

          Line data    Source code
       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
      10             :  *
      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.
      15             :  *
      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.
      20             :  *
      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/>.
      23             :  */
      24             : 
      25             : #include "includes.h"
      26             : #include "system/filesys.h"
      27             : #include "passdb.h"
      28             : #include "dbwrap/dbwrap.h"
      29             : #include "dbwrap/dbwrap_open.h"
      30             : #include "../libcli/security/security.h"
      31             : #include "util_tdb.h"
      32             : #include "passdb/pdb_tdb.h"
      33             : #include "lib/util/smb_strtox.h"
      34             : #include "lib/util/string_wrappers.h"
      35             : 
      36             : #if 0 /* when made a module use this */
      37             : 
      38             : static int tdbsam_debug_level = DBGC_ALL;
      39             : #undef DBGC_CLASS
      40             : #define DBGC_CLASS tdbsam_debug_level
      41             : 
      42             : #else
      43             : 
      44             : #undef DBGC_CLASS
      45             : #define DBGC_CLASS DBGC_PASSDB
      46             : 
      47             : #endif
      48             : 
      49             : #define TDBSAM_VERSION  4       /* Most recent TDBSAM version */
      50             : #define TDBSAM_MINOR_VERSION    0       /* Most recent TDBSAM minor version */
      51             : #define TDBSAM_VERSION_STRING   "INFO/version"
      52             : #define TDBSAM_MINOR_VERSION_STRING     "INFO/minor_version"
      53             : #define PASSDB_FILE_NAME        "passdb.tdb"
      54             : #define USERPREFIX              "USER_"
      55             : #define USERPREFIX_LEN          5
      56             : #define RIDPREFIX               "RID_"
      57             : #define PRIVPREFIX              "PRIV_"
      58             : #define NEXT_RID_STRING         "NEXT_RID"
      59             : 
      60             : /* GLOBAL TDB SAM CONTEXT */
      61             : 
      62             : static struct db_context *db_sam;
      63             : static char *tdbsam_filename;
      64             : static bool map_builtin;
      65             : 
      66             : struct tdbsam_convert_state {
      67             :         int32_t from;
      68             :         bool success;
      69             : };
      70             : 
      71          71 : static int tdbsam_convert_one(struct db_record *rec, void *priv)
      72             : {
      73          71 :         struct tdbsam_convert_state *state =
      74             :                 (struct tdbsam_convert_state *)priv;
      75          16 :         struct samu *user;
      76          16 :         TDB_DATA data;
      77          16 :         NTSTATUS status;
      78          16 :         bool ret;
      79          16 :         TDB_DATA key;
      80          16 :         TDB_DATA value;
      81             : 
      82          71 :         key = dbwrap_record_get_key(rec);
      83             : 
      84          71 :         if (key.dsize < USERPREFIX_LEN) {
      85           0 :                 return 0;
      86             :         }
      87          71 :         if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
      88          55 :                 return 0;
      89             :         }
      90             : 
      91           6 :         user = samu_new(talloc_tos());
      92           6 :         if (user == NULL) {
      93           0 :                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
      94           0 :                 state->success = false;
      95           0 :                 return -1;
      96             :         }
      97             : 
      98           6 :         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
      99             :                   "(version:%d)\n", (char *)key.dptr, state->from));
     100             : 
     101           6 :         value = dbwrap_record_get_value(rec);
     102             : 
     103           6 :         switch (state->from) {
     104           0 :         case 0:
     105           0 :                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
     106           0 :                                             (uint8_t *)value.dptr,
     107           0 :                                             value.dsize);
     108           0 :                 break;
     109           0 :         case 1:
     110           0 :                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
     111           0 :                                             (uint8_t *)value.dptr,
     112           0 :                                             value.dsize);
     113           0 :                 break;
     114           6 :         case 2:
     115           6 :                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
     116           0 :                                             (uint8_t *)value.dptr,
     117           0 :                                             value.dsize);
     118           6 :                 break;
     119           0 :         case 3:
     120           0 :                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
     121           0 :                                             (uint8_t *)value.dptr,
     122           0 :                                             value.dsize);
     123           0 :                 break;
     124           0 :         case 4:
     125           0 :                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
     126           0 :                                             (uint8_t *)value.dptr,
     127           0 :                                             value.dsize);
     128           0 :                 break;
     129           0 :         default:
     130             :                 /* unknown tdbsam version */
     131           0 :                 ret = False;
     132             :         }
     133           6 :         if (!ret) {
     134           0 :                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
     135             :                          "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
     136             :                          state->from));
     137           0 :                 TALLOC_FREE(user);
     138           0 :                 state->success = false;
     139           0 :                 return -1;
     140             :         }
     141             : 
     142           6 :         data.dsize = init_buffer_from_samu(&data.dptr, user, false);
     143           6 :         TALLOC_FREE(user);
     144             : 
     145           6 :         if (data.dsize == -1) {
     146           0 :                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
     147             :                          "the new format\n"));
     148           0 :                 state->success = false;
     149           0 :                 return -1;
     150             :         }
     151             : 
     152           6 :         status = dbwrap_record_store(rec, data, TDB_MODIFY);
     153           6 :         if (!NT_STATUS_IS_OK(status)) {
     154           0 :                 DEBUG(0, ("Could not store the new record: %s\n",
     155             :                           nt_errstr(status)));
     156           0 :                 state->success = false;
     157           0 :                 return -1;
     158             :         }
     159             : 
     160           0 :         return 0;
     161             : }
     162             : 
     163             : /**********************************************************************
     164             :  Struct and function to backup an old record.
     165             :  *********************************************************************/
     166             : 
     167             : struct tdbsam_backup_state {
     168             :         struct db_context *new_db;
     169             :         bool success;
     170             : };
     171             : 
     172          14 : static int backup_copy_fn(struct db_record *orig_rec, void *state)
     173             : {
     174          14 :         struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
     175          14 :         struct db_record *new_rec;
     176          14 :         NTSTATUS status;
     177          14 :         TDB_DATA key;
     178          14 :         TDB_DATA value;
     179             : 
     180          14 :         key = dbwrap_record_get_key(orig_rec);
     181             : 
     182          14 :         new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
     183          14 :         if (new_rec == NULL) {
     184           0 :                 bs->success = false;
     185           0 :                 return 1;
     186             :         }
     187             : 
     188          14 :         value = dbwrap_record_get_value(orig_rec);
     189             : 
     190          14 :         status = dbwrap_record_store(new_rec, value, TDB_INSERT);
     191             : 
     192          14 :         TALLOC_FREE(new_rec);
     193             : 
     194          14 :         if (!NT_STATUS_IS_OK(status)) {
     195           0 :                 bs->success = false;
     196           0 :                 return 1;
     197             :         }
     198           0 :         return 0;
     199             : }
     200             : 
     201             : /**********************************************************************
     202             :  Make a backup of an old passdb and replace the new one with it. We
     203             :  have to do this as between 3.0.x and 3.2.x the hash function changed
     204             :  by mistake (used unsigned char * instead of char *). This means the
     205             :  previous simple update code will fail due to not being able to find
     206             :  existing records to replace in the tdbsam_convert_one() function. JRA.
     207             :  *********************************************************************/
     208             : 
     209          57 : static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
     210             : {
     211          57 :         TALLOC_CTX *frame = talloc_stackframe();
     212          57 :         const char *tmp_fname = NULL;
     213          57 :         struct db_context *tmp_db = NULL;
     214          57 :         struct db_context *orig_db = *pp_db;
     215           2 :         struct tdbsam_backup_state bs;
     216           2 :         NTSTATUS status;
     217             : 
     218          57 :         tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
     219          57 :         if (!tmp_fname) {
     220           0 :                 TALLOC_FREE(frame);
     221           0 :                 return false;
     222             :         }
     223             : 
     224          57 :         unlink(tmp_fname);
     225             : 
     226             :         /* Remember to open this on the NULL context. We need
     227             :          * it to stay around after we return from here. */
     228             : 
     229          57 :         tmp_db = db_open(NULL, tmp_fname, 0,
     230             :                          TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
     231             :                          DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
     232          57 :         if (tmp_db == NULL) {
     233           0 :                 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
     234             :                           "[%s]\n", tmp_fname));
     235           0 :                 TALLOC_FREE(frame);
     236           0 :                 return false;
     237             :         }
     238             : 
     239          57 :         if (dbwrap_transaction_start(orig_db) != 0) {
     240           0 :                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
     241           0 :                 unlink(tmp_fname);
     242           0 :                 TALLOC_FREE(tmp_db);
     243           0 :                 TALLOC_FREE(frame);
     244           0 :                 return false;
     245             :         }
     246          57 :         if (dbwrap_transaction_start(tmp_db) != 0) {
     247           0 :                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
     248           0 :                 dbwrap_transaction_cancel(orig_db);
     249           0 :                 unlink(tmp_fname);
     250           0 :                 TALLOC_FREE(tmp_db);
     251           0 :                 TALLOC_FREE(frame);
     252           0 :                 return false;
     253             :         }
     254             : 
     255          57 :         bs.new_db = tmp_db;
     256          57 :         bs.success = true;
     257             : 
     258          57 :         status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
     259          57 :         if (!NT_STATUS_IS_OK(status)) {
     260           0 :                 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
     261           0 :                 goto cancel;
     262             :         }
     263             : 
     264          57 :         if (!bs.success) {
     265           0 :                 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
     266           0 :                 goto cancel;
     267             :         }
     268             : 
     269          57 :         if (dbwrap_transaction_commit(orig_db) != 0) {
     270           0 :                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
     271             :         }
     272          57 :         if (dbwrap_transaction_commit(tmp_db) != 0) {
     273           0 :                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
     274             :         }
     275             : 
     276             :         /* be sure to close the DBs _before_ renaming the file */
     277             : 
     278          57 :         TALLOC_FREE(orig_db);
     279          57 :         TALLOC_FREE(tmp_db);
     280             : 
     281             :         /* This is safe from other users as we know we're
     282             :          * under a mutex here. */
     283             : 
     284          57 :         if (rename(tmp_fname, dbname) == -1) {
     285           0 :                 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
     286             :                         tmp_fname,
     287             :                         dbname,
     288             :                         strerror(errno)));
     289           0 :                 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
     290             :         }
     291             : 
     292          57 :         TALLOC_FREE(frame);
     293             : 
     294             :         /* re-open the converted TDB */
     295             : 
     296          57 :         orig_db = db_open(NULL, dbname, 0,
     297             :                           TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
     298             :                           DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
     299          57 :         if (orig_db == NULL) {
     300           0 :                 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
     301             :                           "converted passdb TDB [%s]\n", dbname));
     302           0 :                 return false;
     303             :         }
     304             : 
     305          57 :         DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
     306             :                 dbname ));
     307             : 
     308             :         /* Replace the global db pointer. */
     309          57 :         *pp_db = orig_db;
     310          57 :         return true;
     311             : 
     312           0 :   cancel:
     313             : 
     314           0 :         if (dbwrap_transaction_cancel(orig_db) != 0) {
     315           0 :                 smb_panic("tdbsam_convert: transaction_cancel failed");
     316             :         }
     317             : 
     318           0 :         if (dbwrap_transaction_cancel(tmp_db) != 0) {
     319           0 :                 smb_panic("tdbsam_convert: transaction_cancel failed");
     320             :         }
     321             : 
     322           0 :         unlink(tmp_fname);
     323           0 :         TALLOC_FREE(tmp_db);
     324           0 :         TALLOC_FREE(frame);
     325           0 :         return false;
     326             : }
     327             : 
     328          57 : static bool tdbsam_upgrade_next_rid(struct db_context *db)
     329             : {
     330           2 :         TDB_CONTEXT *tdb;
     331           2 :         uint32_t rid;
     332          57 :         bool ok = false;
     333           2 :         NTSTATUS status;
     334           2 :         char *db_path;
     335             : 
     336          57 :         status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
     337          57 :         if (NT_STATUS_IS_OK(status)) {
     338           0 :                 return true;
     339             :         }
     340             : 
     341          57 :         db_path = state_path(talloc_tos(), "winbindd_idmap.tdb");
     342          57 :         if (db_path == NULL) {
     343           0 :                 return false;
     344             :         }
     345             : 
     346          57 :         tdb = tdb_open_log(db_path, 0,
     347             :                            TDB_DEFAULT, O_RDONLY, 0644);
     348          57 :         TALLOC_FREE(db_path);
     349          57 :         if (tdb) {
     350           4 :                 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
     351           4 :                 if (!ok) {
     352           4 :                         rid = BASE_RID;
     353             :                 }
     354           4 :                 tdb_close(tdb);
     355             :         } else {
     356          53 :                 rid = BASE_RID;
     357             :         }
     358             : 
     359          57 :         status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
     360          57 :         if (!NT_STATUS_IS_OK(status)) {
     361           0 :                 return false;
     362             :         }
     363             : 
     364          55 :         return true;
     365             : }
     366             : 
     367          57 : static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32_t from)
     368             : {
     369           2 :         struct tdbsam_convert_state state;
     370          57 :         struct db_context *db = NULL;
     371           2 :         NTSTATUS status;
     372             : 
     373             :         /* We only need the update backup for local db's. */
     374          57 :         if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
     375           0 :                 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
     376           0 :                 return false;
     377             :         }
     378             : 
     379          57 :         db = *pp_db;
     380          57 :         state.from = from;
     381          57 :         state.success = true;
     382             : 
     383          57 :         if (dbwrap_transaction_start(db) != 0) {
     384           0 :                 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
     385           0 :                 return false;
     386             :         }
     387             : 
     388          57 :         if (!tdbsam_upgrade_next_rid(db)) {
     389           0 :                 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
     390           0 :                 goto cancel;
     391             :         }
     392             : 
     393          57 :         status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
     394          57 :         if (!NT_STATUS_IS_OK(status)) {
     395           0 :                 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
     396           0 :                 goto cancel;
     397             :         }
     398             : 
     399          57 :         if (!state.success) {
     400           0 :                 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
     401           0 :                 goto cancel;
     402             :         }
     403             : 
     404          57 :         status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
     405             :                                              TDBSAM_VERSION);
     406          57 :         if (!NT_STATUS_IS_OK(status)) {
     407           0 :                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
     408             :                           "%s\n", nt_errstr(status)));
     409           0 :                 goto cancel;
     410             :         }
     411             : 
     412          57 :         status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
     413             :                                              TDBSAM_MINOR_VERSION);
     414          57 :         if (!NT_STATUS_IS_OK(status)) {
     415           0 :                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
     416             :                           "version: %s\n", nt_errstr(status)));
     417           0 :                 goto cancel;
     418             :         }
     419             : 
     420          57 :         if (dbwrap_transaction_commit(db) != 0) {
     421           0 :                 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
     422           0 :                 return false;
     423             :         }
     424             : 
     425          55 :         return true;
     426             : 
     427           0 :  cancel:
     428           0 :         if (dbwrap_transaction_cancel(db) != 0) {
     429           0 :                 smb_panic("tdbsam_convert: transaction_cancel failed");
     430             :         }
     431             : 
     432           0 :         return false;
     433             : }
     434             : 
     435             : /*********************************************************************
     436             :  Open the tdbsam file based on the absolute path specified.
     437             :  Uses a reference count to allow multiple open calls.
     438             : *********************************************************************/
     439             : 
     440       67577 : static bool tdbsam_open( const char *name )
     441             : {
     442          74 :         int32_t version;
     443          74 :         int32_t minor_version;
     444          74 :         NTSTATUS status;
     445             : 
     446             :         /* check if we are already open */
     447             : 
     448       67577 :         if ( db_sam ) {
     449       66510 :                 return true;
     450             :         }
     451             : 
     452             :         /* Try to open tdb passwd.  Create a new one if necessary */
     453             : 
     454         997 :         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
     455             :                          DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
     456         997 :         if (db_sam == NULL) {
     457           0 :                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
     458             :                           "[%s]\n", name));
     459           0 :                 return false;
     460             :         }
     461             : 
     462             :         /* Check the version */
     463         997 :         status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
     464             :                                              &version);
     465         997 :         if (!NT_STATUS_IS_OK(status)) {
     466          55 :                 version = 0;    /* Version not found, assume version 0 */
     467             :         }
     468             : 
     469             :         /* Get the minor version */
     470         997 :         status = dbwrap_fetch_int32_bystring(
     471             :                 db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
     472         997 :         if (!NT_STATUS_IS_OK(status)) {
     473          57 :                 minor_version = 0; /* Minor version not found, assume 0 */
     474             :         }
     475             : 
     476             :         /* Compare the version */
     477         997 :         if (version > TDBSAM_VERSION) {
     478             :                 /* Version more recent than the latest known */
     479           0 :                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
     480           0 :                 TALLOC_FREE(db_sam);
     481           0 :                 return false;
     482             :         }
     483             : 
     484         997 :         if ( version < TDBSAM_VERSION ||
     485         940 :                         (version == TDBSAM_VERSION &&
     486         940 :                          minor_version < TDBSAM_MINOR_VERSION) ) {
     487             :                 /*
     488             :                  * Ok - we think we're going to have to convert.
     489             :                  * Due to the backup process we now must do to
     490             :                  * upgrade we have to get a mutex and re-check
     491             :                  * the version. Someone else may have upgraded
     492             :                  * whilst we were checking.
     493             :                  */
     494             : 
     495          57 :                 struct named_mutex *mtx = grab_named_mutex(NULL,
     496             :                                                 "tdbsam_upgrade_mutex",
     497             :                                                 600);
     498             : 
     499          57 :                 if (!mtx) {
     500           0 :                         DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
     501           0 :                         TALLOC_FREE(db_sam);
     502           0 :                         return false;
     503             :                 }
     504             : 
     505             :                 /* Re-check the version */
     506          57 :                 status = dbwrap_fetch_int32_bystring(
     507             :                         db_sam, TDBSAM_VERSION_STRING, &version);
     508          57 :                 if (!NT_STATUS_IS_OK(status)) {
     509          55 :                         version = 0;    /* Version not found, assume version 0 */
     510             :                 }
     511             : 
     512             :                 /* Re-check the minor version */
     513          57 :                 status = dbwrap_fetch_int32_bystring(
     514             :                         db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
     515          57 :                 if (!NT_STATUS_IS_OK(status)) {
     516          57 :                         minor_version = 0; /* Minor version not found, assume 0 */
     517             :                 }
     518             : 
     519             :                 /* Compare the version */
     520          57 :                 if (version > TDBSAM_VERSION) {
     521             :                         /* Version more recent than the latest known */
     522           0 :                         DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
     523           0 :                         TALLOC_FREE(db_sam);
     524           0 :                         TALLOC_FREE(mtx);
     525           0 :                         return false;
     526             :                 }
     527             : 
     528          57 :                 if ( version < TDBSAM_VERSION ||
     529           0 :                                 (version == TDBSAM_VERSION &&
     530           0 :                                  minor_version < TDBSAM_MINOR_VERSION) ) {
     531             :                         /*
     532             :                          * Note that minor versions we read that are greater
     533             :                          * than the current minor version we have hard coded
     534             :                          * are assumed to be compatible if they have the same
     535             :                          * major version. That allows previous versions of the
     536             :                          * passdb code that don't know about minor versions to
     537             :                          * still use this database. JRA.
     538             :                          */
     539             : 
     540          57 :                         DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
     541             :                                   "version %d.%d.\n",
     542             :                                         version,
     543             :                                         minor_version,
     544             :                                         TDBSAM_VERSION,
     545             :                                         TDBSAM_MINOR_VERSION));
     546             : 
     547          57 :                         if ( !tdbsam_convert(&db_sam, name, version) ) {
     548           0 :                                 DEBUG(0, ("tdbsam_open: Error when trying to convert "
     549             :                                           "tdbsam [%s]\n",name));
     550           0 :                                 TALLOC_FREE(db_sam);
     551           0 :                                 TALLOC_FREE(mtx);
     552           0 :                                 return false;
     553             :                         }
     554             : 
     555          57 :                         DEBUG(3, ("TDBSAM converted successfully.\n"));
     556             :                 }
     557          57 :                 TALLOC_FREE(mtx);
     558             :         }
     559             : 
     560         997 :         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
     561             : 
     562         993 :         return true;
     563             : }
     564             : 
     565             : /******************************************************************
     566             :  Lookup a name in the SAM TDB
     567             : ******************************************************************/
     568             : 
     569       55425 : static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
     570             :                                     struct samu *user, const char *sname)
     571             : {
     572          37 :         TDB_DATA        data;
     573          37 :         fstring         keystr;
     574          37 :         fstring         name;
     575          37 :         NTSTATUS status;
     576             : 
     577       55425 :         if ( !user ) {
     578           0 :                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
     579           0 :                 return NT_STATUS_NO_MEMORY;
     580             :         }
     581             : 
     582             :         /* Data is stored in all lower-case */
     583       55425 :         fstrcpy(name, sname);
     584       55425 :         if (!strlower_m(name)) {
     585           0 :                 return NT_STATUS_INVALID_PARAMETER;
     586             :         }
     587             : 
     588             :         /* set search key */
     589       55425 :         fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
     590             : 
     591             :         /* open the database */
     592             : 
     593       55425 :         if ( !tdbsam_open( tdbsam_filename ) ) {
     594           0 :                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
     595           0 :                 return NT_STATUS_ACCESS_DENIED;
     596             :         }
     597             : 
     598             :         /* get the record */
     599             : 
     600       55425 :         status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
     601       55425 :         if (!NT_STATUS_IS_OK(status)) {
     602        4499 :                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
     603        4499 :                 DEBUGADD(5, (" Key: %s\n", keystr));
     604        4499 :                 return NT_STATUS_NO_SUCH_USER;
     605             :         }
     606             : 
     607       50926 :         if (data.dsize == 0) {
     608           0 :                 DEBUG(5, ("%s: Got 0-sized record for key %s\n", __func__,
     609             :                           keystr));
     610           0 :                 return NT_STATUS_NO_SUCH_USER;
     611             :         }
     612             : 
     613             :         /* unpack the buffer */
     614             : 
     615       50926 :         if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
     616           0 :                 DBG_ERR("Bad struct samu entry returned from TDB!\n");
     617           0 :                 TALLOC_FREE(data.dptr);
     618           0 :                 return NT_STATUS_NO_MEMORY;
     619             :         }
     620             : 
     621             :         /* success */
     622             : 
     623       50926 :         TALLOC_FREE(data.dptr);
     624             : 
     625       50926 :         return NT_STATUS_OK;
     626             : }
     627             : 
     628             : /***************************************************************************
     629             :  Search by rid
     630             :  **************************************************************************/
     631             : 
     632        9567 : static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
     633             :                                     struct samu *user, uint32_t rid)
     634             : {
     635        9567 :         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
     636          30 :         TDB_DATA                data;
     637          30 :         fstring                 keystr;
     638          30 :         fstring                 name;
     639             : 
     640        9567 :         if ( !user ) {
     641           0 :                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
     642           0 :                 return nt_status;
     643             :         }
     644             : 
     645             :         /* set search key */
     646             : 
     647        9567 :         fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
     648             : 
     649             :         /* open the database */
     650             : 
     651        9567 :         if ( !tdbsam_open( tdbsam_filename ) ) {
     652           0 :                 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
     653           0 :                 return NT_STATUS_ACCESS_DENIED;
     654             :         }
     655             : 
     656             :         /* get the record */
     657             : 
     658        9567 :         nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
     659        9567 :         if (!NT_STATUS_IS_OK(nt_status)) {
     660        2361 :                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
     661        2361 :                 return nt_status;
     662             :         }
     663             : 
     664        7206 :         fstrcpy(name, (const char *)data.dptr);
     665        7206 :         TALLOC_FREE(data.dptr);
     666             : 
     667        7206 :         return tdbsam_getsampwnam (my_methods, user, name);
     668             : }
     669             : 
     670        8854 : static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
     671             :                                    struct samu * user, const struct dom_sid *sid)
     672             : {
     673           9 :         uint32_t rid;
     674             : 
     675        8854 :         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
     676           0 :                 return NT_STATUS_UNSUCCESSFUL;
     677             : 
     678        8854 :         return tdbsam_getsampwrid(my_methods, user, rid);
     679             : }
     680             : 
     681           0 : static bool tdb_delete_samacct_only( struct samu *sam_pass )
     682             : {
     683           0 :         fstring         keystr;
     684           0 :         fstring         name;
     685           0 :         NTSTATUS status;
     686             : 
     687           0 :         fstrcpy(name, pdb_get_username(sam_pass));
     688           0 :         if (!strlower_m(name)) {
     689           0 :                 return false;
     690             :         }
     691             : 
     692             :         /* set the search key */
     693             : 
     694           0 :         fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
     695             : 
     696             :         /* it's outaa here!  8^) */
     697           0 :         if ( !tdbsam_open( tdbsam_filename ) ) {
     698           0 :                 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
     699             :                          tdbsam_filename));
     700           0 :                 return false;
     701             :         }
     702             : 
     703           0 :         status = dbwrap_delete_bystring(db_sam, keystr);
     704           0 :         if (!NT_STATUS_IS_OK(status)) {
     705           0 :                 DEBUG(5, ("Error deleting entry from tdb passwd "
     706             :                           "database: %s!\n", nt_errstr(status)));
     707           0 :                 return false;
     708             :         }
     709             : 
     710           0 :         return true;
     711             : }
     712             : 
     713             : /***************************************************************************
     714             :  Delete a struct samu records for the username and RID key
     715             : ****************************************************************************/
     716             : 
     717          60 : static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
     718             :                                           struct samu *sam_pass)
     719             : {
     720           0 :         NTSTATUS        nt_status;
     721           0 :         fstring         keystr;
     722           0 :         uint32_t        rid;
     723           0 :         fstring         name;
     724             : 
     725             :         /* open the database */
     726             : 
     727          60 :         if ( !tdbsam_open( tdbsam_filename ) ) {
     728           0 :                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
     729             :                          tdbsam_filename));
     730           0 :                 return NT_STATUS_ACCESS_DENIED;
     731             :         }
     732             : 
     733          60 :         fstrcpy(name, pdb_get_username(sam_pass));
     734          60 :         if (!strlower_m(name)) {
     735           0 :                 return NT_STATUS_INVALID_PARAMETER;
     736             :         }
     737             : 
     738             :         /* set the search key */
     739             : 
     740          60 :         fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
     741             : 
     742          60 :         rid = pdb_get_user_rid(sam_pass);
     743             : 
     744             :         /* it's outaa here!  8^) */
     745             : 
     746          60 :         if (dbwrap_transaction_start(db_sam) != 0) {
     747           0 :                 DEBUG(0, ("Could not start transaction\n"));
     748           0 :                 return NT_STATUS_UNSUCCESSFUL;
     749             :         }
     750             : 
     751          60 :         nt_status = dbwrap_delete_bystring(db_sam, keystr);
     752          60 :         if (!NT_STATUS_IS_OK(nt_status)) {
     753           0 :                 DEBUG(5, ("Error deleting entry from tdb passwd "
     754             :                           "database: %s!\n", nt_errstr(nt_status)));
     755           0 :                 goto cancel;
     756             :         }
     757             : 
     758             :         /* set the search key */
     759             : 
     760          60 :         fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
     761             : 
     762             :         /* it's outaa here!  8^) */
     763             : 
     764          60 :         nt_status = dbwrap_delete_bystring(db_sam, keystr);
     765          60 :         if (!NT_STATUS_IS_OK(nt_status)) {
     766           0 :                 DEBUG(5, ("Error deleting entry from tdb rid "
     767             :                           "database: %s!\n", nt_errstr(nt_status)));
     768           0 :                 goto cancel;
     769             :         }
     770             : 
     771          60 :         if (dbwrap_transaction_commit(db_sam) != 0) {
     772           0 :                 DEBUG(0, ("Could not commit transaction\n"));
     773           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     774             :         }
     775             : 
     776          60 :         return NT_STATUS_OK;
     777             : 
     778           0 :  cancel:
     779           0 :         if (dbwrap_transaction_cancel(db_sam) != 0) {
     780           0 :                 smb_panic("transaction_cancel failed");
     781             :         }
     782             : 
     783           0 :         return nt_status;
     784             : }
     785             : 
     786             : 
     787             : /***************************************************************************
     788             :  Update the TDB SAM account record only
     789             :  Assumes that the tdbsam is already open
     790             : ****************************************************************************/
     791        1354 : static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
     792             : {
     793           0 :         TDB_DATA        data;
     794        1354 :         uint8_t         *buf = NULL;
     795           0 :         fstring         keystr;
     796           0 :         fstring         name;
     797        1354 :         bool            ret = false;
     798           0 :         NTSTATUS status;
     799             : 
     800             :         /* copy the struct samu struct into a BYTE buffer for storage */
     801             : 
     802        1354 :         if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
     803           0 :                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
     804           0 :                 goto done;
     805             :         }
     806        1354 :         data.dptr = buf;
     807             : 
     808        1354 :         fstrcpy(name, pdb_get_username(newpwd));
     809        1354 :         if (!strlower_m(name)) {
     810           0 :                 goto done;
     811             :         }
     812             : 
     813        1354 :         DEBUG(5, ("Storing %saccount %s with RID %d\n",
     814             :                   flag == TDB_INSERT ? "(new) " : "", name,
     815             :                   pdb_get_user_rid(newpwd)));
     816             : 
     817             :         /* setup the USER index key */
     818        1354 :         fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
     819             : 
     820             :         /* add the account */
     821             : 
     822        1354 :         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
     823        1354 :         if (!NT_STATUS_IS_OK(status)) {
     824           0 :                 DEBUG(0, ("Unable to modify passwd TDB: %s!\n",
     825             :                           nt_errstr(status)));
     826           0 :                 goto done;
     827             :         }
     828             : 
     829        1354 :         ret = true;
     830             : 
     831        1354 : done:
     832             :         /* cleanup */
     833        1354 :         SAFE_FREE(buf);
     834        1354 :         return ret;
     835             : }
     836             : 
     837             : /***************************************************************************
     838             :  Update the TDB SAM RID record only
     839             :  Assumes that the tdbsam is already open
     840             : ****************************************************************************/
     841        1354 : static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
     842             : {
     843           0 :         TDB_DATA        data;
     844           0 :         fstring         keystr;
     845           0 :         fstring         name;
     846           0 :         NTSTATUS status;
     847             : 
     848        1354 :         fstrcpy(name, pdb_get_username(newpwd));
     849        1354 :         if (!strlower_m(name)) {
     850           0 :                 return false;
     851             :         }
     852             : 
     853             :         /* setup RID data */
     854        1354 :         data = string_term_tdb_data(name);
     855             : 
     856             :         /* setup the RID index key */
     857        1354 :         fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
     858             : 
     859             :         /* add the reference */
     860        1354 :         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
     861        1354 :         if (!NT_STATUS_IS_OK(status)) {
     862           0 :                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
     863             :                           nt_errstr(status)));
     864           0 :                 return false;
     865             :         }
     866             : 
     867        1354 :         return true;
     868             : 
     869             : }
     870             : 
     871             : /***************************************************************************
     872             :  Update the TDB SAM
     873             : ****************************************************************************/
     874             : 
     875        1354 : static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
     876             :                            int flag)
     877             : {
     878           0 :         uint32_t oldrid;
     879           0 :         uint32_t newrid;
     880             : 
     881        1354 :         if (!(newrid = pdb_get_user_rid(newpwd))) {
     882           0 :                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
     883             :                          pdb_get_username(newpwd)));
     884           0 :                 return False;
     885             :         }
     886             : 
     887        1354 :         oldrid = newrid;
     888             : 
     889             :         /* open the database */
     890             : 
     891        1354 :         if ( !tdbsam_open( tdbsam_filename ) ) {
     892           0 :                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
     893           0 :                 return False;
     894             :         }
     895             : 
     896        1354 :         if (dbwrap_transaction_start(db_sam) != 0) {
     897           0 :                 DEBUG(0, ("Could not start transaction\n"));
     898           0 :                 return false;
     899             :         }
     900             : 
     901             :         /* If we are updating, we may be changing this users RID. Retrieve the old RID
     902             :            so we can check. */
     903             : 
     904        1354 :         if (flag == TDB_MODIFY) {
     905         800 :                 struct samu *account = samu_new(talloc_tos());
     906         800 :                 if (account == NULL) {
     907           0 :                         DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
     908           0 :                         goto cancel;
     909             :                 }
     910         800 :                 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
     911           0 :                         DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
     912             :                                 pdb_get_username(newpwd)));
     913           0 :                         TALLOC_FREE(account);
     914           0 :                         goto cancel;
     915             :                 }
     916         800 :                 if (!(oldrid = pdb_get_user_rid(account))) {
     917           0 :                         DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
     918           0 :                         TALLOC_FREE(account);
     919           0 :                         goto cancel;
     920             :                 }
     921         800 :                 TALLOC_FREE(account);
     922             :         }
     923             : 
     924             :         /* Update the new samu entry. */
     925        1354 :         if (!tdb_update_samacct_only(newpwd, flag)) {
     926           0 :                 goto cancel;
     927             :         }
     928             : 
     929             :         /* Now take care of the case where the RID changed. We need
     930             :          * to delete the old RID key and add the new. */
     931             : 
     932        1354 :         if (flag == TDB_MODIFY && newrid != oldrid) {
     933           0 :                 fstring keystr;
     934             : 
     935             :                 /* Delete old RID key */
     936           0 :                 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
     937           0 :                 fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, oldrid);
     938           0 :                 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
     939           0 :                         DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
     940           0 :                         goto cancel;
     941             :                 }
     942             :                 /* Insert new RID key */
     943           0 :                 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
     944           0 :                 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
     945           0 :                         goto cancel;
     946             :                 }
     947             :         } else {
     948        1354 :                 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
     949             :                         flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
     950        1354 :                 if (!tdb_update_ridrec_only(newpwd, flag)) {
     951           0 :                         goto cancel;
     952             :                 }
     953             :         }
     954             : 
     955        1354 :         if (dbwrap_transaction_commit(db_sam) != 0) {
     956           0 :                 DEBUG(0, ("Could not commit transaction\n"));
     957           0 :                 return false;
     958             :         }
     959             : 
     960        1354 :         return true;
     961             : 
     962           0 :  cancel:
     963           0 :         if (dbwrap_transaction_cancel(db_sam) != 0) {
     964           0 :                 smb_panic("transaction_cancel failed");
     965             :         }
     966           0 :         return false;
     967             : }
     968             : 
     969             : /***************************************************************************
     970             :  Modifies an existing struct samu
     971             : ****************************************************************************/
     972             : 
     973         800 : static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
     974             : {
     975         800 :         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
     976           0 :                 return NT_STATUS_UNSUCCESSFUL;
     977             : 
     978         800 :         return NT_STATUS_OK;
     979             : }
     980             : 
     981             : /***************************************************************************
     982             :  Adds an existing struct samu
     983             : ****************************************************************************/
     984             : 
     985         554 : static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
     986             : {
     987         554 :         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
     988           0 :                 return NT_STATUS_UNSUCCESSFUL;
     989             : 
     990         554 :         return NT_STATUS_OK;
     991             : }
     992             : 
     993             : /***************************************************************************
     994             :  Renames a struct samu
     995             :  - check for the posix user/rename user script
     996             :  - Add and lock the new user record
     997             :  - rename the posix user
     998             :  - rewrite the rid->username record
     999             :  - delete the old user
    1000             :  - unlock the new user record
    1001             : ***************************************************************************/
    1002           0 : static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
    1003             :                                           struct samu *old_acct,
    1004             :                                           const char *newname)
    1005             : {
    1006           0 :         const struct loadparm_substitution *lp_sub =
    1007           0 :                 loadparm_s3_global_substitution();
    1008           0 :         struct samu      *new_acct = NULL;
    1009           0 :         char *rename_script = NULL;
    1010           0 :         int              rename_ret;
    1011           0 :         fstring          oldname_lower;
    1012           0 :         fstring          newname_lower;
    1013             : 
    1014             :         /* can't do anything without an external script */
    1015             : 
    1016           0 :         if ( !(new_acct = samu_new( talloc_tos() )) ) {
    1017           0 :                 return NT_STATUS_NO_MEMORY;
    1018             :         }
    1019             : 
    1020           0 :         rename_script = lp_rename_user_script(new_acct, lp_sub);
    1021           0 :         if (!rename_script) {
    1022           0 :                 TALLOC_FREE(new_acct);
    1023           0 :                 return NT_STATUS_NO_MEMORY;
    1024             :         }
    1025           0 :         if (!*rename_script) {
    1026           0 :                 TALLOC_FREE(new_acct);
    1027           0 :                 return NT_STATUS_ACCESS_DENIED;
    1028             :         }
    1029             : 
    1030           0 :         if ( !pdb_copy_sam_account(new_acct, old_acct)
    1031           0 :                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
    1032             :         {
    1033           0 :                 TALLOC_FREE(new_acct);
    1034           0 :                 return NT_STATUS_NO_MEMORY;
    1035             :         }
    1036             : 
    1037             :         /* open the database */
    1038           0 :         if ( !tdbsam_open( tdbsam_filename ) ) {
    1039           0 :                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
    1040             :                           tdbsam_filename));
    1041           0 :                 TALLOC_FREE(new_acct);
    1042           0 :                 return NT_STATUS_ACCESS_DENIED;
    1043             :         }
    1044             : 
    1045           0 :         if (dbwrap_transaction_start(db_sam) != 0) {
    1046           0 :                 DEBUG(0, ("Could not start transaction\n"));
    1047           0 :                 TALLOC_FREE(new_acct);
    1048           0 :                 return NT_STATUS_ACCESS_DENIED;
    1049             : 
    1050             :         }
    1051             : 
    1052             :         /* add the new account and lock it */
    1053           0 :         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
    1054           0 :                 goto cancel;
    1055             :         }
    1056             : 
    1057             :         /* Rename the posix user.  Follow the semantics of _samr_create_user()
    1058             :            so that we lower case the posix name but preserve the case in passdb */
    1059             : 
    1060           0 :         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
    1061           0 :         if (!strlower_m( oldname_lower )) {
    1062           0 :                 goto cancel;
    1063             :         }
    1064             : 
    1065           0 :         fstrcpy( newname_lower, newname );
    1066           0 :         if (!strlower_m( newname_lower )) {
    1067           0 :                 goto cancel;
    1068             :         }
    1069             : 
    1070           0 :         rename_script = talloc_string_sub2(new_acct,
    1071             :                                 rename_script,
    1072             :                                 "%unew",
    1073             :                                 newname_lower,
    1074             :                                 true,
    1075             :                                 false,
    1076             :                                 true);
    1077           0 :         if (!rename_script) {
    1078           0 :                 goto cancel;
    1079             :         }
    1080           0 :         rename_script = talloc_string_sub2(new_acct,
    1081             :                                 rename_script,
    1082             :                                 "%uold",
    1083             :                                 oldname_lower,
    1084             :                                 true,
    1085             :                                 false,
    1086             :                                 true);
    1087           0 :         if (!rename_script) {
    1088           0 :                 goto cancel;
    1089             :         }
    1090           0 :         rename_ret = smbrun(rename_script, NULL, NULL);
    1091             : 
    1092           0 :         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
    1093             :                                 rename_script, rename_ret));
    1094             : 
    1095           0 :         if (rename_ret != 0) {
    1096           0 :                 goto cancel;
    1097             :         }
    1098             : 
    1099           0 :         smb_nscd_flush_user_cache();
    1100             : 
    1101             :         /* rewrite the rid->username record */
    1102             : 
    1103           0 :         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
    1104           0 :                 goto cancel;
    1105             :         }
    1106             : 
    1107           0 :         tdb_delete_samacct_only( old_acct );
    1108             : 
    1109           0 :         if (dbwrap_transaction_commit(db_sam) != 0) {
    1110             :                 /*
    1111             :                  * Ok, we're screwed. We've changed the posix account, but
    1112             :                  * could not adapt passdb.tdb. Shall we change the posix
    1113             :                  * account back?
    1114             :                  */
    1115           0 :                 DEBUG(0, ("transaction_commit failed\n"));
    1116           0 :                 TALLOC_FREE(new_acct);
    1117           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1118             :         }
    1119             : 
    1120           0 :         TALLOC_FREE(new_acct );
    1121           0 :         return NT_STATUS_OK;
    1122             : 
    1123           0 :  cancel:
    1124           0 :         if (dbwrap_transaction_cancel(db_sam) != 0) {
    1125           0 :                 smb_panic("transaction_cancel failed");
    1126             :         }
    1127             : 
    1128           0 :         TALLOC_FREE(new_acct);
    1129             : 
    1130           0 :         return NT_STATUS_ACCESS_DENIED;
    1131             : }
    1132             : 
    1133        1679 : static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
    1134             : {
    1135        1679 :         return PDB_CAP_STORE_RIDS;
    1136             : }
    1137             : 
    1138        1156 : static bool tdbsam_new_rid(struct pdb_methods *methods, uint32_t *prid)
    1139             : {
    1140           0 :         uint32_t rid;
    1141           0 :         NTSTATUS status;
    1142             : 
    1143        1156 :         rid = BASE_RID;         /* Default if not set */
    1144             : 
    1145        1156 :         if (!tdbsam_open(tdbsam_filename)) {
    1146           0 :                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
    1147             :                         tdbsam_filename));
    1148           0 :                 return false;
    1149             :         }
    1150             : 
    1151        1156 :         status = dbwrap_trans_change_uint32_atomic_bystring(
    1152             :                 db_sam, NEXT_RID_STRING, &rid, 1);
    1153        1156 :         if (!NT_STATUS_IS_OK(status)) {
    1154           0 :                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
    1155             :                         NEXT_RID_STRING, nt_errstr(status)));
    1156           0 :                 return false;
    1157             :         }
    1158             : 
    1159        1156 :         *prid = rid;
    1160             : 
    1161        1156 :         return true;
    1162             : }
    1163             : 
    1164             : struct tdbsam_search_state {
    1165             :         struct pdb_methods *methods;
    1166             :         uint32_t acct_flags;
    1167             : 
    1168             :         uint32_t *rids;
    1169             :         uint32_t num_rids;
    1170             :         ssize_t array_size;
    1171             :         uint32_t current;
    1172             : };
    1173             : 
    1174        1471 : static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
    1175             : {
    1176        1471 :         struct tdbsam_search_state *state = talloc_get_type_abort(
    1177             :                 private_data, struct tdbsam_search_state);
    1178        1471 :         size_t prefixlen = strlen(RIDPREFIX);
    1179          63 :         uint32_t rid;
    1180        1471 :         int error = 0;
    1181          63 :         TDB_DATA key;
    1182             : 
    1183        1471 :         key = dbwrap_record_get_key(rec);
    1184             : 
    1185        1471 :         if ((key.dsize < prefixlen)
    1186        1471 :             || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
    1187         716 :                 return 0;
    1188             :         }
    1189             : 
    1190         713 :         rid = smb_strtoul((char *)key.dptr+prefixlen,
    1191             :                           NULL,
    1192             :                           16,
    1193             :                           &error,
    1194             :                           SMB_STR_STANDARD);
    1195         713 :         if (error != 0) {
    1196           0 :                 return 0;
    1197             :         }
    1198             : 
    1199         713 :         ADD_TO_LARGE_ARRAY(state, uint32_t, rid, &state->rids, &state->num_rids,
    1200          21 :                            &state->array_size);
    1201             : 
    1202         713 :         return 0;
    1203             : }
    1204             : 
    1205          15 : static void tdbsam_search_end(struct pdb_search *search)
    1206             : {
    1207          15 :         struct tdbsam_search_state *state = talloc_get_type_abort(
    1208             :                 search->private_data, struct tdbsam_search_state);
    1209          15 :         TALLOC_FREE(state);
    1210          15 : }
    1211             : 
    1212         718 : static bool tdbsam_search_next_entry(struct pdb_search *search,
    1213             :                                      struct samr_displayentry *entry)
    1214             : {
    1215         718 :         struct tdbsam_search_state *state = talloc_get_type_abort(
    1216             :                 search->private_data, struct tdbsam_search_state);
    1217         718 :         struct samu *user = NULL;
    1218          28 :         NTSTATUS status;
    1219          28 :         uint32_t rid;
    1220             : 
    1221         700 :  again:
    1222         728 :         TALLOC_FREE(user);
    1223         728 :         user = samu_new(talloc_tos());
    1224         728 :         if (user == NULL) {
    1225           0 :                 DEBUG(0, ("samu_new failed\n"));
    1226           0 :                 return false;
    1227             :         }
    1228             : 
    1229         728 :         if (state->current == state->num_rids) {
    1230          15 :                 TALLOC_FREE(user);
    1231          15 :                 return false;
    1232             :         }
    1233             : 
    1234         713 :         rid = state->rids[state->current++];
    1235             : 
    1236         713 :         status = tdbsam_getsampwrid(state->methods, user, rid);
    1237             : 
    1238         713 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
    1239             :                 /*
    1240             :                  * Someone has deleted that user since we listed the RIDs
    1241             :                  */
    1242           0 :                 goto again;
    1243             :         }
    1244             : 
    1245         713 :         if (!NT_STATUS_IS_OK(status)) {
    1246           0 :                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
    1247             :                            nt_errstr(status)));
    1248           0 :                 TALLOC_FREE(user);
    1249           0 :                 return false;
    1250             :         }
    1251             : 
    1252         713 :         if ((state->acct_flags != 0) &&
    1253         692 :             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
    1254          10 :                 goto again;
    1255             :         }
    1256             : 
    1257         703 :         entry->acct_flags = pdb_get_acct_ctrl(user);
    1258         703 :         entry->rid = rid;
    1259         703 :         entry->account_name = talloc_strdup(search, pdb_get_username(user));
    1260         703 :         entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
    1261         703 :         entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
    1262             : 
    1263         703 :         TALLOC_FREE(user);
    1264             : 
    1265         703 :         if ((entry->account_name == NULL) || (entry->fullname == NULL)
    1266         703 :             || (entry->description == NULL)) {
    1267           0 :                 DBG_ERR("talloc_strdup failed\n");
    1268           0 :                 return false;
    1269             :         }
    1270             : 
    1271         682 :         return true;
    1272             : }
    1273             : 
    1274          15 : static bool tdbsam_search_users(struct pdb_methods *methods,
    1275             :                                 struct pdb_search *search,
    1276             :                                 uint32_t acct_flags)
    1277             : {
    1278           7 :         struct tdbsam_search_state *state;
    1279             : 
    1280          15 :         if (!tdbsam_open(tdbsam_filename)) {
    1281           0 :                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
    1282             :                          tdbsam_filename));
    1283           0 :                 return false;
    1284             :         }
    1285             : 
    1286          15 :         state = talloc_zero(search, struct tdbsam_search_state);
    1287          15 :         if (state == NULL) {
    1288           0 :                 DEBUG(0, ("talloc failed\n"));
    1289           0 :                 return false;
    1290             :         }
    1291          15 :         state->acct_flags = acct_flags;
    1292          15 :         state->methods = methods;
    1293             : 
    1294          15 :         dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
    1295             : 
    1296          15 :         search->private_data = state;
    1297          15 :         search->next_entry = tdbsam_search_next_entry;
    1298          15 :         search->search_end = tdbsam_search_end;
    1299             : 
    1300          15 :         return true;
    1301             : }
    1302             : 
    1303       69784 : static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
    1304             : {
    1305       69784 :         return map_builtin;
    1306             : }
    1307             : 
    1308             : /*********************************************************************
    1309             :  Initialize the tdb sam backend.  Setup the dispatch table of methods,
    1310             :  open the tdb, etc...
    1311             : *********************************************************************/
    1312             : 
    1313       23524 : static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
    1314             : {
    1315          15 :         NTSTATUS nt_status;
    1316       23524 :         char *tdbfile = NULL;
    1317       23524 :         const char *pfile = location;
    1318             : 
    1319       23524 :         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
    1320           0 :                 return nt_status;
    1321             :         }
    1322             : 
    1323       23524 :         (*pdb_method)->name = "tdbsam";
    1324             : 
    1325       23524 :         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
    1326       23524 :         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
    1327       23524 :         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
    1328       23524 :         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
    1329       23524 :         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
    1330       23524 :         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
    1331       23524 :         (*pdb_method)->search_users = tdbsam_search_users;
    1332             : 
    1333       23524 :         (*pdb_method)->capabilities = tdbsam_capabilities;
    1334       23524 :         (*pdb_method)->new_rid = tdbsam_new_rid;
    1335             : 
    1336       23524 :         (*pdb_method)->is_responsible_for_builtin =
    1337             :                                         tdbsam_is_responsible_for_builtin;
    1338       23524 :         map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
    1339             : 
    1340             :         /* save the path for later */
    1341             : 
    1342       23524 :         if (!location) {
    1343       23518 :                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
    1344             :                              PASSDB_FILE_NAME) < 0) {
    1345           0 :                         return NT_STATUS_NO_MEMORY;
    1346             :                 }
    1347       23518 :                 pfile = tdbfile;
    1348             :         }
    1349             : 
    1350             :         /* Do not leak memory if the init function is called more than once */
    1351       23524 :         SAFE_FREE(tdbsam_filename);
    1352       23524 :         tdbsam_filename = SMB_STRDUP(pfile);
    1353       23524 :         if (!tdbsam_filename) {
    1354           0 :                 return NT_STATUS_NO_MEMORY;
    1355             :         }
    1356       23524 :         SAFE_FREE(tdbfile);
    1357             : 
    1358             :         /* no private data */
    1359             : 
    1360       23524 :         (*pdb_method)->private_data      = NULL;
    1361       23524 :         (*pdb_method)->free_private_data = NULL;
    1362             : 
    1363       23524 :         return NT_STATUS_OK;
    1364             : }
    1365             : 
    1366        1915 : NTSTATUS pdb_tdbsam_init(TALLOC_CTX *ctx)
    1367             : {
    1368        1915 :         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
    1369             : }

Generated by: LCOV version 1.14