diff --git a/src/chat/chat_feedback.c b/src/chat/chat_feedback.c index e3d86a85..39cb67cf 100644 --- a/src/chat/chat_feedback.c +++ b/src/chat/chat_feedback.c @@ -428,10 +428,13 @@ static int fb_next_channel(struct UTUN_INSTANCE* inst, const char* after, char c /* Пересчитывает только листья, зависящие от изменённого автора/ключа пригласившего. */ int chat_feedback_member_update(struct UTUN_INSTANCE* inst, uint64_t node_id) { if (!merkle_sync_registered(inst, MT_DATA_FEEDBACK)) return 0; - if (sqlite3_get_autocommit(inst->topo_sqlite_db)) return fb_db_error(inst, "-", "member update requires transaction"); + if (sqlite3_get_autocommit(inst->topo_sqlite_db)) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member update requires transaction node=%016llx", + (unsigned long long)node_id); return -1; + } char channel[21] = "", next[21]; int scan; while ((scan = fb_next_channel(inst, channel, next, 1)) > 0) { - memcpy(channel, next, sizeof(channel)); + strcpy(channel, next); char table[40], sql[384]; if (fb_table(inst, channel, table, NULL) < 0) return -1; snprintf(sql, sizeof(sql), "SELECT DISTINCT f.bucket FROM %s f LEFT JOIN peers_%s p ON p.node_id=f.node_id" " WHERE f.node_id=?1 OR p.signed_by=?1 ORDER BY f.bucket", table, channel); @@ -448,7 +451,10 @@ int chat_feedback_member_update(struct UTUN_INSTANCE* inst, uint64_t node_id) { buckets++; } int final = sqlite3_finalize(st); - if (rc != SQLITE_DONE || final != SQLITE_OK) return fb_db_error(inst, channel, "member index update"); + if (rc != SQLITE_DONE || final != SQLITE_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member index failed ch=%s dependency=%016llx step=%d finalize=%d", + channel, (unsigned long long)node_id, rc, final); return -1; + } if (buckets) DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member index updated ch=%s dependency=%016llx buckets=%u", channel, (unsigned long long)node_id, buckets); } @@ -461,7 +467,7 @@ void chat_feedback_member_committed(struct UTUN_INSTANCE* inst, uint64_t node_id if (!sqlite3_get_autocommit(inst->topo_sqlite_db)) { fb_db_error(inst, "-", "member notify before commit"); return; } char channel[21] = "", next[21]; while (fb_next_channel(inst, channel, next, 1) > 0) { - memcpy(channel, next, sizeof(channel)); + strcpy(channel, next); /* Даже без локального feedback ключ может разрешить приём ранее отложенной страницы. */ merkle_sync_changed(inst, MT_DATA_FEEDBACK, channel); char table[40], sql[512]; if (fb_table(inst, channel, table, NULL) < 0) return; @@ -502,7 +508,7 @@ int chat_feedback_init(struct UTUN_INSTANCE* inst) { return fb_db_error(inst, "-", "init begin"); char channel[21] = "", next[21]; int scan, result = 0; unsigned buckets = 0; while ((scan = fb_next_channel(inst, channel, next, 0)) > 0) { - memcpy(channel, next, sizeof(channel)); + strcpy(channel, next); char table[40], sql[128]; if (chat_feedback_ensure_channel(inst, channel) < 0 || fb_table(inst, channel, table, NULL) < 0) { result = -1; break; } snprintf(sql, sizeof(sql), "SELECT DISTINCT bucket FROM %s ORDER BY bucket", table); diff --git a/src/chat/member_sync.c b/src/chat/member_sync.c index 6dae5f65..566a4ddf 100644 --- a/src/chat/member_sync.c +++ b/src/chat/member_sync.c @@ -1344,57 +1344,63 @@ enum ms_author_status member_sync_author_key(struct UTUN_INSTANCE* inst, const c if (rc != SQLITE_ROW) goto done; int x_bytes = sqlite3_column_bytes(st, 0), ed_bytes = sqlite3_column_bytes(st, 1); int tree_bytes = sqlite3_column_bytes(st, 3), join_bytes = sqlite3_column_bytes(st, 4); - if (sqlite3_errcode(db) == SQLITE_NOMEM) goto done; + if (sqlite3_errcode(db) == SQLITE_NOMEM) { rc = SQLITE_NOMEM; goto done; } status = MS_AUTHOR_INVALID; reason = "invalid member fields"; if (x_bytes != 32 || ed_bytes != 32 || (tree_bytes != 0 && tree_bytes != 64) || (join_bytes != 0 && join_bytes != 64)) goto done; - if (!tree_bytes || !join_bytes || sqlite3_column_int64(st, 5) <= 0 - || _sig_is_zero64(sqlite3_column_blob(st, 3)) || _sig_is_zero64(sqlite3_column_blob(st, 4))) { - status = MS_AUTHOR_PENDING; reason = "join or invitation pending"; goto done; - } struct ms_member_rec member = { .node_id = author, .x25519 = sqlite3_column_blob(st, 0), .ed25519 = sqlite3_column_blob(st, 1), .signed_by = (uint64_t)sqlite3_column_int64(st, 2), .signature = sqlite3_column_blob(st, 3), .join_sig = sqlite3_column_blob(st, 4), .join_ts = (uint64_t)sqlite3_column_int64(st, 5) }; + if (sqlite3_errcode(db) == SQLITE_NOMEM || !member.x25519 || !member.ed25519 + || (tree_bytes && !member.signature) || (join_bytes && !member.join_sig)) { + status = MS_AUTHOR_ERROR; reason = "member column allocation"; rc = SQLITE_NOMEM; goto done; + } + if (!tree_bytes || !join_bytes || !member.join_ts + || _sig_is_zero64(member.signature) || _sig_is_zero64(member.join_sig)) { + status = MS_AUTHOR_PENDING; reason = "join or invitation pending"; goto done; + } reason = "node_id/X25519 mismatch"; uint64_t derived = sc_derive_node_id_from_pubkey(member.x25519); - if (!derived) { status = MS_AUTHOR_ERROR; reason = "identity digest"; goto done; } + if (!derived) { status = MS_AUTHOR_ERROR; reason = "identity digest"; rc = SC_ERR_CRYPTO; goto done; } if (derived != author) goto done; uint8_t trusted[32], x[32], ed[32], body[112]; reason = "trusted Ed25519 key unavailable"; int lookup = topo_node_sqlite_get_ed25519_pubkey(db, author, trusted); if (lookup != 0) { - status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; goto done; + status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; rc = lookup; goto done; } reason = "trusted Ed25519 key mismatch"; if (memcmp(trusted, member.ed25519, 32)) goto done; reason = "channel keys unavailable"; lookup = topo_node_sqlite_channel_get(db, channel, NULL, 0, NULL, x, ed, NULL); if (lookup != 0) { - status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; goto done; + status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; rc = lookup; goto done; } reason = "invalid join signature"; int bytes = member_sync_build_join_msg(x, ed, author, member.x25519, member.join_ts, body, sizeof(body)); if (bytes != 112) { status = MS_AUTHOR_ERROR; reason = "join message build"; goto done; } int signature = sc_ed25519_verify(member.ed25519, body, bytes, member.join_sig); if (signature != SC_OK) { - status = signature == SC_ERR_AUTH_FAILED ? MS_AUTHOR_INVALID : MS_AUTHOR_ERROR; goto done; + status = signature == SC_ERR_AUTH_FAILED ? MS_AUTHOR_INVALID : MS_AUTHOR_ERROR; rc = signature; goto done; } reason = "invitation verification"; signature = member_sync_verify_signature(db, channel, &member); if (signature != 1) { status = signature == MS_VERIFY_DEFERRED ? MS_AUTHOR_PENDING : signature == MS_VERIFY_ERROR ? MS_AUTHOR_ERROR : MS_AUTHOR_INVALID; + rc = signature; goto done; } memcpy(verified_key, member.ed25519, 32); status = MS_AUTHOR_ACTIVE; reason = "verified"; -done: - if (sqlite3_finalize(st) != SQLITE_OK) { status = MS_AUTHOR_ERROR; reason = "member finalize"; } +done:; + int final = sqlite3_finalize(st); + if (final != SQLITE_OK) { status = MS_AUTHOR_ERROR; reason = "member finalize"; rc = final; } if (status == MS_AUTHOR_ACTIVE) memcpy(key, verified_key, 32); if (status == MS_AUTHOR_ERROR) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, - "author verification failed ch=%s node=%016llx reason=%s rc=%d: %s", - channel, (unsigned long long)author, reason, rc, sqlite3_errmsg(db)); + "author verification failed ch=%s node=%016llx reason=%s result=%d", + channel, (unsigned long long)author, reason, rc); else if (status == MS_AUTHOR_INVALID) DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "author invalid ch=%s node=%016llx reason=%s", channel, (unsigned long long)author, reason); else if (status != MS_AUTHOR_ACTIVE) DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC,