📄 rdpdr.c
字号:
{ case IRP_MN_QUERY_DIRECTORY: in_uint32_le(s, info_level); in_uint8s(s, 1); in_uint32_le(s, length); in_uint8s(s, 0x17); if (length && length < 2 * 255) { rdp_in_unistr(s, filename, length); convert_to_unix_filename(filename); } else { filename[0] = 0; } out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_directory(file, info_level, filename, &out); result = buffer_len = out.p - out.data; if (!buffer_len) buffer_len++; break; case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* JIF unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */ in_uint32_le(s, info_level); /* notify mask */ g_notify_stamp = True; status = disk_create_notify(file, info_level); result = 0; if (status == STATUS_PENDING) add_async_iorequest(device, file, id, major, length, fns, 0, 0, NULL, 0); break; default: status = STATUS_INVALID_PARAMETER; /* JIF */ unimpl("IRP major=0x%x minor=0x%x\n", major, minor); } break; case IRP_MJ_DEVICE_CONTROL: if (!fns->device_control) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, bytes_out); in_uint32_le(s, bytes_in); in_uint32_le(s, request); in_uint8s(s, 0x14); buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14); if (!buffer) { status = STATUS_CANCELLED; break; } out.data = out.p = buffer; out.size = sizeof(buffer); status = fns->device_control(file, request, s, &out); result = buffer_len = out.p - out.data; /* Serial SERIAL_WAIT_ON_MASK */ if (status == STATUS_PENDING) { if (add_async_iorequest (device, file, id, major, length, fns, 0, 0, NULL, 0)) { status = STATUS_PENDING; break; } } break; case IRP_MJ_LOCK_CONTROL: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); /* FIXME: Perhaps consider actually *do* something here :-) */ status = STATUS_SUCCESS; result = buffer_len = out.p - out.data; break; default: unimpl("IRP major=0x%x minor=0x%x\n", major, minor); break; } if (status != STATUS_PENDING) { rdpdr_send_completion(device, id, status, result, buffer, buffer_len); } if (buffer) xfree(buffer); buffer = NULL;}static voidrdpdr_send_clientcapabilty(void){ uint8 magic[4] = "rDPC"; STREAM s; s = channel_init(rdpdr_channel, 0x50); out_uint8a(s, magic, 4); out_uint32_le(s, 5); /* count */ out_uint16_le(s, 1); /* first */ out_uint16_le(s, 0x28); /* length */ out_uint32_le(s, 1); out_uint32_le(s, 2); out_uint16_le(s, 2); out_uint16_le(s, 5); out_uint16_le(s, 1); out_uint16_le(s, 5); out_uint16_le(s, 0xFFFF); out_uint16_le(s, 0); out_uint32_le(s, 0); out_uint32_le(s, 3); out_uint32_le(s, 0); out_uint32_le(s, 0); out_uint16_le(s, 2); /* second */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 3); /* third */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 4); /* fourth */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 5); /* fifth */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); s_mark_end(s); channel_send(s, rdpdr_channel);}static voidrdpdr_process(STREAM s){ uint32 handle; uint8 *magic;#if WITH_DEBUG_RDP5 printf("--- rdpdr_process ---\n"); hexdump(s->p, s->end - s->p);#endif in_uint8p(s, magic, 4); if ((magic[0] == 'r') && (magic[1] == 'D')) { if ((magic[2] == 'R') && (magic[3] == 'I')) { rdpdr_process_irp(s); return; } if ((magic[2] == 'n') && (magic[3] == 'I')) { rdpdr_send_connect(); rdpdr_send_name(); return; } if ((magic[2] == 'C') && (magic[3] == 'C')) { /* connect from server */ rdpdr_send_clientcapabilty(); rdpdr_send_available(); return; } if ((magic[2] == 'r') && (magic[3] == 'd')) { /* connect to a specific resource */ in_uint32(s, handle);#if WITH_DEBUG_RDP5 DEBUG(("RDPDR: Server connected to resource %d\n", handle));#endif return; } if ((magic[2] == 'P') && (magic[3] == 'S')) { /* server capability */ return; } } if ((magic[0] == 'R') && (magic[1] == 'P')) { if ((magic[2] == 'C') && (magic[3] == 'P')) { printercache_process(s); return; } } unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);}BOOLrdpdr_init(){ if (g_num_devices > 0) { rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process); } return (rdpdr_channel != NULL);}/* Add file descriptors of pending io request to select() */voidrdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout){ uint32 select_timeout = 0; /* Timeout value to be used for select() (in millisecons). */ struct async_iorequest *iorq; char c; iorq = g_iorequest; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_READ: /* Is this FD valid? FDs will be invalid when reconnecting. FIXME: Real support for reconnects. */ FD_SET(iorq->fd, rfds); *n = MAX(*n, iorq->fd); /* Check if io request timeout is smaller than current (but not 0). */ if (iorq->timeout && (select_timeout == 0 || iorq->timeout < select_timeout)) { /* Set new timeout */ select_timeout = iorq->timeout; g_min_timeout_fd = iorq->fd; /* Remember fd */ tv->tv_sec = select_timeout / 1000; tv->tv_usec = (select_timeout % 1000) * 1000; *timeout = True; break; } if (iorq->itv_timeout && iorq->partial_len > 0 && (select_timeout == 0 || iorq->itv_timeout < select_timeout)) { /* Set new timeout */ select_timeout = iorq->itv_timeout; g_min_timeout_fd = iorq->fd; /* Remember fd */ tv->tv_sec = select_timeout / 1000; tv->tv_usec = (select_timeout % 1000) * 1000; *timeout = True; break; } break; case IRP_MJ_WRITE: /* FD still valid? See above. */ if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF)) break; FD_SET(iorq->fd, wfds); *n = MAX(*n, iorq->fd); break; case IRP_MJ_DEVICE_CONTROL: if (select_timeout > 5) select_timeout = 5; /* serial event queue */ break; } } iorq = iorq->next; }}struct async_iorequest *rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq){ if (!iorq) return NULL; if (iorq->buffer) xfree(iorq->buffer); if (prev) { prev->next = iorq->next; xfree(iorq); iorq = prev->next; } else { /* Even if NULL */ g_iorequest = iorq->next; xfree(iorq); iorq = NULL; } return iorq;}/* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */static void_rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out){ NTSTATUS status; uint32 result = 0; DEVICE_FNS *fns; struct async_iorequest *iorq; struct async_iorequest *prev; uint32 req_size = 0; uint32 buffer_len; struct stream out; uint8 *buffer = NULL; if (timed_out) { /* check serial iv_timeout */ iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd == g_min_timeout_fd) { if ((iorq->partial_len > 0) && (g_rdpdr_device[iorq->device].device_type == DEVICE_TYPE_SERIAL)) { /* iv_timeout between 2 chars, send partial_len */ /*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */ rdpdr_send_completion(iorq->device, iorq->id, STATUS_SUCCESS, iorq->partial_len, iorq->buffer, iorq->partial_len); iorq = rdpdr_remove_iorequest(prev, iorq); return; } else { break; } } else { break; } prev = iorq; if (iorq) iorq = iorq->next; } rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT); return; } iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_READ: if (FD_ISSET(iorq->fd, rfds)) { /* Read the data */ fns = iorq->fns; req_size = (iorq->length - iorq->partial_len) > 8192 ? 8192 : (iorq->length - iorq->partial_len); /* never read larger chunks than 8k - chances are that it will block */ status = fns->read(iorq->fd, iorq->buffer + iorq->partial_len, req_size, iorq->offset, &result); if ((long) result > 0) { iorq->partial_len += result; iorq->offset += result; }#if WITH_DEBUG_RDP5 DEBUG(("RDPDR: %d bytes of data read\n", result));#endif /* only delete link if all data has been transfered */ /* or if result was 0 and status success - EOF */ if ((iorq->partial_len == iorq->length) || (result == 0)) {#if WITH_DEBUG_RDP5 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));#endif rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, iorq->buffer, iorq->partial_len); iorq = rdpdr_remove_iorequest(prev, iorq); } } break; case IRP_MJ_WRITE: if (FD_ISSET(iorq->fd, wfds)) { /* Write data. */ fns = iorq->fns; req_size = (iorq->length - iorq->partial_len) > 8192 ? 8192 : (iorq->length - iorq->partial_len); /* never write larger chunks than 8k - chances are that it will block */ status = fns->write(iorq->fd, iorq->buffer + iorq->partial_len, req_size, iorq->offset, &result); if ((long) result > 0) { iorq->partial_len += result; iorq->offset += result; }#if WITH_DEBUG_RDP5 DEBUG(("RDPDR: %d bytes of data written\n", result));#endif /* only delete link if all data has been transfered */ /* or we couldn't write */ if ((iorq->partial_len == iorq->length) || (result == 0)) {#if WITH_DEBUG_RDP5 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));#endif rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, (uint8 *) "", 1); iorq = rdpdr_remove_iorequest(prev, iorq); } } break; case IRP_MJ_DEVICE_CONTROL: if (serial_get_event(iorq->fd, &result)) { buffer = (uint8 *) xrealloc((void *) buffer, 0x14); out.data = out.p = buffer; out.size = sizeof(buffer); out_uint32_le(&out, result); result = buffer_len = out.p - out.data; status = STATUS_SUCCESS; rdpdr_send_completion(iorq->device, iorq->id, status, result, buffer, buffer_len); xfree(buffer); iorq = rdpdr_remove_iorequest(prev, iorq); } break; } } prev = iorq; if (iorq) iorq = iorq->next; } /* Check notify */ iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_DIRECTORY_CONTROL: if (g_rdpdr_device[iorq->device].device_type == DEVICE_TYPE_DISK) { if (g_notify_stamp) { g_notify_stamp = False; status = disk_check_notify(iorq->fd); if (status != STATUS_PENDING) { rdpdr_send_completion(iorq->device, iorq->id, status, 0, NULL, 0); iorq = rdpdr_remove_iorequest(prev, iorq); } } } break; } } prev = iorq; if (iorq) iorq = iorq->next; }}voidrdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out){ fd_set dummy; FD_ZERO(&dummy); /* fist check event queue only, any serial wait event must be done before read block will be sent */ _rdpdr_check_fds(&dummy, &dummy, False); _rdpdr_check_fds(rfds, wfds, timed_out);}/* Abort a pending io request for a given handle and major */BOOLrdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status){ uint32 result; struct async_iorequest *iorq; struct async_iorequest *prev; iorq = g_iorequest; prev = NULL; while (iorq != NULL) { /* Only remove from table when major is not set, or when correct major is supplied. Abort read should not abort a write io request. */ if ((iorq->fd == fd) && (major == 0 || iorq->major == major)) { result = 0; rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "", 1); iorq = rdpdr_remove_iorequest(prev, iorq); return True; } prev = iorq; iorq = iorq->next; } return False;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -