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; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(orig_rec); new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key); if (new_rec == NULL) { bs->success = false; return 1; } value = dbwrap_record_get_value(orig_rec); status = dbwrap_record_store(new_rec, value, TDB_INSERT); TALLOC_FREE(new_rec); if (!NT_STATUS_IS_OK(status)) { bs->success = false; return 1; } return 0; }
static bool serverid_rec_parse(const struct db_record *rec, struct server_id *id, uint32_t *msg_flags) { struct serverid_key key; struct serverid_data data; TDB_DATA tdbkey; TDB_DATA tdbdata; tdbkey = dbwrap_record_get_key(rec); tdbdata = dbwrap_record_get_value(rec); if (tdbkey.dsize != sizeof(key)) { DEBUG(1, ("Found invalid key length %d in serverid.tdb\n", (int)tdbkey.dsize)); return false; } if (tdbdata.dsize != sizeof(data)) { DEBUG(1, ("Found invalid value length %d in serverid.tdb\n", (int)tdbdata.dsize)); return false; } memcpy(&key, tdbkey.dptr, sizeof(key)); memcpy(&data, tdbdata.dptr, sizeof(data)); id->pid = key.pid; id->task_id = key.task_id; id->vnn = key.vnn; id->unique_id = data.unique_id; *msg_flags = data.msg_flags; return true; }
static int regdb_normalize_keynames_fn(struct db_record *rec, void *private_data) { TALLOC_CTX *mem_ctx = talloc_tos(); const char *keyname; NTSTATUS status; TDB_DATA key; TDB_DATA value; struct db_context *db = (struct db_context *)private_data; key = dbwrap_record_get_key(rec); if (key.dptr == NULL || key.dsize == 0) { return 0; } value = dbwrap_record_get_value(rec); if (db == NULL) { DEBUG(0, ("regdb_normalize_keynames_fn: ERROR: " "NULL db context handed in via private_data\n")); return 1; } if (strncmp((const char *)key.dptr, REGDB_VERSION_KEYNAME, strlen(REGDB_VERSION_KEYNAME)) == 0) { return 0; } keyname = strchr((const char *)key.dptr, '/'); if (keyname) { keyname = talloc_string_sub(mem_ctx, (const char *)key.dptr, "/", "\\"); DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n", (const char *)key.dptr, keyname)); /* Delete the original record and store the normalized key */ status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "tdb_delete for [%s] failed!\n", (const char *)key.dptr)); return 1; } status = dbwrap_store_bystring(db, keyname, value, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "failed to store new record for [%s]!\n", keyname)); return 1; } } return 0; }
bool serverid_register_msg_flags(const struct server_id id, bool do_reg, uint32_t msg_flags) { struct db_context *db; struct serverid_key key; struct serverid_data *data; struct db_record *rec; TDB_DATA tdbkey; TDB_DATA value; NTSTATUS status; bool ret = false; db = serverid_db(); if (db == NULL) { return false; } serverid_fill_key(&id, &key); tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key)); rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey); if (rec == NULL) { DEBUG(1, ("Could not fetch_lock serverid.tdb record\n")); return false; } value = dbwrap_record_get_value(rec); if (value.dsize != sizeof(struct serverid_data)) { DEBUG(1, ("serverid record has unexpected size %d " "(wanted %d)\n", (int)value.dsize, (int)sizeof(struct serverid_data))); goto done; } data = (struct serverid_data *)value.dptr; if (do_reg) { data->msg_flags |= msg_flags; } else { data->msg_flags &= ~msg_flags; } status = dbwrap_record_store(rec, value, 0); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Storing serverid.tdb record failed: %s\n", nt_errstr(status))); goto done; } ret = true; done: TALLOC_FREE(rec); return ret; }
static int printer_list_clean_fn(struct db_record *rec, void *private_data) { struct printer_list_clean_state *state = (struct printer_list_clean_state *)private_data; uint32_t time_h, time_l; time_t refresh; char *name; char *comment; char *location; int ret; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(rec); /* skip anything that does not contain PL_DATA_FORMAT data */ if (strncmp((char *)key.dptr, PL_KEY_PREFIX, sizeof(PL_KEY_PREFIX)-1)) { return 0; } value = dbwrap_record_get_value(rec); ret = tdb_unpack(value.dptr, value.dsize, PL_DATA_FORMAT, &time_h, &time_l, &name, &comment, &location); if (ret == -1) { DEBUG(1, ("Failed to un pack printer data")); state->status = NT_STATUS_INTERNAL_DB_CORRUPTION; return -1; } SAFE_FREE(name); SAFE_FREE(comment); SAFE_FREE(location); refresh = (time_t)(((uint64_t)time_h << 32) + time_l); if (refresh < state->last_refresh) { state->status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(state->status)) { return -1; } } return 0; }
static struct share_mode_lock *get_share_mode_lock_internal( TALLOC_CTX *mem_ctx, struct file_id id, const char *servicepath, const struct smb_filename *smb_fname, const struct timespec *old_write_time) { struct share_mode_lock *lck; struct share_mode_data *d; struct db_record *rec; TDB_DATA key = locking_key(&id); TDB_DATA value; rec = dbwrap_fetch_locked(lock_db, mem_ctx, key); if (rec == NULL) { DEBUG(3, ("Could not lock share entry\n")); return NULL; } value = dbwrap_record_get_value(rec); if (value.dptr == NULL) { d = fresh_share_mode_lock(mem_ctx, servicepath, smb_fname, old_write_time); } else { d = parse_share_modes(mem_ctx, value); } if (d == NULL) { DEBUG(5, ("get_share_mode_lock_internal: " "Could not get share mode lock\n")); TALLOC_FREE(rec); return NULL; } d->id = id; d->record = talloc_move(d, &rec); talloc_set_destructor(d, share_mode_data_destructor); lck = talloc(mem_ctx, struct share_mode_lock); if (lck == NULL) { DEBUG(1, ("talloc failed\n")); TALLOC_FREE(d); return NULL; } lck->data = talloc_move(lck, &d); return lck; }
static int conn_traverse_fn(struct db_record *rec, void *private_data) { TDB_DATA key; TDB_DATA value; struct conn_traverse_state *state = (struct conn_traverse_state *)private_data; key = dbwrap_record_get_key(rec); value = dbwrap_record_get_value(rec); if ((key.dsize != sizeof(struct connections_key)) || (value.dsize != sizeof(struct connections_data))) { return 0; } return state->fn(rec, (const struct connections_key *)key.dptr, (const struct connections_data *)value.dptr, state->private_data); }
static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db, void *private_data) { struct db_record *rec; uint32_t val = (uint32_t)-1; uint32_t v_store; NTSTATUS ret; struct dbwrap_change_uint32_atomic_context *state; TDB_DATA value; state = (struct dbwrap_change_uint32_atomic_context *)private_data; rec = dbwrap_fetch_locked(db, talloc_tos(), string_term_tdb_data(state->keystr)); if (!rec) { return NT_STATUS_UNSUCCESSFUL; } value = dbwrap_record_get_value(rec); if (value.dptr == NULL) { val = *(state->oldval); } else if (value.dsize == sizeof(val)) { val = IVAL(value.dptr, 0); *(state->oldval) = val; } else { ret = NT_STATUS_UNSUCCESSFUL; goto done; } val += state->change_val; SIVAL(&v_store, 0, val); ret = dbwrap_record_store(rec, make_tdb_data((const uint8_t *)&v_store, sizeof(v_store)), TDB_REPLACE); done: TALLOC_FREE(rec); return ret; }
static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec, void *private_data) { struct smbXsrv_tcon_disconnect_all_state *state = (struct smbXsrv_tcon_disconnect_all_state *)private_data; TDB_DATA val; void *ptr = NULL; struct smbXsrv_tcon *tcon = NULL; uint64_t vuid; NTSTATUS status; val = dbwrap_record_get_value(local_rec); if (val.dsize != sizeof(ptr)) { status = NT_STATUS_INTERNAL_ERROR; if (NT_STATUS_IS_OK(state->first_status)) { state->first_status = status; } state->errors++; return 0; } memcpy(&ptr, val.dptr, val.dsize); tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon); vuid = state->vuid; if (vuid == 0 && tcon->compat) { vuid = tcon->compat->vuid; } tcon->db_rec = local_rec; status = smbXsrv_tcon_disconnect(tcon, vuid); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_IS_OK(state->first_status)) { state->first_status = status; } state->errors++; return 0; } return 0; }
static NTSTATUS smbXsrv_open_global_parse_record(TALLOC_CTX *mem_ctx, struct db_record *rec, struct smbXsrv_open_global0 **global) { TDB_DATA key = dbwrap_record_get_key(rec); TDB_DATA val = dbwrap_record_get_value(rec); DATA_BLOB blob = data_blob_const(val.dptr, val.dsize); struct smbXsrv_open_globalB global_blob; enum ndr_err_code ndr_err; NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob, (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:" "key '%s' ndr_pull_struct_blob - %s\n", hex_encode_talloc(frame, key.dptr, key.dsize), ndr_errstr(ndr_err))); status = ndr_map_error2ntstatus(ndr_err); goto done; } if (global_blob.version != SMBXSRV_VERSION_0) { status = NT_STATUS_INTERNAL_DB_CORRUPTION; DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:" "key '%s' unsuported version - %d - %s\n", hex_encode_talloc(frame, key.dptr, key.dsize), (int)global_blob.version, nt_errstr(status))); goto done; } *global = talloc_move(mem_ctx, &global_blob.info.info0); status = NT_STATUS_OK; done: talloc_free(frame); return status; }
static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map) { TDB_DATA key = dbwrap_record_get_key(rec); TDB_DATA value = dbwrap_record_get_value(rec); int ret = 0; fstring nt_name; fstring comment; if ((key.dsize < strlen(GROUP_PREFIX)) || (strncmp((char *)key.dptr, GROUP_PREFIX, GROUP_PREFIX_LEN) != 0)) { return False; } if (!string_to_sid(&map->sid, (const char *)key.dptr + GROUP_PREFIX_LEN)) { return False; } ret = tdb_unpack(value.dptr, value.dsize, "ddff", &map->gid, &map->sid_name_use, &nt_name, &comment); if (ret == -1) { DEBUG(3, ("dbrec2map: tdb_unpack failure\n")); return false; } map->nt_name = talloc_strdup(map, nt_name); if (!map->nt_name) { return false; } map->comment = talloc_strdup(map, comment); if (!map->comment) { return false; } return true; }
static int printer_list_exec_fn(struct db_record *rec, void *private_data) { struct printer_list_exec_state *state = (struct printer_list_exec_state *)private_data; uint32_t time_h, time_l; char *name; char *comment; char *location; int ret; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(rec); /* always skip PL_TIMESTAMP_KEY key */ if (strequal((const char *)key.dptr, PL_TIMESTAMP_KEY)) { return 0; } value = dbwrap_record_get_value(rec); ret = tdb_unpack(value.dptr, value.dsize, PL_DATA_FORMAT, &time_h, &time_l, &name, &comment, &location); if (ret == -1) { DEBUG(1, ("Failed to un pack printer data")); state->status = NT_STATUS_INTERNAL_DB_CORRUPTION; return -1; } state->fn(name, comment, location, state->private_data); SAFE_FREE(name); SAFE_FREE(comment); SAFE_FREE(location); return 0; }
/* load the notify array */ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec) { TDB_DATA dbuf; DATA_BLOB blob; NTSTATUS status; int seqnum; seqnum = dbwrap_get_seqnum(notify->db_recursive); if (seqnum == notify->seqnum && notify->array != NULL) { return NT_STATUS_OK; } notify->seqnum = seqnum; talloc_free(notify->array); notify->array = talloc_zero(notify, struct notify_array); NT_STATUS_HAVE_NO_MEMORY(notify->array); if (!rec) { status = dbwrap_fetch(notify->db_recursive, notify, notify->key, &dbuf); if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else { dbuf = dbwrap_record_get_value(rec); } blob.data = (uint8 *)dbuf.dptr; blob.length = dbuf.dsize; status = NT_STATUS_OK; if (blob.length > 0) { enum ndr_err_code ndr_err; ndr_err = ndr_pull_struct_blob(&blob, notify->array, notify->array, (ndr_pull_flags_fn_t)ndr_pull_notify_array); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { /* 1. log that we got a corrupt notify_array * 2. clear the variable the garbage was stored into to not trip * over it next time this method is entered with the same seqnum * 3. delete it from the database */ DEBUG(2, ("notify_array is corrupt, discarding it\n")); ZERO_STRUCTP(notify->array); if (rec != NULL) { dbwrap_record_delete(rec); } } else { if (DEBUGLEVEL >= 10) { DEBUG(10, ("notify_load:\n")); NDR_PRINT_DEBUG(notify_array, notify->array); } } } if (!rec) { talloc_free(dbuf.dptr); } return status; }
NTSTATUS smbXsrv_version_global_init(const struct server_id *server_id) { const char *global_path = NULL; struct db_context *db_ctx = NULL; struct db_record *db_rec = NULL; TDB_DATA key; TDB_DATA val; DATA_BLOB blob; struct smbXsrv_version_globalB global_blob; enum ndr_err_code ndr_err; struct smbXsrv_version_global0 *global = NULL; uint32_t i; uint32_t num_valid = 0; struct smbXsrv_version_node0 *valid = NULL; struct smbXsrv_version_node0 *local_node = NULL; bool exists; NTSTATUS status; const char *key_string = "smbXsrv_version_global"; TALLOC_CTX *frame; if (smbXsrv_version_global_db_ctx != NULL) { return NT_STATUS_OK; } frame = talloc_stackframe(); global_path = lock_path("smbXsrv_version_global.tdb"); if (global_path == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } db_ctx = db_open(NULL, global_path, 0, /* hash_size */ TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH, O_RDWR | O_CREAT, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); if (db_ctx == NULL) { status = map_nt_error_from_unix_common(errno); DEBUG(0,("smbXsrv_version_global_init: " "failed to open[%s] - %s\n", global_path, nt_errstr(status))); TALLOC_FREE(frame); return status; } key = string_term_tdb_data(key_string); db_rec = dbwrap_fetch_locked(db_ctx, db_ctx, key); if (db_rec == NULL) { status = NT_STATUS_INTERNAL_DB_ERROR; DEBUG(0,("smbXsrv_version_global_init: " "dbwrap_fetch_locked(%s) - %s\n", key_string, nt_errstr(status))); TALLOC_FREE(frame); return status; } val = dbwrap_record_get_value(db_rec); if (val.dsize == 0) { global = talloc_zero(frame, struct smbXsrv_version_global0); if (global == NULL) { DEBUG(0,("smbXsrv_version_global_init: " "talloc_zero failed - %s\n", __location__)); TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } ZERO_STRUCT(global_blob); global_blob.version = SMBXSRV_VERSION_CURRENT; global_blob.info.info0 = global; } else {
NTSTATUS leases_db_add(const struct GUID *client_guid, const struct smb2_lease_key *lease_key, const struct file_id *id, const char *servicepath, const char *base_name, const char *stream_name) { TDB_DATA db_key, db_value; DATA_BLOB blob; struct db_record *rec; NTSTATUS status; bool ok; struct leases_db_value new_value; struct leases_db_file new_file; struct leases_db_value *value = NULL; enum ndr_err_code ndr_err; if (!leases_db_init(false)) { return NT_STATUS_INTERNAL_ERROR; } ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key); if (!ok) { DEBUG(10, ("%s: leases_db_key failed\n", __func__)); return NT_STATUS_NO_MEMORY; } rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key); TALLOC_FREE(db_key.dptr); if (rec == NULL) { return NT_STATUS_INTERNAL_ERROR; } db_value = dbwrap_record_get_value(rec); if (db_value.dsize != 0) { uint32_t i; DEBUG(10, ("%s: record exists\n", __func__)); value = talloc(talloc_tos(), struct leases_db_value); if (value == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } blob.data = db_value.dptr; blob.length = db_value.dsize; ndr_err = ndr_pull_struct_blob_all( &blob, value, value, (ndr_pull_flags_fn_t)ndr_pull_leases_db_value); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n", __func__, ndr_errstr(ndr_err))); status = ndr_map_error2ntstatus(ndr_err); goto out; } /* id must be unique. */ for (i = 0; i < value->num_files; i++) { if (file_id_equal(id, &value->files[i].id)) { status = NT_STATUS_OBJECT_NAME_COLLISION; goto out; } } value->files = talloc_realloc(value, value->files, struct leases_db_file, value->num_files + 1); if (value->files == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } value->files[value->num_files].id = *id; value->files[value->num_files].servicepath = servicepath; value->files[value->num_files].base_name = base_name; value->files[value->num_files].stream_name = stream_name; value->num_files += 1; } else {
static void test_store_records(struct db_context *db, struct tevent_context *ev) { TDB_DATA key; uint32_t *counters; TALLOC_CTX *tmp_ctx = talloc_stackframe(); struct timeval start; key = string_term_tdb_data("testkey"); start = timeval_current(); while ((timelimit == 0) || (timeval_elapsed(&start) < timelimit)) { struct db_record *rec; TDB_DATA data; TDB_DATA value; int ret; NTSTATUS status; if (!no_trans) { if (verbose) DEBUG(1, ("starting transaction\n")); ret = dbwrap_transaction_start(db); if (ret != 0) { DEBUG(0, ("Failed to start transaction on node " "%d\n", pnn)); goto fail; } if (verbose) DEBUG(1, ("transaction started\n")); do_sleep(torture_delay); } if (verbose) DEBUG(1, ("calling fetch_lock\n")); rec = dbwrap_fetch_locked(db, tmp_ctx, key); if (rec == NULL) { DEBUG(0, ("Failed to fetch record\n")); goto fail; } if (verbose) DEBUG(1, ("fetched record ok\n")); do_sleep(torture_delay); value = dbwrap_record_get_value(rec); data.dsize = MAX(value.dsize, sizeof(uint32_t) * (pnn+1)); data.dptr = (unsigned char *)talloc_zero_size(tmp_ctx, data.dsize); if (data.dptr == NULL) { DEBUG(0, ("Failed to allocate data\n")); goto fail; } memcpy(data.dptr, value.dptr, value.dsize); counters = (uint32_t *)data.dptr; /* bump our counter */ counters[pnn]++; if (verbose) DEBUG(1, ("storing data\n")); status = dbwrap_record_store(rec, data, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to store record\n")); if (!no_trans) { ret = dbwrap_transaction_cancel(db); if (ret != 0) { DEBUG(0, ("Error cancelling transaction.\n")); } } goto fail; } talloc_free(rec); if (verbose) DEBUG(1, ("stored data ok\n")); do_sleep(torture_delay); if (!no_trans) { if (verbose) DEBUG(1, ("calling transaction_commit\n")); ret = dbwrap_transaction_commit(db); if (ret != 0) { DEBUG(0, ("Failed to commit transaction\n")); goto fail; } if (verbose) DEBUG(1, ("transaction committed\n")); } /* store the counters and verify that they are sane */ if (verbose || (pnn == 0)) { if (!check_counters(db, data)) { goto fail; } } talloc_free(data.dptr); do_sleep(torture_delay); } goto done; fail: success = false; done: talloc_free(tmp_ctx); return; }
static NTSTATUS smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0 *global) { struct smbXsrv_tcon_globalB global_blob; DATA_BLOB blob = data_blob_null; TDB_DATA key; TDB_DATA val; NTSTATUS status; enum ndr_err_code ndr_err; /* * TODO: if we use other versions than '0' * we would add glue code here, that would be able to * store the information in the old format. */ if (global->db_rec == NULL) { return NT_STATUS_INTERNAL_ERROR; } key = dbwrap_record_get_key(global->db_rec); val = dbwrap_record_get_value(global->db_rec); ZERO_STRUCT(global_blob); global_blob.version = smbXsrv_version_global_current(); if (val.dsize >= 8) { global_blob.seqnum = IVAL(val.dptr, 4); } global_blob.seqnum += 1; global_blob.info.info0 = global; ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob, (ndr_push_flags_fn_t)ndr_push_smbXsrv_tcon_globalB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(1,("smbXsrv_tcon_global_store: key '%s' ndr_push - %s\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize), nt_errstr(status))); TALLOC_FREE(global->db_rec); return status; } val = make_tdb_data(blob.data, blob.length); status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("smbXsrv_tcon_global_store: key '%s' store - %s\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize), nt_errstr(status))); TALLOC_FREE(global->db_rec); return status; } if (DEBUGLVL(10)) { DEBUG(10,("smbXsrv_tcon_global_store: key '%s' stored\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize))); NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob); } TALLOC_FREE(global->db_rec); return NT_STATUS_OK; }
static NTSTATUS smbXsrv_tcon_create(struct smbXsrv_tcon_table *table, enum protocol_types protocol, struct server_id server_id, NTTIME now, struct smbXsrv_tcon **_tcon) { struct db_record *local_rec = NULL; struct smbXsrv_tcon *tcon = NULL; void *ptr = NULL; TDB_DATA val; struct smbXsrv_tcon_global0 *global = NULL; NTSTATUS status; if (table->local.num_tcons >= table->local.max_tcons) { return NT_STATUS_INSUFFICIENT_RESOURCES; } tcon = talloc_zero(table, struct smbXsrv_tcon); if (tcon == NULL) { return NT_STATUS_NO_MEMORY; } tcon->table = table; tcon->status = NT_STATUS_INTERNAL_ERROR; tcon->idle_time = now; status = smbXsrv_tcon_global_allocate(table->global.db_ctx, tcon, &global); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } tcon->global = global; if (protocol >= PROTOCOL_SMB2_02) { uint64_t id = global->tcon_global_id; uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; global->tcon_wire_id = id; tcon->local_id = global->tcon_global_id; key = smbXsrv_tcon_local_id_to_key(tcon->local_id, key_buf); local_rec = dbwrap_fetch_locked(table->local.db_ctx, tcon, key); if (local_rec == NULL) { TALLOC_FREE(tcon); return NT_STATUS_NO_MEMORY; } val = dbwrap_record_get_value(local_rec); if (val.dsize != 0) { TALLOC_FREE(tcon); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else { status = smb1srv_tcon_local_allocate_id(table->local.db_ctx, table->local.lowest_id, table->local.highest_id, tcon, &local_rec, &tcon->local_id); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } global->tcon_wire_id = tcon->local_id; } global->creation_time = now; global->server_id = server_id; ptr = tcon; val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr)); status = dbwrap_record_store(local_rec, val, TDB_REPLACE); TALLOC_FREE(local_rec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } table->local.num_tcons += 1; talloc_set_destructor(tcon, smbXsrv_tcon_destructor); status = smbXsrv_tcon_global_store(global); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_tcon_create: " "global_id (0x%08x) store failed - %s\n", tcon->global->tcon_global_id, nt_errstr(status))); TALLOC_FREE(tcon); return status; } if (DEBUGLVL(10)) { struct smbXsrv_tconB tcon_blob; ZERO_STRUCT(tcon_blob); tcon_blob.version = SMBXSRV_VERSION_0; tcon_blob.info.info0 = tcon; DEBUG(10,("smbXsrv_tcon_create: global_id (0x%08x) stored\n", tcon->global->tcon_global_id)); NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob); } *_tcon = tcon; return NT_STATUS_OK; }
static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db, uint32_t lowest_id, uint32_t highest_id, TALLOC_CTX *mem_ctx, struct db_record **_rec, uint32_t *_id) { struct smb1srv_tcon_local_allocate_state state = { .lowest_id = lowest_id, .highest_id = highest_id, .last_id = 0, .useable_id = lowest_id, .status = NT_STATUS_INTERNAL_ERROR, }; uint32_t i; uint32_t range; NTSTATUS status; int count = 0; *_rec = NULL; *_id = 0; if (lowest_id > highest_id) { return NT_STATUS_INSUFFICIENT_RESOURCES; } /* * first we try randomly */ range = (highest_id - lowest_id) + 1; for (i = 0; i < (range / 2); i++) { uint32_t id; uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; id = generate_random() % range; id += lowest_id; if (id < lowest_id) { id = lowest_id; } if (id > highest_id) { id = highest_id; } key = smbXsrv_tcon_local_id_to_key(id, key_buf); rec = dbwrap_fetch_locked(db, mem_ctx, key); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } val = dbwrap_record_get_value(rec); if (val.dsize != 0) { TALLOC_FREE(rec); continue; } *_rec = rec; *_id = id; return NT_STATUS_OK; } /* * if the range is almost full, * we traverse the whole table * (this relies on sorted behavior of dbwrap_rbt) */ status = dbwrap_traverse_read(db, smb1srv_tcon_local_allocate_traverse, &state, &count); if (NT_STATUS_IS_OK(status)) { if (NT_STATUS_IS_OK(state.status)) { return NT_STATUS_INTERNAL_ERROR; } if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) { return state.status; } if (state.useable_id <= state.highest_id) { state.status = NT_STATUS_OK; } else { return NT_STATUS_INSUFFICIENT_RESOURCES; } } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) { /* * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION! * * If we get anything else it is an error, because it * means we did not manage to find a free slot in * the db. */ return NT_STATUS_INSUFFICIENT_RESOURCES; } if (NT_STATUS_IS_OK(state.status)) { uint32_t id; uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; TDB_DATA val; struct db_record *rec = NULL; id = state.useable_id; key = smbXsrv_tcon_local_id_to_key(id, key_buf); rec = dbwrap_fetch_locked(db, mem_ctx, key); if (rec == NULL) { return NT_STATUS_INSUFFICIENT_RESOURCES; } val = dbwrap_record_get_value(rec); if (val.dsize != 0) { TALLOC_FREE(rec); return NT_STATUS_INTERNAL_DB_CORRUPTION; } *_rec = rec; *_id = id; return NT_STATUS_OK; } return state.status; } struct smbXsrv_tcon_local_fetch_state { struct smbXsrv_tcon *tcon; NTSTATUS status; }; static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key, TDB_DATA data, void *private_data) { struct smbXsrv_tcon_local_fetch_state *state = (struct smbXsrv_tcon_local_fetch_state *)private_data; void *ptr; if (data.dsize != sizeof(ptr)) { state->status = NT_STATUS_INTERNAL_DB_ERROR; return; } memcpy(&ptr, data.dptr, data.dsize); state->tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon); state->status = NT_STATUS_OK; } static NTSTATUS smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table *table, uint32_t tcon_local_id, NTTIME now, struct smbXsrv_tcon **_tcon) { struct smbXsrv_tcon_local_fetch_state state = { .tcon = NULL, .status = NT_STATUS_INTERNAL_ERROR, }; uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; NTSTATUS status; *_tcon = NULL; if (tcon_local_id == 0) { return NT_STATUS_NETWORK_NAME_DELETED; } if (table == NULL) { /* this might happen before the end of negprot */ return NT_STATUS_NETWORK_NAME_DELETED; } if (table->local.db_ctx == NULL) { return NT_STATUS_INTERNAL_ERROR; } key = smbXsrv_tcon_local_id_to_key(tcon_local_id, key_buf); status = dbwrap_parse_record(table->local.db_ctx, key, smbXsrv_tcon_local_fetch_parser, &state); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { return NT_STATUS_NETWORK_NAME_DELETED; } else if (!NT_STATUS_IS_OK(status)) { return status; } if (!NT_STATUS_IS_OK(state.status)) { return state.status; } if (NT_STATUS_EQUAL(state.tcon->status, NT_STATUS_NETWORK_NAME_DELETED)) { return NT_STATUS_NETWORK_NAME_DELETED; } state.tcon->idle_time = now; *_tcon = state.tcon; return state.tcon->status; } static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0 *global) { return 0; } static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec, bool *is_free, bool *was_free, TALLOC_CTX *mem_ctx, struct smbXsrv_tcon_global0 **_g); static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db, TALLOC_CTX *mem_ctx, struct smbXsrv_tcon_global0 **_global) { uint32_t i; struct smbXsrv_tcon_global0 *global = NULL; uint32_t last_free = 0; const uint32_t min_tries = 3; *_global = NULL; global = talloc_zero(mem_ctx, struct smbXsrv_tcon_global0); if (global == NULL) { return NT_STATUS_NO_MEMORY; } talloc_set_destructor(global, smbXsrv_tcon_global_destructor); /* * Here we just randomly try the whole 32-bit space * * We use just 32-bit, because we want to reuse the * ID for SRVSVC. */ for (i = 0; i < UINT32_MAX; i++) { bool is_free = false; bool was_free = false; uint32_t id; uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE]; TDB_DATA key; if (i >= min_tries && last_free != 0) { id = last_free; } else { id = generate_random(); } if (id == 0) { id++; } if (id == UINT32_MAX) { id--; } key = smbXsrv_tcon_global_id_to_key(id, key_buf); global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key); if (global->db_rec == NULL) { talloc_free(global); return NT_STATUS_INSUFFICIENT_RESOURCES; } smbXsrv_tcon_global_verify_record(global->db_rec, &is_free, &was_free, NULL, NULL); if (!is_free) { TALLOC_FREE(global->db_rec); continue; } if (!was_free && i < min_tries) { /* * The session_id is free now, * but was not free before. * * This happens if a smbd crashed * and did not cleanup the record. * * If this is one of our first tries, * then we try to find a real free one. */ if (last_free == 0) { last_free = id; } TALLOC_FREE(global->db_rec); continue; } global->tcon_global_id = id; *_global = global; return NT_STATUS_OK; } /* should not be reached */ talloc_free(global); return NT_STATUS_INTERNAL_ERROR; }
static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec, bool *is_free, bool *was_free, TALLOC_CTX *mem_ctx, struct smbXsrv_tcon_global0 **_g) { TDB_DATA key; TDB_DATA val; DATA_BLOB blob; struct smbXsrv_tcon_globalB global_blob; enum ndr_err_code ndr_err; struct smbXsrv_tcon_global0 *global = NULL; bool exists; TALLOC_CTX *frame = talloc_stackframe(); *is_free = false; if (was_free) { *was_free = false; } if (_g) { *_g = NULL; } key = dbwrap_record_get_key(db_rec); val = dbwrap_record_get_value(db_rec); if (val.dsize == 0) { TALLOC_FREE(frame); *is_free = true; if (was_free) { *was_free = true; } return; } blob = data_blob_const(val.dptr, val.dsize); ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob, (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { NTSTATUS status = ndr_map_error2ntstatus(ndr_err); DEBUG(1,("smbXsrv_tcon_global_verify_record: " "key '%s' ndr_pull_struct_blob - %s\n", hex_encode_talloc(frame, key.dptr, key.dsize), nt_errstr(status))); TALLOC_FREE(frame); return; } DEBUG(10,("smbXsrv_tcon_global_verify_record\n")); if (DEBUGLVL(10)) { NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob); } if (global_blob.version != SMBXSRV_VERSION_0) { DEBUG(0,("smbXsrv_tcon_global_verify_record: " "key '%s' use unsupported version %u\n", hex_encode_talloc(frame, key.dptr, key.dsize), global_blob.version)); NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob); TALLOC_FREE(frame); return; } global = global_blob.info.info0; exists = serverid_exists(&global->server_id); if (!exists) { struct server_id_buf idbuf; DEBUG(2,("smbXsrv_tcon_global_verify_record: " "key '%s' server_id %s does not exist.\n", hex_encode_talloc(frame, key.dptr, key.dsize), server_id_str_buf(global->server_id, &idbuf))); if (DEBUGLVL(2)) { NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob); } TALLOC_FREE(frame); dbwrap_record_delete(db_rec); *is_free = true; return; } if (_g) { *_g = talloc_move(mem_ctx, &global); } TALLOC_FREE(frame); }
static int upgrade_v2_to_v3(struct db_record *rec, void *priv) { size_t prefix_len = strlen(SHARE_SECURITY_DB_KEY_PREFIX_STR); const char *servicename = NULL; char *c_servicename = NULL; char *newkey = NULL; bool *p_upgrade_ok = (bool *)priv; NTSTATUS status; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(rec); /* Is there space for a one character sharename ? */ if (key.dsize <= prefix_len+2) { return 0; } /* Does it start with the share key prefix ? */ if (memcmp(key.dptr, SHARE_SECURITY_DB_KEY_PREFIX_STR, prefix_len) != 0) { return 0; } /* Is it a null terminated string as a key ? */ if (key.dptr[key.dsize-1] != '\0') { return 0; } /* Bytes after the prefix are the sharename string. */ servicename = (char *)&key.dptr[prefix_len]; c_servicename = canonicalize_servicename(talloc_tos(), servicename); if (!c_servicename) { smb_panic("out of memory upgrading share security db from v2 -> v3"); } if (strcmp(servicename, c_servicename) == 0) { /* Old and new names match. No canonicalization needed. */ TALLOC_FREE(c_servicename); return 0; } /* Oops. Need to canonicalize name, delete old then store new. */ status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("upgrade_v2_to_v3: Failed to delete secdesc for " "%s: %s\n", (const char *)key.dptr, nt_errstr(status))); TALLOC_FREE(c_servicename); *p_upgrade_ok = false; return -1; } else { DEBUG(10, ("upgrade_v2_to_v3: deleted secdesc for " "%s\n", (const char *)key.dptr)); } if (!(newkey = talloc_asprintf(talloc_tos(), SHARE_SECURITY_DB_KEY_PREFIX_STR "%s", c_servicename))) { smb_panic("out of memory upgrading share security db from v2 -> v3"); } value = dbwrap_record_get_value(rec); status = dbwrap_store(share_db, string_term_tdb_data(newkey), value, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("upgrade_v2_to_v3: Failed to store secdesc for " "%s: %s\n", c_servicename, nt_errstr(status))); TALLOC_FREE(c_servicename); TALLOC_FREE(newkey); *p_upgrade_ok = false; return -1; } else { DEBUG(10, ("upgrade_v2_to_v3: stored secdesc for " "%s\n", newkey )); } TALLOC_FREE(newkey); TALLOC_FREE(c_servicename); return 0; }
static int tdbsam_convert_one(struct db_record *rec, void *priv) { struct tdbsam_convert_state *state = (struct tdbsam_convert_state *)priv; struct samu *user; TDB_DATA data; NTSTATUS status; bool ret; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(rec); if (key.dsize < USERPREFIX_LEN) { return 0; } if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) { return 0; } user = samu_new(talloc_tos()); if (user == NULL) { DEBUG(0,("tdbsam_convert: samu_new() failed!\n")); state->success = false; return -1; } DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) " "(version:%d)\n", (char *)key.dptr, state->from)); value = dbwrap_record_get_value(rec); switch (state->from) { case 0: ret = init_samu_from_buffer(user, SAMU_BUFFER_V0, (uint8_t *)value.dptr, value.dsize); break; case 1: ret = init_samu_from_buffer(user, SAMU_BUFFER_V1, (uint8_t *)value.dptr, value.dsize); break; case 2: ret = init_samu_from_buffer(user, SAMU_BUFFER_V2, (uint8_t *)value.dptr, value.dsize); break; case 3: ret = init_samu_from_buffer(user, SAMU_BUFFER_V3, (uint8_t *)value.dptr, value.dsize); break; case 4: ret = init_samu_from_buffer(user, SAMU_BUFFER_V4, (uint8_t *)value.dptr, value.dsize); break; default: /* unknown tdbsam version */ ret = False; } if (!ret) { DEBUG(0,("tdbsam_convert: Bad struct samu entry returned " "from TDB (key:%s) (version:%d)\n", (char *)key.dptr, state->from)); TALLOC_FREE(user); state->success = false; return -1; } data.dsize = init_buffer_from_samu(&data.dptr, user, false); TALLOC_FREE(user); if (data.dsize == -1) { DEBUG(0,("tdbsam_convert: cannot pack the struct samu into " "the new format\n")); state->success = false; return -1; } status = dbwrap_record_store(rec, data, TDB_MODIFY); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Could not store the new record: %s\n", nt_errstr(status))); state->success = false; return -1; } return 0; }
static bool upgrade_v2_to_v3_check_subkeylist(struct db_context *db, const char *key, const char *subkey) { static uint32_t zero = 0; static TDB_DATA empty_subkey_list = { .dptr = (unsigned char*)&zero, .dsize = sizeof(uint32_t), }; bool success = false; char *path = talloc_asprintf(talloc_tos(), "%s\\%s", key, subkey); strupper_m(path); if (!dbwrap_exists(db, string_term_tdb_data(path))) { NTSTATUS status; DEBUG(10, ("regdb_upgrade_v2_to_v3: writing subkey list [%s]\n", path)); status = dbwrap_store_bystring(db, path, empty_subkey_list, TDB_INSERT); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("regdb_upgrade_v2_to_v3: writing subkey list " "[%s] failed\n", path)); goto done; } } success = true; done: talloc_free(path); return success; } static bool upgrade_v2_to_v3_check_parent(struct db_context *db, const char *key) { const char *sep = strrchr_m(key, '\\'); if (sep != NULL) { char *pkey = talloc_strndup(talloc_tos(), key, sep-key); if (!dbwrap_exists(db, string_term_tdb_data(pkey))) { DEBUG(0, ("regdb_upgrade_v2_to_v3: missing subkey list " "[%s]\nrun \"net registry check\"\n", pkey)); } talloc_free(pkey); } return true; } #define IS_EQUAL(d,s) (((d).dsize == strlen(s)+1) && \ (strcmp((char*)(d).dptr, (s)) == 0)) #define STARTS_WITH(d,s) (((d).dsize > strlen(s)) && \ (strncmp((char*)(d).dptr, (s), strlen(s)) == 0)) #define SSTR(d) (int)(d).dsize , (char*)(d).dptr static int regdb_upgrade_v2_to_v3_fn(struct db_record *rec, void *private_data) { struct db_context *db = (struct db_context *)private_data; TDB_DATA key = dbwrap_record_get_key(rec); TDB_DATA val = dbwrap_record_get_value(rec); if (tdb_data_is_empty(key)) { return 0; } if (db == NULL) { DEBUG(0, ("regdb_upgrade_v2_to_v3_fn: ERROR: " "NULL db context handed in via private_data\n")); return 1; } if (IS_EQUAL(key, REGDB_VERSION_KEYNAME) || STARTS_WITH(key, REG_VALUE_PREFIX) || STARTS_WITH(key, REG_SECDESC_PREFIX)) { DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%.*s]\n", SSTR(key))); return 0; } if (STARTS_WITH(key, REG_SORTED_SUBKEYS_PREFIX)) { NTSTATUS status; /* Delete the deprecated sorted subkeys cache. */ DEBUG(10, ("regdb_upgrade_v2_to_v3: deleting [%.*s]\n", SSTR(key))); status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("regdb_upgrade_v2_to_v3: deleting [%.*s] " "failed!\n", SSTR(key))); return 1; } return 0; } if ( tdb_data_is_cstr(key) && hive_info((char*)key.dptr) != NULL ) { /* * Found a regular subkey list record. * Walk the list and create the list record for those * subkeys that don't already have one. */ TDB_DATA pos = val; char *subkey, *path = (char*)key.dptr; uint32_t num_items, found_items = 0; DEBUG(10, ("regdb_upgrade_v2_to_v3: scanning subkeylist of " "[%s]\n", path)); if (!tdb_data_read_uint32(&pos, &num_items)) { /* invalid or empty - skip */ return 0; } while (tdb_data_read_cstr(&pos, &subkey)) { found_items++; if (!upgrade_v2_to_v3_check_subkeylist(db, path, subkey)) { return 1; } if (!upgrade_v2_to_v3_check_parent(db, path)) { return 1; } } if (found_items != num_items) { DEBUG(0, ("regdb_upgrade_v2_to_v3: inconsistent subkey " "list [%s]\nrun \"net registry check\"\n", path)); } } else { DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping invalid [%.*s]\n" "run \"net registry check\"\n", SSTR(key))); } return 0; } static WERROR regdb_upgrade_v2_to_v3(struct db_context *db) { NTSTATUS status; WERROR werr; status = dbwrap_traverse(db, regdb_upgrade_v2_to_v3_fn, db, NULL); if (!NT_STATUS_IS_OK(status)) { werr = WERR_REG_IO_FAILURE; goto done; } werr = regdb_store_regdb_version(db, REGDB_VERSION_V3); done: return werr; }
/***************************************************************************** For idmap conversion: convert one record to new format Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid instead of the SID. *****************************************************************************/ static int convert_fn(struct db_record *rec, void *private_data) { struct winbindd_domain *domain; char *p; NTSTATUS status; struct dom_sid sid; uint32 rid; fstring keystr; fstring dom_name; TDB_DATA key; TDB_DATA key2; TDB_DATA value; struct convert_fn_state *s = (struct convert_fn_state *)private_data; key = dbwrap_record_get_key(rec); DEBUG(10,("Converting %s\n", (const char *)key.dptr)); p = strchr((const char *)key.dptr, '/'); if (!p) return 0; *p = 0; fstrcpy(dom_name, (const char *)key.dptr); *p++ = '/'; domain = find_domain_from_name(dom_name); if (domain == NULL) { /* We must delete the old record. */ DEBUG(0,("Unable to find domain %s\n", dom_name )); DEBUG(0,("deleting record %s\n", (const char *)key.dptr )); status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Unable to delete record %s:%s\n", (const char *)key.dptr, nt_errstr(status))); s->failed = true; return -1; } return 0; } rid = atoi(p); sid_compose(&sid, &domain->sid, rid); sid_to_fstring(keystr, &sid); key2 = string_term_tdb_data(keystr); value = dbwrap_record_get_value(rec); status = dbwrap_store(s->db, key2, value, TDB_INSERT); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to add record %s:%s\n", (const char *)key2.dptr, nt_errstr(status))); s->failed = true; return -1; } status = dbwrap_store(s->db, value, key2, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to update record %s:%s\n", (const char *)value.dptr, nt_errstr(status))); s->failed = true; return -1; } status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to delete record %s:%s\n", (const char *)key.dptr, nt_errstr(status))); s->failed = true; return -1; } return 0; }
NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id) { NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *frame = talloc_stackframe(); struct smbXsrv_open_global0 *op = NULL; TDB_DATA val; struct db_record *rec; bool delete_open = false; uint32_t global_id = persistent_id & UINT32_MAX; rec = smbXsrv_open_global_fetch_locked(smbXsrv_open_global_db_ctx, global_id, frame); if (rec == NULL) { status = NT_STATUS_NOT_FOUND; goto done; } val = dbwrap_record_get_value(rec); if (val.dsize == 0) { DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] " "empty record in %s, skipping...\n", global_id, dbwrap_name(smbXsrv_open_global_db_ctx))); goto done; } status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &op); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] " "failed to read record: %s\n", global_id, nt_errstr(status))); goto done; } if (server_id_is_disconnected(&op->server_id)) { struct timeval now, disconnect_time; int64_t tdiff; now = timeval_current(); nttime_to_timeval(&disconnect_time, op->disconnect_time); tdiff = usec_time_diff(&now, &disconnect_time); delete_open = (tdiff >= 1000*op->durable_timeout_msec); DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] " "disconnected at [%s] %us ago with " "timeout of %us -%s reached\n", global_id, nt_time_string(frame, op->disconnect_time), (unsigned)(tdiff/1000000), op->durable_timeout_msec / 1000, delete_open ? "" : " not")); } else if (!serverid_exists(&op->server_id)) { struct server_id_buf idbuf; DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] " "server[%s] does not exist\n", global_id, server_id_str_buf(op->server_id, &idbuf))); delete_open = true; } if (!delete_open) { goto done; } status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] " "failed to delete record" "from %s: %s\n", global_id, dbwrap_name(smbXsrv_open_global_db_ctx), nt_errstr(status))); goto done; } DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] " "delete record from %s\n", global_id, dbwrap_name(smbXsrv_open_global_db_ctx))); done: talloc_free(frame); return status; }