Exemple #1
0
struct _SID_AND_ATTRIBUTES *
get_current_sid_a(ULONG *sid_a_size)		// must be called at PASSIVE_LEVEL!
{
	NTSTATUS status;
	HANDLE token;
	ULONG size;
	SID_AND_ATTRIBUTES *sid_a;

	*sid_a_size = 0;

	// open thread token
	status = ZwOpenThreadToken(CURRENT_THREAD, TOKEN_QUERY, FALSE, &token);
	if (status == STATUS_NO_TOKEN) {
		// open process token
		status = ZwOpenProcessToken(CURRENT_PROCESS, TOKEN_QUERY, &token);
	}
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] get_current_sid_a: ZwOpen{Thread|Process}Token: 0x%x!\n"));
		return NULL;
	}

	size = sizeof(*sid_a) + 100;		// default size
	
	sid_a = (SID_AND_ATTRIBUTES *)malloc_np(size);
	if (sid_a == NULL) {
		KdPrint(("[tdi_fw] get_current_sid_a: malloc_np!\n"));
		goto done;
	}

	status = ZwQueryInformationToken(token, TokenUser, sid_a, size, &size);
	if (status == STATUS_BUFFER_TOO_SMALL) {
		free(sid_a);
		
		sid_a = (SID_AND_ATTRIBUTES *)malloc_np(size);
		if (sid_a == NULL) {
			KdPrint(("[tdi_fw] get_current_sid_a: malloc_np!\n"));
			goto done;
		}

		status = ZwQueryInformationToken(token, TokenUser, sid_a, size, &size);
	}
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] get_current_sid_a: ZwQueryInformationToken: 0x%x!\n"));

		free(sid_a);
		sid_a = NULL;
		goto done;
	}

	// got sid & attributes!

	*sid_a_size = size;

done:
	ZwClose(token);
	return sid_a;
}
Exemple #2
0
NTSTATUS proc_init(void)
{
    g_proc_hash = (proc_entry_t **)malloc_np(sizeof(*g_proc_hash) * HASH_SIZE);
    if (!g_proc_hash) {
        return STATUS_NO_MEMORY;
    }
    RtlZeroMemory(g_proc_hash, sizeof(*g_proc_hash) * HASH_SIZE);

    KeInitializeSpinLock(&g_proc_hash_guard);

    return STATUS_SUCCESS;
}
Exemple #3
0
NTSTATUS
set_sid_list(char *buf, ULONG size)
{
	KIRQL irql;
	NTSTATUS status;
	ULONG pos;
	int i;

	KeAcquireSpinLock(&g_sids.guard, &irql);

	// first, free information
	if (g_sids.buf != NULL) {
		free(g_sids.buf);
		g_sids.buf = NULL;
	}
	memset(g_sids.list, 0, sizeof(g_sids.list));
	g_sids.count = 0;

	if (size != 0) {
		// copy buffer
		g_sids.buf = (char *)malloc_np(size);
		if (g_sids.buf == NULL) {
			KdPrint(("[tdi_fw] set_sid_list: malloc_np!\n"));
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto done;
		}
		memcpy(g_sids.buf, buf, size);

		// parse buffer and find struct sid_nfo
		for (pos = 0, i = 0; pos + sizeof(struct sid_nfo) < size && i < MAX_SIDS_COUNT; i++) {
			struct sid_nfo *nfo = (struct sid_nfo *)&g_sids.buf[pos];

			if (pos + sizeof(*nfo) + nfo->sid_len > size)
				break;

			g_sids.list[i] = nfo;

			pos += sizeof(*nfo) + nfo->sid_len;
		}

		g_sids.count = i;

		if (pos == size)
			status = STATUS_SUCCESS;
		else
			status = STATUS_INVALID_PARAMETER;
	} else
		status = STATUS_SUCCESS;

done:
	KeReleaseSpinLock(&g_sids.guard, irql);
	return status;
}
Exemple #4
0
NTSTATUS proc_add(CONST ULONG pid, CONST ProcessData *pProcInfo, CONST TIME seen)
{
    ULONG hash = CALC_HASH(pid);
    KIRQL irql;
    proc_entry_t *ote, *old_next;
    NTSTATUS status;
    int i;

    KeAcquireSpinLock(&g_proc_hash_guard, &irql);

    for (ote = g_proc_hash[hash]; ote; ote = ote->next)
        if (ote->pid == pid) break;

    if (!ote) {
        ote = (proc_entry_t *)malloc_np(sizeof(*ote));
        if (!ote) {
            status = STATUS_NO_MEMORY;
            goto done;
        }
        memset(ote, 0, sizeof(*ote));

        ote->next = g_proc_hash[hash];
        g_proc_hash[hash] = ote;

        ote->pid = pid;
    } else {
        struct proc_entry *saved_next;
        ULONG saved_pid;

        DBGOUT(("proc_add: reuse pid 0x%x\n", pid));

        // set all fields to zero except "next" and "fileobj" (cleanup listen/conn_entry if any)

        saved_next = ote->next;
        saved_pid = ote->pid;

        memset(ote, 0, sizeof(*ote));

        ote->next = saved_next;
        ote->pid = saved_pid;
    }

    ote->lastseen = seen;
    ote->pProcInfo = pProcInfo;
    status = STATUS_SUCCESS;
done:

    KeReleaseSpinLock(&g_proc_hash_guard, irql);
    RemoveUnseenProcesses();
    return status;
}
Exemple #5
0
NTSTATUS
ot_init(void)
{
	g_ot_hash = (struct ot_entry **)malloc_np(sizeof(*g_ot_hash) * HASH_SIZE);
	if (g_ot_hash == NULL) {
		KdPrint(("[tdi_fw] ot_init: malloc_np\n"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	memset(g_ot_hash, 0, sizeof(*g_ot_hash) * HASH_SIZE);

	KeInitializeSpinLock(&g_ot_hash_guard);

	g_cte_hash = (struct ctx_entry **)malloc_np(sizeof(*g_cte_hash) * HASH_SIZE);
	if (g_cte_hash == NULL) {
		KdPrint(("[tdi_fw] ot_init: malloc_np\n"));
		free(g_ot_hash);
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	memset(g_cte_hash, 0, sizeof(*g_cte_hash) * HASH_SIZE);

	KeInitializeSpinLock(&g_cte_hash_guard);

	return STATUS_SUCCESS;
}
Exemple #6
0
int
add_adapter(const wchar_t *name)
{
	KIRQL irql;
	struct adapter_entry *adapter;
	int result;

	KeAcquireSpinLock(&g_list_guard, &irql);

	__try {
		
		// first try to find adapter by name
		
		if (g_first != NULL) {
			for (adapter = g_first, result = 1; adapter != NULL; adapter = adapter->next, result++)
				if (wcscmp(adapter->name, name) == 0)
					__leave;
		}
		
		// not found: add adapter to list
		
		adapter = (struct adapter_entry *)malloc_np(sizeof(*adapter) +
			(wcslen(name) + 1) * sizeof(wchar_t));
		if (adapter == NULL) {
			KdPrint(("[ndis_hk] add_adapter: malloc_np!\n"));
			result = 0;
			__leave;
		}
		
		adapter->next = NULL;
		wcscpy(adapter->name, name);
		
		if (g_first == NULL)
			g_first = g_last = adapter;
		else {
			g_last->next = adapter;
			g_last = adapter;
		}
		
		result = ++g_count;

	} __finally {
		KeReleaseSpinLock(&g_list_guard, irql);
	}

	return result;
}
Exemple #7
0
struct _SID_AND_ATTRIBUTES *
copy_sid_a(SID_AND_ATTRIBUTES *sid_a, ULONG sid_a_size)
{
	SID_AND_ATTRIBUTES *result;
	
	if (sid_a == NULL)
		return NULL;

	result = (SID_AND_ATTRIBUTES *)malloc_np(sid_a_size);
	if (result == NULL)
		return NULL;

	memcpy(result, sid_a, sid_a_size);

	result->Sid = (char *)result + ((char *)(sid_a->Sid) - (char *)sid_a);

	return result;
}
Exemple #8
0
NTSTATUS datapipe_push(datapipe_t *dp, const char *data, ULONG size)
{
	struct datapipe_entry *de;
	KIRQL irql;

	de = (struct datapipe_entry *)malloc_np(sizeof(*de) + size);
	if (!de) return STATUS_NO_MEMORY;

	de->next = NULL;
	de->size = size;
	memcpy(de->data, data, size);

	KeAcquireSpinLock(&dp->guard, &irql);

	if (dp->last) dp->last->next = de; else dp->last = de;
	if (!dp->first) dp->first = dp->last;
	
	KeReleaseSpinLock(&dp->guard, irql);

	return STATUS_SUCCESS;
}
Exemple #9
0
NTSTATUS
ot_add_conn_ctx(PFILE_OBJECT addrobj, CONNECTION_CONTEXT conn_ctx, PFILE_OBJECT connobj)
{
	ULONG hash = CALC_HASH_2(addrobj, conn_ctx);
	KIRQL irql;
	struct ctx_entry *cte;
	NTSTATUS status;

	KeAcquireSpinLock(&g_cte_hash_guard, &irql);
	
	for (cte = g_cte_hash[hash]; cte != NULL; cte = cte->next)
		if (cte->addrobj == addrobj && cte->conn_ctx == conn_ctx)
			break;

	if (cte == NULL) {
		KdPrint(("[tdi_fw] ot_add_fileobj: reuse addrobj 0x%x, conn_ctx 0x%x\n",
			addrobj, conn_ctx));

		cte = (struct ctx_entry *)malloc_np(sizeof(*cte));
		if (cte == NULL) {
			KdPrint(("[tdi_fw] ot_add_conn_ctx: malloc_np\n"));
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto done;
		}
		cte->next = g_cte_hash[hash];
		g_cte_hash[hash] = cte;
	
		cte->addrobj = addrobj;
		cte->conn_ctx = conn_ctx;
	}

	cte->connobj = connobj;
	
	status = STATUS_SUCCESS;
done:

	KeReleaseSpinLock(&g_cte_hash_guard, irql);
	return status;
}
Exemple #10
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;
}
Exemple #11
0
/* this completion routine queries address and port from address object */
NTSTATUS
tdi_create_addrobj_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
	NTSTATUS status;
	PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(Irp);
	PIRP query_irp = (PIRP)Context;
	PDEVICE_OBJECT devobj;
	TDI_CREATE_ADDROBJ2_CTX *ctx = NULL;
	PMDL mdl = NULL;

	KdPrint(("[tdi_fw] tdi_create_addrobj_complete: devobj 0x%x; addrobj 0x%x\n",
		DeviceObject, irps->FileObject));

	if (Irp->IoStatus.Status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: status 0x%x\n", Irp->IoStatus.Status));

		status = Irp->IoStatus.Status;
		goto done;
	}

	// query addrobj address:port

	ctx = (TDI_CREATE_ADDROBJ2_CTX *)malloc_np(sizeof(TDI_CREATE_ADDROBJ2_CTX));
	if (ctx == NULL) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: malloc_np\n"));
		
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto done;
	}
	ctx->fileobj = irps->FileObject;

	ctx->tai = (TDI_ADDRESS_INFO *)malloc_np(TDI_ADDRESS_INFO_MAX);
	if (ctx->tai == NULL) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: malloc_np!\n"));

		status = STATUS_INSUFFICIENT_RESOURCES;
		goto done;
	}

	mdl = IoAllocateMdl(ctx->tai, TDI_ADDRESS_INFO_MAX, FALSE, FALSE, NULL);
	if (mdl == NULL) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: IoAllocateMdl!\n"));
		
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto done;
	}
	MmBuildMdlForNonPagedPool(mdl);

	devobj = get_original_devobj(DeviceObject, NULL);	// use original devobj!
	if (devobj == NULL) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: get_original_devobj!\n"));

		status = STATUS_INVALID_PARAMETER;
		goto done;
	}

	TdiBuildQueryInformation(query_irp, devobj, irps->FileObject,
		tdi_create_addrobj_complete2, ctx,
		TDI_QUERY_ADDRESS_INFO, mdl);

	status = IoCallDriver(devobj, query_irp);
	query_irp = NULL;
	mdl = NULL;
	ctx = NULL;

	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] tdi_create_addrobj_complete: IoCallDriver: 0x%x\n", status));
		goto done;
	}

	status = STATUS_SUCCESS;

done:
	// cleanup
	if (mdl != NULL)
		IoFreeMdl(mdl);
	
	if (ctx != NULL) {
		if (ctx->tai != NULL)
			free(ctx->tai);
		free(ctx);
	}
	
	if (query_irp != NULL)
		IoCompleteRequest(query_irp, IO_NO_INCREMENT);

	Irp->IoStatus.Status = status;
	
	if (status != STATUS_SUCCESS) {
		// tdi_create failed - remove fileobj from hash
		ot_del_fileobj(irps->FileObject, NULL);
	}

	return tdi_generic_complete(DeviceObject, Irp, Context);
}
Exemple #12
0
/*
 * Dispatch routines call this function to complete their processing.
 * They _MUST_ call this function anyway.
 */
NTSTATUS
tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter,
					  PIO_COMPLETION_ROUTINE cr, PVOID context)
{
	PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp);
	NTSTATUS status;

	if (filter == FILTER_DENY) {
		
		/*
		 * DENY: complete request with status "Access violation"
		 */

		KdPrint(("[tdi_fw] tdi_dispatch_complete: [DROP!]"
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n",
			irps->MajorFunction,
			irps->MinorFunction,
			devobj,
			irps->FileObject));

		if (irp->IoStatus.Status == STATUS_SUCCESS) {
			// change status
			status = irp->IoStatus.Status = STATUS_ACCESS_DENIED;
		} else {
			// set IRP status unchanged
			status = irp->IoStatus.Status;
		}

		IoCompleteRequest (irp, IO_NO_INCREMENT);
		
	} else if (filter == FILTER_ALLOW) {

		/*
		 * ALLOW: pass IRP to the next driver
		 */

#ifndef USE_TDI_HOOKING

		PDEVICE_OBJECT old_devobj = get_original_devobj(devobj, NULL);

		if (old_devobj == NULL) {
			KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: Unknown DeviceObject 0x%x!\n", devobj));
	
			status = irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
			IoCompleteRequest (irp, IO_NO_INCREMENT);
			
			return status;
		}

#endif

		KdPrint(("[tdi_fw] tdi_dispatch_complete: [ALLOW.]"
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n",
			irps->MajorFunction,
			irps->MinorFunction,
			devobj,
			irps->FileObject));

#ifndef USE_TDI_HOOKING

		if (cr == NULL || irp->CurrentLocation <= 1) {
			/*
			 * we use _THIS_ way of sending IRP to old driver
			 * a) to avoid NO_MORE_STACK_LOCATIONS
			 * b) and if we haven't our completions - no need to copy stack locations!
			 */

			// stay on this location after IoCallDriver
			IoSkipCurrentIrpStackLocation(irp);

#endif

			if (cr != NULL) {
				/*
				 * set completion routine (this way is slow)
				 */

				// save old completion routine and context
				TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)malloc_np(sizeof(*ctx));
				if (ctx == NULL) {
					KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: malloc_np\n"));
					
					status = irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
					IoCompleteRequest(irp, IO_NO_INCREMENT);
					
					return status;
				}

				ctx->old_cr = irps->CompletionRoutine;
				ctx->old_context = irps->Context;
				ctx->new_cr = cr;
				ctx->new_context = context;
				ctx->fileobj = irps->FileObject;
				ctx->new_devobj = devobj;

				ctx->old_control = irps->Control;

				IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE);
			}

#ifndef USE_TDI_HOOKING			
		} else {
			PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp),
				next_irps = IoGetNextIrpStackLocation(irp);
			
			memcpy(next_irps, irps, sizeof(*irps));

			if (cr != NULL) {
				/*
				 * this way for completion is more quicker than used above
				 */

				IoSetCompletionRoutine(irp, cr, context, TRUE, TRUE, TRUE);
			} else
				IoSetCompletionRoutine(irp, tdi_generic_complete, NULL, TRUE, TRUE, TRUE);
		}
#endif

		/* call original driver */

#ifndef USE_TDI_HOOKING
		status = IoCallDriver(old_devobj, irp);
#else
		status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp);
#endif

	} else {	/* FILTER_UNKNOWN */

		/*
		 * UNKNOWN: just complete the request
		 */

		status = irp->IoStatus.Status = STATUS_SUCCESS;	// ???
		IoCompleteRequest (irp, IO_NO_INCREMENT);
	}

	return status;
}
Exemple #13
0
int
tdi_connect(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion)
{
	PTDI_REQUEST_KERNEL_CONNECT param = (PTDI_REQUEST_KERNEL_CONNECT)(&irps->Parameters);
	TA_ADDRESS *remote_addr = ((TRANSPORT_ADDRESS *)(param->RequestConnectionInformation->RemoteAddress))->Address;
	PFILE_OBJECT addrobj;
	NTSTATUS status;
	TA_ADDRESS *local_addr;
	int result = FILTER_DENY, ipproto;
	struct ot_entry *ote_conn = NULL, *ote_addr;
	KIRQL irql;
	struct flt_request request;
	struct flt_rule rule;

	memset(&request, 0, sizeof(request));

	KdPrint(("[tdi_fw] tdi_connect: connobj 0x%x, to address %x:%u\n",
		irps->FileObject,
		ntohl(((TDI_ADDRESS_IP *)(remote_addr->Address))->in_addr),
		ntohs(((TDI_ADDRESS_IP *)(remote_addr->Address))->sin_port)));

	// check device object: TCP or UDP
	if (irps->DeviceObject != g_tcpfltobj && irps->DeviceObject != g_udpfltobj) {
		KdPrint(("[tdi_fw] tdi_connect: unknown DeviceObject 0x%x!\n", irps->DeviceObject));
		goto done;
	}

	ote_conn = ot_find_fileobj(irps->FileObject, &irql);
	if (ote_conn == NULL) {
		KdPrint(("[tdi_fw] tdi_connect: ot_find_fileobj(0x%x)!\n", irps->FileObject));
		goto done;
	}

	if (get_original_devobj(irps->DeviceObject, &ipproto) == NULL ||
		(ipproto != IPPROTO_TCP && ipproto != IPPROTO_UDP)) {
		// invalid device object!
		KdPrint(("[tdi_fw] tdi_connect: invalid device object 0x%x!\n", irps->DeviceObject));
		goto done;
	}

	if (ipproto == IPPROTO_TCP) {
		/*
		 * For TCP: get addrobj by connobj and get local address by it
		 */

		addrobj = ote_conn->associated_fileobj;
		if (addrobj == NULL) {
			KdPrint(("[tdi_fw] tdi_connect: empty addrobj!\n"));
			goto done;
		}

		ote_addr = ot_find_fileobj(addrobj, NULL); // we're already in spinlock
		if (ote_addr == NULL) {
			KdPrint(("[tdi_fw] tdi_connect: ot_find_fileobj(0x%x)!\n", addrobj));
			goto done;
		}

	} else {
		/*
		 * For UDP: connobj and addrobj are the same
		 */
		KdPrint(("[tdi_fw] tdi_connect: connected UDP socket detected\n"));

		// for connected UDP sockets connobj and addrobj are the same
		addrobj= irps->FileObject;
		ote_addr = ote_conn;
	}

	local_addr = (TA_ADDRESS *)(ote_addr->local_addr);

	// sanity check
	if (local_addr->AddressLength != remote_addr->AddressLength) {
		KdPrint(("[tdi_fw] tdi_connect: different addr lengths! (%u != %u)\n",
			local_addr->AddressLength, remote_addr->AddressLength));
		goto done;
	}

	// set remote address with connobj
	
	if (remote_addr->AddressLength > sizeof(ote_conn->remote_addr)) {
		KdPrint(("[tdi_fw] tdi_connect: address too long! (%u)\n", remote_addr->AddressLength));
		goto done;
	}
	memcpy(ote_conn->remote_addr, remote_addr, remote_addr->AddressLength);

	// set local address with connobj

	if (local_addr->AddressLength > sizeof(ote_conn->local_addr)) {
		KdPrint(("[tdi_fw] tdi_connect: address to long! (%u)\n", local_addr->AddressLength));
		goto done;
	}
	memcpy(ote_conn->local_addr, local_addr, local_addr->AddressLength);

	KdPrint(("[tdi_fw] tdi_connect(pid:%u/%u): %x:%u -> %x:%u (ipproto = %d)\n",
		ote_conn->pid, PsGetCurrentProcessId(),
		ntohl(((TDI_ADDRESS_IP *)(local_addr->Address))->in_addr),
		ntohs(((TDI_ADDRESS_IP *)(local_addr->Address))->sin_port),
		ntohl(((TDI_ADDRESS_IP *)(remote_addr->Address))->in_addr),
		ntohs(((TDI_ADDRESS_IP *)(remote_addr->Address))->sin_port), ipproto));

	/*
	 * Call quick_filter
	 */

	request.struct_size = sizeof(request);

	request.type = TYPE_CONNECT;
	request.direction = DIRECTION_OUT;
	request.proto = ipproto;

	// don't use ote_conn->pid because one process can create connection object
	// but another one can connect
	request.pid = (ULONG)PsGetCurrentProcessId();
	if (request.pid == 0) {
		// avoid idle process pid (XXX do we need this?)
		request.pid = ote_addr->pid;
	}

	// get user SID & attributes (can't call get_current_sid_a at DISPATCH_LEVEL)
	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, &local_addr->AddressType, sizeof(struct sockaddr));
	memcpy(&request.addr.to, &remote_addr->AddressType, sizeof(struct sockaddr));
	request.addr.len = sizeof(struct sockaddr_in);

	memset(&rule, 0, sizeof(rule));

	result = quick_filter(&request, &rule);

	memcpy(request.log_rule_id, rule.rule_id, RULE_ID_SIZE);

	if (result == FILTER_ALLOW && ipproto == IPPROTO_TCP) {
		struct flt_request *context_req = NULL;

		// add connection with state "SYN_SENT"
		status = add_tcp_conn(ote_conn, TCP_STATE_SYN_SENT);
		if (status != STATUS_SUCCESS) {
			KdPrint(("[tdi_fw] tdi_connect: add_conn: 0x%x!\n", status));
			
			result = FILTER_DENY;
			goto done;				// don't log this failure
		}

		if (rule.log >= RULE_LOG_LOG) {
			// set ote_conn->log_disconnect
			ote_conn->log_disconnect = (rule.log >= RULE_LOG_COUNT);

			// copy request for completion (LOG success or not)
			context_req = (struct flt_request *)malloc_np(sizeof(*context_req));
			if (context_req != NULL) {
				memcpy(context_req, &request, sizeof(*context_req));

				// don't free SID
				request.sid_a = NULL;

				// don't log request in this time
				rule.log = RULE_LOG_NOLOG;
			}
		}

		// set completion to add connection info to connection table
		completion->routine = tdi_connect_complete;
		completion->context = context_req;
	}

	// if logging is needed log request
	if (rule.log >= RULE_LOG_LOG)
		log_request(&request);

done:
	// cleanup
	if (ote_conn != NULL)
		KeReleaseSpinLock(&g_ot_hash_guard, irql);
	if (request.sid_a != NULL)
		free(request.sid_a);

	if (result != FILTER_ALLOW) {
		irp->IoStatus.Status = STATUS_REMOTE_NOT_LISTENING;	// set fake status
	}

	return result;
}
Exemple #14
0
/* query local address and port for connection */
void
update_conn_info(PDEVICE_OBJECT devobj, PFILE_OBJECT connobj)
{
	PIRP query_irp;
	PMDL mdl = NULL;
	struct uci_param *uci_param = NULL;

	// MUST be executed at PASSIVE_LEVEL

	if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
		// do it a bit later :-)
		struct delayed_ucn_param *ucn_param = (struct delayed_ucn_param *)malloc_np(sizeof(*ucn_param));
		if (ucn_param != NULL) {

			memset(ucn_param, 0, sizeof(*ucn_param));

			ucn_param->devobj = devobj;
			ucn_param->fileobj = connobj;

			ExInitializeWorkItem(&ucn_param->item, delayed_ucn, ucn_param);
			ExQueueWorkItem(&ucn_param->item, DelayedWorkQueue);	// DelayedWorkQueue a good value?

		} else {
			KdPrint(("[ndis_hk] tdi_connect_complete: malloc_np!\n"));
			// so we'll live without known local address :-(
		}
		return;
	}

	// we're at PASSIVE_LEVEL

	query_irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devobj, connobj, NULL, NULL);
	if (query_irp == NULL) {
		KdPrint(("[tdi_fw] update_conn_info: TdiBuildInternalDeviceControlIrp!\n"));
		goto done;
	}

	uci_param = (struct uci_param *)malloc_np(sizeof(*uci_param) + TDI_ADDRESS_INFO_MAX);
	if (uci_param == NULL) {
		KdPrint(("[tdi_fw] update_conn_info: malloc_np!\n"));
		goto done;
	}

	memset(uci_param, 0, sizeof(*uci_param) + TDI_ADDRESS_INFO_MAX);
	uci_param->connobj = connobj;

	mdl = IoAllocateMdl(uci_param->address, TDI_ADDRESS_INFO_MAX, FALSE, FALSE, NULL);
	if (mdl == NULL) {
		KdPrint(("[tdi_fw] update_conn_info: IoAllocateMdl!\n"));
		goto done;
	}
	MmBuildMdlForNonPagedPool(mdl);

	TdiBuildQueryInformation(query_irp, devobj, connobj,
		update_conn_info_complete, uci_param,
		TDI_QUERY_ADDRESS_INFO, mdl);

	IoCallDriver(devobj, query_irp);

	query_irp = NULL;
	mdl = NULL;
	uci_param = NULL;

done:
	// cleanup
	if (mdl != NULL)
		IoFreeMdl(mdl);
	if (uci_param != NULL)
		ExFreePool(uci_param);
	if (query_irp != NULL)
		IoCompleteRequest(query_irp, IO_NO_INCREMENT);
}
Exemple #15
0
NTSTATUS
tdi_event_receive(
    IN PVOID TdiEventContext,
    IN CONNECTION_CONTEXT ConnectionContext,
    IN ULONG ReceiveFlags,
    IN ULONG BytesIndicated,
    IN ULONG BytesAvailable,
    OUT ULONG *BytesTaken,
    IN PVOID Tsdu,
    OUT PIRP *IoRequestPacket)
{
	TDI_EVENT_CONTEXT *ctx = (TDI_EVENT_CONTEXT *)TdiEventContext;
	PFILE_OBJECT connobj = ot_find_conn_ctx(ctx->fileobj, ConnectionContext);
	NTSTATUS status;

	KdPrint(("[tdi_fw] tdi_event_receive: addrobj 0x%x; connobj: 0x%x; %u/%u; flags: 0x%x\n",
		ctx->fileobj, connobj, BytesIndicated, BytesAvailable, ReceiveFlags));

	status = ((PTDI_IND_RECEIVE)(ctx->old_handler))
		(ctx->old_context, ConnectionContext, ReceiveFlags, BytesIndicated,
		BytesAvailable, BytesTaken, Tsdu, IoRequestPacket);

	KdPrint(("[tdi_fw] tdi_event_receive: status 0x%x; BytesTaken: %u; Irp: 0x%x\n",
		status, *BytesTaken, *IoRequestPacket));

	if (*BytesTaken != 0) {
		struct ot_entry *ote_conn;
		KIRQL irql;

		ote_conn = ot_find_fileobj(connobj, &irql);
		if (ote_conn != NULL) {
			ULONG bytes = *BytesTaken;

			ote_conn->bytes_in += bytes;

			// traffic stats
			KeAcquireSpinLockAtDpcLevel(&g_traffic_guard);
			
			g_traffic[TRAFFIC_TOTAL_IN] += bytes;
			
			if (ote_conn->log_disconnect)
				g_traffic[TRAFFIC_COUNTED_IN] += bytes;
			
			KeReleaseSpinLockFromDpcLevel(&g_traffic_guard);

			KeReleaseSpinLock(&g_ot_hash_guard, irql);
		}
	}

	if (*IoRequestPacket != NULL) {
	    // got IRP. replace completion.
	    struct tdi_client_irp_ctx *new_ctx;
		PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(*IoRequestPacket);

		new_ctx = (struct tdi_client_irp_ctx *)malloc_np(sizeof(*new_ctx));
		if (new_ctx != NULL) {

            new_ctx->connobj = connobj;

			if (irps->CompletionRoutine != NULL) {
				new_ctx->completion = irps->CompletionRoutine;
				new_ctx->context = irps->Context;
				new_ctx->old_control = irps->Control;

			} else {

				// we don't use IoSetCompletionRoutine because it uses next not current location

				new_ctx->completion = NULL;
				new_ctx->context = NULL;

			}

			irps->CompletionRoutine = tdi_client_irp_complete;
			irps->Context = new_ctx;
			irps->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
		}
	}

	return status;
}
Exemple #16
0
NTSTATUS
ot_add_fileobj(PDEVICE_OBJECT devobj, PFILE_OBJECT fileobj, int fileobj_type, int ipproto,
			   CONNECTION_CONTEXT conn_ctx)		// must be called at PASSIVE_LEVEL!
{
	ULONG hash = CALC_HASH(fileobj);
	KIRQL irql;
	struct ot_entry *ote;
	NTSTATUS status;
	int i;
	SID_AND_ATTRIBUTES *sid_a;
	ULONG sid_a_size;

	if (fileobj == NULL)
		return STATUS_INVALID_PARAMETER_2;

	// while we're at PASSIVE_LEVEL get SID & attributes
	sid_a = get_current_sid_a(&sid_a_size);

	KeAcquireSpinLock(&g_ot_hash_guard, &irql);
	
	for (ote = g_ot_hash[hash]; ote != NULL; ote = ote->next)
		if (ote->fileobj == fileobj)
			break;

	if (ote == NULL) {
		ote = (struct ot_entry *)malloc_np(sizeof(*ote));
		if (ote == NULL) {
			KdPrint(("[tdi_fw] ot_add_fileobj: malloc_np\n"));
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto done;
		}
		memset(ote, 0, sizeof(*ote));

		ote->next = g_ot_hash[hash];
		g_ot_hash[hash] = ote;

		ote->fileobj = fileobj;
		for (i = 0; i < MAX_EVENT; i++)
			ote->ctx[i].fileobj = fileobj;

	} else {
		KdPrint(("[tdi_fw] ot_add_fileobj: reuse fileobj 0x%x\n", fileobj));

        ot_cleanup_ote(ote);
	}

	ote->signature = 'OTE ';
	ote->pid = (ULONG)PsGetCurrentProcessId();

	// save SID & attributes
	ote->sid_a = sid_a;
	ote->sid_a_size = sid_a_size;
	sid_a = NULL;

	ote->devobj = devobj;

	ote->type = fileobj_type;
	ote->ipproto = ipproto;
	ote->conn_ctx = conn_ctx;

	status = STATUS_SUCCESS;

done:
	// cleanup
	KeReleaseSpinLock(&g_ot_hash_guard, irql);
	if (sid_a != NULL)
		free(sid_a);

	return status;
}