Ignore:
Timestamp:
May 24, 2009, 7:51:24 AM (16 years ago)
Author:
Herwig Bauernfeind
Message:

Update Samba 3.3 branch to 3.3.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/samba-3.3.x/source/passdb/pdb_tdb.c

    r221 r223  
    55 * Copyright (C) Simo Sorce        2000-2003
    66 * Copyright (C) Gerald Carter     2000-2006
    7  * Copyright (C) Jeremy Allison    2001
     7 * Copyright (C) Jeremy Allison    2001-2009
    88 * Copyright (C) Andrew Bartlett   2002
    99 * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
     
    3939
    4040#define TDBSAM_VERSION  4       /* Most recent TDBSAM version */
     41#define TDBSAM_MINOR_VERSION    0       /* Most recent TDBSAM minor version */
    4142#define TDBSAM_VERSION_STRING   "INFO/version"
     43#define TDBSAM_MINOR_VERSION_STRING     "INFO/minor_version"
    4244#define PASSDB_FILE_NAME        "passdb.tdb"
    4345#define USERPREFIX              "USER_"
     
    103105                                            (uint8 *)rec->value.dptr,
    104106                                            rec->value.dsize);
     107                break;
    105108        case 4:
    106109                ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
     
    142145}
    143146
     147/**********************************************************************
     148 Struct and function to backup an old record.
     149 *********************************************************************/
     150
     151struct tdbsam_backup_state {
     152        struct db_context *new_db;
     153        bool success;
     154};
     155
     156static int backup_copy_fn(struct db_record *orig_rec, void *state)
     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
     187static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
     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
    144304static bool tdbsam_upgrade_next_rid(struct db_context *db)
    145305{
     
    173333}
    174334
    175 static bool tdbsam_convert(struct db_context *db, int32 from)
     335static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
    176336{
    177337        struct tdbsam_convert_state state;
     338        struct db_context *db = NULL;
    178339        int ret;
    179340
     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;
    180348        state.from = from;
    181349        state.success = true;
    182350
    183351        if (db->transaction_start(db) != 0) {
    184                 DEBUG(0, ("Could not start transaction\n"));
     352                DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
    185353                return false;
    186354        }
    187355
    188356        if (!tdbsam_upgrade_next_rid(db)) {
    189                 DEBUG(0, ("tdbsam_upgrade_next_rid failed\n"));
     357                DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
    190358                goto cancel;
    191359        }
     
    193361        ret = db->traverse(db, tdbsam_convert_one, &state);
    194362        if (ret < 0) {
    195                 DEBUG(0, ("traverse failed\n"));
     363                DEBUG(0, ("tdbsam_convert: traverse failed\n"));
    196364                goto cancel;
    197365        }
    198366
    199367        if (!state.success) {
    200                 DEBUG(0, ("Converting records failed\n"));
     368                DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
    201369                goto cancel;
    202370        }
     
    204372        if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
    205373                               TDBSAM_VERSION) != 0) {
    206                 DEBUG(0, ("Could not store tdbsam version\n"));
     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"));
    207381                goto cancel;
    208382        }
    209383
    210384        if (db->transaction_commit(db) != 0) {
    211                 DEBUG(0, ("Could not commit transaction\n"));
     385                DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
    212386                return false;
    213387        }
     
    217391 cancel:
    218392        if (db->transaction_cancel(db) != 0) {
    219                 smb_panic("transaction_cancel failed");
     393                smb_panic("tdbsam_convert: transaction_cancel failed");
    220394        }
    221395
     
    231405{
    232406        int32   version;
     407        int32   minor_version;
    233408
    234409        /* check if we are already open */
     
    251426        if (version == -1) {
    252427                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 */
    253434        }
    254435
     
    261442        }
    262443
    263         if ( version < TDBSAM_VERSION ) {
    264                 DEBUG(1, ("tdbsam_open: Converting version %d database to "
    265                           "version %d.\n", version, TDBSAM_VERSION));
    266 
    267                 if ( !tdbsam_convert(db_sam, version) ) {
    268                         DEBUG(0, ("tdbsam_open: Error when trying to convert "
    269                                   "tdbsam [%s]\n",name));
     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"));
    270461                        TALLOC_FREE(db_sam);
    271462                        return false;
    272463                }
    273464
    274                 DEBUG(3, ("TDBSAM converted successfully.\n"));
     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);
    275516        }
    276517
Note: See TracChangeset for help on using the changeset viewer.