Example #1
0
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;

}
Example #2
0
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;
}
Example #4
0
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;
}