void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus) { struct stream *s; int bytes; if (IoStatus != NT_STATUS_SUCCESS) { FUSE_DATA *fuse_data = dev_redir_fuse_data_dequeue(irp); if (fuse_data) { xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); free(fuse_data); } devredir_irp_delete(irp); return; } xstream_new(s, 1024); irp->completion_type = CID_RMDIR_OR_FILE_RESP; devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_SET_INFORMATION, 0); xstream_wr_u32_le(s, FileDispositionInformation); xstream_wr_u32_le(s, 0); /* length is zero */ xstream_seek(s, 24); /* padding */ /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return; }
int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, tui32 DeviceId, tui32 FileId, tui32 CompletionId, tui32 MajorFunction, tui32 MinorFunc, int pad_len) { struct stream *s; int bytes; xstream_new(s, 1024); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, CompletionId, MajorFunction, MinorFunc); if (pad_len) xstream_seek(s, pad_len); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); log_debug("sent close request; expect CID_FILE_CLOSE"); return 0; }
void dev_redir_send_server_core_cap_req() { struct stream *s; int bytes; xstream_new(s, 1024); /* setup header */ xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_SERVER_CAPABILITY); xstream_wr_u16_le(s, 5); /* num of caps we are sending */ xstream_wr_u16_le(s, 0x0000); /* padding */ /* setup general capability */ xstream_wr_u16_le(s, CAP_GENERAL_TYPE); /* CapabilityType */ xstream_wr_u16_le(s, 44); /* CapabilityLength - len of this */ /* CAPABILITY_SET in bytes, inc */ /* the header */ xstream_wr_u32_le(s, 2); /* Version */ xstream_wr_u32_le(s, 2); /* O.S type */ xstream_wr_u32_le(s, 0); /* O.S version */ xstream_wr_u16_le(s, 1); /* protocol major version */ xstream_wr_u16_le(s, g_client_rdp_version); /* protocol minor version */ xstream_wr_u32_le(s, 0xffff); /* I/O code 1 */ xstream_wr_u32_le(s, 0); /* I/O code 2 */ xstream_wr_u32_le(s, 7); /* Extended PDU */ xstream_wr_u32_le(s, 0); /* extra flags 1 */ xstream_wr_u32_le(s, 0); /* extra flags 2 */ xstream_wr_u32_le(s, 2); /* special type device cap */ /* setup printer capability */ xstream_wr_u16_le(s, CAP_PRINTER_TYPE); xstream_wr_u16_le(s, 8); xstream_wr_u32_le(s, 1); /* setup serial port capability */ xstream_wr_u16_le(s, CAP_PORT_TYPE); xstream_wr_u16_le(s, 8); xstream_wr_u32_le(s, 1); /* setup file system capability */ xstream_wr_u16_le(s, CAP_DRIVE_TYPE); /* CapabilityType */ xstream_wr_u16_le(s, 8); /* CapabilityLength - len of this */ /* CAPABILITY_SET in bytes, inc */ /* the header */ xstream_wr_u32_le(s, 2); /* Version */ /* setup smart card capability */ xstream_wr_u16_le(s, CAP_SMARTCARD_TYPE); xstream_wr_u16_le(s, 8); xstream_wr_u32_le(s, 1); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); }
// LK_TODO Path needs to be Unicode void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, tui32 InitialQuery, char *Path) { struct stream *s; int bytes; char upath[4096]; // LK_TODO need to malloc this int path_len = 0; /* during Initial Query, Path cannot be NULL */ if (InitialQuery) { if (Path == NULL) { return; } /* Path in unicode needs this much space */ path_len = ((g_mbstowcs(NULL, Path, 0) * sizeof(twchar)) / 2) + 2; devredir_cvt_to_unicode(upath, Path); } xstream_new(s, 1024 + path_len); irp->completion_type = CID_DIRECTORY_CONTROL; devredir_insert_DeviceIoRequest(s, device_id, irp->FileId, irp->CompletionId, IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY); #ifdef USE_SHORT_NAMES_IN_DIR_LISTING xstream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */ #else xstream_wr_u32_le(s, FileDirectoryInformation); /* FsInformationClass */ #endif xstream_wr_u8(s, InitialQuery); /* InitialQuery */ if (!InitialQuery) { xstream_wr_u32_le(s, 0); /* PathLength */ xstream_seek(s, 23); } else { xstream_wr_u32_le(s, path_len); /* PathLength */ xstream_seek(s, 23); /* Padding */ xstream_wr_string(s, upath, path_len); } /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); }
int APP_CC dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, const char *buf, int Length, tui64 Offset) { struct stream *s; IRP *irp; IRP *new_irp; int bytes; log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld", DeviceId, FileId, Length, Offset); xstream_new(s, 1024 + Length); if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) { log_error("no IRP found with FileId = %d", FileId); xfuse_devredir_cb_write_file(fusep, NULL, 0); xstream_free(s); return -1; } /* create a new IRP for this request */ if ((new_irp = devredir_irp_clone(irp)) == NULL) { /* system out of memory */ xfuse_devredir_cb_write_file(fusep, NULL, 0); xstream_free(s); return -1; } new_irp->FileId = 0; new_irp->completion_type = CID_WRITE; new_irp->CompletionId = g_completion_id++; devredir_fuse_data_enqueue(new_irp, fusep); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, new_irp->CompletionId, IRP_MJ_WRITE, 0); xstream_wr_u32_le(s, Length); xstream_wr_u64_le(s, Offset); xstream_seek(s, 20); /* padding */ /* now insert real data */ xstream_copyin(s, buf, Length); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
void APP_CC devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus) { struct stream *s; int bytes; int sblen; /* SetBuffer length */ int flen; /* FileNameLength */ if (IoStatus != NT_STATUS_SUCCESS) { log_debug("rename returned with IoStatus=0x%x", IoStatus); FUSE_DATA *fuse_data = devredir_fuse_data_dequeue(irp); if (fuse_data) { xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); free(fuse_data); } devredir_irp_delete(irp); return; } /* Path in unicode needs this much space */ flen = ((g_mbstowcs(NULL, irp->gen_buf, 0) * sizeof(twchar)) / 2) + 2; sblen = 6 + flen; xstream_new(s, 1024 + flen); irp->completion_type = CID_RENAME_FILE_RESP; devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_SET_INFORMATION, 0); xstream_wr_u32_le(s, FileRenameInformation); xstream_wr_u32_le(s, sblen); /* number of bytes after padding */ xstream_seek(s, 24); /* padding */ xstream_wr_u8(s, 1); /* ReplaceIfExists */ xstream_wr_u8(s, 0); /* RootDirectory */ xstream_wr_u32_le(s, flen); /* FileNameLength */ /* filename in unicode */ devredir_cvt_to_unicode(s->p, irp->gen_buf); /* UNICODE_TODO */ xstream_seek(s, flen); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return; }
int APP_CC devredir_file_read(void *fusep, tui32 DeviceId, tui32 FileId, tui32 Length, tui64 Offset) { struct stream *s; IRP *irp; IRP *new_irp; int bytes; xstream_new(s, 1024); if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) { log_error("no IRP found with FileId = %d", FileId); xfuse_devredir_cb_read_file(fusep, NULL, 0); xstream_free(s); return -1; } /* create a new IRP for this request */ if ((new_irp = devredir_irp_clone(irp)) == NULL) { /* system out of memory */ xfuse_devredir_cb_read_file(fusep, NULL, 0); xstream_free(s); return -1; } new_irp->FileId = 0; new_irp->completion_type = CID_READ; new_irp->CompletionId = g_completion_id++; devredir_fuse_data_enqueue(new_irp, fusep); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, new_irp->CompletionId, IRP_MJ_READ, 0); xstream_wr_u32_le(s, Length); xstream_wr_u64_le(s, Offset); xstream_seek(s, 20); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
static struct stream * APP_CC scard_make_new_ioctl(IRP *irp, tui32 ioctl) { /* * format of device control request * * DeviceIoRequest * u16 RDPDR_CTYP_CORE * u16 PAKID_CORE_DEVICE_IOREQUEST * u32 DeviceId * u32 FileId * u32 CompletionId * u32 MajorFunction * u32 MinorFunction * * u32 OutputBufferLength SHOULD be 2048 * u32 InputBufferLength * u32 IoControlCode * 20 bytes padding * xx bytes InputBuffer (variable) */ struct stream *s; xstream_new(s, 1024 * 3); if (s == NULL) { log_error("system out of memory"); return s; } devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_DEVICE_CONTROL, 0); xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ xstream_seek(s, 20); /* padding */ /* [MS-RPCE] 2.2.6.1 */ xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ xstream_wr_u32_le(s, 0xcccccccc); /* filler */ return s; }
void dev_redir_send_server_user_logged_on() { struct stream *s; int bytes; xstream_new(s, 1024); /* setup stream */ xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_USER_LOGGEDON); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); }
int APP_CC dev_redir_init(void) { struct stream *s; int bytes; int fd; union _u { tui32 clientID; char buf[4]; } u; /* get a random number that will act as a unique clientID */ if ((fd = open("/dev/urandom", O_RDONLY)) != -1) { if (read(fd, u.buf, 4) != 4) { } close(fd); } else { /* /dev/urandom did not work - use address of struct s */ tui64 u64 = (tui64) (tintptr) &s; u.clientID = (tui32) u64; } /* setup stream */ xstream_new(s, 1024); /* initiate drive redirection protocol by sending Server Announce Req */ xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_SERVER_ANNOUNCE); xstream_wr_u16_le(s, 0x0001); /* server major ver */ xstream_wr_u16_le(s, 0x000C); /* server minor ver - pretend 2 b Win 7 */ xstream_wr_u32_le(s, u.clientID); /* unique ClientID */ /* send data to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
int dev_redir_send_drive_create_request(tui32 device_id, const char *path, tui32 DesiredAccess, tui32 CreateOptions, tui32 CreateDisposition, tui32 completion_id) { struct stream *s; int bytes; int len; log_debug("DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", DesiredAccess, CreateDisposition, CreateOptions); /* path in unicode needs this much space */ len = ((g_mbstowcs(NULL, path, 0) * sizeof(twchar)) / 2) + 2; xstream_new(s, 1024 + len); devredir_insert_DeviceIoRequest(s, device_id, 0, completion_id, IRP_MJ_CREATE, 0); xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */ xstream_wr_u32_le(s, 0); /* AllocationSize high unused */ xstream_wr_u32_le(s, 0); /* AllocationSize low unused */ xstream_wr_u32_le(s, 0); /* FileAttributes */ xstream_wr_u32_le(s, 3); /* SharedAccess LK_TODO */ xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */ xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */ xstream_wr_u32_le(s, len); /* PathLength */ devredir_cvt_to_unicode(s->p, path); /* path in unicode */ xstream_seek(s, len); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
int dnsrv_child_main(dns_io di) { pool p = pool_new(); xstream xs = xstream_new(p, dnsrv_child_process_xstream_io, di); int len; char readbuf[1024]; sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGHUP); sigprocmask(SIG_BLOCK, &sigs, NULL); log_debug(ZONE,"DNSRV CHILD: starting"); /* Transmit stream header */ write(di->out, "<stream>", 8); /* Loop forever, processing requests and feeding them to the xstream*/ while (1) { len = read(di->in, &readbuf, 1024); if (len <= 0) { log_debug(ZONE,"dnsrv: Read error on coprocess(%d): %d %s",getppid(),errno,strerror(errno)); break; } log_debug(ZONE, "DNSRV CHILD: Read from buffer: %.*s",len,readbuf); if (xstream_eat(xs, readbuf, len) > XSTREAM_NODE) { log_debug(ZONE, "DNSRV CHILD: xstream died"); break; } } /* child is out of loop... normal exit so parent will start us again */ log_debug(ZONE, "DNSRV CHILD: out of loop.. exiting normal"); pool_free(p); exit(0); return 0; }
void devredir_send_server_device_announce_resp(tui32 device_id) { struct stream *s; int bytes; xstream_new(s, 1024); /* setup stream */ xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY); xstream_wr_u32_le(s, device_id); xstream_wr_u32_le(s, 0); /* ResultCode */ /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); }
void dev_redir_send_server_clientID_confirm() { struct stream *s; int bytes; xstream_new(s, 1024); /* setup stream */ xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_CLIENTID_CONFIRM); xstream_wr_u16_le(s, 0x0001); xstream_wr_u16_le(s, g_client_rdp_version); xstream_wr_u32_le(s, g_clientID); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); }
Stream *stream_connect(char *host,int port,int nonblock,xstream_onNode cb){ Stream *s; struct hostent *he; int optval; int r; int fd; s=g_new0(Stream,1); fd=socket(PF_INET,SOCK_STREAM,0); if (!fd){ error_exit(L_("socket: %s"),g_strerror(errno)); g_free(s); return NULL; } s->ioch=g_io_channel_unix_new(fd); g_io_channel_set_encoding(s->ioch,NULL,NULL); g_io_channel_set_buffered(s->ioch,0); s->sa.sin_family=AF_INET; s->sa.sin_port=htons(port); he=gethostbyname(host); if (he == NULL){ g_warning(N_("Unknown host: %s"),host); g_free(s); return NULL; } s->sa.sin_addr = *(struct in_addr *) he->h_addr; optval=1; r=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)); if (r<0){ g_warning("setsockopt(fd,SOL_SOCKET,SO_REUSEADDR...): %s",g_strerror(errno)); g_free(s); return NULL; } optval=1; r=setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,&optval,sizeof(optval)); if (r<0){ g_warning("setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE...): %s",g_strerror(errno)); g_free(s); return NULL; } if (nonblock) if (stream_set_nonblocking(s,1)){ g_free(s); return NULL; } r=connect(fd, (struct sockaddr *) &s->sa, sizeof (s->sa)); if (r<0 && nonblock && errno==EINPROGRESS){ s->connecting=1; } else{ if (r<0){ error_exit(L_("connect: %s"),g_strerror(errno)); g_free(s); return NULL; } s->connected=1; } s->dest=g_strdup(host); /* FIXME */ s->err_watch=g_io_add_watch(s->ioch,G_IO_ERR|G_IO_HUP|G_IO_NVAL,stream_io_error,s); if (s->connecting) s->write_watch=g_io_add_watch(s->ioch,G_IO_OUT,stream_io_connect,s); else s->read_watch=g_io_add_watch(s->ioch,G_IO_IN,stream_io_read,s); s->xs=xstream_new(pool_new(),cb,s); if (s->connected) stream_write_hello(s); return s; }
void* dnsrv_process_io(void* threadarg) { /* Get DNS IO info */ dns_io di = (dns_io)threadarg; int retcode = 0; int pid = 0; int readlen = 0; char readbuf[1024]; xstream xs = NULL; sigset_t sigs; #ifdef __CYGWIN__ dns_resend_list iternode = NULL; #endif sigemptyset(&sigs); sigaddset(&sigs, SIGHUP); sigprocmask(SIG_BLOCK, &sigs, NULL); /* Allocate an xstream for talking to the process */ xs = xstream_new(di->mempool, dnsrv_process_xstream_io, di); /* Transmit root element to coprocess */ pth_write(di->out, "<stream>", 8); /* Transmit resend entries to coprocess */ #ifdef __CYGWIN__ iternode = di->svclist; while (iternode != NULL) { if (iternode->service) { sprintf(readbuf, "<resend service=\"%s\">%s</resend>", iternode->service, iternode->host); } else { sprintf(readbuf, "<resend>%s</resend>", iternode->host); } pth_write(di->out, readbuf, strlen(readbuf)); iternode = iternode->next; } #endif /* Loop forever */ while (1) { /* Hostname lookup completed from coprocess */ readlen = pth_read(di->in, readbuf, sizeof(readbuf)); if (readlen <= 0) { log_debug(ZONE,"dnsrv: Read error on coprocess: %d %s",errno,strerror(errno)); break; } if (xstream_eat(xs, readbuf, readlen) > XSTREAM_NODE) break; } /* If we reached this point, the coprocess probably is dead, so process the SIG_CHLD */ pid = pth_waitpid(di->pid, &retcode, 0); if(pid == -1) { log_debug(ZONE, "pth_waitpid returned -1: %s", strerror(errno)); } else if(pid == 0) { log_debug(ZONE, "no child available to call waitpid on"); } else { log_debug(ZONE, "pid %d, exit status: %d", pid, WEXITSTATUS(retcode)); } /* Cleanup */ close(di->in); close(di->out); di->out = 0; log_debug(ZONE,"child returned %d",WEXITSTATUS(retcode)); if(WIFEXITED(retcode)) /* if the child exited normally */ { log_debug(ZONE, "child being restarted..."); /* Fork out resolver function/process */ di->pid = dnsrv_fork_and_capture(dnsrv_child_main, di); /* Start IO thread */ pth_spawn(PTH_ATTR_DEFAULT, dnsrv_process_io, (void*)di); return NULL; } log_debug(ZONE, "child dying..."); return NULL; }
int APP_CC dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { struct stream *ls; tui16 comp_type; tui16 pktID; tui16 minor_ver; int rv = 0; /* * handle packet fragmentation */ if ((chan_flags & 3) == 3) { /* all data contained in one packet */ ls = s; } else { /* is this is the first packet? */ if (chan_flags & 1) xstream_new(g_input_stream, total_length); xstream_copyin(g_input_stream, s->p, length); /* in last packet, chan_flags & 0x02 will be true */ if ((chan_flags & 2) == 0) return 0; g_input_stream->p = g_input_stream->data; ls = g_input_stream; } /* read header from incoming data */ xstream_rd_u16_le(ls, comp_type); xstream_rd_u16_le(ls, pktID); /* for now we only handle core type, not printers */ if (comp_type != RDPDR_CTYP_CORE) { log_error("invalid component type in response; expected 0x%x got 0x%x", RDPDR_CTYP_CORE, comp_type); rv = -1; goto done; } /* figure out what kind of response we have gotten */ switch (pktID) { case PAKID_CORE_CLIENTID_CONFIRM: xstream_seek(ls, 2); /* major version, we ignore it */ xstream_rd_u16_le(ls, minor_ver); xstream_rd_u32_le(ls, g_clientID); g_client_rdp_version = minor_ver; switch (minor_ver) { case RDP_CLIENT_50: break; case RDP_CLIENT_51: break; case RDP_CLIENT_52: break; case RDP_CLIENT_60_61: break; } // LK_TODO dev_redir_send_server_clientID_confirm(); break; case PAKID_CORE_CLIENT_NAME: /* client is telling us its computer name; do we even care? */ /* let client know loggin was successful */ dev_redir_send_server_user_logged_on(); usleep(1000 * 100); /* let client know our capabilites */ dev_redir_send_server_core_cap_req(); /* send confirm clientID */ dev_redir_send_server_clientID_confirm(); break; case PAKID_CORE_CLIENT_CAPABILITY: dev_redir_proc_client_core_cap_resp(ls); break; case PAKID_CORE_DEVICELIST_ANNOUNCE: devredir_proc_client_devlist_announce_req(ls); break; case PAKID_CORE_DEVICE_IOCOMPLETION: dev_redir_proc_device_iocompletion(ls); break; default: log_error("got unknown response 0x%x", pktID); break; } done: if (g_input_stream) { xstream_free(g_input_stream); g_input_stream = NULL; } return rv; }