root/source3/passdb/pdb_tdb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tdbsam_convert_one
  2. backup_copy_fn
  3. tdbsam_convert_backup
  4. tdbsam_upgrade_next_rid
  5. tdbsam_convert
  6. tdbsam_open
  7. tdbsam_getsampwnam
  8. tdbsam_getsampwrid
  9. tdbsam_getsampwsid
  10. tdb_delete_samacct_only
  11. tdbsam_delete_sam_account
  12. tdb_update_samacct_only
  13. tdb_update_ridrec_only
  14. tdb_update_sam
  15. tdbsam_update_sam_account
  16. tdbsam_add_sam_account
  17. tdbsam_rename_sam_account
  18. tdbsam_rid_algorithm
  19. tdbsam_new_rid
  20. tdbsam_collect_rids
  21. tdbsam_search_end
  22. tdbsam_search_next_entry
  23. tdbsam_search_users
  24. pdb_init_tdbsam
  25. pdb_tdbsam_init

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

/* [<][>][^][v][top][bottom][index][help] */