void ot_cleanup_ote(struct ot_entry *ote) { struct ot_entry *saved_next; PFILE_OBJECT saved_fileobj; unsigned int i; // set all fields to zero except "next" and "fileobj" (cleanup listen/conn_entry if any) saved_next = ote->next; saved_fileobj = ote->fileobj; if (ote->type == FILEOBJ_ADDROBJ && ote->listen_entry != NULL) { del_listen_obj(ote->listen_entry, FALSE); } else if (ote->type == FILEOBJ_CONNOBJ && ote->conn_entry != NULL) { if (ote->ipproto == IPPROTO_TCP && ote->log_disconnect) log_disconnect(ote); del_tcp_conn_obj(ote->conn_entry, FALSE); } memset(ote, 0, sizeof(*ote)); ote->next = saved_next; ote->fileobj = saved_fileobj; // restore fileobjs for (i = 0; i < MAX_EVENT; i++) ote->ctx[i].fileobj = saved_fileobj; }
NTSTATUS ot_del_fileobj(PFILE_OBJECT fileobj, int *fileobj_type) { ULONG hash = CALC_HASH(fileobj); KIRQL irql; struct ot_entry *ote, *prev_ote; NTSTATUS status; if (fileobj == NULL) return STATUS_INVALID_PARAMETER_1; KeAcquireSpinLock(&g_ot_hash_guard, &irql); prev_ote = NULL; for (ote = g_ot_hash[hash]; ote; ote = ote->next) { if (ote->fileobj == fileobj) break; prev_ote = ote; } if (ote == NULL) { KdPrint(("[tdi_fw] ot_del_fileobj: fileobj 0x%x not found!\n", fileobj)); status = STATUS_OBJECT_NAME_NOT_FOUND; goto done; } if (ote->type == FILEOBJ_ADDROBJ && ote->listen_entry != NULL) del_listen_obj(ote->listen_entry, FALSE); else if (ote->type == FILEOBJ_CONNOBJ && ote->conn_entry != NULL) { if (ote->ipproto == IPPROTO_TCP && ote->log_disconnect) log_disconnect(ote); del_tcp_conn_obj(ote->conn_entry, FALSE); } if (fileobj_type != NULL) *fileobj_type = ote->type; if (prev_ote != NULL) prev_ote->next = ote->next; else g_ot_hash[hash] = ote->next; if (ote->sid_a != NULL) free(ote->sid_a); free(ote); status = STATUS_SUCCESS; done: KeReleaseSpinLock(&g_ot_hash_guard, irql); return status; }
static int get_protocol_version(int connection, struct ssgl_protocol_id *proto_id) { int protocol_version; int rc; /* get protocol version */ rc = ssgl_readsocket(connection, proto_id, sizeof(*proto_id)); if (rc != 0) return rc; if (memcmp(proto_id->signature, SSGL_SIGNATURE_STRING, sizeof(proto_id->signature)) != 0) goto bad_protocol; protocol_version = ntohl(proto_id->protocol_version); if (protocol_version != SSGL_PROTOCOL_VERSION) goto bad_protocol; return 0; bad_protocol: log_disconnect(SSGL_WARN, connection, "bad protocol identifier"); shutdown(connection, SHUT_RDWR); close(connection); return -1; }
NTSTATUS tdi_event_connect( IN PVOID TdiEventContext, IN LONG RemoteAddressLength, IN PVOID RemoteAddress, IN LONG UserDataLength, IN PVOID UserData, IN LONG OptionsLength, IN PVOID Options, OUT CONNECTION_CONTEXT *ConnectionContext, OUT PIRP *AcceptIrp) { TDI_EVENT_CONTEXT *ctx = (TDI_EVENT_CONTEXT *)TdiEventContext; TA_ADDRESS *remote_addr = ((TRANSPORT_ADDRESS *)RemoteAddress)->Address, *local_addr; struct ot_entry *ote_addr = NULL, *ote_conn = NULL; KIRQL irql; struct flt_request request; struct flt_rule rule; int result = FILTER_DENY; NTSTATUS status; PIO_STACK_LOCATION irps = NULL; struct accept_param *param = NULL; memset(&request, 0, sizeof(request)); KdPrint(("[tdi_fw] tdi_event_connect: addrobj 0x%x\n", ctx->fileobj)); ote_addr = ot_find_fileobj(ctx->fileobj, &irql); if (ote_addr == NULL) { KdPrint(("[tdi_fw] tdi_event_connect: ot_find_fileobj(0x%x)\n", ctx->fileobj)); goto done; } local_addr = (TA_ADDRESS *)(ote_addr->local_addr); KdPrint(("[tdi_fw] tdi_event_connect(pid:%u): %x:%u -> %x:%u\n", ote_addr->pid, ntohl(((TDI_ADDRESS_IP *)(remote_addr->Address))->in_addr), ntohs(((TDI_ADDRESS_IP *)(remote_addr->Address))->sin_port), ntohl(((TDI_ADDRESS_IP *)(local_addr->Address))->in_addr), ntohs(((TDI_ADDRESS_IP *)(local_addr->Address))->sin_port))); /* * request quick filter */ request.struct_size = sizeof(request); request.type = TYPE_CONNECT; request.direction = DIRECTION_IN; request.proto = IPPROTO_TCP; request.pid = ote_addr->pid; // get user SID & attributes! if ((request.sid_a = copy_sid_a(ote_addr->sid_a, ote_addr->sid_a_size)) != NULL) request.sid_a_size = ote_addr->sid_a_size; memcpy(&request.addr.from, &remote_addr->AddressType, sizeof(struct sockaddr)); memcpy(&request.addr.to, &local_addr->AddressType, sizeof(struct sockaddr)); request.addr.len = sizeof(struct sockaddr_in); result = quick_filter(&request, &rule); memcpy(request.log_rule_id, rule.rule_id, RULE_ID_SIZE); // log request later if (result == FILTER_DENY) goto done; result = FILTER_DENY; // leave spinlock before calling original handler KeReleaseSpinLock(&g_ot_hash_guard, irql); ote_addr = NULL; /* * run original handler */ status = ((PTDI_IND_CONNECT)(ctx->old_handler)) (ctx->old_context, RemoteAddressLength, RemoteAddress, UserDataLength, UserData, OptionsLength, Options, ConnectionContext, AcceptIrp); if (status != STATUS_MORE_PROCESSING_REQUIRED || *AcceptIrp == NULL) { KdPrint(("[tdi_fw] tdi_event_connect: status from original handler: 0x%x\n", status)); goto done; } /* * reinitialize connobj */ irps = IoGetCurrentIrpStackLocation(*AcceptIrp); KdPrint(("[tdi_fw] tdi_event_connect: connobj 0x%x\n", irps->FileObject)); // patch *AcceptIrp to change completion routine param = (struct accept_param *)malloc_np(sizeof(*param)); if (param == NULL) { KdPrint(("[tdi_fw] tdi_event_connect: malloc_np!\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto done; } param->old_cr = irps->CompletionRoutine; param->old_context = irps->Context; param->fileobj = irps->FileObject; param->old_control = irps->Control; // can't use IoSetCompletionRoutine because it uses next not current stack location irps->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; irps->CompletionRoutine = tdi_evconn_accept_complete; irps->Context = param; param = NULL; // find connobj for changing ote_conn = ot_find_fileobj(irps->FileObject, &irql); if (ote_conn == NULL) { KdPrint(("[tdi_fw] tdi_event_connect: ot_find_fileobj(0x%x)\n", irps->FileObject)); status = STATUS_OBJECT_NAME_NOT_FOUND; goto done; } ASSERT(ote_conn->type == FILEOBJ_CONNOBJ); // connobj must be associated with addrobj! if (ote_conn->associated_fileobj != ctx->fileobj) { KdPrint(("[tdi_fw] tdi_event_connect: 0x%x != 0x%x\n", ote_conn->associated_fileobj, ctx->fileobj)); status = STATUS_INVALID_PARAMETER; goto done; } // change conn_ctx (if needed) if (ote_conn->conn_ctx != *ConnectionContext) { // update (conn_ctx, addrobj)->connobj status = ot_del_conn_ctx(ote_conn->associated_fileobj, ote_conn->conn_ctx); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] tdi_event_connect: ot_del_conn_ctx: 0x%x\n", status)); goto done; } ote_conn->conn_ctx = *ConnectionContext; status = ot_add_conn_ctx(ote_conn->associated_fileobj, ote_conn->conn_ctx, irps->FileObject); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] tdi_event_connect: ot_add_conn_ctx: 0x%x\n", status)); goto done; } } // clear listen & conn entries in connobj (fileobject can be reused) ASSERT(ote_conn->listen_entry == NULL); if (ote_conn->listen_entry != NULL) del_listen_obj(ote_conn->listen_entry, FALSE); // free build case if (ote_conn->conn_entry != NULL) { if (ote_conn->ipproto == IPPROTO_TCP && ote_conn->log_disconnect) log_disconnect(ote_conn); del_tcp_conn_obj(ote_conn->conn_entry, FALSE); } // clear bytes count ote_conn->bytes_in = ote_conn->bytes_out = 0; // setup log_disconnect flag from rule ote_conn->log_disconnect = (rule.log >= RULE_LOG_COUNT); // sanity check if (local_addr->AddressLength != remote_addr->AddressLength) { KdPrint(("[tdi_fw] tdi_event_connect: different addr lengths! (%u != %u)\n", local_addr->AddressLength, remote_addr->AddressLength)); status = STATUS_INFO_LENGTH_MISMATCH; goto done; } // associate remote address with connobj if (remote_addr->AddressLength > sizeof(ote_conn->remote_addr)) { KdPrint(("[tdi_fw] tdi_event_connect: address too long! (%u)\n", remote_addr->AddressLength)); status = STATUS_BUFFER_TOO_SMALL; goto done; } memcpy(ote_conn->remote_addr, remote_addr, remote_addr->AddressLength); // associate local address with connobj if (local_addr->AddressLength > sizeof(ote_conn->local_addr)) { KdPrint(("[tdi_fw] tdi_event_connect: address too long! (%u)\n", local_addr->AddressLength)); status = STATUS_BUFFER_TOO_SMALL; goto done; } memcpy(ote_conn->local_addr, local_addr, local_addr->AddressLength); // create connection with "SYN_RCVD" state status = add_tcp_conn(ote_conn, TCP_STATE_SYN_RCVD); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] tdi_event_connect: add_tcp_conn: 0x%x\n", status)); goto done; } result = FILTER_ALLOW; done: // if logging is needed log request if (rule.log >= RULE_LOG_LOG) { if (result != FILTER_ALLOW && rule.result == FILTER_ALLOW) { request.type = TYPE_CONNECT_ERROR; // error has been occured request.status = status; } log_request(&request); } if (result != FILTER_ALLOW) { // deny incoming connection KdPrint(("[tdi_fw] tdi_event_connect: deny on reason 0x%x\n", status)); if (irps != NULL) { // delete connection if (ote_conn != NULL && ote_conn->conn_entry != NULL) { del_tcp_conn_obj(ote_conn->conn_entry, FALSE); ote_conn->conn_entry = NULL; } // release spinlock before IoCompleteRequest to avoid completion call inside spinlock if (ote_addr != NULL || ote_conn != NULL) { KeReleaseSpinLock(&g_ot_hash_guard, irql); ote_addr = NULL; ote_conn = NULL; } // destroy accepted IRP (*AcceptIrp)->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(*AcceptIrp, IO_NO_INCREMENT); } *AcceptIrp = NULL; status = STATUS_CONNECTION_REFUSED; } else status = STATUS_MORE_PROCESSING_REQUIRED; // cleanup if (ote_addr != NULL || ote_conn != NULL) KeReleaseSpinLock(&g_ot_hash_guard, irql); if (param != NULL) free(param); if (request.sid_a != NULL) free(request.sid_a); return status; }