From be1dfff02d562e42a7847bd02fed8538630d3f41 Mon Sep 17 00:00:00 2001 From: Dan Sledz Date: Mon, 2 Mar 2009 16:50:19 -0800 Subject: It appears that the first time we see a uid/gid that winbind can't map, we end up returning the null sid instead of falling back to the legacy code. Next time through the code we'll hit the negative cache and do the right thing, but we still fail the first time. If we fail the winbind id to sid mapping, call the legacy version. This catches the case where we don't have a negative cache entry for the mapping. This is better than returning the NULL sid to the caller. --- source3/passdb/lookup_sid.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 53845117e2..10ff36d51b 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -1308,13 +1308,17 @@ void uid_to_sid(DOM_SID *psid, uid_t uid) if (!ret || expired) { /* Not in cache. Ask winbindd. */ if (!winbind_uid_to_sid(psid, uid)) { - if (!winbind_ping()) { - legacy_uid_to_sid(psid, uid); - return; - } - - DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n", - uid)); + /* + * We shouldn't return the NULL SID + * here if winbind was running and + * couldn't map, as winbind will have + * added a negative entry that will + * cause us to go though the + * legacy_uid_to_sid() + * function anyway in the case above + * the next time we ask. + */ + legacy_uid_to_sid(psid, uid); return; } } @@ -1354,13 +1358,17 @@ void gid_to_sid(DOM_SID *psid, gid_t gid) if (!ret || expired) { /* Not in cache. Ask winbindd. */ if (!winbind_gid_to_sid(psid, gid)) { - if (!winbind_ping()) { - legacy_gid_to_sid(psid, gid); - return; - } - - DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n", - gid)); + /* + * We shouldn't return the NULL SID + * here if winbind was running and + * couldn't map, as winbind will have + * added a negative entry that will + * cause us to go though the + * legacy_gid_to_sid() + * function anyway in the case above + * the next time we ask. + */ + legacy_gid_to_sid(psid, gid); return; } } -- cgit From ef89c4bc0db2e9ba48f4dac1fd381e4cc6c8ca7d Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Tue, 3 Mar 2009 16:47:48 -0800 Subject: s3 passdb: Add back some useful debug statements Originally removed in be1dfff02d562e42a7847bd02fed8538630d3f41 --- source3/passdb/lookup_sid.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 10ff36d51b..9c20042a62 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -1309,15 +1309,18 @@ void uid_to_sid(DOM_SID *psid, uid_t uid) /* Not in cache. Ask winbindd. */ if (!winbind_uid_to_sid(psid, uid)) { /* - * We shouldn't return the NULL SID - * here if winbind was running and - * couldn't map, as winbind will have - * added a negative entry that will - * cause us to go though the - * legacy_uid_to_sid() - * function anyway in the case above - * the next time we ask. - */ + * We shouldn't return the NULL SID + * here if winbind was running and + * couldn't map, as winbind will have + * added a negative entry that will + * cause us to go though the + * legacy_uid_to_sid() + * function anyway in the case above + * the next time we ask. + */ + DEBUG(5, ("uid_to_sid: winbind failed to find a sid " + "for uid %u\n", uid)); + legacy_uid_to_sid(psid, uid); return; } @@ -1359,15 +1362,18 @@ void gid_to_sid(DOM_SID *psid, gid_t gid) /* Not in cache. Ask winbindd. */ if (!winbind_gid_to_sid(psid, gid)) { /* - * We shouldn't return the NULL SID - * here if winbind was running and - * couldn't map, as winbind will have - * added a negative entry that will - * cause us to go though the - * legacy_gid_to_sid() - * function anyway in the case above - * the next time we ask. - */ + * We shouldn't return the NULL SID + * here if winbind was running and + * couldn't map, as winbind will have + * added a negative entry that will + * cause us to go though the + * legacy_gid_to_sid() + * function anyway in the case above + * the next time we ask. + */ + DEBUG(5, ("gid_to_sid: winbind failed to find a sid " + "for gid %u\n", gid)); + legacy_gid_to_sid(psid, gid); return; } -- cgit From 46bcb10b5abb21758cf234764b64220ede1b7ab5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 12 Feb 2009 17:48:52 +0100 Subject: Shape up pdb_search a bit by making it a talloc ctx with a destructor --- source3/passdb/pdb_interface.c | 63 +++++++++++++++++++----------------------- source3/passdb/pdb_ldap.c | 20 +++++++------- source3/passdb/pdb_smbpasswd.c | 9 +++--- source3/passdb/pdb_tdb.c | 11 +++----- 4 files changed, 46 insertions(+), 57 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index e618b425e0..1909bd0da4 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -1709,24 +1709,25 @@ static NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods, } #endif -struct pdb_search *pdb_search_init(enum pdb_search_type type) +static int pdb_search_destructor(struct pdb_search *search) { - TALLOC_CTX *mem_ctx; - struct pdb_search *result; - - mem_ctx = talloc_init("pdb_search"); - if (mem_ctx == NULL) { - DEBUG(0, ("talloc_init failed\n")); - return NULL; + if (!search->search_ended) { + search->search_end(search); } + return 0; +} - result = TALLOC_P(mem_ctx, struct pdb_search); +struct pdb_search *pdb_search_init(TALLOC_CTX *mem_ctx, + enum pdb_search_type type) +{ + struct pdb_search *result; + + result = talloc(mem_ctx, struct pdb_search); if (result == NULL) { DEBUG(0, ("talloc failed\n")); return NULL; } - result->mem_ctx = mem_ctx; result->type = type; result->cache = NULL; result->num_entries = 0; @@ -1737,6 +1738,8 @@ struct pdb_search *pdb_search_init(enum pdb_search_type type) result->next_entry = NULL; result->search_end = NULL; + talloc_set_destructor(result, pdb_search_destructor); + return result; } @@ -1783,8 +1786,7 @@ static bool next_entry_groups(struct pdb_search *s, sid_peek_rid(&map->sid, &rid); - fill_displayentry(s->mem_ctx, rid, 0, map->nt_name, NULL, map->comment, - entry); + fill_displayentry(s, rid, 0, map->nt_name, NULL, map->comment, entry); state->current_group += 1; return True; @@ -1802,7 +1804,7 @@ static bool pdb_search_grouptype(struct pdb_search *search, { struct group_search *state; - state = TALLOC_P(search->mem_ctx, struct group_search); + state = talloc(search, struct group_search); if (state == NULL) { DEBUG(0, ("talloc failed\n")); return False; @@ -1853,7 +1855,7 @@ static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, break; } - ADD_TO_LARGE_ARRAY(search->mem_ctx, struct samr_displayentry, + ADD_TO_LARGE_ARRAY(search, struct samr_displayentry, entry, &search->cache, &search->num_entries, &search->cache_size); } @@ -1861,52 +1863,54 @@ static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, return (search->num_entries > idx) ? &search->cache[idx] : NULL; } -struct pdb_search *pdb_search_users(uint32 acct_flags) +struct pdb_search *pdb_search_users(TALLOC_CTX *mem_ctx, uint32 acct_flags) { struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; - result = pdb_search_init(PDB_USER_SEARCH); + result = pdb_search_init(mem_ctx, PDB_USER_SEARCH); if (result == NULL) { return NULL; } if (!pdb->search_users(pdb, result, acct_flags)) { - talloc_destroy(result->mem_ctx); + TALLOC_FREE(result); return NULL; } return result; } -struct pdb_search *pdb_search_groups(void) +struct pdb_search *pdb_search_groups(TALLOC_CTX *mem_ctx) { struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; - result = pdb_search_init(PDB_GROUP_SEARCH); + result = pdb_search_init(mem_ctx, PDB_GROUP_SEARCH); if (result == NULL) { return NULL; } if (!pdb->search_groups(pdb, result)) { - talloc_destroy(result->mem_ctx); + TALLOC_FREE(result); return NULL; } return result; } -struct pdb_search *pdb_search_aliases(const DOM_SID *sid) +struct pdb_search *pdb_search_aliases(TALLOC_CTX *mem_ctx, const DOM_SID *sid) { struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; if (pdb == NULL) return NULL; - result = pdb_search_init(PDB_ALIAS_SEARCH); - if (result == NULL) return NULL; + result = pdb_search_init(mem_ctx, PDB_ALIAS_SEARCH); + if (result == NULL) { + return NULL; + } if (!pdb->search_aliases(pdb, result, sid)) { - talloc_destroy(result->mem_ctx); + TALLOC_FREE(result); return NULL; } return result; @@ -1935,17 +1939,6 @@ uint32 pdb_search_entries(struct pdb_search *search, return search->num_entries - start_idx; } -void pdb_search_destroy(struct pdb_search *search) -{ - if (search == NULL) - return; - - if (!search->search_ended) - search->search_end(search); - - talloc_destroy(search->mem_ctx); -} - /******************************************************************* trustdom methods *******************************************************************/ diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 70a1c62bef..77b19e3de9 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -4349,7 +4349,8 @@ static bool ldapsam_search_next_entry(struct pdb_search *search, !ldapsam_search_nextpage(search)) return False; - result = state->ldap2displayentry(state, search->mem_ctx, state->connection->ldap_struct, + result = state->ldap2displayentry(state, search, + state->connection->ldap_struct, state->current_entry, entry); if (!result) { @@ -4508,7 +4509,7 @@ static bool ldapsam_search_users(struct pdb_methods *methods, (struct ldapsam_privates *)methods->private_data; struct ldap_search_state *state; - state = TALLOC_P(search->mem_ctx, struct ldap_search_state); + state = talloc(search, struct ldap_search_state); if (state == NULL) { DEBUG(0, ("talloc failed\n")); return False; @@ -4525,10 +4526,10 @@ static bool ldapsam_search_users(struct pdb_methods *methods, state->base = lp_ldap_suffix(); state->acct_flags = acct_flags; - state->base = talloc_strdup(search->mem_ctx, state->base); + state->base = talloc_strdup(search, state->base); state->scope = LDAP_SCOPE_SUBTREE; - state->filter = get_ldap_filter(search->mem_ctx, "*"); - state->attrs = talloc_attrs(search->mem_ctx, "uid", "sambaSid", + state->filter = get_ldap_filter(search, "*"); + state->attrs = talloc_attrs(search, "uid", "sambaSid", "displayName", "description", "sambaAcctFlags", NULL); state->attrsonly = 0; @@ -4682,7 +4683,7 @@ static bool ldapsam_search_grouptype(struct pdb_methods *methods, struct ldap_search_state *state; fstring tmp; - state = TALLOC_P(search->mem_ctx, struct ldap_search_state); + state = talloc(search, struct ldap_search_state); if (state == NULL) { DEBUG(0, ("talloc failed\n")); return False; @@ -4690,15 +4691,14 @@ static bool ldapsam_search_grouptype(struct pdb_methods *methods, state->connection = ldap_state->smbldap_state; - state->base = talloc_strdup(search->mem_ctx, lp_ldap_group_suffix()); + state->base = talloc_strdup(search, lp_ldap_group_suffix()); state->connection = ldap_state->smbldap_state; state->scope = LDAP_SCOPE_SUBTREE; - state->filter = talloc_asprintf(search->mem_ctx, - "(&(objectclass=%s)" + state->filter = talloc_asprintf(search, "(&(objectclass=%s)" "(sambaGroupType=%d)(sambaSID=%s*))", LDAP_OBJ_GROUPMAP, type, sid_to_fstring(tmp, sid)); - state->attrs = talloc_attrs(search->mem_ctx, "cn", "sambaSid", + state->attrs = talloc_attrs(search, "cn", "sambaSid", "displayName", "description", "sambaGroupType", NULL); state->attrsonly = 0; diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index b72e0f2cba..d663c7f0b2 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/passdb/pdb_smbpasswd.c @@ -1566,11 +1566,11 @@ static bool smbpasswd_search_next_entry(struct pdb_search *search, entry->acct_flags = state->entries[state->current].acct_flags; entry->account_name = talloc_strdup( - search->mem_ctx, state->entries[state->current].account_name); + search, state->entries[state->current].account_name); entry->fullname = talloc_strdup( - search->mem_ctx, state->entries[state->current].fullname); + search, state->entries[state->current].fullname); entry->description = talloc_strdup( - search->mem_ctx, state->entries[state->current].description); + search, state->entries[state->current].description); if ((entry->account_name == NULL) || (entry->fullname == NULL) || (entry->description == NULL)) { @@ -1593,8 +1593,7 @@ static bool smbpasswd_search_users(struct pdb_methods *methods, struct smb_passwd *pwd; FILE *fp; - search_state = TALLOC_ZERO_P(search->mem_ctx, - struct smbpasswd_search_state); + search_state = talloc_zero(search, struct smbpasswd_search_state); if (search_state == NULL) { DEBUG(0, ("talloc failed\n")); return false; diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 143a2e2390..3442561030 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -882,12 +882,9 @@ static bool tdbsam_search_next_entry(struct pdb_search *search, entry->acct_flags = pdb_get_acct_ctrl(user); entry->rid = rid; - entry->account_name = talloc_strdup( - search->mem_ctx, pdb_get_username(user)); - entry->fullname = talloc_strdup( - search->mem_ctx, pdb_get_fullname(user)); - entry->description = talloc_strdup( - search->mem_ctx, pdb_get_acct_desc(user)); + entry->account_name = talloc_strdup(search, pdb_get_username(user)); + entry->fullname = talloc_strdup(search, pdb_get_fullname(user)); + entry->description = talloc_strdup(search, pdb_get_acct_desc(user)); TALLOC_FREE(user); @@ -912,7 +909,7 @@ static bool tdbsam_search_users(struct pdb_methods *methods, return false; } - state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state); + state = talloc_zero(search, struct tdbsam_search_state); if (state == NULL) { DEBUG(0, ("talloc failed\n")); return false; -- cgit From b6616ca8dc263da648b980ed7f18d88f850293d0 Mon Sep 17 00:00:00 2001 From: Dan Sledz Date: Wed, 11 Mar 2009 23:27:01 +0000 Subject: s3 pdb_wbc_sam: LookupRids should return sAMAccountName, not NT4 names Also fix an incorrect TALLOC_FREE --- source3/passdb/pdb_wbc_sam.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/pdb_wbc_sam.c b/source3/passdb/pdb_wbc_sam.c index d2c7fda293..e8116d0995 100644 --- a/source3/passdb/pdb_wbc_sam.c +++ b/source3/passdb/pdb_wbc_sam.c @@ -150,7 +150,6 @@ static NTSTATUS pdb_wbc_sam_lookup_rids(struct pdb_methods *methods, NTSTATUS result = NT_STATUS_OK; char *domain = NULL; char **account_names = NULL; - char name[256]; enum lsa_SidType *attr_list = NULL; int i; @@ -168,16 +167,19 @@ static NTSTATUS pdb_wbc_sam_lookup_rids(struct pdb_methods *methods, if (attrs[i] == SID_NAME_UNKNOWN) { names[i] = NULL; } else { - snprintf(name, sizeof(name), "%s%c%s", domain, - *lp_winbind_separator(), account_names[i]); - names[i] = talloc_strdup(names, name); + names[i] = talloc_strdup(names, account_names[i]); + if (names[i] == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + } } done: TALLOC_FREE(account_names); TALLOC_FREE(domain); - TALLOC_FREE(attrs); + TALLOC_FREE(attr_list); return result; } -- cgit From b4ae0e8d84c26d548dbce9f4b6d74254725fe428 Mon Sep 17 00:00:00 2001 From: Alexander Zagrebin Date: Tue, 17 Mar 2009 15:38:33 -0700 Subject: Missing break in conversion function prevents tdb password database update. --- source3/passdb/pdb_tdb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/passdb') diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 3442561030..ab266515da 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -102,6 +102,7 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv) ret = init_samu_from_buffer(user, SAMU_BUFFER_V3, (uint8 *)rec->value.dptr, rec->value.dsize); + break; case 4: ret = init_samu_from_buffer(user, SAMU_BUFFER_V4, (uint8 *)rec->value.dptr, -- cgit From f942cb616e981e5370fab122969127de0910b58b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 18 Mar 2009 15:44:13 -0700 Subject: Fix bug #6195 - Migrating from 3.0.x to 3.3.x can fail to update passdb.tdb correctly. This is a really nasty one to fix as in order to successfully update the passdb.tdb we must do the equivalent of a tdbbackup to move to the new hash values before we do the upgrade. Jeremy. --- source3/passdb/pdb_tdb.c | 215 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 201 insertions(+), 14 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index ab266515da..73fcfee4b3 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -142,6 +142,149 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv) return 0; } +/********************************************************************** + Struct and function to backup an old record. + *********************************************************************/ + +struct tdbsam_backup_state { + struct db_context *new_db; + bool success; +}; + +static int backup_copy_fn(struct db_record *orig_rec, void *state) +{ + struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state; + struct db_record *new_rec; + NTSTATUS status; + + new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key); + if (new_rec == NULL) { + bs->success = false; + return 1; + } + + status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT); + + TALLOC_FREE(new_rec); + + if (!NT_STATUS_IS_OK(status)) { + bs->success = false; + return 1; + } + return 0; +} + +/********************************************************************** + Make a backup of an old passdb and replace the new one with it. We + have to do this as between 3.0.x and 3.2.x the hash function changed + by mistake (used unsigned char * instead of char *). This means the + previous simple update code will fail due to not being able to find + existing records to replace in the tdbsam_convert_one() function. JRA. + *********************************************************************/ + +static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db) +{ + TALLOC_CTX *frame = talloc_stackframe(); + const char *tmp_fname = NULL; + struct db_context *tmp_db = NULL; + struct db_context *orig_db = *pp_db; + struct tdbsam_backup_state bs; + int ret; + + tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname); + if (!tmp_fname) { + TALLOC_FREE(frame); + return false; + } + + unlink(tmp_fname); + + /* Remember to open this on the NULL context. We need + * it to stay around after we return from here. */ + + tmp_db = db_open(NULL, tmp_fname, 0, + TDB_DEFAULT, O_CREAT|O_RDWR, 0600); + if (tmp_db == NULL) { + DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd " + "[%s]\n", tmp_fname)); + TALLOC_FREE(frame); + return false; + } + + if (orig_db->transaction_start(orig_db) != 0) { + DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n")); + unlink(tmp_fname); + TALLOC_FREE(tmp_db); + TALLOC_FREE(frame); + return false; + } + if (tmp_db->transaction_start(tmp_db) != 0) { + DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n")); + orig_db->transaction_cancel(orig_db); + unlink(tmp_fname); + TALLOC_FREE(tmp_db); + TALLOC_FREE(frame); + return false; + } + + bs.new_db = tmp_db; + bs.success = true; + + ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs); + if (ret < 0) { + DEBUG(0, ("tdbsam_convert_backup: traverse failed\n")); + goto cancel; + } + + if (!bs.success) { + DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n")); + goto cancel; + } + + if (orig_db->transaction_commit(orig_db) != 0) { + smb_panic("tdbsam_convert_backup: orig commit failed\n"); + } + if (tmp_db->transaction_commit(tmp_db) != 0) { + smb_panic("tdbsam_convert_backup: orig commit failed\n"); + } + + /* This is safe from other users as we know we're + * under a mutex here. */ + + if (rename(tmp_fname, dbname) == -1) { + DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n", + tmp_fname, + dbname, + strerror(errno))); + smb_panic("tdbsam_convert_backup: replace passdb failed\n"); + } + + TALLOC_FREE(frame); + TALLOC_FREE(orig_db); + + DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n", + dbname )); + + /* Replace the global db pointer. */ + *pp_db = tmp_db; + return true; + + cancel: + + if (orig_db->transaction_cancel(orig_db) != 0) { + smb_panic("tdbsam_convert: transaction_cancel failed"); + } + + if (tmp_db->transaction_cancel(tmp_db) != 0) { + smb_panic("tdbsam_convert: transaction_cancel failed"); + } + + unlink(tmp_fname); + TALLOC_FREE(tmp_db); + TALLOC_FREE(frame); + return false; +} + static bool tdbsam_upgrade_next_rid(struct db_context *db) { TDB_CONTEXT *tdb; @@ -173,43 +316,50 @@ static bool tdbsam_upgrade_next_rid(struct db_context *db) return true; } -static bool tdbsam_convert(struct db_context *db, int32 from) +static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from) { struct tdbsam_convert_state state; + struct db_context *db = NULL; int ret; + if (!tdbsam_convert_backup(name, pp_db)) { + DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name)); + return false; + } + + db = *pp_db; state.from = from; state.success = true; if (db->transaction_start(db) != 0) { - DEBUG(0, ("Could not start transaction\n")); + DEBUG(0, ("tdbsam_convert: Could not start transaction\n")); return false; } if (!tdbsam_upgrade_next_rid(db)) { - DEBUG(0, ("tdbsam_upgrade_next_rid failed\n")); + DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n")); goto cancel; } ret = db->traverse(db, tdbsam_convert_one, &state); if (ret < 0) { - DEBUG(0, ("traverse failed\n")); + DEBUG(0, ("tdbsam_convert: traverse failed\n")); goto cancel; } if (!state.success) { - DEBUG(0, ("Converting records failed\n")); + DEBUG(0, ("tdbsam_convert: Converting records failed\n")); goto cancel; } if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING, TDBSAM_VERSION) != 0) { - DEBUG(0, ("Could not store tdbsam version\n")); + DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n")); goto cancel; } if (db->transaction_commit(db) != 0) { - DEBUG(0, ("Could not commit transaction\n")); + DEBUG(0, ("tdbsam_convert: Could not commit transaction\n")); return false; } @@ -217,7 +367,7 @@ static bool tdbsam_convert(struct db_context *db, int32 from) cancel: if (db->transaction_cancel(db) != 0) { - smb_panic("transaction_cancel failed"); + smb_panic("tdbsam_convert: transaction_cancel failed"); } return false; @@ -262,17 +412,54 @@ static bool tdbsam_open( const char *name ) } if ( version < TDBSAM_VERSION ) { - DEBUG(1, ("tdbsam_open: Converting version %d database to " - "version %d.\n", version, TDBSAM_VERSION)); + /* + * Ok - we think we're going to have to convert. + * Due to the backup process we now must do to + * upgrade we have to get a mutex and re-check + * the version. Someone else may have upgraded + * whilst we were checking. + */ + + struct named_mutex *mtx = grab_named_mutex(NULL, + "tdbsam_upgrade_mutex", + 600); - if ( !tdbsam_convert(db_sam, version) ) { - DEBUG(0, ("tdbsam_open: Error when trying to convert " - "tdbsam [%s]\n",name)); + if (!mtx) { + DEBUG(0, ("tdbsam_open: failed to grab mutex.\n")); TALLOC_FREE(db_sam); return false; } - DEBUG(3, ("TDBSAM converted successfully.\n")); + /* Re-check the version */ + version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING); + if (version == -1) { + version = 0; /* Version not found, assume version 0 */ + } + + /* Compare the version */ + if (version > TDBSAM_VERSION) { + /* Version more recent than the latest known */ + DEBUG(0, ("tdbsam_open: unknown version => %d\n", version)); + TALLOC_FREE(db_sam); + TALLOC_FREE(mtx); + return false; + } + + if ( version < TDBSAM_VERSION ) { + DEBUG(1, ("tdbsam_open: Converting version %d database to " + "version %d.\n", version, TDBSAM_VERSION)); + + if ( !tdbsam_convert(&db_sam, name, version) ) { + DEBUG(0, ("tdbsam_open: Error when trying to convert " + "tdbsam [%s]\n",name)); + TALLOC_FREE(db_sam); + TALLOC_FREE(mtx); + return false; + } + + DEBUG(3, ("TDBSAM converted successfully.\n")); + } + TALLOC_FREE(mtx); } DEBUG(4,("tdbsam_open: successfully opened %s\n", name )); -- cgit