xrdp_0.9.12.orig.tar.gz
mirabilos authored 4 years ago
mirabilos committed 4 years ago
0 | # Release notes for xrdp v0.9.9 (2018/12/25) | |
1 | ||
2 | # Release cycle | |
0 | # Release notes for xrdp v0.9.12 (2019/12/28) | |
1 | ||
2 | ## Bug fixes | |
3 | * Fix "The log reference is NULL" error when sesman startup #1425 | |
4 | * Fix behavior when shmem_id changes #1439 | |
5 | * Make vsock config accept -1 for cid and port #1441 | |
6 | * Cleanup refresh rect and check stream bounds #1437 | |
7 | * Significant improvements in drive redirection #1449 | |
8 | * Fix build on macOS Catalina #1462 | |
9 | ||
10 | ## Other changes | |
11 | * Proprietary microphone redirection via rdpsnd is now default off | |
12 | RDP compatible microphone redirection is on instead #1427 | |
13 | * Skip connecting to chansrv when no channels enabled #1393 | |
14 | * Add openSUSE's pam rules #1442 | |
15 | * Do not terminate xrdp daemon when caught SIGHUP #1319 | |
16 | ||
17 | ## Known issues | |
18 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
19 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
20 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
21 | ||
22 | # Release notes for xrdp v0.9.11 (2019/08/19) | |
23 | ||
24 | ## New features | |
25 | * Suppress output (do not draw screen when client window is minimized) #1330 | |
26 | * Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369 | |
27 | * Now xrdp can listen on more than one port #1124 #1366 | |
28 | ||
29 | ## Bug fixes | |
30 | * Fix the issue audio redirection sometimes sounds with long delay #1363 | |
31 | * Check term event for more responsive shutdown #1372 | |
32 | ||
33 | ## Known issues | |
34 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
35 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
36 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
37 | ||
38 | ----------------------- | |
39 | ||
40 | # Release notes for xrdp v0.9.11 (2019/08/19) | |
41 | ||
42 | ## New features | |
43 | * Suppress output (do not draw screen when client window is minimized) #1330 | |
44 | * Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369 | |
45 | * Now xrdp can listen on more than one port #1124 #1366 | |
46 | ||
47 | ## Bug fixes | |
48 | * Fix the issue audio redirection sometimes sounds with long delay #1363 | |
49 | * Check term event for more responsive shutdown #1372 | |
50 | ||
51 | ## Known issues | |
52 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
53 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
54 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
55 | ||
56 | ----------------------- | |
57 | ||
58 | # Release notes for xrdp v0.9.10 (2019/04/18) | |
59 | ||
60 | ## Special thanks | |
61 | Thank you for matt335672 contributing to lots of improvements in drive redirection! | |
62 | ||
63 | ## New features | |
64 | * Restrict outbound (server->client) clipboard transfer, configured in `sesman.ini` #1298 | |
65 | ||
66 | ## Bug fixes | |
67 | * Fix the issue libscp v1 not setting width but height twice #1293 | |
68 | * Fix the issue reconnecting to session causes duplicate drive entries in fuse fs #1299 | |
69 | * Fix default_wm and reconnect_sh refer wrong path after sesman caught SIGUP #1315 #1331 | |
70 | * Shutdown xrdp more responsively #1325 | |
71 | * Improve remote file lookup in drive redirection #996 #1327 | |
72 | * Overwriting & appending to existing files is are now supported #1327 | |
73 | ||
74 | ## Other changes | |
75 | * Add Danish Keyboard #1290 | |
76 | * Put xrdp- prefix to some executables appear in man page #1313 | |
77 | * Replace some URLs from SF.net to xrdp.org #1313 | |
78 | ||
79 | ## Known issues | |
80 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
81 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
82 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
83 | ||
84 | ----------------------- | |
85 | ||
86 | ## Release notes for xrdp v0.9.9 (2018/12/25) | |
87 | ||
88 | ## Release cycle | |
3 | 89 | From the next release, release cycle will be changed from quarterly to every |
4 | 90 | 4 months. xrdp will be released in April, August, December. |
5 | 91 | |
6 | # New features | |
92 | ## New features | |
7 | 93 | * Disconnection by idle timeout (requires xorgxrdp v0.2.9 or later) #1227 |
8 | 94 | * Glyph cache v2 (fixes no font issue on iOS/macOS/Android client) #367 #1235 |
9 | 95 | |
10 | # Bug fixes | |
96 | ## Bug fixes | |
11 | 97 | * Fix xrdp-chansrv crashes caused in drive redirection #1202 #1225 |
12 | 98 | * Fix build with FDK AAC v2 #1257 |
13 | 99 | * Do not enable RemoteApp if the INFO_RAIL flag is not set (RDP-RDP proxy) #1253 |
14 | 100 | |
15 | # Other changes | |
101 | ## Other changes | |
16 | 102 | * Add Spanish Latin Amarican keyboard #1237 #1240 #1244 |
17 | 103 | * Dynamic channel improvements #1222 #1224 |
18 | 104 | * Remove some deprecated sesman session types #1232 |
19 | 105 | * Refactoring and cleanups |
20 | 106 | |
21 | # Known issues | |
22 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
23 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
24 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
107 | ## Known issues | |
108 | * FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to | |
109 | xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 | |
110 | * Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 | |
111 | ||
112 | ----------------------- | |
25 | 113 | |
26 | 114 | # Release notes for xrdp v0.9.8 (2018/09/25) |
27 | 115 |
1 | 1 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp) |
2 | 2 | ![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg) |
3 | 3 | |
4 | *Current Version:* 0.9.9 | |
4 | *Current Version:* 0.9.12 | |
5 | 5 | |
6 | 6 | # xrdp - an open source RDP server |
7 | 7 |
1039 | 1039 | return -1; |
1040 | 1040 | #endif |
1041 | 1041 | } |
1042 | ||
1043 | /*****************************************************************************/ | |
1044 | int | |
1045 | g_sck_vsock_bind_address(int sck, const char *port, const char *address) | |
1046 | { | |
1047 | #if defined(XRDP_ENABLE_VSOCK) | |
1048 | struct sockaddr_vm s; | |
1049 | ||
1050 | g_memset(&s, 0, sizeof(struct sockaddr_vm)); | |
1051 | s.svm_family = AF_VSOCK; | |
1052 | s.svm_port = atoi(port); | |
1053 | s.svm_cid = atoi(address); | |
1054 | ||
1055 | return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_vm)); | |
1056 | #else | |
1057 | return -1; | |
1058 | #endif | |
1059 | } | |
1060 | ||
1042 | 1061 | |
1043 | 1062 | #if defined(XRDP_ENABLE_IPV6) |
1044 | 1063 | /*****************************************************************************/ |
3822 | 3841 | return 0; |
3823 | 3842 | } |
3824 | 3843 | |
3844 | /*****************************************************************************/ | |
3845 | int | |
3846 | g_tcp4_socket(void) | |
3847 | { | |
3848 | #if defined(XRDP_ENABLE_IPV6ONLY) | |
3849 | return -1; | |
3850 | #else | |
3851 | int rv; | |
3852 | int option_value; | |
3853 | socklen_t option_len; | |
3854 | ||
3855 | rv = socket(AF_INET, SOCK_STREAM, 0); | |
3856 | if (rv < 0) | |
3857 | { | |
3858 | return -1; | |
3859 | } | |
3860 | option_len = sizeof(option_value); | |
3861 | if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, | |
3862 | (char *) &option_value, &option_len) == 0) | |
3863 | { | |
3864 | if (option_value == 0) | |
3865 | { | |
3866 | option_value = 1; | |
3867 | option_len = sizeof(option_value); | |
3868 | if (setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, | |
3869 | (char *) &option_value, option_len) < 0) | |
3870 | { | |
3871 | } | |
3872 | } | |
3873 | } | |
3874 | return rv; | |
3875 | #endif | |
3876 | } | |
3877 | ||
3878 | /*****************************************************************************/ | |
3879 | int | |
3880 | g_tcp4_bind_address(int sck, const char *port, const char *address) | |
3881 | { | |
3882 | #if defined(XRDP_ENABLE_IPV6ONLY) | |
3883 | return -1; | |
3884 | #else | |
3885 | struct sockaddr_in s; | |
3886 | ||
3887 | memset(&s, 0, sizeof(s)); | |
3888 | s.sin_family = AF_INET; | |
3889 | s.sin_addr.s_addr = htonl(INADDR_ANY); | |
3890 | s.sin_port = htons((uint16_t) atoi(port)); | |
3891 | if (inet_aton(address, &s.sin_addr) < 0) | |
3892 | { | |
3893 | return -1; /* bad address */ | |
3894 | } | |
3895 | if (bind(sck, (struct sockaddr*) &s, sizeof(s)) < 0) | |
3896 | { | |
3897 | return -1; | |
3898 | } | |
3899 | return 0; | |
3900 | #endif | |
3901 | } | |
3902 | ||
3903 | /*****************************************************************************/ | |
3904 | int | |
3905 | g_tcp6_socket(void) | |
3906 | { | |
3907 | #if defined(XRDP_ENABLE_IPV6) | |
3908 | int rv; | |
3909 | int option_value; | |
3910 | socklen_t option_len; | |
3911 | ||
3912 | rv = socket(AF_INET6, SOCK_STREAM, 0); | |
3913 | if (rv < 0) | |
3914 | { | |
3915 | return -1; | |
3916 | } | |
3917 | option_len = sizeof(option_value); | |
3918 | if (getsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY, | |
3919 | (char *) &option_value, &option_len) == 0) | |
3920 | { | |
3921 | #if defined(XRDP_ENABLE_IPV6ONLY) | |
3922 | if (option_value == 0) | |
3923 | { | |
3924 | option_value = 1; | |
3925 | #else | |
3926 | if (option_value != 0) | |
3927 | { | |
3928 | option_value = 0; | |
3929 | #endif | |
3930 | option_len = sizeof(option_value); | |
3931 | if (setsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY, | |
3932 | (char *) &option_value, option_len) < 0) | |
3933 | { | |
3934 | } | |
3935 | } | |
3936 | } | |
3937 | option_len = sizeof(option_value); | |
3938 | if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, | |
3939 | (char *) &option_value, &option_len) == 0) | |
3940 | { | |
3941 | if (option_value == 0) | |
3942 | { | |
3943 | option_value = 1; | |
3944 | option_len = sizeof(option_value); | |
3945 | if (setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, | |
3946 | (char *) &option_value, option_len) < 0) | |
3947 | { | |
3948 | } | |
3949 | } | |
3950 | } | |
3951 | return rv; | |
3952 | #else | |
3953 | return -1; | |
3954 | #endif | |
3955 | } | |
3956 | ||
3957 | /*****************************************************************************/ | |
3958 | int | |
3959 | g_tcp6_bind_address(int sck, const char *port, const char *address) | |
3960 | { | |
3961 | #if defined(XRDP_ENABLE_IPV6) | |
3962 | int rv; | |
3963 | int error; | |
3964 | struct addrinfo hints; | |
3965 | struct addrinfo *list; | |
3966 | struct addrinfo *i; | |
3967 | ||
3968 | rv = -1; | |
3969 | memset(&hints, 0, sizeof(hints)); | |
3970 | hints.ai_family = AF_UNSPEC; | |
3971 | hints.ai_flags = 0; | |
3972 | hints.ai_socktype = SOCK_STREAM; | |
3973 | hints.ai_protocol = IPPROTO_TCP; | |
3974 | error = getaddrinfo(address, port, &hints, &list); | |
3975 | if (error == 0) | |
3976 | { | |
3977 | i = list; | |
3978 | while ((i != NULL) && (rv < 0)) | |
3979 | { | |
3980 | rv = bind(sck, i->ai_addr, i->ai_addrlen); | |
3981 | i = i->ai_next; | |
3982 | } | |
3983 | freeaddrinfo(list); | |
3984 | } | |
3985 | else | |
3986 | { | |
3987 | return -1; | |
3988 | } | |
3989 | return rv; | |
3990 | #else | |
3991 | return -1; | |
3992 | #endif | |
3993 | } |
70 | 70 | int g_tcp_bind(int sck, const char *port); |
71 | 71 | int g_sck_local_bind(int sck, const char* port); |
72 | 72 | int g_sck_vsock_bind(int sck, const char* port); |
73 | int g_sck_vsock_bind_address(int sck, const char *port, const char *address); | |
73 | 74 | int g_tcp_bind_address(int sck, const char* port, const char* address); |
74 | 75 | int g_sck_listen(int sck); |
75 | 76 | int g_tcp_accept(int sck); |
182 | 183 | int g_shmdt(const void *shmaddr); |
183 | 184 | int g_gethostname(char *name, int len); |
184 | 185 | int g_mirror_memcpy(void *dst, const void *src, int len); |
186 | int g_tcp4_socket(void); | |
187 | int g_tcp4_bind_address(int sck, const char *port, const char *address); | |
188 | int g_tcp6_socket(void); | |
189 | int g_tcp6_bind_address(int sck, const char *port, const char *address); | |
185 | 190 | |
186 | 191 | /* glib-style wrappers */ |
187 | 192 | #define g_new(struct_type, n_structs) \ |
711 | 711 | now = g_time3(); |
712 | 712 | if (now - start_time < timeout) |
713 | 713 | { |
714 | g_sleep(timeout / 5); | |
714 | g_sleep(100); | |
715 | 715 | } |
716 | 716 | else |
717 | 717 | { |
718 | 718 | self->status = TRANS_STATUS_DOWN; |
719 | 719 | return 1; |
720 | 720 | } |
721 | if (self->is_term != NULL) | |
722 | { | |
723 | if (self->is_term()) | |
724 | { | |
725 | self->status = TRANS_STATUS_DOWN; | |
726 | return 1; | |
727 | } | |
728 | } | |
721 | 729 | } |
722 | 730 | } |
723 | 731 | } |
747 | 755 | now = g_time3(); |
748 | 756 | if (now - start_time < timeout) |
749 | 757 | { |
750 | g_sleep(timeout / 5); | |
758 | g_sleep(100); | |
751 | 759 | } |
752 | 760 | else |
753 | 761 | { |
754 | 762 | self->status = TRANS_STATUS_DOWN; |
755 | 763 | return 1; |
764 | } | |
765 | if (self->is_term != NULL) | |
766 | { | |
767 | if (self->is_term()) | |
768 | { | |
769 | self->status = TRANS_STATUS_DOWN; | |
770 | return 1; | |
771 | } | |
756 | 772 | } |
757 | 773 | } |
758 | 774 | } |
858 | 874 | |
859 | 875 | g_tcp_set_non_blocking(self->sck); |
860 | 876 | |
861 | if (g_sck_vsock_bind(self->sck, port) == 0) | |
877 | if (g_sck_vsock_bind_address(self->sck, port, address) == 0) | |
862 | 878 | { |
863 | 879 | if (g_tcp_listen(self->sck) == 0) |
864 | 880 | { |
868 | 884 | } |
869 | 885 | } |
870 | 886 | } |
871 | ||
887 | else if (self->mode == TRANS_MODE_TCP4) /* tcp4 */ | |
888 | { | |
889 | self->sck = g_tcp4_socket(); | |
890 | if (self->sck < 0) | |
891 | { | |
892 | return 1; | |
893 | } | |
894 | g_tcp_set_non_blocking(self->sck); | |
895 | if (g_tcp4_bind_address(self->sck, port, address) == 0) | |
896 | { | |
897 | if (g_tcp_listen(self->sck) == 0) | |
898 | { | |
899 | self->status = TRANS_STATUS_UP; /* ok */ | |
900 | self->type1 = TRANS_TYPE_LISTENER; /* listener */ | |
901 | return 0; | |
902 | } | |
903 | } | |
904 | } | |
905 | else if (self->mode == TRANS_MODE_TCP6) /* tcp6 */ | |
906 | { | |
907 | self->sck = g_tcp6_socket(); | |
908 | if (self->sck < 0) | |
909 | { | |
910 | return 1; | |
911 | } | |
912 | g_tcp_set_non_blocking(self->sck); | |
913 | if (g_tcp6_bind_address(self->sck, port, address) == 0) | |
914 | { | |
915 | if (g_tcp_listen(self->sck) == 0) | |
916 | { | |
917 | self->status = TRANS_STATUS_UP; /* ok */ | |
918 | self->type1 = TRANS_TYPE_LISTENER; /* listener */ | |
919 | return 0; | |
920 | } | |
921 | } | |
922 | } | |
872 | 923 | return 1; |
873 | 924 | } |
874 | 925 |
23 | 23 | #include "arch.h" |
24 | 24 | #include "parse.h" |
25 | 25 | |
26 | #define TRANS_MODE_TCP 1 | |
26 | #define TRANS_MODE_TCP 1 /* tcp6 if defined, else tcp4 */ | |
27 | 27 | #define TRANS_MODE_UNIX 2 |
28 | 28 | #define TRANS_MODE_VSOCK 3 |
29 | #define TRANS_MODE_TCP4 4 /* tcp4 only */ | |
30 | #define TRANS_MODE_TCP6 6 /* tcp6 only */ | |
29 | 31 | |
30 | 32 | #define TRANS_TYPE_LISTENER 1 |
31 | 33 | #define TRANS_TYPE_SERVER 2 |
155 | 155 | int no_orders_supported; |
156 | 156 | int use_cache_glyph_v2; |
157 | 157 | int rail_enable; |
158 | int suppress_output; | |
158 | 159 | }; |
159 | 160 | |
160 | 161 | #endif |
542 | 542 | #define RDP_DATA_PDU_POINTER 27 |
543 | 543 | #define RDP_DATA_PDU_INPUT 28 |
544 | 544 | #define RDP_DATA_PDU_SYNCHRONISE 31 |
545 | #define PDUTYPE2_REFRESH_RECT 33 | |
545 | 546 | #define RDP_DATA_PDU_PLAY_SOUND 34 |
546 | 547 | #define RDP_DATA_PDU_LOGON 38 |
547 | 548 | #define RDP_DATA_PDU_FONT2 39 |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for xrdp 0.9.9. | |
2 | # Generated by GNU Autoconf 2.69 for xrdp 0.9.12. | |
3 | 3 | # |
4 | 4 | # Report bugs to <xrdp-devel@googlegroups.com>. |
5 | 5 | # |
589 | 589 | # Identity of this package. |
590 | 590 | PACKAGE_NAME='xrdp' |
591 | 591 | PACKAGE_TARNAME='xrdp' |
592 | PACKAGE_VERSION='0.9.9' | |
593 | PACKAGE_STRING='xrdp 0.9.9' | |
592 | PACKAGE_VERSION='0.9.12' | |
593 | PACKAGE_STRING='xrdp 0.9.12' | |
594 | 594 | PACKAGE_BUGREPORT='xrdp-devel@googlegroups.com' |
595 | 595 | PACKAGE_URL='' |
596 | 596 | |
657 | 657 | OPENSSL_LIBS |
658 | 658 | OPENSSL_CFLAGS |
659 | 659 | DLOPEN_LIBS |
660 | XRDP_RDPSNDAUDIN_FALSE | |
661 | XRDP_RDPSNDAUDIN_TRUE | |
660 | 662 | XRDP_RFXCODEC_FALSE |
661 | 663 | XRDP_RFXCODEC_TRUE |
662 | 664 | XRDP_PAINTER_FALSE |
855 | 857 | enable_pixman |
856 | 858 | enable_painter |
857 | 859 | enable_rfxcodec |
860 | enable_rdpsndaudin | |
858 | 861 | with_x |
859 | 862 | enable_strict_locations |
860 | 863 | with_pkgconfigdir |
1423 | 1426 | # Omit some internal or obsolete options to make the list less imposing. |
1424 | 1427 | # This message is too long to be a string in the A/UX 3.1 sh. |
1425 | 1428 | cat <<_ACEOF |
1426 | \`configure' configures xrdp 0.9.9 to adapt to many kinds of systems. | |
1429 | \`configure' configures xrdp 0.9.12 to adapt to many kinds of systems. | |
1427 | 1430 | |
1428 | 1431 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1429 | 1432 | |
1497 | 1500 | |
1498 | 1501 | if test -n "$ac_init_help"; then |
1499 | 1502 | case $ac_init_help in |
1500 | short | recursive ) echo "Configuration of xrdp 0.9.9:";; | |
1503 | short | recursive ) echo "Configuration of xrdp 0.9.12:";; | |
1501 | 1504 | esac |
1502 | 1505 | cat <<\_ACEOF |
1503 | 1506 | |
1540 | 1543 | --disable-painter Do not use included painter library (default: no) |
1541 | 1544 | --disable-rfxcodec Do not use included librfxcodec library (default: |
1542 | 1545 | no) |
1546 | --enable-rdpsndaudin Use rdpsnd audio in (default: no) | |
1543 | 1547 | --enable-strict-locations |
1544 | 1548 | Use standard Autoconf install directories unless |
1545 | 1549 | overridden (default: use /etc and /var) |
1662 | 1666 | test -n "$ac_init_help" && exit $ac_status |
1663 | 1667 | if $ac_init_version; then |
1664 | 1668 | cat <<\_ACEOF |
1665 | xrdp configure 0.9.9 | |
1669 | xrdp configure 0.9.12 | |
1666 | 1670 | generated by GNU Autoconf 2.69 |
1667 | 1671 | |
1668 | 1672 | Copyright (C) 2012 Free Software Foundation, Inc. |
2031 | 2035 | This file contains any messages produced by compilers while |
2032 | 2036 | running configure, to aid debugging if configure makes a mistake. |
2033 | 2037 | |
2034 | It was created by xrdp $as_me 0.9.9, which was | |
2038 | It was created by xrdp $as_me 0.9.12, which was | |
2035 | 2039 | generated by GNU Autoconf 2.69. Invocation command line was |
2036 | 2040 | |
2037 | 2041 | $ $0 $@ |
2896 | 2900 | |
2897 | 2901 | # Define the identity of the package. |
2898 | 2902 | PACKAGE='xrdp' |
2899 | VERSION='0.9.9' | |
2903 | VERSION='0.9.12' | |
2900 | 2904 | |
2901 | 2905 | |
2902 | 2906 | cat >>confdefs.h <<_ACEOF |
12961 | 12965 | fi |
12962 | 12966 | |
12963 | 12967 | |
12968 | # Check whether --enable-rdpsndaudin was given. | |
12969 | if test "${enable_rdpsndaudin+set}" = set; then : | |
12970 | enableval=$enable_rdpsndaudin; | |
12971 | else | |
12972 | enable_rdpsndaudin=no | |
12973 | fi | |
12974 | ||
12975 | if test x$enable_rdpsndaudin = xyes; then | |
12976 | XRDP_RDPSNDAUDIN_TRUE= | |
12977 | XRDP_RDPSNDAUDIN_FALSE='#' | |
12978 | else | |
12979 | XRDP_RDPSNDAUDIN_TRUE='#' | |
12980 | XRDP_RDPSNDAUDIN_FALSE= | |
12981 | fi | |
12982 | ||
12983 | ||
12964 | 12984 | # Don't fail without working nasm if rfxcodec is not enabled |
12965 | 12985 | if test "x$enable_rfxcodec" != xyes; then |
12966 | 12986 | with_simd=no |
14653 | 14673 | as_fn_error $? "conditional \"XRDP_RFXCODEC\" was never defined. |
14654 | 14674 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 |
14655 | 14675 | fi |
14676 | if test -z "${XRDP_RDPSNDAUDIN_TRUE}" && test -z "${XRDP_RDPSNDAUDIN_FALSE}"; then | |
14677 | as_fn_error $? "conditional \"XRDP_RDPSNDAUDIN\" was never defined. | |
14678 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 | |
14679 | fi | |
14656 | 14680 | |
14657 | 14681 | : "${CONFIG_STATUS=./config.status}" |
14658 | 14682 | ac_write_fail=0 |
15050 | 15074 | # report actual input values of CONFIG_FILES etc. instead of their |
15051 | 15075 | # values after options handling. |
15052 | 15076 | ac_log=" |
15053 | This file was extended by xrdp $as_me 0.9.9, which was | |
15077 | This file was extended by xrdp $as_me 0.9.12, which was | |
15054 | 15078 | generated by GNU Autoconf 2.69. Invocation command line was |
15055 | 15079 | |
15056 | 15080 | CONFIG_FILES = $CONFIG_FILES |
15116 | 15140 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
15117 | 15141 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
15118 | 15142 | ac_cs_version="\\ |
15119 | xrdp config.status 0.9.9 | |
15143 | xrdp config.status 0.9.12 | |
15120 | 15144 | configured by $0, generated by GNU Autoconf 2.69, |
15121 | 15145 | with options \\"\$ac_cs_config\\" |
15122 | 15146 | |
16992 | 17016 | echo " pam $enable_pam" |
16993 | 17017 | echo " kerberos $enable_kerberos" |
16994 | 17018 | echo " debug $enable_xrdpdebug" |
17019 | echo " rdpsndaudin $enable_rdpsndaudin" | |
16995 | 17020 | echo "" |
16996 | 17021 | echo " strict_locations $enable_strict_locations" |
16997 | 17022 | echo " prefix $prefix" |
0 | 0 | # Process this file with autoconf to produce a configure script |
1 | 1 | |
2 | 2 | AC_PREREQ(2.65) |
3 | AC_INIT([xrdp], [0.9.9], [xrdp-devel@googlegroups.com]) | |
3 | AC_INIT([xrdp], [0.9.12], [xrdp-devel@googlegroups.com]) | |
4 | 4 | AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) |
5 | 5 | AM_INIT_AUTOMAKE([1.7.2 foreign]) |
6 | 6 | AC_CONFIG_MACRO_DIR([m4]) |
149 | 149 | [], [enable_rfxcodec=yes]) |
150 | 150 | AM_CONDITIONAL(XRDP_RFXCODEC, [test x$enable_rfxcodec = xyes]) |
151 | 151 | |
152 | AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin], | |
153 | [Use rdpsnd audio in (default: no)]), | |
154 | [], [enable_rdpsndaudin=no]) | |
155 | AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes]) | |
156 | ||
152 | 157 | # Don't fail without working nasm if rfxcodec is not enabled |
153 | 158 | if test "x$enable_rfxcodec" != xyes; then |
154 | 159 | with_simd=no |
389 | 394 | echo " pam $enable_pam" |
390 | 395 | echo " kerberos $enable_kerberos" |
391 | 396 | echo " debug $enable_xrdpdebug" |
397 | echo " rdpsndaudin $enable_rdpsndaudin" | |
392 | 398 | echo "" |
393 | 399 | echo " strict_locations $enable_strict_locations" |
394 | 400 | echo " prefix $prefix" |
196 | 196 | have session management rights. |
197 | 197 | |
198 | 198 | .TP |
199 | \fBRestrictOutboundClipboard\fR=\fI[true|false]\fR | |
200 | If set to \fB1\fR, \fBtrue\fR or \fByes\fR, will restrict the clipboard | |
201 | outbound from the server, to prevent data copied inside the xrdp session | |
202 | to be be pasted in the client host. Default value is \fBfalse\fR. | |
203 | ||
204 | .TP | |
199 | 205 | \fBAlwaysGroupCheck\fR=\fI[true|false]\fR |
200 | 206 | If set to \fB1\fR, \fBtrue\fR or \fByes\fR, require group membership even |
201 | 207 | if the group specified in \fBTerminalServerUsers\fR doesn't exist. |
217 | 223 | \fBFuseMountName\fR=\fIstring\fR |
218 | 224 | Directory for drive redirection, relative to the user home directory. |
219 | 225 | Created if it doesn't exist. If not specified, defaults to \fIxrdp_client\fR. |
226 | ||
227 | .TP | |
228 | \fBFileUmask\fR=\fImode\fR | |
229 | Additional umask to apply to files in the \fBFuseMountName\fR directory. | |
230 | The default value of 077 prevents other users on the system from reading | |
231 | files on your redirected drives. This may not be approprate for all | |
232 | environents, and so you can change this value to allow other users to | |
233 | access your remote files if required. | |
220 | 234 | |
221 | 235 | .SH "SESSIONS VARIABLES" |
222 | 236 | All entries in the \fB[SessionVariables]\fR section are set as |
22 | 22 | Output help information and exit. |
23 | 23 | |
24 | 24 | .SH "FILES" |
25 | @bindir@/sesman | |
25 | @bindir@/xrdp\-sesman | |
26 | 26 | .br |
27 | @bindir@/sesrun | |
27 | @bindir@/xrdp\-sesrun | |
28 | 28 | .br |
29 | 29 | @sysconfdir@/xrdp/sesman.ini |
30 | 30 | .br |
31 | @localstatedir@/log/sesman.log | |
31 | @localstatedir@/log/xrdp\-sesman.log | |
32 | 32 | .br |
33 | @localstatedir@/run/sesman.pid | |
33 | @localstatedir@/run/xrdp\-sesman.pid | |
34 | 34 | |
35 | 35 | .SH "AUTHORS" |
36 | 36 | Jay Sorg <jsorg71@users.sourceforge.net> |
31 | 31 | Session color depth |
32 | 32 | |
33 | 33 | .SH "FILES" |
34 | @bindir@/sesman | |
34 | @bindir@/xrdp\-sesman | |
35 | 35 | .br |
36 | @bindir@/sesrun | |
36 | @bindir@/xrdp\-sesrun | |
37 | 37 | |
38 | 38 | .SH "AUTHORS" |
39 | 39 | Jay Sorg <jsorg71@users.sourceforge.net> |
29 | 29 | startwm.sh |
30 | 30 | xrdp.ini |
31 | 31 | xrdp_keyboard.ini |
32 | xrdp.sh | |
33 | 32 | |
34 | 33 | /etc/xrdp/pulse |
35 | 34 | default.pa |
0 | 0 | EXTRA_DIST = \ |
1 | 1 | keymap-names.txt \ |
2 | xrdp.sh \ | |
3 | 2 | xrdp-sesman.service.in \ |
4 | 3 | xrdp.service.in |
5 | 4 | |
29 | 28 | startscriptdir=$(sysconfdir)/xrdp |
30 | 29 | |
31 | 30 | dist_startscript_DATA = \ |
31 | km-00000406.ini \ | |
32 | 32 | km-00000407.ini \ |
33 | 33 | km-00000409.ini \ |
34 | 34 | km-0000040a.ini \ |
59 | 59 | SUBDIRS += \ |
60 | 60 | pam.d \ |
61 | 61 | pulse |
62 | dist_startscript_SCRIPTS = xrdp.sh | |
63 | 62 | if HAVE_SYSTEMD |
64 | 63 | systemdsystemunit_DATA = \ |
65 | 64 | xrdp-sesman.service \ |
12 | 12 | # PARTICULAR PURPOSE. |
13 | 13 | |
14 | 14 | @SET_MAKE@ |
15 | ||
16 | 15 | |
17 | 16 | VPATH = @srcdir@ |
18 | 17 | am__is_gnu_make = { \ |
117 | 116 | $(top_srcdir)/configure.ac |
118 | 117 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ |
119 | 118 | $(ACLOCAL_M4) |
120 | DIST_COMMON = $(srcdir)/Makefile.am \ | |
121 | $(am__dist_startscript_SCRIPTS_DIST) $(dist_startscript_DATA) \ | |
119 | DIST_COMMON = $(srcdir)/Makefile.am $(dist_startscript_DATA) \ | |
122 | 120 | $(am__DIST_COMMON) |
123 | 121 | mkinstalldirs = $(install_sh) -d |
124 | 122 | CONFIG_HEADER = $(top_builddir)/config_ac.h |
125 | 123 | CONFIG_CLEAN_FILES = |
126 | 124 | CONFIG_CLEAN_VPATH_FILES = |
127 | am__dist_startscript_SCRIPTS_DIST = xrdp.sh | |
125 | AM_V_P = $(am__v_P_@AM_V@) | |
126 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) | |
127 | am__v_P_0 = false | |
128 | am__v_P_1 = : | |
129 | AM_V_GEN = $(am__v_GEN_@AM_V@) | |
130 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) | |
131 | am__v_GEN_0 = @echo " GEN " $@; | |
132 | am__v_GEN_1 = | |
133 | AM_V_at = $(am__v_at_@AM_V@) | |
134 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) | |
135 | am__v_at_0 = @ | |
136 | am__v_at_1 = | |
137 | SOURCES = | |
138 | DIST_SOURCES = | |
139 | RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ | |
140 | ctags-recursive dvi-recursive html-recursive info-recursive \ | |
141 | install-data-recursive install-dvi-recursive \ | |
142 | install-exec-recursive install-html-recursive \ | |
143 | install-info-recursive install-pdf-recursive \ | |
144 | install-ps-recursive install-recursive installcheck-recursive \ | |
145 | installdirs-recursive pdf-recursive ps-recursive \ | |
146 | tags-recursive uninstall-recursive | |
147 | am__can_run_installinfo = \ | |
148 | case $$AM_UPDATE_INFO_DIR in \ | |
149 | n|no|NO) false;; \ | |
150 | *) (install-info --version) >/dev/null 2>&1;; \ | |
151 | esac | |
128 | 152 | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; |
129 | 153 | am__vpath_adj = case $$p in \ |
130 | 154 | $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ |
153 | 177 | $(am__cd) "$$dir" && rm -f $$files; }; \ |
154 | 178 | } |
155 | 179 | am__installdirs = "$(DESTDIR)$(startscriptdir)" \ |
156 | "$(DESTDIR)$(startscriptdir)" \ | |
157 | 180 | "$(DESTDIR)$(systemdsystemunitdir)" |
158 | SCRIPTS = $(dist_startscript_SCRIPTS) | |
159 | AM_V_P = $(am__v_P_@AM_V@) | |
160 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) | |
161 | am__v_P_0 = false | |
162 | am__v_P_1 = : | |
163 | AM_V_GEN = $(am__v_GEN_@AM_V@) | |
164 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) | |
165 | am__v_GEN_0 = @echo " GEN " $@; | |
166 | am__v_GEN_1 = | |
167 | AM_V_at = $(am__v_at_@AM_V@) | |
168 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) | |
169 | am__v_at_0 = @ | |
170 | am__v_at_1 = | |
171 | SOURCES = | |
172 | DIST_SOURCES = | |
173 | RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ | |
174 | ctags-recursive dvi-recursive html-recursive info-recursive \ | |
175 | install-data-recursive install-dvi-recursive \ | |
176 | install-exec-recursive install-html-recursive \ | |
177 | install-info-recursive install-pdf-recursive \ | |
178 | install-ps-recursive install-recursive installcheck-recursive \ | |
179 | installdirs-recursive pdf-recursive ps-recursive \ | |
180 | tags-recursive uninstall-recursive | |
181 | am__can_run_installinfo = \ | |
182 | case $$AM_UPDATE_INFO_DIR in \ | |
183 | n|no|NO) false;; \ | |
184 | *) (install-info --version) >/dev/null 2>&1;; \ | |
185 | esac | |
186 | 181 | DATA = $(dist_startscript_DATA) $(systemdsystemunit_DATA) |
187 | 182 | RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ |
188 | 183 | distclean-recursive maintainer-clean-recursive |
384 | 379 | top_srcdir = @top_srcdir@ |
385 | 380 | EXTRA_DIST = \ |
386 | 381 | keymap-names.txt \ |
387 | xrdp.sh \ | |
388 | 382 | xrdp-sesman.service.in \ |
389 | 383 | xrdp.service.in |
390 | 384 | |
411 | 405 | # |
412 | 406 | startscriptdir = $(sysconfdir)/xrdp |
413 | 407 | dist_startscript_DATA = \ |
408 | km-00000406.ini \ | |
414 | 409 | km-00000407.ini \ |
415 | 410 | km-00000409.ini \ |
416 | 411 | km-0000040a.ini \ |
439 | 434 | # |
440 | 435 | SUBDIRS = $(am__append_1) $(am__append_2) $(am__append_3) \ |
441 | 436 | $(am__append_4) |
442 | @LINUX_TRUE@dist_startscript_SCRIPTS = xrdp.sh | |
443 | 437 | @HAVE_SYSTEMD_TRUE@@LINUX_TRUE@systemdsystemunit_DATA = \ |
444 | 438 | @HAVE_SYSTEMD_TRUE@@LINUX_TRUE@ xrdp-sesman.service \ |
445 | 439 | @HAVE_SYSTEMD_TRUE@@LINUX_TRUE@ xrdp.service |
477 | 471 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) |
478 | 472 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh |
479 | 473 | $(am__aclocal_m4_deps): |
480 | install-dist_startscriptSCRIPTS: $(dist_startscript_SCRIPTS) | |
481 | @$(NORMAL_INSTALL) | |
482 | @list='$(dist_startscript_SCRIPTS)'; test -n "$(startscriptdir)" || list=; \ | |
483 | if test -n "$$list"; then \ | |
484 | echo " $(MKDIR_P) '$(DESTDIR)$(startscriptdir)'"; \ | |
485 | $(MKDIR_P) "$(DESTDIR)$(startscriptdir)" || exit 1; \ | |
486 | fi; \ | |
487 | for p in $$list; do \ | |
488 | if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ | |
489 | if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ | |
490 | done | \ | |
491 | sed -e 'p;s,.*/,,;n' \ | |
492 | -e 'h;s|.*|.|' \ | |
493 | -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ | |
494 | $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ | |
495 | { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ | |
496 | if ($$2 == $$4) { files[d] = files[d] " " $$1; \ | |
497 | if (++n[d] == $(am__install_max)) { \ | |
498 | print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ | |
499 | else { print "f", d "/" $$4, $$1 } } \ | |
500 | END { for (d in files) print "f", d, files[d] }' | \ | |
501 | while read type dir files; do \ | |
502 | if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ | |
503 | test -z "$$files" || { \ | |
504 | echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(startscriptdir)$$dir'"; \ | |
505 | $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(startscriptdir)$$dir" || exit $$?; \ | |
506 | } \ | |
507 | ; done | |
508 | ||
509 | uninstall-dist_startscriptSCRIPTS: | |
510 | @$(NORMAL_UNINSTALL) | |
511 | @list='$(dist_startscript_SCRIPTS)'; test -n "$(startscriptdir)" || exit 0; \ | |
512 | files=`for p in $$list; do echo "$$p"; done | \ | |
513 | sed -e 's,.*/,,;$(transform)'`; \ | |
514 | dir='$(DESTDIR)$(startscriptdir)'; $(am__uninstall_files_from_dir) | |
515 | 474 | |
516 | 475 | mostlyclean-libtool: |
517 | 476 | -rm -f *.lo |
720 | 679 | done |
721 | 680 | check-am: all-am |
722 | 681 | check: check-recursive |
723 | all-am: Makefile $(SCRIPTS) $(DATA) | |
682 | all-am: Makefile $(DATA) | |
724 | 683 | installdirs: installdirs-recursive |
725 | 684 | installdirs-am: |
726 | for dir in "$(DESTDIR)$(startscriptdir)" "$(DESTDIR)$(startscriptdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \ | |
685 | for dir in "$(DESTDIR)$(startscriptdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \ | |
727 | 686 | test -z "$$dir" || $(MKDIR_P) "$$dir"; \ |
728 | 687 | done |
729 | 688 | install: install-recursive |
779 | 738 | info-am: |
780 | 739 | |
781 | 740 | install-data-am: install-dist_startscriptDATA \ |
782 | install-dist_startscriptSCRIPTS install-systemdsystemunitDATA | |
741 | install-systemdsystemunitDATA | |
783 | 742 | @$(NORMAL_INSTALL) |
784 | 743 | $(MAKE) $(AM_MAKEFLAGS) install-data-hook |
785 | 744 | install-dvi: install-dvi-recursive |
825 | 784 | ps-am: |
826 | 785 | |
827 | 786 | uninstall-am: uninstall-dist_startscriptDATA \ |
828 | uninstall-dist_startscriptSCRIPTS \ | |
829 | 787 | uninstall-systemdsystemunitDATA |
830 | 788 | |
831 | 789 | .MAKE: $(am__recursive_targets) install-am install-data-am \ |
836 | 794 | ctags-am distclean distclean-generic distclean-libtool \ |
837 | 795 | distclean-tags distdir dvi dvi-am html html-am info info-am \ |
838 | 796 | install install-am install-data install-data-am \ |
839 | install-data-hook install-dist_startscriptDATA \ | |
840 | install-dist_startscriptSCRIPTS install-dvi install-dvi-am \ | |
841 | install-exec install-exec-am install-html install-html-am \ | |
842 | install-info install-info-am install-man install-pdf \ | |
843 | install-pdf-am install-ps install-ps-am install-strip \ | |
844 | install-systemdsystemunitDATA installcheck installcheck-am \ | |
845 | installdirs installdirs-am maintainer-clean \ | |
797 | install-data-hook install-dist_startscriptDATA install-dvi \ | |
798 | install-dvi-am install-exec install-exec-am install-html \ | |
799 | install-html-am install-info install-info-am install-man \ | |
800 | install-pdf install-pdf-am install-ps install-ps-am \ | |
801 | install-strip install-systemdsystemunitDATA installcheck \ | |
802 | installcheck-am installdirs installdirs-am maintainer-clean \ | |
846 | 803 | maintainer-clean-generic mostlyclean mostlyclean-generic \ |
847 | 804 | mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ |
848 | 805 | uninstall-am uninstall-dist_startscriptDATA \ |
849 | uninstall-dist_startscriptSCRIPTS \ | |
850 | 806 | uninstall-systemdsystemunitDATA |
851 | 807 | |
852 | 808 | .PRECIOUS: Makefile |
0 | [noshift] | |
1 | Key8=0:0 | |
2 | Key9=65307:27 | |
3 | Key10=49:49 | |
4 | Key11=50:50 | |
5 | Key12=51:51 | |
6 | Key13=52:52 | |
7 | Key14=53:53 | |
8 | Key15=54:54 | |
9 | Key16=55:55 | |
10 | Key17=56:56 | |
11 | Key18=57:57 | |
12 | Key19=48:48 | |
13 | Key20=43:43 | |
14 | Key21=65105:180 | |
15 | Key22=65288:8 | |
16 | Key23=65289:9 | |
17 | Key24=113:113 | |
18 | Key25=119:119 | |
19 | Key26=101:101 | |
20 | Key27=114:114 | |
21 | Key28=116:116 | |
22 | Key29=121:121 | |
23 | Key30=117:117 | |
24 | Key31=105:105 | |
25 | Key32=111:111 | |
26 | Key33=112:112 | |
27 | Key34=229:229 | |
28 | Key35=168:168 | |
29 | Key36=65293:13 | |
30 | Key37=65507:0 | |
31 | Key38=97:97 | |
32 | Key39=115:115 | |
33 | Key40=100:100 | |
34 | Key41=102:102 | |
35 | Key42=103:103 | |
36 | Key43=104:104 | |
37 | Key44=106:106 | |
38 | Key45=107:107 | |
39 | Key46=108:108 | |
40 | Key47=230:230 | |
41 | Key48=248:248 | |
42 | Key49=189:189 | |
43 | Key50=65505:0 | |
44 | Key51=39:39 | |
45 | Key52=122:122 | |
46 | Key53=120:120 | |
47 | Key54=99:99 | |
48 | Key55=118:118 | |
49 | Key56=98:98 | |
50 | Key57=110:110 | |
51 | Key58=109:109 | |
52 | Key59=44:44 | |
53 | Key60=46:46 | |
54 | Key61=45:45 | |
55 | Key62=65506:0 | |
56 | Key63=65450:42 | |
57 | Key64=65513:0 | |
58 | Key65=32:32 | |
59 | Key66=65509:0 | |
60 | Key67=65470:0 | |
61 | Key68=65471:0 | |
62 | Key69=65472:0 | |
63 | Key70=65473:0 | |
64 | Key71=65474:0 | |
65 | Key72=65475:0 | |
66 | Key73=65476:0 | |
67 | Key74=65477:0 | |
68 | Key75=65478:0 | |
69 | Key76=65479:0 | |
70 | Key77=65407:0 | |
71 | Key78=65300:0 | |
72 | Key79=65429:0 | |
73 | Key80=65431:0 | |
74 | Key81=65434:0 | |
75 | Key82=65453:45 | |
76 | Key83=65430:0 | |
77 | Key84=65437:0 | |
78 | Key85=65432:0 | |
79 | Key86=65451:43 | |
80 | Key87=65436:0 | |
81 | Key88=65433:0 | |
82 | Key89=65435:0 | |
83 | Key90=65438:0 | |
84 | Key91=65439:0 | |
85 | Key92=0:0 | |
86 | Key93=65406:0 | |
87 | Key94=60:60 | |
88 | Key95=65480:0 | |
89 | Key96=65481:0 | |
90 | Key97=65360:0 | |
91 | Key98=65362:0 | |
92 | Key99=65365:0 | |
93 | Key100=65361:0 | |
94 | Key101=0:0 | |
95 | Key102=65363:0 | |
96 | Key103=65367:0 | |
97 | Key104=65364:0 | |
98 | Key105=65366:0 | |
99 | Key106=65379:0 | |
100 | Key107=65535:127 | |
101 | Key108=65421:13 | |
102 | Key109=65508:0 | |
103 | Key110=65299:0 | |
104 | Key111=65377:0 | |
105 | Key112=65455:47 | |
106 | Key113=65027:0 | |
107 | Key114=0:0 | |
108 | Key115=65515:0 | |
109 | Key116=65516:0 | |
110 | Key117=65383:0 | |
111 | Key118=0:0 | |
112 | Key119=0:0 | |
113 | Key120=0:0 | |
114 | Key121=0:0 | |
115 | Key122=0:0 | |
116 | Key123=0:0 | |
117 | Key124=65027:0 | |
118 | Key125=0:0 | |
119 | Key126=65469:61 | |
120 | Key127=0:0 | |
121 | Key128=0:0 | |
122 | Key129=0:0 | |
123 | Key130=0:0 | |
124 | Key131=0:0 | |
125 | Key132=0:0 | |
126 | Key133=0:0 | |
127 | Key134=0:0 | |
128 | Key135=0:0 | |
129 | Key136=0:0 | |
130 | Key137=0:0 | |
131 | ||
132 | [shift] | |
133 | Key8=0:0 | |
134 | Key9=65307:27 | |
135 | Key10=33:33 | |
136 | Key11=34:34 | |
137 | Key12=35:35 | |
138 | Key13=164:164 | |
139 | Key14=37:37 | |
140 | Key15=38:38 | |
141 | Key16=47:47 | |
142 | Key17=40:40 | |
143 | Key18=41:41 | |
144 | Key19=61:61 | |
145 | Key20=63:63 | |
146 | Key21=65104:96 | |
147 | Key22=65288:8 | |
148 | Key23=65056:0 | |
149 | Key24=81:81 | |
150 | Key25=87:87 | |
151 | Key26=69:69 | |
152 | Key27=82:82 | |
153 | Key28=84:84 | |
154 | Key29=89:89 | |
155 | Key30=85:85 | |
156 | Key31=73:73 | |
157 | Key32=79:79 | |
158 | Key33=80:80 | |
159 | Key34=197:197 | |
160 | Key35=94:94 | |
161 | Key36=65293:13 | |
162 | Key37=65507:0 | |
163 | Key38=65:65 | |
164 | Key39=83:83 | |
165 | Key40=68:68 | |
166 | Key41=70:70 | |
167 | Key42=71:71 | |
168 | Key43=72:72 | |
169 | Key44=74:74 | |
170 | Key45=75:75 | |
171 | Key46=76:76 | |
172 | Key47=198:198 | |
173 | Key48=216:216 | |
174 | Key49=167:167 | |
175 | Key50=65505:0 | |
176 | Key51=42:42 | |
177 | Key52=90:90 | |
178 | Key53=88:88 | |
179 | Key54=67:67 | |
180 | Key55=86:86 | |
181 | Key56=66:66 | |
182 | Key57=78:78 | |
183 | Key58=77:77 | |
184 | Key59=59:59 | |
185 | Key60=58:58 | |
186 | Key61=95:95 | |
187 | Key62=65506:0 | |
188 | Key63=65450:42 | |
189 | Key64=65511:0 | |
190 | Key65=32:32 | |
191 | Key66=65509:0 | |
192 | Key67=65470:0 | |
193 | Key68=65471:0 | |
194 | Key69=65472:0 | |
195 | Key70=65473:0 | |
196 | Key71=65474:0 | |
197 | Key72=65475:0 | |
198 | Key73=65476:0 | |
199 | Key74=65477:0 | |
200 | Key75=65478:0 | |
201 | Key76=65479:0 | |
202 | Key77=65273:0 | |
203 | Key78=65300:0 | |
204 | Key79=65463:55 | |
205 | Key80=65464:56 | |
206 | Key81=65465:57 | |
207 | Key82=65453:45 | |
208 | Key83=65460:52 | |
209 | Key84=65461:53 | |
210 | Key85=65462:54 | |
211 | Key86=65451:43 | |
212 | Key87=65457:49 | |
213 | Key88=65458:50 | |
214 | Key89=65459:51 | |
215 | Key90=65456:48 | |
216 | Key91=65452:44 | |
217 | Key92=0:0 | |
218 | Key93=65406:0 | |
219 | Key94=62:62 | |
220 | Key95=65480:0 | |
221 | Key96=65481:0 | |
222 | Key97=65360:0 | |
223 | Key98=65362:0 | |
224 | Key99=65365:0 | |
225 | Key100=65361:0 | |
226 | Key101=0:0 | |
227 | Key102=65363:0 | |
228 | Key103=65367:0 | |
229 | Key104=65364:0 | |
230 | Key105=65366:0 | |
231 | Key106=65379:0 | |
232 | Key107=65535:127 | |
233 | Key108=65421:13 | |
234 | Key109=65508:0 | |
235 | Key110=65299:0 | |
236 | Key111=65377:0 | |
237 | Key112=65455:47 | |
238 | Key113=65027:0 | |
239 | Key114=0:0 | |
240 | Key115=65515:0 | |
241 | Key116=65516:0 | |
242 | Key117=65383:0 | |
243 | Key118=0:0 | |
244 | Key119=0:0 | |
245 | Key120=0:0 | |
246 | Key121=0:0 | |
247 | Key122=0:0 | |
248 | Key123=0:0 | |
249 | Key124=65027:0 | |
250 | Key125=65513:0 | |
251 | Key126=65469:61 | |
252 | Key127=65515:0 | |
253 | Key128=65517:0 | |
254 | Key129=0:0 | |
255 | Key130=0:0 | |
256 | Key131=0:0 | |
257 | Key132=0:0 | |
258 | Key133=0:0 | |
259 | Key134=0:0 | |
260 | Key135=0:0 | |
261 | Key136=0:0 | |
262 | Key137=0:0 | |
263 | ||
264 | [altgr] | |
265 | Key8=0:0 | |
266 | Key9=65307:27 | |
267 | Key10=161:161 | |
268 | Key11=64:64 | |
269 | Key12=163:163 | |
270 | Key13=36:36 | |
271 | Key14=8364:8364 | |
272 | Key15=165:165 | |
273 | Key16=123:123 | |
274 | Key17=91:91 | |
275 | Key18=93:93 | |
276 | Key19=125:125 | |
277 | Key20=92:92 | |
278 | Key21=124:124 | |
279 | Key22=65288:8 | |
280 | Key23=65289:9 | |
281 | Key24=64:64 | |
282 | Key25=435:322 | |
283 | Key26=8364:8364 | |
284 | Key27=174:174 | |
285 | Key28=254:254 | |
286 | Key29=2299:8592 | |
287 | Key30=2302:8595 | |
288 | Key31=2301:8594 | |
289 | Key32=5053:339 | |
290 | Key33=254:254 | |
291 | Key34=65111:168 | |
292 | Key35=126:126 | |
293 | Key36=65293:13 | |
294 | Key37=65507:0 | |
295 | Key38=170:170 | |
296 | Key39=223:223 | |
297 | Key40=240:240 | |
298 | Key41=496:273 | |
299 | Key42=959:331 | |
300 | Key43=689:295 | |
301 | Key44=106:106 | |
302 | Key45=930:312 | |
303 | Key46=435:322 | |
304 | Key47=248:248 | |
305 | Key48=230:230 | |
306 | Key49=182:182 | |
307 | Key50=65505:0 | |
308 | Key51=180:180 | |
309 | Key52=171:171 | |
310 | Key53=187:187 | |
311 | Key54=169:169 | |
312 | Key55=2770:8220 | |
313 | Key56=2771:8221 | |
314 | Key57=110:110 | |
315 | Key58=181:181 | |
316 | Key59=65115:184 | |
317 | Key60=183:183 | |
318 | Key61=65120:0 | |
319 | Key62=65506:0 | |
320 | Key63=65450:42 | |
321 | Key64=65513:0 | |
322 | Key65=32:32 | |
323 | Key66=65509:0 | |
324 | Key67=65470:0 | |
325 | Key68=65471:0 | |
326 | Key69=65472:0 | |
327 | Key70=65473:0 | |
328 | Key71=65474:0 | |
329 | Key72=65475:0 | |
330 | Key73=65476:0 | |
331 | Key74=65477:0 | |
332 | Key75=65478:0 | |
333 | Key76=65479:0 | |
334 | Key77=65407:0 | |
335 | Key78=65300:0 | |
336 | Key79=65429:0 | |
337 | Key80=65431:0 | |
338 | Key81=65434:0 | |
339 | Key82=65453:45 | |
340 | Key83=65430:0 | |
341 | Key84=65437:0 | |
342 | Key85=65432:0 | |
343 | Key86=65451:43 | |
344 | Key87=65436:0 | |
345 | Key88=65433:0 | |
346 | Key89=65435:0 | |
347 | Key90=65438:0 | |
348 | Key91=65439:0 | |
349 | Key92=0:0 | |
350 | Key93=65406:0 | |
351 | Key94=92:92 | |
352 | Key95=65480:0 | |
353 | Key96=65481:0 | |
354 | Key97=65360:0 | |
355 | Key98=65362:0 | |
356 | Key99=65365:0 | |
357 | Key100=65361:0 | |
358 | Key101=0:0 | |
359 | Key102=65363:0 | |
360 | Key103=65367:0 | |
361 | Key104=65364:0 | |
362 | Key105=65366:0 | |
363 | Key106=65379:0 | |
364 | Key107=65535:127 | |
365 | Key108=65421:13 | |
366 | Key109=65508:0 | |
367 | Key110=65299:0 | |
368 | Key111=0:0 | |
369 | Key112=65455:47 | |
370 | Key113=65027:0 | |
371 | Key114=0:0 | |
372 | Key115=65515:0 | |
373 | Key116=65516:0 | |
374 | Key117=65383:0 | |
375 | Key118=0:0 | |
376 | Key119=0:0 | |
377 | Key120=0:0 | |
378 | Key121=0:0 | |
379 | Key122=0:0 | |
380 | Key123=0:0 | |
381 | Key124=65027:0 | |
382 | Key125=0:0 | |
383 | Key126=65469:61 | |
384 | Key127=0:0 | |
385 | Key128=0:0 | |
386 | Key129=0:0 | |
387 | Key130=0:0 | |
388 | Key131=0:0 | |
389 | Key132=0:0 | |
390 | Key133=0:0 | |
391 | Key134=0:0 | |
392 | Key135=0:0 | |
393 | Key136=0:0 | |
394 | Key137=0:0 | |
395 | ||
396 | [capslock] | |
397 | Key8=0:0 | |
398 | Key9=65307:27 | |
399 | Key10=49:49 | |
400 | Key11=50:50 | |
401 | Key12=51:51 | |
402 | Key13=52:52 | |
403 | Key14=53:53 | |
404 | Key15=54:54 | |
405 | Key16=55:55 | |
406 | Key17=56:56 | |
407 | Key18=57:57 | |
408 | Key19=48:48 | |
409 | Key20=43:43 | |
410 | Key21=65105:180 | |
411 | Key22=65288:8 | |
412 | Key23=65289:9 | |
413 | Key24=81:81 | |
414 | Key25=87:87 | |
415 | Key26=69:69 | |
416 | Key27=82:82 | |
417 | Key28=84:84 | |
418 | Key29=89:89 | |
419 | Key30=85:85 | |
420 | Key31=73:73 | |
421 | Key32=79:79 | |
422 | Key33=80:80 | |
423 | Key34=197:197 | |
424 | Key35=65111:168 | |
425 | Key36=65293:13 | |
426 | Key37=65507:0 | |
427 | Key38=65:65 | |
428 | Key39=83:83 | |
429 | Key40=68:68 | |
430 | Key41=70:70 | |
431 | Key42=71:71 | |
432 | Key43=72:72 | |
433 | Key44=74:74 | |
434 | Key45=75:75 | |
435 | Key46=76:76 | |
436 | Key47=214:214 | |
437 | Key48=196:196 | |
438 | Key49=167:167 | |
439 | Key50=65505:0 | |
440 | Key51=39:39 | |
441 | Key52=90:90 | |
442 | Key53=88:88 | |
443 | Key54=67:67 | |
444 | Key55=86:86 | |
445 | Key56=66:66 | |
446 | Key57=78:78 | |
447 | Key58=77:77 | |
448 | Key59=44:44 | |
449 | Key60=46:46 | |
450 | Key61=45:45 | |
451 | Key62=65506:0 | |
452 | Key63=65450:42 | |
453 | Key64=65513:0 | |
454 | Key65=32:32 | |
455 | Key66=65509:0 | |
456 | Key67=65470:0 | |
457 | Key68=65471:0 | |
458 | Key69=65472:0 | |
459 | Key70=65473:0 | |
460 | Key71=65474:0 | |
461 | Key72=65475:0 | |
462 | Key73=65476:0 | |
463 | Key74=65477:0 | |
464 | Key75=65478:0 | |
465 | Key76=65479:0 | |
466 | Key77=65407:0 | |
467 | Key78=65300:0 | |
468 | Key79=65429:0 | |
469 | Key80=65431:0 | |
470 | Key81=65434:0 | |
471 | Key82=65453:45 | |
472 | Key83=65430:0 | |
473 | Key84=65437:0 | |
474 | Key85=65432:0 | |
475 | Key86=65451:43 | |
476 | Key87=65436:0 | |
477 | Key88=65433:0 | |
478 | Key89=65435:0 | |
479 | Key90=65438:0 | |
480 | Key91=65439:0 | |
481 | Key92=0:0 | |
482 | Key93=65406:0 | |
483 | Key94=60:60 | |
484 | Key95=65480:0 | |
485 | Key96=65481:0 | |
486 | Key97=65360:0 | |
487 | Key98=65362:0 | |
488 | Key99=65365:0 | |
489 | Key100=65361:0 | |
490 | Key101=0:0 | |
491 | Key102=65363:0 | |
492 | Key103=65367:0 | |
493 | Key104=65364:0 | |
494 | Key105=65366:0 | |
495 | Key106=65379:0 | |
496 | Key107=65535:127 | |
497 | Key108=65421:13 | |
498 | Key109=65508:0 | |
499 | Key110=65299:0 | |
500 | Key111=65377:0 | |
501 | Key112=65455:47 | |
502 | Key113=65027:0 | |
503 | Key114=0:0 | |
504 | Key115=65515:0 | |
505 | Key116=65516:0 | |
506 | Key117=65383:0 | |
507 | Key118=0:0 | |
508 | Key119=0:0 | |
509 | Key120=0:0 | |
510 | Key121=0:0 | |
511 | Key122=0:0 | |
512 | Key123=0:0 | |
513 | Key124=65027:0 | |
514 | Key125=0:0 | |
515 | Key126=65469:61 | |
516 | Key127=0:0 | |
517 | Key128=0:0 | |
518 | Key129=0:0 | |
519 | Key130=0:0 | |
520 | Key131=0:0 | |
521 | Key132=0:0 | |
522 | Key133=0:0 | |
523 | Key134=0:0 | |
524 | Key135=0:0 | |
525 | Key136=0:0 | |
526 | Key137=0:0 | |
527 | ||
528 | [shiftcapslock] | |
529 | Key8=0:0 | |
530 | Key9=65307:27 | |
531 | Key10=33:33 | |
532 | Key11=34:34 | |
533 | Key12=35:35 | |
534 | Key13=164:164 | |
535 | Key14=37:37 | |
536 | Key15=38:38 | |
537 | Key16=47:47 | |
538 | Key17=40:40 | |
539 | Key18=41:41 | |
540 | Key19=61:61 | |
541 | Key20=63:63 | |
542 | Key21=65104:96 | |
543 | Key22=65288:8 | |
544 | Key23=65056:0 | |
545 | Key24=113:113 | |
546 | Key25=119:119 | |
547 | Key26=101:101 | |
548 | Key27=114:114 | |
549 | Key28=116:116 | |
550 | Key29=121:121 | |
551 | Key30=117:117 | |
552 | Key31=105:105 | |
553 | Key32=111:111 | |
554 | Key33=112:112 | |
555 | Key34=229:229 | |
556 | Key35=65106:94 | |
557 | Key36=65293:13 | |
558 | Key37=65507:0 | |
559 | Key38=97:97 | |
560 | Key39=115:115 | |
561 | Key40=100:100 | |
562 | Key41=102:102 | |
563 | Key42=103:103 | |
564 | Key43=104:104 | |
565 | Key44=106:106 | |
566 | Key45=107:107 | |
567 | Key46=108:108 | |
568 | Key47=246:246 | |
569 | Key48=228:228 | |
570 | Key49=189:189 | |
571 | Key50=65505:0 | |
572 | Key51=42:42 | |
573 | Key52=122:122 | |
574 | Key53=120:120 | |
575 | Key54=99:99 | |
576 | Key55=118:118 | |
577 | Key56=98:98 | |
578 | Key57=110:110 | |
579 | Key58=109:109 | |
580 | Key59=59:59 | |
581 | Key60=58:58 | |
582 | Key61=95:95 | |
583 | Key62=65506:0 | |
584 | Key63=65450:42 | |
585 | Key64=65511:0 | |
586 | Key65=32:32 | |
587 | Key66=65509:0 | |
588 | Key67=65470:0 | |
589 | Key68=65471:0 | |
590 | Key69=65472:0 | |
591 | Key70=65473:0 | |
592 | Key71=65474:0 | |
593 | Key72=65475:0 | |
594 | Key73=65476:0 | |
595 | Key74=65477:0 | |
596 | Key75=65478:0 | |
597 | Key76=65479:0 | |
598 | Key77=65273:0 | |
599 | Key78=65300:0 | |
600 | Key79=65463:55 | |
601 | Key80=65464:56 | |
602 | Key81=65465:57 | |
603 | Key82=65453:45 | |
604 | Key83=65460:52 | |
605 | Key84=65461:53 | |
606 | Key85=65462:54 | |
607 | Key86=65451:43 | |
608 | Key87=65457:49 | |
609 | Key88=65458:50 | |
610 | Key89=65459:51 | |
611 | Key90=65456:48 | |
612 | Key91=65452:44 | |
613 | Key92=0:0 | |
614 | Key93=65406:0 | |
615 | Key94=62:62 | |
616 | Key95=65480:0 | |
617 | Key96=65481:0 | |
618 | Key97=65360:0 | |
619 | Key98=65362:0 | |
620 | Key99=65365:0 | |
621 | Key100=65361:0 | |
622 | Key101=0:0 | |
623 | Key102=65363:0 | |
624 | Key103=65367:0 | |
625 | Key104=65364:0 | |
626 | Key105=65366:0 | |
627 | Key106=65379:0 | |
628 | Key107=65535:127 | |
629 | Key108=65421:13 | |
630 | Key109=65508:0 | |
631 | Key110=65299:0 | |
632 | Key111=65377:0 | |
633 | Key112=65455:47 | |
634 | Key113=65027:0 | |
635 | Key114=0:0 | |
636 | Key115=65515:0 | |
637 | Key116=65516:0 | |
638 | Key117=65383:0 | |
639 | Key118=0:0 | |
640 | Key119=0:0 | |
641 | Key120=0:0 | |
642 | Key121=0:0 | |
643 | Key122=0:0 | |
644 | Key123=0:0 | |
645 | Key124=65027:0 | |
646 | Key125=65513:0 | |
647 | Key126=65469:61 | |
648 | Key127=65515:0 | |
649 | Key128=65517:0 | |
650 | Key129=0:0 | |
651 | Key130=0:0 | |
652 | Key131=0:0 | |
653 | Key132=0:0 | |
654 | Key133=0:0 | |
655 | Key134=0:0 | |
656 | Key135=0:0 | |
657 | Key136=0:0 | |
658 | Key137=0:0 |
7 | 7 | |
8 | 8 | service="xrdp-sesman" |
9 | 9 | pamdir="/etc/pam.d" |
10 | pamdir_suse="/usr/etc/pam.d" | |
10 | 11 | |
11 | 12 | guess_rules () |
12 | 13 | { |
13 | 14 | if test -s "$pamdir/password-auth"; then |
14 | 15 | rules="redhat" |
16 | return | |
17 | fi | |
18 | ||
19 | if test -s "$pamdir_suse/common-account"; then | |
20 | rules="suse" | |
15 | 21 | return |
16 | 22 | fi |
17 | 23 |
0 | #!/bin/sh | |
1 | # xrdp control script | |
2 | # Written : 1-13-2006 - Mark Balliet - posicat@pobox.com | |
3 | # maintaned by Jay Sorg | |
4 | # chkconfig: 2345 11 89 | |
5 | # description: starts xrdp | |
6 | ||
7 | ### BEGIN INIT INFO | |
8 | # Provides: xrdp | |
9 | # Required-Start: | |
10 | # Required-Stop: | |
11 | # Should-Start: | |
12 | # Should-Stop: | |
13 | # Default-Start: 2 3 4 5 | |
14 | # Default-Stop: 0 1 6 | |
15 | # Short-Description: Start and stop xrdp | |
16 | # Description: starts xrdp | |
17 | ### END INIT INFO | |
18 | ||
19 | SBINDIR=/usr/local/sbin | |
20 | LOG=/dev/null | |
21 | CFGDIR=/etc/xrdp | |
22 | ||
23 | if ! test -x $SBINDIR/xrdp | |
24 | then | |
25 | echo "xrdp is not executable" | |
26 | exit 0 | |
27 | fi | |
28 | if ! test -x $SBINDIR/xrdp-sesman | |
29 | then | |
30 | echo "xrdp-sesman is not executable" | |
31 | exit 0 | |
32 | fi | |
33 | if ! test -x $CFGDIR/startwm.sh | |
34 | then | |
35 | echo "startwm.sh is not executable" | |
36 | exit 0 | |
37 | fi | |
38 | ||
39 | xrdp_start() | |
40 | { | |
41 | echo -n "Starting: xrdp and sesman . . " | |
42 | $SBINDIR/xrdp >> $LOG | |
43 | $SBINDIR/xrdp-sesman >> $LOG | |
44 | echo "." | |
45 | sleep 1 | |
46 | return 0; | |
47 | } | |
48 | ||
49 | xrdp_stop() | |
50 | { | |
51 | echo -n "Stopping: xrdp and sesman . . " | |
52 | $SBINDIR/xrdp-sesman --kill >> $LOG | |
53 | $SBINDIR/xrdp --kill >> $LOG | |
54 | echo "." | |
55 | return 0; | |
56 | } | |
57 | ||
58 | is_xrdp_running() | |
59 | { | |
60 | ps u --noheading -C xrdp | grep -q -i xrdp | |
61 | if test $? -eq 0 | |
62 | then | |
63 | return 1; | |
64 | else | |
65 | return 0; | |
66 | fi | |
67 | } | |
68 | ||
69 | is_sesman_running() | |
70 | { | |
71 | ps u --noheading -C xrdp-sesman | grep -q -i xrdp-sesman | |
72 | if test $? -eq 0 | |
73 | then | |
74 | return 1; | |
75 | else | |
76 | return 0; | |
77 | fi | |
78 | } | |
79 | ||
80 | check_up() | |
81 | { | |
82 | # Cleanup : If sesman isn't running, but the pid exists, erase it. | |
83 | is_sesman_running | |
84 | if test $? -eq 0 | |
85 | then | |
86 | if test -e /var/run/xrdp-sesman.pid | |
87 | then | |
88 | rm /var/run/xrdp-sesman.pid | |
89 | fi | |
90 | fi | |
91 | # Cleanup : If xrdp isn't running, but the pid exists, erase it. | |
92 | is_xrdp_running | |
93 | if test $? -eq 0 | |
94 | then | |
95 | if test -e /var/run/xrdp.pid | |
96 | then | |
97 | rm /var/run/xrdp.pid | |
98 | fi | |
99 | fi | |
100 | return 0; | |
101 | } | |
102 | ||
103 | case "$1" in | |
104 | start) | |
105 | check_up | |
106 | is_xrdp_running | |
107 | if ! test $? -eq 0 | |
108 | then | |
109 | echo "xrdp is already loaded" | |
110 | exit 1 | |
111 | fi | |
112 | is_sesman_running | |
113 | if ! test $? -eq 0 | |
114 | then | |
115 | echo "sesman is already loaded" | |
116 | exit 1 | |
117 | fi | |
118 | xrdp_start | |
119 | ;; | |
120 | stop) | |
121 | check_up | |
122 | is_xrdp_running | |
123 | if test $? -eq 0 | |
124 | then | |
125 | echo "xrdp is not loaded." | |
126 | fi | |
127 | is_sesman_running | |
128 | if test $? -eq 0 | |
129 | then | |
130 | echo "sesman is not loaded." | |
131 | fi | |
132 | xrdp_stop | |
133 | ;; | |
134 | force-reload|restart) | |
135 | check_up | |
136 | echo "Restarting xrdp ..." | |
137 | xrdp_stop | |
138 | is_xrdp_running | |
139 | while ! test $? -eq 0 | |
140 | do | |
141 | check_up | |
142 | sleep 1 | |
143 | is_xrdp_running | |
144 | done | |
145 | xrdp_start | |
146 | ;; | |
147 | *) | |
148 | echo "Usage: xrdp.sh {start|stop|restart|force-reload}" | |
149 | exit 1 | |
150 | esac | |
151 | ||
152 | exit 0 |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for rfxcodec 0.1.4. | |
2 | # Generated by GNU Autoconf 2.69 for rfxcodec 0.1.5. | |
3 | 3 | # |
4 | 4 | # Report bugs to <xrdp-devel@googlegroups.com>. |
5 | 5 | # |
589 | 589 | # Identity of this package. |
590 | 590 | PACKAGE_NAME='rfxcodec' |
591 | 591 | PACKAGE_TARNAME='rfxcodec' |
592 | PACKAGE_VERSION='0.1.4' | |
593 | PACKAGE_STRING='rfxcodec 0.1.4' | |
592 | PACKAGE_VERSION='0.1.5' | |
593 | PACKAGE_STRING='rfxcodec 0.1.5' | |
594 | 594 | PACKAGE_BUGREPORT='xrdp-devel@googlegroups.com' |
595 | 595 | PACKAGE_URL='' |
596 | 596 | |
1320 | 1320 | # Omit some internal or obsolete options to make the list less imposing. |
1321 | 1321 | # This message is too long to be a string in the A/UX 3.1 sh. |
1322 | 1322 | cat <<_ACEOF |
1323 | \`configure' configures rfxcodec 0.1.4 to adapt to many kinds of systems. | |
1323 | \`configure' configures rfxcodec 0.1.5 to adapt to many kinds of systems. | |
1324 | 1324 | |
1325 | 1325 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1326 | 1326 | |
1390 | 1390 | |
1391 | 1391 | if test -n "$ac_init_help"; then |
1392 | 1392 | case $ac_init_help in |
1393 | short | recursive ) echo "Configuration of rfxcodec 0.1.4:";; | |
1393 | short | recursive ) echo "Configuration of rfxcodec 0.1.5:";; | |
1394 | 1394 | esac |
1395 | 1395 | cat <<\_ACEOF |
1396 | 1396 | |
1503 | 1503 | test -n "$ac_init_help" && exit $ac_status |
1504 | 1504 | if $ac_init_version; then |
1505 | 1505 | cat <<\_ACEOF |
1506 | rfxcodec configure 0.1.4 | |
1506 | rfxcodec configure 0.1.5 | |
1507 | 1507 | generated by GNU Autoconf 2.69 |
1508 | 1508 | |
1509 | 1509 | Copyright (C) 2012 Free Software Foundation, Inc. |
1781 | 1781 | This file contains any messages produced by compilers while |
1782 | 1782 | running configure, to aid debugging if configure makes a mistake. |
1783 | 1783 | |
1784 | It was created by rfxcodec $as_me 0.1.4, which was | |
1784 | It was created by rfxcodec $as_me 0.1.5, which was | |
1785 | 1785 | generated by GNU Autoconf 2.69. Invocation command line was |
1786 | 1786 | |
1787 | 1787 | $ $0 $@ |
2646 | 2646 | |
2647 | 2647 | # Define the identity of the package. |
2648 | 2648 | PACKAGE='rfxcodec' |
2649 | VERSION='0.1.4' | |
2649 | VERSION='0.1.5' | |
2650 | 2650 | |
2651 | 2651 | |
2652 | 2652 | cat >>confdefs.h <<_ACEOF |
13159 | 13159 | # report actual input values of CONFIG_FILES etc. instead of their |
13160 | 13160 | # values after options handling. |
13161 | 13161 | ac_log=" |
13162 | This file was extended by rfxcodec $as_me 0.1.4, which was | |
13162 | This file was extended by rfxcodec $as_me 0.1.5, which was | |
13163 | 13163 | generated by GNU Autoconf 2.69. Invocation command line was |
13164 | 13164 | |
13165 | 13165 | CONFIG_FILES = $CONFIG_FILES |
13225 | 13225 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
13226 | 13226 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
13227 | 13227 | ac_cs_version="\\ |
13228 | rfxcodec config.status 0.1.4 | |
13228 | rfxcodec config.status 0.1.5 | |
13229 | 13229 | configured by $0, generated by GNU Autoconf 2.69, |
13230 | 13230 | with options \\"\$ac_cs_config\\" |
13231 | 13231 |
0 | 0 | # Process this file with autoconf to produce a configure script |
1 | 1 | |
2 | 2 | AC_PREREQ(2.59) |
3 | AC_INIT([rfxcodec], [0.1.4], [xrdp-devel@googlegroups.com]) | |
3 | AC_INIT([rfxcodec], [0.1.5], [xrdp-devel@googlegroups.com]) | |
4 | 4 | AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) |
5 | 5 | AM_INIT_AUTOMAKE([1.6 foreign]) |
6 | 6 | AC_CONFIG_MACRO_DIR([m4]) |
83 | 83 | } |
84 | 84 | while (x < 64) |
85 | 85 | { |
86 | *lr_buf++ = r; | |
87 | *lg_buf++ = g; | |
88 | *lb_buf++ = r; | |
86 | *lb_buf++ = b; | |
87 | *lg_buf++ = g; | |
88 | *lr_buf++ = r; | |
89 | 89 | x++; |
90 | 90 | } |
91 | 91 | } |
154 | 154 | } |
155 | 155 | while (x < 64) |
156 | 156 | { |
157 | *lr_buf++ = r; | |
158 | *lg_buf++ = g; | |
159 | *lb_buf++ = b; | |
157 | *lb_buf++ = b; | |
158 | *lg_buf++ = g; | |
159 | *lr_buf++ = r; | |
160 | 160 | x++; |
161 | 161 | } |
162 | 162 | } |
256 | 256 | } |
257 | 257 | while (x < 64) |
258 | 258 | { |
259 | *lb_buf++ = b; | |
260 | *lg_buf++ = g; | |
261 | *lr_buf++ = r; | |
259 | 262 | *la_buf++ = a; |
260 | *lr_buf++ = r; | |
261 | *lg_buf++ = g; | |
262 | *lb_buf++ = r; | |
263 | 263 | x++; |
264 | 264 | } |
265 | 265 | } |
297 | 297 | } |
298 | 298 | while (x < 64) |
299 | 299 | { |
300 | *lr_buf++ = r; | |
301 | *lg_buf++ = g; | |
302 | *lb_buf++ = b; | |
300 | 303 | *la_buf++ = a; |
301 | *lr_buf++ = r; | |
302 | *lg_buf++ = g; | |
303 | *lb_buf++ = b; | |
304 | 304 | x++; |
305 | 305 | } |
306 | 306 | } |
335 | 335 | } |
336 | 336 | while (x < 64) |
337 | 337 | { |
338 | *lr_buf++ = r; | |
339 | *lg_buf++ = g; | |
340 | *lb_buf++ = b; | |
338 | *lb_buf++ = b; | |
339 | *lg_buf++ = g; | |
340 | *lr_buf++ = r; | |
341 | 341 | x++; |
342 | 342 | } |
343 | 343 | } |
809 | 809 | out_uint16_le(s, 0); /* Update capability */ |
810 | 810 | out_uint16_le(s, 0); /* Remote unshare capability */ |
811 | 811 | out_uint16_le(s, 0); /* Compression level */ |
812 | out_uint16_le(s, 0); /* Pad */ | |
812 | out_uint8(s, 1); /* refreshRectSupport */ | |
813 | out_uint8(s, 1); /* suppressOutputSupport */ | |
813 | 814 | |
814 | 815 | /* Output bitmap capability set */ |
815 | 816 | caps_count++; |
1043 | 1043 | } |
1044 | 1044 | |
1045 | 1045 | /*****************************************************************************/ |
1046 | /* 2.2.11.2.1 Refresh Rect PDU Data (TS_REFRESH_RECT_PDU) */ | |
1046 | 1047 | static int |
1047 | 1048 | xrdp_rdp_process_screen_update(struct xrdp_rdp *self, struct stream *s) |
1048 | 1049 | { |
1050 | int index; | |
1051 | int num_rects; | |
1049 | 1052 | int left; |
1050 | 1053 | int top; |
1051 | 1054 | int right; |
1053 | 1056 | int cx; |
1054 | 1057 | int cy; |
1055 | 1058 | |
1056 | in_uint8s(s, 4); /* op */ | |
1057 | in_uint16_le(s, left); | |
1058 | in_uint16_le(s, top); | |
1059 | in_uint16_le(s, right); | |
1060 | in_uint16_le(s, bottom); | |
1061 | cx = (right - left) + 1; | |
1062 | cy = (bottom - top) + 1; | |
1063 | ||
1064 | if (self->session->callback != 0) | |
1065 | { | |
1066 | self->session->callback(self->session->id, 0x4444, left, top, cx, cy); | |
1067 | } | |
1068 | ||
1059 | if (!s_check_rem(s, 4)) | |
1060 | { | |
1061 | return 1; | |
1062 | } | |
1063 | in_uint8(s, num_rects); | |
1064 | in_uint8s(s, 3); /* pad */ | |
1065 | g_writeln("xrdp_rdp_process_screen_update: num_rects %d", num_rects); | |
1066 | for (index = 0; index < num_rects; index++) | |
1067 | { | |
1068 | if (!s_check_rem(s, 8)) | |
1069 | { | |
1070 | return 1; | |
1071 | } | |
1072 | /* Inclusive Rectangle (TS_RECTANGLE16) */ | |
1073 | in_uint16_le(s, left); | |
1074 | in_uint16_le(s, top); | |
1075 | in_uint16_le(s, right); | |
1076 | in_uint16_le(s, bottom); | |
1077 | g_writeln(" left %d top %d right %d bottom %d", | |
1078 | left, top, right, bottom); | |
1079 | cx = (right - left) + 1; | |
1080 | cy = (bottom - top) + 1; | |
1081 | if (self->session->callback != 0) | |
1082 | { | |
1083 | self->session->callback(self->session->id, 0x4444, | |
1084 | left, top, cx, cy); | |
1085 | } | |
1086 | } | |
1069 | 1087 | return 0; |
1070 | 1088 | } |
1071 | 1089 | |
1209 | 1227 | } |
1210 | 1228 | |
1211 | 1229 | /*****************************************************************************/ |
1230 | static int | |
1231 | xrdp_rdp_process_suppress(struct xrdp_rdp *self, struct stream *s) | |
1232 | { | |
1233 | int allowDisplayUpdates; | |
1234 | int left; | |
1235 | int top; | |
1236 | int right; | |
1237 | int bottom; | |
1238 | ||
1239 | if (!s_check_rem(s, 1)) | |
1240 | { | |
1241 | return 1; | |
1242 | } | |
1243 | in_uint8(s, allowDisplayUpdates); | |
1244 | g_writeln("xrdp_rdp_process_suppress: allowDisplayUpdates %d bytes " | |
1245 | "left %d", allowDisplayUpdates, (int) (s->end - s->p)); | |
1246 | switch (allowDisplayUpdates) | |
1247 | { | |
1248 | case 0: /* SUPPRESS_DISPLAY_UPDATES */ | |
1249 | self->client_info.suppress_output = 1; | |
1250 | g_writeln("xrdp_rdp_process_suppress: suppress_output %d", | |
1251 | self->client_info.suppress_output); | |
1252 | if (self->session->callback != 0) | |
1253 | { | |
1254 | self->session->callback(self->session->id, 0x5559, 1, | |
1255 | 0, 0, 0); | |
1256 | } | |
1257 | break; | |
1258 | case 1: /* ALLOW_DISPLAY_UPDATES */ | |
1259 | self->client_info.suppress_output = 0; | |
1260 | if (!s_check_rem(s, 11)) | |
1261 | { | |
1262 | return 1; | |
1263 | } | |
1264 | in_uint8s(s, 3); /* pad */ | |
1265 | in_uint16_le(s, left); | |
1266 | in_uint16_le(s, top); | |
1267 | in_uint16_le(s, right); | |
1268 | in_uint16_le(s, bottom); | |
1269 | g_writeln("xrdp_rdp_process_suppress: suppress_output %d " | |
1270 | "left %d top %d right %d bottom %d", | |
1271 | self->client_info.suppress_output, | |
1272 | left, top, right, bottom); | |
1273 | if (self->session->callback != 0) | |
1274 | { | |
1275 | self->session->callback(self->session->id, 0x5559, 0, | |
1276 | MAKELONG(left, top), | |
1277 | MAKELONG(right, bottom), 0); | |
1278 | } | |
1279 | break; | |
1280 | } | |
1281 | return 0; | |
1282 | } | |
1283 | ||
1284 | /*****************************************************************************/ | |
1212 | 1285 | /* RDP_PDU_DATA */ |
1213 | 1286 | int |
1214 | 1287 | xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s) |
1215 | 1288 | { |
1216 | int data_type; | |
1217 | ||
1289 | int uncompressedLength; | |
1290 | int pduType2; | |
1291 | int compressedType; | |
1292 | int compressedLength; | |
1293 | ||
1294 | if (!s_check_rem(s, 12)) | |
1295 | { | |
1296 | return 1; | |
1297 | } | |
1218 | 1298 | in_uint8s(s, 6); |
1219 | in_uint8s(s, 2); /* len */ | |
1220 | in_uint8(s, data_type); | |
1221 | in_uint8s(s, 1); /* ctype */ | |
1222 | in_uint8s(s, 2); /* clen */ | |
1223 | DEBUG(("xrdp_rdp_process_data code %d", data_type)); | |
1224 | ||
1225 | switch (data_type) | |
1299 | in_uint16_le(s, uncompressedLength); | |
1300 | in_uint8(s, pduType2); | |
1301 | in_uint8(s, compressedType); | |
1302 | in_uint16_le(s, compressedLength); | |
1303 | if (compressedType != 0) | |
1304 | { | |
1305 | /* don't support compression */ | |
1306 | return 1; | |
1307 | } | |
1308 | if (compressedLength > uncompressedLength) | |
1309 | { | |
1310 | return 1; | |
1311 | } | |
1312 | DEBUG(("xrdp_rdp_process_data pduType2 %d", pduType2)); | |
1313 | switch (pduType2) | |
1226 | 1314 | { |
1227 | 1315 | case RDP_DATA_PDU_POINTER: /* 27(0x1b) */ |
1228 | 1316 | xrdp_rdp_process_data_pointer(self, s); |
1236 | 1324 | case RDP_DATA_PDU_SYNCHRONISE: /* 31(0x1f) */ |
1237 | 1325 | xrdp_rdp_process_data_sync(self); |
1238 | 1326 | break; |
1239 | case 33: /* 33(0x21) ?? Invalidate an area I think */ | |
1327 | case PDUTYPE2_REFRESH_RECT: | |
1240 | 1328 | xrdp_rdp_process_screen_update(self, s); |
1241 | 1329 | break; |
1242 | case 35: /* 35(0x23) */ | |
1243 | /* 35 ?? this comes when minimizing a full screen mstsc.exe 2600 */ | |
1244 | /* I think this is saying the client no longer wants screen */ | |
1245 | /* updates and it will issue a 33 above to catch up */ | |
1246 | /* so minimized apps don't take bandwidth */ | |
1330 | case 35: /* 35(0x23) PDUTYPE2_SUPPRESS_OUTPUT */ | |
1331 | xrdp_rdp_process_suppress(self, s); | |
1247 | 1332 | break; |
1248 | 1333 | case 36: /* 36(0x24) ?? disconnect query? */ |
1249 | 1334 | /* when this message comes, send a 37 back so the client */ |
1258 | 1343 | xrdp_rdp_process_frame_ack(self, s); |
1259 | 1344 | break; |
1260 | 1345 | default: |
1261 | g_writeln("unknown in xrdp_rdp_process_data %d", data_type); | |
1346 | g_writeln("unknown in xrdp_rdp_process_data pduType2 %d", pduType2); | |
1262 | 1347 | break; |
1263 | 1348 | } |
1264 | ||
1265 | 1349 | return 0; |
1266 | 1350 | } |
1267 | 1351 | /*****************************************************************************/ |
26 | 26 | #include "log.h" |
27 | 27 | #include <freerdp/settings.h> |
28 | 28 | |
29 | #if defined(VERSION_STRUCT_RDP_FREERDP) | |
30 | #if VERSION_STRUCT_RDP_FREERDP > 1 | |
31 | #define NEUTRINORDP_HAS_SUPPRESS_OUTPUT | |
32 | #endif | |
33 | #endif | |
34 | ||
29 | 35 | #ifdef XRDP_DEBUG |
30 | 36 | #define LOG_LEVEL 99 |
31 | 37 | #else |
537 | 543 | return 1; |
538 | 544 | } |
539 | 545 | |
546 | return 0; | |
547 | } | |
548 | ||
549 | /******************************************************************************/ | |
550 | static int | |
551 | lxrdp_frame_ack(struct mod* mod, int flags, int frame_id) | |
552 | { | |
553 | return 0; | |
554 | } | |
555 | ||
556 | /******************************************************************************/ | |
557 | static int | |
558 | lxrdp_suppress_output(struct mod* mod, int suppress, | |
559 | int left, int top, int right, int bottom) | |
560 | { | |
561 | #if defined(NEUTRINORDP_HAS_SUPPRESS_OUTPUT) | |
562 | mod->inst->SendSuppressOutput(mod->inst, !suppress, left, top, right, bottom); | |
563 | #endif | |
540 | 564 | return 0; |
541 | 565 | } |
542 | 566 | |
2008 | 2032 | mod->mod_session_change = lxrdp_session_change; |
2009 | 2033 | mod->mod_get_wait_objs = lxrdp_get_wait_objs; |
2010 | 2034 | mod->mod_check_wait_objs = lxrdp_check_wait_objs; |
2035 | mod->mod_frame_ack = lxrdp_frame_ack; | |
2036 | mod->mod_suppress_output = lxrdp_suppress_output; | |
2011 | 2037 | |
2012 | 2038 | mod->inst = freerdp_new(); |
2013 | 2039 | mod->inst->PreConnect = lfreerdp_pre_connect; |
57 | 57 | int bpp; |
58 | 58 | }; |
59 | 59 | |
60 | #define CURRENT_MOD_VER 3 | |
60 | #define CURRENT_MOD_VER 4 | |
61 | 61 | |
62 | 62 | struct mod |
63 | 63 | { |
75 | 75 | int (*mod_get_wait_objs)(struct mod *v, tbus *read_objs, int *rcount, |
76 | 76 | tbus *write_objs, int *wcount, int *timeout); |
77 | 77 | int (*mod_check_wait_objs)(struct mod *v); |
78 | tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod | |
79 | functions above */ | |
78 | int (*mod_frame_ack)(struct mod* mod, int flags, int frame_id); | |
79 | int (*mod_suppress_output)(struct mod* mod, int suppress, | |
80 | int left, int top, int right, int bottom); | |
81 | tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod | |
82 | functions above */ | |
80 | 83 | /* server functions */ |
81 | 84 | int (*server_begin_update)(struct mod *v); |
82 | 85 | int (*server_end_update)(struct mod *v); |
36 | 36 | CHANSRV_EXTRA_LIBS += -lmp3lame |
37 | 37 | endif |
38 | 38 | |
39 | if XRDP_RDPSNDAUDIN | |
40 | AM_CPPFLAGS += -DXRDP_RDPSNDAUDIN | |
41 | endif | |
42 | ||
39 | 43 | AM_CFLAGS = $(X_CFLAGS) |
40 | 44 | |
41 | 45 | sbin_PROGRAMS = \ |
48 | 52 | chansrv_common.h \ |
49 | 53 | chansrv_fuse.c \ |
50 | 54 | chansrv_fuse.h \ |
55 | chansrv_xfs.c \ | |
56 | chansrv_xfs.h \ | |
51 | 57 | clipboard.c \ |
52 | 58 | clipboard.h \ |
53 | 59 | clipboard_common.h \ |
60 | 66 | irp.c \ |
61 | 67 | irp.h \ |
62 | 68 | mlog.h \ |
69 | ms-erref.h \ | |
70 | ms-fscc.h \ | |
71 | ms-rdpefs.h \ | |
72 | ms-smb2.h \ | |
63 | 73 | rail.c \ |
64 | 74 | rail.h \ |
65 | 75 | smartcard.c \ |
69 | 79 | sound.c \ |
70 | 80 | sound.h \ |
71 | 81 | xcommon.c \ |
72 | xcommon.h | |
82 | xcommon.h \ | |
83 | audin.c \ | |
84 | audin.h | |
73 | 85 | |
74 | 86 | xrdp_chansrv_LDFLAGS = \ |
75 | 87 | $(X_LIBS) |
96 | 96 | @XRDP_OPUS_TRUE@am__append_7 = -lopus |
97 | 97 | @XRDP_MP3LAME_TRUE@am__append_8 = -DXRDP_MP3LAME |
98 | 98 | @XRDP_MP3LAME_TRUE@am__append_9 = -lmp3lame |
99 | @XRDP_RDPSNDAUDIN_TRUE@am__append_10 = -DXRDP_RDPSNDAUDIN | |
99 | 100 | sbin_PROGRAMS = xrdp-chansrv$(EXEEXT) |
100 | 101 | subdir = sesman/chansrv |
101 | 102 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 |
120 | 121 | am__installdirs = "$(DESTDIR)$(sbindir)" |
121 | 122 | PROGRAMS = $(sbin_PROGRAMS) |
122 | 123 | am_xrdp_chansrv_OBJECTS = chansrv.$(OBJEXT) chansrv_common.$(OBJEXT) \ |
123 | chansrv_fuse.$(OBJEXT) clipboard.$(OBJEXT) \ | |
124 | clipboard_file.$(OBJEXT) devredir.$(OBJEXT) fifo.$(OBJEXT) \ | |
125 | irp.$(OBJEXT) rail.$(OBJEXT) smartcard.$(OBJEXT) \ | |
126 | smartcard_pcsc.$(OBJEXT) sound.$(OBJEXT) xcommon.$(OBJEXT) | |
124 | chansrv_fuse.$(OBJEXT) chansrv_xfs.$(OBJEXT) \ | |
125 | clipboard.$(OBJEXT) clipboard_file.$(OBJEXT) \ | |
126 | devredir.$(OBJEXT) fifo.$(OBJEXT) irp.$(OBJEXT) rail.$(OBJEXT) \ | |
127 | smartcard.$(OBJEXT) smartcard_pcsc.$(OBJEXT) sound.$(OBJEXT) \ | |
128 | xcommon.$(OBJEXT) audin.$(OBJEXT) | |
127 | 129 | xrdp_chansrv_OBJECTS = $(am_xrdp_chansrv_OBJECTS) |
128 | 130 | am__DEPENDENCIES_1 = |
129 | 131 | @XRDP_FUSE_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) |
155 | 157 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) |
156 | 158 | depcomp = $(SHELL) $(top_srcdir)/depcomp |
157 | 159 | am__maybe_remake_depfiles = depfiles |
158 | am__depfiles_remade = ./$(DEPDIR)/chansrv.Po \ | |
160 | am__depfiles_remade = ./$(DEPDIR)/audin.Po ./$(DEPDIR)/chansrv.Po \ | |
159 | 161 | ./$(DEPDIR)/chansrv_common.Po ./$(DEPDIR)/chansrv_fuse.Po \ |
160 | ./$(DEPDIR)/clipboard.Po ./$(DEPDIR)/clipboard_file.Po \ | |
161 | ./$(DEPDIR)/devredir.Po ./$(DEPDIR)/fifo.Po ./$(DEPDIR)/irp.Po \ | |
162 | ./$(DEPDIR)/rail.Po ./$(DEPDIR)/smartcard.Po \ | |
163 | ./$(DEPDIR)/smartcard_pcsc.Po ./$(DEPDIR)/sound.Po \ | |
164 | ./$(DEPDIR)/xcommon.Po | |
162 | ./$(DEPDIR)/chansrv_xfs.Po ./$(DEPDIR)/clipboard.Po \ | |
163 | ./$(DEPDIR)/clipboard_file.Po ./$(DEPDIR)/devredir.Po \ | |
164 | ./$(DEPDIR)/fifo.Po ./$(DEPDIR)/irp.Po ./$(DEPDIR)/rail.Po \ | |
165 | ./$(DEPDIR)/smartcard.Po ./$(DEPDIR)/smartcard_pcsc.Po \ | |
166 | ./$(DEPDIR)/sound.Po ./$(DEPDIR)/xcommon.Po | |
165 | 167 | am__mv = mv -f |
166 | 168 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
167 | 169 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
363 | 365 | -DXRDP_PID_PATH=\"${localstatedir}/run\" \ |
364 | 366 | -DXRDP_SOCKET_PATH=\"${socketdir}\" -I$(top_srcdir)/common \ |
365 | 367 | $(am__append_1) $(am__append_2) $(am__append_4) \ |
366 | $(am__append_6) $(am__append_8) | |
368 | $(am__append_6) $(am__append_8) $(am__append_10) | |
367 | 369 | CHANSRV_EXTRA_LIBS = $(am__append_3) $(am__append_5) $(am__append_7) \ |
368 | 370 | $(am__append_9) |
369 | 371 | AM_CFLAGS = $(X_CFLAGS) |
374 | 376 | chansrv_common.h \ |
375 | 377 | chansrv_fuse.c \ |
376 | 378 | chansrv_fuse.h \ |
379 | chansrv_xfs.c \ | |
380 | chansrv_xfs.h \ | |
377 | 381 | clipboard.c \ |
378 | 382 | clipboard.h \ |
379 | 383 | clipboard_common.h \ |
386 | 390 | irp.c \ |
387 | 391 | irp.h \ |
388 | 392 | mlog.h \ |
393 | ms-erref.h \ | |
394 | ms-fscc.h \ | |
395 | ms-rdpefs.h \ | |
396 | ms-smb2.h \ | |
389 | 397 | rail.c \ |
390 | 398 | rail.h \ |
391 | 399 | smartcard.c \ |
395 | 403 | sound.c \ |
396 | 404 | sound.h \ |
397 | 405 | xcommon.c \ |
398 | xcommon.h | |
406 | xcommon.h \ | |
407 | audin.c \ | |
408 | audin.h | |
399 | 409 | |
400 | 410 | xrdp_chansrv_LDFLAGS = \ |
401 | 411 | $(X_LIBS) |
498 | 508 | distclean-compile: |
499 | 509 | -rm -f *.tab.c |
500 | 510 | |
511 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audin.Po@am__quote@ # am--include-marker | |
501 | 512 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chansrv.Po@am__quote@ # am--include-marker |
502 | 513 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chansrv_common.Po@am__quote@ # am--include-marker |
503 | 514 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chansrv_fuse.Po@am__quote@ # am--include-marker |
515 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chansrv_xfs.Po@am__quote@ # am--include-marker | |
504 | 516 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clipboard.Po@am__quote@ # am--include-marker |
505 | 517 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clipboard_file.Po@am__quote@ # am--include-marker |
506 | 518 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devredir.Po@am__quote@ # am--include-marker |
673 | 685 | mostlyclean-am |
674 | 686 | |
675 | 687 | distclean: distclean-am |
676 | -rm -f ./$(DEPDIR)/chansrv.Po | |
688 | -rm -f ./$(DEPDIR)/audin.Po | |
689 | -rm -f ./$(DEPDIR)/chansrv.Po | |
677 | 690 | -rm -f ./$(DEPDIR)/chansrv_common.Po |
678 | 691 | -rm -f ./$(DEPDIR)/chansrv_fuse.Po |
692 | -rm -f ./$(DEPDIR)/chansrv_xfs.Po | |
679 | 693 | -rm -f ./$(DEPDIR)/clipboard.Po |
680 | 694 | -rm -f ./$(DEPDIR)/clipboard_file.Po |
681 | 695 | -rm -f ./$(DEPDIR)/devredir.Po |
731 | 745 | installcheck-am: |
732 | 746 | |
733 | 747 | maintainer-clean: maintainer-clean-am |
734 | -rm -f ./$(DEPDIR)/chansrv.Po | |
748 | -rm -f ./$(DEPDIR)/audin.Po | |
749 | -rm -f ./$(DEPDIR)/chansrv.Po | |
735 | 750 | -rm -f ./$(DEPDIR)/chansrv_common.Po |
736 | 751 | -rm -f ./$(DEPDIR)/chansrv_fuse.Po |
752 | -rm -f ./$(DEPDIR)/chansrv_xfs.Po | |
737 | 753 | -rm -f ./$(DEPDIR)/clipboard.Po |
738 | 754 | -rm -f ./$(DEPDIR)/clipboard_file.Po |
739 | 755 | -rm -f ./$(DEPDIR)/devredir.Po |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * Copyright (C) Jay Sorg 2019 | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * MS-RDPEAI | |
18 | * | |
19 | */ | |
20 | ||
21 | #if defined(HAVE_CONFIG_H) | |
22 | #include <config_ac.h> | |
23 | #endif | |
24 | ||
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
28 | ||
29 | #include "os_calls.h" | |
30 | #include "chansrv.h" | |
31 | #include "log.h" | |
32 | #include "xrdp_constants.h" | |
33 | #include "fifo.h" | |
34 | ||
35 | #define MSG_SNDIN_VERSION 1 | |
36 | #define MSG_SNDIN_FORMATS 2 | |
37 | #define MSG_SNDIN_OPEN 3 | |
38 | #define MSG_SNDIN_OPEN_REPLY 4 | |
39 | #define MSG_SNDIN_DATA_INCOMING 5 | |
40 | #define MSG_SNDIN_DATA 6 | |
41 | #define MSG_SNDIN_FORMATCHANGE 7 | |
42 | ||
43 | #define AUDIN_VERSION 0x00000001 | |
44 | ||
45 | #define AUDIN_NAME "AUDIO_INPUT" | |
46 | #define AUDIN_FLAGS 1 /* WTS_CHANNEL_OPTION_DYNAMIC */ | |
47 | ||
48 | extern FIFO g_in_fifo; /* in sound.c */ | |
49 | extern int g_bytes_in_fifo; /* in sound.c */ | |
50 | ||
51 | struct xr_wave_format_ex | |
52 | { | |
53 | int wFormatTag; | |
54 | int nChannels; | |
55 | int nSamplesPerSec; | |
56 | int nAvgBytesPerSec; | |
57 | int nBlockAlign; | |
58 | int wBitsPerSample; | |
59 | int cbSize; | |
60 | uint8_t *data; | |
61 | }; | |
62 | ||
63 | static uint8_t g_pcm_44100_data[] = { 0 }; | |
64 | static struct xr_wave_format_ex g_pcm_44100 = | |
65 | { | |
66 | WAVE_FORMAT_PCM, /* wFormatTag */ | |
67 | 2, /* num of channels */ | |
68 | 44100, /* samples per sec */ | |
69 | 176400, /* avg bytes per sec */ | |
70 | 4, /* block align */ | |
71 | 16, /* bits per sample */ | |
72 | 0, /* data size */ | |
73 | g_pcm_44100_data /* data */ | |
74 | }; | |
75 | ||
76 | static struct chansrv_drdynvc_procs g_audin_info; | |
77 | static int g_audin_chanid; | |
78 | static struct stream *g_in_s; | |
79 | ||
80 | static struct xr_wave_format_ex *g_server_formats[] = | |
81 | { | |
82 | &g_pcm_44100, | |
83 | NULL | |
84 | }; | |
85 | ||
86 | static struct xr_wave_format_ex **g_client_formats = NULL; | |
87 | ||
88 | static int g_current_format = 0; /* index in g_client_formats */ | |
89 | ||
90 | /*****************************************************************************/ | |
91 | static int | |
92 | cleanup_client_formats(void) | |
93 | { | |
94 | int index; | |
95 | ||
96 | if (g_client_formats == NULL) | |
97 | { | |
98 | return 0; | |
99 | } | |
100 | index = 0; | |
101 | while (g_client_formats[index] != NULL) | |
102 | { | |
103 | g_free(g_client_formats[index]->data); | |
104 | g_free(g_client_formats[index]); | |
105 | index++; | |
106 | } | |
107 | g_free(g_client_formats); | |
108 | g_client_formats = NULL; | |
109 | return 0; | |
110 | } | |
111 | ||
112 | /*****************************************************************************/ | |
113 | static int | |
114 | audin_send_version(int chan_id) | |
115 | { | |
116 | int error; | |
117 | int bytes; | |
118 | struct stream *s; | |
119 | ||
120 | LOG(0, ("audin_send_version:")); | |
121 | make_stream(s); | |
122 | init_stream(s, 32); | |
123 | out_uint8(s, MSG_SNDIN_VERSION); | |
124 | out_uint32_le(s, AUDIN_VERSION); | |
125 | s_mark_end(s); | |
126 | bytes = (int) (s->end - s->data); | |
127 | error = chansrv_drdynvc_data(chan_id, s->data, bytes); | |
128 | free_stream(s); | |
129 | return error; | |
130 | } | |
131 | ||
132 | /*****************************************************************************/ | |
133 | static int | |
134 | audin_send_formats(int chan_id) | |
135 | { | |
136 | int error; | |
137 | int bytes; | |
138 | int num_formats; | |
139 | int index; | |
140 | struct stream *s; | |
141 | struct xr_wave_format_ex *wf; | |
142 | ||
143 | LOG(0, ("audin_send_formats:")); | |
144 | num_formats = sizeof(g_server_formats) / | |
145 | sizeof(g_server_formats[0]) - 1; | |
146 | make_stream(s); | |
147 | init_stream(s, 8192 * num_formats); | |
148 | out_uint8(s, MSG_SNDIN_FORMATS); | |
149 | out_uint32_le(s, num_formats); | |
150 | out_uint32_le(s, 0); /* cbSizeFormatsPacket */ | |
151 | for (index = 0; index < num_formats; index++) | |
152 | { | |
153 | wf = g_server_formats[index]; | |
154 | LOG(0, ("audin_send_formats: sending format wFormatTag 0x%4.4x " | |
155 | "nChannels %d nSamplesPerSec %d", | |
156 | wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec)); | |
157 | out_uint16_le(s, wf->wFormatTag); | |
158 | out_uint16_le(s, wf->nChannels); | |
159 | out_uint32_le(s, wf->nSamplesPerSec); | |
160 | out_uint32_le(s, wf->nAvgBytesPerSec); | |
161 | out_uint16_le(s, wf->nBlockAlign); | |
162 | out_uint16_le(s, wf->wBitsPerSample); | |
163 | out_uint16_le(s, wf->cbSize); | |
164 | if (wf->cbSize > 0) | |
165 | { | |
166 | out_uint8p(s, wf->data, wf->cbSize); | |
167 | } | |
168 | } | |
169 | s_mark_end(s); | |
170 | bytes = (int) (s->end - s->data); | |
171 | error = chansrv_drdynvc_data(chan_id, s->data, bytes); | |
172 | free_stream(s); | |
173 | return error; | |
174 | } | |
175 | ||
176 | /*****************************************************************************/ | |
177 | static int | |
178 | audin_send_open(int chan_id) | |
179 | { | |
180 | int error; | |
181 | int bytes; | |
182 | struct stream *s; | |
183 | struct xr_wave_format_ex *wf; | |
184 | ||
185 | LOG(0, ("audin_send_open:")); | |
186 | make_stream(s); | |
187 | init_stream(s, 8192); | |
188 | out_uint8(s, MSG_SNDIN_OPEN); | |
189 | out_uint32_le(s, 2048); /* FramesPerPacket */ | |
190 | out_uint32_le(s, g_current_format); /* initialFormat */ | |
191 | wf = g_client_formats[g_current_format]; | |
192 | out_uint16_le(s, wf->wFormatTag); | |
193 | out_uint16_le(s, wf->nChannels); | |
194 | out_uint32_le(s, wf->nSamplesPerSec); | |
195 | out_uint32_le(s, wf->nAvgBytesPerSec); | |
196 | out_uint16_le(s, wf->nBlockAlign); | |
197 | out_uint16_le(s, wf->wBitsPerSample); | |
198 | bytes = wf->cbSize; | |
199 | out_uint16_le(s, bytes); | |
200 | if (bytes > 0) | |
201 | { | |
202 | out_uint8p(s, wf->data, bytes); | |
203 | } | |
204 | s_mark_end(s); | |
205 | bytes = (int) (s->end - s->data); | |
206 | error = chansrv_drdynvc_data(chan_id, s->data, bytes); | |
207 | free_stream(s); | |
208 | return error; | |
209 | } | |
210 | ||
211 | /*****************************************************************************/ | |
212 | static int | |
213 | audin_process_version(int chan_id, struct stream *s) | |
214 | { | |
215 | int version; | |
216 | ||
217 | LOG(0, ("audin_process_version:")); | |
218 | if (!s_check_rem(s, 4)) | |
219 | { | |
220 | LOG(0, ("audin_process_version: parse error")); | |
221 | return 1; | |
222 | } | |
223 | in_uint32_le(s, version); | |
224 | LOG(0, ("audin_process_version: version %d", version)); | |
225 | return audin_send_formats(chan_id); | |
226 | } | |
227 | ||
228 | /*****************************************************************************/ | |
229 | static int | |
230 | audin_process_formats(int chan_id, struct stream *s) | |
231 | { | |
232 | int index; | |
233 | int num_formats; | |
234 | struct xr_wave_format_ex *wf; | |
235 | ||
236 | LOG(0, ("audin_process_formats:")); | |
237 | cleanup_client_formats(); | |
238 | if (!s_check_rem(s, 8)) | |
239 | { | |
240 | LOG(0, ("audin_process_formats: parse error")); | |
241 | return 1; | |
242 | } | |
243 | in_uint32_le(s, num_formats); | |
244 | in_uint8s(s, 4); /* cbSizeFormatsPacket */ | |
245 | g_client_formats = g_new0(struct xr_wave_format_ex *, num_formats + 1); | |
246 | for (index = 0; index < num_formats; index++) | |
247 | { | |
248 | if (!s_check_rem(s, 18)) | |
249 | { | |
250 | LOG(0, ("audin_process_formats: parse error")); | |
251 | return 1; | |
252 | } | |
253 | wf = g_new0(struct xr_wave_format_ex, 1); | |
254 | g_client_formats[index] = wf; | |
255 | in_uint16_le(s, wf->wFormatTag); | |
256 | in_uint16_le(s, wf->nChannels); | |
257 | in_uint32_le(s, wf->nSamplesPerSec); | |
258 | in_uint32_le(s, wf->nAvgBytesPerSec); | |
259 | in_uint16_le(s, wf->nBlockAlign); | |
260 | in_uint16_le(s, wf->wBitsPerSample); | |
261 | in_uint16_le(s, wf->cbSize); | |
262 | LOG(0, ("audin_process_formats: recved format wFormatTag 0x%4.4x " | |
263 | "nChannels %d nSamplesPerSec %d", | |
264 | wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec)); | |
265 | if (wf->cbSize > 0) | |
266 | { | |
267 | if (!s_check_rem(s, wf->cbSize)) | |
268 | { | |
269 | LOG(0, ("audin_process_formats: parse error")); | |
270 | return 1; | |
271 | } | |
272 | wf->data = g_new0(uint8_t, wf->cbSize); | |
273 | in_uint8a(s, wf->data, wf->cbSize); | |
274 | } | |
275 | } | |
276 | audin_send_open(chan_id); | |
277 | return 0; | |
278 | } | |
279 | ||
280 | /*****************************************************************************/ | |
281 | static int | |
282 | audin_process_open_reply(int chan_id, struct stream *s) | |
283 | { | |
284 | int result; | |
285 | ||
286 | if (!s_check_rem(s, 4)) | |
287 | { | |
288 | LOG(0, ("audin_process_open_reply: parse error")); | |
289 | return 1; | |
290 | } | |
291 | in_uint32_le(s, result); | |
292 | LOG(0, ("audin_process_open_reply: result 0x%8.8x", result)); | |
293 | return 0; | |
294 | } | |
295 | ||
296 | /*****************************************************************************/ | |
297 | static int | |
298 | audin_process_incoming_data(int chan_id, struct stream *s) | |
299 | { | |
300 | LOG(10, ("audin_process_incoming_data:")); | |
301 | return 0; | |
302 | } | |
303 | ||
304 | /*****************************************************************************/ | |
305 | static int | |
306 | audin_process_data(int chan_id, struct stream *s) | |
307 | { | |
308 | int data_bytes; | |
309 | struct stream *ls; | |
310 | ||
311 | data_bytes = (int) (s->end - s->p); | |
312 | LOG(10, ("audin_process_data: data_bytes %d", data_bytes)); | |
313 | ||
314 | xstream_new(ls, data_bytes); | |
315 | g_memcpy(ls->data, s->p, data_bytes); | |
316 | ls->p += data_bytes; | |
317 | s_mark_end(ls); | |
318 | fifo_insert(&g_in_fifo, (void *) ls); | |
319 | g_bytes_in_fifo += data_bytes; | |
320 | ||
321 | return 0; | |
322 | } | |
323 | ||
324 | /*****************************************************************************/ | |
325 | static int | |
326 | audin_process_format_change(int chan_id, struct stream *s) | |
327 | { | |
328 | LOG(0, ("audin_process_format_change:")); | |
329 | if (!s_check_rem(s, 4)) | |
330 | { | |
331 | LOG(0, ("audin_process_format_change: parse error")); | |
332 | return 1; | |
333 | } | |
334 | in_uint32_le(s, g_current_format); | |
335 | LOG(0, ("audin_process_format_change: g_current_format %d", | |
336 | g_current_format)); | |
337 | return 0; | |
338 | } | |
339 | ||
340 | /*****************************************************************************/ | |
341 | static int | |
342 | audin_process_msg(int chan_id, struct stream *s) | |
343 | { | |
344 | int code; | |
345 | ||
346 | LOG(10, ("audin_process_msg:")); | |
347 | if (!s_check_rem(s, 1)) | |
348 | { | |
349 | LOG(0, ("audin_process_msg: parse error")); | |
350 | return 1; | |
351 | } | |
352 | in_uint8(s, code); | |
353 | LOG(10, ("audin_process_msg: code %d", code)); | |
354 | switch (code) | |
355 | { | |
356 | case MSG_SNDIN_VERSION: | |
357 | return audin_process_version(chan_id, s); | |
358 | case MSG_SNDIN_FORMATS: | |
359 | return audin_process_formats(chan_id, s); | |
360 | case MSG_SNDIN_OPEN_REPLY: | |
361 | return audin_process_open_reply(chan_id, s); | |
362 | case MSG_SNDIN_DATA_INCOMING: | |
363 | return audin_process_incoming_data(chan_id, s); | |
364 | case MSG_SNDIN_DATA: | |
365 | return audin_process_data(chan_id, s); | |
366 | case MSG_SNDIN_FORMATCHANGE: | |
367 | return audin_process_format_change(chan_id, s); | |
368 | default: | |
369 | LOG(0, ("audin_process_msg: unprocessed code %d", code)); | |
370 | break; | |
371 | } | |
372 | return 0; | |
373 | } | |
374 | ||
375 | /*****************************************************************************/ | |
376 | static int | |
377 | audin_open_response(int chan_id, int creation_status) | |
378 | { | |
379 | LOG(0, ("audin_open_response: creation_status 0x%8.8x", creation_status)); | |
380 | if (creation_status == 0) | |
381 | { | |
382 | return audin_send_version(chan_id); | |
383 | } | |
384 | return 0; | |
385 | } | |
386 | ||
387 | /*****************************************************************************/ | |
388 | static int | |
389 | audin_close_response(int chan_id) | |
390 | { | |
391 | LOG(0, ("audin_close_response:")); | |
392 | g_audin_chanid = 0; | |
393 | cleanup_client_formats(); | |
394 | free_stream(g_in_s); | |
395 | g_in_s = NULL; | |
396 | return 0; | |
397 | } | |
398 | ||
399 | /*****************************************************************************/ | |
400 | static int | |
401 | audin_data_fragment(int chan_id, char *data, int bytes) | |
402 | { | |
403 | int rv; | |
404 | int left; | |
405 | ||
406 | LOG(10, ("audin_data_fragment:")); | |
407 | if (!s_check_rem(g_in_s, bytes)) | |
408 | { | |
409 | left = (int) (g_in_s->end - g_in_s->p); | |
410 | LOG(0, ("audin_data_fragment: error bytes %d left %d", bytes, left)); | |
411 | return 1; | |
412 | } | |
413 | out_uint8a(g_in_s, data, bytes); | |
414 | if (g_in_s->p == g_in_s->end) | |
415 | { | |
416 | g_in_s->p = g_in_s->data; | |
417 | rv = audin_process_msg(chan_id, g_in_s); | |
418 | free_stream(g_in_s); | |
419 | g_in_s = NULL; | |
420 | return rv; | |
421 | } | |
422 | return 0; | |
423 | } | |
424 | ||
425 | /*****************************************************************************/ | |
426 | static int | |
427 | audin_data_first(int chan_id, char *data, int bytes, int total_bytes) | |
428 | { | |
429 | LOG(10, ("audin_data_first:")); | |
430 | if (g_in_s != NULL) | |
431 | { | |
432 | LOG(0, ("audin_data_first: warning g_in_s is not nil")); | |
433 | free_stream(g_in_s); | |
434 | } | |
435 | make_stream(g_in_s); | |
436 | init_stream(g_in_s, total_bytes); | |
437 | g_in_s->end = g_in_s->data + total_bytes; | |
438 | return audin_data_fragment(chan_id, data, bytes); | |
439 | } | |
440 | ||
441 | /*****************************************************************************/ | |
442 | static int | |
443 | audin_data(int chan_id, char *data, int bytes) | |
444 | { | |
445 | struct stream ls; | |
446 | ||
447 | LOG(10, ("audin_data:")); | |
448 | //g_hexdump(data, bytes); | |
449 | if (g_in_s == NULL) | |
450 | { | |
451 | g_memset(&ls, 0, sizeof(ls)); | |
452 | ls.data = data; | |
453 | ls.p = ls.data; | |
454 | ls.end = ls.p + bytes; | |
455 | return audin_process_msg(chan_id, &ls); | |
456 | } | |
457 | return audin_data_fragment(chan_id, data, bytes); | |
458 | } | |
459 | ||
460 | /*****************************************************************************/ | |
461 | int | |
462 | audin_init(void) | |
463 | { | |
464 | LOG(0, ("audin_init:")); | |
465 | g_memset(&g_audin_info, 0, sizeof(g_audin_info)); | |
466 | g_audin_info.open_response = audin_open_response; | |
467 | g_audin_info.close_response = audin_close_response; | |
468 | g_audin_info.data_first = audin_data_first; | |
469 | g_audin_info.data = audin_data; | |
470 | g_audin_chanid = 0; | |
471 | g_in_s = NULL; | |
472 | return 0; | |
473 | } | |
474 | ||
475 | /*****************************************************************************/ | |
476 | int | |
477 | audin_deinit(void) | |
478 | { | |
479 | LOG(0, ("audin_deinit:")); | |
480 | return 0; | |
481 | } | |
482 | ||
483 | /*****************************************************************************/ | |
484 | int | |
485 | audin_start(void) | |
486 | { | |
487 | int error; | |
488 | struct stream* s; | |
489 | ||
490 | LOG(0, ("audin_start:")); | |
491 | if (g_audin_chanid != 0) | |
492 | { | |
493 | return 1; | |
494 | } | |
495 | ||
496 | /* if there is any data in FIFO, discard it */ | |
497 | while ((s = (struct stream *) fifo_remove(&g_in_fifo)) != NULL) | |
498 | { | |
499 | xstream_free(s); | |
500 | } | |
501 | g_bytes_in_fifo = 0; | |
502 | ||
503 | error = chansrv_drdynvc_open(AUDIN_NAME, AUDIN_FLAGS, | |
504 | &g_audin_info, /* callback functions */ | |
505 | &g_audin_chanid); /* chansrv chan_id */ | |
506 | LOG(0, ("audin_start: error %d g_audin_chanid %d", error, g_audin_chanid)); | |
507 | return error; | |
508 | } | |
509 | ||
510 | /*****************************************************************************/ | |
511 | int | |
512 | audin_stop(void) | |
513 | { | |
514 | LOG(0, ("audin_stop:")); | |
515 | chansrv_drdynvc_close(g_audin_chanid); | |
516 | return 0; | |
517 | } |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * Copyright (C) Jay Sorg 2019 | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * MS-RDPEAI | |
18 | * | |
19 | */ | |
20 | ||
21 | #ifndef _AUDIN_H_ | |
22 | #define _AUDIN_H_ | |
23 | ||
24 | int | |
25 | audin_init(void); | |
26 | int | |
27 | audin_deinit(void); | |
28 | int | |
29 | audin_start(void); | |
30 | int | |
31 | audin_stop(void); | |
32 | ||
33 | #endif |
36 | 36 | #include "xcommon.h" |
37 | 37 | #include "chansrv_fuse.h" |
38 | 38 | #include "xrdp_sockets.h" |
39 | #include "audin.h" | |
39 | 40 | |
40 | 41 | static struct trans *g_lis_trans = 0; |
41 | 42 | static struct trans *g_con_trans = 0; |
58 | 59 | int g_rdpsnd_chan_id = -1; /* rdpsnd */ |
59 | 60 | int g_rdpdr_chan_id = -1; /* rdpdr */ |
60 | 61 | int g_rail_chan_id = -1; /* rail */ |
62 | int g_restrict_outbound_clipboard = 0; | |
61 | 63 | |
62 | 64 | char *g_exec_name; |
63 | 65 | tbus g_exec_event; |
404 | 406 | |
405 | 407 | if (g_rdpdr_index >= 0) |
406 | 408 | { |
407 | dev_redir_init(); | |
409 | devredir_init(); | |
408 | 410 | xfuse_init(); |
409 | 411 | } |
410 | 412 | |
412 | 414 | { |
413 | 415 | rail_init(); |
414 | 416 | } |
417 | ||
418 | audin_init(); | |
415 | 419 | |
416 | 420 | return rv; |
417 | 421 | } |
453 | 457 | } |
454 | 458 | else if (chan_id == g_rdpdr_chan_id) |
455 | 459 | { |
456 | rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length); | |
460 | rv = devredir_data_in(s, chan_id, chan_flags, length, total_length); | |
457 | 461 | } |
458 | 462 | else if (chan_id == g_rail_chan_id) |
459 | 463 | { |
1407 | 1411 | LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); |
1408 | 1412 | clipboard_deinit(); |
1409 | 1413 | sound_deinit(); |
1410 | dev_redir_deinit(); | |
1414 | devredir_deinit(); | |
1411 | 1415 | rail_deinit(); |
1412 | 1416 | break; |
1413 | 1417 | } |
1429 | 1433 | "trans_check_wait_objs error resetting")); |
1430 | 1434 | clipboard_deinit(); |
1431 | 1435 | sound_deinit(); |
1432 | dev_redir_deinit(); | |
1436 | devredir_deinit(); | |
1433 | 1437 | rail_deinit(); |
1434 | 1438 | /* delete g_con_trans */ |
1435 | 1439 | trans_delete(g_con_trans); |
1455 | 1459 | api_con_trans_list_check_wait_objs(); |
1456 | 1460 | xcommon_check_wait_objs(); |
1457 | 1461 | sound_check_wait_objs(); |
1458 | dev_redir_check_wait_objs(); | |
1462 | devredir_check_wait_objs(); | |
1459 | 1463 | xfuse_check_wait_objs(); |
1460 | 1464 | timeout = -1; |
1461 | 1465 | num_objs = 0; |
1474 | 1478 | &timeout); |
1475 | 1479 | xcommon_get_wait_objs(objs, &num_objs, &timeout); |
1476 | 1480 | sound_get_wait_objs(objs, &num_objs, &timeout); |
1477 | dev_redir_get_wait_objs(objs, &num_objs, &timeout); | |
1481 | devredir_get_wait_objs(objs, &num_objs, &timeout); | |
1478 | 1482 | xfuse_get_wait_objs(objs, &num_objs, &timeout); |
1479 | 1483 | get_timeout(&timeout); |
1480 | 1484 | } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ |
1779 | 1783 | enum logReturns error; |
1780 | 1784 | struct log_config logconfig; |
1781 | 1785 | enum logLevels log_level; |
1782 | ||
1786 | char *restrict_outbound_clipboard_env; | |
1783 | 1787 | g_init("xrdp-chansrv"); /* os_calls */ |
1784 | 1788 | |
1785 | 1789 | log_path[255] = 0; |
1788 | 1792 | g_writeln("error reading CHANSRV_LOG_PATH and HOME environment variable"); |
1789 | 1793 | g_deinit(); |
1790 | 1794 | return 1; |
1795 | } | |
1796 | ||
1797 | restrict_outbound_clipboard_env = g_getenv("CHANSRV_RESTRICT_OUTBOUND_CLIPBOARD"); | |
1798 | if (restrict_outbound_clipboard_env != 0) | |
1799 | { | |
1800 | if (g_strcmp(restrict_outbound_clipboard_env, "1") == 0) | |
1801 | { | |
1802 | g_restrict_outbound_clipboard = 1; | |
1803 | } | |
1791 | 1804 | } |
1792 | 1805 | |
1793 | 1806 | read_ini(); |
15 | 15 | * limitations under the License. |
16 | 16 | */ |
17 | 17 | |
18 | /* | |
19 | * TODO | |
20 | * o when creating dir/file, ensure it does not already exist | |
21 | * o do not allow dirs to be created in ino==1 except for .clipboard and share mounts | |
22 | * o fix the HACK where I have to use my own buf instead of g_buffer | |
23 | * this is in func xfuse_check_wait_objs() | |
24 | * o if fuse mount point is already mounted, I get segfault | |
25 | * o in open, check for modes such as O_TRUNC, O_APPEND | |
26 | * o copying over an existing file does not work | |
27 | * o after a dir is created, the device cannot be unmounted on the client side | |
28 | * so something is holding it up | |
29 | * o in thunar, when I move a file by dragging to another folder, the file | |
30 | * is getting copied instead of being moved | |
31 | * o unable to edit files in vi | |
32 | * o fuse ops to support | |
33 | * o touch does not work | |
34 | * o chmod must work | |
35 | * o cat >> file is not working | |
36 | * | |
37 | */ | |
38 | ||
39 | //#define USE_SYNC_FLAG | |
40 | ||
41 | 18 | /* FUSE mount point */ |
42 | 19 | char g_fuse_root_path[256] = ""; |
43 | 20 | char g_fuse_clipboard_path[256] = ""; /* for clipboard use */ |
57 | 34 | #include <stdio.h> |
58 | 35 | #include <stdlib.h> |
59 | 36 | #include <string.h> |
60 | #include <time.h> | |
61 | 37 | |
62 | 38 | #include "arch.h" |
63 | 39 | #include "chansrv_fuse.h" |
40 | #include "chansrv_xfs.h" | |
64 | 41 | |
65 | 42 | /* dummy calls when XRDP_FUSE is not defined */ |
66 | 43 | int xfuse_init(void) { return 0; } |
67 | 44 | int xfuse_deinit(void) { return 0; } |
68 | 45 | int xfuse_check_wait_objs(void) { return 0; } |
69 | 46 | int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) { return 0; } |
47 | int xfuse_create_share(tui32 device_id, const char *dirname) { return 0; } | |
48 | void xfuse_delete_share(tui32 share_id) {} | |
70 | 49 | int xfuse_clear_clip_dir(void) { return 0; } |
71 | 50 | int xfuse_file_contents_range(int stream_id, const char *data, int data_bytes) { return 0; } |
72 | int xfuse_file_contents_size(int stream_id, int file_size) { return 0; } | |
73 | int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int lindex) { return 0; } | |
74 | int xfuse_create_share(tui32 device_id, const char *dirname) { return 0; } | |
75 | void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId) {} | |
76 | void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length) {} | |
77 | void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length) {} | |
78 | int xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { return 0; } | |
79 | void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) {} | |
80 | void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus) {} | |
81 | void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus) {} | |
82 | void xfuse_devredir_cb_file_close(void *vp) {} | |
51 | int xfuse_file_contents_size(int stream_id, int file_size) | |
52 | { return 0; } | |
53 | int xfuse_add_clip_dir_item(const char *filename, | |
54 | int flags, int size, int lindex) { return 0; } | |
55 | ||
56 | void xfuse_devredir_cb_enum_dir_add_entry( | |
57 | struct state_dirscan *fip, | |
58 | const char *name, | |
59 | const struct file_attr *fattr) | |
60 | {} | |
61 | void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip, | |
62 | enum NTSTATUS IoStatus) | |
63 | {} | |
64 | void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip, | |
65 | enum NTSTATUS IoStatus, | |
66 | const struct file_attr *file_info) | |
67 | {} | |
68 | void xfuse_devredir_cb_setattr(struct state_setattr *fip, | |
69 | enum NTSTATUS IoStatus) | |
70 | {} | |
71 | void xfuse_devredir_cb_create_file(struct state_create *fip, | |
72 | enum NTSTATUS IoStatus, | |
73 | tui32 DeviceId, tui32 FileId) | |
74 | {} | |
75 | void xfuse_devredir_cb_open_file(struct state_open *fip, | |
76 | enum NTSTATUS IoStatus, | |
77 | tui32 DeviceId, tui32 FileId) | |
78 | {} | |
79 | void xfuse_devredir_cb_read_file(struct state_read *fip, | |
80 | const char *buf, size_t length) | |
81 | {} | |
82 | void xfuse_devredir_cb_write_file( | |
83 | struct state_write *fip, | |
84 | enum NTSTATUS IoStatus, | |
85 | off_t offset, | |
86 | size_t length) | |
87 | {} | |
88 | void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip, | |
89 | enum NTSTATUS IoStatus) | |
90 | {} | |
91 | void xfuse_devredir_cb_rename_file(struct state_rename *fip, | |
92 | enum NTSTATUS IoStatus) | |
93 | {} | |
94 | void xfuse_devredir_cb_file_close(struct state_close *fip) | |
95 | {} | |
83 | 96 | |
84 | 97 | #else |
85 | 98 | |
105 | 118 | #include "os_calls.h" |
106 | 119 | #include "clipboard_file.h" |
107 | 120 | #include "chansrv_fuse.h" |
121 | #include "chansrv_xfs.h" | |
108 | 122 | #include "devredir.h" |
109 | 123 | #include "list.h" |
110 | #include "fifo.h" | |
111 | 124 | #include "file.h" |
112 | 125 | |
113 | 126 | #ifndef EREMOTEIO |
114 | 127 | #define EREMOTEIO EIO |
115 | 128 | #endif |
116 | 129 | |
117 | #define min(x, y) ((x) < (y) ? (x) : (y)) | |
118 | ||
119 | #define XFUSE_ATTR_TIMEOUT 1.0 | |
120 | #define XFUSE_ENTRY_TIMEOUT 1.0 | |
121 | ||
122 | #define DOTDOT_INODE 0 | |
123 | #define DOT_INODE 0 | |
124 | #define FIRST_INODE 1 | |
130 | #define XFUSE_ATTR_TIMEOUT 5.0 | |
131 | #define XFUSE_ENTRY_TIMEOUT 5.0 | |
125 | 132 | |
126 | 133 | /* module based logging */ |
127 | 134 | #define LOG_ERROR 0 |
128 | 135 | #define LOG_INFO 1 |
129 | 136 | #define LOG_DEBUG 2 |
137 | #ifndef LOG_LEVEL | |
130 | 138 | #define LOG_LEVEL LOG_ERROR |
139 | #endif | |
131 | 140 | |
132 | 141 | #define log_error(_params...) \ |
133 | 142 | { \ |
163 | 172 | } \ |
164 | 173 | } |
165 | 174 | |
166 | #define OP_RENAME_FILE 0x01 | |
167 | ||
168 | /* the xrdp file system in memory */ | |
169 | struct xrdp_fs | |
170 | { | |
171 | struct xrdp_inode **inode_table; /* a table of entries; can grow */ | |
172 | unsigned int max_entries; /* size of inode_table[] */ | |
173 | unsigned int num_entries; /* num entries available in inode_table */ | |
174 | unsigned int next_node; /* next free node number */ | |
175 | ||
176 | /* Type of buffer used for fuse_add_direntry() calls */ | |
177 | struct dirbuf1 | |
178 | { | |
179 | char buf[4096]; | |
180 | size_t len; | |
175 | 181 | }; |
176 | 182 | |
177 | struct dirbuf | |
178 | { | |
179 | char *p; | |
180 | size_t size; | |
183 | /* | |
184 | * Record type used to maintain state when running a directory scan | |
185 | */ | |
186 | struct state_dirscan | |
187 | { | |
188 | fuse_req_t req; /* Original FUSE request from opendir */ | |
189 | struct fuse_file_info fi; /* File info struct passed to opendir */ | |
190 | fuse_ino_t pinum; /* inum of parent directory */ | |
181 | 191 | }; |
182 | 192 | |
183 | struct dirbuf1 | |
184 | { | |
185 | char buf[4096]; | |
186 | int bytes_in_buf; | |
187 | int first_time; | |
193 | ||
194 | /* | |
195 | * Record type used to maintain state when running an entry lookup | |
196 | */ | |
197 | struct state_lookup | |
198 | { | |
199 | fuse_req_t req; /* Original FUSE request from lookup */ | |
200 | fuse_ino_t pinum; /* inum of parent directory */ | |
201 | char name[XFS_MAXFILENAMELEN]; | |
202 | /* Name to look up */ | |
203 | fuse_ino_t existing_inum; | |
204 | /* inum of an existing entry */ | |
205 | tui32 existing_generation; | |
206 | /* generation of the above */ | |
188 | 207 | }; |
189 | 208 | |
190 | /* FUSE reply types */ | |
191 | #define RT_FUSE_REPLY_OPEN 1 | |
192 | #define RT_FUSE_REPLY_CREATE 2 | |
193 | ||
194 | struct xfuse_info | |
195 | { | |
196 | struct fuse_file_info *fi; | |
197 | fuse_req_t req; | |
198 | fuse_ino_t inode; | |
199 | fuse_ino_t new_inode; | |
200 | int invoke_fuse; | |
201 | char name[1024]; | |
202 | char new_name[1024]; | |
203 | tui32 device_id; | |
204 | int reply_type; | |
205 | int mode; | |
206 | int type; | |
207 | size_t size; | |
208 | off_t off; | |
209 | struct dirbuf1 dirbuf1; | |
209 | /* | |
210 | * Record type used to maintain state when running an entry setattr | |
211 | */ | |
212 | struct state_setattr | |
213 | { | |
214 | fuse_req_t req; /* Original FUSE request from lookup */ | |
215 | fuse_ino_t inum; /* inum of entry */ | |
216 | struct file_attr fattr; /* File attributes to set */ | |
217 | tui32 change_mask; /* Attributes to set in fattr */ | |
210 | 218 | }; |
211 | typedef struct xfuse_info XFUSE_INFO; | |
219 | ||
220 | ||
221 | /* | |
222 | * Record type used to maintain state when running an open | |
223 | */ | |
224 | struct state_open | |
225 | { | |
226 | fuse_req_t req; /* Original FUSE request from lookup */ | |
227 | struct fuse_file_info fi; /* File info struct passed to open */ | |
228 | fuse_ino_t inum; /* inum of file to open */ | |
229 | }; | |
230 | ||
231 | ||
232 | /* | |
233 | * Record type used to maintain state when running a create | |
234 | */ | |
235 | struct state_create | |
236 | { | |
237 | fuse_req_t req; /* Original FUSE request from lookup */ | |
238 | struct fuse_file_info fi; /* File info struct passed to open */ | |
239 | fuse_ino_t pinum; /* inum of parent directory */ | |
240 | char name[XFS_MAXFILENAMELEN]; | |
241 | /* Name of file in parent directory */ | |
242 | mode_t mode; /* Mode of file to create */ | |
243 | }; | |
244 | ||
245 | /* | |
246 | * Record type used to maintain state when running a read | |
247 | */ | |
248 | struct state_read | |
249 | { | |
250 | fuse_req_t req; /* Original FUSE request from lookup */ | |
251 | }; | |
252 | ||
253 | /* | |
254 | * Record type used to maintain state when running a write | |
255 | */ | |
256 | struct state_write | |
257 | { | |
258 | fuse_req_t req; /* Original FUSE request from lookup */ | |
259 | fuse_ino_t inum; /* inum of file we're writing */ | |
260 | }; | |
261 | ||
262 | /* | |
263 | * Record type used to maintain state when running a remove | |
264 | */ | |
265 | struct state_remove | |
266 | { | |
267 | fuse_req_t req; /* Original FUSE request from lookup */ | |
268 | fuse_ino_t inum; /* inum of file we're removing */ | |
269 | }; | |
270 | ||
271 | /* | |
272 | * Record type used to maintain state when running a rename | |
273 | */ | |
274 | struct state_rename | |
275 | { | |
276 | fuse_req_t req; /* Original FUSE request from lookup */ | |
277 | fuse_ino_t pinum; /* inum of parent of file */ | |
278 | fuse_ino_t new_pinum; /* inum of new parent of file */ | |
279 | char name[XFS_MAXFILENAMELEN]; | |
280 | /* New name of file in new parent dir */ | |
281 | }; | |
282 | ||
283 | /* | |
284 | * Record type used to maintain state when running a close | |
285 | */ | |
286 | struct state_close | |
287 | { | |
288 | fuse_req_t req; /* Original FUSE request from lookup */ | |
289 | struct fuse_file_info fi; /* File info struct passed to open */ | |
290 | fuse_ino_t inum; /* inum of file to open */ | |
291 | }; | |
212 | 292 | |
213 | 293 | struct xfuse_handle |
214 | 294 | { |
228 | 308 | int size; |
229 | 309 | }; |
230 | 310 | |
231 | struct dir_info | |
232 | { | |
233 | /* last index accessed in g_xrdp_fs.inode_table[] */ | |
234 | int index; | |
235 | }; | |
236 | ||
237 | /* queue FUSE opendir commands so we run only one at a time */ | |
238 | struct opendir_req | |
239 | { | |
240 | fuse_req_t req; | |
241 | fuse_ino_t ino; | |
242 | struct fuse_file_info *fi; | |
243 | }; | |
244 | ||
245 | 311 | static char g_fuse_mount_name[256] = "xrdp_client"; |
246 | ||
247 | FIFO g_fifo_opendir; | |
312 | static mode_t g_umask = 077; /* Umask for files in fs */ | |
248 | 313 | |
249 | 314 | static struct list *g_req_list = 0; |
250 | static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */ | |
315 | static struct xfs_fs *g_xfs; /* an inst of xrdp file system */ | |
316 | static ino_t g_clipboard_inum; /* inode of clipboard dir */ | |
251 | 317 | static char *g_mount_point = 0; /* our FUSE mount point */ |
252 | 318 | static struct fuse_lowlevel_ops g_xfuse_ops; /* setup FUSE callbacks */ |
253 | 319 | static int g_xfuse_inited = 0; /* true when FUSE is inited */ |
261 | 327 | static int xfuse_init_xrdp_fs(void); |
262 | 328 | static int xfuse_deinit_xrdp_fs(void); |
263 | 329 | static int xfuse_init_lib(struct fuse_args *args); |
264 | static int xfuse_is_inode_valid(fuse_ino_t ino); | |
265 | ||
266 | // LK_TODO | |
267 | #if 0 | |
268 | static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, | |
269 | const char *name, mode_t mode, int type); | |
270 | #endif | |
271 | ||
272 | static void xfuse_dump_fs(void); | |
273 | static tui32 xfuse_get_device_id_for_inode(fuse_ino_t ino, char *full_path); | |
274 | static void fuse_reverse_pathname(char *full_path, char *reverse_path); | |
275 | ||
276 | static struct xrdp_inode * xfuse_get_inode_from_pinode_name(fuse_ino_t pinode, | |
277 | const char *name); | |
278 | ||
279 | static struct xrdp_inode * | |
280 | xfuse_create_file_in_xrdp_fs(tui32 device_id, int pinode, const char *name, | |
281 | int type); | |
282 | ||
283 | static int xfuse_does_file_exist(fuse_ino_t parent, char *name); | |
284 | static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode); | |
285 | static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode); | |
286 | static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode); | |
287 | static void xfuse_update_xrdpfs_size(void); | |
288 | ||
289 | #ifdef USE_SYNC_FLAG | |
290 | static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, | |
291 | off_t off, struct fuse_file_info *fi); | |
292 | #endif | |
293 | 330 | |
294 | 331 | /* forward declarations for FUSE callbacks */ |
295 | 332 | static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, |
300 | 337 | |
301 | 338 | /* this is not a callback, but it's used by xfuse_cb_readdir() */ |
302 | 339 | static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, |
303 | const char *name, fuse_ino_t ino); | |
340 | XFS_INODE *xinode, off_t offset); | |
304 | 341 | |
305 | 342 | static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, |
306 | 343 | off_t off, struct fuse_file_info *fi); |
307 | 344 | |
308 | 345 | static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, |
309 | 346 | const char *name, mode_t mode); |
310 | ||
311 | static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, | |
312 | const char *name); | |
313 | 347 | |
314 | 348 | static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, |
315 | 349 | const char *name); |
318 | 352 | fuse_ino_t old_parent, const char *old_name, |
319 | 353 | fuse_ino_t new_parent, const char *new_name); |
320 | 354 | |
321 | /* this is not a callback, but it is used by the above two functions */ | |
322 | static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent, | |
323 | const char *name, int type); | |
324 | ||
355 | /* Whether to create a dir of file depends on whether S_IFDIR is set in the | |
356 | mode field */ | |
325 | 357 | static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, |
326 | 358 | const char *name, mode_t mode, |
327 | struct fuse_file_info *fi, int type); | |
359 | struct fuse_file_info *fi); | |
328 | 360 | |
329 | 361 | static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, |
330 | 362 | struct fuse_file_info *fi); |
353 | 385 | static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, |
354 | 386 | struct fuse_file_info *fi); |
355 | 387 | |
356 | static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, | |
357 | struct fuse_file_info *fi); | |
358 | ||
359 | 388 | static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, |
360 | 389 | struct fuse_file_info *fi); |
361 | 390 | |
362 | /* misc calls */ | |
363 | static void xfuse_mark_as_stale(fuse_ino_t pinode); | |
364 | static void xfuse_delete_stale_entries(fuse_ino_t pinode); | |
391 | /* miscellaneous functions */ | |
392 | static void xfs_inode_to_fuse_entry_param(const XFS_INODE *xinode, | |
393 | struct fuse_entry_param *e); | |
394 | static void make_fuse_entry_reply(fuse_req_t req, const XFS_INODE *xinode); | |
395 | static void make_fuse_attr_reply(fuse_req_t req, const XFS_INODE *xinode); | |
396 | static const char *filename_on_device(const char *full_path); | |
397 | static void update_inode_file_attributes(const struct file_attr *fattr, | |
398 | tui32 change_mask, XFS_INODE *xinode); | |
399 | static char *get_name_for_entry_in_parent(fuse_ino_t parent, const char *name); | |
365 | 400 | |
366 | 401 | /*****************************************************************************/ |
367 | 402 | int |
388 | 423 | { |
389 | 424 | g_strncpy(g_fuse_mount_name, value, 255); |
390 | 425 | } |
426 | else if (g_strcasecmp(item, "FileUmask") == 0) | |
427 | { | |
428 | g_umask = strtol(value, NULL, 0); | |
429 | log_info("g_umask set to 0%o", g_umask); | |
430 | } | |
391 | 431 | } |
392 | 432 | list_delete(items); |
393 | 433 | list_delete(values); |
445 | 485 | if (xfuse_init_xrdp_fs()) |
446 | 486 | return -1; |
447 | 487 | |
448 | /* setup FIFOs */ | |
449 | fifo_init(&g_fifo_opendir, 30); | |
450 | ||
451 | 488 | /* setup FUSE callbacks */ |
452 | 489 | g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops)); |
453 | 490 | g_xfuse_ops.lookup = xfuse_cb_lookup; |
454 | 491 | g_xfuse_ops.readdir = xfuse_cb_readdir; |
455 | 492 | g_xfuse_ops.mkdir = xfuse_cb_mkdir; |
456 | g_xfuse_ops.rmdir = xfuse_cb_rmdir; | |
493 | g_xfuse_ops.rmdir = xfuse_cb_unlink; | |
457 | 494 | g_xfuse_ops.unlink = xfuse_cb_unlink; |
458 | 495 | g_xfuse_ops.rename = xfuse_cb_rename; |
459 | 496 | g_xfuse_ops.open = xfuse_cb_open; |
491 | 528 | int |
492 | 529 | xfuse_deinit(void) |
493 | 530 | { |
494 | xfuse_deinit_xrdp_fs(); | |
495 | fifo_deinit(&g_fifo_opendir); | |
496 | ||
497 | 531 | if (g_ch != 0) |
498 | 532 | { |
499 | 533 | fuse_session_remove_chan(g_ch); |
519 | 553 | g_req_list = 0; |
520 | 554 | } |
521 | 555 | |
556 | xfuse_deinit_xrdp_fs(); | |
557 | ||
522 | 558 | g_xfuse_inited = 0; |
523 | 559 | return 0; |
524 | 560 | } |
533 | 569 | struct fuse_chan *tmpch; |
534 | 570 | int rval; |
535 | 571 | |
536 | #define HACK | |
537 | ||
538 | #ifdef HACK | |
539 | char buf[135168]; | |
540 | #endif | |
541 | ||
542 | 572 | if (g_ch == 0) |
543 | 573 | return 0; |
544 | 574 | |
546 | 576 | { |
547 | 577 | tmpch = g_ch; |
548 | 578 | |
549 | #ifdef HACK | |
550 | rval = fuse_chan_recv(&tmpch, buf, g_bufsize); | |
551 | #else | |
552 | 579 | rval = fuse_chan_recv(&tmpch, g_buffer, g_bufsize); |
553 | #endif | |
554 | 580 | if (rval == -EINTR) |
555 | 581 | return -1; |
556 | 582 | |
560 | 586 | if (rval <= 0) |
561 | 587 | return -1; |
562 | 588 | |
563 | #ifdef HACK | |
564 | fuse_session_process(g_se, buf, rval, tmpch); | |
565 | #else | |
566 | 589 | fuse_session_process(g_se, g_buffer, rval, tmpch); |
567 | #endif | |
568 | 590 | } |
569 | 591 | |
570 | 592 | return 0; |
601 | 623 | |
602 | 624 | int xfuse_create_share(tui32 device_id, const char *dirname) |
603 | 625 | { |
604 | #if 0 | |
605 | XFUSE_INFO *fip; | |
606 | #endif | |
607 | XRDP_INODE *xinode; | |
608 | /* tui32 saved_inode; */ | |
609 | ||
610 | if (dirname == NULL || strlen(dirname) == 0) | |
611 | return -1; | |
612 | ||
613 | /* Do we have an inode table yet? */ | |
614 | if (xfuse_init_xrdp_fs()) | |
615 | { | |
616 | return -1; | |
617 | } | |
618 | ||
619 | xinode = g_new0(struct xrdp_inode, 1); | |
620 | if (xinode == NULL) | |
621 | { | |
622 | log_debug("g_new0() failed"); | |
623 | return -1; | |
624 | } | |
625 | ||
626 | /* create directory entry */ | |
627 | xinode->parent_inode = 1; | |
628 | xinode->inode = g_xrdp_fs.next_node++; | |
629 | xinode->mode = 0755 | S_IFDIR; | |
630 | xinode->nlink = 1; | |
631 | xinode->uid = getuid(); | |
632 | xinode->gid = getgid(); | |
633 | xinode->size = 0; | |
634 | xinode->atime = time(0); | |
635 | xinode->mtime = time(0); | |
636 | xinode->ctime = time(0); | |
637 | strcpy(xinode->name, dirname); | |
638 | xinode->device_id = device_id; | |
639 | ||
640 | g_xrdp_fs.num_entries++; | |
641 | /* saved_inode = xinode->inode; */ | |
642 | ||
643 | /* insert it in xrdp fs */ | |
644 | g_xrdp_fs.inode_table[xinode->inode] = xinode; | |
645 | log_debug("created new share named %s at inode_table[%d]", | |
646 | dirname, xinode->inode); | |
647 | ||
648 | /* update nentries in parent inode */ | |
649 | xinode = g_xrdp_fs.inode_table[1]; | |
650 | if (xinode == NULL) | |
651 | return -1; | |
652 | xinode->nentries++; | |
653 | ||
654 | #if 0 | |
655 | fip = g_new0(XFUSE_INFO, 1); | |
656 | if (fip == NULL) | |
657 | { | |
658 | log_error("system out of memory"); | |
659 | return -1; | |
660 | } | |
661 | ||
662 | /* enumerate root dir, do not call FUSE when done */ | |
663 | fip->req = NULL; | |
664 | fip->inode = 1; /* TODO saved_inode; */ | |
665 | strncpy(fip->name, dirname, 1024); | |
666 | fip->name[1023] = 0; | |
667 | fip->device_id = device_id; | |
668 | ||
669 | dev_redir_get_dir_listing((void *) fip, device_id, "\\"); | |
670 | #endif | |
671 | ||
672 | return 0; | |
626 | int result = -1; | |
627 | XFS_INODE *xinode; | |
628 | ||
629 | if (dirname != NULL && strlen(dirname) > 0 && | |
630 | xfuse_init_xrdp_fs() == 0) | |
631 | { | |
632 | xinode = xfs_add_entry(g_xfs, FUSE_ROOT_ID, dirname, (0777 | S_IFDIR)); | |
633 | if (xinode == NULL) | |
634 | { | |
635 | log_debug("xfs_add_entry() failed"); | |
636 | } | |
637 | else | |
638 | { | |
639 | xinode->device_id = device_id; | |
640 | result = 0; | |
641 | } | |
642 | } | |
643 | ||
644 | return result; | |
645 | } | |
646 | ||
647 | /** | |
648 | * @brief Remove specified share directory. | |
649 | * | |
650 | * This code gets called from devredir | |
651 | *****************************************************************************/ | |
652 | ||
653 | void xfuse_delete_share(tui32 device_id) | |
654 | { | |
655 | xfs_delete_entries_with_device_id(g_xfs, device_id); | |
673 | 656 | } |
674 | 657 | |
675 | 658 | /** |
682 | 665 | |
683 | 666 | int xfuse_clear_clip_dir(void) |
684 | 667 | { |
685 | fuse_ino_t i; | |
686 | XRDP_INODE *xinode; | |
687 | XRDP_INODE *xip; | |
688 | ||
689 | log_debug("entered"); | |
690 | ||
691 | if (g_xrdp_fs.inode_table == NULL) | |
692 | { | |
693 | return 0; | |
694 | } | |
695 | ||
696 | /* xinode for .clipboard */ | |
697 | xip = g_xrdp_fs.inode_table[2]; | |
698 | ||
699 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
700 | { | |
701 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
702 | continue; | |
703 | ||
704 | if (xinode->parent_inode == 2) | |
705 | { | |
706 | g_xrdp_fs.inode_table[i] = NULL; | |
707 | free(xinode); | |
708 | xip->nentries--; | |
709 | } | |
710 | } | |
711 | ||
712 | return 0; | |
668 | int result = 0; | |
669 | ||
670 | if (g_xfs != NULL && g_clipboard_inum > 0) | |
671 | { | |
672 | xfs_remove_directory_contents(g_xfs, g_clipboard_inum); | |
673 | } | |
674 | ||
675 | return result; | |
713 | 676 | } |
714 | 677 | |
715 | 678 | /** |
773 | 736 | filename, flags, size, lindex); |
774 | 737 | |
775 | 738 | /* add entry to xrdp_fs */ |
776 | XRDP_INODE *xinode = xfuse_create_file_in_xrdp_fs(0, /* device id */ | |
777 | 2, /* parent inode */ | |
778 | filename, | |
779 | S_IFREG); | |
739 | XFS_INODE *xinode = xfs_add_entry( g_xfs, | |
740 | g_clipboard_inum, /* parent inode */ | |
741 | filename, | |
742 | (0666 | S_IFREG)); | |
780 | 743 | if (xinode == NULL) |
781 | 744 | { |
782 | 745 | log_debug("failed to create file in xrdp filesystem"); |
784 | 747 | } |
785 | 748 | xinode->size = size; |
786 | 749 | xinode->lindex = lindex; |
787 | xinode->is_loc_resource = 1; | |
788 | 750 | |
789 | 751 | return 0; |
790 | 752 | } |
861 | 823 | |
862 | 824 | static int xfuse_init_xrdp_fs(void) |
863 | 825 | { |
864 | struct xrdp_inode *xino; | |
826 | XFS_INODE *xino; | |
827 | int result = -1; | |
865 | 828 | |
866 | 829 | /* Already called? */ |
867 | if (g_xrdp_fs.inode_table != NULL) | |
868 | { | |
869 | return 0; | |
870 | } | |
871 | ||
872 | g_xrdp_fs.inode_table = g_new0(struct xrdp_inode *, 4096); | |
873 | if (g_xrdp_fs.inode_table == NULL) | |
830 | if (g_xfs != NULL) | |
831 | { | |
832 | result = 0; | |
833 | } | |
834 | else if ((g_xfs = xfs_create_xfs_fs(0, g_getuid(), g_getgid())) == NULL) | |
874 | 835 | { |
875 | 836 | log_error("system out of memory"); |
876 | return -1; | |
877 | } | |
878 | ||
879 | /* | |
880 | * index 0 is our .. dir | |
881 | */ | |
882 | ||
883 | xino = g_new0(struct xrdp_inode, 1); | |
884 | if (xino == NULL) | |
885 | { | |
886 | log_error("system out of memory"); | |
887 | free(g_xrdp_fs.inode_table); | |
888 | return -1; | |
889 | } | |
890 | g_xrdp_fs.inode_table[0] = xino; | |
891 | xino->parent_inode = 0; | |
892 | xino->inode = 0; | |
893 | xino->mode = S_IFDIR | 0755; | |
894 | xino->nentries = 1; | |
895 | xino->uid = getuid(); | |
896 | xino->gid = getgid(); | |
897 | xino->size = 0; | |
898 | xino->atime = time(0); | |
899 | xino->mtime = time(0); | |
900 | xino->ctime = time(0); | |
901 | strcpy(xino->name, ".."); | |
902 | ||
903 | /* | |
904 | * index 1 is our . dir | |
905 | */ | |
906 | ||
907 | xino = g_new0(struct xrdp_inode, 1); | |
908 | if (xino == NULL) | |
909 | { | |
910 | log_error("system out of memory"); | |
911 | free(g_xrdp_fs.inode_table[0]); | |
912 | free(g_xrdp_fs.inode_table); | |
913 | return -1; | |
914 | } | |
915 | g_xrdp_fs.inode_table[1] = xino; | |
916 | xino->parent_inode = 0; | |
917 | xino->inode = 1; | |
918 | xino->mode = S_IFDIR | 0755; | |
919 | xino->nentries = 1; | |
920 | xino->uid = getuid(); | |
921 | xino->gid = getgid(); | |
922 | xino->size = 0; | |
923 | xino->atime = time(0); | |
924 | xino->mtime = time(0); | |
925 | xino->ctime = time(0); | |
926 | strcpy(xino->name, "."); | |
927 | ||
928 | /* | |
929 | * index 2 is for clipboard use | |
930 | */ | |
931 | ||
932 | xino = g_new0(struct xrdp_inode, 1); | |
933 | if (xino == NULL) | |
934 | { | |
935 | log_error("system out of memory"); | |
936 | free(g_xrdp_fs.inode_table[0]); | |
937 | free(g_xrdp_fs.inode_table[1]); | |
938 | free(g_xrdp_fs.inode_table); | |
939 | return -1; | |
940 | } | |
941 | ||
942 | g_xrdp_fs.inode_table[2] = xino; | |
943 | xino->parent_inode = 1; | |
944 | xino->inode = 2; | |
945 | xino->nentries = 0; | |
946 | xino->mode = S_IFDIR | 0755; | |
947 | xino->uid = getuid(); | |
948 | xino->gid = getgid(); | |
949 | xino->size = 0; | |
950 | xino->atime = time(0); | |
951 | xino->mtime = time(0); | |
952 | xino->ctime = time(0); | |
953 | xino->is_loc_resource = 1; | |
954 | strcpy(xino->name, ".clipboard"); | |
955 | ||
956 | g_xrdp_fs.max_entries = 4096; | |
957 | g_xrdp_fs.num_entries = 3; | |
958 | g_xrdp_fs.next_node = 3; | |
837 | } | |
838 | else | |
839 | { | |
840 | /* Need a top-level .clipboard directory */ | |
841 | xino = xfs_add_entry(g_xfs, FUSE_ROOT_ID, ".clipboard", | |
842 | (0777 | S_IFDIR)); | |
843 | if (xino == NULL) | |
844 | { | |
845 | log_error("system out of memory"); | |
846 | xfs_delete_xfs_fs(g_xfs); | |
847 | g_xfs = NULL; | |
848 | } | |
849 | else | |
850 | { | |
851 | g_clipboard_inum = xino->inum; | |
852 | result = 0; | |
853 | } | |
854 | } | |
855 | return result; | |
856 | } | |
857 | ||
858 | /** | |
859 | * zap the xrdp file system | |
860 | * | |
861 | * @return 0 on success, -1 on failure | |
862 | *****************************************************************************/ | |
863 | ||
864 | static int xfuse_deinit_xrdp_fs(void) | |
865 | { | |
866 | xfs_delete_xfs_fs(g_xfs); | |
867 | g_xfs = NULL; | |
868 | g_clipboard_inum = 0; | |
959 | 869 | |
960 | 870 | return 0; |
961 | } | |
962 | ||
963 | /** | |
964 | * zap the xrdp file system | |
965 | * | |
966 | * @return 0 on success, -1 on failure | |
967 | *****************************************************************************/ | |
968 | ||
969 | static int xfuse_deinit_xrdp_fs(void) | |
970 | { | |
971 | return 0; | |
972 | } | |
973 | ||
974 | /** | |
975 | * determine if specified ino exists in xrdp file system | |
976 | * | |
977 | * @return 1 if it does, 0 otherwise | |
978 | *****************************************************************************/ | |
979 | ||
980 | static int xfuse_is_inode_valid(fuse_ino_t ino) | |
981 | { | |
982 | /* is ino present in our table? */ | |
983 | if ((ino < FIRST_INODE) || (ino >= g_xrdp_fs.next_node)) | |
984 | return 0; | |
985 | ||
986 | if (g_xrdp_fs.inode_table[ino] == NULL) | |
987 | return 0; | |
988 | ||
989 | return 1; | |
990 | } | |
991 | ||
992 | /** | |
993 | * @brief Create a directory or regular file. | |
994 | *****************************************************************************/ | |
995 | ||
996 | // LK_TODO | |
997 | #if 0 | |
998 | static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, | |
999 | const char *name, mode_t mode, int type) | |
1000 | { | |
1001 | struct xrdp_inode *xinode; | |
1002 | struct fuse_entry_param e; | |
1003 | ||
1004 | log_debug("parent=%ld name=%s", parent, name); | |
1005 | ||
1006 | /* do we have a valid parent inode? */ | |
1007 | if (!xfuse_is_inode_valid(parent)) | |
1008 | { | |
1009 | log_error("inode %ld is not valid", parent); | |
1010 | fuse_reply_err(req, EBADF); | |
1011 | } | |
1012 | ||
1013 | xinode = g_new0(struct xrdp_inode, 1); | |
1014 | if (xinode == NULL) | |
1015 | { | |
1016 | log_error("g_new0() failed"); | |
1017 | fuse_reply_err(req, ENOMEM); | |
1018 | } | |
1019 | ||
1020 | /* create directory entry */ | |
1021 | xinode->parent_inode = parent; | |
1022 | xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */ | |
1023 | xinode->mode = mode | type; | |
1024 | xinode->uid = getuid(); | |
1025 | xinode->gid = getgid(); | |
1026 | xinode->size = 0; | |
1027 | xinode->atime = time(0); | |
1028 | xinode->mtime = time(0); | |
1029 | xinode->ctime = time(0); | |
1030 | strcpy(xinode->name, name); | |
1031 | ||
1032 | g_xrdp_fs.num_entries++; | |
1033 | ||
1034 | /* insert it in xrdp fs */ | |
1035 | g_xrdp_fs.inode_table[xinode->inode] = xinode; | |
1036 | xfuse_update_xrdpfs_size(); | |
1037 | log_debug("inserted new dir at inode_table[%d]", xinode->inode); | |
1038 | ||
1039 | xfuse_dump_fs(); | |
1040 | ||
1041 | log_debug("new inode=%d", xinode->inode); | |
1042 | ||
1043 | /* setup return value */ | |
1044 | memset(&e, 0, sizeof(e)); | |
1045 | e.ino = xinode->inode; | |
1046 | e.attr_timeout = XFUSE_ATTR_TIMEOUT; | |
1047 | e.entry_timeout = XFUSE_ENTRY_TIMEOUT; | |
1048 | e.attr.st_ino = xinode->inode; | |
1049 | e.attr.st_mode = xinode->mode; | |
1050 | e.attr.st_nlink = xinode->nlink; | |
1051 | e.attr.st_uid = xinode->uid; | |
1052 | e.attr.st_gid = xinode->gid; | |
1053 | e.attr.st_size = 0; | |
1054 | e.attr.st_atime = xinode->atime; | |
1055 | e.attr.st_mtime = xinode->mtime; | |
1056 | e.attr.st_ctime = xinode->ctime; | |
1057 | e.generation = 1; | |
1058 | ||
1059 | fuse_reply_entry(req, &e); | |
1060 | } | |
1061 | #endif | |
1062 | ||
1063 | static void xfuse_dump_fs(void) | |
1064 | { | |
1065 | fuse_ino_t i; | |
1066 | struct xrdp_inode *xinode; | |
1067 | ||
1068 | log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE); | |
1069 | ||
1070 | #if 0 | |
1071 | log_debug("not dumping xrdp fs"); | |
1072 | return; | |
1073 | #endif | |
1074 | ||
1075 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
1076 | { | |
1077 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
1078 | continue; | |
1079 | ||
1080 | log_debug("pinode=%d inode=%d nentries=%d nopen=%d is_synced=%d name=%s", | |
1081 | xinode->parent_inode, xinode->inode, | |
1082 | xinode->nentries, xinode->nopen, xinode->is_synced, | |
1083 | xinode->name); | |
1084 | } | |
1085 | log_debug("%s", ""); | |
1086 | } | |
1087 | ||
1088 | /** | |
1089 | * Dump contents of xinode structure | |
1090 | * | |
1091 | * @param xino xinode structure to dump | |
1092 | *****************************************************************************/ | |
1093 | ||
1094 | #if 0 | |
1095 | static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino) | |
1096 | { | |
1097 | log_debug("--- dumping struct xinode ---"); | |
1098 | log_debug("name: %s", xino->name); | |
1099 | log_debug("parent_inode: %d", xino->parent_inode); | |
1100 | log_debug("inode: %d", xino->inode); | |
1101 | log_debug("mode: %o", xino->mode); | |
1102 | log_debug("nlink: %d", xino->nlink); | |
1103 | log_debug("uid: %d", xino->uid); | |
1104 | log_debug("gid: %d", xino->gid); | |
1105 | log_debug("size: %zd", xino->size); | |
1106 | log_debug("device_id: %d", xino->device_id); | |
1107 | log_debug("%s", ""); | |
1108 | } | |
1109 | #endif | |
1110 | ||
1111 | /** | |
1112 | * Return the device_id associated with specified inode and copy the | |
1113 | * full path to the specified inode into full_path | |
1114 | * | |
1115 | * @param ino the inode | |
1116 | * @param full_path full path to the inode | |
1117 | * | |
1118 | * @return the device_id of specified inode | |
1119 | *****************************************************************************/ | |
1120 | ||
1121 | static tui32 xfuse_get_device_id_for_inode(fuse_ino_t ino, char *full_path) | |
1122 | { | |
1123 | fuse_ino_t parent_inode = 0; | |
1124 | fuse_ino_t child_inode = ino; | |
1125 | char reverse_path[4096]; | |
1126 | ||
1127 | /* ino == 1 is a special case; we already know that it is not */ | |
1128 | /* associated with any device redirection */ | |
1129 | if (ino == 1) | |
1130 | { | |
1131 | /* just return the device_id for the file in full_path */ | |
1132 | log_debug("looking for file with pinode=%ld name=%s", ino, full_path); | |
1133 | xfuse_dump_fs(); | |
1134 | ||
1135 | XRDP_INODE *xinode = xfuse_get_inode_from_pinode_name(ino, full_path); | |
1136 | full_path[0] = 0; | |
1137 | if (xinode) | |
1138 | return xinode->device_id; | |
1139 | else | |
1140 | return 0; | |
1141 | } | |
1142 | ||
1143 | reverse_path[0] = 0; | |
1144 | full_path[0] = 0; | |
1145 | ||
1146 | while (1) | |
1147 | { | |
1148 | strcat(reverse_path, g_xrdp_fs.inode_table[child_inode]->name); | |
1149 | ||
1150 | parent_inode = g_xrdp_fs.inode_table[child_inode]->parent_inode; | |
1151 | if (parent_inode == 1) | |
1152 | break; | |
1153 | ||
1154 | strcat(reverse_path, "/"); | |
1155 | child_inode = parent_inode; | |
1156 | } | |
1157 | ||
1158 | fuse_reverse_pathname(full_path, reverse_path); | |
1159 | ||
1160 | return g_xrdp_fs.inode_table[child_inode]->device_id; | |
1161 | } | |
1162 | ||
1163 | /** | |
1164 | * Reverse the pathname in 'reverse_path' and insert it into 'full_path' | |
1165 | * | |
1166 | * Example: abba/music/share1 becomes share1/music/abba | |
1167 | * | |
1168 | * @param full_path path name in the correct order | |
1169 | * @param reverse_path path name in the reverse order | |
1170 | *****************************************************************************/ | |
1171 | ||
1172 | static void fuse_reverse_pathname(char *full_path, char *reverse_path) | |
1173 | { | |
1174 | char *cptr; | |
1175 | ||
1176 | full_path[0] = 0; | |
1177 | ||
1178 | while ((cptr = strrchr(reverse_path, '/')) != NULL) | |
1179 | { | |
1180 | strcat(full_path, cptr + 1); | |
1181 | strcat(full_path, "/"); | |
1182 | cptr[0] = 0; | |
1183 | } | |
1184 | strcat(full_path, reverse_path); | |
1185 | } | |
1186 | ||
1187 | /** | |
1188 | * Return the inode that matches the name and parent inode | |
1189 | *****************************************************************************/ | |
1190 | ||
1191 | static struct xrdp_inode * xfuse_get_inode_from_pinode_name(fuse_ino_t pinode, | |
1192 | const char *name) | |
1193 | { | |
1194 | fuse_ino_t i; | |
1195 | struct xrdp_inode * xinode; | |
1196 | ||
1197 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
1198 | { | |
1199 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
1200 | continue; | |
1201 | ||
1202 | /* match parent inode */ | |
1203 | if (xinode->parent_inode != pinode) | |
1204 | continue; | |
1205 | ||
1206 | /* match name */ | |
1207 | if (strcmp(xinode->name, name) != 0) | |
1208 | continue; | |
1209 | ||
1210 | return xinode; | |
1211 | } | |
1212 | return NULL; | |
1213 | } | |
1214 | ||
1215 | /** | |
1216 | * Create file in xrdp file system | |
1217 | * | |
1218 | * @param pinode the parent inode | |
1219 | * @param name filename | |
1220 | * | |
1221 | * @return XRDP_INODE on success, NULL on failure | |
1222 | *****************************************************************************/ | |
1223 | ||
1224 | static struct xrdp_inode * | |
1225 | xfuse_create_file_in_xrdp_fs(tui32 device_id, int pinode, const char *name, | |
1226 | int type) | |
1227 | { | |
1228 | XRDP_INODE *xinode; | |
1229 | XRDP_INODE *xinodep; | |
1230 | time_t cur_time; | |
1231 | ||
1232 | if ((name == NULL) || (strlen(name) == 0)) | |
1233 | return NULL; | |
1234 | ||
1235 | /* Do we have an inode table yet? */ | |
1236 | if (xfuse_init_xrdp_fs()) | |
1237 | { | |
1238 | return NULL; | |
1239 | } | |
1240 | ||
1241 | xinode = g_new0(XRDP_INODE, 1); | |
1242 | if (xinode == NULL) | |
1243 | { | |
1244 | log_error("system out of memory"); | |
1245 | return NULL; | |
1246 | } | |
1247 | ||
1248 | cur_time = time(0); | |
1249 | ||
1250 | xinode->parent_inode = pinode; | |
1251 | xinode->inode = g_xrdp_fs.next_node++; | |
1252 | xinode->nlink = 1; | |
1253 | xinode->uid = getuid(); | |
1254 | xinode->gid = getgid(); | |
1255 | xinode->atime = cur_time; | |
1256 | xinode->mtime = cur_time; | |
1257 | xinode->ctime = cur_time; | |
1258 | xinode->device_id = device_id; | |
1259 | xinode->is_synced = 1; | |
1260 | strcpy(xinode->name, name); | |
1261 | ||
1262 | if (type == S_IFDIR) | |
1263 | { | |
1264 | xinode->mode = 0755 | type; | |
1265 | xinode->size = 4096; | |
1266 | } | |
1267 | else | |
1268 | { | |
1269 | xinode->mode = 0644 | type; | |
1270 | xinode->size = 0; | |
1271 | } | |
1272 | ||
1273 | g_xrdp_fs.inode_table[xinode->inode] = xinode; | |
1274 | g_xrdp_fs.num_entries++; | |
1275 | ||
1276 | /* bump up lookup count in parent dir */ | |
1277 | xinodep = g_xrdp_fs.inode_table[pinode]; | |
1278 | xinodep->nentries++; | |
1279 | xfuse_update_xrdpfs_size(); | |
1280 | ||
1281 | log_debug("incremented nentries; parent=%d nentries=%d", | |
1282 | pinode, xinodep->nentries); | |
1283 | ||
1284 | return xinode; | |
1285 | } | |
1286 | ||
1287 | /** | |
1288 | * Check if specified file exists | |
1289 | * | |
1290 | * @param parent parent inode of file | |
1291 | * @param name filename or dirname | |
1292 | * | |
1293 | * @return 1 if specified file exists, 0 otherwise | |
1294 | *****************************************************************************/ | |
1295 | ||
1296 | static int xfuse_does_file_exist(fuse_ino_t parent, char *name) | |
1297 | { | |
1298 | fuse_ino_t i; | |
1299 | XRDP_INODE *xinode; | |
1300 | ||
1301 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
1302 | { | |
1303 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
1304 | continue; | |
1305 | ||
1306 | if ((xinode->parent_inode == parent) && | |
1307 | (strcmp(xinode->name, name) == 0)) | |
1308 | { | |
1309 | return 1; | |
1310 | } | |
1311 | } | |
1312 | ||
1313 | return 0; | |
1314 | } | |
1315 | ||
1316 | static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode) | |
1317 | { | |
1318 | /* make sure it is not a dir */ | |
1319 | if ((xinode == NULL) || (xinode->mode & S_IFDIR)) | |
1320 | return -1; | |
1321 | ||
1322 | log_always("deleting: inode=%d name=%s", xinode->inode, xinode->name); | |
1323 | log_debug("deleting: inode=%d name=%s", xinode->inode, xinode->name); | |
1324 | ||
1325 | g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; | |
1326 | g_xrdp_fs.inode_table[xinode->inode] = NULL; | |
1327 | free(xinode); | |
1328 | ||
1329 | return 0; | |
1330 | } | |
1331 | ||
1332 | static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode) | |
1333 | { | |
1334 | XRDP_INODE *xip; | |
1335 | fuse_ino_t i; | |
1336 | ||
1337 | /* make sure it is not a file */ | |
1338 | if ((xinode == NULL) || (xinode->mode & S_IFREG)) | |
1339 | return -1; | |
1340 | ||
1341 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
1342 | { | |
1343 | if ((xip = g_xrdp_fs.inode_table[i]) == NULL) | |
1344 | continue; | |
1345 | ||
1346 | /* look for child inodes */ | |
1347 | if (xip->parent_inode == xinode->inode) | |
1348 | { | |
1349 | /* got one, delete it */ | |
1350 | g_xrdp_fs.inode_table[xip->inode] = NULL; | |
1351 | free(xip); | |
1352 | } | |
1353 | } | |
1354 | ||
1355 | /* our parent will have one less dir */ | |
1356 | g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; | |
1357 | ||
1358 | g_xrdp_fs.inode_table[xinode->inode] = NULL; | |
1359 | free(xinode); | |
1360 | ||
1361 | return 0; | |
1362 | } | |
1363 | ||
1364 | /** | |
1365 | * Recursively delete dir with specified inode | |
1366 | *****************************************************************************/ | |
1367 | ||
1368 | static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode) | |
1369 | { | |
1370 | XRDP_INODE *xip; | |
1371 | fuse_ino_t i; | |
1372 | ||
1373 | /* make sure it is not a file */ | |
1374 | if ((xinode == NULL) || (xinode->mode & S_IFREG)) | |
1375 | return -1; | |
1376 | ||
1377 | log_always("recursively deleting dir with inode=%d name=%s", | |
1378 | xinode->inode, xinode->name); | |
1379 | ||
1380 | log_debug("recursively deleting dir with inode=%d name=%s", | |
1381 | xinode->inode, xinode->name); | |
1382 | ||
1383 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
1384 | { | |
1385 | if ((xip = g_xrdp_fs.inode_table[i]) == NULL) | |
1386 | continue; | |
1387 | ||
1388 | /* look for child inodes */ | |
1389 | if (xip->parent_inode == xinode->inode) | |
1390 | { | |
1391 | /* got one */ | |
1392 | if (xip->mode & S_IFREG) | |
1393 | { | |
1394 | /* regular file */ | |
1395 | g_xrdp_fs.inode_table[xip->parent_inode]->nentries--; | |
1396 | g_xrdp_fs.inode_table[xip->inode] = NULL; | |
1397 | free(xip); | |
1398 | } | |
1399 | else | |
1400 | { | |
1401 | /* got another dir */ | |
1402 | xfuse_recursive_delete_dir_with_xinode(xip); | |
1403 | } | |
1404 | } | |
1405 | } | |
1406 | ||
1407 | /* our parent will have one less dir */ | |
1408 | g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; | |
1409 | ||
1410 | g_xrdp_fs.inode_table[xinode->inode] = NULL; | |
1411 | free(xinode); | |
1412 | ||
1413 | return 0; | |
1414 | } | |
1415 | ||
1416 | static void xfuse_update_xrdpfs_size(void) | |
1417 | { | |
1418 | void *vp; | |
1419 | int diff; | |
1420 | ||
1421 | diff = g_xrdp_fs.max_entries - g_xrdp_fs.num_entries; | |
1422 | if (diff > 100) | |
1423 | return; | |
1424 | ||
1425 | /* extend memory */ | |
1426 | vp = realloc(g_xrdp_fs.inode_table, | |
1427 | (g_xrdp_fs.max_entries + 100) * sizeof(struct xrdp_inode *)); | |
1428 | ||
1429 | if (vp == NULL) | |
1430 | { | |
1431 | log_error("system out of memory"); | |
1432 | return; | |
1433 | } | |
1434 | ||
1435 | /* zero newly added memory */ | |
1436 | memset((char *) vp + g_xrdp_fs.max_entries * sizeof(struct xrdp_inode *), | |
1437 | 0, | |
1438 | 100 * sizeof(struct xrdp_inode *)); | |
1439 | ||
1440 | g_xrdp_fs.max_entries += 100; | |
1441 | g_xrdp_fs.inode_table = (struct xrdp_inode **) vp; | |
1442 | 871 | } |
1443 | 872 | |
1444 | 873 | /****************************************************************************** |
1447 | 876 | ** ** |
1448 | 877 | ******************************************************************************/ |
1449 | 878 | |
1450 | /** | |
1451 | * Add a file or directory to xrdp file system | |
1452 | *****************************************************************************/ | |
1453 | ||
1454 | int xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) | |
1455 | { | |
1456 | XFUSE_INFO *fip = (XFUSE_INFO *) vp; | |
1457 | XRDP_INODE *xip = NULL; | |
1458 | ||
1459 | if ((fip == NULL) || (xinode == NULL)) | |
1460 | { | |
1461 | log_error("fip or xinode are NULL"); | |
1462 | return -1; | |
1463 | } | |
1464 | ||
1465 | if (!xfuse_is_inode_valid(fip->inode)) | |
1466 | { | |
1467 | log_error("inode %ld is not valid", fip->inode); | |
1468 | g_free(xinode); | |
1469 | return -1; | |
1470 | } | |
1471 | ||
1472 | log_debug("parent_inode=%ld name=%s", fip->inode, xinode->name); | |
1473 | ||
1474 | /* if filename is . or .. don't add it */ | |
1475 | if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) | |
1476 | { | |
1477 | g_free(xinode); | |
1478 | return -1; | |
1479 | } | |
1480 | ||
1481 | xfuse_dump_fs(); | |
1482 | ||
1483 | if ((xip = xfuse_get_inode_from_pinode_name(fip->inode, xinode->name)) != NULL) | |
1484 | { | |
1485 | log_debug("inode=%ld name=%s already exists in xrdp_fs; not adding it", | |
1486 | fip->inode, xinode->name); | |
1487 | g_free(xinode); | |
1488 | xip->stale = 0; | |
1489 | return -1; | |
1490 | } | |
1491 | ||
1492 | xinode->parent_inode = fip->inode; | |
1493 | xinode->inode = g_xrdp_fs.next_node++; | |
1494 | xinode->uid = getuid(); | |
1495 | xinode->gid = getgid(); | |
1496 | xinode->device_id = fip->device_id; | |
1497 | ||
1498 | g_xrdp_fs.num_entries++; | |
1499 | ||
1500 | /* insert it in xrdp fs and update lookup count */ | |
1501 | g_xrdp_fs.inode_table[xinode->inode] = xinode; | |
1502 | g_xrdp_fs.inode_table[fip->inode]->nentries++; | |
1503 | xfuse_update_xrdpfs_size(); | |
1504 | ||
1505 | xfuse_dump_fs(); | |
1506 | return 0; | |
1507 | } | |
1508 | ||
1509 | /** | |
1510 | *****************************************************************************/ | |
1511 | ||
1512 | void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) | |
1513 | { | |
1514 | XFUSE_INFO *fip; | |
1515 | struct dir_info *di; | |
1516 | struct opendir_req *odreq; | |
1517 | ||
1518 | log_debug("vp=%p IoStatus=0x%x", vp, IoStatus); | |
1519 | ||
1520 | fip = (XFUSE_INFO *) vp; | |
1521 | if (fip == NULL) | |
1522 | { | |
1523 | log_debug("fip is NULL"); | |
1524 | goto done; | |
1525 | } | |
879 | ||
880 | /** | |
881 | * Add a file or directory to xrdp file system as part of a | |
882 | * directory request | |
883 | * | |
884 | * If the file or directory already exists, no changes are made to it. | |
885 | *****************************************************************************/ | |
886 | ||
887 | void xfuse_devredir_cb_enum_dir_add_entry( | |
888 | struct state_dirscan *fip, | |
889 | const char *name, | |
890 | const struct file_attr *fattr) | |
891 | { | |
892 | XFS_INODE *xinode = NULL; | |
893 | ||
894 | if (!xfs_get(g_xfs, fip->pinum)) | |
895 | { | |
896 | log_error("inode %ld is not valid", fip->pinum); | |
897 | } | |
898 | else if ((strcmp(name, ".") == 0) || | |
899 | (strcmp(name, "..") == 0)) | |
900 | { | |
901 | ; /* filename is . or .. - don't add it */ | |
902 | } | |
903 | else | |
904 | { | |
905 | log_debug("parent_inode=%ld name=%s", fip->pinum, name); | |
906 | ||
907 | /* Does the file already exist ? If it does it's important we | |
908 | * don't mess with it, as we're only enumerating the directory, and | |
909 | * we don't want to disrupt any existing operations on the file | |
910 | */ | |
911 | xinode = xfs_lookup_in_dir(g_xfs, fip->pinum, name); | |
912 | if (xinode == NULL) | |
913 | { | |
914 | /* Add a new node to the file system */ | |
915 | log_debug("Creating name=%s in parent=%ld in xrdp_fs", | |
916 | name, fip->pinum); | |
917 | xinode = xfs_add_entry(g_xfs, fip->pinum, name, fattr->mode); | |
918 | if (xinode == NULL) | |
919 | { | |
920 | log_error("xfs_add_entry() failed"); | |
921 | } | |
922 | else | |
923 | { | |
924 | xinode->size = fattr->size; | |
925 | xinode->atime = fattr->atime; | |
926 | xinode->mtime = fattr->mtime; | |
927 | /* Initially, set the attribute change time to the file data | |
928 | change time */ | |
929 | xinode->ctime = fattr->mtime; | |
930 | ||
931 | /* device_id is inherited from parent */ | |
932 | } | |
933 | } | |
934 | } | |
935 | } | |
936 | ||
937 | /** | |
938 | * This routine is called by devredir when the opendir request has | |
939 | * completed | |
940 | *****************************************************************************/ | |
941 | ||
942 | void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip, | |
943 | enum NTSTATUS IoStatus) | |
944 | { | |
945 | log_debug("fip=%p IoStatus=0x%x", fip, IoStatus); | |
946 | ||
947 | /* | |
948 | * NT_STATUS_NO_SUCH_FILE is returned for empty directories | |
949 | */ | |
950 | if (IoStatus != NT_STATUS_SUCCESS && IoStatus != NT_STATUS_NO_SUCH_FILE) | |
951 | { | |
952 | int status; | |
953 | switch (IoStatus) | |
954 | { | |
955 | case NT_STATUS_ACCESS_DENIED: | |
956 | status = EACCES; | |
957 | break; | |
958 | default: | |
959 | status = ENOENT; | |
960 | } | |
961 | fuse_reply_err(fip->req, status); | |
962 | } | |
963 | else if (!xfs_get(g_xfs, fip->pinum)) | |
964 | { | |
965 | log_error("inode %ld is not valid", fip->pinum); | |
966 | fuse_reply_err(fip->req, ENOENT); | |
967 | } | |
968 | else | |
969 | { | |
970 | struct fuse_file_info *fi = &fip->fi; | |
971 | ||
972 | if ((fi->fh = (tintptr) xfs_opendir(g_xfs, fip->pinum)) == 0) | |
973 | { | |
974 | fuse_reply_err(fip->req, ENOMEM); | |
975 | } | |
976 | else | |
977 | { | |
978 | fuse_reply_open(fip->req, &fip->fi); | |
979 | } | |
980 | } | |
981 | ||
982 | free(fip); | |
983 | } | |
984 | ||
985 | /** | |
986 | * This routine is caused as a result of a devredir remote lookup | |
987 | * instigated by xfuse_cb_lookup() | |
988 | *****************************************************************************/ | |
989 | ||
990 | void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip, | |
991 | enum NTSTATUS IoStatus, | |
992 | const struct file_attr *file_info) | |
993 | { | |
994 | XFS_INODE *xinode = NULL; | |
995 | ||
996 | if (IoStatus != NT_STATUS_SUCCESS) | |
997 | { | |
998 | switch (IoStatus) | |
999 | { | |
1000 | case NT_STATUS_SHARING_VIOLATION: | |
1001 | /* This can happen when trying to read the attributes of | |
1002 | * some system files (e.g. pagefile.sys) */ | |
1003 | case NT_STATUS_ACCESS_DENIED: | |
1004 | fuse_reply_err(fip->req, EACCES); | |
1005 | break; | |
1006 | ||
1007 | case NT_STATUS_UNSUCCESSFUL: | |
1008 | /* Happens if we try to lookup an illegal filename (e.g. | |
1009 | * one with a '*' in it) */ | |
1010 | fuse_reply_err(fip->req, ENOENT); | |
1011 | break; | |
1012 | ||
1013 | case NT_STATUS_NO_SUCH_FILE: | |
1014 | /* Remove our copy, if any */ | |
1015 | if (fip->existing_inum && | |
1016 | (xinode = xfs_get(g_xfs, fip->existing_inum)) != NULL && | |
1017 | xinode->generation == fip->existing_generation) | |
1018 | { | |
1019 | xfs_remove_entry(g_xfs, fip->existing_inum); | |
1020 | } | |
1021 | fuse_reply_err(fip->req, ENOENT); | |
1022 | break; | |
1023 | ||
1024 | default: | |
1025 | log_info("Error code %08x - fallthrough", (int) IoStatus); | |
1026 | fuse_reply_err(fip->req, EIO); | |
1027 | break; | |
1028 | } | |
1029 | } | |
1030 | else if (!xfs_get(g_xfs, fip->pinum)) | |
1031 | { | |
1032 | log_error("parent inode %ld is not valid", fip->pinum); | |
1033 | fuse_reply_err(fip->req, ENOENT); | |
1034 | } | |
1035 | else | |
1036 | { | |
1037 | log_debug("parent_inode=%ld name=%s", fip->pinum, fip->name); | |
1038 | ||
1039 | /* Does the file already exist ? */ | |
1040 | xinode = xfs_lookup_in_dir(g_xfs, fip->pinum, fip->name); | |
1041 | if (xinode != NULL) | |
1042 | { | |
1043 | /* Is the existing file the same type ? */ | |
1044 | if ((xinode->mode & (S_IFREG | S_IFDIR)) == | |
1045 | (file_info->mode & (S_IFREG | S_IFDIR))) | |
1046 | { | |
1047 | log_debug("inode=%ld name=%s already exists in xrdp_fs as %ld", | |
1048 | fip->pinum, fip->name, xinode->inum); | |
1049 | if (xfs_get_file_open_count(g_xfs, xinode->inum) > 0) | |
1050 | { | |
1051 | /* | |
1052 | * Don't mess with open files. The local attributes are | |
1053 | * almost certainly more up-to-date. A worst case scenario | |
1054 | * would be truncating a file we're currently writing | |
1055 | * to, as the lookup value for the size is stale. | |
1056 | */ | |
1057 | log_debug("inode=%ld is open - " | |
1058 | "preferring local attributes", xinode->inum); | |
1059 | } | |
1060 | else | |
1061 | { | |
1062 | log_debug("Updating attributes of inode=%ld", xinode->inum); | |
1063 | update_inode_file_attributes(file_info, TO_SET_ALL, xinode); | |
1064 | } | |
1065 | } | |
1066 | else | |
1067 | { | |
1068 | /* Type has changed from file to directory, or vice-versa */ | |
1069 | log_debug("inode=%ld name=%s of different type in xrdp_fs" | |
1070 | " - removing", | |
1071 | fip->pinum, xinode->name); | |
1072 | xfs_remove_entry(g_xfs, xinode->inum); | |
1073 | xinode = NULL; | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | if (xinode == NULL) | |
1078 | { | |
1079 | /* Add a new node to the file system */ | |
1080 | log_debug("Creating name=%s in parent=%ld in xrdp_fs", | |
1081 | fip->name, fip->pinum); | |
1082 | xinode = xfs_add_entry(g_xfs, fip->pinum, fip->name, | |
1083 | file_info->mode); | |
1084 | if (xinode == NULL) | |
1085 | { | |
1086 | log_debug("xfs_add_entry() failed"); | |
1087 | } | |
1088 | else | |
1089 | { | |
1090 | xinode->size = file_info->size; | |
1091 | xinode->atime = file_info->atime; | |
1092 | xinode->mtime = file_info->mtime; | |
1093 | /* Initially, set the attribute change time to the file data | |
1094 | change time */ | |
1095 | xinode->ctime = file_info->mtime; | |
1096 | /* device_id is inherited from parent */ | |
1097 | } | |
1098 | } | |
1099 | if (xinode != NULL) | |
1100 | { | |
1101 | make_fuse_entry_reply(fip->req, xinode); | |
1102 | } | |
1103 | else | |
1104 | { | |
1105 | fuse_reply_err(fip->req, EIO); | |
1106 | } | |
1107 | } | |
1108 | ||
1109 | free(fip); | |
1110 | } | |
1111 | ||
1112 | /** | |
1113 | * This routine is caused as a result of a devredir remote setattr | |
1114 | * instigated by xfuse_cb_setattr() | |
1115 | *****************************************************************************/ | |
1116 | void xfuse_devredir_cb_setattr(struct state_setattr *fip, | |
1117 | enum NTSTATUS IoStatus) | |
1118 | { | |
1119 | XFS_INODE *xinode; | |
1120 | ||
1121 | if (IoStatus != NT_STATUS_SUCCESS) | |
1122 | { | |
1123 | switch (IoStatus) | |
1124 | { | |
1125 | case NT_STATUS_SHARING_VIOLATION: | |
1126 | /* This can happen when trying to read the attributes of | |
1127 | * some system files (e.g. pagefile.sys) */ | |
1128 | case NT_STATUS_ACCESS_DENIED: | |
1129 | fuse_reply_err(fip->req, EACCES); | |
1130 | break; | |
1131 | ||
1132 | case NT_STATUS_UNSUCCESSFUL: | |
1133 | /* Happens if we try to lookup an illegal filename */ | |
1134 | case NT_STATUS_NO_SUCH_FILE: | |
1135 | fuse_reply_err(fip->req, ENOENT); | |
1136 | break; | |
1137 | ||
1138 | default: | |
1139 | log_info("Error code %08x - fallthrough", (int) IoStatus); | |
1140 | fuse_reply_err(fip->req, EIO); | |
1141 | break; | |
1142 | } | |
1143 | } | |
1144 | else if ((xinode = xfs_get(g_xfs, fip->inum)) == NULL) | |
1145 | { | |
1146 | fuse_reply_err(fip->req, ENOENT); | |
1147 | } | |
1148 | else | |
1149 | { | |
1150 | update_inode_file_attributes(&fip->fattr, fip->change_mask, xinode); | |
1151 | make_fuse_attr_reply(fip->req, xinode); | |
1152 | } | |
1153 | free(fip); | |
1154 | } | |
1155 | ||
1156 | /** | |
1157 | * This routine is caused as a result of a file or directory | |
1158 | * create request */ | |
1159 | void xfuse_devredir_cb_create_file(struct state_create *fip, | |
1160 | enum NTSTATUS IoStatus, | |
1161 | tui32 DeviceId, tui32 FileId) | |
1162 | { | |
1163 | XFUSE_HANDLE *fh = NULL; | |
1526 | 1164 | |
1527 | 1165 | if (IoStatus != 0) |
1528 | 1166 | { |
1529 | /* command failed */ | |
1530 | if (fip->invoke_fuse) | |
1531 | fuse_reply_err(fip->req, ENOENT); | |
1532 | goto done; | |
1533 | } | |
1534 | ||
1535 | /* do we have a valid inode? */ | |
1536 | if (!xfuse_is_inode_valid(fip->inode)) | |
1537 | { | |
1538 | log_error("inode %ld is not valid", fip->inode); | |
1539 | if (fip->invoke_fuse) | |
1540 | fuse_reply_err(fip->req, EBADF); | |
1541 | goto done; | |
1542 | } | |
1543 | ||
1544 | xfuse_delete_stale_entries(fip->inode); | |
1545 | ||
1546 | /* this will be used by xfuse_cb_readdir() */ | |
1547 | di = g_new0(struct dir_info, 1); | |
1548 | di->index = FIRST_INODE; | |
1549 | fip->fi->fh = (tintptr) di; | |
1550 | ||
1551 | fuse_reply_open(fip->req, fip->fi); | |
1552 | ||
1553 | done: | |
1554 | ||
1555 | if (fip) | |
1556 | free(fip); | |
1557 | ||
1558 | /* remove current request */ | |
1559 | g_free(fifo_remove(&g_fifo_opendir)); | |
1560 | ||
1561 | while (1) | |
1562 | { | |
1563 | /* process next request */ | |
1564 | odreq = (struct opendir_req *) fifo_peek(&g_fifo_opendir); | |
1565 | if (!odreq) | |
1566 | return; | |
1567 | ||
1568 | if (xfuse_proc_opendir_req(odreq->req, odreq->ino, odreq->fi)) | |
1569 | g_free(fifo_remove(&g_fifo_opendir)); /* req failed */ | |
1570 | else | |
1571 | break; /* req has been queued */ | |
1572 | } | |
1573 | } | |
1574 | ||
1575 | void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, | |
1576 | tui32 FileId) | |
1577 | { | |
1578 | XFUSE_HANDLE *fh; | |
1579 | XRDP_INODE *xinode; | |
1580 | ||
1581 | XFUSE_INFO *fip = (XFUSE_INFO *) vp; | |
1582 | if (fip == NULL) | |
1583 | { | |
1584 | log_debug("fip is NULL"); | |
1585 | goto done; | |
1586 | } | |
1587 | ||
1588 | log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p DeviceId=%d FileId=%d", | |
1589 | fip, fip->fi, DeviceId, FileId); | |
1590 | ||
1591 | if (IoStatus != 0) | |
1592 | { | |
1593 | if (!fip->invoke_fuse) | |
1594 | goto done; | |
1595 | ||
1596 | 1167 | switch (IoStatus) |
1597 | 1168 | { |
1598 | case 0xC0000022: | |
1169 | case NT_STATUS_ACCESS_DENIED: | |
1599 | 1170 | fuse_reply_err(fip->req, EACCES); |
1600 | 1171 | break; |
1601 | 1172 | |
1602 | case 0xC0000033: | |
1603 | case 0xC0000034: | |
1173 | case NT_STATUS_OBJECT_NAME_INVALID: | |
1174 | case NT_STATUS_OBJECT_NAME_NOT_FOUND: | |
1604 | 1175 | fuse_reply_err(fip->req, ENOENT); |
1605 | 1176 | break; |
1606 | 1177 | |
1608 | 1179 | fuse_reply_err(fip->req, EIO); |
1609 | 1180 | break; |
1610 | 1181 | } |
1611 | ||
1612 | goto done; | |
1613 | } | |
1614 | ||
1615 | if (fip->fi != NULL) | |
1616 | { | |
1617 | fh = g_new0(XFUSE_HANDLE, 1); | |
1618 | if (fh == NULL) | |
1619 | { | |
1182 | } | |
1183 | else | |
1184 | { | |
1185 | if ((fip->mode & S_IFREG) != 0) | |
1186 | { | |
1187 | /* We've created a regular file */ | |
1188 | /* Allocate an XFUSE_HANDLE for future file operations */ | |
1189 | if ((fh = g_new0(XFUSE_HANDLE, 1)) != NULL) | |
1190 | { | |
1191 | /* save file handle for later use */ | |
1192 | fh->DeviceId = DeviceId; | |
1193 | fh->FileId = FileId; | |
1194 | ||
1195 | fip->fi.fh = (tintptr) fh; | |
1196 | } | |
1197 | } | |
1198 | ||
1199 | if ((fip->mode & S_IFREG) != 0 && fh == NULL) | |
1200 | { | |
1201 | /* We failed to allocate a file handle */ | |
1620 | 1202 | log_error("system out of memory"); |
1621 | if (fip->invoke_fuse) | |
1622 | fuse_reply_err(fip->req, ENOMEM); | |
1623 | ||
1624 | free(fip); | |
1625 | return; | |
1626 | } | |
1627 | ||
1628 | /* save file handle for later use */ | |
1629 | fh->DeviceId = DeviceId; | |
1630 | fh->FileId = FileId; | |
1631 | ||
1632 | fip->fi->fh = (tintptr) fh; | |
1633 | log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", | |
1634 | fip, fip->fi, (long long) fip->fi->fh); | |
1635 | } | |
1636 | ||
1637 | if (fip->invoke_fuse) | |
1638 | { | |
1639 | if (fip->reply_type == RT_FUSE_REPLY_OPEN) | |
1640 | { | |
1641 | log_debug("sending fuse_reply_open(); " | |
1642 | "DeviceId=%d FileId=%d req=%p fi=%p", | |
1643 | fh->DeviceId, fh->FileId, fip->req, fip->fi); | |
1644 | ||
1645 | /* update open count */ | |
1646 | if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) | |
1647 | xinode->nopen++; | |
1648 | ||
1649 | fuse_reply_open(fip->req, fip->fi); | |
1650 | } | |
1651 | else if (fip->reply_type == RT_FUSE_REPLY_CREATE) | |
1652 | { | |
1653 | struct fuse_entry_param e; | |
1654 | ||
1655 | // LK_TODO | |
1656 | #if 0 | |
1657 | if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL) | |
1658 | { | |
1659 | log_error("inode at inode_table[%ld] is NULL", fip->inode); | |
1660 | fuse_reply_err(fip->req, EBADF); | |
1661 | goto done; | |
1662 | } | |
1663 | #else | |
1203 | fuse_reply_err(fip->req, ENOMEM); | |
1204 | } | |
1205 | else | |
1206 | { | |
1207 | XFS_INODE *xinode; | |
1664 | 1208 | /* create entry in xrdp file system */ |
1665 | xinode = xfuse_create_file_in_xrdp_fs(fip->device_id, fip->inode, | |
1666 | fip->name, fip->mode); | |
1209 | xinode = xfs_add_entry(g_xfs, fip->pinum, fip->name, fip->mode); | |
1667 | 1210 | if (xinode == NULL) |
1668 | 1211 | { |
1212 | /* It's possible xfs_add_entry() has failed, as the | |
1213 | * file has already been added (by a lookup request) | |
1214 | * in the time between our request and the response | |
1215 | * This can happen if an 'ls' is happening in the same | |
1216 | * directory as this file is being created. | |
1217 | * | |
1218 | * We'll check for this before we fail the create */ | |
1219 | if ((xinode = xfs_lookup_in_dir(g_xfs, | |
1220 | fip->pinum, | |
1221 | fip->name)) != NULL) | |
1222 | { | |
1223 | /* | |
1224 | * The mode should be correct anyway, but we'll | |
1225 | * set it to the mode requested at creation | |
1226 | */ | |
1227 | xinode->mode = fip->mode; | |
1228 | } | |
1229 | } | |
1230 | ||
1231 | if (xinode == NULL) | |
1232 | { | |
1233 | log_error("Out of memory!"); | |
1669 | 1234 | fuse_reply_err(fip->req, ENOMEM); |
1670 | return; | |
1671 | } | |
1672 | #endif | |
1673 | memset(&e, 0, sizeof(struct fuse_entry_param)); | |
1674 | ||
1675 | e.ino = xinode->inode; | |
1676 | e.attr_timeout = XFUSE_ATTR_TIMEOUT; | |
1677 | e.entry_timeout = XFUSE_ENTRY_TIMEOUT; | |
1678 | e.attr.st_ino = xinode->inode; | |
1679 | e.attr.st_mode = xinode->mode; | |
1680 | e.attr.st_nlink = xinode->nlink; | |
1681 | e.attr.st_uid = xinode->uid; | |
1682 | e.attr.st_gid = xinode->gid; | |
1683 | e.attr.st_size = xinode->size; | |
1684 | e.attr.st_atime = xinode->atime; | |
1685 | e.attr.st_mtime = xinode->mtime; | |
1686 | e.attr.st_ctime = xinode->ctime; | |
1687 | e.generation = 1; | |
1688 | ||
1689 | if (fip->mode == S_IFDIR) | |
1690 | { | |
1691 | fuse_reply_entry(fip->req, &e); | |
1692 | 1235 | } |
1693 | 1236 | else |
1694 | 1237 | { |
1695 | xinode->nopen++; | |
1696 | fuse_reply_create(fip->req, &e, fip->fi); | |
1238 | ||
1239 | if ((fip->mode & S_IFDIR) != 0) | |
1240 | { | |
1241 | make_fuse_entry_reply(fip->req, xinode); | |
1242 | } | |
1243 | else | |
1244 | { | |
1245 | struct fuse_entry_param e; | |
1246 | xfs_inode_to_fuse_entry_param(xinode, &e); | |
1247 | fuse_reply_create(fip->req, &e, &fip->fi); | |
1248 | xfs_increment_file_open_count(g_xfs, xinode->inum); | |
1249 | } | |
1697 | 1250 | } |
1698 | 1251 | } |
1252 | } | |
1253 | ||
1254 | free(fip); | |
1255 | } | |
1256 | ||
1257 | ||
1258 | /** | |
1259 | * This routine is caused as a result of a file open request */ | |
1260 | void xfuse_devredir_cb_open_file(struct state_open *fip, | |
1261 | enum NTSTATUS IoStatus, | |
1262 | tui32 DeviceId, tui32 FileId) | |
1263 | { | |
1264 | XFUSE_HANDLE *fh; | |
1265 | ||
1266 | if (IoStatus != 0) | |
1267 | { | |
1268 | switch (IoStatus) | |
1269 | { | |
1270 | case NT_STATUS_ACCESS_DENIED: | |
1271 | fuse_reply_err(fip->req, EACCES); | |
1272 | break; | |
1273 | ||
1274 | case NT_STATUS_OBJECT_NAME_INVALID: | |
1275 | case NT_STATUS_OBJECT_NAME_NOT_FOUND: | |
1276 | fuse_reply_err(fip->req, ENOENT); | |
1277 | break; | |
1278 | ||
1279 | default: | |
1280 | fuse_reply_err(fip->req, EIO); | |
1281 | break; | |
1282 | } | |
1283 | } | |
1284 | else | |
1285 | { | |
1286 | /* Allocate an XFUSE_HANDLE for future file operations */ | |
1287 | if ((fh = g_new0(XFUSE_HANDLE, 1)) == NULL) | |
1288 | { | |
1289 | log_error("system out of memory"); | |
1290 | fuse_reply_err(fip->req, ENOMEM); | |
1291 | } | |
1699 | 1292 | else |
1700 | 1293 | { |
1701 | log_error("invalid reply type: %d", fip->reply_type); | |
1702 | } | |
1703 | } | |
1704 | ||
1705 | done: | |
1294 | /* save file handle for later use */ | |
1295 | fh->DeviceId = DeviceId; | |
1296 | fh->FileId = FileId; | |
1297 | ||
1298 | fip->fi.fh = (tintptr) fh; | |
1299 | ||
1300 | log_debug("sending fuse_reply_open(); " | |
1301 | "DeviceId=%d FileId=%d req=%p", | |
1302 | fh->DeviceId, fh->FileId, fip->req); | |
1303 | ||
1304 | /* update open count */ | |
1305 | xfs_increment_file_open_count(g_xfs, fip->inum); | |
1306 | ||
1307 | fuse_reply_open(fip->req, &fip->fi); | |
1308 | } | |
1309 | } | |
1706 | 1310 | |
1707 | 1311 | free(fip); |
1708 | 1312 | } |
1709 | 1313 | |
1710 | void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length) | |
1711 | { | |
1712 | XFUSE_INFO *fip; | |
1713 | ||
1714 | fip = (XFUSE_INFO *) vp; | |
1715 | if ((fip == NULL) || (fip->req == NULL)) | |
1716 | { | |
1717 | log_error("fip for fip->req is NULL"); | |
1718 | return; | |
1719 | } | |
1720 | ||
1314 | void xfuse_devredir_cb_read_file(struct state_read *fip, | |
1315 | const char *buf, size_t length) | |
1316 | { | |
1721 | 1317 | fuse_reply_buf(fip->req, buf, length); |
1722 | 1318 | free(fip); |
1723 | 1319 | } |
1724 | 1320 | |
1725 | void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length) | |
1726 | { | |
1727 | XRDP_INODE *xinode; | |
1728 | XFUSE_INFO *fip; | |
1729 | ||
1730 | fip = (XFUSE_INFO *) vp; | |
1731 | if ((fip == NULL) || (fip->req == NULL) || (fip->fi == NULL)) | |
1732 | { | |
1733 | log_error("fip, fip->req or fip->fi is NULL"); | |
1734 | return; | |
1735 | } | |
1736 | ||
1737 | log_debug("+++ XFUSE_INFO=%p, XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", | |
1738 | fip, fip->fi, (long long) fip->fi->fh); | |
1739 | ||
1740 | fuse_reply_write(fip->req, length); | |
1741 | ||
1742 | /* update file size */ | |
1743 | if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) | |
1744 | xinode->size += length; | |
1321 | void xfuse_devredir_cb_write_file( | |
1322 | struct state_write *fip, | |
1323 | enum NTSTATUS IoStatus, | |
1324 | off_t offset, | |
1325 | size_t length) | |
1326 | { | |
1327 | XFS_INODE *xinode; | |
1328 | ||
1329 | if (IoStatus != NT_STATUS_SUCCESS) | |
1330 | { | |
1331 | log_error("Write NTSTATUS is %d", (int) IoStatus); | |
1332 | fuse_reply_err(fip->req, EIO); | |
1333 | } | |
1745 | 1334 | else |
1746 | log_error("inode at inode_table[%ld] is NULL", fip->inode); | |
1335 | { | |
1336 | off_t new_size = offset + length; | |
1337 | fuse_reply_write(fip->req, length); | |
1338 | ||
1339 | /* update file size */ | |
1340 | if ((xinode = xfs_get(g_xfs, fip->inum)) != NULL) | |
1341 | { | |
1342 | if (new_size > xinode->size) | |
1343 | { | |
1344 | xinode->size = new_size; | |
1345 | } | |
1346 | } | |
1347 | else | |
1348 | { | |
1349 | log_error("inode %ld is invalid", fip->inum); | |
1350 | } | |
1351 | } | |
1747 | 1352 | |
1748 | 1353 | free(fip); |
1749 | 1354 | } |
1750 | 1355 | |
1751 | void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus) | |
1752 | { | |
1753 | XFUSE_INFO *fip; | |
1754 | XRDP_INODE *xinode; | |
1755 | ||
1756 | fip = (XFUSE_INFO *) vp; | |
1757 | if (fip == NULL) | |
1758 | return; | |
1759 | ||
1760 | if (IoStatus != 0) | |
1761 | { | |
1762 | fuse_reply_err(fip->req, EBADF); | |
1763 | free(fip); | |
1764 | return; | |
1765 | } | |
1766 | ||
1767 | /* now delete the item in xrdp fs */ | |
1768 | xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); | |
1769 | if (xinode == NULL) | |
1770 | { | |
1771 | fuse_reply_err(fip->req, EBADF); | |
1772 | free(fip); | |
1773 | return; | |
1774 | } | |
1775 | ||
1776 | g_xrdp_fs.inode_table[xinode->inode] = NULL; | |
1777 | free(xinode); | |
1778 | ||
1779 | /* update parent */ | |
1780 | xinode = g_xrdp_fs.inode_table[fip->inode]; | |
1781 | xinode->nentries--; | |
1782 | ||
1356 | void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip, | |
1357 | enum NTSTATUS IoStatus) | |
1358 | { | |
1359 | XFS_INODE *xinode = xfs_get(g_xfs, fip->inum); | |
1360 | ||
1361 | switch (IoStatus) | |
1362 | { | |
1363 | case NT_STATUS_SUCCESS: | |
1364 | case NT_STATUS_NO_SUCH_FILE: | |
1365 | xfs_remove_entry(g_xfs, xinode->inum); /* Remove local copy */ | |
1366 | fuse_reply_err(fip->req, 0); | |
1367 | break; | |
1368 | ||
1369 | case NT_STATUS_SHARING_VIOLATION: | |
1370 | case NT_STATUS_ACCESS_DENIED: | |
1371 | fuse_reply_err(fip->req, EACCES); | |
1372 | break; | |
1373 | ||
1374 | default: | |
1375 | log_info("Error code %08x - fallthrough", (int) IoStatus); | |
1376 | fuse_reply_err(fip->req, EBADF); | |
1377 | break; | |
1378 | } | |
1379 | free(fip); | |
1380 | } | |
1381 | ||
1382 | void xfuse_devredir_cb_rename_file(struct state_rename *fip, | |
1383 | enum NTSTATUS IoStatus) | |
1384 | { | |
1385 | int status; | |
1386 | ||
1387 | if (IoStatus != NT_STATUS_SUCCESS) | |
1388 | { | |
1389 | status = | |
1390 | (IoStatus == NT_STATUS_SHARING_VIOLATION) ? EBUSY : | |
1391 | (IoStatus == NT_STATUS_ACCESS_DENIED) ? EACCES : | |
1392 | /* default */ EEXIST ; | |
1393 | } | |
1394 | else | |
1395 | { | |
1396 | status = xfs_move_entry(g_xfs, fip->pinum, | |
1397 | fip->new_pinum, fip->name); | |
1398 | } | |
1399 | ||
1400 | fuse_reply_err(fip->req, status); | |
1401 | free(fip); | |
1402 | } | |
1403 | ||
1404 | void xfuse_devredir_cb_file_close(struct state_close *fip) | |
1405 | { | |
1783 | 1406 | fuse_reply_err(fip->req, 0); |
1407 | xfs_decrement_file_open_count(g_xfs, fip->inum); | |
1408 | ||
1784 | 1409 | free(fip); |
1785 | } | |
1786 | ||
1787 | void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus) | |
1788 | { | |
1789 | XFUSE_INFO *fip; | |
1790 | XRDP_INODE *old_xinode; | |
1791 | XRDP_INODE *new_xinode; | |
1792 | ||
1793 | fip = (XFUSE_INFO *) vp; | |
1794 | if (fip == NULL) | |
1795 | return; | |
1796 | ||
1797 | if (IoStatus != 0) | |
1798 | { | |
1799 | fuse_reply_err(fip->req, EEXIST); | |
1800 | free(fip); | |
1801 | return; | |
1802 | } | |
1803 | ||
1804 | /* | |
1805 | * update xrdp file system | |
1806 | */ | |
1807 | ||
1808 | /* if destination dir/file exists, delete it */ | |
1809 | if (xfuse_does_file_exist(fip->new_inode, fip->new_name)) | |
1810 | { | |
1811 | new_xinode = xfuse_get_inode_from_pinode_name(fip->new_inode, | |
1812 | fip->new_name); | |
1813 | ||
1814 | if (new_xinode) | |
1815 | { | |
1816 | if (new_xinode->mode & S_IFREG) | |
1817 | xfuse_delete_file_with_xinode(new_xinode); | |
1818 | else | |
1819 | xfuse_delete_dir_with_xinode(new_xinode); | |
1820 | ||
1821 | new_xinode = NULL; | |
1822 | } | |
1823 | } | |
1824 | ||
1825 | old_xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); | |
1826 | if (old_xinode == NULL) | |
1827 | { | |
1828 | fuse_reply_err(fip->req, EBADF); | |
1829 | free(fip); | |
1830 | return; | |
1831 | } | |
1832 | ||
1833 | old_xinode->parent_inode = fip->new_inode; | |
1834 | strncpy(old_xinode->name, fip->new_name, 1023); | |
1835 | old_xinode->name[1023] = 0; | |
1836 | ||
1837 | if (fip->inode != fip->new_inode) | |
1838 | { | |
1839 | /* file has been moved to a different dir */ | |
1840 | old_xinode->is_synced = 1; | |
1841 | g_xrdp_fs.inode_table[fip->inode]->nentries--; | |
1842 | g_xrdp_fs.inode_table[fip->new_inode]->nentries++; | |
1843 | } | |
1844 | ||
1845 | fuse_reply_err(fip->req, 0); | |
1846 | free(fip); | |
1847 | } | |
1848 | ||
1849 | void xfuse_devredir_cb_file_close(void *vp) | |
1850 | { | |
1851 | XFUSE_INFO *fip; | |
1852 | XRDP_INODE *xinode; | |
1853 | ||
1854 | fip = (XFUSE_INFO *) vp; | |
1855 | if (fip == NULL) | |
1856 | { | |
1857 | log_error("fip is NULL"); | |
1858 | return; | |
1859 | } | |
1860 | ||
1861 | if (fip->fi == NULL) | |
1862 | { | |
1863 | log_error("fip->fi is NULL"); | |
1864 | return; | |
1865 | } | |
1866 | ||
1867 | log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", | |
1868 | fip, fip->fi, (long long) fip->fi->fh); | |
1869 | ||
1870 | if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL) | |
1871 | { | |
1872 | log_debug("inode_table[%ld] is NULL", fip->inode); | |
1873 | fuse_reply_err(fip->req, EBADF); | |
1874 | return; | |
1875 | } | |
1876 | ||
1877 | log_debug("before: inode=%d nopen=%d", xinode->inode, xinode->nopen); | |
1878 | ||
1879 | if (xinode->nopen > 0) | |
1880 | xinode->nopen--; | |
1881 | ||
1882 | /* LK_TODO */ | |
1883 | #if 0 | |
1884 | if ((xinode->nopen == 0) && fip->fi && fip->fi->fh) | |
1885 | { | |
1886 | printf("LK_TODO: ################################ fi=%p fi->fh=0x%llx\n", | |
1887 | fip->fi, (long long) fip->fi->fh); | |
1888 | ||
1889 | free((char *) (tintptr) (fip->fi->fh)); | |
1890 | fip->fi->fh = 0; | |
1891 | } | |
1892 | #endif | |
1893 | ||
1894 | fuse_reply_err(fip->req, 0); | |
1895 | 1410 | } |
1896 | 1411 | |
1897 | 1412 | /****************************************************************************** |
1902 | 1417 | |
1903 | 1418 | /** |
1904 | 1419 | * Look up a directory entry by name and get its attributes |
1905 | * | |
1906 | 1420 | *****************************************************************************/ |
1907 | 1421 | |
1908 | 1422 | static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) |
1909 | 1423 | { |
1910 | XRDP_INODE *xinode; | |
1911 | struct fuse_entry_param e; | |
1424 | XFS_INODE *parent_xinode; | |
1425 | XFS_INODE *xinode = NULL; | |
1912 | 1426 | |
1913 | 1427 | log_debug("looking for parent=%ld name=%s", parent, name); |
1914 | xfuse_dump_fs(); | |
1915 | ||
1916 | if (!xfuse_is_inode_valid(parent)) | |
1428 | ||
1429 | if (strlen(name) > XFS_MAXFILENAMELEN) | |
1430 | { | |
1431 | fuse_reply_err(req, ENAMETOOLONG); | |
1432 | } | |
1433 | else if ((parent_xinode = xfs_get(g_xfs, parent)) == NULL) | |
1917 | 1434 | { |
1918 | 1435 | log_error("inode %ld is not valid", parent); |
1919 | fuse_reply_err(req, EBADF); | |
1920 | return; | |
1921 | } | |
1922 | ||
1923 | xinode = xfuse_get_inode_from_pinode_name(parent, name); | |
1924 | if (xinode == NULL) | |
1925 | { | |
1926 | log_debug("did not find entry for parent=%ld name=%s", parent, name); | |
1927 | 1436 | fuse_reply_err(req, ENOENT); |
1928 | return; | |
1929 | } | |
1930 | ||
1931 | memset(&e, 0, sizeof(e)); | |
1932 | e.ino = xinode->inode; | |
1933 | e.attr_timeout = XFUSE_ATTR_TIMEOUT; | |
1934 | e.entry_timeout = XFUSE_ENTRY_TIMEOUT; | |
1935 | e.attr.st_ino = xinode->inode; | |
1936 | e.attr.st_mode = xinode->mode; | |
1937 | e.attr.st_nlink = xinode->nlink; | |
1938 | e.attr.st_uid = xinode->uid; | |
1939 | e.attr.st_gid = xinode->gid; | |
1940 | e.attr.st_size = xinode->size; | |
1941 | e.attr.st_atime = xinode->atime; | |
1942 | e.attr.st_mtime = xinode->mtime; | |
1943 | e.attr.st_ctime = xinode->ctime; | |
1944 | e.generation = 1; | |
1945 | ||
1946 | fuse_reply_entry(req, &e); | |
1947 | log_debug("found entry for parent=%ld name=%s uid=%d gid=%d", | |
1948 | parent, name, xinode->uid, xinode->gid); | |
1949 | return; | |
1437 | } | |
1438 | else | |
1439 | { | |
1440 | if (parent_xinode->device_id == 0) | |
1441 | { | |
1442 | /* File cannot be remote - we either know about it or we don't */ | |
1443 | if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL) | |
1444 | { | |
1445 | log_debug("found entry for parent=%ld name=%s", | |
1446 | parent, name); | |
1447 | make_fuse_entry_reply(req, xinode); | |
1448 | } | |
1449 | else | |
1450 | { | |
1451 | fuse_reply_err(req, ENOENT); | |
1452 | } | |
1453 | } | |
1454 | else | |
1455 | { | |
1456 | /* specified file resides on redirected share | |
1457 | * | |
1458 | * We always look these up, and relying on libfuse to do sane | |
1459 | * caching */ | |
1460 | struct state_lookup *fip = g_new0(struct state_lookup, 1); | |
1461 | char *full_path = get_name_for_entry_in_parent(parent, name); | |
1462 | ||
1463 | if (fip == NULL || full_path == NULL) | |
1464 | { | |
1465 | log_error("system out of memory"); | |
1466 | fuse_reply_err(req, ENOMEM); | |
1467 | free(fip); | |
1468 | free(full_path); | |
1469 | } | |
1470 | else | |
1471 | { | |
1472 | const char *cptr; | |
1473 | ||
1474 | fip->req = req; | |
1475 | fip->pinum = parent; | |
1476 | strcpy(fip->name, name); | |
1477 | ||
1478 | /* we want path minus 'root node of the share' */ | |
1479 | cptr = filename_on_device(full_path); | |
1480 | ||
1481 | /* If the file already exists on our side, save the inum | |
1482 | * and generation. If it's not remote any more this means we | |
1483 | * can remove it when we get the response | |
1484 | */ | |
1485 | if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL) | |
1486 | { | |
1487 | fip->existing_inum = xinode->inum; | |
1488 | fip->existing_generation = xinode->generation; | |
1489 | } | |
1490 | log_debug("Looking up %s in %s on %d", name, cptr, | |
1491 | parent_xinode->device_id); | |
1492 | /* | |
1493 | * If this call succeeds, further request processing happens in | |
1494 | * xfuse_devredir_cb_lookup_entry() | |
1495 | */ | |
1496 | if (devredir_lookup_entry(fip, parent_xinode->device_id, cptr)) | |
1497 | { | |
1498 | log_error("failed to send devredir_lookup_entry() cmd"); | |
1499 | fuse_reply_err(req, EREMOTEIO); | |
1500 | free(fip); | |
1501 | } | |
1502 | free(full_path); | |
1503 | } | |
1504 | } | |
1505 | } | |
1950 | 1506 | } |
1951 | 1507 | |
1952 | 1508 | /** |
1953 | 1509 | * Get file attributes |
1510 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
1511 | * stack by the caller, so must be copied if we're not using it | |
1512 | * to reply to FUSE immediately | |
1954 | 1513 | *****************************************************************************/ |
1955 | 1514 | |
1956 | 1515 | static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, |
1957 | 1516 | struct fuse_file_info *fi) |
1958 | 1517 | { |
1959 | struct xrdp_inode *xino; | |
1960 | struct stat stbuf; | |
1961 | ||
1962 | (void) fi; | |
1518 | XFS_INODE *xino; | |
1963 | 1519 | |
1964 | 1520 | log_debug("req=%p ino=%ld", req, ino); |
1965 | 1521 | |
1966 | 1522 | /* if ino is not valid, just return */ |
1967 | if (!xfuse_is_inode_valid(ino)) | |
1523 | if ((xino = xfs_get(g_xfs, ino)) == NULL) | |
1968 | 1524 | { |
1969 | 1525 | log_error("inode %ld is not valid", ino); |
1970 | fuse_reply_err(req, EBADF); | |
1971 | return; | |
1972 | } | |
1973 | ||
1974 | xino = g_xrdp_fs.inode_table[ino]; | |
1975 | if (!xino) | |
1976 | { | |
1977 | log_debug("****** invalid ino=%ld", ino); | |
1978 | fuse_reply_err(req, EBADF); | |
1979 | return; | |
1980 | } | |
1526 | fuse_reply_err(req, ENOENT); | |
1527 | } | |
1528 | else | |
1529 | { | |
1530 | make_fuse_attr_reply(req, xino); | |
1531 | } | |
1532 | } | |
1533 | ||
1534 | /** | |
1535 | * | |
1536 | *****************************************************************************/ | |
1537 | ||
1538 | /* | |
1539 | * Adds an entry to the buffer, using fuse_add_direnty() | |
1540 | * | |
1541 | * Returns 1 for success, or zero if the entry couldn't be added | |
1542 | */ | |
1543 | static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, | |
1544 | XFS_INODE *xinode, off_t offset) | |
1545 | { | |
1546 | struct stat stbuf; | |
1547 | size_t len; | |
1548 | int result = 0; | |
1981 | 1549 | |
1982 | 1550 | memset(&stbuf, 0, sizeof(stbuf)); |
1983 | stbuf.st_ino = ino; | |
1984 | stbuf.st_mode = xino->mode; | |
1985 | stbuf.st_nlink = xino->nlink; | |
1986 | stbuf.st_size = xino->size; | |
1987 | fuse_reply_attr(req, &stbuf, 1.0); | |
1988 | } | |
1989 | ||
1990 | /** | |
1991 | * | |
1992 | *****************************************************************************/ | |
1993 | ||
1994 | #if 0 | |
1995 | static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, | |
1996 | const char *name, fuse_ino_t ino) | |
1997 | { | |
1998 | struct stat stbuf; | |
1999 | size_t oldsize = b->size; | |
2000 | ||
2001 | log_debug("adding ino=%ld name=%s", ino, name); | |
2002 | ||
2003 | b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0); | |
2004 | b->p = (char *) realloc(b->p, b->size); | |
2005 | ||
2006 | memset(&stbuf, 0, sizeof(stbuf)); | |
2007 | stbuf.st_ino = ino; | |
2008 | fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, | |
2009 | b->size); | |
2010 | } | |
2011 | #endif | |
2012 | ||
2013 | static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, | |
2014 | const char *name, fuse_ino_t ino) | |
2015 | { | |
2016 | struct stat stbuf; | |
2017 | int len; | |
2018 | ||
2019 | len = fuse_add_direntry(req, NULL, 0, name, NULL, 0); | |
2020 | if (b->bytes_in_buf + len > 4096) | |
2021 | { | |
2022 | log_debug("not adding entry because dirbuf overflow would occur"); | |
2023 | return -1; | |
2024 | } | |
2025 | ||
2026 | memset(&stbuf, 0, sizeof(stbuf)); | |
2027 | stbuf.st_ino = ino; | |
2028 | ||
2029 | fuse_add_direntry(req, | |
2030 | &b->buf[b->bytes_in_buf], /* index where new entry will be added to buf */ | |
2031 | 4096 - len, /* remaining size of buf */ | |
2032 | name, /* name of entry */ | |
1551 | stbuf.st_ino = xinode->inum; | |
1552 | stbuf.st_mode = xinode->mode & ~g_umask; | |
1553 | ||
1554 | /* | |
1555 | * Try to add the entry. From the docs for fuse_add_direntry():- | |
1556 | * "Buffer needs to be large enough to hold the entry. If it's not, | |
1557 | * then the entry is not filled in but the size of the entry is | |
1558 | * still returned." | |
1559 | */ | |
1560 | len = fuse_add_direntry(req, | |
1561 | &b->buf[b->len], /* index where new entry will be added to buf */ | |
1562 | sizeof(b->buf) - b->len, /* Space left */ | |
1563 | xinode->name, /* name of entry */ | |
2033 | 1564 | &stbuf, /* file attributes */ |
2034 | b->bytes_in_buf + len /* offset of next entry */ | |
1565 | offset /* offset of next entry */ | |
2035 | 1566 | ); |
2036 | ||
2037 | b->bytes_in_buf += len; | |
2038 | return 0; | |
2039 | } | |
2040 | ||
2041 | /** | |
2042 | * | |
1567 | if (len + b->len <= sizeof(b->buf)) | |
1568 | { | |
1569 | /* Entry fitted in OK */ | |
1570 | b->len += len; | |
1571 | result = 1; | |
1572 | } | |
1573 | ||
1574 | return result; | |
1575 | } | |
1576 | ||
1577 | /** | |
1578 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
1579 | * stack by the caller, so must be copied if we're not using it | |
1580 | * to reply to FUSE immediately | |
2043 | 1581 | *****************************************************************************/ |
2044 | 1582 | |
2045 | 1583 | static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, |
2046 | 1584 | off_t off, struct fuse_file_info *fi) |
2047 | 1585 | { |
2048 | XRDP_INODE *xinode; | |
2049 | XRDP_INODE *ti; | |
2050 | struct dir_info *di; | |
1586 | XFS_INODE *xinode; | |
1587 | struct xfs_dir_handle *dh; | |
2051 | 1588 | struct dirbuf1 b; |
2052 | fuse_ino_t i; | |
2053 | int first_time; | |
2054 | 1589 | |
2055 | 1590 | log_debug("req=%p inode=%ld size=%zd offset=%lld", req, ino, size, (long long) off); |
2056 | 1591 | |
2057 | /* do we have a valid inode? */ | |
2058 | if (!xfuse_is_inode_valid(ino)) | |
1592 | /* On the first call, check the inode is valid */ | |
1593 | if (off == 0 && !xfs_get(g_xfs, ino)) | |
2059 | 1594 | { |
2060 | 1595 | log_error("inode %ld is not valid", ino); |
2061 | fuse_reply_err(req, EBADF); | |
2062 | return; | |
2063 | } | |
2064 | ||
2065 | di = (struct dir_info *) (tintptr) (fi->fh); | |
2066 | if (di == NULL) | |
1596 | fuse_reply_err(req, ENOENT); | |
1597 | } | |
1598 | else if ((dh = (struct xfs_dir_handle *) fi->fh) == NULL) | |
2067 | 1599 | { |
2068 | 1600 | /* something seriously wrong somewhere! */ |
2069 | 1601 | fuse_reply_buf(req, 0, 0); |
2070 | return; | |
2071 | } | |
2072 | ||
2073 | b.bytes_in_buf = 0; | |
2074 | first_time = (di->index == FIRST_INODE) ? 1 : 0; | |
2075 | ||
2076 | for (i = di->index; i < g_xrdp_fs.num_entries; i++, di->index++) | |
2077 | { | |
2078 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
2079 | continue; | |
2080 | ||
2081 | /* match parent inode */ | |
2082 | if (xinode->parent_inode != ino) | |
2083 | continue; | |
2084 | ||
2085 | xinode->is_synced = 1; | |
2086 | ||
2087 | if (first_time) | |
2088 | { | |
2089 | first_time = 0; | |
2090 | ti = g_xrdp_fs.inode_table[ino]; | |
2091 | if (!ti) | |
1602 | } | |
1603 | else | |
1604 | { | |
1605 | b.len = 0; | |
1606 | ||
1607 | off_t new_off = off; | |
1608 | while ((xinode = xfs_readdir(g_xfs, dh, &new_off)) != NULL) | |
1609 | { | |
1610 | if (xfuse_dirbuf_add1(req, &b, xinode, new_off) == 0) | |
2092 | 1611 | { |
2093 | log_debug("****** g_xrdp_fs.inode_table[%ld] is NULL", ino); | |
2094 | fuse_reply_buf(req, NULL, 0); | |
2095 | return; | |
1612 | break; /* buffer is full */ | |
2096 | 1613 | } |
2097 | xfuse_dirbuf_add1(req, &b, ".", ino); | |
2098 | xfuse_dirbuf_add1(req, &b, "..", ti->parent_inode); | |
2099 | } | |
2100 | ||
2101 | if (xfuse_dirbuf_add1(req, &b, xinode->name, xinode->inode)) | |
2102 | break; /* buffer is full */ | |
2103 | } | |
2104 | ||
2105 | if (b.bytes_in_buf) | |
2106 | fuse_reply_buf(req, b.buf, b.bytes_in_buf); | |
2107 | else | |
2108 | fuse_reply_buf(req, NULL, 0); | |
2109 | } | |
1614 | /* Make sure we get the next entry next time */ | |
1615 | off = new_off; | |
1616 | } | |
1617 | ||
1618 | fuse_reply_buf(req, b.buf, b.len); | |
1619 | } | |
1620 | } | |
1621 | ||
2110 | 1622 | |
2111 | 1623 | /** |
2112 | 1624 | * Create a directory |
2115 | 1627 | static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, |
2116 | 1628 | const char *name, mode_t mode) |
2117 | 1629 | { |
2118 | XRDP_INODE *xinode; | |
2119 | struct fuse_entry_param e; | |
1630 | XFS_INODE *xinode; | |
2120 | 1631 | |
2121 | 1632 | log_debug("entered: parent_inode=%ld name=%s", parent, name); |
2122 | 1633 | |
2123 | if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL) | |
1634 | if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL) | |
2124 | 1635 | { |
2125 | 1636 | /* dir already exists, just return it */ |
2126 | memset(&e, 0, sizeof(struct fuse_entry_param)); | |
2127 | ||
2128 | e.ino = xinode->inode; | |
2129 | e.attr_timeout = XFUSE_ATTR_TIMEOUT; | |
2130 | e.entry_timeout = XFUSE_ENTRY_TIMEOUT; | |
2131 | e.attr.st_ino = xinode->inode; | |
2132 | e.attr.st_mode = xinode->mode; | |
2133 | e.attr.st_nlink = xinode->nlink; | |
2134 | e.attr.st_uid = xinode->uid; | |
2135 | e.attr.st_gid = xinode->gid; | |
2136 | e.attr.st_size = xinode->size; | |
2137 | e.attr.st_atime = xinode->atime; | |
2138 | e.attr.st_mtime = xinode->mtime; | |
2139 | e.attr.st_ctime = xinode->ctime; | |
2140 | e.generation = 1; | |
2141 | ||
2142 | fuse_reply_entry(req, &e); | |
2143 | return; | |
2144 | } | |
2145 | ||
2146 | /* dir does not exist, create it */ | |
2147 | xfuse_create_dir_or_file(req, parent, name, mode, NULL, S_IFDIR); | |
2148 | } | |
2149 | ||
2150 | /** | |
2151 | * Remove specified dir | |
2152 | *****************************************************************************/ | |
2153 | ||
2154 | static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, | |
2155 | const char *name) | |
2156 | { | |
2157 | xfuse_remove_dir_or_file(req, parent, name, 1); | |
2158 | } | |
1637 | make_fuse_entry_reply(req, xinode); | |
1638 | } | |
1639 | else | |
1640 | { | |
1641 | /* dir does not exist, create it */ | |
1642 | xfuse_create_dir_or_file(req, parent, name, mode | S_IFDIR, NULL); | |
1643 | } | |
1644 | } | |
1645 | ||
1646 | /** | |
1647 | * Remove a dir or file | |
1648 | * | |
1649 | *****************************************************************************/ | |
2159 | 1650 | |
2160 | 1651 | static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, |
2161 | 1652 | const char *name) |
2162 | 1653 | { |
2163 | xfuse_remove_dir_or_file(req, parent, name, 2); | |
2164 | } | |
2165 | ||
2166 | /** | |
2167 | * Remove a dir or file | |
2168 | * | |
2169 | * @param type 1=dir, 2=file | |
2170 | *****************************************************************************/ | |
2171 | ||
2172 | static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent, | |
2173 | const char *name, int type) | |
2174 | { | |
2175 | XFUSE_INFO *fip; | |
2176 | XRDP_INODE *xinode; | |
2177 | char *cptr; | |
2178 | char full_path[4096]; | |
2179 | tui32 device_id; | |
1654 | XFS_INODE *xinode; | |
2180 | 1655 | |
2181 | 1656 | log_debug("entered: parent=%ld name=%s", parent, name); |
2182 | 1657 | |
2183 | /* is parent inode valid? */ | |
2184 | if (!xfuse_is_inode_valid(parent)) | |
2185 | { | |
2186 | log_error("inode %ld is not valid", parent); | |
2187 | fuse_reply_err(req, EBADF); | |
2188 | return; | |
2189 | } | |
2190 | ||
2191 | if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) == NULL) | |
1658 | if (strlen(name) > XFS_MAXFILENAMELEN) | |
1659 | { | |
1660 | fuse_reply_err(req, ENAMETOOLONG); | |
1661 | } | |
1662 | else if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) == NULL) | |
2192 | 1663 | { |
2193 | 1664 | log_error("did not find file with pinode=%ld name=%s", parent, name); |
2194 | fuse_reply_err(req, EBADF); | |
2195 | return; | |
2196 | } | |
2197 | ||
2198 | device_id = xfuse_get_device_id_for_inode(parent, full_path); | |
2199 | ||
2200 | log_debug("path=%s nentries=%d", full_path, xinode->nentries); | |
2201 | ||
2202 | if ((type == 1) && (xinode->nentries != 0)) | |
2203 | { | |
2204 | log_debug("cannot rmdir; lookup count is %d", xinode->nentries); | |
1665 | fuse_reply_err(req, ENOENT); | |
1666 | } | |
1667 | ||
1668 | else if ((xinode->mode & S_IFDIR) != 0 && | |
1669 | !xfs_is_dir_empty(g_xfs, xinode->inum)) | |
1670 | { | |
1671 | log_debug("cannot rmdir; directory is not empty"); | |
2205 | 1672 | fuse_reply_err(req, ENOTEMPTY); |
2206 | return; | |
2207 | } | |
2208 | else if (type == 2) | |
2209 | { | |
2210 | if ((xinode->nopen > 1) || ((xinode->nopen == 1) && | |
2211 | (xinode->close_in_progress == 0))) | |
2212 | { | |
2213 | log_debug("cannot unlink; open count is %d", xinode->nopen); | |
2214 | fuse_reply_err(req, EBUSY); | |
2215 | return; | |
2216 | } | |
2217 | } | |
2218 | ||
2219 | strcat(full_path, "/"); | |
2220 | strncat(full_path, name, sizeof(full_path) - strlen(full_path) - 1); | |
2221 | ||
2222 | if (xinode->is_loc_resource) | |
1673 | } | |
1674 | ||
1675 | else if (xinode->device_id == 0) | |
2223 | 1676 | { |
2224 | 1677 | /* specified file is a local resource */ |
2225 | 1678 | //XFUSE_HANDLE *fh; |
2226 | 1679 | |
2227 | 1680 | log_debug("LK_TODO: this is still a TODO"); |
2228 | 1681 | fuse_reply_err(req, EINVAL); |
2229 | return; | |
2230 | } | |
2231 | ||
2232 | /* specified file resides on redirected share */ | |
2233 | ||
2234 | fip = g_new0(XFUSE_INFO, 1); | |
2235 | if (fip == NULL) | |
2236 | { | |
2237 | log_error("system out of memory"); | |
2238 | fuse_reply_err(req, ENOMEM); | |
2239 | return; | |
2240 | } | |
2241 | ||
2242 | fip->req = req; | |
2243 | fip->inode = parent; | |
2244 | fip->invoke_fuse = 1; | |
2245 | fip->device_id = device_id; | |
2246 | strncpy(fip->name, name, 1024); | |
2247 | fip->name[1023] = 0; | |
2248 | fip->type = type; | |
2249 | ||
2250 | /* we want path minus 'root node of the share' */ | |
2251 | if ((cptr = strchr(full_path, '/')) == NULL) | |
2252 | { | |
2253 | /* get dev_redir to open the remote file */ | |
2254 | if (devredir_rmdir_or_file((void *) fip, device_id, "\\", O_RDWR)) | |
2255 | { | |
2256 | log_error("failed to send dev_redir_open_file() cmd"); | |
2257 | fuse_reply_err(req, EREMOTEIO); | |
1682 | } | |
1683 | else | |
1684 | { | |
1685 | /* specified file resides on redirected share */ | |
1686 | struct state_remove *fip = g_new0(struct state_remove, 1); | |
1687 | char *full_path = xfs_get_full_path(g_xfs, xinode->inum); | |
1688 | if (!full_path || !fip) | |
1689 | { | |
1690 | log_error("system out of memory"); | |
1691 | fuse_reply_err(req, ENOMEM); | |
2258 | 1692 | free(fip); |
2259 | return; | |
2260 | } | |
2261 | } | |
2262 | else | |
2263 | { | |
2264 | if (devredir_rmdir_or_file((void *) fip, device_id, cptr, O_RDWR)) | |
2265 | { | |
2266 | log_error("failed to send dev_redir_get_dir_listing() cmd"); | |
2267 | fuse_reply_err(req, EREMOTEIO); | |
2268 | free(fip); | |
2269 | return; | |
2270 | } | |
1693 | free(full_path); | |
1694 | } | |
1695 | else | |
1696 | { | |
1697 | const char *cptr; | |
1698 | ||
1699 | fip->req = req; | |
1700 | fip->inum = xinode->inum; | |
1701 | ||
1702 | /* we want path minus 'root node of the share' */ | |
1703 | cptr = filename_on_device(full_path); | |
1704 | ||
1705 | /* get devredir to open the remote file | |
1706 | * | |
1707 | * If this call succeeds, further request processing happens in | |
1708 | * xfuse_devredir_cb_rmdir_or_file() | |
1709 | */ | |
1710 | if (devredir_rmdir_or_file(fip, xinode->device_id, cptr)) | |
1711 | { | |
1712 | log_error("failed to send devredir_rmdir_or_file() cmd"); | |
1713 | fuse_reply_err(req, EREMOTEIO); | |
1714 | free(fip); | |
1715 | } | |
1716 | ||
1717 | } | |
1718 | free(full_path); | |
2271 | 1719 | } |
2272 | 1720 | } |
2273 | 1721 | |
2275 | 1723 | fuse_ino_t old_parent, const char *old_name, |
2276 | 1724 | fuse_ino_t new_parent, const char *new_name) |
2277 | 1725 | { |
2278 | XRDP_INODE *old_xinode; | |
2279 | XFUSE_INFO *fip; | |
2280 | tui32 new_device_id; | |
2281 | char *cptr; | |
2282 | char old_full_path[1024]; | |
2283 | char new_full_path[1024]; | |
2284 | const char *cp; | |
2285 | ||
2286 | tui32 device_id; | |
1726 | XFS_INODE *old_xinode; | |
1727 | XFS_INODE *new_parent_xinode; | |
2287 | 1728 | |
2288 | 1729 | log_debug("entered: old_parent=%ld old_name=%s new_parent=%ld new_name=%s", |
2289 | 1730 | old_parent, old_name, new_parent, new_name); |
2290 | xfuse_dump_fs(); | |
2291 | ||
2292 | /* is old_parent inode valid? */ | |
2293 | if (!xfuse_is_inode_valid(old_parent)) | |
2294 | { | |
2295 | log_error("inode %ld is not valid", old_parent); | |
2296 | fuse_reply_err(req, EINVAL); | |
2297 | return; | |
2298 | } | |
2299 | ||
2300 | /* is new_parent inode valid? */ | |
2301 | if (!xfuse_is_inode_valid(new_parent)) | |
1731 | ||
1732 | if (strlen(old_name) > XFS_MAXFILENAMELEN || | |
1733 | strlen(new_name) > XFS_MAXFILENAMELEN) | |
1734 | { | |
1735 | fuse_reply_err(req, ENAMETOOLONG); | |
1736 | } | |
1737 | else if (!(old_xinode = xfs_lookup_in_dir(g_xfs, old_parent, old_name))) | |
1738 | { | |
1739 | log_error("did not find file with pinode=%ld name=%s", | |
1740 | old_parent, old_name); | |
1741 | fuse_reply_err(req, ENOENT); | |
1742 | } | |
1743 | ||
1744 | else if (!(new_parent_xinode = xfs_get(g_xfs, new_parent))) | |
2302 | 1745 | { |
2303 | 1746 | log_error("inode %ld is not valid", new_parent); |
2304 | 1747 | fuse_reply_err(req, EINVAL); |
2305 | return; | |
2306 | } | |
2307 | ||
2308 | if ((old_name == NULL) || (strlen(old_name) == 0)) | |
1748 | } | |
1749 | ||
1750 | else if (!xfs_check_move_entry(g_xfs, old_xinode->inum, | |
1751 | new_parent, new_name)) | |
2309 | 1752 | { |
2310 | 1753 | fuse_reply_err(req, EINVAL); |
2311 | return; | |
2312 | } | |
2313 | ||
2314 | if ((new_name == NULL) || (strlen(new_name) == 0)) | |
2315 | { | |
2316 | fuse_reply_err(req, EINVAL); | |
2317 | return; | |
2318 | } | |
2319 | ||
2320 | old_xinode = xfuse_get_inode_from_pinode_name(old_parent, old_name); | |
2321 | if (old_xinode == NULL) | |
2322 | { | |
2323 | log_error("did not find file with pinode=%ld name=%s", | |
2324 | old_parent, old_name); | |
2325 | fuse_reply_err(req, EBADF); | |
2326 | return; | |
2327 | } | |
2328 | ||
2329 | /* if file is open, cannot rename */ | |
2330 | if (old_xinode->nopen != 0) | |
2331 | { | |
2332 | fuse_reply_err(req, EBUSY); | |
2333 | return; | |
2334 | } | |
2335 | ||
2336 | /* rename across file systems not yet supported */ | |
2337 | new_device_id = xfuse_get_device_id_for_inode(new_parent, new_full_path); | |
2338 | strcat(new_full_path, "/"); | |
2339 | strcat(new_full_path, new_name); | |
2340 | ||
2341 | if (new_device_id != old_xinode->device_id) | |
1754 | } | |
1755 | ||
1756 | else if (new_parent_xinode->device_id != old_xinode->device_id) | |
2342 | 1757 | { |
2343 | 1758 | log_error("rename across file systems not supported"); |
2344 | 1759 | fuse_reply_err(req, EINVAL); |
2345 | return; | |
2346 | } | |
2347 | ||
2348 | if (old_xinode->is_loc_resource) | |
1760 | } | |
1761 | ||
1762 | else if (old_xinode->device_id == 0) | |
2349 | 1763 | { |
2350 | 1764 | /* specified file is a local resource */ |
2351 | 1765 | log_debug("LK_TODO: this is still a TODO"); |
2352 | 1766 | fuse_reply_err(req, EINVAL); |
2353 | return; | |
2354 | } | |
2355 | ||
2356 | /* resource is on a redirected share */ | |
2357 | ||
2358 | device_id = old_xinode->device_id; | |
2359 | ||
2360 | xfuse_get_device_id_for_inode(old_parent, old_full_path); | |
2361 | strcat(old_full_path, "/"); | |
2362 | strcat(old_full_path, old_name); | |
2363 | ||
2364 | fip = g_new0(XFUSE_INFO, 1); | |
2365 | if (fip == NULL) | |
2366 | { | |
2367 | log_error("system out of memory"); | |
2368 | fuse_reply_err(req, ENOMEM); | |
2369 | return; | |
2370 | } | |
2371 | ||
2372 | fip->req = req; | |
2373 | fip->inode = old_parent; | |
2374 | fip->new_inode = new_parent; | |
2375 | strncpy(fip->name, old_name, 1024); | |
2376 | strncpy(fip->new_name, new_name, 1024); | |
2377 | fip->name[1023] = 0; | |
2378 | fip->new_name[1023] = 0; | |
2379 | fip->invoke_fuse = 1; | |
2380 | fip->device_id = device_id; | |
2381 | ||
2382 | if ((cp = strchr(new_full_path, '/')) == NULL) | |
2383 | cp = "\\"; | |
2384 | ||
2385 | /* we want path minus 'root node of the share' */ | |
2386 | if ((cptr = strchr(old_full_path, '/')) == NULL) | |
2387 | { | |
2388 | /* get dev_redir to open the remote file */ | |
2389 | if (dev_redir_file_open((void *) fip, device_id, "\\", | |
2390 | O_RDWR, S_IFREG | OP_RENAME_FILE, cp)) | |
2391 | { | |
2392 | log_error("failed to send dev_redir_file_open() cmd"); | |
2393 | fuse_reply_err(req, EREMOTEIO); | |
1767 | } | |
1768 | ||
1769 | else | |
1770 | { | |
1771 | /* resource is on a redirected share */ | |
1772 | struct state_rename *fip = g_new0(struct state_rename, 1); | |
1773 | char *old_full_path = xfs_get_full_path(g_xfs, old_xinode->inum); | |
1774 | char *new_full_path = get_name_for_entry_in_parent(new_parent, | |
1775 | new_name); | |
1776 | ||
1777 | if (!old_full_path || !new_full_path || !fip) | |
1778 | { | |
1779 | log_error("system out of memory"); | |
1780 | fuse_reply_err(req, ENOMEM); | |
2394 | 1781 | free(fip); |
2395 | return; | |
2396 | } | |
2397 | } | |
2398 | else | |
2399 | { | |
2400 | if (dev_redir_file_open((void *) fip, device_id, cptr, | |
2401 | O_RDWR, S_IFREG | OP_RENAME_FILE, cp)) | |
2402 | { | |
2403 | log_error("failed to send dev_redir_file_open() cmd"); | |
2404 | fuse_reply_err(req, EREMOTEIO); | |
2405 | free(fip); | |
2406 | return; | |
1782 | free(old_full_path); | |
1783 | free(new_full_path); | |
1784 | } | |
1785 | else | |
1786 | { | |
1787 | const char *cptr; | |
1788 | const char *cp; | |
1789 | ||
1790 | fip->req = req; | |
1791 | fip->pinum = old_xinode->inum; | |
1792 | fip->new_pinum = new_parent; | |
1793 | strcpy(fip->name, new_name); | |
1794 | ||
1795 | /* we want path minus 'root node of the share' */ | |
1796 | cptr = filename_on_device(old_full_path); | |
1797 | cp = filename_on_device(new_full_path); | |
1798 | ||
1799 | /* | |
1800 | * If this call succeeds, further request processing happens in | |
1801 | * xfuse_devredir_cb_rename_file() | |
1802 | */ | |
1803 | if (devredir_file_rename(fip, old_xinode->device_id, cptr, cp)) | |
1804 | { | |
1805 | log_error("failed to send devredir_file_rename() cmd"); | |
1806 | fuse_reply_err(req, EREMOTEIO); | |
1807 | free(fip); | |
1808 | } | |
1809 | free(old_full_path); | |
1810 | free(new_full_path); | |
2407 | 1811 | } |
2408 | 1812 | } |
2409 | 1813 | } |
2415 | 1819 | * @param parent parent inode |
2416 | 1820 | * @param name name of dir or file to create |
2417 | 1821 | * @param mode creation mode |
2418 | * @param fi for storing file handles | |
2419 | * @param type S_IFDIR for dir and S_IFREG for file | |
1822 | * @param fi File info from fuse_lowlevel_ops.create, or NULL. | |
1823 | * This may need to be copied if we're not replying immediately | |
2420 | 1824 | *****************************************************************************/ |
2421 | 1825 | |
2422 | 1826 | static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, |
2423 | 1827 | const char *name, mode_t mode, |
2424 | struct fuse_file_info *fi, int type) | |
2425 | { | |
2426 | XFUSE_INFO *fip; | |
2427 | char *cptr; | |
2428 | char full_path[1024]; | |
2429 | tui32 device_id; | |
2430 | ||
2431 | full_path[0] = 0; | |
2432 | ||
2433 | log_debug("entered: parent_ino=%ld name=%s type=%s", | |
2434 | parent, name, (type == S_IFDIR) ? "dir" : "file"); | |
1828 | struct fuse_file_info *fi) | |
1829 | { | |
1830 | XFS_INODE *xinode; | |
1831 | ||
1832 | log_debug("entered: parent_ino=%ld name=%s mode=%o type=%s", | |
1833 | parent, name, mode, (mode & S_IFDIR) ? "dir" : "file"); | |
2435 | 1834 | |
2436 | 1835 | /* name must be valid */ |
2437 | if ((name == NULL) || (strlen(name) == 0)) | |
2438 | { | |
2439 | log_error("invalid name"); | |
2440 | fuse_reply_err(req, EBADF); | |
2441 | return; | |
2442 | } | |
2443 | ||
2444 | /* is parent inode valid? */ | |
2445 | if ((parent == 1) || (!xfuse_is_inode_valid(parent))) | |
2446 | { | |
2447 | log_error("inode %ld is not valid", parent); | |
2448 | fuse_reply_err(req, EBADF); | |
2449 | return; | |
2450 | } | |
2451 | ||
2452 | device_id = xfuse_get_device_id_for_inode(parent, full_path); | |
2453 | strcat(full_path, "/"); | |
2454 | strcat(full_path, name); | |
2455 | ||
2456 | XRDP_INODE *xinode = g_xrdp_fs.inode_table[parent]; | |
2457 | if (xinode->is_loc_resource) | |
2458 | { | |
2459 | /* specified file is a local resource */ | |
2460 | //XFUSE_HANDLE *fh; | |
2461 | ||
2462 | log_debug("LK_TODO: this is still a TODO"); | |
2463 | fuse_reply_err(req, EINVAL); | |
2464 | return; | |
2465 | } | |
2466 | ||
2467 | /* specified file resides on redirected share */ | |
2468 | ||
2469 | fip = g_new0(XFUSE_INFO, 1); | |
2470 | if (fip == NULL) | |
2471 | { | |
2472 | log_error("system out of memory"); | |
2473 | fuse_reply_err(req, ENOMEM); | |
2474 | return; | |
2475 | } | |
2476 | ||
2477 | fip->req = req; | |
2478 | fip->fi = fi; | |
2479 | fip->inode = parent; | |
2480 | fip->invoke_fuse = 1; | |
2481 | fip->device_id = device_id; | |
2482 | fip->mode = type; | |
2483 | fip->reply_type = RT_FUSE_REPLY_CREATE; | |
2484 | strncpy(fip->name, name, 1024); | |
2485 | fip->name[1023] = 0; | |
2486 | ||
2487 | log_debug("+++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p", fip, fip->fi); | |
2488 | ||
2489 | /* LK_TODO need to handle open permissions */ | |
2490 | ||
2491 | /* we want path minus 'root node of the share' */ | |
2492 | if ((cptr = strchr(full_path, '/')) == NULL) | |
2493 | { | |
2494 | /* get dev_redir to open the remote file */ | |
2495 | if (dev_redir_file_open((void *) fip, device_id, "\\", | |
2496 | O_CREAT, type, NULL)) | |
2497 | { | |
2498 | log_error("failed to send dev_redir_open_file() cmd"); | |
2499 | fuse_reply_err(req, EREMOTEIO); | |
2500 | } | |
1836 | if (strlen(name) > XFS_MAXFILENAMELEN) | |
1837 | { | |
1838 | fuse_reply_err(req, ENAMETOOLONG); | |
2501 | 1839 | } |
2502 | 1840 | else |
2503 | 1841 | { |
2504 | if (dev_redir_file_open((void *) fip, device_id, cptr, | |
2505 | O_CREAT, type, NULL)) | |
2506 | { | |
2507 | log_error("failed to send dev_redir_get_dir_listing() cmd"); | |
2508 | fuse_reply_err(req, EREMOTEIO); | |
2509 | } | |
1842 | /* Sanitise the mode | |
1843 | * | |
1844 | * Currently group/world write is not allowed. | |
1845 | */ | |
1846 | if (mode & S_IFDIR) | |
1847 | { | |
1848 | mode = (mode & 0777) | S_IFDIR; | |
1849 | } | |
1850 | else | |
1851 | { | |
1852 | mode = (mode & 0777) | S_IFREG; | |
1853 | } | |
1854 | ||
1855 | /* is parent inode valid? */ | |
1856 | if (parent == FUSE_ROOT_ID || | |
1857 | (xinode = xfs_get(g_xfs, parent)) == NULL || | |
1858 | (xinode->mode & S_IFDIR) == 0) | |
1859 | { | |
1860 | log_error("inode %ld is not valid", parent); | |
1861 | fuse_reply_err(req, ENOENT); | |
1862 | } | |
1863 | else if (xinode->device_id == 0) | |
1864 | { | |
1865 | /* specified file is a local resource */ | |
1866 | //XFUSE_HANDLE *fh; | |
1867 | ||
1868 | log_debug("LK_TODO: this is still a TODO"); | |
1869 | fuse_reply_err(req, EINVAL); | |
1870 | } | |
1871 | else | |
1872 | { | |
1873 | struct state_create *fip = g_new0(struct state_create, 1); | |
1874 | char *full_path = get_name_for_entry_in_parent(parent, name); | |
1875 | ||
1876 | if (full_path == NULL || fip == NULL) | |
1877 | { | |
1878 | log_error("Out of memory"); | |
1879 | fuse_reply_err(req, ENOMEM); | |
1880 | free(fip); | |
1881 | free(full_path); | |
1882 | } | |
1883 | else | |
1884 | { | |
1885 | const char *cptr; | |
1886 | ||
1887 | fip->req = req; | |
1888 | if (fi != NULL) | |
1889 | { | |
1890 | fip->fi = *fi; | |
1891 | } | |
1892 | fip->pinum = parent; | |
1893 | strcpy(fip->name, name); | |
1894 | fip->mode = mode; | |
1895 | ||
1896 | /* we want path minus 'root node of the share' */ | |
1897 | cptr = filename_on_device(full_path); | |
1898 | ||
1899 | /* | |
1900 | * If this call succeeds, further request processing happens | |
1901 | * in xfuse_devredir_cb_create_file() | |
1902 | */ | |
1903 | if (devredir_file_create(fip, xinode->device_id, cptr, mode)) | |
1904 | { | |
1905 | log_error("failed to send devredir_file_create() cmd"); | |
1906 | fuse_reply_err(req, EREMOTEIO); | |
1907 | free(fip); | |
1908 | } | |
1909 | free(full_path); | |
1910 | } | |
1911 | } | |
2510 | 1912 | } |
2511 | 1913 | } |
2512 | 1914 | |
2513 | 1915 | /** |
2514 | 1916 | * Open specified file |
1917 | * | |
1918 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
1919 | * stack by the caller, so must be copied if we're not using it | |
1920 | * to reply to FUSE immediately | |
2515 | 1921 | *****************************************************************************/ |
2516 | 1922 | |
2517 | 1923 | static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, |
2518 | 1924 | struct fuse_file_info *fi) |
2519 | 1925 | { |
2520 | XRDP_INODE *xinode; | |
2521 | XFUSE_INFO *fip; | |
2522 | char *cptr; | |
2523 | char full_path[4096]; | |
2524 | tui32 device_id; | |
1926 | XFS_INODE *xinode; | |
2525 | 1927 | |
2526 | 1928 | log_debug("entered: ino=%ld", ino); |
2527 | 1929 | |
2528 | if (!xfuse_is_inode_valid(ino)) | |
1930 | if (!(xinode = xfs_get(g_xfs, ino))) | |
2529 | 1931 | { |
2530 | 1932 | log_error("inode %ld is not valid", ino); |
2531 | fuse_reply_err(req, EBADF); | |
2532 | return; | |
2533 | } | |
2534 | ||
2535 | /* if ino points to a dir, fail the open request */ | |
2536 | xinode = g_xrdp_fs.inode_table[ino]; | |
2537 | if (!xinode) | |
2538 | { | |
2539 | log_debug("****** g_xrdp_fs.inode_table[%ld] is NULL", ino); | |
2540 | fuse_reply_err(req, EBADF); | |
2541 | return; | |
2542 | } | |
2543 | if (xinode->mode & S_IFDIR) | |
2544 | { | |
2545 | log_debug("reading a dir not allowed!"); | |
1933 | fuse_reply_err(req, ENOENT); | |
1934 | } | |
1935 | else if (xinode->mode & S_IFDIR) | |
1936 | { | |
1937 | /* Can't open directories like this */ | |
1938 | log_debug("reading/writing a dir not allowed!"); | |
2546 | 1939 | fuse_reply_err(req, EISDIR); |
2547 | return; | |
2548 | } | |
2549 | ||
2550 | device_id = xfuse_get_device_id_for_inode(ino, full_path); | |
2551 | ||
2552 | if (xinode->is_loc_resource) | |
1940 | } | |
1941 | else if ((fi->flags & O_ACCMODE) != O_RDONLY && | |
1942 | (fi->flags & O_ACCMODE) != O_WRONLY && | |
1943 | (fi->flags & O_ACCMODE) != O_RDWR) | |
1944 | { | |
1945 | log_debug("Invalid access mode specified"); | |
1946 | fuse_reply_err(req, EINVAL); | |
1947 | } | |
1948 | else if (xinode->device_id == 0) | |
2553 | 1949 | { |
2554 | 1950 | /* specified file is a local resource */ |
2555 | 1951 | XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1); |
2556 | 1952 | fh->is_loc_resource = 1; |
2557 | 1953 | fi->fh = (tintptr) fh; |
2558 | 1954 | fuse_reply_open(req, fi); |
2559 | return; | |
2560 | } | |
2561 | ||
2562 | /* specified file resides on redirected share */ | |
2563 | ||
2564 | fip = g_new0(XFUSE_INFO, 1); | |
2565 | if (fip == NULL) | |
2566 | { | |
2567 | log_error("system out of memory"); | |
2568 | fuse_reply_err(req, ENOMEM); | |
2569 | return; | |
2570 | } | |
2571 | ||
2572 | fip->req = req; | |
2573 | fip->inode = ino; | |
2574 | fip->invoke_fuse = 1; | |
2575 | fip->device_id = device_id; | |
2576 | fip->fi = fi; | |
2577 | ||
2578 | log_debug("LK_TODO: fip->fi = %p", fip->fi); | |
2579 | ||
2580 | strncpy(fip->name, full_path, 1024); | |
2581 | fip->name[1023] = 0; | |
2582 | fip->reply_type = RT_FUSE_REPLY_OPEN; | |
2583 | ||
2584 | /* we want path minus 'root node of the share' */ | |
2585 | if ((cptr = strchr(full_path, '/')) == NULL) | |
2586 | { | |
2587 | /* get dev_redir to open the remote file */ | |
2588 | if (dev_redir_file_open((void *) fip, device_id, "\\", | |
2589 | fi->flags, S_IFREG, NULL)) | |
2590 | { | |
2591 | log_error("failed to send dev_redir_open_file() cmd"); | |
2592 | fuse_reply_err(req, EREMOTEIO); | |
2593 | } | |
2594 | 1955 | } |
2595 | 1956 | else |
2596 | 1957 | { |
2597 | if (dev_redir_file_open((void *) fip, device_id, cptr, | |
2598 | fi->flags, S_IFREG, NULL)) | |
2599 | { | |
2600 | log_error("failed to send dev_redir_get_dir_listing() cmd"); | |
2601 | fuse_reply_err(req, EREMOTEIO); | |
2602 | } | |
2603 | } | |
2604 | } | |
2605 | ||
1958 | /* specified file resides on redirected share */ | |
1959 | struct state_open *fip = g_new0(struct state_open, 1); | |
1960 | char *full_path = xfs_get_full_path(g_xfs, ino); | |
1961 | ||
1962 | if (!full_path || !fip) | |
1963 | { | |
1964 | log_error("system out of memory"); | |
1965 | fuse_reply_err(req, ENOMEM); | |
1966 | free(fip); | |
1967 | free(full_path); | |
1968 | } | |
1969 | else | |
1970 | { | |
1971 | const char *cptr; | |
1972 | ||
1973 | fip->req = req; | |
1974 | fip->fi = *fi; | |
1975 | fip->inum = ino; | |
1976 | ||
1977 | /* we want path minus 'root node of the share' */ | |
1978 | cptr = filename_on_device(full_path); | |
1979 | ||
1980 | /* get devredir to open the remote file | |
1981 | * | |
1982 | * If the caller has set O_TRUNC when writing the file, | |
1983 | * fuse should call us back via fuse_cb_setattr() to set | |
1984 | * the size to zero - we don't need to do this ourselves. | |
1985 | * | |
1986 | * If this call succeeds, further request processing happens in | |
1987 | * xfuse_devredir_cb_open_file() | |
1988 | */ | |
1989 | if (devredir_file_open(fip, xinode->device_id, cptr, fi->flags)) | |
1990 | { | |
1991 | log_error("failed to send devredir_file_open() cmd"); | |
1992 | fuse_reply_err(req, EREMOTEIO); | |
1993 | free(fip); | |
1994 | } | |
1995 | free(full_path); | |
1996 | } | |
1997 | } | |
1998 | } | |
1999 | ||
2000 | /* | |
2001 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2002 | * stack by the caller, so must be copied if we're not using it | |
2003 | * to reply to FUSE immediately | |
2004 | */ | |
2606 | 2005 | static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct |
2607 | 2006 | fuse_file_info *fi) |
2608 | 2007 | { |
2609 | XFUSE_INFO *fip = NULL; | |
2008 | XFS_INODE *xinode; | |
2009 | ||
2610 | 2010 | XFUSE_HANDLE *handle = (XFUSE_HANDLE *) (tintptr) (fi->fh); |
2611 | 2011 | |
2612 | 2012 | log_debug("entered: ino=%ld fi=%p fi->fh=0x%llx", ino, fi, |
2613 | 2013 | (long long) fi->fh); |
2614 | 2014 | |
2615 | if (!xfuse_is_inode_valid(ino)) | |
2015 | if ((xinode = xfs_get(g_xfs, ino)) == NULL) | |
2616 | 2016 | { |
2617 | 2017 | log_error("inode %ld is not valid", ino); |
2618 | fuse_reply_err(req, EBADF); | |
2619 | return; | |
2620 | } | |
2621 | ||
2622 | XRDP_INODE *xinode = g_xrdp_fs.inode_table[ino]; | |
2623 | if (!xinode) | |
2624 | { | |
2625 | log_debug("****** g_xrdp_fs.inode_table[%ld] is NULL", ino); | |
2626 | fuse_reply_err(req, 0); | |
2627 | return; | |
2628 | } | |
2629 | if (xinode->is_loc_resource) | |
2018 | fuse_reply_err(req, ENOENT); | |
2019 | } | |
2020 | else if (xinode->device_id == 0) | |
2630 | 2021 | { |
2631 | 2022 | /* specified file is a local resource */ |
2632 | 2023 | fuse_reply_err(req, 0); |
2633 | return; | |
2634 | } | |
2635 | ||
2636 | /* specified file resides on redirected share */ | |
2637 | ||
2638 | log_debug("nopen=%d", xinode->nopen); | |
2639 | ||
2640 | /* if file is not opened, just return */ | |
2641 | if (xinode->nopen == 0) | |
2642 | { | |
2643 | log_debug("cannot close because file not opened"); | |
2644 | fuse_reply_err(req, 0); | |
2645 | return; | |
2646 | } | |
2647 | ||
2648 | fip = g_new0(XFUSE_INFO, 1); | |
2649 | if (fip == NULL) | |
2650 | { | |
2651 | log_error("system out of memory"); | |
2652 | fuse_reply_err(req, ENOMEM); | |
2653 | return; | |
2654 | } | |
2655 | ||
2656 | fip->req = req; | |
2657 | fip->inode = ino; | |
2658 | fip->invoke_fuse = 1; | |
2659 | fip->device_id = handle->DeviceId; | |
2660 | fip->fi = fi; | |
2661 | ||
2662 | log_debug(" +++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", | |
2663 | fip, fip->fi, (long long) fip->fi->fh); | |
2664 | ||
2665 | fip->fi->fh = 0; | |
2666 | xinode->close_in_progress = 1; | |
2667 | ||
2668 | if (devredir_file_close((void *) fip, fip->device_id, handle->FileId)) | |
2669 | { | |
2670 | log_error("failed to send devredir_close_file() cmd"); | |
2671 | fuse_reply_err(req, EREMOTEIO); | |
2672 | } | |
2673 | ||
2674 | free(handle); | |
2675 | } | |
2676 | ||
2677 | /** | |
2024 | } | |
2025 | else | |
2026 | { | |
2027 | /* specified file resides on redirected share */ | |
2028 | ||
2029 | struct state_close *fip = g_new0(struct state_close, 1); | |
2030 | if (fip == NULL) | |
2031 | { | |
2032 | log_error("system out of memory"); | |
2033 | fuse_reply_err(req, ENOMEM); | |
2034 | return; | |
2035 | } | |
2036 | ||
2037 | fip->req = req; | |
2038 | fip->inum = ino; | |
2039 | fip->fi = *fi; | |
2040 | ||
2041 | fi->fh = 0; | |
2042 | ||
2043 | /* | |
2044 | * If this call succeeds, further request processing happens in | |
2045 | * xfuse_devredir_cb_file_close() | |
2046 | */ | |
2047 | if (devredir_file_close(fip, xinode->device_id, handle->FileId)) | |
2048 | { | |
2049 | log_error("failed to send devredir_close_file() cmd"); | |
2050 | fuse_reply_err(req, EREMOTEIO); | |
2051 | free(fip); | |
2052 | } | |
2053 | ||
2054 | free(handle); | |
2055 | } | |
2056 | } | |
2057 | ||
2058 | /** | |
2059 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2060 | * stack by the caller, so must be copied if we're not using it | |
2061 | * to reply to FUSE immediately | |
2678 | 2062 | *****************************************************************************/ |
2679 | 2063 | |
2680 | 2064 | static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size, |
2681 | 2065 | off_t off, struct fuse_file_info *fi) |
2682 | 2066 | { |
2683 | 2067 | XFUSE_HANDLE *fh; |
2684 | XFUSE_INFO *fusep; | |
2685 | XRDP_INODE *xinode; | |
2068 | struct state_read *fusep; | |
2069 | XFS_INODE *xinode; | |
2686 | 2070 | struct req_list_item *rli; |
2687 | long handle; | |
2688 | 2071 | |
2689 | 2072 | log_debug("want_bytes %zd bytes at off %lld", size, (long long) off); |
2690 | 2073 | |
2691 | if (fi->fh == 0) | |
2074 | if ((fh = (XFUSE_HANDLE *)fi->fh) == NULL) | |
2692 | 2075 | { |
2693 | 2076 | fuse_reply_err(req, EINVAL); |
2694 | return; | |
2695 | } | |
2696 | ||
2697 | handle = fi->fh; | |
2698 | fh = (XFUSE_HANDLE *) handle; | |
2699 | ||
2700 | if (fh->is_loc_resource) | |
2077 | } | |
2078 | else if (fh->is_loc_resource) | |
2701 | 2079 | { |
2702 | 2080 | /* target file is in .clipboard dir */ |
2703 | 2081 | |
2704 | 2082 | log_debug("target file is in .clipboard dir"); |
2705 | 2083 | |
2706 | if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) | |
2084 | if ((xinode = xfs_get(g_xfs, ino)) == NULL) | |
2707 | 2085 | { |
2708 | 2086 | log_error("ino does not exist in xrdp_fs"); |
2709 | 2087 | fuse_reply_buf(req, 0, 0); |
2727 | 2105 | clipboard_request_file_data(rli->stream_id, rli->lindex, |
2728 | 2106 | (int) off, (int) size); |
2729 | 2107 | } |
2730 | ||
2731 | return; | |
2732 | } | |
2733 | ||
2734 | /* target file is on a remote device */ | |
2735 | ||
2736 | fusep = g_new0(XFUSE_INFO, 1); | |
2737 | if (fusep == NULL) | |
2738 | { | |
2739 | log_error("system out of memory"); | |
2740 | fuse_reply_err(req, ENOMEM); | |
2741 | return; | |
2742 | } | |
2743 | fusep->req = req; | |
2744 | fusep->inode = ino; | |
2745 | fusep->invoke_fuse = 1; | |
2746 | fusep->device_id = fh->DeviceId; | |
2747 | fusep->fi = fi; | |
2748 | ||
2749 | devredir_file_read(fusep, fh->DeviceId, fh->FileId, size, off); | |
2750 | } | |
2751 | ||
2752 | /** | |
2108 | } | |
2109 | else | |
2110 | { | |
2111 | /* target file is on a remote device */ | |
2112 | ||
2113 | fusep = g_new0(struct state_read, 1); | |
2114 | if (fusep == NULL) | |
2115 | { | |
2116 | log_error("system out of memory"); | |
2117 | fuse_reply_err(req, ENOMEM); | |
2118 | } | |
2119 | else | |
2120 | { | |
2121 | fusep->req = req; | |
2122 | ||
2123 | /* | |
2124 | * If this call succeeds, further request processing happens in | |
2125 | * xfuse_devredir_cb_read_file() | |
2126 | */ | |
2127 | devredir_file_read(fusep, fh->DeviceId, fh->FileId, size, off); | |
2128 | } | |
2129 | } | |
2130 | } | |
2131 | ||
2132 | /** | |
2133 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2134 | * stack by the caller, so must be copied if we're not using it | |
2135 | * to reply to FUSE immediately | |
2753 | 2136 | *****************************************************************************/ |
2754 | 2137 | |
2755 | 2138 | static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, |
2756 | 2139 | size_t size, off_t off, struct fuse_file_info *fi) |
2757 | 2140 | { |
2758 | 2141 | XFUSE_HANDLE *fh; |
2759 | XFUSE_INFO *fusep; | |
2760 | long handle; | |
2142 | struct state_write *fusep; | |
2761 | 2143 | |
2762 | 2144 | log_debug("write %zd bytes at off %lld to inode=%ld", |
2763 | 2145 | size, (long long) off, ino); |
2764 | 2146 | |
2765 | if (fi->fh == 0) | |
2147 | if ((fh = (XFUSE_HANDLE *)fi->fh) == NULL) | |
2766 | 2148 | { |
2767 | 2149 | log_error("file handle fi->fh is NULL"); |
2768 | 2150 | fuse_reply_err(req, EINVAL); |
2769 | return; | |
2770 | } | |
2771 | ||
2772 | handle = fi->fh; | |
2773 | fh = (XFUSE_HANDLE *) handle; | |
2774 | ||
2775 | if (fh->is_loc_resource) | |
2151 | } | |
2152 | else if (fh->is_loc_resource) | |
2776 | 2153 | { |
2777 | 2154 | /* target file is in .clipboard dir */ |
2778 | 2155 | log_debug("THIS IS STILL A TODO!"); |
2779 | return; | |
2780 | } | |
2781 | ||
2782 | /* target file is on a remote device */ | |
2783 | ||
2784 | fusep = g_new0(XFUSE_INFO, 1); | |
2785 | if (fusep == NULL) | |
2786 | { | |
2787 | log_error("system out of memory"); | |
2788 | fuse_reply_err(req, ENOMEM); | |
2789 | return; | |
2790 | } | |
2791 | ||
2792 | fusep->req = req; | |
2793 | fusep->inode = ino; | |
2794 | fusep->invoke_fuse = 1; | |
2795 | fusep->device_id = fh->DeviceId; | |
2796 | fusep->fi = fi; | |
2797 | ||
2798 | log_debug("+++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", | |
2799 | fusep, fusep->fi, (long long) fusep->fi->fh); | |
2800 | ||
2801 | dev_redir_file_write(fusep, fh->DeviceId, fh->FileId, buf, size, off); | |
2802 | log_debug("exiting"); | |
2803 | } | |
2804 | ||
2805 | /** | |
2806 | *****************************************************************************/ | |
2807 | ||
2156 | fuse_reply_err(req, EINVAL); | |
2157 | } | |
2158 | else | |
2159 | { | |
2160 | /* target file is on a remote device */ | |
2161 | ||
2162 | fusep = g_new0(struct state_write, 1); | |
2163 | if (fusep == NULL) | |
2164 | { | |
2165 | log_error("system out of memory"); | |
2166 | fuse_reply_err(req, ENOMEM); | |
2167 | } | |
2168 | else | |
2169 | { | |
2170 | fusep->req = req; | |
2171 | fusep->inum = ino; | |
2172 | ||
2173 | /* | |
2174 | * If this call succeeds, further request processing happens in | |
2175 | * xfuse_devredir_cb_write_file() | |
2176 | */ | |
2177 | devredir_file_write(fusep, fh->DeviceId, fh->FileId, buf, | |
2178 | size, off); | |
2179 | } | |
2180 | } | |
2181 | } | |
2182 | ||
2183 | /** | |
2184 | *****************************************************************************/ | |
2185 | ||
2186 | /* | |
2187 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2188 | * stack by the caller, so must be copied if we're not using it | |
2189 | * to reply to FUSE immediately | |
2190 | */ | |
2808 | 2191 | static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, |
2809 | 2192 | const char *name, mode_t mode, |
2810 | 2193 | struct fuse_file_info *fi) |
2812 | 2195 | log_debug("entered: parent_inode=%ld, name=%s fi=%p", |
2813 | 2196 | parent, name, fi); |
2814 | 2197 | |
2815 | xfuse_create_dir_or_file(req, parent, name, mode, fi, S_IFREG); | |
2198 | xfuse_create_dir_or_file(req, parent, name, mode & ~S_IFDIR , fi); | |
2816 | 2199 | } |
2817 | 2200 | |
2818 | 2201 | /** |
2829 | 2212 | #endif |
2830 | 2213 | |
2831 | 2214 | /** |
2215 | * Sets attributes for a directory entry. | |
2216 | * | |
2217 | * If the file resides on a remote share, devredir | |
2218 | * is asked to update it. This will result in the following | |
2219 | * callbacks:- | |
2220 | * - xfuse_devredir_cb_setattr() to update our copy and return status | |
2221 | * | |
2222 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2223 | * stack by the caller, so must be copied if we're not using it | |
2224 | * to reply to FUSE immediately | |
2832 | 2225 | *****************************************************************************/ |
2833 | 2226 | |
2834 | 2227 | static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, |
2835 | 2228 | int to_set, struct fuse_file_info *fi) |
2836 | 2229 | { |
2837 | XRDP_INODE *xinode; | |
2838 | struct stat st; | |
2230 | XFS_INODE *xinode; | |
2839 | 2231 | |
2840 | 2232 | log_debug("entered to_set=0x%x", to_set); |
2841 | 2233 | |
2842 | if (!xfuse_is_inode_valid(ino)) | |
2234 | if ((xinode = xfs_get(g_xfs, ino)) == NULL) | |
2843 | 2235 | { |
2844 | 2236 | log_error("inode %ld is not valid", ino); |
2845 | fuse_reply_err(req, EBADF); | |
2846 | return; | |
2847 | } | |
2848 | ||
2849 | if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) | |
2850 | { | |
2851 | log_debug("g_xrdp_fs.inode_table[%ld] is NULL", ino); | |
2852 | fuse_reply_err(req, EBADF); | |
2853 | return; | |
2854 | } | |
2855 | ||
2856 | if (to_set & FUSE_SET_ATTR_MODE) | |
2857 | { | |
2858 | xinode->mode = attr->st_mode; | |
2859 | log_debug("FUSE_SET_ATTR_MODE"); | |
2860 | ||
2861 | } | |
2862 | ||
2863 | if (to_set & FUSE_SET_ATTR_UID) | |
2864 | { | |
2865 | xinode->uid = attr->st_uid; | |
2866 | log_debug("FUSE_SET_ATTR_UID"); | |
2867 | } | |
2868 | ||
2869 | if (to_set & FUSE_SET_ATTR_GID) | |
2870 | { | |
2871 | xinode->gid = attr->st_gid; | |
2872 | log_debug("FUSE_SET_ATTR_GID"); | |
2873 | } | |
2874 | ||
2875 | if (to_set & FUSE_SET_ATTR_SIZE) | |
2876 | { | |
2877 | log_debug("previous file size: %lld", (long long) attr->st_size); | |
2878 | xinode->size = attr->st_size; | |
2879 | log_debug("returning file size: %zd", xinode->size); | |
2880 | } | |
2881 | ||
2882 | if (to_set & FUSE_SET_ATTR_ATIME) | |
2883 | { | |
2884 | xinode->atime = attr->st_atime; | |
2885 | log_debug("FUSE_SET_ATTR_ATIME"); | |
2886 | } | |
2887 | ||
2888 | if (to_set & FUSE_SET_ATTR_MTIME) | |
2889 | { | |
2890 | xinode->mtime = attr->st_mtime; | |
2891 | log_debug("FUSE_SET_ATTR_MTIME"); | |
2892 | } | |
2893 | ||
2894 | if (to_set & FUSE_SET_ATTR_ATIME_NOW) | |
2895 | { | |
2896 | xinode->atime = attr->st_atime; | |
2897 | log_debug("FUSE_SET_ATTR_ATIME_NOW"); | |
2898 | } | |
2899 | ||
2900 | if (to_set & FUSE_SET_ATTR_MTIME_NOW) | |
2901 | { | |
2902 | xinode->mtime = attr->st_mtime; | |
2903 | log_debug("FUSE_SET_ATTR_MTIME_NOW"); | |
2904 | } | |
2237 | fuse_reply_err(req, ENOENT); | |
2238 | } | |
2239 | else if (((to_set & FUSE_SET_ATTR_UID) && attr->st_uid != xinode->uid) || | |
2240 | ((to_set & FUSE_SET_ATTR_GID) && attr->st_gid != xinode->gid)) | |
2241 | { | |
2242 | /* We don't allow any of these */ | |
2243 | fuse_reply_err(req, EPERM); | |
2244 | } | |
2245 | else if ((to_set & FUSE_SET_ATTR_MODE) && | |
2246 | (attr->st_mode & ~(0777 | S_IFDIR | S_IFREG)) != 0) | |
2247 | { | |
2248 | /* We only support standard mode bits and S_IFDIR / S_IFREG */ | |
2249 | log_error("Asking for invalid mode bits 0%o to be set", attr->st_mode); | |
2250 | fuse_reply_err(req, EINVAL); | |
2251 | } | |
2252 | else | |
2253 | { | |
2254 | struct file_attr attrs = {0}; | |
2255 | tui32 change_mask = 0; | |
2256 | ||
2257 | if ((to_set & FUSE_SET_ATTR_MODE) && xinode->mode != attr->st_mode) | |
2258 | { | |
2259 | attrs.mode = attr->st_mode & (0777 | S_IFDIR | S_IFREG); | |
2260 | change_mask |= TO_SET_MODE; | |
2261 | } | |
2262 | ||
2263 | if ((to_set & FUSE_SET_ATTR_SIZE) && xinode->size != attr->st_size) | |
2264 | { | |
2265 | attrs.size = attr->st_size; | |
2266 | change_mask |= TO_SET_SIZE; | |
2267 | } | |
2268 | ||
2269 | if ((to_set & FUSE_SET_ATTR_ATIME) && xinode->atime != attr->st_atime) | |
2270 | { | |
2271 | attrs.atime = attr->st_atime; | |
2272 | change_mask |= TO_SET_ATIME; | |
2273 | } | |
2274 | ||
2275 | if ((to_set & FUSE_SET_ATTR_MTIME) && xinode->mtime != attr->st_mtime) | |
2276 | { | |
2277 | attrs.mtime = attr->st_mtime; | |
2278 | change_mask |= TO_SET_MTIME; | |
2279 | } | |
2280 | ||
2281 | if (change_mask == 0) | |
2282 | { | |
2283 | /* No changes have been made */ | |
2284 | make_fuse_attr_reply(req, xinode); | |
2285 | } | |
2286 | else if (xinode->device_id == 0) | |
2287 | { | |
2288 | /* Update the local fs */ | |
2289 | update_inode_file_attributes(&attrs, change_mask, xinode); | |
2290 | make_fuse_attr_reply(req, xinode); | |
2291 | } | |
2292 | else | |
2293 | { | |
2294 | struct state_setattr *fip = g_new0(struct state_setattr, 1); | |
2295 | char *full_path = xfs_get_full_path(g_xfs, ino); | |
2296 | if (!full_path || !fip) | |
2297 | { | |
2298 | log_error("system out of memory"); | |
2299 | fuse_reply_err(req, ENOMEM); | |
2300 | free(fip); | |
2301 | free(full_path); | |
2302 | } | |
2303 | else | |
2304 | { | |
2305 | const char *cptr; | |
2306 | fip->req = req; | |
2307 | fip->inum = ino; | |
2308 | /* Save the important stuff so we can update our node if the | |
2309 | * remote update is successful */ | |
2310 | fip->fattr = attrs; | |
2311 | fip->change_mask = change_mask; | |
2312 | ||
2313 | /* we want path minus 'root node of the share' */ | |
2314 | cptr = filename_on_device(full_path); | |
2315 | ||
2316 | /* | |
2317 | * If this call succeeds, further request processing happens | |
2318 | * in xfuse_devredir_cb_setattr() | |
2319 | */ | |
2320 | if (devredir_setattr_for_entry(fip, xinode->device_id, | |
2321 | cptr, &attrs, change_mask) < 0) | |
2322 | { | |
2323 | fuse_reply_err(req, EIO); | |
2324 | free(fip); | |
2325 | } | |
2326 | ||
2327 | free(full_path); | |
2328 | } | |
2329 | } | |
2330 | } | |
2331 | } | |
2332 | ||
2333 | /** | |
2334 | * Get dir listing | |
2335 | * | |
2336 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2337 | * stack by the caller, so must be copied if we're not using it | |
2338 | * to reply to FUSE immediately | |
2339 | *****************************************************************************/ | |
2340 | static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, | |
2341 | struct fuse_file_info *fi) | |
2342 | { | |
2343 | XFS_INODE *xinode; | |
2344 | ||
2345 | log_debug("inode=%ld", ino); | |
2346 | ||
2347 | if ((xinode = xfs_get(g_xfs, ino)) == NULL) | |
2348 | { | |
2349 | log_error("inode %ld is not valid", ino); | |
2350 | fuse_reply_err(req, ENOENT); | |
2351 | } | |
2352 | else if (xinode->device_id == 0) | |
2353 | { | |
2354 | if ((fi->fh = (tintptr) xfs_opendir(g_xfs, ino)) == 0) | |
2355 | { | |
2356 | fuse_reply_err(req, ENOMEM); | |
2357 | } | |
2358 | else | |
2359 | { | |
2360 | fuse_reply_open(req, fi); | |
2361 | } | |
2362 | } | |
2363 | else | |
2364 | { | |
2365 | log_debug("did not find entry; redirecting call to devredir"); | |
2366 | struct state_dirscan *fip = g_new0(struct state_dirscan, 1); | |
2367 | char *full_path = xfs_get_full_path(g_xfs, ino); | |
2368 | ||
2369 | if (full_path == NULL || fip == NULL) | |
2370 | { | |
2371 | fuse_reply_err(req, ENOMEM); | |
2372 | free(fip); | |
2373 | free(full_path); | |
2374 | } | |
2375 | else | |
2376 | { | |
2377 | const char *cptr; | |
2378 | log_debug("dev_id=%d ino=%ld full_path=%s", | |
2379 | xinode->device_id, ino, full_path); | |
2380 | ||
2381 | fip->req = req; | |
2382 | fip->pinum = ino; | |
2383 | fip->fi = *fi; | |
2384 | ||
2385 | /* we want path minus 'root node of the share' */ | |
2386 | cptr = filename_on_device(full_path); | |
2387 | ||
2388 | /* | |
2389 | * If this call succeeds, further request processing happens in:- | |
2390 | * - xfuse_devredir_cb_enum_dir_add_entry() | |
2391 | * Called for every file in the directory | |
2392 | * - xfuse_devredir_cb_enum_dir_done() | |
2393 | * Called at the end of the directory scan | |
2394 | */ | |
2395 | if (devredir_get_dir_listing(fip, xinode->device_id, cptr)) | |
2396 | { | |
2397 | log_error("failed to send devredir_get_dir_listing() cmd"); | |
2398 | fuse_reply_buf(req, NULL, 0); | |
2399 | free(fip); | |
2400 | } | |
2401 | free(full_path); | |
2402 | } | |
2403 | } | |
2404 | } | |
2405 | ||
2406 | /** | |
2407 | * GOTCHA : For FUSE 2.9 at least, the 'fi' parameter is allocated on the | |
2408 | * stack by the caller, so must be copied if we're not using it | |
2409 | * to reply to FUSE immediately | |
2410 | *****************************************************************************/ | |
2411 | ||
2412 | static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, | |
2413 | struct fuse_file_info *fi) | |
2414 | { | |
2415 | struct xfs_dir_handle *dh = (struct xfs_dir_handle *) fi->fh; | |
2416 | xfs_closedir(g_xfs, dh); | |
2417 | fuse_reply_err(req, 0); | |
2418 | } | |
2419 | ||
2420 | /****************************************************************************** | |
2421 | * miscellaneous functions | |
2422 | *****************************************************************************/ | |
2423 | ||
2424 | static void xfs_inode_to_fuse_entry_param(const XFS_INODE *xinode, | |
2425 | struct fuse_entry_param *e) | |
2426 | { | |
2427 | memset(e, 0, sizeof(*e)); | |
2428 | e->ino = xinode->inum; | |
2429 | e->attr_timeout = XFUSE_ATTR_TIMEOUT; | |
2430 | e->entry_timeout = XFUSE_ENTRY_TIMEOUT; | |
2431 | e->attr.st_ino = xinode->inum; | |
2432 | e->attr.st_mode = xinode->mode & ~g_umask; | |
2433 | e->attr.st_nlink = 1; | |
2434 | e->attr.st_uid = xinode->uid; | |
2435 | e->attr.st_gid = xinode->gid; | |
2436 | e->attr.st_size = xinode->size; | |
2437 | e->attr.st_atime = xinode->atime; | |
2438 | e->attr.st_mtime = xinode->mtime; | |
2439 | e->attr.st_ctime = xinode->ctime; | |
2440 | e->generation = xinode->generation; | |
2441 | } | |
2442 | ||
2443 | static void make_fuse_entry_reply(fuse_req_t req, const XFS_INODE *xinode) | |
2444 | { | |
2445 | struct fuse_entry_param e; | |
2446 | xfs_inode_to_fuse_entry_param(xinode, &e); | |
2447 | fuse_reply_entry(req, &e); | |
2448 | } | |
2449 | ||
2450 | static void make_fuse_attr_reply(fuse_req_t req, const XFS_INODE *xinode) | |
2451 | { | |
2452 | struct stat st; | |
2905 | 2453 | |
2906 | 2454 | memset(&st, 0, sizeof(st)); |
2907 | st.st_ino = xinode->inode; | |
2908 | st.st_mode = xinode->mode; | |
2909 | st.st_size = xinode->size; | |
2910 | st.st_uid = xinode->uid; | |
2911 | st.st_gid = xinode->gid; | |
2455 | st.st_ino = xinode->inum; | |
2456 | st.st_mode = xinode->mode & ~g_umask; | |
2457 | st.st_nlink = 1; | |
2458 | st.st_uid = xinode->uid; | |
2459 | st.st_gid = xinode->gid; | |
2460 | st.st_size = xinode->size; | |
2912 | 2461 | st.st_atime = xinode->atime; |
2913 | 2462 | st.st_mtime = xinode->mtime; |
2914 | 2463 | st.st_ctime = xinode->ctime; |
2915 | 2464 | |
2916 | fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */ | |
2917 | } | |
2918 | ||
2919 | /** | |
2920 | * Get dir listing | |
2921 | *****************************************************************************/ | |
2922 | static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, | |
2923 | struct fuse_file_info *fi) | |
2924 | { | |
2925 | struct opendir_req *odreq; | |
2926 | ||
2927 | /* save request */ | |
2928 | odreq = g_new(struct opendir_req, 1); | |
2929 | odreq->req = req; | |
2930 | odreq->ino = ino; | |
2931 | odreq->fi = fi; | |
2932 | ||
2933 | if (fifo_is_empty(&g_fifo_opendir)) | |
2934 | { | |
2935 | fifo_insert(&g_fifo_opendir, odreq); | |
2936 | xfuse_proc_opendir_req(req, ino, fi); | |
2937 | } | |
2938 | else | |
2939 | { | |
2940 | /* place req in FIFO; xfuse_devredir_cb_enum_dir_done() will handle it */ | |
2941 | fifo_insert(&g_fifo_opendir, odreq); | |
2942 | } | |
2943 | } | |
2944 | ||
2945 | /** | |
2946 | * Process the next opendir req | |
2947 | * | |
2948 | * @return 0 of the request was sent for remote lookup, -1 otherwise | |
2949 | *****************************************************************************/ | |
2950 | static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, | |
2951 | struct fuse_file_info *fi) | |
2952 | { | |
2953 | struct dir_info *di; | |
2954 | XRDP_INODE *xinode; | |
2955 | XFUSE_INFO *fip; | |
2956 | tui32 device_id; | |
2957 | char full_path[4096]; | |
2958 | char *cptr; | |
2959 | ||
2960 | log_debug("inode=%ld", ino); | |
2961 | ||
2962 | if (!xfuse_is_inode_valid(ino)) | |
2963 | { | |
2964 | log_error("inode %ld is not valid", ino); | |
2965 | fuse_reply_err(req, EBADF); | |
2966 | g_free(fifo_remove(&g_fifo_opendir)); | |
2967 | return -1; | |
2968 | } | |
2969 | ||
2970 | if (ino == 1) | |
2971 | goto done; /* special case; enumerate top level dir */ | |
2972 | ||
2973 | if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) | |
2974 | { | |
2975 | log_debug("g_xrdp_fs.inode_table[%ld] is NULL", ino); | |
2976 | fuse_reply_err(req, EBADF); | |
2977 | g_free(fifo_remove(&g_fifo_opendir)); | |
2978 | return -1; | |
2979 | } | |
2980 | ||
2981 | if (xinode->is_loc_resource) | |
2982 | goto done; | |
2983 | ||
2984 | /* enumerate resources on a remote device */ | |
2985 | ||
2986 | #ifdef USE_SYNC_FLAG | |
2987 | if (xinode->is_synced) | |
2988 | { | |
2989 | xfuse_enum_dir(req, ino, size, off, fi); | |
2990 | g_free(fifo_remove(&g_fifo_opendir)); | |
2991 | return -1; | |
2992 | } | |
2993 | else | |
2994 | { | |
2995 | goto do_remote_lookup; | |
2996 | } | |
2997 | ||
2998 | do_remote_lookup: | |
2999 | #endif | |
3000 | ||
3001 | xfuse_mark_as_stale(ino); | |
3002 | ||
3003 | log_debug("did not find entry; redirecting call to dev_redir"); | |
3004 | device_id = xfuse_get_device_id_for_inode(ino, full_path); | |
3005 | ||
3006 | log_debug("dev_id=%d ino=%ld full_path=%s", device_id, ino, full_path); | |
3007 | ||
3008 | fip = g_new0(XFUSE_INFO, 1); | |
3009 | if (fip == NULL) | |
3010 | { | |
3011 | log_error("system out of memory"); | |
3012 | fuse_reply_err(req, ENOMEM); | |
3013 | g_free(fifo_remove(&g_fifo_opendir)); | |
3014 | return -1; | |
3015 | } | |
3016 | ||
3017 | fip->req = req; | |
3018 | fip->inode = ino; | |
3019 | fip->size = 0; | |
3020 | fip->off = 0; | |
3021 | fip->fi = fi; | |
3022 | fip->dirbuf1.first_time = 1; | |
3023 | fip->dirbuf1.bytes_in_buf = 0; | |
3024 | ||
3025 | fip->invoke_fuse = 1; | |
3026 | fip->device_id = device_id; | |
3027 | ||
3028 | /* we want path minus 'root node of the share' */ | |
3029 | if ((cptr = strchr(full_path, '/')) == NULL) | |
3030 | { | |
3031 | /* enumerate root dir */ | |
3032 | if (dev_redir_get_dir_listing((void *) fip, device_id, "\\")) | |
3033 | { | |
3034 | log_error("failed to send dev_redir_get_dir_listing() cmd"); | |
3035 | fuse_reply_buf(req, NULL, 0); | |
3036 | } | |
3037 | } | |
3038 | else | |
3039 | { | |
3040 | if (dev_redir_get_dir_listing((void *) fip, device_id, cptr)) | |
3041 | { | |
3042 | log_error("failed to send dev_redir_get_dir_listing() cmd"); | |
3043 | fuse_reply_buf(req, NULL, 0); | |
3044 | } | |
3045 | } | |
3046 | ||
3047 | return 0; | |
3048 | ||
3049 | done: | |
3050 | ||
3051 | di = g_new0(struct dir_info, 1); | |
3052 | di->index = FIRST_INODE; | |
3053 | fi->fh = (tintptr) di; | |
3054 | fuse_reply_open(req, fi); | |
3055 | g_free(fifo_remove(&g_fifo_opendir)); | |
3056 | return -1; | |
3057 | } | |
3058 | ||
3059 | /** | |
3060 | *****************************************************************************/ | |
3061 | ||
3062 | static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, | |
3063 | struct fuse_file_info *fi) | |
3064 | { | |
3065 | struct dir_info *di; | |
3066 | ||
3067 | di = (struct dir_info *) (tintptr) fi->fh; | |
3068 | if (di) | |
3069 | free(di); | |
3070 | ||
3071 | fuse_reply_err(req, 0); | |
3072 | } | |
3073 | ||
3074 | /****************************************************************************** | |
3075 | * miscellaneous functions | |
3076 | *****************************************************************************/ | |
3077 | ||
3078 | /** | |
3079 | * Mark all files with matching parent inode as stale | |
3080 | * | |
3081 | * @param pinode the parent inode | |
3082 | *****************************************************************************/ | |
3083 | ||
3084 | static void | |
3085 | xfuse_mark_as_stale(fuse_ino_t pinode) | |
3086 | { | |
3087 | fuse_ino_t i; | |
3088 | XRDP_INODE *xinode; | |
3089 | ||
3090 | if ((pinode < FIRST_INODE) || (pinode >= g_xrdp_fs.num_entries)) | |
3091 | return; | |
3092 | ||
3093 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
3094 | { | |
3095 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
3096 | continue; | |
3097 | ||
3098 | /* match parent inode */ | |
3099 | if (xinode->parent_inode != pinode) | |
3100 | continue; | |
3101 | ||
3102 | /* got a match */ | |
3103 | xinode->stale = 1; | |
3104 | } | |
3105 | } | |
3106 | ||
3107 | /** | |
3108 | * Delete all files with matching parent inode that are marked as stale | |
3109 | * | |
3110 | * @param pinode the parent inode | |
3111 | *****************************************************************************/ | |
3112 | ||
3113 | static void | |
3114 | xfuse_delete_stale_entries(fuse_ino_t pinode) | |
3115 | { | |
3116 | fuse_ino_t i; | |
3117 | XRDP_INODE *xinode; | |
3118 | ||
3119 | if ((pinode < FIRST_INODE) || (pinode >= g_xrdp_fs.num_entries)) | |
3120 | return; | |
3121 | ||
3122 | for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) | |
3123 | { | |
3124 | if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) | |
3125 | continue; | |
3126 | ||
3127 | /* match parent inode */ | |
3128 | if (xinode->parent_inode != pinode) | |
3129 | continue; | |
3130 | ||
3131 | /* got a match, but is it stale? */ | |
3132 | if (!xinode->stale) | |
3133 | continue; | |
3134 | ||
3135 | /* ok to delete */ | |
3136 | if (xinode->mode & S_IFREG) | |
3137 | xfuse_delete_file_with_xinode(xinode); | |
2465 | fuse_reply_attr(req, &st, XFUSE_ATTR_TIMEOUT); | |
2466 | } | |
2467 | ||
2468 | /* | |
2469 | * Get the name of a file on the device | |
2470 | * | |
2471 | * For redirected devices, the routine xfs_get_full_path() returns names | |
2472 | * like "/C:/Windows/System32". | |
2473 | * This routine simply returns a pointer to the part of the name following | |
2474 | * the device specification. | |
2475 | */ | |
2476 | static const char *filename_on_device(const char *full_path) | |
2477 | { | |
2478 | const char *result = NULL; | |
2479 | if (full_path[0] != '\0') | |
2480 | { | |
2481 | result = strchr(full_path + 1, '/'); | |
2482 | } | |
2483 | return result ? result : "/"; | |
2484 | } | |
2485 | ||
2486 | /* | |
2487 | * Updates attributes on the filesystem, and bumps the inode ctime | |
2488 | * | |
2489 | * This call is used to set attributes, either locally, or following a | |
2490 | * setattr devredir call | |
2491 | */ | |
2492 | static void update_inode_file_attributes(const struct file_attr *fattr, | |
2493 | tui32 change_mask, XFS_INODE *xinode) | |
2494 | { | |
2495 | int updated = 0; | |
2496 | ||
2497 | if ((change_mask & TO_SET_MODE) != 0 && xinode->mode != fattr->mode) | |
2498 | { | |
2499 | xinode->mode = fattr->mode; | |
2500 | updated = 1; | |
2501 | } | |
2502 | if ((change_mask & TO_SET_SIZE) != 0 && xinode->size != fattr->size) | |
2503 | { | |
2504 | xinode->size = fattr->size; | |
2505 | updated = 1; | |
2506 | } | |
2507 | if ((change_mask & TO_SET_ATIME) != 0 && xinode->atime != fattr->atime) | |
2508 | { | |
2509 | xinode->atime = fattr->atime; | |
2510 | updated = 1; | |
2511 | } | |
2512 | if ((change_mask & TO_SET_MTIME) != 0 && xinode->mtime != fattr->mtime) | |
2513 | { | |
2514 | xinode->mtime = fattr->mtime; | |
2515 | updated = 1; | |
2516 | } | |
2517 | ||
2518 | if (updated) | |
2519 | { | |
2520 | xinode->ctime = time(0); | |
2521 | } | |
2522 | } | |
2523 | ||
2524 | /* | |
2525 | * Gets the name for a file where we know the parent inode and the | |
2526 | * name for the file under that inode | |
2527 | * | |
2528 | * Result must be freed after use | |
2529 | */ | |
2530 | static char *get_name_for_entry_in_parent(fuse_ino_t parent, const char *name) | |
2531 | { | |
2532 | char *result; | |
2533 | ||
2534 | if ((result = xfs_get_full_path(g_xfs, parent)) != NULL) | |
2535 | { | |
2536 | char * p = (char *) realloc(result, | |
2537 | strlen(result) + 1 + strlen(name) + 1); | |
2538 | if (p == NULL) | |
2539 | { | |
2540 | free(result); | |
2541 | result = NULL; | |
2542 | } | |
3138 | 2543 | else |
3139 | xfuse_recursive_delete_dir_with_xinode(xinode); | |
3140 | } | |
2544 | { | |
2545 | result = p; | |
2546 | strcat(result, "/"); | |
2547 | strcat(result, name); | |
2548 | } | |
2549 | } | |
2550 | ||
2551 | return result; | |
3141 | 2552 | } |
3142 | 2553 | |
3143 | 2554 | #endif /* end else #ifndef XRDP_FUSE */ |
18 | 18 | #ifndef _CHANSRV_FUSE_H |
19 | 19 | #define _CHANSRV_FUSE_H |
20 | 20 | |
21 | /* a file or dir entry in the xrdp file system */ | |
22 | struct xrdp_inode | |
21 | #include <sys/types.h> | |
22 | #include <time.h> | |
23 | ||
24 | #include "arch.h" | |
25 | #include "ms-erref.h" | |
26 | ||
27 | /* Used to pass file info back to chansrv_fuse from devredir */ | |
28 | struct file_attr | |
23 | 29 | { |
24 | tui32 parent_inode; /* Parent serial number. */ | |
25 | tui32 inode; /* File serial number. */ | |
26 | 30 | tui32 mode; /* File mode. */ |
27 | tui32 nlink; /* symbolic link count. */ | |
28 | tui32 nentries; /* number of entries in a dir */ | |
29 | tui32 nopen; /* number of simultaneous opens */ | |
30 | tui32 uid; /* User ID of the file's owner. */ | |
31 | tui32 gid; /* Group ID of the file's group. */ | |
32 | size_t size; /* Size of file, in bytes. */ | |
31 | off_t size; /* Size of file, in bytes. */ | |
33 | 32 | time_t atime; /* Time of last access. */ |
34 | 33 | time_t mtime; /* Time of last modification. */ |
35 | time_t ctime; /* Time of last status change. */ | |
36 | char name[1024]; /* Dir or filename */ | |
37 | tui32 device_id; /* for file system redirection */ | |
38 | char is_synced; /* dir struct has been read from */ | |
39 | /* remote device, done just once */ | |
40 | int lindex; /* used in clipboard operations */ | |
41 | int is_loc_resource; /* this is not a redirected resource */ | |
42 | int close_in_progress; /* close cmd sent to client */ | |
43 | int stale; /* mark file as stale, ok to remove */ | |
44 | 34 | }; |
45 | typedef struct xrdp_inode XRDP_INODE; // LK_TODO use this instead of using struct xrdp_inode | |
35 | ||
36 | /* Bitmask values used to identify individual elements in | |
37 | * struct file_attr | |
38 | */ | |
39 | #define TO_SET_MODE (1<<0) | |
40 | #define TO_SET_SIZE (1<<1) | |
41 | #define TO_SET_ATIME (1<<2) | |
42 | #define TO_SET_MTIME (1<<3) | |
43 | #define TO_SET_ALL (TO_SET_MODE | TO_SET_SIZE | TO_SET_ATIME | TO_SET_MTIME) | |
44 | ||
45 | /* Private type passed into and back-from devredir */ | |
46 | typedef struct xfuse_info XFUSE_INFO; | |
46 | 47 | |
47 | 48 | int xfuse_init(void); |
48 | 49 | int xfuse_deinit(void); |
49 | 50 | int xfuse_check_wait_objs(void); |
50 | 51 | int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout); |
51 | 52 | int xfuse_create_share(tui32 share_id, const char *dirname); |
53 | void xfuse_delete_share(tui32 share_id); | |
52 | 54 | |
53 | 55 | int xfuse_clear_clip_dir(void); |
54 | 56 | int xfuse_file_contents_range(int stream_id, const char *data, int data_bytes); |
55 | 57 | int xfuse_file_contents_size(int stream_id, int file_size); |
56 | int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int lindex); | |
58 | int xfuse_add_clip_dir_item(const char *filename, | |
59 | int flags, int size, int lindex); | |
60 | ||
61 | /* State pointer types (opaque outside this module), used for | |
62 | * callback data | |
63 | */ | |
64 | struct state_dirscan; | |
65 | struct state_lookup; | |
66 | struct state_setattr; | |
67 | struct state_open; | |
68 | struct state_create; | |
69 | struct state_read; | |
70 | struct state_write; | |
71 | struct state_remove; | |
72 | struct state_rename; | |
73 | struct state_close; | |
74 | ||
57 | 75 | |
58 | 76 | /* functions that are invoked from devredir */ |
59 | int xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode); | |
60 | void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus); | |
61 | void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId); | |
62 | void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length); | |
63 | void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus); | |
64 | void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus); | |
65 | void xfuse_devredir_cb_file_close(void *vp); | |
77 | void xfuse_devredir_cb_enum_dir_add_entry( | |
78 | struct state_dirscan *fip, | |
79 | const char *name, | |
80 | const struct file_attr *fattr); | |
81 | void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip, | |
82 | enum NTSTATUS IoStatus); | |
83 | ||
84 | void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip, | |
85 | enum NTSTATUS IoStatus, | |
86 | const struct file_attr *file_info); | |
87 | ||
88 | void xfuse_devredir_cb_setattr(struct state_setattr *fip, | |
89 | enum NTSTATUS IoStatus); | |
90 | ||
91 | void xfuse_devredir_cb_create_file(struct state_create *fip, | |
92 | enum NTSTATUS IoStatus, | |
93 | tui32 DeviceId, tui32 FileId); | |
94 | ||
95 | void xfuse_devredir_cb_open_file(struct state_open *fip, | |
96 | enum NTSTATUS IoStatus, | |
97 | tui32 DeviceId, tui32 FileId); | |
98 | ||
99 | void xfuse_devredir_cb_read_file(struct state_read *fip, | |
100 | const char *buf, size_t length); | |
101 | void xfuse_devredir_cb_write_file( | |
102 | struct state_write *fip, | |
103 | enum NTSTATUS IoStatus, | |
104 | off_t offset, | |
105 | size_t length); | |
106 | ||
107 | void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip, | |
108 | enum NTSTATUS IoStatus); | |
109 | ||
110 | void xfuse_devredir_cb_rename_file(struct state_rename *fip, | |
111 | enum NTSTATUS IoStatus); | |
112 | ||
113 | void xfuse_devredir_cb_file_close(struct state_close *fip); | |
66 | 114 | |
67 | 115 | #endif |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | * This file implements the interface in chansrv_fuse_fs.h | |
16 | */ | |
17 | #include <stdlib.h> | |
18 | #include <string.h> | |
19 | #include <sys/types.h> | |
20 | #include <sys/stat.h> | |
21 | #include <unistd.h> | |
22 | #include <errno.h> | |
23 | ||
24 | #if defined(HAVE_CONFIG_H) | |
25 | #include <config_ac.h> | |
26 | #endif | |
27 | ||
28 | #include "os_calls.h" | |
29 | ||
30 | #include "chansrv_xfs.h" | |
31 | ||
32 | /* | |
33 | * Skip this module if FUSE is not supported. A standards-compliant C | |
34 | * translation unit must contain at least one declaration (C99:6.9), and we've | |
35 | * fulfilled that requirement by this stage. | |
36 | */ | |
37 | #ifdef XRDP_FUSE | |
38 | ||
39 | #define INODE_TABLE_ALLOCATION_INITIAL 4096 | |
40 | #define INODE_TABLE_ALLOCATION_GRANULARITY 100 | |
41 | ||
42 | /* inum of the delete pending directory */ | |
43 | #define DELETE_PENDING_ID 2 | |
44 | ||
45 | /* | |
46 | * A double-linked list of inodes, sorted by inum | |
47 | * | |
48 | * The elements in the list are sorted in increasing inum order, as this | |
49 | * allows a directory enumeration to be easily resumed if elements | |
50 | * are removed or added. See xfs_readdir() for details on this. | |
51 | */ | |
52 | typedef struct xfs_inode_all XFS_INODE_ALL; | |
53 | typedef struct xfs_list | |
54 | { | |
55 | XFS_INODE_ALL *begin; | |
56 | XFS_INODE_ALL *end; | |
57 | } XFS_LIST; | |
58 | ||
59 | /* | |
60 | * A complete inode, including the private elements used by the | |
61 | * implementation | |
62 | */ | |
63 | typedef struct xfs_inode_all | |
64 | { | |
65 | XFS_INODE pub; /* Public elements */ | |
66 | /* | |
67 | * Directory linkage elements | |
68 | * | |
69 | * Because we don't support hard-linking, elements can be stored in | |
70 | * one and only one directory:- | |
71 | */ | |
72 | struct xfs_inode_all *parent; /* Parent inode */ | |
73 | struct xfs_inode_all *next; /* Next entry in parent */ | |
74 | struct xfs_inode_all *previous; /* Previous entry in parent */ | |
75 | XFS_LIST dir; /* Directory only - children */ | |
76 | /* | |
77 | * Other private elements | |
78 | */ | |
79 | unsigned int open_count; /* Regular files only */ | |
80 | } XFS_INODE_ALL; | |
81 | ||
82 | ||
83 | /* the xrdp file system in memory | |
84 | * | |
85 | * inode_table allows for O(1) access to any file based on the inum. | |
86 | * Index 0 is unused, so we can use an inode of zero for | |
87 | * an invalid inode, and avoid off-by-one errors index | |
88 | * 1 is our '.' directory. | |
89 | * 2 is the delete pending directory, where we can place | |
90 | * inodes with a positive open count which are | |
91 | * deleted. | |
92 | * free_list List of free inode numbers. Allows for O(1) access to | |
93 | * a free node, provided the free list is not empty. | |
94 | */ | |
95 | struct xfs_fs | |
96 | { | |
97 | XFS_INODE_ALL **inode_table; /* a table of entries; can grow. */ | |
98 | fuse_ino_t *free_list; /* Free inodes */ | |
99 | unsigned int inode_count; /* Current number of inodes */ | |
100 | unsigned int free_count; /* Size of free_list */ | |
101 | unsigned int generation; /* Changes when an inode is deleted */ | |
102 | }; | |
103 | ||
104 | /* A directory handle | |
105 | * | |
106 | * inum inum of the directory being scanned | |
107 | * generation Generation of the inum we opened | |
108 | */ | |
109 | struct xfs_dir_handle | |
110 | { | |
111 | fuse_ino_t inum; | |
112 | tui32 generation; | |
113 | }; | |
114 | ||
115 | /* module based logging */ | |
116 | #define LOG_ERROR 0 | |
117 | #define LOG_INFO 1 | |
118 | #define LOG_DEBUG 2 | |
119 | #ifndef LOG_LEVEL | |
120 | #define LOG_LEVEL LOG_ERROR | |
121 | #endif | |
122 | ||
123 | #define log_error(_params...) \ | |
124 | { \ | |
125 | g_write("[%10.10u]: XFS %s: %d : ERROR: ", \ | |
126 | g_time3(), __func__, __LINE__); \ | |
127 | g_writeln (_params); \ | |
128 | } | |
129 | ||
130 | #define log_always(_params...) \ | |
131 | { \ | |
132 | g_write("[%10.10u]: XFS %s: %d : ALWAYS: ", \ | |
133 | g_time3(), __func__, __LINE__); \ | |
134 | g_writeln (_params); \ | |
135 | } | |
136 | ||
137 | #define log_info(_params...) \ | |
138 | { \ | |
139 | if (LOG_INFO <= LOG_LEVEL) \ | |
140 | { \ | |
141 | g_write("[%10.10u]: XFS %s: %d : ", \ | |
142 | g_time3(), __func__, __LINE__); \ | |
143 | g_writeln (_params); \ | |
144 | } \ | |
145 | } | |
146 | ||
147 | #define log_debug(_params...) \ | |
148 | { \ | |
149 | if (LOG_DEBUG <= LOG_LEVEL) \ | |
150 | { \ | |
151 | g_write("[%10.10u]: XFS %s: %d : ", \ | |
152 | g_time3(), __func__, __LINE__); \ | |
153 | g_writeln (_params); \ | |
154 | } \ | |
155 | } | |
156 | ||
157 | /* ------------------------------------------------------------------------ */ | |
158 | static int | |
159 | grow_xfs(struct xfs_fs *xfs, unsigned int extra_inodes) | |
160 | { | |
161 | int result = 0; | |
162 | unsigned int new_count = xfs->inode_count + extra_inodes; | |
163 | XFS_INODE_ALL **new_table; | |
164 | fuse_ino_t *new_free_list; | |
165 | ||
166 | new_table = (XFS_INODE_ALL **) | |
167 | realloc(xfs->inode_table, new_count * sizeof(new_table[0])); | |
168 | if (new_table != NULL) | |
169 | { | |
170 | unsigned int i; | |
171 | for (i = xfs->inode_count ; i < new_count ; ++i) | |
172 | { | |
173 | new_table[i] = NULL; | |
174 | } | |
175 | xfs->inode_table = new_table; | |
176 | ||
177 | new_free_list = (fuse_ino_t *) | |
178 | realloc(xfs->free_list, | |
179 | new_count * sizeof(new_free_list[0])); | |
180 | if (new_free_list) | |
181 | { | |
182 | /* Add the new inodes in to the new_free_list, so the lowest | |
183 | * number is allocated first | |
184 | */ | |
185 | i = new_count; | |
186 | while (i > xfs->inode_count) | |
187 | { | |
188 | new_free_list[xfs->free_count++] = --i; | |
189 | } | |
190 | ||
191 | xfs->free_list = new_free_list; | |
192 | xfs->inode_count = new_count; | |
193 | ||
194 | result = 1; | |
195 | } | |
196 | } | |
197 | ||
198 | return result; | |
199 | } | |
200 | ||
201 | /* ------------------------------------------------------------------------ */ | |
202 | static void | |
203 | add_inode_to_list(XFS_LIST *list, XFS_INODE_ALL *xino) | |
204 | { | |
205 | fuse_ino_t inum = xino->pub.inum; | |
206 | ||
207 | /* Find the element we need to insert after */ | |
208 | XFS_INODE_ALL *predecessor = list->end; | |
209 | while (predecessor != NULL && predecessor->pub.inum > inum) | |
210 | { | |
211 | predecessor = predecessor->previous; | |
212 | } | |
213 | ||
214 | if (predecessor == NULL) | |
215 | { | |
216 | /* Inserting at the beginning */ | |
217 | /* Set up links in node */ | |
218 | xino->next = list->begin; | |
219 | xino->previous = NULL; | |
220 | ||
221 | /* Set up back-link to node */ | |
222 | if (list->begin == NULL) | |
223 | { | |
224 | /* We are the last node */ | |
225 | list->end = xino; | |
226 | } | |
227 | else | |
228 | { | |
229 | list->begin->previous = xino; | |
230 | } | |
231 | /* Set up forward-link to node */ | |
232 | list->begin = xino; | |
233 | } | |
234 | else | |
235 | { | |
236 | /* Set up links in node */ | |
237 | xino->next = predecessor->next; | |
238 | xino->previous = predecessor; | |
239 | ||
240 | /* Set up back-link to node */ | |
241 | if (predecessor->next == NULL) | |
242 | { | |
243 | list->end = xino; | |
244 | } | |
245 | else | |
246 | { | |
247 | predecessor->next->previous = xino; | |
248 | } | |
249 | /* Set up forward-link to node */ | |
250 | predecessor->next = xino; | |
251 | } | |
252 | } | |
253 | ||
254 | /* ------------------------------------------------------------------------ */ | |
255 | static void | |
256 | remove_inode_from_list(XFS_LIST *list, XFS_INODE_ALL *xino) | |
257 | { | |
258 | if (xino->previous == NULL) | |
259 | { | |
260 | /* First element */ | |
261 | list->begin = xino->next; | |
262 | } | |
263 | else | |
264 | { | |
265 | xino->previous->next = xino->next; | |
266 | } | |
267 | ||
268 | if (xino->next == NULL) | |
269 | { | |
270 | /* Last element */ | |
271 | list->end = xino->previous; | |
272 | } | |
273 | else | |
274 | { | |
275 | xino->next->previous = xino->previous; | |
276 | } | |
277 | ||
278 | } | |
279 | ||
280 | /* ------------------------------------------------------------------------ */ | |
281 | static void | |
282 | link_inode_into_directory_node(XFS_INODE_ALL *dinode, XFS_INODE_ALL *xino) | |
283 | { | |
284 | xino->parent = dinode; | |
285 | add_inode_to_list(&dinode->dir, xino); | |
286 | } | |
287 | ||
288 | /* ------------------------------------------------------------------------ */ | |
289 | static void | |
290 | unlink_inode_from_parent(XFS_INODE_ALL *xino) | |
291 | { | |
292 | remove_inode_from_list(&xino->parent->dir, xino); | |
293 | ||
294 | xino->next = NULL; | |
295 | xino->previous = NULL; | |
296 | xino->parent = NULL; | |
297 | } | |
298 | ||
299 | /* ------------------------------------------------------------------------ */ | |
300 | struct xfs_fs * | |
301 | xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid) | |
302 | { | |
303 | struct xfs_fs *xfs = g_new0(struct xfs_fs, 1); | |
304 | XFS_INODE_ALL *xino1 = NULL; | |
305 | XFS_INODE_ALL *xino2 = NULL; | |
306 | ||
307 | if (xfs != NULL) | |
308 | { | |
309 | xfs->inode_count = 0; | |
310 | xfs->free_count = 0; | |
311 | xfs->inode_table = NULL; | |
312 | xfs->free_list = NULL; | |
313 | xfs->generation = 1; | |
314 | ||
315 | if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) || | |
316 | (xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL || | |
317 | (xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL) | |
318 | { | |
319 | free(xino1); | |
320 | free(xino2); | |
321 | xfs_delete_xfs_fs(xfs); | |
322 | xfs = NULL; | |
323 | } | |
324 | else | |
325 | { | |
326 | /* | |
327 | * The use of grow_xfs to allocate the inode table will make | |
328 | * inodes 0, 1 (FUSE_ROOT_ID) and 2 (DELETE_PENDING_ID) the first | |
329 | * available free inodes. We can ignore these */ | |
330 | xfs->free_count -= 3; | |
331 | ||
332 | xfs->inode_table[0] = NULL; | |
333 | xfs->inode_table[FUSE_ROOT_ID] = xino1; | |
334 | xfs->inode_table[DELETE_PENDING_ID] = xino2; | |
335 | ||
336 | xino1->pub.inum = FUSE_ROOT_ID; | |
337 | xino1->pub.mode = (S_IFDIR | 0777) & ~umask; | |
338 | xino1->pub.uid = uid; | |
339 | xino1->pub.gid = gid; | |
340 | xino1->pub.size = 0; | |
341 | xino1->pub.atime = time(0); | |
342 | xino1->pub.mtime = xino1->pub.atime; | |
343 | xino1->pub.ctime = xino1->pub.atime; | |
344 | strcpy(xino1->pub.name, "."); | |
345 | xino1->pub.generation = xfs->generation; | |
346 | xino1->pub.device_id = 0; | |
347 | ||
348 | /* | |
349 | * FUSE_ROOT_ID has no parent rather than being a parent | |
350 | * of itself. This is intentional */ | |
351 | xino1->parent = NULL; | |
352 | xino1->next = NULL; | |
353 | xino1->previous = NULL; | |
354 | xino1->dir.begin = NULL; | |
355 | xino1->dir.end = NULL; | |
356 | ||
357 | xino2->pub.inum = DELETE_PENDING_ID; | |
358 | xino2->pub.mode = (S_IFDIR | 0777) & ~umask; | |
359 | xino2->pub.uid = uid; | |
360 | xino2->pub.gid = gid; | |
361 | xino2->pub.size = 0; | |
362 | xino2->pub.atime = time(0); | |
363 | xino2->pub.mtime = xino2->pub.atime; | |
364 | xino2->pub.ctime = xino2->pub.atime; | |
365 | strcpy(xino2->pub.name, ".delete-pending"); | |
366 | xino2->pub.generation = xfs->generation; | |
367 | xino2->pub.device_id = 0; | |
368 | ||
369 | xino2->parent = NULL; | |
370 | xino2->next = NULL; | |
371 | xino2->previous = NULL; | |
372 | xino2->dir.begin = NULL; | |
373 | xino2->dir.end = NULL; | |
374 | /* | |
375 | * Uncomment this line to make the .delete-pending | |
376 | * directory visible to the user in the root | |
377 | */ | |
378 | /* link_inode_into_directory_node(xino1, xino2); */ | |
379 | } | |
380 | } | |
381 | ||
382 | return xfs; | |
383 | } | |
384 | ||
385 | /* ------------------------------------------------------------------------ */ | |
386 | void | |
387 | xfs_delete_xfs_fs(struct xfs_fs *xfs) | |
388 | { | |
389 | if (xfs != NULL && xfs->inode_table != NULL) | |
390 | { | |
391 | size_t i; | |
392 | for (i = 0 ; i < xfs->inode_count; ++i) | |
393 | { | |
394 | free(xfs->inode_table[i]); | |
395 | } | |
396 | } | |
397 | free(xfs->inode_table); | |
398 | free(xfs->free_list); | |
399 | free(xfs); | |
400 | } | |
401 | ||
402 | /* ------------------------------------------------------------------------ */ | |
403 | XFS_INODE * | |
404 | xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum, | |
405 | const char *name, mode_t mode) | |
406 | { | |
407 | XFS_INODE *result = NULL; | |
408 | XFS_INODE_ALL *parent = NULL; | |
409 | ||
410 | /* Checks:- | |
411 | * 1) the parent exists (and is a directory) | |
412 | * 2) the caller is not inserting into the .delete-pending directory, | |
413 | * 3) Name's not too long | |
414 | * 4) Entry does not already exist | |
415 | */ | |
416 | if (parent_inum < xfs->inode_count && | |
417 | ((parent = xfs->inode_table[parent_inum]) != NULL) && | |
418 | (parent->pub.mode & S_IFDIR) != 0 && | |
419 | parent_inum != DELETE_PENDING_ID && | |
420 | strlen(name) <= XFS_MAXFILENAMELEN && | |
421 | !xfs_lookup_in_dir(xfs, parent_inum, name)) | |
422 | { | |
423 | /* Sanitise the mode so one-and-only-one of S_IFDIR and | |
424 | * S_IFREG is set */ | |
425 | if ((mode & S_IFDIR) != 0) | |
426 | { | |
427 | mode = (mode & 0777) | S_IFDIR; | |
428 | } | |
429 | else | |
430 | { | |
431 | mode = (mode & 0777) | S_IFREG; | |
432 | } | |
433 | ||
434 | /* Space for a new entry? */ | |
435 | if (xfs->free_count > 0 || | |
436 | grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY)) | |
437 | { | |
438 | XFS_INODE_ALL *xino = NULL; | |
439 | ||
440 | if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL) | |
441 | { | |
442 | fuse_ino_t inum = xfs->free_list[--xfs->free_count]; | |
443 | if (xfs->inode_table[inum] != NULL) | |
444 | { | |
445 | log_error("Unexpected non-NULL value in inode table " | |
446 | "entry %ld", inum); | |
447 | } | |
448 | xfs->inode_table[inum] = xino; | |
449 | xino->pub.inum = inum; | |
450 | xino->pub.mode = mode; | |
451 | xino->pub.uid = parent->pub.uid; | |
452 | xino->pub.gid = parent->pub.gid; | |
453 | if (mode & S_IFDIR) | |
454 | { | |
455 | xino->pub.size = 4096; | |
456 | } | |
457 | else | |
458 | { | |
459 | xino->pub.size = 0; | |
460 | } | |
461 | xino->pub.atime = time(0); | |
462 | xino->pub.mtime = xino->pub.atime; | |
463 | xino->pub.ctime = xino->pub.atime; | |
464 | strcpy(xino->pub.name, name); | |
465 | xino->pub.generation = xfs->generation; | |
466 | xino->pub.device_id = parent->pub.device_id; | |
467 | xino->pub.lindex = 0; | |
468 | ||
469 | xino->parent = NULL; | |
470 | xino->next = NULL; | |
471 | xino->previous = NULL; | |
472 | link_inode_into_directory_node(parent, xino); | |
473 | result = &xino->pub; | |
474 | } | |
475 | } | |
476 | } | |
477 | ||
478 | return result; | |
479 | } | |
480 | ||
481 | /* ------------------------------------------------------------------------ */ | |
482 | void | |
483 | xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum) | |
484 | { | |
485 | XFS_INODE_ALL *xino = NULL; | |
486 | ||
487 | if (inum < xfs->inode_count && | |
488 | ((xino = xfs->inode_table[inum]) != NULL) && | |
489 | ((xino->pub.mode & S_IFDIR) != 0)) | |
490 | { | |
491 | XFS_INODE_ALL *e; | |
492 | while ((e = xino->dir.end) != NULL) | |
493 | { | |
494 | xfs_remove_entry(xfs, e->pub.inum); | |
495 | } | |
496 | } | |
497 | } | |
498 | ||
499 | /* ------------------------------------------------------------------------ */ | |
500 | void | |
501 | xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum) | |
502 | { | |
503 | XFS_INODE_ALL *xino = NULL; | |
504 | ||
505 | if (inum < xfs->inode_count && | |
506 | ((xino = xfs->inode_table[inum]) != NULL)) | |
507 | { | |
508 | if ((xino->pub.mode & S_IFDIR) != 0) | |
509 | { | |
510 | xfs_remove_directory_contents(xfs, inum); | |
511 | } | |
512 | ||
513 | unlink_inode_from_parent(xino); | |
514 | if ((xino->pub.mode & S_IFREG) != 0 && xino->open_count > 0) | |
515 | { | |
516 | link_inode_into_directory_node( | |
517 | xfs->inode_table[DELETE_PENDING_ID], xino); | |
518 | } | |
519 | else | |
520 | { | |
521 | xfs->free_list[xfs->free_count++] = inum; | |
522 | xfs->inode_table[inum] = NULL; | |
523 | /* | |
524 | * Bump the generation when we return an inum to the free list, | |
525 | * so that the caller can distinguish re-uses of the same inum. | |
526 | */ | |
527 | ++xfs->generation; | |
528 | free(xino); | |
529 | } | |
530 | } | |
531 | } | |
532 | ||
533 | /* ------------------------------------------------------------------------ */ | |
534 | XFS_INODE * | |
535 | xfs_get(struct xfs_fs *xfs, fuse_ino_t inum) | |
536 | { | |
537 | return (inum < xfs->inode_count) ? &xfs->inode_table[inum]->pub : NULL; | |
538 | } | |
539 | ||
540 | /* ------------------------------------------------------------------------ */ | |
541 | char * | |
542 | xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum) | |
543 | { | |
544 | char *result = NULL; | |
545 | XFS_INODE_ALL *xino = NULL; | |
546 | ||
547 | if (inum < xfs->inode_count && | |
548 | ((xino = xfs->inode_table[inum]) != NULL)) | |
549 | { | |
550 | if (xino->pub.inum == FUSE_ROOT_ID) | |
551 | { | |
552 | return strdup("/"); | |
553 | } | |
554 | else | |
555 | { | |
556 | /* | |
557 | * Add up the lengths of all the names up to the root, | |
558 | * allowing one extra char for a '/' prefix for each element | |
559 | */ | |
560 | size_t len = 0; | |
561 | XFS_INODE_ALL *p; | |
562 | for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent) | |
563 | { | |
564 | len += strlen(p->pub.name); | |
565 | ++len; /* Allow for '/' prefix */ | |
566 | } | |
567 | ||
568 | result = (char *) malloc(len + 1); | |
569 | if (result != NULL) | |
570 | { | |
571 | /* Construct the path from the end */ | |
572 | char *end = result + len; | |
573 | *end = '\0'; | |
574 | ||
575 | for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent) | |
576 | { | |
577 | len = strlen(p->pub.name); | |
578 | end -= (len + 1); | |
579 | *end = '/'; | |
580 | memcpy(end + 1, p->pub.name, len); | |
581 | } | |
582 | } | |
583 | } | |
584 | } | |
585 | ||
586 | return result; | |
587 | } | |
588 | ||
589 | /* ------------------------------------------------------------------------ */ | |
590 | XFS_INODE * | |
591 | xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name) | |
592 | { | |
593 | XFS_INODE_ALL *xino; | |
594 | XFS_INODE *result = NULL; | |
595 | if (inum < xfs->inode_count && | |
596 | ((xino = xfs->inode_table[inum]) != NULL) && | |
597 | (xino->pub.mode & S_IFDIR) != 0) | |
598 | { | |
599 | XFS_INODE_ALL *p; | |
600 | for (p = xino->dir.begin ; p != NULL; p = p->next) | |
601 | { | |
602 | if (strcmp(p->pub.name, name) == 0) | |
603 | { | |
604 | result = &p->pub; | |
605 | break; | |
606 | } | |
607 | } | |
608 | } | |
609 | ||
610 | return result; | |
611 | } | |
612 | ||
613 | /* ------------------------------------------------------------------------ */ | |
614 | int | |
615 | xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum) | |
616 | { | |
617 | XFS_INODE_ALL *xino = NULL; | |
618 | int result = 0; | |
619 | ||
620 | if (inum < xfs->inode_count && | |
621 | ((xino = xfs->inode_table[inum]) != NULL) && | |
622 | (xino->pub.mode & S_IFDIR) != 0) | |
623 | { | |
624 | result = (xino->dir.begin == NULL); | |
625 | } | |
626 | ||
627 | return result; | |
628 | } | |
629 | ||
630 | /* ------------------------------------------------------------------------ */ | |
631 | unsigned int | |
632 | xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry) | |
633 | { | |
634 | unsigned int result = 0; | |
635 | ||
636 | XFS_INODE_ALL *dxino = NULL; | |
637 | XFS_INODE_ALL *exino = NULL; | |
638 | ||
639 | if (dir < xfs->inode_count && | |
640 | ((dxino = xfs->inode_table[dir]) != NULL) && | |
641 | (dxino->pub.mode & S_IFDIR) != 0 && | |
642 | entry < xfs->inode_count && | |
643 | ((exino = xfs->inode_table[entry]) != NULL)) | |
644 | { | |
645 | unsigned int count = 0; | |
646 | ||
647 | while (exino != NULL && exino != dxino) | |
648 | { | |
649 | ++count; | |
650 | exino = exino->parent; | |
651 | } | |
652 | ||
653 | if (exino != NULL) | |
654 | { | |
655 | result = count; | |
656 | } | |
657 | } | |
658 | ||
659 | return result; | |
660 | } | |
661 | ||
662 | /* ------------------------------------------------------------------------ */ | |
663 | struct xfs_dir_handle * | |
664 | xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir) | |
665 | { | |
666 | XFS_INODE_ALL *xino = NULL; | |
667 | struct xfs_dir_handle *result = NULL; | |
668 | ||
669 | if (dir < xfs->inode_count && | |
670 | ((xino = xfs->inode_table[dir]) != NULL) && | |
671 | (xino->pub.mode & S_IFDIR) != 0) | |
672 | { | |
673 | result = g_new0(struct xfs_dir_handle, 1); | |
674 | if (result) | |
675 | { | |
676 | result->inum = xino->pub.inum; | |
677 | result->generation = xino->pub.generation; | |
678 | } | |
679 | } | |
680 | ||
681 | return result; | |
682 | } | |
683 | ||
684 | /* ------------------------------------------------------------------------ */ | |
685 | XFS_INODE * | |
686 | xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off) | |
687 | { | |
688 | XFS_INODE_ALL *result = NULL; | |
689 | XFS_INODE_ALL *dxino = NULL; | |
690 | XFS_INODE_ALL *xino = NULL; | |
691 | ||
692 | /* Check the direcory is still valid */ | |
693 | if (handle->inum < xfs->inode_count && | |
694 | ((dxino = xfs->inode_table[handle->inum]) != NULL) && | |
695 | (dxino->pub.mode & S_IFDIR) != 0 && | |
696 | handle->generation == dxino->pub.generation) | |
697 | { | |
698 | fuse_ino_t inum; | |
699 | ||
700 | if (*off == (off_t) -1) | |
701 | { | |
702 | /* We're at the end already */ | |
703 | } | |
704 | else if ((inum = *off) == 0) | |
705 | { | |
706 | /* First call */ | |
707 | result = dxino->dir.begin; | |
708 | } | |
709 | else if (inum < xfs->inode_count && | |
710 | (xino = xfs->inode_table[inum]) != 0 && | |
711 | xino->parent == dxino) | |
712 | { | |
713 | /* The node we're pointing to is still valid */ | |
714 | result = xino; | |
715 | } | |
716 | else | |
717 | { | |
718 | /* | |
719 | * The file we wanted has been pulled out from under us. | |
720 | * We will look forward in the inode table to try to | |
721 | * discover the next inode in the directory. Because | |
722 | * files are stored in inode order, this guarantees | |
723 | * we'll meet POSIX requirements. | |
724 | */ | |
725 | for (inum = inum + 1 ; inum < xfs->inode_count ; ++inum) | |
726 | { | |
727 | if ((xino = xfs->inode_table[inum]) != 0 && | |
728 | xino->parent == dxino) | |
729 | { | |
730 | result = xino; | |
731 | break; | |
732 | } | |
733 | } | |
734 | } | |
735 | } | |
736 | ||
737 | /* Update the offset */ | |
738 | if (result == NULL || result->next == NULL) | |
739 | { | |
740 | /* We're done */ | |
741 | *off = (off_t) -1; | |
742 | } | |
743 | else | |
744 | { | |
745 | *off = (off_t)result->next->pub.inum; | |
746 | } | |
747 | ||
748 | /* Caller only sees public interface to the result */ | |
749 | return (result) ? &result->pub : NULL; | |
750 | } | |
751 | ||
752 | /* ------------------------------------------------------------------------ */ | |
753 | void | |
754 | xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle) | |
755 | { | |
756 | free(handle); | |
757 | } | |
758 | ||
759 | /* ------------------------------------------------------------------------ */ | |
760 | void | |
761 | xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum) | |
762 | { | |
763 | XFS_INODE_ALL *xino; | |
764 | if (inum < xfs->inode_count && | |
765 | ((xino = xfs->inode_table[inum]) != NULL) && | |
766 | (xino->pub.mode & S_IFREG) != 0) | |
767 | { | |
768 | ++xino->open_count; | |
769 | } | |
770 | } | |
771 | ||
772 | /* ------------------------------------------------------------------------ */ | |
773 | void | |
774 | xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum) | |
775 | { | |
776 | XFS_INODE_ALL *xino; | |
777 | if (inum < xfs->inode_count && | |
778 | ((xino = xfs->inode_table[inum]) != NULL) && | |
779 | (xino->pub.mode & S_IFREG) != 0) | |
780 | { | |
781 | if (xino->open_count > 0) | |
782 | { | |
783 | --xino->open_count; | |
784 | } | |
785 | ||
786 | if (xino->open_count == 0 && | |
787 | xino->parent == xfs->inode_table[DELETE_PENDING_ID]) | |
788 | { | |
789 | /* We can get rid of this one now */ | |
790 | xfs_remove_entry(xfs, inum); | |
791 | } | |
792 | } | |
793 | } | |
794 | ||
795 | /* ------------------------------------------------------------------------ */ | |
796 | unsigned int | |
797 | xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum) | |
798 | { | |
799 | unsigned int result = 0; | |
800 | XFS_INODE_ALL *xino; | |
801 | if (inum < xfs->inode_count && | |
802 | ((xino = xfs->inode_table[inum]) != NULL) && | |
803 | (xino->pub.mode & S_IFREG) != 0) | |
804 | { | |
805 | result = xino->open_count; | |
806 | } | |
807 | ||
808 | return result; | |
809 | } | |
810 | ||
811 | /* ------------------------------------------------------------------------ */ | |
812 | void | |
813 | xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id) | |
814 | { | |
815 | fuse_ino_t inum; | |
816 | XFS_INODE_ALL *xino; | |
817 | ||
818 | if (device_id != 0) | |
819 | { | |
820 | /* Using xfs_remove_entry() is convenient, but it recurses | |
821 | * in to directories. To make sure all entries are removed, set the | |
822 | * open_count of all affected files to 0 first | |
823 | */ | |
824 | for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum) | |
825 | { | |
826 | if ((xino = xfs->inode_table[inum]) != NULL && | |
827 | xino->pub.device_id == device_id && | |
828 | (xino->pub.mode & S_IFREG) != 0) | |
829 | { | |
830 | xino->open_count = 0; | |
831 | } | |
832 | } | |
833 | ||
834 | /* Now we can be sure everything will be deleted correctly */ | |
835 | for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum) | |
836 | { | |
837 | if ((xino = xfs->inode_table[inum]) != NULL && | |
838 | xino->pub.device_id == device_id) | |
839 | { | |
840 | xfs_remove_entry(xfs, xino->pub.inum); | |
841 | } | |
842 | } | |
843 | } | |
844 | } | |
845 | ||
846 | /* ------------------------------------------------------------------------ */ | |
847 | int | |
848 | xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum, | |
849 | fuse_ino_t new_parent_inum, const char *name) | |
850 | { | |
851 | XFS_INODE_ALL *xino; | |
852 | XFS_INODE_ALL *parent; | |
853 | ||
854 | return | |
855 | (strlen(name) <= XFS_MAXFILENAMELEN && | |
856 | inum < xfs->inode_count && | |
857 | ((xino = xfs->inode_table[inum]) != NULL) && | |
858 | new_parent_inum != DELETE_PENDING_ID && | |
859 | new_parent_inum < xfs->inode_count && | |
860 | ((parent = xfs->inode_table[new_parent_inum]) != NULL) && | |
861 | (parent->pub.mode & S_IFDIR) != 0 && | |
862 | xfs_is_under(xfs, inum, new_parent_inum) == 0); | |
863 | } | |
864 | ||
865 | /* ------------------------------------------------------------------------ */ | |
866 | int | |
867 | xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum, | |
868 | fuse_ino_t new_parent_inum, const char *name) | |
869 | { | |
870 | int result = EINVAL; | |
871 | XFS_INODE_ALL *xino; | |
872 | XFS_INODE_ALL *parent; | |
873 | XFS_INODE *dest; | |
874 | ||
875 | if (xfs_check_move_entry(xfs, inum, new_parent_inum, name)) | |
876 | { | |
877 | xino = xfs->inode_table[inum]; | |
878 | parent = xfs->inode_table[new_parent_inum]; | |
879 | ||
880 | if (xino->parent != parent) | |
881 | { | |
882 | /* We're moving between directories */ | |
883 | ||
884 | /* Does the target name already exist in the destination? */ | |
885 | if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL) | |
886 | { | |
887 | xfs_remove_entry(xfs, dest->inum); | |
888 | } | |
889 | ||
890 | unlink_inode_from_parent(xino); | |
891 | link_inode_into_directory_node(parent, xino); | |
892 | strcpy(xino->pub.name, name); | |
893 | } | |
894 | else if (strcmp(xino->pub.name, name) != 0) | |
895 | { | |
896 | /* Same directory, but name has changed */ | |
897 | if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL) | |
898 | { | |
899 | xfs_remove_entry(xfs, dest->inum); | |
900 | } | |
901 | strcpy(xino->pub.name, name); | |
902 | } | |
903 | result = 0; | |
904 | } | |
905 | ||
906 | return result; | |
907 | } | |
908 | #endif /* XRDP_FUSE */ |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | * This file is the interface to the FUSE file system used by | |
16 | * chansrv | |
17 | */ | |
18 | ||
19 | #ifndef _CHANSRV_XFS | |
20 | #define _CHANSRV_XFS | |
21 | ||
22 | /* Skip this include if there's no FUSE */ | |
23 | #ifdef XRDP_FUSE | |
24 | ||
25 | #include <stddef.h> | |
26 | #include <fuse_lowlevel.h> | |
27 | #include <time.h> | |
28 | ||
29 | #include "arch.h" | |
30 | ||
31 | #define XFS_MAXFILENAMELEN 255 | |
32 | ||
33 | /* | |
34 | * Incomplete types for the public interface | |
35 | */ | |
36 | struct xfs_fs; | |
37 | struct xfs_dir_handle; | |
38 | ||
39 | typedef struct xfs_inode | |
40 | { | |
41 | fuse_ino_t inum; /* File serial number. */ | |
42 | mode_t mode; /* File mode. */ | |
43 | uid_t uid; /* User ID of the file's owner. */ | |
44 | gid_t gid; /* Group ID of the file's group. */ | |
45 | off_t size; /* Size of file, in bytes. */ | |
46 | time_t atime; /* Time of last access. */ | |
47 | time_t mtime; /* Time of last modification. */ | |
48 | time_t ctime; /* Time of last status change. */ | |
49 | char name[XFS_MAXFILENAMELEN + 1]; /* Short name */ | |
50 | tui32 generation; /* Changes if inode is reused */ | |
51 | tui32 device_id; /* for file system redirection | |
52 | * Non-redirected devices are guaranteed | |
53 | * to have a device_id or zero */ | |
54 | int lindex; /* used in clipboard operations */ | |
55 | } XFS_INODE; | |
56 | ||
57 | /* | |
58 | * Create a new filesystem instance | |
59 | * | |
60 | * @param umask Umask to apply to initial data structures | |
61 | * @param uid Owner UID for initial root directory | |
62 | * @param gid Owner GID for initial root directory | |
63 | * @return Pointer to instance, or NULL if no memory | |
64 | */ | |
65 | struct xfs_fs * | |
66 | xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid); | |
67 | ||
68 | /* | |
69 | * Delete a filesystem instance | |
70 | * | |
71 | * @param xfs Filesystem instance | |
72 | */ | |
73 | void | |
74 | xfs_delete_xfs_fs(struct xfs_fs *xfs); | |
75 | ||
76 | /* | |
77 | * Add an entry to the filesystem | |
78 | * | |
79 | * The returned element has default values inherited from the parent | |
80 | * | |
81 | * The specified mode is sanitised in that:- | |
82 | * - Bits other than the lowest nine permissions bits, the directory | |
83 | * bit (S_IFDIR) and the regular bit (S_IFREG) are cleared. | |
84 | * - S_IFREG is cleared if S_IFDIR is set | |
85 | * - S_IFREG is set if neither S_IFDIR or S_IFREG is set | |
86 | * | |
87 | * NULL is returned for one of the following conditions:- | |
88 | * - the parent does not exist | |
89 | * - the parent is not a directory | |
90 | * - the name length exceeds XFS_MAXFILENAMELEN | |
91 | * - the entry already exists | |
92 | * - memory is exhausted. | |
93 | * | |
94 | * @param xfs filesystem instance | |
95 | * @param parent_inode parent inode | |
96 | * @param name Name of entry | |
97 | * @param mode Initial mode for file. | |
98 | * @return inode, or NULL | |
99 | */ | |
100 | XFS_INODE * | |
101 | xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum, | |
102 | const char *name, mode_t mode); | |
103 | ||
104 | /* | |
105 | * Delete the contents of a directory | |
106 | * | |
107 | * If normal files are opened when they are deleted, the inode is not | |
108 | * released until the open count goes to zero. | |
109 | * | |
110 | * @param xfs filesystem instance | |
111 | * @param inode Reference to entry to delete | |
112 | * | |
113 | */ | |
114 | void | |
115 | xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum); | |
116 | ||
117 | /* | |
118 | * Delete an entry from the filesystem | |
119 | * | |
120 | * If normal files are opened when they are deleted, the inode is not | |
121 | * released until the open count goes to zero. | |
122 | * | |
123 | * For directories, the contents are removed first. | |
124 | * | |
125 | * @param xfs filesystem instance | |
126 | * @param inode Reference to entry to delete | |
127 | * | |
128 | */ | |
129 | void | |
130 | xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum); | |
131 | ||
132 | /* | |
133 | * Get an XFS_INODE for an inum | |
134 | * | |
135 | * @param xfs filesystem instance | |
136 | * @param inum Inumber | |
137 | * @return Pointer to XFS_INODE | |
138 | */ | |
139 | XFS_INODE * | |
140 | xfs_get(struct xfs_fs *xfs, fuse_ino_t inum); | |
141 | ||
142 | /* | |
143 | * Get the full path for an inum | |
144 | * | |
145 | * The path is dynamically allocated, and must be freed after use | |
146 | * | |
147 | * @param xfs filesystem instance | |
148 | * @param inum Inumber to get path for | |
149 | * @return Full path (free after use) | |
150 | */ | |
151 | char * | |
152 | xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum); | |
153 | ||
154 | /* | |
155 | * Lookup a file in a directory | |
156 | * | |
157 | * @param xfs filesystem instance | |
158 | * @param inum Inumber of the directory | |
159 | * @param name Name of the file to lookup | |
160 | * @return Pointer to XFS_INODE if found | |
161 | */ | |
162 | XFS_INODE * | |
163 | xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name); | |
164 | ||
165 | /* | |
166 | * Inquires as to whether a directory is empty. | |
167 | * | |
168 | * The caller must check that the inum is actually a directory, or | |
169 | * the result is undefined. | |
170 | * | |
171 | * @param xfs filesystem instance | |
172 | * @param inum Inumber of the directory | |
173 | * @return True if the directory is empty | |
174 | */ | |
175 | int | |
176 | xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum); | |
177 | ||
178 | /* | |
179 | * Inquires as to whether an entry is under a directory. | |
180 | * | |
181 | * This can be used to check for invalid renames, where we try to | |
182 | * rename a directory into one of its sub-directories. | |
183 | * | |
184 | * Returned value means one of the following:- | |
185 | * 0 Entry is not related to the directory | |
186 | * 1 Entry is an immediate member of the directory | |
187 | * 2.. Entry is a few levels below the directory | |
188 | * | |
189 | * @param xfs filesystem instance | |
190 | * @param dir Inumber of the directory | |
191 | * @param entry Inumber of the entry | |
192 | * @return Nesting count of entry in the directory, or 0 for | |
193 | * no nesting | |
194 | */ | |
195 | unsigned int | |
196 | xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry); | |
197 | ||
198 | /* | |
199 | * Opens a directory for reading | |
200 | * | |
201 | * @param xfs filesystem instance | |
202 | * @param dir Inumber of the directory | |
203 | * @return handle to be passed to xfs_readdir() and xfs_closedir() | |
204 | */ | |
205 | struct xfs_dir_handle * | |
206 | xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir); | |
207 | ||
208 | /* | |
209 | * Gets the next entry from a directory | |
210 | * | |
211 | * This function is safe to call while the filesystem is being modified. | |
212 | * Whether files added or removed from the directory in question are | |
213 | * returned or not is unspecified by this interface. | |
214 | * | |
215 | * @param xfs filesystem instance | |
216 | * @param handle Handle from xfs_opendir | |
217 | * @param off Offset (by reference). Pass in zero to get the first | |
218 | * entry. After the call, the offset is updated so that | |
219 | * the next call gets the next entry. | |
220 | * | |
221 | * @return pointer to details of file entry, or NULL if no more | |
222 | * entries are available. | |
223 | */ | |
224 | XFS_INODE * | |
225 | xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off); | |
226 | ||
227 | ||
228 | /* | |
229 | * Closes a directory opened for reading | |
230 | * | |
231 | * @param xfs filesystem instance | |
232 | * @param handle Earlier result of readdir() call | |
233 | */ | |
234 | void | |
235 | xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle); | |
236 | ||
237 | /* | |
238 | * Increment the file open count | |
239 | * | |
240 | * The file open count is used to be sure when an entry can be deleted from | |
241 | * the data structures. It allows us to remove an entry while still retaining | |
242 | * enough state to manage the file | |
243 | * | |
244 | * This call is only necessary for regular files - not directories | |
245 | * | |
246 | * @param xfs filesystem instance | |
247 | * @param inum File to increment the count of | |
248 | */ | |
249 | void | |
250 | xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum); | |
251 | ||
252 | /* | |
253 | * Decrement the file open count | |
254 | * | |
255 | * This call will ensure that deleted inodes are cleared up at the appropriate | |
256 | * time. | |
257 | * | |
258 | * This call is only necessary for regular files - not directories | |
259 | * | |
260 | * @param xfs filesystem instance | |
261 | * @param inum File to decrement the count of | |
262 | */ | |
263 | void | |
264 | xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum); | |
265 | ||
266 | /* | |
267 | * Return the file open count for a regular file | |
268 | */ | |
269 | unsigned int | |
270 | xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum); | |
271 | ||
272 | /* | |
273 | * Deletes all entries with the matching device id | |
274 | * | |
275 | * Files are deleted even if they are open | |
276 | * | |
277 | * The specified device_id must be non-zero so that the root | |
278 | * filesystem is not deleted! | |
279 | * | |
280 | * @param device_id Device ID | |
281 | */ | |
282 | void | |
283 | xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id); | |
284 | ||
285 | /* | |
286 | * Check an entry move will be successful | |
287 | * | |
288 | * A move will fail if:- | |
289 | * - Any of the parameters are invalid | |
290 | * - if the entry is a directory, and the new parent is below the | |
291 | * entry in the existing hierarchy. | |
292 | * | |
293 | * @param xfs filesystem instance | |
294 | * @param inum Inumber of entry | |
295 | * @param new_parent New parent | |
296 | * @param name New name | |
297 | * | |
298 | * @result != 0 if all looks OK | |
299 | */ | |
300 | int | |
301 | xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum, | |
302 | fuse_ino_t new_parent_inum, const char *name); | |
303 | ||
304 | ||
305 | /* | |
306 | * Move (rename) an entry | |
307 | * | |
308 | * @param xfs filesystem instance | |
309 | * @param inum Inumber of entry | |
310 | * @param new_parent New parent | |
311 | * @param name New name | |
312 | * | |
313 | * @result 0, or a suitable errno value. | |
314 | */ | |
315 | int | |
316 | xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum, | |
317 | fuse_ino_t new_parent_inum, const char *name); | |
318 | ||
319 | #endif /* XRDP_FUSE */ | |
320 | #endif /* _CHANSRV_XFS */ |
184 | 184 | #define LOG_LEVEL LOG_ERROR |
185 | 185 | |
186 | 186 | #define log_error(_params...) \ |
187 | { \ | |
188 | g_write("[%10.10u]: CLIPBOARD %s: %d : ERROR: ", \ | |
189 | g_time3(), __func__, __LINE__); \ | |
190 | g_writeln (_params); \ | |
191 | } | |
187 | { \ | |
188 | g_write("[%10.10u]: CLIPBOARD %s: %d : ERROR: ", \ | |
189 | g_time3(), __func__, __LINE__); \ | |
190 | g_writeln (_params); \ | |
191 | } | |
192 | 192 | |
193 | 193 | #define log_always(_params...) \ |
194 | { \ | |
195 | g_write("[%10.10u]: CLIPBOARD %s: %d : ALWAYS: ", \ | |
196 | g_time3(), __func__, __LINE__); \ | |
197 | g_writeln (_params); \ | |
198 | } | |
194 | { \ | |
195 | g_write("[%10.10u]: CLIPBOARD %s: %d : ALWAYS: ", \ | |
196 | g_time3(), __func__, __LINE__); \ | |
197 | g_writeln (_params); \ | |
198 | } | |
199 | 199 | |
200 | 200 | #define log_info(_params...) \ |
201 | { \ | |
202 | if (LOG_INFO <= LOG_LEVEL) \ | |
203 | { \ | |
204 | g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ | |
205 | g_time3(), __func__, __LINE__); \ | |
206 | g_writeln (_params); \ | |
207 | } \ | |
208 | } | |
201 | { \ | |
202 | if (LOG_INFO <= LOG_LEVEL) \ | |
203 | { \ | |
204 | g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ | |
205 | g_time3(), __func__, __LINE__); \ | |
206 | g_writeln (_params); \ | |
207 | } \ | |
208 | } | |
209 | 209 | |
210 | 210 | #define log_debug(_params...) \ |
211 | { \ | |
212 | if (LOG_DEBUG <= LOG_LEVEL) \ | |
213 | { \ | |
214 | g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ | |
215 | g_time3(), __func__, __LINE__); \ | |
216 | g_writeln (_params); \ | |
217 | } \ | |
218 | } | |
211 | { \ | |
212 | if (LOG_DEBUG <= LOG_LEVEL) \ | |
213 | { \ | |
214 | g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ | |
215 | g_time3(), __func__, __LINE__); \ | |
216 | g_writeln (_params); \ | |
217 | } \ | |
218 | } | |
219 | 219 | |
220 | 220 | static char g_bmp_image_header[] = |
221 | 221 | { |
233 | 233 | extern tbus g_x_wait_obj; /* in xcommon.c */ |
234 | 234 | extern Screen *g_screen; /* in xcommon.c */ |
235 | 235 | extern int g_screen_num; /* in xcommon.c */ |
236 | ||
237 | extern int g_restrict_outbound_clipboard; /* in chansrv.c */ | |
236 | 238 | |
237 | 239 | int g_clip_up = 0; |
238 | 240 | |
285 | 287 | static char g_last_atom_name[256] = ""; |
286 | 288 | |
287 | 289 | /*****************************************************************************/ |
288 | static char* | |
290 | static char * | |
289 | 291 | get_atom_text(Atom atom) |
290 | 292 | { |
291 | char* name; | |
293 | char *name; | |
292 | 294 | int failed; |
293 | 295 | |
294 | 296 | failed = 0; |
404 | 406 | if (rv == 0) |
405 | 407 | { |
406 | 408 | log_debug("clipboard_init: g_xfixes_event_base %d", |
407 | g_xfixes_event_base); | |
409 | g_xfixes_event_base); | |
408 | 410 | st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); |
409 | 411 | log_debug("clipboard_init st %d, maj %d min %d", st, |
410 | ver_maj, ver_min); | |
412 | ver_maj, ver_min); | |
411 | 413 | g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", |
412 | 414 | False); |
413 | 415 | g_get_time_atom = XInternAtom(g_display, "XRDP_GET_TIME_ATOM", |
427 | 429 | if (g_image_bmp_atom == None) |
428 | 430 | { |
429 | 431 | log_error("clipboard_init: g_image_bmp_atom was " |
430 | "not allocated"); | |
432 | "not allocated"); | |
431 | 433 | } |
432 | 434 | |
433 | 435 | g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), |
462 | 464 | s_mark_end(s); |
463 | 465 | size = (int)(s->end - s->data); |
464 | 466 | log_debug("clipboard_init: data out, sending " |
465 | "CB_CLIP_CAPS (clip_msg_id = 1)"); | |
467 | "CB_CLIP_CAPS (clip_msg_id = 1)"); | |
466 | 468 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
467 | 469 | if (rv != 0) |
468 | 470 | { |
469 | 471 | log_error("clipboard_init: send_channel_data failed " |
470 | "rv = %d", rv); | |
472 | "rv = %d", rv); | |
471 | 473 | rv = 4; |
472 | 474 | } |
473 | 475 | } |
483 | 485 | s_mark_end(s); |
484 | 486 | size = (int)(s->end - s->data); |
485 | 487 | log_debug("clipboard_init: data out, sending " |
486 | "CB_MONITOR_READY (clip_msg_id = 1)"); | |
488 | "CB_MONITOR_READY (clip_msg_id = 1)"); | |
487 | 489 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
488 | 490 | if (rv != 0) |
489 | 491 | { |
490 | 492 | log_error("clipboard_init: send_channel_data failed " |
491 | "rv = %d", rv); | |
493 | "rv = %d", rv); | |
492 | 494 | rv = 4; |
493 | 495 | } |
494 | 496 | } |
553 | 555 | s_mark_end(s); |
554 | 556 | size = (int)(s->end - s->data); |
555 | 557 | log_debug("clipboard_send_data_request: data out, sending " |
556 | "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)"); | |
558 | "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)"); | |
557 | 559 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
558 | 560 | free_stream(s); |
559 | 561 | return rv; |
576 | 578 | s_mark_end(s); |
577 | 579 | size = (int)(s->end - s->data); |
578 | 580 | log_debug("clipboard_send_format_ack: data out, sending " |
579 | "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)"); | |
581 | "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)"); | |
580 | 582 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
581 | 583 | free_stream(s); |
582 | 584 | return rv; |
714 | 716 | break; |
715 | 717 | default: |
716 | 718 | log_debug("clipboard_send_format_announce: unknown " |
717 | "xrdp_clip_type %d", xrdp_clip_type); | |
719 | "xrdp_clip_type %d", xrdp_clip_type); | |
718 | 720 | break; |
719 | 721 | } |
720 | 722 | } |
758 | 760 | break; |
759 | 761 | default: |
760 | 762 | log_debug("clipboard_send_format_announce: unknown " |
761 | "xrdp_clip_type %d", xrdp_clip_type); | |
763 | "xrdp_clip_type %d", xrdp_clip_type); | |
762 | 764 | break; |
763 | 765 | } |
764 | 766 | } |
773 | 775 | size = (int)(s->end - s->data); |
774 | 776 | //g_hexdump(s->data, size); |
775 | 777 | log_debug("clipboard_send_format_announce: data out, sending " |
776 | "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"); | |
778 | "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"); | |
777 | 779 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
778 | 780 | free_stream(s); |
779 | 781 | return rv; |
788 | 790 | int rv; |
789 | 791 | |
790 | 792 | log_debug("clipboard_send_data_response_for_image: data_size %d", |
791 | data_size); | |
793 | data_size); | |
792 | 794 | make_stream(s); |
793 | 795 | init_stream(s, 64 + data_size); |
794 | 796 | out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ |
813 | 815 | int num_chars; |
814 | 816 | |
815 | 817 | log_debug("clipboard_send_data_response_for_text: data_size %d", |
816 | data_size); | |
818 | data_size); | |
817 | 819 | //g_hexdump(data, data_size); |
818 | 820 | num_chars = g_mbstowcs(0, data, 0); |
819 | 821 | if (num_chars < 0) |
820 | 822 | { |
821 | 823 | log_error("clipboard_send_data_response_for_text: " |
822 | "bad string"); | |
824 | "bad string"); | |
823 | 825 | num_chars = 0; |
824 | 826 | } |
825 | 827 | log_debug("clipboard_send_data_response_for_text: data_size %d " |
826 | "num_chars %d", data_size, num_chars); | |
828 | "num_chars %d", data_size, num_chars); | |
827 | 829 | make_stream(s); |
828 | 830 | init_stream(s, 64 + num_chars * 2); |
829 | 831 | out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ |
832 | 834 | if (clipboard_out_unicode(s, data, num_chars) != num_chars * 2) |
833 | 835 | { |
834 | 836 | log_error("clipboard_send_data_response_for_text: error " |
835 | "clipboard_out_unicode didn't write right number of bytes"); | |
837 | "clipboard_out_unicode didn't write right number of bytes"); | |
836 | 838 | } |
837 | 839 | out_uint16_le(s, 0); /* nil for string */ |
838 | 840 | out_uint32_le(s, 0); |
839 | 841 | s_mark_end(s); |
840 | 842 | size = (int)(s->end - s->data); |
841 | 843 | log_debug("clipboard_send_data_response_for_text: data out, " |
842 | "sending CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d " | |
843 | "num_chars %d", size, num_chars); | |
844 | "sending CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d " | |
845 | "num_chars %d", size, num_chars); | |
844 | 846 | rv = send_channel_data(g_cliprdr_chan_id, s->data, size); |
845 | 847 | free_stream(s); |
846 | 848 | return rv; |
868 | 870 | else |
869 | 871 | { |
870 | 872 | log_debug("clipboard_send_data_response: unknown " |
871 | "xrdp_clip_type %d", xrdp_clip_type); | |
873 | "xrdp_clip_type %d", xrdp_clip_type); | |
872 | 874 | } |
873 | 875 | } |
874 | 876 | else |
907 | 909 | long val1[2]; |
908 | 910 | |
909 | 911 | log_debug("clipboard_provide_selection_c2s: bytes %d", |
910 | g_clip_c2s.total_bytes); | |
912 | g_clip_c2s.total_bytes); | |
911 | 913 | if (g_clip_c2s.total_bytes < g_incr_max_req_size) |
912 | 914 | { |
913 | 915 | XChangeProperty(g_display, req->requestor, req->property, |
933 | 935 | g_clip_c2s.property = req->property; |
934 | 936 | g_clip_c2s.window = req->requestor; |
935 | 937 | log_debug("clipboard_provide_selection_c2s: start INCR property %s " |
936 | "type %s", get_atom_text(req->property), | |
937 | get_atom_text(type)); | |
938 | "type %s", get_atom_text(req->property), | |
939 | get_atom_text(type)); | |
938 | 940 | val1[0] = g_clip_c2s.total_bytes; |
939 | 941 | val1[1] = 0; |
940 | 942 | XChangeProperty(g_display, req->requestor, req->property, |
1019 | 1021 | char *holdp; |
1020 | 1022 | |
1021 | 1023 | log_debug("clipboard_process_format_announce: " |
1022 | "CLIPRDR_FORMAT_ANNOUNCE"); | |
1024 | "CLIPRDR_FORMAT_ANNOUNCE"); | |
1023 | 1025 | log_debug("clipboard_process_format_announce %d", clip_msg_len); |
1024 | 1026 | clipboard_send_format_ack(); |
1025 | 1027 | |
1051 | 1053 | clip_msg_len -= 32; |
1052 | 1054 | } |
1053 | 1055 | log_debug("clipboard_process_format_announce: formatId 0x%8.8x " |
1054 | "wszFormatName [%s] clip_msg_len %d", formatId, desc, | |
1055 | clip_msg_len); | |
1056 | "wszFormatName [%s] clip_msg_len %d", formatId, desc, | |
1057 | clip_msg_len); | |
1056 | 1058 | if (g_num_formatIds <= 15) |
1057 | 1059 | { |
1058 | 1060 | g_formatIds[g_num_formatIds] = formatId; |
1072 | 1074 | } |
1073 | 1075 | |
1074 | 1076 | if ((g_num_formatIds > 0) && |
1075 | (g_clip_c2s.incr_in_progress == 0) && /* don't interrupt incr */ | |
1076 | (g_clip_s2c.incr_in_progress == 0)) | |
1077 | (g_clip_c2s.incr_in_progress == 0) && /* don't interrupt incr */ | |
1078 | (g_clip_s2c.incr_in_progress == 0)) | |
1077 | 1079 | { |
1078 | 1080 | if (clipboard_set_selection_owner() != 0) |
1079 | 1081 | { |
1080 | 1082 | log_error("clipboard_process_format_announce: " |
1081 | "XSetSelectionOwner failed"); | |
1083 | "XSetSelectionOwner failed"); | |
1082 | 1084 | } |
1083 | 1085 | } |
1084 | 1086 | |
1129 | 1131 | int requestedFormatId; |
1130 | 1132 | |
1131 | 1133 | log_debug("clipboard_process_data_request: " |
1132 | "CLIPRDR_DATA_REQUEST"); | |
1134 | "CLIPRDR_DATA_REQUEST"); | |
1133 | 1135 | log_debug("clipboard_process_data_request:"); |
1134 | 1136 | log_debug(" %d", g_clip_s2c.xrdp_clip_type); |
1135 | 1137 | in_uint32_le(s, requestedFormatId); |
1145 | 1147 | else |
1146 | 1148 | { |
1147 | 1149 | log_debug("clipboard_process_data_request: CB_FORMAT_FILE, " |
1148 | "calling XConvertSelection to g_utf8_atom"); | |
1150 | "calling XConvertSelection to g_utf8_atom"); | |
1149 | 1151 | g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE; |
1150 | 1152 | XConvertSelection(g_display, g_clipboard_atom, g_clip_s2c.type, |
1151 | 1153 | g_clip_property_atom, g_wnd, CurrentTime); |
1161 | 1163 | else |
1162 | 1164 | { |
1163 | 1165 | log_debug("clipboard_process_data_request: CB_FORMAT_DIB, " |
1164 | "calling XConvertSelection to g_image_bmp_atom"); | |
1166 | "calling XConvertSelection to g_image_bmp_atom"); | |
1165 | 1167 | g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP; |
1166 | 1168 | XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom, |
1167 | 1169 | g_clip_property_atom, g_wnd, CurrentTime); |
1177 | 1179 | else |
1178 | 1180 | { |
1179 | 1181 | log_debug("clipboard_process_data_request: CB_FORMAT_UNICODETEXT, " |
1180 | "calling XConvertSelection to g_utf8_atom"); | |
1182 | "calling XConvertSelection to g_utf8_atom"); | |
1181 | 1183 | g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT; |
1182 | 1184 | XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, |
1183 | 1185 | g_clip_property_atom, g_wnd, CurrentTime); |
1185 | 1187 | break; |
1186 | 1188 | default: |
1187 | 1189 | log_debug("clipboard_process_data_request: unknown type %d", |
1188 | requestedFormatId); | |
1190 | requestedFormatId); | |
1189 | 1191 | clipboard_send_data_response_failed(); |
1190 | 1192 | break; |
1191 | 1193 | } |
1200 | 1202 | clipboard data. */ |
1201 | 1203 | static int |
1202 | 1204 | clipboard_process_data_response_for_image(struct stream *s, |
1203 | int clip_msg_status, | |
1204 | int clip_msg_len) | |
1205 | int clip_msg_status, | |
1206 | int clip_msg_len) | |
1205 | 1207 | { |
1206 | 1208 | XSelectionRequestEvent *lxev; |
1207 | 1209 | int len; |
1208 | 1210 | |
1209 | 1211 | log_debug("clipboard_process_data_response_for_image: " |
1210 | "CLIPRDR_DATA_RESPONSE_FOR_IMAGE"); | |
1212 | "CLIPRDR_DATA_RESPONSE_FOR_IMAGE"); | |
1211 | 1213 | lxev = &g_saved_selection_req_event; |
1212 | 1214 | len = (int)(s->end - s->p); |
1213 | 1215 | if (len < 1) |
1230 | 1232 | g_memcpy(g_clip_c2s.data, g_bmp_image_header, 14); |
1231 | 1233 | in_uint8a(s, g_clip_c2s.data + 14, len); |
1232 | 1234 | log_debug("clipboard_process_data_response_for_image: calling " |
1233 | "clipboard_provide_selection_c2s"); | |
1235 | "clipboard_provide_selection_c2s"); | |
1234 | 1236 | clipboard_provide_selection_c2s(lxev, lxev->target); |
1235 | 1237 | return 0; |
1236 | 1238 | } |
1258 | 1260 | if (g_clip_c2s.xrdp_clip_type == XRDP_CB_BITMAP) |
1259 | 1261 | { |
1260 | 1262 | clipboard_process_data_response_for_image(s, clip_msg_status, |
1261 | clip_msg_len); | |
1263 | clip_msg_len); | |
1262 | 1264 | return 0; |
1263 | 1265 | } |
1264 | 1266 | if (g_clip_c2s.xrdp_clip_type == XRDP_CB_FILE) |
1286 | 1288 | return 0; |
1287 | 1289 | } |
1288 | 1290 | log_debug("clipboard_process_data_response: " |
1289 | "CLIPRDR_DATA_RESPONSE"); | |
1291 | "CLIPRDR_DATA_RESPONSE"); | |
1290 | 1292 | len = (int)(s->end - s->p); |
1291 | 1293 | if (len < 1) |
1292 | 1294 | { |
1361 | 1363 | in_uint32_le(s, version); /* version */ |
1362 | 1364 | in_uint32_le(s, flags); /* generalFlags */ |
1363 | 1365 | log_debug("clipboard_process_clip_caps: " |
1364 | "g_cliprdr_version %d version %d " | |
1365 | "g_cliprdr_flags 0x%x flags 0x%x", | |
1366 | g_cliprdr_version, version, | |
1367 | g_cliprdr_flags, flags); | |
1366 | "g_cliprdr_version %d version %d " | |
1367 | "g_cliprdr_flags 0x%x flags 0x%x", | |
1368 | g_cliprdr_version, version, | |
1369 | g_cliprdr_flags, flags); | |
1368 | 1370 | if (version < g_cliprdr_version) |
1369 | 1371 | { |
1370 | 1372 | g_cliprdr_version = version; |
1373 | 1375 | break; |
1374 | 1376 | default: |
1375 | 1377 | log_debug("clipboard_process_clip_caps: unknown " |
1376 | "capabilitySetType %d", capabilitySetType); | |
1378 | "capabilitySetType %d", capabilitySetType); | |
1377 | 1379 | break; |
1378 | 1380 | } |
1379 | 1381 | s->p = holdp + lengthCapability; |
1551 | 1553 | if (!g_clip_up) |
1552 | 1554 | { |
1553 | 1555 | log_error("aborting clipboard_data_in - clipboard has not " |
1554 | "been initialized"); | |
1556 | "been initialized"); | |
1555 | 1557 | /* we return 0 here to indicate no protocol problem occurred */ |
1556 | 1558 | return 0; |
1557 | 1559 | } |
1558 | 1560 | |
1559 | 1561 | log_debug("clipboard_data_in: chan_id %d " |
1560 | "chan_flags 0x%x length %d total_length %d " | |
1561 | "in_request %d g_ins->size %d", | |
1562 | chan_id, chan_flags, length, total_length, | |
1563 | g_clip_c2s.in_request, g_ins->size); | |
1562 | "chan_flags 0x%x length %d total_length %d " | |
1563 | "in_request %d g_ins->size %d", | |
1564 | chan_id, chan_flags, length, total_length, | |
1565 | g_clip_c2s.in_request, g_ins->size); | |
1564 | 1566 | |
1565 | 1567 | if (g_clip_c2s.doing_response_ss) |
1566 | 1568 | { |
1620 | 1622 | in_uint32_le(ls, clip_msg_len); |
1621 | 1623 | |
1622 | 1624 | log_debug("clipboard_data_in: clip_msg_id %d " |
1623 | "clip_msg_status %d clip_msg_len %d", | |
1624 | clip_msg_id, clip_msg_status, clip_msg_len); | |
1625 | "clip_msg_status %d clip_msg_len %d", | |
1626 | clip_msg_id, clip_msg_status, clip_msg_len); | |
1625 | 1627 | rv = 0; |
1626 | 1628 | |
1627 | 1629 | log_debug("clipboard_data_in: %d", clip_msg_id); |
1628 | 1630 | switch (clip_msg_id) |
1629 | 1631 | { |
1630 | /* sent by client or server when its local system clipboard is */ | |
1631 | /* updated with new clipboard data; contains Clipboard Format ID */ | |
1632 | /* and name pairs of new Clipboard Formats on the clipboard. */ | |
1632 | /* sent by client or server when its local system clipboard is */ | |
1633 | /* updated with new clipboard data; contains Clipboard Format ID */ | |
1634 | /* and name pairs of new Clipboard Formats on the clipboard. */ | |
1633 | 1635 | case CB_FORMAT_LIST: /* 2 CLIPRDR_FORMAT_ANNOUNCE */ |
1634 | 1636 | rv = clipboard_process_format_announce(ls, clip_msg_status, |
1635 | 1637 | clip_msg_len); |
1636 | 1638 | break; |
1637 | /* response to CB_FORMAT_LIST; used to indicate whether */ | |
1638 | /* processing of the Format List PDU was successful */ | |
1639 | /* response to CB_FORMAT_LIST; used to indicate whether */ | |
1640 | /* processing of the Format List PDU was successful */ | |
1639 | 1641 | case CB_FORMAT_LIST_RESPONSE: /* 3 CLIPRDR_FORMAT_ACK */ |
1640 | 1642 | rv = clipboard_process_format_ack(ls, clip_msg_status, |
1641 | 1643 | clip_msg_len); |
1642 | 1644 | break; |
1643 | /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ | |
1644 | /* of the formats that was listed in CB_FORMAT_LIST */ | |
1645 | /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ | |
1646 | /* of the formats that was listed in CB_FORMAT_LIST */ | |
1645 | 1647 | case CB_FORMAT_DATA_REQUEST: /* 4 CLIPRDR_DATA_REQUEST */ |
1646 | 1648 | rv = clipboard_process_data_request(ls, clip_msg_status, |
1647 | 1649 | clip_msg_len); |
1648 | 1650 | break; |
1649 | /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ | |
1650 | /* whether processing of the CB_FORMAT_DATA_REQUEST was */ | |
1651 | /* successful; if processing was successful, */ | |
1652 | /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ | |
1653 | /* clipboard data. */ | |
1651 | /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ | |
1652 | /* whether processing of the CB_FORMAT_DATA_REQUEST was */ | |
1653 | /* successful; if processing was successful, */ | |
1654 | /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ | |
1655 | /* clipboard data. */ | |
1654 | 1656 | case CB_FORMAT_DATA_RESPONSE: /* 5 CLIPRDR_DATA_RESPONSE */ |
1655 | 1657 | rv = clipboard_process_data_response(ls, clip_msg_status, |
1656 | 1658 | clip_msg_len); |
1670 | 1672 | default: |
1671 | 1673 | log_debug("clipboard_data_in: unknown clip_msg_id %d", clip_msg_id); |
1672 | 1674 | log_error("clipboard_data_in: unknown clip_msg_id %d", |
1673 | clip_msg_id); | |
1675 | clip_msg_id); | |
1674 | 1676 | break; |
1675 | 1677 | } |
1676 | 1678 | |
1702 | 1704 | lxevent = (XFixesSelectionNotifyEvent *)xevent; |
1703 | 1705 | log_debug("clipboard_event_selection_owner_notify: 0x%lx", lxevent->owner); |
1704 | 1706 | log_debug("clipboard_event_selection_owner_notify: " |
1705 | "window %ld subtype %d owner %ld g_wnd %ld", | |
1706 | lxevent->window, lxevent->subtype, lxevent->owner, g_wnd); | |
1707 | "window %ld subtype %d owner %ld g_wnd %ld", | |
1708 | lxevent->window, lxevent->subtype, lxevent->owner, g_wnd); | |
1707 | 1709 | |
1708 | 1710 | if (lxevent->owner == g_wnd) |
1709 | 1711 | { |
1710 | 1712 | log_debug("clipboard_event_selection_owner_notify: matches g_wnd"); |
1711 | 1713 | log_debug("clipboard_event_selection_owner_notify: skipping, " |
1712 | "owner == g_wnd"); | |
1714 | "owner == g_wnd"); | |
1713 | 1715 | g_got_selection = 1; |
1714 | 1716 | return 0; |
1715 | 1717 | } |
1716 | 1718 | |
1717 | 1719 | g_got_selection = 0; |
1718 | 1720 | if (lxevent->owner != 0) /* nil owner comes when selection */ |
1719 | { /* window is closed */ | |
1721 | { | |
1722 | /* window is closed */ | |
1720 | 1723 | XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, |
1721 | 1724 | g_clip_property_atom, g_wnd, lxevent->timestamp); |
1722 | 1725 | } |
1870 | 1873 | if (lxevent->property == None) |
1871 | 1874 | { |
1872 | 1875 | log_error("clipboard_event_selection_notify: clip could " |
1873 | "not be converted"); | |
1876 | "not be converted"); | |
1874 | 1877 | rv = 1; |
1875 | 1878 | } |
1876 | 1879 | |
1877 | 1880 | if (rv == 0) |
1878 | 1881 | { |
1879 | 1882 | log_debug("clipboard_event_selection_notify: wnd 0x%lx prop %s", |
1880 | lxevent->requestor, | |
1881 | get_atom_text(lxevent->property)); | |
1883 | lxevent->requestor, | |
1884 | get_atom_text(lxevent->property)); | |
1882 | 1885 | rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, |
1883 | 1886 | &type, &fmt, |
1884 | 1887 | &n_items, &data, &data_size); |
1885 | 1888 | if (rv != 0) |
1886 | 1889 | { |
1887 | 1890 | log_error("clipboard_event_selection_notify: " |
1888 | "clipboard_get_window_property failed error %d", rv); | |
1891 | "clipboard_get_window_property failed error %d", rv); | |
1889 | 1892 | return 0; |
1890 | 1893 | } |
1891 | 1894 | //g_hexdump(data, data_size); |
1895 | 1898 | /* nothing more to do here, the data is coming in through |
1896 | 1899 | PropertyNotify */ |
1897 | 1900 | log_debug("clipboard_event_selection_notify: type is INCR " |
1898 | "data_size %d property name %s type %s", data_size, | |
1899 | get_atom_text(lxevent->property), | |
1900 | get_atom_text(lxevent->type)); | |
1901 | "data_size %d property name %s type %s", data_size, | |
1902 | get_atom_text(lxevent->property), | |
1903 | get_atom_text(lxevent->type)); | |
1901 | 1904 | g_clip_s2c.incr_in_progress = 1; |
1902 | 1905 | g_clip_s2c.property = lxevent->property; |
1903 | 1906 | g_clip_s2c.type = lxevent->target; |
1927 | 1930 | "clipboard_event_selection_notify: 0x%lx %s 0x%lx", |
1928 | 1931 | atom, get_atom_text(atom), XA_STRING)); |
1929 | 1932 | log_debug("clipboard_event_selection_notify: 0x%lx %s", |
1930 | atom, get_atom_text(atom)); | |
1933 | atom, get_atom_text(atom)); | |
1931 | 1934 | if (atom == g_utf8_atom) |
1932 | 1935 | { |
1933 | 1936 | got_utf8 = 1; |
1954 | 1957 | else |
1955 | 1958 | { |
1956 | 1959 | log_error("clipboard_event_selection_notify: error, " |
1957 | "target is 'TARGETS' and type[%ld] or fmt[%d] not right, " | |
1958 | "should be type[%ld], fmt[%d]", type, fmt, XA_ATOM, 32); | |
1960 | "target is 'TARGETS' and type[%ld] or fmt[%d] not right, " | |
1961 | "should be type[%ld], fmt[%d]", type, fmt, XA_ATOM, 32); | |
1959 | 1962 | } |
1960 | 1963 | } |
1961 | 1964 | else if (lxevent->target == g_utf8_atom) |
1962 | 1965 | { |
1963 | 1966 | log_debug("clipboard_event_selection_notify: UTF8_STRING " |
1964 | "data_size %d", data_size); | |
1967 | "data_size %d", data_size); | |
1965 | 1968 | log_debug("clipboard_event_selection_notify: UTF8_STRING " |
1966 | "data_size %d", data_size); | |
1969 | "data_size %d", data_size); | |
1967 | 1970 | if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) |
1968 | 1971 | { |
1969 | 1972 | g_free(g_clip_s2c.data); |
1986 | 1989 | else if (lxevent->target == XA_STRING) |
1987 | 1990 | { |
1988 | 1991 | log_debug("clipboard_event_selection_notify: XA_STRING " |
1989 | "data_size %d", data_size); | |
1992 | "data_size %d", data_size); | |
1990 | 1993 | log_debug("clipboard_event_selection_notify: XA_STRING " |
1991 | "data_size %d", data_size); | |
1994 | "data_size %d", data_size); | |
1992 | 1995 | if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) |
1993 | 1996 | { |
1994 | 1997 | g_free(g_clip_s2c.data); |
2003 | 2006 | else if (lxevent->target == g_image_bmp_atom) |
2004 | 2007 | { |
2005 | 2008 | log_debug("clipboard_event_selection_notify: image/bmp " |
2006 | "data_size %d", data_size); | |
2009 | "data_size %d", data_size); | |
2007 | 2010 | log_debug("clipboard_event_selection_notify: image/bmp " |
2008 | "data_size %d", data_size); | |
2011 | "data_size %d", data_size); | |
2009 | 2012 | if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 14)) |
2010 | 2013 | { |
2011 | 2014 | g_free(g_clip_s2c.data); |
2019 | 2022 | else if (lxevent->target == g_file_atom1) |
2020 | 2023 | { |
2021 | 2024 | log_debug("clipboard_event_selection_notify: text/uri-list " |
2022 | "data_size %d", data_size); | |
2025 | "data_size %d", data_size); | |
2023 | 2026 | log_debug("clipboard_event_selection_notify: text/uri-list " |
2024 | "data_size %d", data_size); | |
2027 | "data_size %d", data_size); | |
2025 | 2028 | if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) |
2026 | 2029 | { |
2027 | 2030 | g_free(g_clip_s2c.data); |
2036 | 2039 | else if (lxevent->target == g_file_atom2) |
2037 | 2040 | { |
2038 | 2041 | log_debug("clipboard_event_selection_notify: text/uri-list " |
2039 | "data_size %d", data_size); | |
2042 | "data_size %d", data_size); | |
2040 | 2043 | log_debug("clipboard_event_selection_notify: text/uri-list " |
2041 | "data_size %d", data_size); | |
2044 | "data_size %d", data_size); | |
2042 | 2045 | if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) |
2043 | 2046 | { |
2044 | 2047 | g_free(g_clip_s2c.data); |
2053 | 2056 | else |
2054 | 2057 | { |
2055 | 2058 | log_error("clipboard_event_selection_notify: " |
2056 | "unknown target"); | |
2059 | "unknown target"); | |
2057 | 2060 | } |
2058 | 2061 | } |
2059 | 2062 | else |
2060 | 2063 | { |
2061 | 2064 | log_error("clipboard_event_selection_notify: " |
2062 | "unknown selection"); | |
2065 | "unknown selection"); | |
2063 | 2066 | } |
2064 | 2067 | } |
2065 | 2068 | |
2144 | 2147 | lxev = (XSelectionRequestEvent *)xevent; |
2145 | 2148 | log_debug("clipboard_event_selection_request: 0x%lx", lxev->property); |
2146 | 2149 | log_debug("clipboard_event_selection_request: g_wnd %ld, " |
2147 | ".requestor %ld .owner %ld .selection %ld '%s' .target %ld .property %ld", | |
2148 | g_wnd, lxev->requestor, lxev->owner, lxev->selection, | |
2149 | get_atom_text(lxev->selection), | |
2150 | lxev->target, lxev->property); | |
2150 | ".requestor %ld .owner %ld .selection %ld '%s' .target %ld .property %ld", | |
2151 | g_wnd, lxev->requestor, lxev->owner, lxev->selection, | |
2152 | get_atom_text(lxev->selection), | |
2153 | lxev->target, lxev->property); | |
2151 | 2154 | |
2152 | 2155 | if (lxev->property == None) |
2153 | 2156 | { |
2154 | 2157 | log_debug("clipboard_event_selection_request: lxev->property " |
2155 | "is None"); | |
2158 | "is None"); | |
2156 | 2159 | log_debug("clipboard_event_selection_request: " |
2157 | "lxev->property is None"); | |
2160 | "lxev->property is None"); | |
2158 | 2161 | } |
2159 | 2162 | else if (lxev->target == g_targets_atom) |
2160 | 2163 | { |
2161 | 2164 | log_debug("clipboard_event_selection_request: g_targets_atom"); |
2162 | 2165 | /* requestor is asking what the selection can be converted to */ |
2163 | 2166 | log_debug("clipboard_event_selection_request: " |
2164 | "g_targets_atom"); | |
2167 | "g_targets_atom"); | |
2165 | 2168 | atom_buf[0] = g_targets_atom; |
2166 | 2169 | atom_buf[1] = g_timestamp_atom; |
2167 | 2170 | atom_buf[2] = g_multiple_atom; |
2192 | 2195 | { |
2193 | 2196 | /* requestor is asking the time I got the selection */ |
2194 | 2197 | log_debug("clipboard_event_selection_request: " |
2195 | "g_timestamp_atom"); | |
2198 | "g_timestamp_atom"); | |
2196 | 2199 | atom_buf[0] = g_selection_time; |
2197 | 2200 | atom_buf[1] = 0; |
2198 | 2201 | return clipboard_provide_selection(lxev, XA_INTEGER, 32, |
2202 | 2205 | { |
2203 | 2206 | /* target, property pairs */ |
2204 | 2207 | log_debug("clipboard_event_selection_request: " |
2205 | "g_multiple_atom"); | |
2208 | "g_multiple_atom"); | |
2206 | 2209 | |
2207 | 2210 | xdata = 0; |
2208 | 2211 | if (clipboard_get_window_property(lxev->requestor, lxev->property, |
2210 | 2213 | &xdata_size) == 0) |
2211 | 2214 | { |
2212 | 2215 | log_debug("clipboard_event_selection_request: g_multiple_atom " |
2213 | "n_items %d", n_items); | |
2216 | "n_items %d", n_items); | |
2214 | 2217 | /* todo */ |
2215 | 2218 | g_free(xdata); |
2216 | 2219 | } |
2275 | 2278 | else |
2276 | 2279 | { |
2277 | 2280 | log_debug("clipboard_event_selection_request: unknown " |
2278 | "target %s", get_atom_text(lxev->target)); | |
2281 | "target %s", get_atom_text(lxev->target)); | |
2279 | 2282 | LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: unknown " |
2280 | 2283 | "target %s", get_atom_text(lxev->target))); |
2281 | 2284 | } |
2331 | 2334 | |
2332 | 2335 | log_debug("clipboard_event_property_notify:"); |
2333 | 2336 | log_debug("clipboard_event_property_notify: PropertyNotify .window %ld " |
2334 | ".state %d .atom %ld %s", xevent->xproperty.window, | |
2335 | xevent->xproperty.state, xevent->xproperty.atom, | |
2336 | get_atom_text(xevent->xproperty.atom)); | |
2337 | ".state %d .atom %ld %s", xevent->xproperty.window, | |
2338 | xevent->xproperty.state, xevent->xproperty.atom, | |
2339 | get_atom_text(xevent->xproperty.atom)); | |
2337 | 2340 | |
2338 | 2341 | if (g_clip_c2s.incr_in_progress && |
2339 | 2342 | (xevent->xproperty.window == g_clip_c2s.window) && |
2352 | 2355 | data = (tui8 *)(g_clip_c2s.data + g_clip_c2s.incr_bytes_done); |
2353 | 2356 | data_bytes = g_clip_c2s.read_bytes_done - g_clip_c2s.incr_bytes_done; |
2354 | 2357 | if ((data_bytes < 1) && |
2355 | (g_clip_c2s.read_bytes_done < g_clip_c2s.total_bytes)) | |
2358 | (g_clip_c2s.read_bytes_done < g_clip_c2s.total_bytes)) | |
2356 | 2359 | { |
2357 | 2360 | g_clip_c2s.incr_in_progress = 0; |
2358 | 2361 | return 0; |
2422 | 2425 | else |
2423 | 2426 | { |
2424 | 2427 | log_error("clipboard_event_property_notify: error unknown type %ld", |
2425 | g_clip_s2c.type); | |
2428 | g_clip_s2c.type); | |
2426 | 2429 | clipboard_send_data_response_failed(); |
2427 | 2430 | } |
2428 | 2431 | |
2483 | 2486 | { |
2484 | 2487 | XEvent *lxevent; |
2485 | 2488 | |
2489 | log_debug("clipboard_xevent: event detected"); | |
2490 | ||
2486 | 2491 | if (!g_clip_up) |
2487 | 2492 | { |
2488 | 2493 | return 1; |
2493 | 2498 | switch (lxevent->type) |
2494 | 2499 | { |
2495 | 2500 | case SelectionNotify: |
2496 | clipboard_event_selection_notify(lxevent); | |
2501 | if (g_restrict_outbound_clipboard == 0) | |
2502 | { | |
2503 | clipboard_event_selection_notify(lxevent); | |
2504 | } | |
2505 | else | |
2506 | { | |
2507 | log_debug("outbound clipboard is restricted because of config"); | |
2508 | return 1; | |
2509 | } | |
2497 | 2510 | break; |
2498 | 2511 | case SelectionRequest: |
2499 | 2512 | clipboard_event_selection_request(lxevent); |
53 | 53 | #include "chansrv_fuse.h" |
54 | 54 | #include "devredir.h" |
55 | 55 | #include "smartcard.h" |
56 | #include "ms-rdpefs.h" | |
57 | #include "ms-smb2.h" | |
58 | #include "ms-fscc.h" | |
59 | #include "ms-erref.h" | |
56 | 60 | |
57 | 61 | /* module based logging */ |
58 | 62 | #define LOG_ERROR 0 |
59 | 63 | #define LOG_INFO 1 |
60 | 64 | #define LOG_DEBUG 2 |
61 | 65 | |
62 | #ifndef LOG_LEVEL | |
66 | #undef LOG_LEVEL | |
63 | 67 | #define LOG_LEVEL LOG_ERROR |
64 | #endif | |
65 | 68 | |
66 | 69 | #define log_error(_params...) \ |
67 | 70 | { \ |
89 | 92 | g_writeln (_params); \ |
90 | 93 | } \ |
91 | 94 | } |
95 | ||
96 | /* client minor versions */ | |
97 | #define RDP_CLIENT_50 0x0002 | |
98 | #define RDP_CLIENT_51 0x0005 | |
99 | #define RDP_CLIENT_52 0x000a | |
100 | #define RDP_CLIENT_60_61 0x000c | |
101 | ||
102 | /* Windows time starts on Jan 1, 1601 */ | |
103 | /* Linux time starts on Jan 1, 1970 */ | |
104 | #define EPOCH_DIFF 11644473600LL | |
105 | #define WINDOWS_TO_LINUX_TIME(_t) (((_t) / 10000000) - EPOCH_DIFF); | |
106 | #define LINUX_TO_WINDOWS_TIME(_t) (((_t) + EPOCH_DIFF) * 10000000) | |
107 | ||
108 | /* | |
109 | * CompletionID types, used in IRPs to indicate I/O operation | |
110 | */ | |
111 | ||
112 | enum COMPLETION_TYPE | |
113 | { | |
114 | CID_CREATE_DIR_REQ = 1, | |
115 | CID_DIRECTORY_CONTROL, | |
116 | CID_CREATE_REQ, | |
117 | CID_OPEN_REQ, | |
118 | CID_READ, | |
119 | CID_WRITE, | |
120 | CID_CLOSE, | |
121 | CID_FILE_CLOSE, | |
122 | CID_RMDIR_OR_FILE, | |
123 | CID_RMDIR_OR_FILE_RESP, | |
124 | CID_RENAME_FILE, | |
125 | CID_RENAME_FILE_RESP, | |
126 | CID_LOOKUP, | |
127 | CID_SETATTR | |
128 | }; | |
129 | ||
92 | 130 | |
93 | 131 | /* globals */ |
94 | 132 | extern int g_rdpdr_chan_id; /* in chansrv.c */ |
105 | 143 | tui16 g_client_rdp_version; /* returned by client */ |
106 | 144 | struct stream *g_input_stream = NULL; |
107 | 145 | |
108 | void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length); | |
146 | /* | |
147 | * Local functions called from devredir_proc_device_iocompletion() | |
148 | */ | |
149 | static void devredir_proc_cid_rmdir_or_file(IRP *irp, enum NTSTATUS IoStatus); | |
150 | static void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, | |
151 | enum NTSTATUS IoStatus); | |
152 | static void devredir_proc_cid_rename_file(IRP *irp, enum NTSTATUS IoStatus); | |
153 | static void devredir_proc_cid_rename_file_resp(IRP *irp, | |
154 | enum NTSTATUS IoStatus); | |
155 | static void devredir_proc_cid_lookup( IRP *irp, | |
156 | struct stream *s_in, | |
157 | enum NTSTATUS IoStatus); | |
158 | static void devredir_proc_cid_setattr( IRP *irp, | |
159 | struct stream *s_in, | |
160 | enum NTSTATUS IoStatus); | |
161 | /* Other local functions */ | |
162 | static void devredir_send_server_core_cap_req(void); | |
163 | static void devredir_send_server_clientID_confirm(void); | |
164 | static void devredir_send_server_user_logged_on(void); | |
165 | ||
166 | static void devredir_proc_client_core_cap_resp(struct stream *s); | |
167 | static void devredir_proc_client_devlist_announce_req(struct stream *s); | |
168 | static void devredir_proc_client_devlist_remove_req(struct stream *s); | |
169 | static void devredir_proc_device_iocompletion(struct stream *s); | |
170 | static void devredir_proc_query_dir_response(IRP *irp, | |
171 | struct stream *s_in, | |
172 | tui32 DeviceId, | |
173 | tui32 CompletionId, | |
174 | enum NTSTATUS IoStatus); | |
175 | ||
176 | static void devredir_cvt_slash(char *path); | |
177 | static void devredir_cvt_to_unicode(char *unicode, const char *path); | |
178 | static void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); | |
179 | static int devredir_string_ends_with(const char *string, char c); | |
109 | 180 | |
110 | 181 | /*****************************************************************************/ |
111 | 182 | int |
112 | dev_redir_init(void) | |
183 | devredir_init(void) | |
113 | 184 | { |
114 | 185 | struct stream *s; |
115 | 186 | int bytes; |
156 | 227 | |
157 | 228 | /*****************************************************************************/ |
158 | 229 | int |
159 | dev_redir_deinit(void) | |
230 | devredir_deinit(void) | |
160 | 231 | { |
161 | 232 | scard_deinit(); |
162 | 233 | return 0; |
163 | 234 | } |
235 | ||
236 | /*****************************************************************************/ | |
237 | ||
238 | /* | |
239 | * Convert a COMPLETION_TYPE to a string | |
240 | */ | |
241 | const char *completion_type_to_str(enum COMPLETION_TYPE cid) | |
242 | { | |
243 | return | |
244 | (cid == CID_CREATE_DIR_REQ) ? "CID_CREATE_DIR_REQ" : | |
245 | (cid == CID_DIRECTORY_CONTROL) ? "CID_DIRECTORY_CONTROL" : | |
246 | (cid == CID_CREATE_REQ) ? "CID_CREATE_REQ" : | |
247 | (cid == CID_OPEN_REQ) ? "CID_OPEN_REQ" : | |
248 | (cid == CID_READ) ? "CID_READ" : | |
249 | (cid == CID_WRITE) ? "CID_WRITE" : | |
250 | (cid == CID_CLOSE) ? "CID_CLOSE" : | |
251 | (cid == CID_FILE_CLOSE) ? "CID_FILE_CLOSE" : | |
252 | (cid == CID_RMDIR_OR_FILE) ? "CID_RMDIR_OR_FILE" : | |
253 | (cid == CID_RMDIR_OR_FILE_RESP) ? "CID_RMDIR_OR_FILE_RESP" : | |
254 | (cid == CID_RENAME_FILE) ? "CID_RENAME_FILE" : | |
255 | (cid == CID_RENAME_FILE_RESP) ? "CID_RENAME_FILE_RESP" : | |
256 | (cid == CID_LOOKUP) ? "CID_LOOKUP" : | |
257 | (cid == CID_SETATTR) ? "CID_SETATTR" : | |
258 | /* default */ "<unknown>"; | |
259 | }; | |
260 | ||
261 | /*****************************************************************************/ | |
262 | ||
263 | /* | |
264 | * Convert Windows permssions to Linux permissions. | |
265 | * | |
266 | * We can't curently support group or other permissions as separate from the | |
267 | * owner (not that there's much point). We'll assume our caller will provide | |
268 | * a umask if appropriate | |
269 | */ | |
270 | static tui32 | |
271 | WindowsToLinuxFilePerm(tui32 wperm) | |
272 | { | |
273 | tui32 result; | |
274 | if (wperm & W_FILE_ATTRIBUTE_DIRECTORY) | |
275 | { | |
276 | result = S_IFDIR | 0555; /* dirs are always readable and executable */ | |
277 | } | |
278 | else | |
279 | { | |
280 | result = S_IFREG | 0444; /* files are always readable */ | |
281 | if (wperm & W_FILE_ATTRIBUTE_SYSTEM) result |= 0111; /* Executable */ | |
282 | } | |
283 | ||
284 | if ((wperm & W_FILE_ATTRIBUTE_READONLY) == 0) result |= 0222; | |
285 | ||
286 | return result; | |
287 | } | |
288 | ||
289 | /*****************************************************************************/ | |
290 | static tui32 | |
291 | LinuxToWindowsFilePerm(tui32 lperm) | |
292 | { | |
293 | tui32 result = 0; | |
294 | ||
295 | /* Writeable flag is common to files and directories */ | |
296 | if ((lperm & S_IWUSR) == 0) | |
297 | { | |
298 | result |= W_FILE_ATTRIBUTE_READONLY; | |
299 | } | |
300 | ||
301 | if (lperm & S_IFDIR) | |
302 | { | |
303 | result |= W_FILE_ATTRIBUTE_DIRECTORY; | |
304 | } | |
305 | else | |
306 | { | |
307 | /* For normal files the system attribute is used to store the owner | |
308 | executable bit */ | |
309 | if (lperm & S_IXUSR) | |
310 | { | |
311 | result |= W_FILE_ATTRIBUTE_SYSTEM; | |
312 | } | |
313 | if (result == 0) | |
314 | { | |
315 | /* See MS-FSCC section 2.6 */ | |
316 | result = W_FILE_ATTRIBUTE_NORMAL; | |
317 | } | |
318 | } | |
319 | ||
320 | return result; | |
321 | } | |
322 | ||
164 | 323 | |
165 | 324 | /** |
166 | 325 | * @brief process incoming data |
169 | 328 | *****************************************************************************/ |
170 | 329 | |
171 | 330 | int |
172 | dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length, | |
173 | int total_length) | |
331 | devredir_data_in(struct stream *s, int chan_id, int chan_flags, int length, | |
332 | int total_length) | |
174 | 333 | { |
175 | 334 | struct stream *ls; |
176 | 335 | tui16 comp_type; |
240 | 399 | case RDP_CLIENT_60_61: |
241 | 400 | break; |
242 | 401 | } |
243 | // LK_TODO dev_redir_send_server_clientID_confirm(); | |
402 | // LK_TODO devredir_send_server_clientID_confirm(); | |
244 | 403 | break; |
245 | 404 | |
246 | 405 | case PAKID_CORE_CLIENT_NAME: |
247 | 406 | /* client is telling us its computer name; do we even care? */ |
248 | 407 | |
249 | 408 | /* let client know login was successful */ |
250 | dev_redir_send_server_user_logged_on(); | |
409 | devredir_send_server_user_logged_on(); | |
251 | 410 | usleep(1000 * 100); |
252 | 411 | |
253 | 412 | /* let client know our capabilities */ |
254 | dev_redir_send_server_core_cap_req(); | |
413 | devredir_send_server_core_cap_req(); | |
255 | 414 | |
256 | 415 | /* send confirm clientID */ |
257 | dev_redir_send_server_clientID_confirm(); | |
416 | devredir_send_server_clientID_confirm(); | |
258 | 417 | break; |
259 | 418 | |
260 | 419 | case PAKID_CORE_CLIENT_CAPABILITY: |
261 | dev_redir_proc_client_core_cap_resp(ls); | |
420 | devredir_proc_client_core_cap_resp(ls); | |
262 | 421 | break; |
263 | 422 | |
264 | 423 | case PAKID_CORE_DEVICELIST_ANNOUNCE: |
265 | 424 | devredir_proc_client_devlist_announce_req(ls); |
266 | 425 | break; |
267 | 426 | |
427 | case PAKID_CORE_DEVICELIST_REMOVE: | |
428 | devredir_proc_client_devlist_remove_req(ls); | |
429 | break; | |
430 | ||
268 | 431 | case PAKID_CORE_DEVICE_IOCOMPLETION: |
269 | dev_redir_proc_device_iocompletion(ls); | |
432 | devredir_proc_device_iocompletion(ls); | |
270 | 433 | break; |
271 | 434 | |
272 | 435 | default: |
287 | 450 | |
288 | 451 | /*****************************************************************************/ |
289 | 452 | int |
290 | dev_redir_get_wait_objs(tbus *objs, int *count, int *timeout) | |
453 | devredir_get_wait_objs(tbus *objs, int *count, int *timeout) | |
291 | 454 | { |
292 | 455 | if (g_is_smartcard_redir_supported) |
293 | 456 | { |
298 | 461 | |
299 | 462 | /*****************************************************************************/ |
300 | 463 | int |
301 | dev_redir_check_wait_objs(void) | |
464 | devredir_check_wait_objs(void) | |
302 | 465 | { |
303 | 466 | if (g_is_smartcard_redir_supported) |
304 | 467 | { |
311 | 474 | * @brief let client know our capabilities |
312 | 475 | *****************************************************************************/ |
313 | 476 | |
314 | void dev_redir_send_server_core_cap_req(void) | |
477 | static void | |
478 | devredir_send_server_core_cap_req(void) | |
315 | 479 | { |
316 | 480 | struct stream *s; |
317 | 481 | int bytes; |
371 | 535 | xstream_free(s); |
372 | 536 | } |
373 | 537 | |
374 | void dev_redir_send_server_clientID_confirm(void) | |
538 | static void | |
539 | devredir_send_server_clientID_confirm(void) | |
375 | 540 | { |
376 | 541 | struct stream *s; |
377 | 542 | int bytes; |
392 | 557 | xstream_free(s); |
393 | 558 | } |
394 | 559 | |
395 | void dev_redir_send_server_user_logged_on(void) | |
560 | static void | |
561 | devredir_send_server_user_logged_on(void) | |
396 | 562 | { |
397 | 563 | struct stream *s; |
398 | 564 | int bytes; |
410 | 576 | xstream_free(s); |
411 | 577 | } |
412 | 578 | |
413 | void devredir_send_server_device_announce_resp(tui32 device_id) | |
579 | static void | |
580 | devredir_send_server_device_announce_resp(tui32 device_id) | |
414 | 581 | { |
415 | 582 | struct stream *s; |
416 | 583 | int bytes; |
434 | 601 | * @return 0 on success, -1 on failure |
435 | 602 | *****************************************************************************/ |
436 | 603 | |
437 | int dev_redir_send_drive_create_request(tui32 device_id, | |
438 | const char *path, | |
439 | tui32 DesiredAccess, | |
440 | tui32 CreateOptions, | |
441 | tui32 CreateDisposition, | |
442 | tui32 completion_id) | |
604 | static int | |
605 | devredir_send_drive_create_request(tui32 device_id, | |
606 | const char *path, | |
607 | tui32 DesiredAccess, | |
608 | tui32 CreateOptions, | |
609 | tui32 FileAttributes, | |
610 | tui32 CreateDisposition, | |
611 | tui32 completion_id) | |
443 | 612 | { |
444 | 613 | struct stream *s; |
445 | 614 | int bytes; |
446 | 615 | int len; |
447 | ||
448 | log_debug("DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", | |
449 | DesiredAccess, CreateDisposition, CreateOptions); | |
616 | tui32 SharedAccess; | |
617 | ||
618 | log_debug("device_id=%d path=\"%s\"" | |
619 | " DesiredAccess=0x%x CreateDisposition=0x%x" | |
620 | " FileAttributes=0x%x CreateOptions=0x%x" | |
621 | " CompletionId=%d", | |
622 | device_id, path, | |
623 | DesiredAccess, CreateDisposition, | |
624 | FileAttributes, CreateOptions, | |
625 | completion_id); | |
450 | 626 | |
451 | 627 | /* path in unicode needs this much space */ |
452 | 628 | len = ((g_mbstowcs(NULL, path, 0) * sizeof(twchar)) / 2) + 2; |
453 | 629 | |
454 | 630 | xstream_new(s, 1024 + len); |
631 | ||
632 | /* FILE_SHARE_DELETE allows files to be renamed while in use | |
633 | (in some circumstances) */ | |
634 | SharedAccess = SA_FILE_SHARE_READ | SA_FILE_SHARE_WRITE | | |
635 | SA_FILE_SHARE_DELETE; | |
455 | 636 | |
456 | 637 | devredir_insert_DeviceIoRequest(s, |
457 | 638 | device_id, |
458 | 639 | 0, |
459 | 640 | completion_id, |
460 | 641 | IRP_MJ_CREATE, |
461 | 0); | |
642 | IRP_MN_NONE); | |
462 | 643 | |
463 | 644 | xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */ |
464 | 645 | xstream_wr_u32_le(s, 0); /* AllocationSize high unused */ |
465 | 646 | xstream_wr_u32_le(s, 0); /* AllocationSize low unused */ |
466 | xstream_wr_u32_le(s, 0); /* FileAttributes */ | |
467 | xstream_wr_u32_le(s, 3); /* SharedAccess LK_TODO */ | |
647 | xstream_wr_u32_le(s, FileAttributes); /* FileAttributes */ | |
648 | xstream_wr_u32_le(s, SharedAccess); /* SharedAccess */ | |
468 | 649 | xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */ |
469 | 650 | xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */ |
470 | 651 | xstream_wr_u32_le(s, len); /* PathLength */ |
480 | 661 | } |
481 | 662 | |
482 | 663 | /** |
483 | * Close a request previously created by dev_redir_send_drive_create_request() | |
664 | * Close a request previously created by devredir_send_drive_create_request() | |
484 | 665 | *****************************************************************************/ |
485 | 666 | |
486 | int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, | |
487 | tui32 DeviceId, | |
488 | tui32 FileId, | |
489 | tui32 CompletionId, | |
490 | tui32 MajorFunction, | |
491 | tui32 MinorFunc, | |
492 | int pad_len) | |
667 | static int | |
668 | devredir_send_drive_close_request(tui16 Component, tui16 PacketId, | |
669 | tui32 DeviceId, | |
670 | tui32 FileId, | |
671 | tui32 CompletionId, | |
672 | enum IRP_MJ MajorFunction, | |
673 | enum IRP_MN MinorFunc, | |
674 | int pad_len) | |
493 | 675 | { |
494 | 676 | struct stream *s; |
495 | 677 | int bytes; |
519 | 701 | * |
520 | 702 | *****************************************************************************/ |
521 | 703 | // LK_TODO Path needs to be Unicode |
522 | void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, | |
523 | tui32 InitialQuery, char *Path) | |
704 | static void | |
705 | devredir_send_drive_dir_request(IRP *irp, tui32 device_id, | |
706 | tui32 InitialQuery, char *Path) | |
524 | 707 | { |
525 | 708 | struct stream *s; |
526 | 709 | int bytes; |
550 | 733 | IRP_MJ_DIRECTORY_CONTROL, |
551 | 734 | IRP_MN_QUERY_DIRECTORY); |
552 | 735 | |
553 | #ifdef USE_SHORT_NAMES_IN_DIR_LISTING | |
554 | xstream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */ | |
555 | #else | |
556 | 736 | xstream_wr_u32_le(s, FileDirectoryInformation); /* FsInformationClass */ |
557 | #endif | |
558 | 737 | xstream_wr_u8(s, InitialQuery); /* InitialQuery */ |
559 | 738 | |
560 | 739 | if (!InitialQuery) |
585 | 764 | * |
586 | 765 | * @param s stream containing client's response |
587 | 766 | *****************************************************************************/ |
588 | void dev_redir_proc_client_core_cap_resp(struct stream *s) | |
767 | static void | |
768 | devredir_proc_client_core_cap_resp(struct stream *s) | |
589 | 769 | { |
590 | 770 | int i; |
591 | 771 | tui16 num_caps; |
639 | 819 | } |
640 | 820 | } |
641 | 821 | |
642 | void devredir_proc_client_devlist_announce_req(struct stream *s) | |
822 | static void | |
823 | devredir_proc_client_devlist_announce_req(struct stream *s) | |
643 | 824 | { |
644 | 825 | unsigned int i; |
645 | 826 | int j; |
719 | 900 | } |
720 | 901 | } |
721 | 902 | |
722 | void | |
723 | dev_redir_proc_device_iocompletion(struct stream *s) | |
724 | { | |
725 | FUSE_DATA *fuse_data = NULL; | |
903 | static void | |
904 | devredir_proc_client_devlist_remove_req(struct stream *s) | |
905 | { | |
906 | unsigned int i; | |
907 | tui32 device_count; | |
908 | tui32 device_id; | |
909 | ||
910 | /* get number of devices being announced */ | |
911 | xstream_rd_u32_le(s, device_count); | |
912 | ||
913 | log_debug("num of devices removed: %d", device_count); | |
914 | { | |
915 | for (i = 0; i < device_count; i++) | |
916 | { | |
917 | xstream_rd_u32_le(s, device_id); | |
918 | xfuse_delete_share(device_id); | |
919 | } | |
920 | } | |
921 | } | |
922 | ||
923 | static void | |
924 | devredir_proc_device_iocompletion(struct stream *s) | |
925 | { | |
726 | 926 | IRP *irp = NULL; |
727 | 927 | |
728 | 928 | tui32 DeviceId; |
729 | 929 | tui32 CompletionId; |
730 | tui32 IoStatus; | |
930 | tui32 IoStatus32; | |
731 | 931 | tui32 Length; |
932 | enum COMPLETION_TYPE comp_type; | |
732 | 933 | |
733 | 934 | xstream_rd_u32_le(s, DeviceId); |
734 | 935 | xstream_rd_u32_le(s, CompletionId); |
735 | xstream_rd_u32_le(s, IoStatus); | |
736 | ||
737 | log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId); | |
936 | xstream_rd_u32_le(s, IoStatus32); | |
937 | enum NTSTATUS IoStatus = (enum NTSTATUS) IoStatus32; /* Needed by C++ */ | |
738 | 938 | |
739 | 939 | if ((irp = devredir_irp_find(CompletionId)) == NULL) |
740 | 940 | { |
741 | 941 | log_error("IRP with completion ID %d not found", CompletionId); |
742 | return; | |
743 | } | |
744 | ||
745 | /* if callback has been set, call it */ | |
942 | } | |
943 | else | |
746 | 944 | if (irp->callback) |
747 | 945 | { |
946 | /* Callback has been set - call it */ | |
748 | 947 | (*irp->callback)(s, irp, DeviceId, CompletionId, IoStatus); |
749 | goto done; | |
750 | } | |
751 | ||
752 | switch (irp->completion_type) | |
753 | { | |
754 | case CID_CREATE_DIR_REQ: | |
755 | log_debug("got CID_CREATE_DIR_REQ"); | |
756 | if (IoStatus != NT_STATUS_SUCCESS) | |
948 | } | |
949 | else | |
950 | { | |
951 | comp_type = (enum COMPLETION_TYPE) irp->completion_type; | |
952 | /* Log something about the IRP */ | |
953 | if (IoStatus == NT_STATUS_SUCCESS || | |
954 | IoStatus == NT_STATUS_NO_MORE_FILES || | |
955 | (IoStatus == NT_STATUS_NO_SUCH_FILE && comp_type == CID_LOOKUP)) | |
757 | 956 | { |
758 | /* we were trying to create a request to enumerate a dir */ | |
759 | /* that does not exist; let FUSE know */ | |
760 | fuse_data = devredir_fuse_data_dequeue(irp); | |
761 | if (fuse_data) | |
762 | { | |
763 | xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, | |
764 | IoStatus); | |
765 | free(fuse_data); | |
766 | } | |
767 | devredir_irp_delete(irp); | |
768 | return; | |
769 | } | |
770 | ||
771 | xstream_rd_u32_le(s, irp->FileId); | |
772 | log_debug("got CID_CREATE_DIR_REQ IoStatus=0x%x FileId=%d", | |
773 | IoStatus, irp->FileId); | |
774 | ||
775 | dev_redir_send_drive_dir_request(irp, DeviceId, 1, irp->pathname); | |
776 | break; | |
777 | ||
778 | case CID_CREATE_OPEN_REQ: | |
779 | xstream_rd_u32_le(s, irp->FileId); | |
780 | ||
781 | log_debug("got CID_CREATE_OPEN_REQ IoStatus=0x%x FileId=%d", | |
782 | IoStatus, irp->FileId); | |
783 | ||
784 | fuse_data = devredir_fuse_data_dequeue(irp); | |
785 | xfuse_devredir_cb_open_file(fuse_data->data_ptr, IoStatus, | |
786 | DeviceId, irp->FileId); | |
787 | if ((irp->type == S_IFDIR) || (IoStatus != NT_STATUS_SUCCESS)) | |
788 | devredir_irp_delete(irp); | |
789 | break; | |
790 | ||
791 | case CID_READ: | |
792 | log_debug("got CID_READ"); | |
793 | xstream_rd_u32_le(s, Length); | |
794 | fuse_data = devredir_fuse_data_dequeue(irp); | |
795 | ||
796 | if (fuse_data == NULL) | |
797 | { | |
798 | log_error("fuse_data is NULL"); | |
957 | /* Successes or common occurrences - debug logging only */ | |
958 | log_debug("got %s", completion_type_to_str(comp_type)); | |
799 | 959 | } |
800 | 960 | else |
801 | 961 | { |
802 | xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length); | |
962 | const char *pathname = (irp->pathname) ? irp->pathname : "<none>"; | |
963 | log_error("CompletionType = %s, IoStatus=%08x " | |
964 | "Pathname = %s", | |
965 | completion_type_to_str(comp_type), | |
966 | IoStatus, | |
967 | pathname); | |
968 | } | |
969 | ||
970 | switch (comp_type) | |
971 | { | |
972 | case CID_CREATE_DIR_REQ: | |
973 | if (IoStatus != NT_STATUS_SUCCESS) | |
974 | { | |
975 | xfuse_devredir_cb_enum_dir_done( | |
976 | (struct state_dirscan *) irp->fuse_info, IoStatus); | |
977 | devredir_irp_delete(irp); | |
978 | } | |
979 | else | |
980 | { | |
981 | xstream_rd_u32_le(s, irp->FileId); | |
982 | devredir_send_drive_dir_request(irp, DeviceId, | |
983 | 1, irp->pathname); | |
984 | } | |
985 | break; | |
986 | ||
987 | case CID_CREATE_REQ: | |
988 | xstream_rd_u32_le(s, irp->FileId); | |
989 | ||
990 | xfuse_devredir_cb_create_file( | |
991 | (struct state_create *) irp->fuse_info, | |
992 | IoStatus, DeviceId, irp->FileId); | |
993 | if (irp->gen.create.creating_dir || IoStatus != NT_STATUS_SUCCESS) | |
994 | { | |
995 | devredir_irp_delete(irp); | |
996 | } | |
997 | break; | |
998 | ||
999 | case CID_OPEN_REQ: | |
1000 | xstream_rd_u32_le(s, irp->FileId); | |
1001 | ||
1002 | xfuse_devredir_cb_open_file((struct state_open *) irp->fuse_info, | |
1003 | IoStatus, DeviceId, irp->FileId); | |
1004 | if (IoStatus != NT_STATUS_SUCCESS) | |
1005 | { | |
1006 | devredir_irp_delete(irp); | |
1007 | } | |
1008 | break; | |
1009 | ||
1010 | case CID_READ: | |
1011 | xstream_rd_u32_le(s, Length); | |
1012 | xfuse_devredir_cb_read_file((struct state_read *) irp->fuse_info, | |
1013 | s->p, Length); | |
803 | 1014 | devredir_irp_delete(irp); |
1015 | break; | |
1016 | ||
1017 | case CID_WRITE: | |
1018 | xstream_rd_u32_le(s, Length); | |
1019 | xfuse_devredir_cb_write_file((struct state_write *) irp->fuse_info, | |
1020 | IoStatus, | |
1021 | irp->gen.write.offset, Length); | |
1022 | devredir_irp_delete(irp); | |
1023 | break; | |
1024 | ||
1025 | case CID_CLOSE: | |
1026 | devredir_irp_delete(irp); | |
1027 | break; | |
1028 | ||
1029 | case CID_FILE_CLOSE: | |
1030 | xfuse_devredir_cb_file_close((struct state_close *) irp->fuse_info); | |
1031 | devredir_irp_delete(irp); | |
1032 | break; | |
1033 | ||
1034 | case CID_DIRECTORY_CONTROL: | |
1035 | devredir_proc_query_dir_response(irp, s, DeviceId, | |
1036 | CompletionId, IoStatus); | |
1037 | break; | |
1038 | ||
1039 | case CID_RMDIR_OR_FILE: | |
1040 | xstream_rd_u32_le(s, irp->FileId); | |
1041 | devredir_proc_cid_rmdir_or_file(irp, IoStatus); | |
1042 | break; | |
1043 | ||
1044 | case CID_RMDIR_OR_FILE_RESP: | |
1045 | devredir_proc_cid_rmdir_or_file_resp(irp, IoStatus); | |
1046 | break; | |
1047 | ||
1048 | case CID_RENAME_FILE: | |
1049 | xstream_rd_u32_le(s, irp->FileId); | |
1050 | devredir_proc_cid_rename_file(irp, IoStatus); | |
1051 | break; | |
1052 | ||
1053 | case CID_RENAME_FILE_RESP: | |
1054 | devredir_proc_cid_rename_file_resp(irp, IoStatus); | |
1055 | break; | |
1056 | ||
1057 | case CID_LOOKUP: | |
1058 | devredir_proc_cid_lookup(irp, s, IoStatus); | |
1059 | break; | |
1060 | ||
1061 | case CID_SETATTR: | |
1062 | devredir_proc_cid_setattr(irp, s, IoStatus); | |
1063 | break; | |
1064 | ||
1065 | default: | |
1066 | log_error("got unknown CompletionID: DeviceId=0x%x " | |
1067 | "CompletionId=0x%x IoStatus=0x%x", | |
1068 | DeviceId, CompletionId, IoStatus); | |
1069 | break; | |
804 | 1070 | } |
805 | break; | |
806 | ||
807 | case CID_WRITE: | |
808 | log_debug("got CID_WRITE"); | |
809 | xstream_rd_u32_le(s, Length); | |
810 | fuse_data = devredir_fuse_data_dequeue(irp); | |
811 | ||
812 | if (fuse_data == NULL) | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | static void | |
1075 | devredir_proc_query_dir_response(IRP *irp, | |
1076 | struct stream *s_in, | |
1077 | tui32 DeviceId, | |
1078 | tui32 CompletionId, | |
1079 | enum NTSTATUS IoStatus) | |
1080 | { | |
1081 | tui32 Length; | |
1082 | xstream_rd_u32_le(s_in, Length); | |
1083 | ||
1084 | if (IoStatus == NT_STATUS_SUCCESS) | |
1085 | { | |
1086 | unsigned int i; | |
1087 | /* process FILE_DIRECTORY_INFORMATION structures */ | |
1088 | for (i = 0 ; i < Length ; ++i) | |
813 | 1089 | { |
814 | log_error("fuse_data is NULL"); | |
1090 | char filename[256]; | |
1091 | tui64 LastAccessTime; | |
1092 | tui64 LastWriteTime; | |
1093 | tui64 EndOfFile; | |
1094 | tui32 FileAttributes; | |
1095 | tui32 FileNameLength; | |
1096 | struct file_attr fattr; | |
1097 | ||
1098 | xstream_seek(s_in, 4); /* NextEntryOffset */ | |
1099 | xstream_seek(s_in, 4); /* FileIndex */ | |
1100 | xstream_seek(s_in, 8); /* CreationTime */ | |
1101 | xstream_rd_u64_le(s_in, LastAccessTime); | |
1102 | xstream_rd_u64_le(s_in, LastWriteTime); | |
1103 | xstream_seek(s_in, 8); /* ChangeTime */ | |
1104 | xstream_rd_u64_le(s_in, EndOfFile); | |
1105 | xstream_seek(s_in, 8); /* AllocationSize */ | |
1106 | xstream_rd_u32_le(s_in, FileAttributes); | |
1107 | xstream_rd_u32_le(s_in, FileNameLength); | |
1108 | ||
1109 | devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength); | |
1110 | ||
1111 | i += 64 + FileNameLength; | |
1112 | ||
1113 | //log_debug("LastAccessTime: 0x%llx", LastAccessTime); | |
1114 | //log_debug("LastWriteTime: 0x%llx", LastWriteTime); | |
1115 | //log_debug("EndOfFile: %lld", EndOfFile); | |
1116 | //log_debug("FileAttributes: 0x%x", FileAttributes); | |
1117 | //log_debug("FileNameLength: %d", FileNameLength); | |
1118 | log_debug("FileName: %s", filename); | |
1119 | ||
1120 | fattr.mode = WindowsToLinuxFilePerm(FileAttributes); | |
1121 | fattr.size = (size_t) EndOfFile; | |
1122 | fattr.atime = WINDOWS_TO_LINUX_TIME(LastAccessTime); | |
1123 | fattr.mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime); | |
1124 | ||
1125 | /* add this entry to xrdp file system */ | |
1126 | xfuse_devredir_cb_enum_dir_add_entry( | |
1127 | (struct state_dirscan *) irp->fuse_info, | |
1128 | filename, &fattr); | |
815 | 1129 | } |
816 | else | |
1130 | ||
1131 | /* Ask for more directory entries */ | |
1132 | devredir_send_drive_dir_request(irp, DeviceId, 0, NULL); | |
1133 | } | |
1134 | else | |
1135 | { | |
1136 | if (IoStatus == NT_STATUS_NO_MORE_FILES) | |
817 | 1137 | { |
818 | xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length); | |
819 | devredir_irp_delete(irp); | |
1138 | IoStatus = NT_STATUS_SUCCESS; | |
820 | 1139 | } |
821 | break; | |
822 | ||
823 | case CID_CLOSE: | |
824 | log_debug("got CID_CLOSE"); | |
825 | log_debug("deleting irp with completion_id=%d comp_type=%d", | |
826 | irp->CompletionId, irp->completion_type); | |
827 | devredir_irp_delete(irp); | |
828 | break; | |
829 | ||
830 | case CID_FILE_CLOSE: | |
831 | log_debug("got CID_FILE_CLOSE"); | |
832 | fuse_data = devredir_fuse_data_dequeue(irp); | |
833 | xfuse_devredir_cb_file_close(fuse_data->data_ptr); | |
834 | devredir_irp_delete(irp); | |
835 | break; | |
836 | ||
837 | case CID_DIRECTORY_CONTROL: | |
838 | log_debug("got CID_DIRECTORY_CONTROL"); | |
839 | ||
840 | dev_redir_proc_query_dir_response(irp, s, DeviceId, | |
841 | CompletionId, IoStatus); | |
842 | break; | |
843 | ||
844 | case CID_RMDIR_OR_FILE: | |
845 | log_debug("got CID_RMDIR_OR_FILE"); | |
846 | xstream_rd_u32_le(s, irp->FileId); | |
847 | devredir_proc_cid_rmdir_or_file(irp, IoStatus); | |
848 | return; | |
849 | break; | |
850 | ||
851 | case CID_RMDIR_OR_FILE_RESP: | |
852 | log_debug("got CID_RMDIR_OR_FILE_RESP"); | |
853 | devredir_proc_cid_rmdir_or_file_resp(irp, IoStatus); | |
854 | break; | |
855 | ||
856 | case CID_RENAME_FILE: | |
857 | log_debug("got CID_RENAME_FILE"); | |
858 | xstream_rd_u32_le(s, irp->FileId); | |
859 | devredir_proc_cid_rename_file(irp, IoStatus); | |
860 | return; | |
861 | break; | |
862 | ||
863 | case CID_RENAME_FILE_RESP: | |
864 | log_debug("got CID_RENAME_FILE_RESP"); | |
865 | devredir_proc_cid_rename_file_resp(irp, IoStatus); | |
866 | break; | |
867 | ||
868 | default: | |
869 | log_error("got unknown CompletionID: DeviceId=0x%x " | |
870 | "CompletionId=0x%x IoStatus=0x%x", | |
871 | DeviceId, CompletionId, IoStatus); | |
872 | break; | |
873 | } | |
874 | ||
875 | done: | |
876 | ||
877 | if (fuse_data) | |
878 | { | |
879 | log_debug("free FUSE_DATA=%p", fuse_data); | |
880 | free(fuse_data); | |
881 | } | |
882 | ||
883 | log_debug("exiting"); | |
884 | } | |
885 | ||
886 | void | |
887 | dev_redir_proc_query_dir_response(IRP *irp, | |
888 | struct stream *s_in, | |
889 | tui32 DeviceId, | |
890 | tui32 CompletionId, | |
891 | tui32 IoStatus) | |
892 | { | |
893 | FUSE_DATA *fuse_data = NULL; | |
894 | XRDP_INODE *xinode; | |
895 | ||
896 | tui32 Length; | |
897 | tui64 CreationTime; | |
898 | tui64 LastAccessTime; | |
899 | tui64 LastWriteTime; | |
900 | tui64 EndOfFile; | |
901 | tui32 FileAttributes; | |
902 | tui32 FileNameLength; | |
903 | tui32 status; | |
904 | ||
905 | char filename[256]; | |
906 | unsigned int i = 0; | |
907 | ||
908 | xstream_rd_u32_le(s_in, Length); | |
909 | ||
910 | if ((IoStatus == NT_STATUS_UNSUCCESSFUL) || | |
911 | (IoStatus == STATUS_NO_MORE_FILES)) | |
912 | { | |
913 | status = (IoStatus == STATUS_NO_MORE_FILES) ? 0 : IoStatus; | |
914 | fuse_data = devredir_fuse_data_dequeue(irp); | |
915 | xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, status); | |
1140 | xfuse_devredir_cb_enum_dir_done((struct state_dirscan *)irp->fuse_info, | |
1141 | IoStatus); | |
916 | 1142 | irp->completion_type = CID_CLOSE; |
917 | dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, | |
918 | PAKID_CORE_DEVICE_IOREQUEST, | |
919 | DeviceId, | |
920 | irp->FileId, | |
921 | irp->CompletionId, | |
922 | IRP_MJ_CLOSE, 0, 32); | |
923 | free(fuse_data); | |
924 | return; | |
925 | } | |
926 | ||
927 | /* TODO check status for errors */ | |
928 | ||
929 | /* process FILE_DIRECTORY_INFORMATION structures */ | |
930 | while (i < Length) | |
931 | { | |
932 | log_debug("processing FILE_DIRECTORY_INFORMATION structs"); | |
933 | ||
934 | xstream_seek(s_in, 4); /* NextEntryOffset */ | |
935 | xstream_seek(s_in, 4); /* FileIndex */ | |
936 | xstream_rd_u64_le(s_in, CreationTime); | |
937 | xstream_rd_u64_le(s_in, LastAccessTime); | |
938 | xstream_rd_u64_le(s_in, LastWriteTime); | |
939 | xstream_seek(s_in, 8); /* ChangeTime */ | |
940 | xstream_rd_u64_le(s_in, EndOfFile); | |
941 | xstream_seek(s_in, 8); /* AllocationSize */ | |
942 | xstream_rd_u32_le(s_in, FileAttributes); | |
943 | xstream_rd_u32_le(s_in, FileNameLength); | |
944 | ||
945 | #ifdef USE_SHORT_NAMES_IN_DIR_LISTING | |
946 | xstream_seek(s_in, 4); /* EaSize */ | |
947 | xstream_seek(s_in, 1); /* ShortNameLength */ | |
948 | xstream_seek(s_in, 1); /* Reserved */ | |
949 | xstream_seek(s_in, 23); /* ShortName in Unicode */ | |
950 | #endif | |
951 | devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength); | |
952 | ||
953 | #ifdef USE_SHORT_NAMES_IN_DIR_LISTING | |
954 | i += 70 + 23 + FileNameLength; | |
955 | #else | |
956 | i += 64 + FileNameLength; | |
957 | #endif | |
958 | //log_debug("CreationTime: 0x%llx", CreationTime); | |
959 | //log_debug("LastAccessTime: 0x%llx", LastAccessTime); | |
960 | //log_debug("LastWriteTime: 0x%llx", LastWriteTime); | |
961 | //log_debug("EndOfFile: %lld", EndOfFile); | |
962 | //log_debug("FileAttributes: 0x%x", FileAttributes); | |
963 | #ifdef USE_SHORT_NAMES_IN_DIR_LISTING | |
964 | //log_debug("ShortNameLength: %d", ShortNameLength); | |
965 | #endif | |
966 | //log_debug("FileNameLength: %d", FileNameLength); | |
967 | log_debug("FileName: %s", filename); | |
968 | ||
969 | xinode = g_new0(struct xrdp_inode, 1); | |
970 | if (xinode == NULL) | |
971 | { | |
972 | log_error("system out of memory"); | |
973 | fuse_data = devredir_fuse_data_peek(irp); | |
974 | xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, NULL); | |
975 | return; | |
976 | } | |
977 | ||
978 | strcpy(xinode->name, filename); | |
979 | xinode->size = (size_t) EndOfFile; | |
980 | xinode->mode = WINDOWS_TO_LINUX_FILE_PERM(FileAttributes); | |
981 | xinode->atime = WINDOWS_TO_LINUX_TIME(LastAccessTime); | |
982 | xinode->mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime); | |
983 | xinode->ctime = WINDOWS_TO_LINUX_TIME(CreationTime); | |
984 | ||
985 | /* add this entry to xrdp file system */ | |
986 | fuse_data = devredir_fuse_data_peek(irp); | |
987 | xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, xinode); | |
988 | } | |
989 | ||
990 | dev_redir_send_drive_dir_request(irp, DeviceId, 0, NULL); | |
1143 | devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1144 | PAKID_CORE_DEVICE_IOREQUEST, | |
1145 | DeviceId, | |
1146 | irp->FileId, | |
1147 | irp->CompletionId, | |
1148 | IRP_MJ_CLOSE, IRP_MN_NONE, 32); | |
1149 | } | |
991 | 1150 | } |
992 | 1151 | |
993 | 1152 | /** |
1001 | 1160 | *****************************************************************************/ |
1002 | 1161 | |
1003 | 1162 | int |
1004 | dev_redir_get_dir_listing(void *fusep, tui32 device_id, const char *path) | |
1163 | devredir_get_dir_listing(struct state_dirscan *fusep, tui32 device_id, | |
1164 | const char *path) | |
1005 | 1165 | { |
1006 | 1166 | tui32 DesiredAccess; |
1007 | 1167 | tui32 CreateOptions; |
1008 | 1168 | tui32 CreateDisposition; |
1009 | int rval; | |
1169 | int rval = -1; | |
1010 | 1170 | IRP *irp; |
1011 | 1171 | |
1012 | log_debug("fusep=%p", fusep); | |
1013 | ||
1014 | if ((irp = devredir_irp_new()) == NULL) | |
1015 | return -1; | |
1016 | ||
1017 | strncpy(irp->pathname, path, 255); | |
1018 | ||
1019 | /* convert / to windows compatible \ */ | |
1020 | devredir_cvt_slash(irp->pathname); | |
1021 | ||
1022 | irp->CompletionId = g_completion_id++; | |
1023 | irp->completion_type = CID_CREATE_DIR_REQ; | |
1024 | irp->DeviceId = device_id; | |
1025 | ||
1026 | devredir_fuse_data_enqueue(irp, fusep); | |
1027 | ||
1028 | DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; | |
1029 | CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT; | |
1030 | CreateDisposition = CD_FILE_OPEN; | |
1031 | ||
1032 | rval = dev_redir_send_drive_create_request(device_id, irp->pathname, | |
1033 | DesiredAccess, CreateOptions, | |
1034 | CreateDisposition, | |
1035 | irp->CompletionId); | |
1036 | ||
1037 | log_debug("looking for device_id=%d path=%s", device_id, irp->pathname); | |
1038 | ||
1039 | /* when we get a response to dev_redir_send_drive_create_request(), we */ | |
1040 | /* call dev_redir_send_drive_dir_request(), which needs the following */ | |
1041 | /* at the end of the path argument */ | |
1042 | if (dev_redir_string_ends_with(irp->pathname, '\\')) | |
1043 | strcat(irp->pathname, "*"); | |
1044 | else | |
1045 | strcat(irp->pathname, "\\*"); | |
1046 | ||
1172 | /* | |
1173 | * We need to be able to append two additional characters to the | |
1174 | * path after we create the IRP | |
1175 | */ | |
1176 | if ((irp = devredir_irp_with_pathnamelen_new(strlen(path) + 2)) != NULL) | |
1177 | { | |
1178 | /* convert / to windows compatible \ */ | |
1179 | strcpy(irp->pathname, path); | |
1180 | devredir_cvt_slash(irp->pathname); | |
1181 | ||
1182 | irp->CompletionId = g_completion_id++; | |
1183 | irp->completion_type = CID_CREATE_DIR_REQ; | |
1184 | irp->DeviceId = device_id; | |
1185 | irp->fuse_info = fusep; | |
1186 | ||
1187 | DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; | |
1188 | CreateOptions = CO_FILE_DIRECTORY_FILE | | |
1189 | CO_FILE_SYNCHRONOUS_IO_NONALERT; | |
1190 | CreateDisposition = CD_FILE_OPEN; | |
1191 | ||
1192 | rval = devredir_send_drive_create_request(device_id, irp->pathname, | |
1193 | DesiredAccess, CreateOptions, | |
1194 | 0, CreateDisposition, | |
1195 | irp->CompletionId); | |
1196 | ||
1197 | log_debug("looking for device_id=%d path=%s", device_id, irp->pathname); | |
1198 | ||
1199 | /* when we get a response to devredir_send_drive_create_request(), we | |
1200 | * call devredir_send_drive_dir_request(), which needs the following | |
1201 | * at the end of the path argument */ | |
1202 | if (devredir_string_ends_with(irp->pathname, '\\')) | |
1203 | { | |
1204 | strcat(irp->pathname, "*"); | |
1205 | } | |
1206 | else | |
1207 | { | |
1208 | strcat(irp->pathname, "\\*"); | |
1209 | } | |
1210 | } | |
1047 | 1211 | return rval; |
1048 | 1212 | } |
1049 | 1213 | |
1214 | /** | |
1215 | * FUSE calls this function whenever it wants us to lookup a file or directory | |
1216 | * | |
1217 | * @param fusep opaque data struct that we just pass back to FUSE when done | |
1218 | * @param device_id device_id of the redirected share | |
1219 | * @param path the name of the directory containing the file | |
1220 | * @param file the filename | |
1221 | * | |
1222 | * @return 0 on success, -1 on failure | |
1223 | *****************************************************************************/ | |
1224 | ||
1050 | 1225 | int |
1051 | dev_redir_file_open(void *fusep, tui32 device_id, const char *path, | |
1052 | int mode, int type, const char *gen_buf) | |
1226 | devredir_lookup_entry(struct state_lookup *fusep, tui32 device_id, | |
1227 | const char *path) | |
1053 | 1228 | { |
1054 | 1229 | tui32 DesiredAccess; |
1055 | 1230 | tui32 CreateOptions; |
1056 | 1231 | tui32 CreateDisposition; |
1057 | int rval; | |
1232 | int rval = -1; | |
1058 | 1233 | IRP *irp; |
1059 | 1234 | |
1060 | log_debug("device_id=%d path=%s mode=0x%x", device_id, path, mode); | |
1061 | ||
1062 | if ((irp = devredir_irp_new()) == NULL) | |
1063 | return -1; | |
1064 | ||
1065 | if (type & OP_RENAME_FILE) | |
1066 | { | |
1067 | irp->completion_type = CID_RENAME_FILE; | |
1068 | strncpy(irp->gen_buf, gen_buf, 1023); | |
1069 | } | |
1070 | else | |
1071 | { | |
1072 | irp->completion_type = CID_CREATE_OPEN_REQ; | |
1073 | } | |
1074 | ||
1075 | irp->CompletionId = g_completion_id++; | |
1076 | irp->DeviceId = device_id; | |
1077 | ||
1078 | strncpy(irp->pathname, path, 255); | |
1079 | devredir_fuse_data_enqueue(irp, fusep); | |
1080 | ||
1081 | if (mode & O_CREAT) | |
1082 | { | |
1083 | log_debug("open file in O_CREAT"); | |
1235 | log_debug("fusep=%p", fusep); | |
1236 | ||
1237 | if ((irp = devredir_irp_with_pathname_new(path)) != NULL) | |
1238 | { | |
1239 | /* convert / to windows compatible \ */ | |
1240 | devredir_cvt_slash(irp->pathname); | |
1241 | ||
1242 | /* | |
1243 | * Allocate an IRP to open the file, read the basic attributes, | |
1244 | * read the standard attributes, and then close the file | |
1245 | */ | |
1246 | irp->CompletionId = g_completion_id++; | |
1247 | irp->completion_type = CID_LOOKUP; | |
1248 | irp->DeviceId = device_id; | |
1249 | irp->gen.lookup.state = E_LOOKUP_GET_FH; | |
1250 | irp->fuse_info = fusep; | |
1251 | ||
1252 | DesiredAccess = DA_FILE_READ_ATTRIBUTES | DA_SYNCHRONIZE; | |
1253 | CreateOptions = 0; | |
1254 | CreateDisposition = CD_FILE_OPEN; | |
1255 | ||
1256 | log_debug("lookup for device_id=%d path=%s CompletionId=%d", | |
1257 | device_id, irp->pathname, irp->CompletionId); | |
1258 | ||
1259 | rval = devredir_send_drive_create_request(device_id, | |
1260 | irp->pathname, | |
1261 | DesiredAccess, CreateOptions, | |
1262 | 0, CreateDisposition, | |
1263 | irp->CompletionId); | |
1264 | } | |
1265 | ||
1266 | return rval; | |
1267 | } | |
1268 | ||
1269 | /** | |
1270 | * FUSE calls this function whenever it wants us to set the attributes for | |
1271 | * a file or directory. | |
1272 | * | |
1273 | * @param fusep opaque data struct that we just pass back to FUSE when done | |
1274 | * @param device_id device_id of the redirected share | |
1275 | * @param filename the name of the file | |
1276 | * @param fattr the file attributes to set for the file | |
1277 | * @param to_set Which bits of the file attributes have changed | |
1278 | * | |
1279 | * @return 0 on success, -1 on failure | |
1280 | *****************************************************************************/ | |
1281 | int | |
1282 | devredir_setattr_for_entry(struct state_setattr *fusep, tui32 device_id, | |
1283 | const char *filename, | |
1284 | const struct file_attr *fattr, | |
1285 | tui32 to_set) | |
1286 | { | |
1287 | tui32 DesiredAccess; | |
1288 | tui32 CreateOptions; | |
1289 | tui32 CreateDisposition; | |
1290 | int rval = -1; | |
1291 | IRP *irp; | |
1292 | ||
1293 | log_debug("fusep=%p", fusep); | |
1294 | ||
1295 | if ((irp = devredir_irp_with_pathname_new(filename)) != NULL) | |
1296 | { | |
1297 | /* convert / to windows compatible \ */ | |
1298 | devredir_cvt_slash(irp->pathname); | |
1299 | ||
1300 | /* | |
1301 | * Allocate an IRP to open the file, update the attributes | |
1302 | * and close the file. | |
1303 | */ | |
1304 | irp->CompletionId = g_completion_id++; | |
1305 | irp->completion_type = CID_SETATTR; | |
1306 | irp->DeviceId = device_id; | |
1307 | irp->fuse_info = fusep; | |
1308 | ||
1309 | irp->gen.setattr.state = E_SETATTR_GET_FH; | |
1310 | irp->gen.setattr.to_set = to_set; | |
1311 | irp->gen.setattr.fattr = *fattr; | |
1312 | ||
1313 | /* | |
1314 | * Don't set DA_FILE_WRITE_DATA unless we're changing the | |
1315 | * EndOfFile pointer. Otherwise we can't change the attributes | |
1316 | * of read-only files! */ | |
1317 | DesiredAccess = DA_FILE_WRITE_ATTRIBUTES; | |
1318 | if (to_set & TO_SET_SIZE) | |
1319 | { | |
1320 | DesiredAccess |= DA_FILE_WRITE_DATA; | |
1321 | } | |
1322 | CreateOptions = 0; | |
1323 | CreateDisposition = CD_FILE_OPEN; | |
1324 | ||
1325 | log_debug("lookup for device_id=%d path=%s", | |
1326 | device_id, irp->pathname); | |
1327 | ||
1328 | rval = devredir_send_drive_create_request(device_id, | |
1329 | irp->pathname, | |
1330 | DesiredAccess, CreateOptions, | |
1331 | 0, CreateDisposition, | |
1332 | irp->CompletionId); | |
1333 | } | |
1334 | ||
1335 | return rval; | |
1336 | } | |
1337 | ||
1338 | int | |
1339 | devredir_file_create(struct state_create *fusep, tui32 device_id, | |
1340 | const char *path, int mode) | |
1341 | { | |
1342 | tui32 DesiredAccess; | |
1343 | tui32 CreateOptions; | |
1344 | tui32 FileAttributes = 0; | |
1345 | tui32 CreateDisposition; | |
1346 | int rval = -1; | |
1347 | IRP *irp; | |
1348 | ||
1349 | log_debug("device_id=%d path=%s mode=0%o", device_id, path, mode); | |
1350 | ||
1351 | if ((irp = devredir_irp_with_pathname_new(path)) != NULL) | |
1352 | { | |
1353 | /* convert / to windows compatible \ */ | |
1354 | devredir_cvt_slash(irp->pathname); | |
1355 | ||
1356 | irp->completion_type = CID_CREATE_REQ; | |
1357 | irp->CompletionId = g_completion_id++; | |
1358 | irp->DeviceId = device_id; | |
1359 | irp->fuse_info = fusep; | |
1360 | ||
1084 | 1361 | DesiredAccess = 0x0016019f; /* got this value from windows */ |
1085 | ||
1086 | if (type & S_IFDIR) | |
1362 | FileAttributes = LinuxToWindowsFilePerm(mode); | |
1363 | if (mode & S_IFDIR) | |
1087 | 1364 | { |
1088 | 1365 | log_debug("creating dir"); |
1089 | 1366 | CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT; |
1090 | irp->type = S_IFDIR; | |
1367 | irp->gen.create.creating_dir = 1; | |
1091 | 1368 | } |
1092 | 1369 | else |
1093 | 1370 | { |
1094 | 1371 | log_debug("creating file"); |
1095 | 1372 | CreateOptions = 0x44; /* got this value from windows */ |
1373 | irp->gen.create.creating_dir = 0; | |
1096 | 1374 | } |
1097 | 1375 | |
1098 | 1376 | //CreateDisposition = CD_FILE_CREATE; |
1099 | 1377 | CreateDisposition = 0x02; /* got this value from windows */ |
1100 | } | |
1101 | else | |
1102 | { | |
1103 | log_debug("open file in O_RDWR"); | |
1104 | #if 1 | |
1105 | /* without the 0x00000010 rdesktop opens files in */ | |
1106 | /* O_RDONLY instead of O_RDWR mode */ | |
1107 | if (mode & O_RDWR) | |
1108 | DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; | |
1109 | else | |
1110 | DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; | |
1378 | ||
1379 | rval = devredir_send_drive_create_request(device_id, path, | |
1380 | DesiredAccess, CreateOptions, | |
1381 | FileAttributes, | |
1382 | CreateDisposition, | |
1383 | irp->CompletionId); | |
1384 | } | |
1385 | ||
1386 | return rval; | |
1387 | } | |
1388 | ||
1389 | int | |
1390 | devredir_file_open(struct state_open *fusep, tui32 device_id, | |
1391 | const char *path, int flags) | |
1392 | { | |
1393 | tui32 DesiredAccess; | |
1394 | tui32 CreateOptions; | |
1395 | tui32 FileAttributes = 0; | |
1396 | tui32 CreateDisposition; | |
1397 | int rval = -1; | |
1398 | IRP *irp; | |
1399 | ||
1400 | log_debug("device_id=%d path=%s flags=0%x", | |
1401 | device_id, path, flags); | |
1402 | ||
1403 | if ((irp = devredir_irp_with_pathname_new(path)) != NULL) | |
1404 | { | |
1405 | /* convert / to windows compatible \ */ | |
1406 | devredir_cvt_slash(irp->pathname); | |
1407 | ||
1408 | irp->completion_type = CID_OPEN_REQ; | |
1409 | irp->CompletionId = g_completion_id++; | |
1410 | irp->DeviceId = device_id; | |
1411 | ||
1412 | irp->fuse_info = fusep; | |
1413 | ||
1414 | switch(flags & O_ACCMODE) | |
1415 | { | |
1416 | case O_RDONLY: | |
1417 | log_debug("open file in O_RDONLY"); | |
1418 | DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; | |
1419 | break; | |
1420 | ||
1421 | case O_WRONLY: | |
1422 | log_debug("open file in O_WRONLY"); | |
1423 | DesiredAccess = DA_FILE_WRITE_DATA | DA_SYNCHRONIZE; | |
1424 | break; | |
1425 | ||
1426 | default: | |
1427 | /* | |
1428 | * The access mode could conceivably be invalid here, | |
1429 | * but we assume this has been checked by the caller | |
1430 | */ | |
1431 | log_debug("open file in O_RDWR"); | |
1432 | /* without the 0x00000010 rdesktop opens files in */ | |
1433 | /* O_RDONLY instead of O_RDWR mode */ | |
1434 | DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | | |
1435 | DA_SYNCHRONIZE | 0x00000010; | |
1436 | } | |
1111 | 1437 | |
1112 | 1438 | CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; |
1113 | 1439 | CreateDisposition = CD_FILE_OPEN; // WAS 1 |
1114 | #else | |
1115 | /* got this value from windows; the 0x00000010 was added by LK; */ | |
1116 | /* without this rdesktop opens files in O_RDONLY instead of */ | |
1117 | /* O_RDWR mode */ | |
1118 | DesiredAccess = 0x00120089 | 0x00000010; | |
1119 | CreateOptions = 0x20060; | |
1120 | CreateDisposition = 0x01; | |
1121 | #endif | |
1122 | } | |
1123 | ||
1124 | rval = dev_redir_send_drive_create_request(device_id, path, | |
1125 | DesiredAccess, CreateOptions, | |
1126 | CreateDisposition, | |
1127 | irp->CompletionId); | |
1440 | ||
1441 | rval = devredir_send_drive_create_request(device_id, path, | |
1442 | DesiredAccess, CreateOptions, | |
1443 | FileAttributes, | |
1444 | CreateDisposition, | |
1445 | irp->CompletionId); | |
1446 | } | |
1128 | 1447 | |
1129 | 1448 | return rval; |
1130 | 1449 | } |
1131 | 1450 | |
1132 | int devredir_file_close(void *fusep, tui32 device_id, tui32 FileId) | |
1451 | int devredir_file_close(struct state_close *fusep, tui32 device_id, | |
1452 | tui32 FileId) | |
1133 | 1453 | { |
1134 | 1454 | IRP *irp; |
1135 | 1455 | |
1150 | 1470 | #endif |
1151 | 1471 | irp->completion_type = CID_FILE_CLOSE; |
1152 | 1472 | irp->DeviceId = device_id; |
1153 | devredir_fuse_data_enqueue(irp, fusep); | |
1154 | ||
1155 | return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1156 | PAKID_CORE_DEVICE_IOREQUEST, | |
1157 | device_id, | |
1158 | FileId, | |
1159 | irp->CompletionId, | |
1160 | IRP_MJ_CLOSE, | |
1161 | 0, 32); | |
1473 | irp->fuse_info = fusep; | |
1474 | ||
1475 | return devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1476 | PAKID_CORE_DEVICE_IOREQUEST, | |
1477 | device_id, | |
1478 | FileId, | |
1479 | irp->CompletionId, | |
1480 | IRP_MJ_CLOSE, | |
1481 | IRP_MN_NONE, 32); | |
1162 | 1482 | } |
1163 | 1483 | |
1164 | 1484 | /** |
1166 | 1486 | *****************************************************************************/ |
1167 | 1487 | |
1168 | 1488 | int |
1169 | devredir_rmdir_or_file(void *fusep, tui32 device_id, const char *path, int mode) | |
1489 | devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id, | |
1490 | const char *path) | |
1170 | 1491 | { |
1171 | 1492 | tui32 DesiredAccess; |
1172 | 1493 | tui32 CreateOptions; |
1173 | 1494 | tui32 CreateDisposition; |
1174 | int rval; | |
1495 | int rval = -1; | |
1175 | 1496 | IRP *irp; |
1176 | 1497 | |
1177 | if ((irp = devredir_irp_new()) == NULL) | |
1178 | return -1; | |
1179 | ||
1180 | irp->CompletionId = g_completion_id++; | |
1181 | irp->completion_type = CID_RMDIR_OR_FILE; | |
1182 | irp->DeviceId = device_id; | |
1183 | ||
1184 | strncpy(irp->pathname, path, 255); | |
1185 | devredir_fuse_data_enqueue(irp, fusep); | |
1186 | ||
1187 | //DesiredAccess = DA_DELETE | DA_FILE_READ_ATTRIBUTES | DA_SYNCHRONIZE; | |
1188 | DesiredAccess = 0x00100080; /* got this value from windows */ | |
1189 | ||
1190 | //CreateOptions = CO_FILE_DELETE_ON_CLOSE | CO_FILE_DIRECTORY_FILE | | |
1191 | // CO_FILE_SYNCHRONOUS_IO_NONALERT; | |
1192 | CreateOptions = 0x020; /* got this value from windows */ | |
1193 | ||
1194 | //CreateDisposition = CD_FILE_OPEN; // WAS 1 | |
1195 | CreateDisposition = 0x01; /* got this value from windows */ | |
1196 | ||
1197 | rval = dev_redir_send_drive_create_request(device_id, path, | |
1198 | DesiredAccess, CreateOptions, | |
1199 | CreateDisposition, | |
1200 | irp->CompletionId); | |
1498 | if ((irp = devredir_irp_with_pathname_new(path)) != NULL) | |
1499 | { | |
1500 | /* convert / to windows compatible \ */ | |
1501 | devredir_cvt_slash(irp->pathname); | |
1502 | ||
1503 | irp->CompletionId = g_completion_id++; | |
1504 | irp->completion_type = CID_RMDIR_OR_FILE; | |
1505 | irp->DeviceId = device_id; | |
1506 | ||
1507 | irp->fuse_info = fusep; | |
1508 | ||
1509 | //DesiredAccess = DA_DELETE | DA_FILE_READ_ATTRIBUTES | DA_SYNCHRONIZE; | |
1510 | DesiredAccess = 0x00100080; /* got this value from windows */ | |
1511 | ||
1512 | //CreateOptions = CO_FILE_DELETE_ON_CLOSE | CO_FILE_DIRECTORY_FILE | | |
1513 | // CO_FILE_SYNCHRONOUS_IO_NONALERT; | |
1514 | CreateOptions = 0x020; /* got this value from windows */ | |
1515 | ||
1516 | //CreateDisposition = CD_FILE_OPEN; // WAS 1 | |
1517 | CreateDisposition = 0x01; /* got this value from windows */ | |
1518 | ||
1519 | rval = devredir_send_drive_create_request(device_id, path, | |
1520 | DesiredAccess, CreateOptions, | |
1521 | 0, CreateDisposition, | |
1522 | irp->CompletionId); | |
1523 | } | |
1201 | 1524 | |
1202 | 1525 | return rval; |
1203 | 1526 | } |
1209 | 1532 | *****************************************************************************/ |
1210 | 1533 | |
1211 | 1534 | int |
1212 | devredir_file_read(void *fusep, tui32 DeviceId, tui32 FileId, | |
1535 | devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId, | |
1213 | 1536 | tui32 Length, tui64 Offset) |
1214 | 1537 | { |
1215 | 1538 | struct stream *s; |
1216 | 1539 | IRP *irp; |
1217 | 1540 | IRP *new_irp; |
1218 | 1541 | int bytes; |
1542 | int rval = -1; | |
1219 | 1543 | |
1220 | 1544 | xstream_new(s, 1024); |
1221 | 1545 | |
1546 | /* Check we've got an open IRP for this file already */ | |
1222 | 1547 | if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) |
1223 | 1548 | { |
1224 | 1549 | log_error("no IRP found with FileId = %d", FileId); |
1225 | 1550 | xfuse_devredir_cb_read_file(fusep, NULL, 0); |
1226 | 1551 | xstream_free(s); |
1227 | return -1; | |
1228 | } | |
1229 | ||
1552 | } | |
1230 | 1553 | /* create a new IRP for this request */ |
1231 | if ((new_irp = devredir_irp_clone(irp)) == NULL) | |
1554 | else if ((new_irp = devredir_irp_new()) == NULL) | |
1232 | 1555 | { |
1233 | 1556 | /* system out of memory */ |
1234 | 1557 | xfuse_devredir_cb_read_file(fusep, NULL, 0); |
1235 | 1558 | xstream_free(s); |
1236 | return -1; | |
1237 | } | |
1238 | new_irp->FileId = 0; | |
1239 | new_irp->completion_type = CID_READ; | |
1240 | new_irp->CompletionId = g_completion_id++; | |
1241 | devredir_fuse_data_enqueue(new_irp, fusep); | |
1242 | ||
1243 | devredir_insert_DeviceIoRequest(s, | |
1244 | DeviceId, | |
1245 | FileId, | |
1246 | new_irp->CompletionId, | |
1247 | IRP_MJ_READ, | |
1248 | 0); | |
1249 | ||
1250 | xstream_wr_u32_le(s, Length); | |
1251 | xstream_wr_u64_le(s, Offset); | |
1252 | xstream_seek(s, 20); | |
1253 | ||
1254 | /* send to client */ | |
1255 | bytes = xstream_len(s); | |
1256 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
1257 | xstream_free(s); | |
1258 | ||
1259 | return 0; | |
1559 | } | |
1560 | else | |
1561 | { | |
1562 | new_irp->DeviceId = DeviceId; | |
1563 | new_irp->FileId = FileId; | |
1564 | new_irp->completion_type = CID_READ; | |
1565 | new_irp->CompletionId = g_completion_id++; | |
1566 | new_irp->fuse_info = fusep; | |
1567 | ||
1568 | devredir_insert_DeviceIoRequest(s, | |
1569 | DeviceId, | |
1570 | FileId, | |
1571 | new_irp->CompletionId, | |
1572 | IRP_MJ_READ, | |
1573 | IRP_MN_NONE); | |
1574 | ||
1575 | xstream_wr_u32_le(s, Length); | |
1576 | xstream_wr_u64_le(s, Offset); | |
1577 | xstream_seek(s, 20); | |
1578 | ||
1579 | /* send to client */ | |
1580 | bytes = xstream_len(s); | |
1581 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
1582 | xstream_free(s); | |
1583 | rval = 0; | |
1584 | } | |
1585 | ||
1586 | return rval; | |
1260 | 1587 | } |
1261 | 1588 | |
1262 | 1589 | int |
1263 | dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, | |
1264 | const char *buf, int Length, tui64 Offset) | |
1590 | devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, | |
1591 | const char *buf, int Length, tui64 Offset) | |
1265 | 1592 | { |
1266 | 1593 | struct stream *s; |
1267 | 1594 | IRP *irp; |
1268 | 1595 | IRP *new_irp; |
1269 | 1596 | int bytes; |
1597 | int rval = -1; | |
1270 | 1598 | |
1271 | 1599 | log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld", |
1272 | 1600 | DeviceId, FileId, Length, (long long)Offset); |
1276 | 1604 | if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) |
1277 | 1605 | { |
1278 | 1606 | log_error("no IRP found with FileId = %d", FileId); |
1279 | xfuse_devredir_cb_write_file(fusep, NULL, 0); | |
1607 | xfuse_devredir_cb_write_file(fusep, NT_STATUS_UNSUCCESSFUL, 0, 0); | |
1280 | 1608 | xstream_free(s); |
1281 | return -1; | |
1282 | } | |
1283 | ||
1609 | } | |
1284 | 1610 | /* create a new IRP for this request */ |
1285 | if ((new_irp = devredir_irp_clone(irp)) == NULL) | |
1611 | else if ((new_irp = devredir_irp_new()) == NULL) | |
1286 | 1612 | { |
1287 | 1613 | /* system out of memory */ |
1288 | xfuse_devredir_cb_write_file(fusep, NULL, 0); | |
1614 | xfuse_devredir_cb_write_file(fusep, NT_STATUS_UNSUCCESSFUL, 0, 0); | |
1289 | 1615 | xstream_free(s); |
1290 | return -1; | |
1291 | } | |
1292 | new_irp->FileId = 0; | |
1293 | new_irp->completion_type = CID_WRITE; | |
1294 | new_irp->CompletionId = g_completion_id++; | |
1295 | devredir_fuse_data_enqueue(new_irp, fusep); | |
1296 | ||
1297 | devredir_insert_DeviceIoRequest(s, | |
1298 | DeviceId, | |
1299 | FileId, | |
1300 | new_irp->CompletionId, | |
1301 | IRP_MJ_WRITE, | |
1302 | 0); | |
1303 | ||
1304 | xstream_wr_u32_le(s, Length); | |
1305 | xstream_wr_u64_le(s, Offset); | |
1306 | xstream_seek(s, 20); /* padding */ | |
1307 | ||
1308 | /* now insert real data */ | |
1309 | xstream_copyin(s, buf, Length); | |
1310 | ||
1311 | /* send to client */ | |
1312 | bytes = xstream_len(s); | |
1313 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
1314 | xstream_free(s); | |
1315 | ||
1316 | return 0; | |
1317 | } | |
1318 | ||
1319 | /****************************************************************************** | |
1320 | ** FIFO for FUSE_DATA ** | |
1321 | ******************************************************************************/ | |
1322 | ||
1323 | /** | |
1324 | * Return FUSE_DATA at the head of the queue without removing it | |
1325 | * | |
1326 | * @return FUSE_DATA on success, or NULL on failure | |
1327 | *****************************************************************************/ | |
1328 | ||
1329 | FUSE_DATA * | |
1330 | devredir_fuse_data_peek(IRP *irp) | |
1331 | { | |
1332 | log_debug("returning %p", irp->fd_head); | |
1333 | return irp->fd_head; | |
1334 | } | |
1335 | ||
1336 | /** | |
1337 | * Return oldest FUSE_DATA from queue | |
1338 | * | |
1339 | * @return FUSE_DATA on success, NULL on failure | |
1340 | *****************************************************************************/ | |
1341 | ||
1342 | FUSE_DATA * | |
1343 | devredir_fuse_data_dequeue(IRP *irp) | |
1344 | { | |
1345 | FUSE_DATA *head; | |
1346 | ||
1347 | if ((irp == NULL) || (irp->fd_head == NULL)) | |
1348 | { | |
1349 | log_debug("+++ returning NULL"); | |
1350 | return NULL; | |
1351 | } | |
1352 | ||
1353 | if (irp->fd_head->next == NULL) | |
1354 | { | |
1355 | /* only one element in queue */ | |
1356 | head = irp->fd_head; | |
1357 | irp->fd_head = NULL; | |
1358 | irp->fd_tail = NULL; | |
1359 | log_debug("+++ returning FUSE_DATA=%p containing FUSE_INFO=%p", | |
1360 | head, head->data_ptr); | |
1361 | return head; | |
1362 | } | |
1363 | ||
1364 | /* more than one element in queue */ | |
1365 | head = irp->fd_head; | |
1366 | irp->fd_head = head->next; | |
1367 | log_debug("+++ returning FUSE_DATA=%p containing FUSE_INFO=%p", | |
1368 | head, head->data_ptr); | |
1369 | return head; | |
1370 | } | |
1371 | ||
1372 | /** | |
1373 | * Insert specified FUSE_DATA at the end of our queue | |
1374 | * | |
1375 | * @return 0 on success, -1 on failure | |
1376 | *****************************************************************************/ | |
1377 | ||
1378 | int | |
1379 | devredir_fuse_data_enqueue(IRP *irp, void *vp) | |
1380 | { | |
1381 | FUSE_DATA *fd; | |
1382 | FUSE_DATA *tail; | |
1383 | ||
1384 | if (irp == NULL) | |
1385 | return -1; | |
1386 | ||
1387 | fd = g_new0(FUSE_DATA, 1); | |
1388 | if (fd == NULL) | |
1389 | return -1; | |
1390 | ||
1391 | fd->data_ptr = vp; | |
1392 | fd->next = NULL; | |
1393 | ||
1394 | if (irp->fd_tail == NULL) | |
1395 | { | |
1396 | /* queue is empty, insert at head */ | |
1397 | irp->fd_head = fd; | |
1398 | irp->fd_tail = fd; | |
1399 | log_debug("+++ inserted FUSE_DATA=%p containing FUSE_INFO=%p at head", | |
1400 | fd, vp); | |
1401 | return 0; | |
1402 | } | |
1403 | ||
1404 | /* queue is not empty, insert at tail end */ | |
1405 | tail = irp->fd_tail; | |
1406 | tail->next = fd; | |
1407 | irp->fd_tail = fd; | |
1408 | log_debug("+++ inserted FUSE_DATA=%p containing FUSE_INFO=%p at tail", | |
1409 | fd, vp); | |
1410 | return 0; | |
1411 | } | |
1616 | } | |
1617 | else | |
1618 | { | |
1619 | new_irp->DeviceId = DeviceId; | |
1620 | new_irp->FileId = FileId; | |
1621 | new_irp->completion_type = CID_WRITE; | |
1622 | new_irp->CompletionId = g_completion_id++; | |
1623 | new_irp->fuse_info = fusep; | |
1624 | /* Offset needed after write to calculate new EOF */ | |
1625 | new_irp->gen.write.offset = Offset; | |
1626 | ||
1627 | devredir_insert_DeviceIoRequest(s, | |
1628 | DeviceId, | |
1629 | FileId, | |
1630 | new_irp->CompletionId, | |
1631 | IRP_MJ_WRITE, | |
1632 | IRP_MN_NONE); | |
1633 | ||
1634 | xstream_wr_u32_le(s, Length); | |
1635 | xstream_wr_u64_le(s, Offset); | |
1636 | xstream_seek(s, 20); /* padding */ | |
1637 | ||
1638 | /* now insert real data */ | |
1639 | xstream_copyin(s, buf, Length); | |
1640 | ||
1641 | /* send to client */ | |
1642 | bytes = xstream_len(s); | |
1643 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
1644 | xstream_free(s); | |
1645 | rval = 0; | |
1646 | } | |
1647 | ||
1648 | return rval; | |
1649 | } | |
1650 | ||
1651 | ||
1652 | int devredir_file_rename(struct state_rename *fusep, tui32 device_id, | |
1653 | const char *old_name, | |
1654 | const char *new_name) | |
1655 | { | |
1656 | tui32 DesiredAccess; | |
1657 | tui32 CreateOptions; | |
1658 | tui32 FileAttributes = 0; | |
1659 | tui32 CreateDisposition; | |
1660 | int rval = -1; | |
1661 | IRP *irp; | |
1662 | unsigned int len; | |
1663 | ||
1664 | log_debug("device_id=%d old_name=%s new_name=%s", | |
1665 | device_id, old_name, new_name); | |
1666 | ||
1667 | /* | |
1668 | * Allocate an IRP with enough space for both the old and new names. | |
1669 | * We'll store the new name after the old name:- | |
1670 | * | |
1671 | * | n | a | m | e | 1 | \0 | n | a | m | e | 2 | \0 | | |
1672 | * ^ ^ | |
1673 | * irp->pathname ----+ | | |
1674 | * irp->gen.rename.new_name ------------------+ | |
1675 | */ | |
1676 | len = strlen(old_name) + 1 + strlen(new_name); | |
1677 | if ((irp = devredir_irp_with_pathnamelen_new(len)) != NULL) | |
1678 | { | |
1679 | /* Set up pointer to new name string */ | |
1680 | irp->gen.rename.new_name = irp->pathname + strlen(old_name) + 1; | |
1681 | ||
1682 | /* Copy both strings, and change'/' to '\\' characters */ | |
1683 | strcpy(irp->pathname, old_name); | |
1684 | devredir_cvt_slash(irp->pathname); | |
1685 | strcpy(irp->gen.rename.new_name, new_name); | |
1686 | devredir_cvt_slash(irp->gen.rename.new_name); | |
1687 | ||
1688 | irp->completion_type = CID_RENAME_FILE; | |
1689 | irp->CompletionId = g_completion_id++; | |
1690 | irp->DeviceId = device_id; | |
1691 | ||
1692 | irp->fuse_info = fusep; | |
1693 | ||
1694 | DesiredAccess = DA_FILE_WRITE_ATTRIBUTES | DA_DELETE; | |
1695 | CreateOptions = 0; | |
1696 | CreateDisposition = CD_FILE_OPEN; // WAS 1 | |
1697 | ||
1698 | rval = devredir_send_drive_create_request(device_id, old_name, | |
1699 | DesiredAccess, CreateOptions, | |
1700 | FileAttributes, | |
1701 | CreateDisposition, | |
1702 | irp->CompletionId); | |
1703 | } | |
1704 | ||
1705 | return rval; | |
1706 | } | |
1707 | ||
1412 | 1708 | |
1413 | 1709 | /****************************************************************************** |
1414 | 1710 | ** miscellaneous stuff ** |
1419 | 1715 | tui32 DeviceId, |
1420 | 1716 | tui32 FileId, |
1421 | 1717 | tui32 CompletionId, |
1422 | tui32 MajorFunction, | |
1423 | tui32 MinorFunction) | |
1718 | enum IRP_MJ MajorFunction, | |
1719 | enum IRP_MN MinorFunction) | |
1424 | 1720 | { |
1425 | 1721 | /* setup DR_DEVICE_IOREQUEST header */ |
1426 | 1722 | xstream_wr_u16_le(s, RDPDR_CTYP_CORE); |
1436 | 1732 | * Convert / to windows compatible \ |
1437 | 1733 | *****************************************************************************/ |
1438 | 1734 | |
1439 | void | |
1735 | static void | |
1440 | 1736 | devredir_cvt_slash(char *path) |
1441 | 1737 | { |
1442 | 1738 | char *cptr = path; |
1449 | 1745 | } |
1450 | 1746 | } |
1451 | 1747 | |
1452 | void | |
1748 | static void | |
1453 | 1749 | devredir_cvt_to_unicode(char *unicode, const char *path) |
1454 | 1750 | { |
1455 | 1751 | char *dest; |
1475 | 1771 | *dest++ = 0; |
1476 | 1772 | } |
1477 | 1773 | |
1478 | void | |
1774 | static void | |
1479 | 1775 | devredir_cvt_from_unicode_len(char *path, char *unicode, int len) |
1480 | 1776 | { |
1481 | 1777 | char *dest; |
1512 | 1808 | g_free(dest_saved); |
1513 | 1809 | } |
1514 | 1810 | |
1515 | int | |
1516 | dev_redir_string_ends_with(char *string, char c) | |
1517 | { | |
1518 | int len; | |
1811 | static int | |
1812 | devredir_string_ends_with(const char *string, char c) | |
1813 | { | |
1814 | size_t len; | |
1519 | 1815 | |
1520 | 1816 | len = strlen(string); |
1521 | return (string[len - 1] == c) ? 1 : 0; | |
1522 | } | |
1523 | ||
1524 | void | |
1525 | devredir_insert_RDPDR_header(struct stream *s, tui16 Component, | |
1526 | tui16 PacketId) | |
1527 | { | |
1528 | xstream_wr_u16_le(s, Component); | |
1529 | xstream_wr_u16_le(s, PacketId); | |
1530 | } | |
1531 | ||
1532 | void | |
1533 | devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus) | |
1817 | return (len > 0 && string[len - 1] == c) ? 1 : 0; | |
1818 | } | |
1819 | ||
1820 | static void | |
1821 | devredir_proc_cid_rmdir_or_file(IRP *irp, enum NTSTATUS IoStatus) | |
1534 | 1822 | { |
1535 | 1823 | struct stream *s; |
1536 | 1824 | int bytes; |
1537 | 1825 | |
1538 | 1826 | if (IoStatus != NT_STATUS_SUCCESS) |
1539 | 1827 | { |
1540 | FUSE_DATA *fuse_data = devredir_fuse_data_dequeue(irp); | |
1541 | if (fuse_data) | |
1542 | { | |
1543 | xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); | |
1544 | free(fuse_data); | |
1545 | } | |
1828 | xfuse_devredir_cb_rmdir_or_file((struct state_remove *) irp->fuse_info, | |
1829 | IoStatus); | |
1546 | 1830 | devredir_irp_delete(irp); |
1547 | 1831 | return; |
1548 | 1832 | } |
1552 | 1836 | irp->completion_type = CID_RMDIR_OR_FILE_RESP; |
1553 | 1837 | devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, |
1554 | 1838 | irp->CompletionId, |
1555 | IRP_MJ_SET_INFORMATION, 0); | |
1839 | IRP_MJ_SET_INFORMATION, IRP_MN_NONE); | |
1556 | 1840 | |
1557 | 1841 | xstream_wr_u32_le(s, FileDispositionInformation); |
1558 | 1842 | xstream_wr_u32_le(s, 0); /* length is zero */ |
1566 | 1850 | return; |
1567 | 1851 | } |
1568 | 1852 | |
1569 | void | |
1570 | devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus) | |
1571 | { | |
1572 | FUSE_DATA *fuse_data; | |
1573 | ||
1574 | fuse_data = devredir_fuse_data_dequeue(irp); | |
1575 | if (fuse_data) | |
1576 | { | |
1577 | xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); | |
1578 | free(fuse_data); | |
1579 | } | |
1853 | static void | |
1854 | devredir_proc_cid_rmdir_or_file_resp(IRP *irp, enum NTSTATUS IoStatus) | |
1855 | { | |
1856 | xfuse_devredir_cb_rmdir_or_file((struct state_remove *)irp->fuse_info, | |
1857 | IoStatus); | |
1580 | 1858 | |
1581 | 1859 | if (IoStatus != NT_STATUS_SUCCESS) |
1582 | 1860 | { |
1585 | 1863 | } |
1586 | 1864 | |
1587 | 1865 | irp->completion_type = CID_CLOSE; |
1588 | dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1589 | PAKID_CORE_DEVICE_IOREQUEST, | |
1590 | irp->DeviceId, | |
1591 | irp->FileId, | |
1592 | irp->CompletionId, | |
1593 | IRP_MJ_CLOSE, 0, 32); | |
1594 | } | |
1595 | ||
1596 | void | |
1597 | devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus) | |
1866 | devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1867 | PAKID_CORE_DEVICE_IOREQUEST, | |
1868 | irp->DeviceId, | |
1869 | irp->FileId, | |
1870 | irp->CompletionId, | |
1871 | IRP_MJ_CLOSE, IRP_MN_NONE, 32); | |
1872 | } | |
1873 | ||
1874 | static void | |
1875 | devredir_proc_cid_rename_file(IRP *irp, enum NTSTATUS IoStatus) | |
1598 | 1876 | { |
1599 | 1877 | struct stream *s; |
1600 | 1878 | int bytes; |
1606 | 1884 | { |
1607 | 1885 | log_debug("rename returned with IoStatus=0x%x", IoStatus); |
1608 | 1886 | |
1609 | FUSE_DATA *fuse_data = devredir_fuse_data_dequeue(irp); | |
1610 | if (fuse_data) | |
1611 | { | |
1612 | xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); | |
1613 | free(fuse_data); | |
1614 | } | |
1887 | xfuse_devredir_cb_rename_file((struct state_rename *)irp->fuse_info, | |
1888 | IoStatus); | |
1615 | 1889 | devredir_irp_delete(irp); |
1616 | 1890 | return; |
1617 | 1891 | } |
1618 | 1892 | |
1619 | 1893 | /* Path in unicode needs this much space */ |
1620 | flen = ((g_mbstowcs(NULL, irp->gen_buf, 0) * sizeof(twchar)) / 2) + 2; | |
1894 | flen = ((g_mbstowcs(NULL, irp->gen.rename.new_name, 0) | |
1895 | * sizeof(twchar)) / 2) + 2; | |
1621 | 1896 | sblen = 6 + flen; |
1622 | 1897 | |
1623 | 1898 | xstream_new(s, 1024 + flen); |
1625 | 1900 | irp->completion_type = CID_RENAME_FILE_RESP; |
1626 | 1901 | devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, |
1627 | 1902 | irp->CompletionId, |
1628 | IRP_MJ_SET_INFORMATION, 0); | |
1903 | IRP_MJ_SET_INFORMATION, IRP_MN_NONE); | |
1629 | 1904 | |
1630 | 1905 | xstream_wr_u32_le(s, FileRenameInformation); |
1631 | 1906 | xstream_wr_u32_le(s, sblen); /* number of bytes after padding */ |
1635 | 1910 | xstream_wr_u32_le(s, flen); /* FileNameLength */ |
1636 | 1911 | |
1637 | 1912 | /* filename in unicode */ |
1638 | devredir_cvt_to_unicode(s->p, irp->gen_buf); /* UNICODE_TODO */ | |
1913 | devredir_cvt_to_unicode(s->p, irp->gen.rename.new_name); /* UNICODE_TODO */ | |
1639 | 1914 | xstream_seek(s, flen); |
1640 | 1915 | |
1641 | 1916 | /* send to client */ |
1646 | 1921 | return; |
1647 | 1922 | } |
1648 | 1923 | |
1649 | void | |
1650 | devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus) | |
1651 | { | |
1652 | FUSE_DATA *fuse_data; | |
1653 | ||
1924 | static void | |
1925 | devredir_proc_cid_rename_file_resp(IRP *irp, enum NTSTATUS IoStatus) | |
1926 | { | |
1654 | 1927 | log_debug("entered"); |
1655 | 1928 | |
1656 | fuse_data = devredir_fuse_data_dequeue(irp); | |
1657 | if (fuse_data) | |
1658 | { | |
1659 | xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); | |
1660 | free(fuse_data); | |
1661 | } | |
1929 | xfuse_devredir_cb_rename_file((struct state_rename *)irp->fuse_info, | |
1930 | IoStatus); | |
1662 | 1931 | |
1663 | 1932 | if (IoStatus != NT_STATUS_SUCCESS) |
1664 | 1933 | { |
1667 | 1936 | } |
1668 | 1937 | |
1669 | 1938 | irp->completion_type = CID_CLOSE; |
1670 | dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1939 | devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
1671 | 1940 | PAKID_CORE_DEVICE_IOREQUEST, |
1672 | 1941 | irp->DeviceId, |
1673 | 1942 | irp->FileId, |
1674 | 1943 | irp->CompletionId, |
1675 | IRP_MJ_CLOSE, 0, 32); | |
1676 | } | |
1944 | IRP_MJ_CLOSE, IRP_MN_NONE, 32); | |
1945 | } | |
1946 | ||
1947 | ||
1948 | /* | |
1949 | * Re-uses the specified IRP to issue a request to get file attributes | |
1950 | * of varying types | |
1951 | * | |
1952 | * References : [MS-RDPEFS] 2.2.3.3.9 [MS-FSCC] 2.4 | |
1953 | *****************************************************************************/ | |
1954 | static void issue_lookup(IRP *irp, int lookup_type) | |
1955 | { | |
1956 | struct stream *s; | |
1957 | int bytes; | |
1958 | ||
1959 | bytes = | |
1960 | lookup_type == FileBasicInformation ? FILE_BASIC_INFORMATION_SIZE : | |
1961 | lookup_type == FileStandardInformation ? FILE_STD_INFORMATION_SIZE : | |
1962 | 0; | |
1963 | xstream_new(s, 1024); | |
1964 | devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, | |
1965 | irp->CompletionId, | |
1966 | IRP_MJ_QUERY_INFORMATION, IRP_MN_NONE); | |
1967 | ||
1968 | xstream_wr_u32_le(s, lookup_type); | |
1969 | xstream_wr_u32_le(s, bytes); /* buffer length */ | |
1970 | xstream_seek(s, 24); /* padding */ | |
1971 | xstream_seek(s, bytes); /* buffer */ | |
1972 | ||
1973 | /* send to client */ | |
1974 | bytes = xstream_len(s); | |
1975 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
1976 | xstream_free(s); | |
1977 | } | |
1978 | ||
1979 | /* | |
1980 | * Parses an incoming FileBasicInformation structure | |
1981 | *****************************************************************************/ | |
1982 | static void lookup_read_basic_attributes(IRP *irp, struct stream *s_in) | |
1983 | { | |
1984 | tui64 LastAccessTime; | |
1985 | tui64 LastWriteTime; | |
1986 | tui32 FileAttributes; | |
1987 | ||
1988 | log_debug("processing FILE_BASIC_INFORMATION"); | |
1989 | ||
1990 | xstream_seek(s_in, 8); /* CreationTime */ | |
1991 | xstream_rd_u64_le(s_in, LastAccessTime); | |
1992 | xstream_rd_u64_le(s_in, LastWriteTime); | |
1993 | xstream_seek(s_in, 8); /* ChangeTime */ | |
1994 | xstream_rd_u32_le(s_in, FileAttributes); | |
1995 | ||
1996 | //log_debug("LastAccessTime: 0x%llx", | |
1997 | // (unsigned long long)LastAccessTime); | |
1998 | //log_debug("LastWriteTime: 0x%llx", | |
1999 | // (unsigned long long)LastWriteTime); | |
2000 | //log_debug("ChangeTime: 0x%llx", | |
2001 | // (unsigned long long)ChangeTime); | |
2002 | //log_debug("FileAttributes: 0x%x", (unsigned int)FileAttributes); | |
2003 | ||
2004 | /* Save the basic attributes in the IRP */ | |
2005 | irp->gen.lookup.fattr.mode = WindowsToLinuxFilePerm(FileAttributes); | |
2006 | irp->gen.lookup.fattr.atime = WINDOWS_TO_LINUX_TIME(LastAccessTime); | |
2007 | irp->gen.lookup.fattr.mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime); | |
2008 | } | |
2009 | ||
2010 | /* | |
2011 | * Parses an incoming FileStandardInformation structure | |
2012 | *****************************************************************************/ | |
2013 | static void lookup_read_standard_attributes(IRP *irp, struct stream *s_in) | |
2014 | { | |
2015 | tui64 EndOfFile; | |
2016 | log_debug("processing FILE_STD_INFORMATION"); | |
2017 | xstream_seek(s_in, 8); /* AllocationSize */ | |
2018 | xstream_rd_u64_le(s_in, EndOfFile); | |
2019 | //log_debug("EndOfFile: %lld", | |
2020 | // (unsigned long long)EndOfFile); | |
2021 | ||
2022 | irp->gen.lookup.fattr.size = EndOfFile; | |
2023 | } | |
2024 | ||
2025 | /* | |
2026 | * Completes a lookup request and returns status to the caller. | |
2027 | * | |
2028 | * Unless IoStatus is NT_STATUS_SUCCESS, the lookup has failed. | |
2029 | *****************************************************************************/ | |
2030 | static void lookup_done(IRP *irp, enum NTSTATUS IoStatus) | |
2031 | { | |
2032 | log_debug("Lookup with completion_id=%d returning 0x%x", | |
2033 | irp->CompletionId, IoStatus); | |
2034 | xfuse_devredir_cb_lookup_entry((struct state_lookup *)irp->fuse_info, | |
2035 | IoStatus, | |
2036 | &irp->gen.lookup.fattr); | |
2037 | ||
2038 | if (irp->FileId == 0) | |
2039 | { | |
2040 | /* Open failed - no file handle */ | |
2041 | devredir_irp_delete(irp); | |
2042 | } | |
2043 | else | |
2044 | { | |
2045 | /* Close the file handle */ | |
2046 | irp->completion_type = CID_CLOSE; | |
2047 | devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
2048 | PAKID_CORE_DEVICE_IOREQUEST, | |
2049 | irp->DeviceId, | |
2050 | irp->FileId, | |
2051 | irp->CompletionId, | |
2052 | IRP_MJ_CLOSE, IRP_MN_NONE, 32); | |
2053 | } | |
2054 | } | |
2055 | ||
2056 | ||
2057 | /* | |
2058 | * lookup has a mini state machine built-in, as it needs to issue | |
2059 | * multiple I/O requests, but unlike lookup these are not always the same. | |
2060 | */ | |
2061 | static void | |
2062 | devredir_proc_cid_lookup(IRP *irp, | |
2063 | struct stream *s_in, | |
2064 | enum NTSTATUS IoStatus) | |
2065 | { | |
2066 | tui32 Length; | |
2067 | ||
2068 | log_debug("entry state is %d",irp->gen.lookup.state); | |
2069 | if (IoStatus != NT_STATUS_SUCCESS) | |
2070 | { | |
2071 | /* This is common to all setattr states */ | |
2072 | log_debug("last lookup returned with IoStatus=0x%08x", IoStatus); | |
2073 | lookup_done(irp, IoStatus); | |
2074 | } | |
2075 | else | |
2076 | { | |
2077 | /* Read and validate any data we've got queued up */ | |
2078 | switch(irp->gen.lookup.state) | |
2079 | { | |
2080 | case E_LOOKUP_GET_FH: | |
2081 | /* We've been sent the file ID */ | |
2082 | xstream_rd_u32_le(s_in, irp->FileId); | |
2083 | issue_lookup(irp, FileBasicInformation); | |
2084 | irp->gen.lookup.state = E_LOOKUP_CHECK_BASIC; | |
2085 | break; | |
2086 | ||
2087 | case E_LOOKUP_CHECK_BASIC: | |
2088 | /* Returned length what we expected? */ | |
2089 | xstream_rd_u32_le(s_in, Length); | |
2090 | if (Length != FILE_BASIC_INFORMATION_SIZE) | |
2091 | { | |
2092 | log_error("Expected FILE_BASIC_INFORMATION length" | |
2093 | "%d, got len=%d", | |
2094 | FILE_BASIC_INFORMATION_SIZE, Length); | |
2095 | IoStatus = NT_STATUS_UNSUCCESSFUL; | |
2096 | lookup_done(irp, IoStatus); | |
2097 | } | |
2098 | else | |
2099 | { | |
2100 | lookup_read_basic_attributes(irp, s_in); | |
2101 | issue_lookup(irp, FileStandardInformation); | |
2102 | irp->gen.lookup.state = E_LOOKUP_CHECK_EOF; | |
2103 | } | |
2104 | break; | |
2105 | ||
2106 | case E_LOOKUP_CHECK_EOF: | |
2107 | /* Returned length what we expected? */ | |
2108 | xstream_rd_u32_le(s_in, Length); | |
2109 | if (Length != FILE_STD_INFORMATION_SIZE) | |
2110 | { | |
2111 | log_error("Expected FILE_STD_INFORMATION length" | |
2112 | "%d, got len=%d", | |
2113 | FILE_STD_INFORMATION_SIZE, Length); | |
2114 | IoStatus = NT_STATUS_UNSUCCESSFUL; | |
2115 | } | |
2116 | else | |
2117 | { | |
2118 | lookup_read_standard_attributes(irp, s_in); | |
2119 | } | |
2120 | lookup_done(irp, IoStatus); | |
2121 | break; | |
2122 | } | |
2123 | } | |
2124 | } | |
2125 | ||
2126 | ||
2127 | /* | |
2128 | * Re-uses the specified IRP to issue a request to set basic file attributes | |
2129 | * | |
2130 | * References : [MS-RDPEFS] 2.2.3.3.9 [MS-FSCC] 2.4.7 | |
2131 | *****************************************************************************/ | |
2132 | static void issue_setattr_basic(IRP *irp) | |
2133 | { | |
2134 | struct stream *s; | |
2135 | int bytes; | |
2136 | const struct file_attr *fattr = &irp->gen.setattr.fattr; | |
2137 | tui32 to_set = irp->gen.setattr.to_set; | |
2138 | ||
2139 | tui32 FileAttributes = 0; | |
2140 | tui64 atime = 0; | |
2141 | tui64 mtime = 0; | |
2142 | ||
2143 | if (to_set & TO_SET_MODE) | |
2144 | { | |
2145 | FileAttributes = LinuxToWindowsFilePerm(fattr->mode); | |
2146 | } | |
2147 | if (to_set & TO_SET_ATIME) | |
2148 | { | |
2149 | atime = LINUX_TO_WINDOWS_TIME(fattr->atime); | |
2150 | } | |
2151 | if (to_set & TO_SET_MTIME) | |
2152 | { | |
2153 | mtime = LINUX_TO_WINDOWS_TIME(fattr->mtime); | |
2154 | } | |
2155 | ||
2156 | xstream_new(s, 1024); | |
2157 | devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, | |
2158 | irp->CompletionId, | |
2159 | IRP_MJ_SET_INFORMATION, IRP_MN_NONE); | |
2160 | ||
2161 | xstream_wr_u32_le(s, FileBasicInformation); | |
2162 | xstream_wr_u32_le(s, FILE_BASIC_INFORMATION_SIZE); | |
2163 | /* buffer length */ | |
2164 | xstream_seek(s, 24); /* padding */ | |
2165 | ||
2166 | xstream_wr_u64_le(s, 0LL); /* CreationTime */ | |
2167 | xstream_wr_u64_le(s, atime); /* LastAccessTime */ | |
2168 | xstream_wr_u64_le(s, mtime); /* LastWriteTime */ | |
2169 | xstream_wr_u64_le(s, 0LL); /* ChangeTime */ | |
2170 | xstream_wr_u32_le(s, FileAttributes); /* FileAttributes */ | |
2171 | ||
2172 | /* send to client */ | |
2173 | bytes = xstream_len(s); | |
2174 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
2175 | xstream_free(s); | |
2176 | } | |
2177 | ||
2178 | ||
2179 | /* | |
2180 | * Re-uses the specified IRP to issue a request to set file EOF | |
2181 | * | |
2182 | * References : [MS-RDPEFS] 2.2.3.3.9 [MS-FSCC] 2.4.13 | |
2183 | *****************************************************************************/ | |
2184 | static void issue_setattr_eof(IRP *irp) | |
2185 | { | |
2186 | struct stream *s; | |
2187 | int bytes; | |
2188 | ||
2189 | xstream_new(s, 1024); | |
2190 | devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, | |
2191 | irp->CompletionId, | |
2192 | IRP_MJ_SET_INFORMATION, IRP_MN_NONE); | |
2193 | ||
2194 | xstream_wr_u32_le(s, FileEndOfFileInformation); | |
2195 | xstream_wr_u32_le(s, FILE_END_OF_FILE_INFORMATION_SIZE); | |
2196 | /* buffer length */ | |
2197 | xstream_seek(s, 24); /* padding */ | |
2198 | xstream_wr_u64_le(s, (tui64)irp->gen.setattr.fattr.size); | |
2199 | /* File size */ | |
2200 | /* send to client */ | |
2201 | bytes = xstream_len(s); | |
2202 | send_channel_data(g_rdpdr_chan_id, s->data, bytes); | |
2203 | xstream_free(s); | |
2204 | } | |
2205 | ||
2206 | /* | |
2207 | * Completes a setattr request and returns status to the caller. | |
2208 | *****************************************************************************/ | |
2209 | static void setattr_done(IRP *irp, enum NTSTATUS IoStatus) | |
2210 | { | |
2211 | xfuse_devredir_cb_setattr((struct state_setattr *) irp->fuse_info, | |
2212 | IoStatus); | |
2213 | ||
2214 | if (irp->FileId == 0) | |
2215 | { | |
2216 | /* Open failed - no file handle */ | |
2217 | devredir_irp_delete(irp); | |
2218 | } | |
2219 | else | |
2220 | { | |
2221 | /* Close the file handle */ | |
2222 | irp->completion_type = CID_CLOSE; | |
2223 | devredir_send_drive_close_request(RDPDR_CTYP_CORE, | |
2224 | PAKID_CORE_DEVICE_IOREQUEST, | |
2225 | irp->DeviceId, | |
2226 | irp->FileId, | |
2227 | irp->CompletionId, | |
2228 | IRP_MJ_CLOSE, IRP_MN_NONE, 32); | |
2229 | } | |
2230 | } | |
2231 | ||
2232 | ||
2233 | /* | |
2234 | * setattr has a mini state machine built-in, as it needs to issue | |
2235 | * multiple I/O requests, but unlike lookup these are not always the same. | |
2236 | */ | |
2237 | static void | |
2238 | devredir_proc_cid_setattr(IRP *irp, | |
2239 | struct stream *s_in, | |
2240 | enum NTSTATUS IoStatus) | |
2241 | { | |
2242 | #define TO_SET_BASIC_ATTRS (TO_SET_MODE | \ | |
2243 | TO_SET_ATIME | TO_SET_MTIME) | |
2244 | tui32 Length; | |
2245 | ||
2246 | log_debug("entry state is %d",irp->gen.setattr.state); | |
2247 | if (IoStatus != NT_STATUS_SUCCESS) | |
2248 | { | |
2249 | /* This is common to all setattr states */ | |
2250 | log_debug("last setattr returned with IoStatus=0x%08x", IoStatus); | |
2251 | setattr_done(irp, IoStatus); | |
2252 | } | |
2253 | else | |
2254 | { | |
2255 | /* Read and validate any data we've got queued up */ | |
2256 | switch(irp->gen.setattr.state) | |
2257 | { | |
2258 | case E_SETATTR_GET_FH: | |
2259 | /* We've been sent the file ID */ | |
2260 | xstream_rd_u32_le(s_in, irp->FileId); | |
2261 | break; | |
2262 | ||
2263 | case E_SETATTR_CHECK_BASIC: | |
2264 | /* Returned length what we expected? */ | |
2265 | xstream_rd_u32_le(s_in, Length); | |
2266 | if (Length != FILE_BASIC_INFORMATION_SIZE) | |
2267 | { | |
2268 | log_error("Expected FILE_BASIC_INFORMATION length" | |
2269 | "%d, got len=%d", | |
2270 | FILE_BASIC_INFORMATION_SIZE, Length); | |
2271 | } | |
2272 | ||
2273 | /* Clear the basic bits so we don't end up in here again */ | |
2274 | irp->gen.setattr.to_set &= ~TO_SET_BASIC_ATTRS; | |
2275 | break; | |
2276 | ||
2277 | case E_SETATTR_CHECK_EOF: | |
2278 | /* Returned length what we expected? */ | |
2279 | xstream_rd_u32_le(s_in, Length); | |
2280 | if (Length != FILE_END_OF_FILE_INFORMATION_SIZE) | |
2281 | { | |
2282 | log_error("Expected FILE_END_OF_FILE_INFORMATION length" | |
2283 | "%d, got len=%d", | |
2284 | FILE_END_OF_FILE_INFORMATION_SIZE, Length); | |
2285 | } | |
2286 | ||
2287 | /* Clear the size bits so we don't end up in here again */ | |
2288 | irp->gen.setattr.to_set &= ~TO_SET_SIZE; | |
2289 | break; | |
2290 | } | |
2291 | ||
2292 | /* Work out the next call to issue */ | |
2293 | if (irp->gen.setattr.to_set & TO_SET_BASIC_ATTRS) | |
2294 | { | |
2295 | issue_setattr_basic(irp); | |
2296 | irp->gen.setattr.state = E_SETATTR_CHECK_BASIC; | |
2297 | } | |
2298 | else if (irp->gen.setattr.to_set & TO_SET_SIZE) | |
2299 | { | |
2300 | issue_setattr_eof(irp); | |
2301 | irp->gen.setattr.state = E_SETATTR_CHECK_EOF; | |
2302 | } | |
2303 | else | |
2304 | { | |
2305 | setattr_done(irp, IoStatus); | |
2306 | } | |
2307 | } | |
2308 | #undef TO_SET_BASIC_ATTRS | |
2309 | } |
17 | 17 | * limitations under the License. |
18 | 18 | */ |
19 | 19 | |
20 | // LK_TODO dev_redir_xxx should become devredir_xxx | |
21 | ||
22 | 20 | #if !defined(DEVREDIR_H) |
23 | 21 | #define DEVREDIR_H |
24 | 22 | |
25 | 23 | #include "irp.h" |
24 | #include "ms-rdpefs.h" | |
26 | 25 | |
27 | #define USE_SHORT_NAMES_IN_DIR_LISTING | |
26 | int devredir_init(void); | |
27 | int devredir_deinit(void); | |
28 | 28 | |
29 | FUSE_DATA *devredir_fuse_data_peek(IRP *irp); | |
30 | FUSE_DATA *devredir_fuse_data_dequeue(IRP *irp); | |
31 | int devredir_fuse_data_enqueue(IRP *irp, void *vp); | |
29 | int devredir_data_in(struct stream* s, int chan_id, int chan_flags, | |
30 | int length, int total_length); | |
32 | 31 | |
33 | int dev_redir_init(void); | |
34 | int dev_redir_deinit(void); | |
35 | ||
36 | int dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, | |
37 | int length, int total_length); | |
38 | ||
39 | int dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout); | |
40 | int dev_redir_check_wait_objs(void); | |
41 | ||
42 | void dev_redir_send_server_core_cap_req(void); | |
43 | void dev_redir_send_server_clientID_confirm(void); | |
44 | void dev_redir_send_server_user_logged_on(void); | |
45 | void devredir_send_server_device_announce_resp(tui32 device_id); | |
46 | ||
47 | void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, | |
48 | tui32 InitialQuery, char *Path); | |
49 | ||
50 | int dev_redir_send_drive_create_request(tui32 device_id, | |
51 | const char *path, | |
52 | tui32 DesiredAccess, | |
53 | tui32 CreateOptions, | |
54 | tui32 CreateDisposition, | |
55 | tui32 completion_id); | |
56 | ||
57 | int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, | |
58 | tui32 DeviceId, | |
59 | tui32 FileId, | |
60 | tui32 CompletionId, | |
61 | tui32 MajorFunction, | |
62 | tui32 MinorFunc, | |
63 | int pad_len); | |
64 | ||
65 | void devredir_proc_client_devlist_announce_req(struct stream *s); | |
66 | void dev_redir_proc_client_core_cap_resp(struct stream *s); | |
67 | void dev_redir_proc_device_iocompletion(struct stream *s); | |
68 | ||
69 | void dev_redir_proc_query_dir_response(IRP *irp, | |
70 | struct stream *s, | |
71 | tui32 DeviceId, | |
72 | tui32 CompletionId, | |
73 | tui32 IoStatus); | |
32 | int devredir_get_wait_objs(tbus* objs, int* count, int* timeout); | |
33 | int devredir_check_wait_objs(void); | |
74 | 34 | |
75 | 35 | /* misc stuff */ |
76 | 36 | void devredir_insert_DeviceIoRequest(struct stream *s, |
77 | 37 | tui32 DeviceId, |
78 | 38 | tui32 FileId, |
79 | 39 | tui32 CompletionId, |
80 | tui32 MajorFunction, | |
81 | tui32 MinorFunction); | |
40 | enum IRP_MJ MajorFunction, | |
41 | enum IRP_MN MinorFunction); | |
82 | 42 | |
83 | void devredir_cvt_slash(char *path); | |
84 | void devredir_cvt_to_unicode(char *unicode, const char *path); | |
85 | void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); | |
86 | int dev_redir_string_ends_with(char *string, char c); | |
87 | ||
88 | void devredir_insert_RDPDR_header(struct stream *s, tui16 Component, | |
89 | tui16 PacketId); | |
90 | ||
91 | void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus); | |
92 | void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus); | |
93 | void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus); | |
94 | void devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus); | |
43 | /* State pointer types (opaque outside this module), used for | |
44 | * callback data | |
45 | */ | |
46 | struct state_dirscan; | |
47 | struct state_lookup; | |
48 | struct state_setattr; | |
49 | struct state_open; | |
50 | struct state_create; | |
51 | struct state_read; | |
52 | struct state_write; | |
53 | struct state_remove; | |
54 | struct state_close; | |
95 | 55 | |
96 | 56 | /* called from FUSE module */ |
97 | int dev_redir_get_dir_listing(void *fusep, tui32 device_id, const char *path); | |
98 | 57 | |
99 | int dev_redir_file_open(void *fusep, tui32 device_id, const char *path, | |
100 | int mode, int type, const char *gen_buf); | |
58 | int devredir_get_dir_listing(struct state_dirscan *fusep, tui32 device_id, | |
59 | const char *path); | |
101 | 60 | |
102 | int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id); | |
61 | int devredir_lookup_entry(struct state_lookup *fusep, tui32 device_id, | |
62 | const char *path); | |
103 | 63 | |
104 | int devredir_file_read(void *fusep, tui32 device_id, tui32 FileId, | |
64 | int devredir_setattr_for_entry( | |
65 | struct state_setattr *fusep, tui32 device_id, | |
66 | const char *filename, | |
67 | const struct file_attr *fattr, | |
68 | tui32 to_set); | |
69 | ||
70 | int devredir_file_create( | |
71 | struct state_create *fusep, tui32 device_id, | |
72 | const char *path, int mode); | |
73 | ||
74 | int devredir_file_open(struct state_open *fusep, tui32 device_id, | |
75 | const char *path, int flags); | |
76 | ||
77 | int devredir_file_close(struct state_close *fusep, tui32 device_id, | |
78 | tui32 file_id); | |
79 | ||
80 | int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId, | |
105 | 81 | tui32 Length, tui64 Offset); |
106 | 82 | |
107 | 83 | int |
108 | dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, | |
84 | devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, | |
109 | 85 | const char *buf, int Length, tui64 Offset); |
110 | 86 | |
87 | int devredir_file_rename( | |
88 | struct state_rename *fusep, tui32 device_id, | |
89 | const char *old_name, | |
90 | const char *new_name); | |
91 | ||
111 | 92 | int |
112 | devredir_rmdir_or_file(void *fusep, tui32 device_id, const char *path, int mode); | |
113 | ||
114 | /* | |
115 | * RDPDR_HEADER definitions | |
116 | */ | |
117 | ||
118 | /* device redirector core component; most of the packets in this protocol */ | |
119 | /* are sent under this component ID */ | |
120 | #define RDPDR_CTYP_CORE 0x4472 | |
121 | ||
122 | /* printing component. the packets that use this ID are typically about */ | |
123 | /* printer cache management and identifying XPS printers */ | |
124 | #define RDPDR_CTYP_PRN 0x5052 | |
125 | ||
126 | /* Server Announce Request, as specified in section 2.2.2.2 */ | |
127 | #define PAKID_CORE_SERVER_ANNOUNCE 0x496E | |
128 | ||
129 | /* Client Announce Reply and Server Client ID Confirm, as specified in */ | |
130 | /* sections 2.2.2.3 and 2.2.2.6. */ | |
131 | #define PAKID_CORE_CLIENTID_CONFIRM 0x4343 | |
132 | ||
133 | /* Client Name Request, as specified in section 2.2.2.4 */ | |
134 | #define PAKID_CORE_CLIENT_NAME 0x434E | |
135 | ||
136 | /* Client Device List Announce Request, as specified in section 2.2.2.9 */ | |
137 | #define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441 | |
138 | ||
139 | /* Server Device Announce Response, as specified in section 2.2.2.1 */ | |
140 | #define PAKID_CORE_DEVICE_REPLY 0x6472 | |
141 | ||
142 | /* Device I/O Request, as specified in section 2.2.1.4 */ | |
143 | #define PAKID_CORE_DEVICE_IOREQUEST 0x4952 | |
144 | ||
145 | /* Device I/O Response, as specified in section 2.2.1.5 */ | |
146 | #define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 | |
147 | ||
148 | /* Server Core Capability Request, as specified in section 2.2.2.7 */ | |
149 | #define PAKID_CORE_SERVER_CAPABILITY 0x5350 | |
150 | ||
151 | /* Client Core Capability Response, as specified in section 2.2.2.8 */ | |
152 | #define PAKID_CORE_CLIENT_CAPABILITY 0x4350 | |
153 | ||
154 | /* Client Drive Device List Remove, as specified in section 2.2.3.2 */ | |
155 | #define PAKID_CORE_DEVICELIST_REMOVE 0x444D | |
156 | ||
157 | /* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */ | |
158 | #define PAKID_PRN_CACHE_DATA 0x5043 | |
159 | ||
160 | /* Server User Logged On, as specified in section 2.2.2.5 */ | |
161 | #define PAKID_CORE_USER_LOGGEDON 0x554C | |
162 | ||
163 | /* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */ | |
164 | #define PAKID_PRN_USING_XPS 0x5543 | |
165 | ||
166 | /* | |
167 | * Capability header definitions | |
168 | */ | |
169 | ||
170 | #define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */ | |
171 | #define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */ | |
172 | #define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */ | |
173 | #define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */ | |
174 | #define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */ | |
175 | ||
176 | /* client minor versions */ | |
177 | #define RDP_CLIENT_50 0x0002 | |
178 | #define RDP_CLIENT_51 0x0005 | |
179 | #define RDP_CLIENT_52 0x000a | |
180 | #define RDP_CLIENT_60_61 0x000c | |
181 | ||
182 | /* used in device announce list */ | |
183 | #define RDPDR_DTYP_SERIAL 0x0001 | |
184 | #define RDPDR_DTYP_PARALLEL 0x0002 | |
185 | #define RDPDR_DTYP_PRINT 0x0004 | |
186 | #define RDPDR_DTYP_FILESYSTEM 0x0008 | |
187 | #define RDPDR_DTYP_SMARTCARD 0x0020 | |
188 | ||
189 | /* | |
190 | * DesiredAccess Mask [MS-SMB2] section 2.2.13.1.1 | |
191 | */ | |
192 | ||
193 | #define DA_FILE_READ_DATA 0x00000001 | |
194 | #define DA_FILE_WRITE_DATA 0x00000002 | |
195 | #define DA_FILE_APPEND_DATA 0x00000004 | |
196 | #define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */ | |
197 | #define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */ | |
198 | #define DA_FILE_EXECUTE 0x00000020 | |
199 | #define DA_FILE_READ_ATTRIBUTES 0x00000080 | |
200 | #define DA_FILE_WRITE_ATTRIBUTES 0x00000100 | |
201 | #define DA_DELETE 0x00010000 | |
202 | #define DA_READ_CONTROL 0x00020000 /* rd security descriptor */ | |
203 | #define DA_WRITE_DAC 0x00040000 | |
204 | #define DA_WRITE_OWNER 0x00080000 | |
205 | #define DA_SYNCHRONIZE 0x00100000 | |
206 | #define DA_ACCESS_SYSTEM_SECURITY 0x01000000 | |
207 | #define DA_MAXIMUM_ALLOWED 0x02000000 | |
208 | #define DA_GENERIC_ALL 0x10000000 | |
209 | #define DA_GENERIC_EXECUTE 0x20000000 | |
210 | #define DA_GENERIC_WRITE 0x40000000 | |
211 | #define DA_GENERIC_READ 0x80000000 | |
212 | ||
213 | /* | |
214 | * CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request | |
215 | */ | |
216 | ||
217 | enum CREATE_OPTIONS | |
218 | { | |
219 | CO_FILE_DIRECTORY_FILE = 0x00000001, | |
220 | CO_FILE_WRITE_THROUGH = 0x00000002, | |
221 | CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, | |
222 | CO_FILE_DELETE_ON_CLOSE = 0x00001000 | |
223 | }; | |
224 | ||
225 | /* | |
226 | * CreateDispositions Mask [MS-SMB2] section 2.2.13 | |
227 | */ | |
228 | ||
229 | #define CD_FILE_SUPERSEDE 0x00000000 | |
230 | #define CD_FILE_OPEN 0x00000001 | |
231 | #define CD_FILE_CREATE 0x00000002 | |
232 | #define CD_FILE_OPEN_IF 0x00000003 | |
233 | #define CD_FILE_OVERWRITE 0x00000004 | |
234 | #define CD_FILE_OVERWRITE_IF 0x00000005 | |
235 | ||
236 | /* | |
237 | * Device I/O Request MajorFunction definitions | |
238 | */ | |
239 | ||
240 | #define IRP_MJ_CREATE 0x00000000 | |
241 | #define IRP_MJ_CLOSE 0x00000002 | |
242 | #define IRP_MJ_READ 0x00000003 | |
243 | #define IRP_MJ_WRITE 0x00000004 | |
244 | #define IRP_MJ_DEVICE_CONTROL 0x0000000E | |
245 | #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0000000A | |
246 | #define IRP_MJ_SET_VOLUME_INFORMATION 0x0000000B | |
247 | #define IRP_MJ_QUERY_INFORMATION 0x00000005 | |
248 | #define IRP_MJ_SET_INFORMATION 0x00000006 | |
249 | #define IRP_MJ_DIRECTORY_CONTROL 0x0000000C | |
250 | #define IRP_MJ_LOCK_CONTROL 0x00000011 | |
251 | ||
252 | /* | |
253 | * Device I/O Request MinorFunction definitions | |
254 | * | |
255 | * Only valid when MajorFunction code = IRP_MJ_DIRECTORY_CONTROL | |
256 | */ | |
257 | ||
258 | #define IRP_MN_QUERY_DIRECTORY 0x00000001 | |
259 | #define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x00000002 | |
260 | ||
261 | /* | |
262 | * NTSTATUS codes (used by IoStatus) | |
263 | */ | |
264 | ||
265 | #define NT_STATUS_SUCCESS 0x00000000 | |
266 | #define NT_STATUS_UNSUCCESSFUL 0xC0000001 | |
267 | ||
268 | /* | |
269 | * File system ioctl codes | |
270 | * MS-FSCC section 2.3 FSCTL Structures | |
271 | */ | |
272 | #define FSCTL_DELETE_OBJECT_ID 0x900a0 | |
273 | ||
274 | ||
275 | /* | |
276 | * CompletionID types, used in IRPs to indicate I/O operation | |
277 | */ | |
278 | ||
279 | enum COMPLETION_ID | |
280 | { | |
281 | CID_CREATE_DIR_REQ = 1, | |
282 | CID_DIRECTORY_CONTROL, | |
283 | CID_CREATE_OPEN_REQ, | |
284 | CID_READ, | |
285 | CID_WRITE, | |
286 | CID_CLOSE, | |
287 | CID_FILE_CLOSE, | |
288 | CID_RMDIR_OR_FILE, | |
289 | CID_RMDIR_OR_FILE_RESP, | |
290 | CID_RENAME_FILE, | |
291 | CID_RENAME_FILE_RESP | |
292 | }; | |
293 | ||
294 | enum FS_INFORMATION_CLASS | |
295 | { | |
296 | FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */ | |
297 | FileEndOfFileInformation = 0x00000014, /* set EOF info */ | |
298 | FileDispositionInformation = 0x0000000D, /* mark a file for deletion */ | |
299 | FileRenameInformation = 0x0000000A, /* rename a file */ | |
300 | FileAllocationInformation = 0x00000013 /* set file allocation size */ | |
301 | }; | |
302 | ||
303 | /* | |
304 | * constants for drive dir query | |
305 | */ | |
306 | ||
307 | /* Basic information about a file or directory. Basic information is */ | |
308 | /* defined as the file's name, time stamp, and size, or its attributes */ | |
309 | #define FileDirectoryInformation 0x00000001 | |
310 | ||
311 | /* Full information about a file or directory. Full information is defined */ | |
312 | /* as all the basic information, plus extended attribute size. */ | |
313 | #define FileFullDirectoryInformation 0x00000002 | |
314 | ||
315 | /* Basic information plus extended attribute size and short name */ | |
316 | /* about a file or directory. */ | |
317 | #define FileBothDirectoryInformation 0x00000003 | |
318 | ||
319 | /* Detailed information on the names of files in a directory. */ | |
320 | #define FileNamesInformation 0x0000000C | |
321 | ||
322 | /* | |
323 | * NTSTATUS Codes of interest to us | |
324 | */ | |
325 | ||
326 | /* No more files were found which match the file specification */ | |
327 | #define STATUS_NO_MORE_FILES 0x80000006 | |
328 | ||
329 | /* Windows file attributes */ | |
330 | #define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010 | |
331 | #define W_FILE_ATTRIBUTE_READONLY 0x00000001 | |
332 | ||
333 | #define WINDOWS_TO_LINUX_FILE_PERM(_a) \ | |
334 | (((_a) & W_FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | 0100 : S_IFREG) |\ | |
335 | (((_a) & W_FILE_ATTRIBUTE_READONLY) ? 0444 : 0644) | |
336 | ||
337 | /* Windows time starts on Jan 1, 1601 */ | |
338 | /* Linux time starts on Jan 1, 1970 */ | |
339 | #define EPOCH_DIFF 11644473600LL | |
340 | #define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF; | |
341 | ||
342 | #define OP_RENAME_FILE 0x01 | |
93 | devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id, | |
94 | const char *path); | |
343 | 95 | |
344 | 96 | #endif |
104 | 104 | } |
105 | 105 | |
106 | 106 | /** |
107 | * Clone specified IRP | |
107 | * Create a new IRP with a copied pathname, and append to linked list. | |
108 | * | |
109 | * Allocation is made in such a way that the IRP can be freed with a single | |
110 | * free() operation | |
108 | 111 | * |
109 | 112 | * @return new IRP or NULL on error |
110 | 113 | *****************************************************************************/ |
111 | 114 | |
112 | IRP * devredir_irp_clone(IRP *irp) | |
113 | { | |
114 | IRP *new_irp; | |
115 | IRP *prev; | |
116 | IRP *next; | |
117 | ||
118 | if ((new_irp = devredir_irp_new()) == NULL) | |
115 | IRP * devredir_irp_with_pathname_new(const char *pathname) | |
116 | { | |
117 | unsigned int len = g_strlen(pathname); | |
118 | IRP * irp = devredir_irp_with_pathnamelen_new(len); | |
119 | if (irp != NULL) | |
120 | { | |
121 | g_strcpy(irp->pathname, pathname); | |
122 | } | |
123 | ||
124 | return irp; | |
125 | } | |
126 | ||
127 | /** | |
128 | * Create a new IRP with space allocated for a pathname, and append to | |
129 | * linked list. | |
130 | * | |
131 | * Allocation is made in such a way that the IRP can be freed with a single | |
132 | * free() operation | |
133 | * | |
134 | * @return new IRP or NULL on error | |
135 | *****************************************************************************/ | |
136 | ||
137 | IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen) | |
138 | { | |
139 | IRP *irp; | |
140 | IRP *irp_last; | |
141 | ||
142 | log_debug("entered"); | |
143 | ||
144 | /* create new IRP with space on end for the pathname and a terminator */ | |
145 | irp = (IRP *)g_malloc(sizeof(IRP) + (pathnamelen + 1), 1); | |
146 | if (irp == NULL) | |
147 | { | |
148 | log_error("system out of memory!"); | |
119 | 149 | return NULL; |
120 | ||
121 | /* save link pointers */ | |
122 | prev = new_irp->prev; | |
123 | next = new_irp->next; | |
124 | ||
125 | /* copy all members */ | |
126 | g_memcpy(new_irp, irp, sizeof(IRP)); | |
127 | ||
128 | /* restore link pointers */ | |
129 | new_irp->prev = prev; | |
130 | new_irp->next = next; | |
131 | ||
132 | return new_irp; | |
150 | } | |
151 | ||
152 | irp->pathname = (char *)irp + sizeof(IRP); /* Initialise pathname pointer */ | |
153 | ||
154 | /* insert at end of linked list */ | |
155 | if ((irp_last = devredir_irp_get_last()) == NULL) | |
156 | { | |
157 | /* list is empty, this is the first entry */ | |
158 | g_irp_head = irp; | |
159 | } | |
160 | else | |
161 | { | |
162 | irp_last->next = irp; | |
163 | irp->prev = irp_last; | |
164 | } | |
165 | ||
166 | log_debug("new IRP=%p", irp); | |
167 | return irp; | |
133 | 168 | } |
134 | 169 | |
135 | 170 | /** |
23 | 23 | #ifndef __IRP_H |
24 | 24 | #define __IRP_H |
25 | 25 | |
26 | typedef struct fuse_data FUSE_DATA; | |
27 | struct fuse_data | |
26 | #ifndef _TIME_H_ | |
27 | #include <time.h> | |
28 | #endif | |
29 | #include "chansrv_fuse.h" | |
30 | ||
31 | /* Opaque data types to us */ | |
32 | typedef struct xfuse_info XFUSE_INFO; | |
33 | ||
34 | enum irp_lookup_state | |
28 | 35 | { |
29 | void *data_ptr; | |
30 | FUSE_DATA *next; | |
36 | E_LOOKUP_GET_FH = 0, | |
37 | E_LOOKUP_CHECK_BASIC, | |
38 | E_LOOKUP_CHECK_EOF | |
39 | } ; | |
40 | ||
41 | enum irp_setattr_state | |
42 | { | |
43 | E_SETATTR_GET_FH = 0, | |
44 | E_SETATTR_CHECK_BASIC, | |
45 | E_SETATTR_CHECK_EOF | |
46 | } ; | |
47 | ||
48 | struct irp_lookup | |
49 | { | |
50 | enum irp_lookup_state state; /* Next state to consider */ | |
51 | struct file_attr fattr; /* Attributes to get */ | |
52 | }; | |
53 | ||
54 | struct irp_setattr | |
55 | { | |
56 | enum irp_setattr_state state; /* Next state to consider */ | |
57 | tui32 to_set; /* Bit mask for elements in use */ | |
58 | struct file_attr fattr; /* Attributes to set */ | |
59 | }; | |
60 | ||
61 | struct irp_write | |
62 | { | |
63 | tui64 offset; /* Offset the write was made at */ | |
64 | }; | |
65 | ||
66 | struct irp_create | |
67 | { | |
68 | int creating_dir; /* We're creating a directory */ | |
69 | }; | |
70 | ||
71 | struct irp_rename | |
72 | { | |
73 | char *new_name; /* New name for file */ | |
31 | 74 | }; |
32 | 75 | |
33 | 76 | /* An I/O Resource Packet to track I/O calls */ |
40 | 83 | tui32 DeviceId; /* identifies remote device */ |
41 | 84 | tui32 FileId; /* RDP client provided unique number */ |
42 | 85 | char completion_type; /* describes I/O type */ |
43 | char pathname[256]; /* absolute pathname */ | |
44 | char gen_buf[1024]; /* for general use */ | |
45 | int type; | |
46 | FUSE_DATA *fd_head; /* point to first FUSE opaque object */ | |
47 | FUSE_DATA *fd_tail; /* point to last FUSE opaque object */ | |
86 | char *pathname; /* absolute pathname | |
87 | * Allocate with | |
88 | * devredir_irp_with_pathname_new() */ | |
89 | union | |
90 | { | |
91 | struct irp_lookup lookup; /* Used by lookup */ | |
92 | struct irp_setattr setattr; /* Used by setattr */ | |
93 | struct irp_write write; /* Used by write */ | |
94 | struct irp_create create; /* Used by create */ | |
95 | struct irp_rename rename; /* Use by rename */ | |
96 | } gen; /* Additional state data for some ops */ | |
97 | void *fuse_info; /* Fuse info pointer for FUSE calls */ | |
48 | 98 | IRP *next; /* point to next IRP */ |
49 | 99 | IRP *prev; /* point to previous IRP */ |
50 | 100 | int scard_index; /* used to smart card to locate dev */ |
55 | 105 | }; |
56 | 106 | |
57 | 107 | IRP * devredir_irp_new(void); |
58 | IRP * devredir_irp_clone(IRP *irp); | |
108 | /* As above, but allocates sufficent space for the specified | |
109 | * pathname, and copies it in to the pathname field */ | |
110 | IRP * devredir_irp_with_pathname_new(const char *pathname); | |
111 | /* As above, but specifies a pathname length with pathname | |
112 | * initially set to "". Use if you need to modify the pathname | |
113 | * significantly */ | |
114 | IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen); | |
59 | 115 | int devredir_irp_delete(IRP *irp); |
60 | 116 | IRP * devredir_irp_find(tui32 completion_id); |
61 | 117 | IRP * devredir_irp_find_by_fileid(tui32 FileId); |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * MS-ERREF : Definitions from [MS-ERREF] | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * References to MS-ERREF are currently correct for v20180912 of that | |
18 | * document | |
19 | */ | |
20 | ||
21 | #if !defined(MS_ERREF_H) | |
22 | #define MS_ERREF_H | |
23 | ||
24 | /* | |
25 | * NTSTATUS codes (section 2.3) | |
26 | */ | |
27 | enum NTSTATUS | |
28 | { | |
29 | NT_STATUS_SUCCESS = 0x00000000, | |
30 | NT_STATUS_UNSUCCESSFUL = 0xC0000001, | |
31 | NT_STATUS_NO_SUCH_FILE = 0xC000000F, | |
32 | NT_STATUS_ACCESS_DENIED = 0xC0000022, | |
33 | NT_STATUS_OBJECT_NAME_INVALID = 0xC0000033, | |
34 | NT_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, | |
35 | NT_STATUS_SHARING_VIOLATION = 0xC0000043, | |
36 | NT_STATUS_NO_MORE_FILES = 0x80000006 | |
37 | }; | |
38 | ||
39 | #endif /* MS_ERREF_H */ | |
40 | ||
41 | ||
42 | ||
43 |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * MS-FSCC : Definitions from [MS-FSCC] | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * References to MS-FSCC are currently correct for v20190923 of that | |
18 | * document | |
19 | */ | |
20 | ||
21 | #if !defined(MS_FSCC_H) | |
22 | #define MS_FSCC_H | |
23 | ||
24 | /* | |
25 | * File system ioctl codes (section 2.3) | |
26 | */ | |
27 | #define FSCTL_DELETE_OBJECT_ID 0x900a0 | |
28 | ||
29 | /* | |
30 | * File information classes (section 2.4) | |
31 | */ | |
32 | enum FS_INFORMATION_CLASS | |
33 | { | |
34 | FileAllocationInformation = 19, /* Set */ | |
35 | FileBasicInformation = 4, /* Query, Set */ | |
36 | FileBothDirectoryInformation = 3, /* Query */ | |
37 | FileDirectoryInformation = 1, /* Query */ | |
38 | FileDispositionInformation = 13, /* Set */ | |
39 | FileEndOfFileInformation = 20, /* Set */ | |
40 | FileFullDirectoryInformation = 2, /* Query */ | |
41 | FileNamesInformation = 12, /* Query */ | |
42 | FileRenameInformation = 10, /* Set */ | |
43 | FileStandardInformation = 5 /* Query */ | |
44 | }; | |
45 | ||
46 | /* | |
47 | * Size of structs above without trailing RESERVED fields (MS-RDPEFS | |
48 | * 2.2.3.3.8) | |
49 | */ | |
50 | #define FILE_BASIC_INFORMATION_SIZE 36 | |
51 | #define FILE_STD_INFORMATION_SIZE 22 | |
52 | #define FILE_END_OF_FILE_INFORMATION_SIZE 8 | |
53 | ||
54 | /* Windows file attributes (section 2.6) */ | |
55 | #define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010 | |
56 | #define W_FILE_ATTRIBUTE_READONLY 0x00000001 | |
57 | #define W_FILE_ATTRIBUTE_SYSTEM 0x00000004 | |
58 | #define W_FILE_ATTRIBUTE_NORMAL 0x00000080 | |
59 | ||
60 | #endif /* MS_FSCC_H */ | |
61 | ||
62 | ||
63 |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * MS-RDPEFS : Definitions from [MS-RDPEFS] | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * References to MS-RDPEFS are currently correct for v20180912 of that | |
18 | * document | |
19 | */ | |
20 | ||
21 | #if !defined(MS_RDPEFS_H) | |
22 | #define MS_RDPEFS_H | |
23 | ||
24 | /* | |
25 | * RDPDR_HEADER definitions (2.2.1.1) | |
26 | */ | |
27 | ||
28 | /* device redirector core component; most of the packets in this protocol */ | |
29 | /* are sent under this component ID */ | |
30 | #define RDPDR_CTYP_CORE 0x4472 | |
31 | ||
32 | /* printing component. the packets that use this ID are typically about */ | |
33 | /* printer cache management and identifying XPS printers */ | |
34 | #define RDPDR_CTYP_PRN 0x5052 | |
35 | ||
36 | /* Server Announce Request, as specified in section 2.2.2.2 */ | |
37 | #define PAKID_CORE_SERVER_ANNOUNCE 0x496E | |
38 | ||
39 | /* Client Announce Reply and Server Client ID Confirm, as specified in */ | |
40 | /* sections 2.2.2.3 and 2.2.2.6. */ | |
41 | #define PAKID_CORE_CLIENTID_CONFIRM 0x4343 | |
42 | ||
43 | /* Client Name Request, as specified in section 2.2.2.4 */ | |
44 | #define PAKID_CORE_CLIENT_NAME 0x434E | |
45 | ||
46 | /* Client Device List Announce Request, as specified in section 2.2.2.9 */ | |
47 | #define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441 | |
48 | ||
49 | /* Server Device Announce Response, as specified in section 2.2.2.1 */ | |
50 | #define PAKID_CORE_DEVICE_REPLY 0x6472 | |
51 | ||
52 | /* Device I/O Request, as specified in section 2.2.1.4 */ | |
53 | #define PAKID_CORE_DEVICE_IOREQUEST 0x4952 | |
54 | ||
55 | /* Device I/O Response, as specified in section 2.2.1.5 */ | |
56 | #define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 | |
57 | ||
58 | /* Server Core Capability Request, as specified in section 2.2.2.7 */ | |
59 | #define PAKID_CORE_SERVER_CAPABILITY 0x5350 | |
60 | ||
61 | /* Client Core Capability Response, as specified in section 2.2.2.8 */ | |
62 | #define PAKID_CORE_CLIENT_CAPABILITY 0x4350 | |
63 | ||
64 | /* Client Drive Device List Remove, as specified in section 2.2.3.2 */ | |
65 | #define PAKID_CORE_DEVICELIST_REMOVE 0x444D | |
66 | ||
67 | /* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */ | |
68 | #define PAKID_PRN_CACHE_DATA 0x5043 | |
69 | ||
70 | /* Server User Logged On, as specified in section 2.2.2.5 */ | |
71 | #define PAKID_CORE_USER_LOGGEDON 0x554C | |
72 | ||
73 | /* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */ | |
74 | #define PAKID_PRN_USING_XPS 0x5543 | |
75 | ||
76 | /* | |
77 | * Capability header definitions (2.2.1.2) | |
78 | */ | |
79 | ||
80 | #define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */ | |
81 | #define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */ | |
82 | #define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */ | |
83 | #define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */ | |
84 | #define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */ | |
85 | ||
86 | /* | |
87 | * Device announce header (2.2.1.3) | |
88 | */ | |
89 | #define RDPDR_DTYP_SERIAL 0x0001 | |
90 | #define RDPDR_DTYP_PARALLEL 0x0002 | |
91 | #define RDPDR_DTYP_PRINT 0x0004 | |
92 | #define RDPDR_DTYP_FILESYSTEM 0x0008 | |
93 | #define RDPDR_DTYP_SMARTCARD 0x0020 | |
94 | ||
95 | /* Device I/O Request definitions (2.2.1.4) */ | |
96 | /* MajorFunction */ | |
97 | enum IRP_MJ | |
98 | { | |
99 | IRP_MJ_CREATE = 0x00000000, | |
100 | IRP_MJ_CLOSE = 0x00000002, | |
101 | IRP_MJ_READ = 0x00000003, | |
102 | IRP_MJ_WRITE = 0x00000004, | |
103 | IRP_MJ_DEVICE_CONTROL = 0x0000000E, | |
104 | IRP_MJ_QUERY_VOLUME_INFORMATION = 0x0000000A, | |
105 | IRP_MJ_SET_VOLUME_INFORMATION = 0x0000000B, | |
106 | IRP_MJ_QUERY_INFORMATION = 0x00000005, | |
107 | IRP_MJ_SET_INFORMATION = 0x00000006, | |
108 | IRP_MJ_DIRECTORY_CONTROL = 0x0000000C, | |
109 | IRP_MJ_LOCK_CONTROL = 0x00000011 | |
110 | }; | |
111 | ||
112 | /* MinorFunction */ | |
113 | /* Set to zero unless MajorFunction code == IRP_MJ_DIRECTORY_CONTROL */ | |
114 | enum IRP_MN | |
115 | { | |
116 | IRP_MN_NONE = 0x00000000, /* Name not in MS docs */ | |
117 | IRP_MN_QUERY_DIRECTORY = 0x00000001, | |
118 | IRP_MN_NOTIFY_CHANGE_DIRECTORY = 0x00000002 | |
119 | }; | |
120 | ||
121 | ||
122 | #endif /* MS_RDPEFS_H */ | |
123 | ||
124 |
0 | /** | |
1 | * xrdp: A Remote Desktop Protocol server. | |
2 | * | |
3 | * MS-SMB2 : Definitions from [MS-SMB2] | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * References to MS-SMB2 are currently correct for v20190923 of that | |
18 | * document | |
19 | */ | |
20 | ||
21 | #if !defined(MS_SMB2_H) | |
22 | #define MS_SMB2_H | |
23 | ||
24 | /* SMB2 CREATE request values (section 2.2.13) */ | |
25 | ||
26 | /* | |
27 | * ShareAccess Mask. Currently, this is referred | |
28 | * to in MS-RDPEFS 2.2.1.4.1 as 'SharedAccess' rather than 'ShareAccess'. | |
29 | */ | |
30 | #define SA_FILE_SHARE_READ 0x00000001 | |
31 | #define SA_FILE_SHARE_WRITE 0x00000002 | |
32 | #define SA_FILE_SHARE_DELETE 0x00000004 | |
33 | ||
34 | /* CreateDisposition Mask */ | |
35 | #define CD_FILE_SUPERSEDE 0x00000000 | |
36 | #define CD_FILE_OPEN 0x00000001 | |
37 | #define CD_FILE_CREATE 0x00000002 | |
38 | #define CD_FILE_OPEN_IF 0x00000003 | |
39 | #define CD_FILE_OVERWRITE 0x00000004 | |
40 | #define CD_FILE_OVERWRITE_IF 0x00000005 | |
41 | ||
42 | /* CreateOptions Mask */ | |
43 | enum CREATE_OPTIONS | |
44 | { | |
45 | CO_FILE_DIRECTORY_FILE = 0x00000001, | |
46 | CO_FILE_WRITE_THROUGH = 0x00000002, | |
47 | CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, | |
48 | CO_FILE_DELETE_ON_CLOSE = 0x00001000 | |
49 | }; | |
50 | ||
51 | /* | |
52 | * DesiredAccess Mask (section 2.2.13.1.1) | |
53 | */ | |
54 | ||
55 | #define DA_FILE_READ_DATA 0x00000001 | |
56 | #define DA_FILE_WRITE_DATA 0x00000002 | |
57 | #define DA_FILE_APPEND_DATA 0x00000004 | |
58 | #define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */ | |
59 | #define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */ | |
60 | #define DA_FILE_EXECUTE 0x00000020 | |
61 | #define DA_FILE_READ_ATTRIBUTES 0x00000080 | |
62 | #define DA_FILE_WRITE_ATTRIBUTES 0x00000100 | |
63 | #define DA_DELETE 0x00010000 | |
64 | #define DA_READ_CONTROL 0x00020000 /* rd security descriptor */ | |
65 | #define DA_WRITE_DAC 0x00040000 | |
66 | #define DA_WRITE_OWNER 0x00080000 | |
67 | #define DA_SYNCHRONIZE 0x00100000 | |
68 | #define DA_ACCESS_SYSTEM_SECURITY 0x01000000 | |
69 | #define DA_MAXIMUM_ALLOWED 0x02000000 | |
70 | #define DA_GENERIC_ALL 0x10000000 | |
71 | #define DA_GENERIC_EXECUTE 0x20000000 | |
72 | #define DA_GENERIC_WRITE 0x40000000 | |
73 | #define DA_GENERIC_READ 0x80000000 | |
74 | ||
75 | #endif /* MS_SMB2_H */ | |
76 | ||
77 | ||
78 |
870 | 870 | irp->FileId, |
871 | 871 | irp->CompletionId, |
872 | 872 | IRP_MJ_DEVICE_CONTROL, |
873 | 0); | |
873 | IRP_MN_NONE); | |
874 | 874 | |
875 | 875 | xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ |
876 | 876 | s_push_layer(s, iso_hdr, 4); /* InputBufferLength - insert later */ |
33 | 33 | #include "xrdp_constants.h" |
34 | 34 | #include "xrdp_sockets.h" |
35 | 35 | #include "chansrv_common.h" |
36 | #include "list.h" | |
37 | #include "audin.h" | |
36 | 38 | |
37 | 39 | #if defined(XRDP_FDK_AAC) |
38 | 40 | #include <fdk-aac/aacenc_lib.h> |
69 | 71 | static int g_training_sent_time = 0; |
70 | 72 | static int g_cBlockNo = 0; |
71 | 73 | static int g_bytes_in_stream = 0; |
72 | static FIFO g_in_fifo; | |
73 | static int g_bytes_in_fifo = 0; | |
74 | static int g_unacked_frames = 0; | |
74 | FIFO g_in_fifo; | |
75 | int g_bytes_in_fifo = 0; | |
76 | static int g_time_diff = 0; | |
77 | static int g_best_time_diff = 0; | |
78 | ||
75 | 79 | |
76 | 80 | static struct stream *g_stream_inp = NULL; |
77 | 81 | static struct stream *g_stream_incoming_packet = NULL; |
80 | 84 | static char g_buffer[MAX_BBUF_SIZE]; |
81 | 85 | static int g_buf_index = 0; |
82 | 86 | static int g_sent_time[256]; |
83 | static int g_sent_flag[256]; | |
84 | 87 | |
85 | 88 | static int g_bbuf_size = 1024 * 8; /* may change later */ |
89 | ||
90 | static struct list *g_ack_time_diff = 0; | |
86 | 91 | |
87 | 92 | struct xr_wave_format_ex |
88 | 93 | { |
235 | 240 | 0 |
236 | 241 | }; |
237 | 242 | |
243 | static int g_rdpsnd_can_rec = 0; | |
244 | ||
238 | 245 | static int g_client_input_format_index = 0; |
239 | 246 | static int g_server_input_format_index = 0; |
240 | 247 | |
339 | 346 | out_uint16_le(s, SNDC_TRAINING); |
340 | 347 | size_ptr = s->p; |
341 | 348 | out_uint16_le(s, 0); /* size, set later */ |
342 | time = g_time2(); | |
349 | time = g_time3(); | |
343 | 350 | g_training_sent_time = time; |
344 | 351 | out_uint16_le(s, time); |
345 | 352 | out_uint16_le(s, 1024); |
882 | 889 | return 1; |
883 | 890 | } |
884 | 891 | |
885 | LOG(20, ("sound_send_wave_data_chunk: g_sent_flag[%d] = %d", | |
886 | g_cBlockNo + 1, g_sent_flag[(g_cBlockNo + 1) & 0xff])); | |
887 | if (g_sent_flag[(g_cBlockNo + 1) & 0xff] & 1) | |
888 | { | |
889 | LOG(10, ("sound_send_wave_data_chunk: no room")); | |
890 | return 2; | |
891 | } | |
892 | else | |
893 | { | |
894 | LOG(10, ("sound_send_wave_data_chunk: got room")); | |
895 | } | |
896 | ||
897 | 892 | /* compress, if available */ |
898 | 893 | format_index = g_current_client_format_index; |
899 | 894 | data_bytes = sound_wave_compress(data, data_bytes, &format_index); |
907 | 902 | out_uint16_le(s, SNDC_WAVE); |
908 | 903 | size_ptr = s->p; |
909 | 904 | out_uint16_le(s, 0); /* size, set later */ |
910 | time = g_time2(); | |
905 | time = g_time3(); | |
911 | 906 | out_uint16_le(s, time); |
912 | 907 | out_uint16_le(s, format_index); /* wFormatNo */ |
913 | 908 | g_cBlockNo++; |
914 | g_unacked_frames++; | |
915 | 909 | out_uint8(s, g_cBlockNo); |
916 | 910 | g_sent_time[g_cBlockNo & 0xff] = time; |
917 | g_sent_flag[g_cBlockNo & 0xff] = 1; | |
918 | 911 | |
919 | 912 | LOG(10, ("sound_send_wave_data_chunk: sending time %d, g_cBlockNo %d", |
920 | 913 | time & 0xffff, g_cBlockNo & 0xff)); |
955 | 948 | int res; |
956 | 949 | |
957 | 950 | LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes)); |
951 | if (g_time_diff > g_best_time_diff + 250) | |
952 | { | |
953 | data_bytes = data_bytes / 4; | |
954 | data_bytes = data_bytes & ~3; | |
955 | g_memset(data, 0, data_bytes); | |
956 | g_time_diff = 0; | |
957 | } | |
958 | 958 | data_index = 0; |
959 | 959 | error = 0; |
960 | 960 | while (data_bytes > 0) |
1004 | 1004 | |
1005 | 1005 | LOG(10, ("sound_send_close:")); |
1006 | 1006 | |
1007 | /* send any left over data */ | |
1008 | if (g_buf_index) | |
1009 | { | |
1010 | if (sound_send_wave_data_chunk(g_buffer, g_buf_index) != 0) | |
1011 | { | |
1012 | LOG(10, ("sound_send_close: sound_send_wave_data_chunk failed")); | |
1013 | return 1; | |
1014 | } | |
1015 | } | |
1007 | g_best_time_diff = 0; | |
1016 | 1008 | g_buf_index = 0; |
1017 | g_memset(g_sent_flag, 0, sizeof(g_sent_flag)); | |
1018 | 1009 | |
1019 | 1010 | /* send close msg */ |
1020 | 1011 | make_stream(s); |
1039 | 1030 | { |
1040 | 1031 | int time_diff; |
1041 | 1032 | |
1042 | time_diff = g_time2() - g_training_sent_time; | |
1033 | time_diff = g_time3() - g_training_sent_time; | |
1043 | 1034 | LOG(0, ("sound_process_training: round trip time %u", time_diff)); |
1044 | 1035 | return 0; |
1045 | 1036 | } |
1051 | 1042 | { |
1052 | 1043 | int wTimeStamp; |
1053 | 1044 | int cConfirmedBlockNo; |
1054 | int cleared_count; | |
1055 | 1045 | int time; |
1056 | 1046 | int time_diff; |
1057 | int block_no; | |
1058 | int block_no_clamped; | |
1059 | int found; | |
1060 | 1047 | int index; |
1061 | ||
1062 | time = g_time2(); | |
1048 | int acc; | |
1049 | ||
1050 | time = g_time3(); | |
1063 | 1051 | in_uint16_le(s, wTimeStamp); |
1064 | 1052 | in_uint8(s, cConfirmedBlockNo); |
1065 | 1053 | time_diff = time - g_sent_time[cConfirmedBlockNo & 0xff]; |
1066 | cleared_count = 0; | |
1067 | found = 0; | |
1068 | block_no = g_cBlockNo; | |
1069 | for (index = 0; index < g_unacked_frames; index++) | |
1070 | { | |
1071 | block_no_clamped = block_no & 0xff; | |
1072 | if ((cConfirmedBlockNo == block_no_clamped) || found) | |
1073 | { | |
1074 | found = 1; | |
1075 | if (g_sent_flag[block_no_clamped] & 1) | |
1076 | { | |
1077 | LOG(10, ("sound_process_wave_confirm: clearing %d", | |
1078 | block_no_clamped)); | |
1079 | g_sent_flag[block_no_clamped] &= ~1; | |
1080 | cleared_count++; | |
1081 | } | |
1082 | } | |
1083 | block_no--; | |
1084 | } | |
1054 | ||
1085 | 1055 | LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, " |
1086 | "cConfirmedBlockNo %d time diff %d cleared_count %d " | |
1087 | "g_unacked_frames %d", wTimeStamp, cConfirmedBlockNo, time_diff, | |
1088 | cleared_count, g_unacked_frames)); | |
1089 | g_unacked_frames -= cleared_count; | |
1056 | "cConfirmedBlockNo %d time diff %d", | |
1057 | wTimeStamp, cConfirmedBlockNo, time_diff)); | |
1058 | ||
1059 | acc = 0; | |
1060 | list_add_item(g_ack_time_diff, time_diff); | |
1061 | if (g_ack_time_diff->count >= 50) | |
1062 | { | |
1063 | while (g_ack_time_diff->count > 50) | |
1064 | { | |
1065 | list_remove_item(g_ack_time_diff, 0); | |
1066 | } | |
1067 | for (index = 0; index < g_ack_time_diff->count; index++) | |
1068 | { | |
1069 | acc += list_get_item(g_ack_time_diff, index); | |
1070 | } | |
1071 | acc = acc / g_ack_time_diff->count; | |
1072 | if ((g_best_time_diff < 1) || (g_best_time_diff > acc)) | |
1073 | { | |
1074 | g_best_time_diff = acc; | |
1075 | } | |
1076 | } | |
1077 | g_time_diff = acc; | |
1090 | 1078 | return 0; |
1091 | 1079 | } |
1092 | 1080 | |
1218 | 1206 | { |
1219 | 1207 | LOG(0, ("sound_init:")); |
1220 | 1208 | |
1221 | g_memset(g_sent_flag, 0, sizeof(g_sent_flag)); | |
1222 | 1209 | g_stream_incoming_packet = NULL; |
1223 | 1210 | |
1224 | 1211 | /* init sound output */ |
1240 | 1227 | |
1241 | 1228 | g_client_does_mp3lame = 0; |
1242 | 1229 | g_client_mp3lame_index = 0; |
1230 | ||
1231 | if (g_ack_time_diff == 0) | |
1232 | { | |
1233 | g_ack_time_diff = list_create(); | |
1234 | } | |
1235 | list_clear(g_ack_time_diff); | |
1243 | 1236 | |
1244 | 1237 | return 0; |
1245 | 1238 | } |
1444 | 1437 | static int |
1445 | 1438 | sound_send_server_input_formats(void) |
1446 | 1439 | { |
1440 | #if defined(XRDP_RDPSNDAUDIN) | |
1447 | 1441 | struct stream *s; |
1448 | 1442 | int bytes; |
1449 | 1443 | int index; |
1498 | 1492 | bytes = (int)(s->end - s->data); |
1499 | 1493 | send_channel_data(g_rdpsnd_chan_id, s->data, bytes); |
1500 | 1494 | free_stream(s); |
1495 | #else | |
1496 | /* avoid warning */ | |
1497 | (void)g_wave_inp_formats; | |
1498 | #endif | |
1501 | 1499 | return 0; |
1502 | 1500 | } |
1503 | 1501 | |
1569 | 1567 | |
1570 | 1568 | LOG(10, ("sound_process_input_formats: size=%d", size)); |
1571 | 1569 | |
1570 | if (g_getenv("XRDP_NO_RDPSND_REC") == NULL) | |
1571 | { | |
1572 | g_rdpsnd_can_rec = 1; | |
1573 | } | |
1572 | 1574 | in_uint8s(s, 8); /* skip 8 bytes */ |
1573 | 1575 | in_uint16_le(s, num_formats); |
1574 | 1576 | in_uint8s(s, 2); /* skip version */ |
1781 | 1783 | } |
1782 | 1784 | else if (cmd == PA_CMD_START_REC) |
1783 | 1785 | { |
1784 | sound_input_start_recording(); | |
1786 | if (g_rdpsnd_can_rec) | |
1787 | { | |
1788 | sound_input_start_recording(); | |
1789 | } | |
1790 | else | |
1791 | { | |
1792 | audin_start(); | |
1793 | } | |
1785 | 1794 | } |
1786 | 1795 | else if (cmd == PA_CMD_STOP_REC) |
1787 | 1796 | { |
1788 | sound_input_stop_recording(); | |
1797 | if (g_rdpsnd_can_rec) | |
1798 | { | |
1799 | sound_input_stop_recording(); | |
1800 | } | |
1801 | else | |
1802 | { | |
1803 | audin_stop(); | |
1804 | } | |
1789 | 1805 | } |
1790 | 1806 | |
1791 | 1807 | xstream_free(s); |
33 | 33 | #include "sesman.h" |
34 | 34 | #include "log.h" |
35 | 35 | |
36 | extern struct config_sesman *g_cfg; /* in sesman.c */ | |
37 | ||
38 | 36 | |
39 | 37 | |
40 | 38 | /******************************************************************************/ |
52 | 50 | |
53 | 51 | if (-1 == fd) |
54 | 52 | { |
55 | //if (g_cfg->log.fd >= 0) | |
56 | //{ | |
57 | /* logging is already active */ | |
58 | log_message(LOG_LEVEL_ALWAYS, "error opening %s in \ | |
59 | config_read", cfg_file); | |
60 | //} | |
61 | //else | |
62 | //{ | |
63 | g_printf("error opening %s in config_read", cfg_file); | |
64 | //} | |
65 | 53 | return 1; |
66 | 54 | } |
67 | 55 | |
184 | 172 | if (cf->default_wm[0] != '/') |
185 | 173 | { |
186 | 174 | /* sizeof operator returns string length including null terminator */ |
187 | length = sizeof(XRDP_CFG_PATH) + g_strlen(g_cfg->default_wm) + 1; /* '/' */ | |
175 | length = sizeof(XRDP_CFG_PATH) + g_strlen(cf->default_wm) + 1; /* '/' */ | |
188 | 176 | buf = (char *)g_malloc(length, 0); |
189 | g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); | |
190 | g_free(g_cfg->default_wm); | |
191 | g_cfg->default_wm = g_strdup(buf); | |
177 | g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, cf->default_wm); | |
178 | g_free(cf->default_wm); | |
179 | cf->default_wm = g_strdup(buf); | |
192 | 180 | g_free(buf); |
193 | 181 | } |
194 | 182 | |
205 | 193 | if (cf->reconnect_sh[0] != '/') |
206 | 194 | { |
207 | 195 | /* sizeof operator returns string length including null terminator */ |
208 | length = sizeof(XRDP_CFG_PATH) + g_strlen(g_cfg->reconnect_sh) + 1; /* '/' */ | |
196 | length = sizeof(XRDP_CFG_PATH) + g_strlen(cf->reconnect_sh) + 1; /* '/' */ | |
209 | 197 | buf = (char *)g_malloc(length, 0); |
210 | g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, g_cfg->reconnect_sh); | |
211 | g_free(g_cfg->reconnect_sh); | |
212 | g_cfg->reconnect_sh = g_strdup(buf); | |
198 | g_sprintf(buf, "%s/%s", XRDP_CFG_PATH, cf->reconnect_sh); | |
199 | g_free(cf->reconnect_sh); | |
200 | cf->reconnect_sh = g_strdup(buf); | |
213 | 201 | g_free(buf); |
214 | 202 | } |
215 | 203 | |
234 | 222 | sc->login_retry = 3; |
235 | 223 | sc->ts_users_enable = 0; |
236 | 224 | sc->ts_admins_enable = 0; |
225 | sc->restrict_outbound_clipboard = 0; | |
237 | 226 | |
238 | 227 | file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); |
239 | 228 | |
272 | 261 | { |
273 | 262 | sc->ts_always_group_check = g_text2bool((char *)list_get_item(param_v, i)); |
274 | 263 | } |
264 | ||
265 | if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD)) | |
266 | { | |
267 | sc->restrict_outbound_clipboard = g_text2bool((char *)list_get_item(param_v, i)); | |
268 | } | |
269 | ||
275 | 270 | } |
276 | 271 | |
277 | 272 | return 0; |
480 | 475 | g_writeln(" DefaultWindowManager: %s", config->default_wm); |
481 | 476 | g_writeln(" ReconnectScript: %s", config->reconnect_sh); |
482 | 477 | g_writeln(" AuthFilePath: %s", |
483 | ((config->auth_file_path) ? (config->auth_file_path) : ("disabled"))); | |
478 | ((config->auth_file_path) ? (config->auth_file_path) : ("disabled"))); | |
484 | 479 | |
485 | 480 | /* Session configuration */ |
486 | 481 | g_writeln("Session configuration:"); |
496 | 491 | g_writeln(" AllowRootLogin: %d", sc->allow_root); |
497 | 492 | g_writeln(" MaxLoginRetry: %d", sc->login_retry); |
498 | 493 | g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check); |
494 | g_writeln(" RestrictOutboundClipboard: %d", sc->restrict_outbound_clipboard); | |
499 | 495 | |
500 | 496 | g_printf( " TSUsersGroup: "); |
501 | 497 | if (sc->ts_users_enable) |
529 | 525 | for (i = 0; i < config->xorg_params->count; i++) |
530 | 526 | { |
531 | 527 | g_writeln(" Parameter %02d %s", |
532 | i, (char *) list_get_item(config->xorg_params, i)); | |
528 | i, (char *) list_get_item(config->xorg_params, i)); | |
533 | 529 | } |
534 | 530 | |
535 | 531 | /* Xvnc */ |
541 | 537 | for (i = 0; i < config->vnc_params->count; i++) |
542 | 538 | { |
543 | 539 | g_writeln(" Parameter %02d %s", |
544 | i, (char *)list_get_item(config->vnc_params, i)); | |
540 | i, (char *)list_get_item(config->vnc_params, i)); | |
545 | 541 | } |
546 | 542 | |
547 | 543 | /* X11rdp */ |
553 | 549 | for (i = 0; i < config->rdp_params->count; i++) |
554 | 550 | { |
555 | 551 | g_writeln(" Parameter %02d %s", |
556 | i, (char *)list_get_item(config->rdp_params, i)); | |
552 | i, (char *)list_get_item(config->rdp_params, i)); | |
557 | 553 | } |
558 | 554 | |
559 | 555 | /* SessionVariables */ |
566 | 562 | { |
567 | 563 | g_writeln(" Parameter %02d %s=%s", |
568 | 564 | i, (char *) list_get_item(config->env_names, i), |
569 | (char *) list_get_item(config->env_values, i)); | |
565 | (char *) list_get_item(config->env_values, i)); | |
570 | 566 | } |
571 | 567 | } |
572 | 568 |
53 | 53 | #define SESMAN_CFG_LOG_ENABLE_SYSLOG "EnableSyslog" |
54 | 54 | #define SESMAN_CFG_LOG_SYSLOG_LEVEL "SyslogLevel" |
55 | 55 | */ |
56 | #define SESMAN_CFG_SECURITY "Security" | |
57 | #define SESMAN_CFG_SEC_LOGIN_RETRY "MaxLoginRetry" | |
58 | #define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" | |
59 | #define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" | |
60 | #define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" | |
61 | #define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck" | |
56 | #define SESMAN_CFG_SECURITY "Security" | |
57 | #define SESMAN_CFG_SEC_LOGIN_RETRY "MaxLoginRetry" | |
58 | #define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" | |
59 | #define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" | |
60 | #define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" | |
61 | #define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck" | |
62 | #define SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD "RestrictOutboundClipboard" | |
62 | 63 | |
63 | 64 | #define SESMAN_CFG_SESSIONS "Sessions" |
64 | 65 | #define SESMAN_CFG_SESS_MAX "MaxSessions" |
125 | 126 | * @brief if the Groups are not found deny access |
126 | 127 | */ |
127 | 128 | int ts_always_group_check; |
129 | /** | |
130 | * @var restrict_outbound_clipboard | |
131 | * @brief if the clipboard should be enforced restricted. If true only allow client -> server, not vice versa. | |
132 | */ | |
133 | int restrict_outbound_clipboard; | |
128 | 134 | }; |
129 | 135 | |
130 | 136 | /** |
132 | 132 | in_uint16_be(c->in_s, cmd); |
133 | 133 | scp_session_set_height(session, cmd); |
134 | 134 | in_uint16_be(c->in_s, cmd); |
135 | scp_session_set_height(session, cmd); | |
135 | scp_session_set_width(session, cmd); | |
136 | 136 | in_uint8(c->in_s, sz); |
137 | 137 | if (0 != scp_session_set_bpp(session, sz)) |
138 | 138 | { |
341 | 341 | g_exit(1); |
342 | 342 | } |
343 | 343 | |
344 | log_message(LOG_LEVEL_TRACE, "config loaded in %s at %s:%d", __func__, __FILE__, __LINE__); | |
345 | log_message(LOG_LEVEL_TRACE, " listen_address = %s", g_cfg->listen_address); | |
346 | log_message(LOG_LEVEL_TRACE, " listen_port = %s", g_cfg->listen_port); | |
347 | log_message(LOG_LEVEL_TRACE, " enable_user_wm = %d", g_cfg->enable_user_wm); | |
348 | log_message(LOG_LEVEL_TRACE, " default_wm = %s", g_cfg->default_wm); | |
349 | log_message(LOG_LEVEL_TRACE, " user_wm = %s", g_cfg->user_wm); | |
350 | log_message(LOG_LEVEL_TRACE, " reconnect_sh = %s", g_cfg->reconnect_sh); | |
351 | log_message(LOG_LEVEL_TRACE, " auth_file_path = %s", g_cfg->auth_file_path); | |
352 | ||
344 | 353 | if (daemon) |
345 | 354 | { |
346 | 355 | /* not to spit on the console, shut up stdout/stderr before anything's logged */ |
347 | 356 | g_file_close(0); |
348 | 357 | g_file_close(1); |
349 | 358 | g_file_close(2); |
359 | ||
360 | if (g_file_open("/dev/null") < 0) | |
361 | { | |
362 | } | |
363 | ||
364 | if (g_file_open("/dev/null") < 0) | |
365 | { | |
366 | } | |
367 | ||
368 | if (g_file_open("/dev/null") < 0) | |
369 | { | |
370 | } | |
350 | 371 | } |
351 | 372 | |
352 | 373 | /* libscp initialization */ |
371 | 392 | g_exit(0); |
372 | 393 | } |
373 | 394 | |
374 | if (g_file_open("/dev/null") < 0) | |
375 | { | |
376 | } | |
377 | ||
378 | if (g_file_open("/dev/null") < 0) | |
379 | { | |
380 | } | |
381 | ||
382 | if (g_file_open("/dev/null") < 0) | |
383 | { | |
384 | } | |
385 | 395 | } |
386 | 396 | |
387 | 397 | /* signal handling */ |
18 | 18 | ; When AlwaysGroupCheck=false access will be permitted |
19 | 19 | ; if the group TerminalServerUsers is not defined. |
20 | 20 | AlwaysGroupCheck=false |
21 | ; When RestrictOutboundClipboard=true clipboard from the | |
22 | ; server is not pushed to the client. | |
23 | RestrictOutboundClipboard=false | |
21 | 24 | |
22 | 25 | [Sessions] |
23 | 26 | ;; X11DisplayOffset - x11 display number offset |
101 | 104 | [Chansrv] |
102 | 105 | ; drive redirection, defaults to xrdp_client if not set |
103 | 106 | FuseMountName=thinclient_drives |
107 | ; this value allows only the user to acess their own mapped drives. | |
108 | ; Make this more permissive (e.g. 022) if required. | |
109 | FileUmask=077 | |
104 | 110 | |
105 | 111 | [SessionVariables] |
106 | 112 | PULSE_SCRIPT=/etc/xrdp/pulse/default.pa |
372 | 372 | env_set_user(username, 0, display, |
373 | 373 | g_cfg->env_names, |
374 | 374 | g_cfg->env_values); |
375 | ||
376 | if (g_cfg->sec.restrict_outbound_clipboard == 1) | |
377 | { | |
378 | g_setenv("CHANSRV_RESTRICT_OUTBOUND_CLIPBOARD", "1", 1); | |
379 | } | |
375 | 380 | |
376 | 381 | /* executing chansrv */ |
377 | 382 | g_execvp(exe_path, (char **) (chansrv_params->items)); |
379 | 379 | } |
380 | 380 | else if (msg == 200) /* invalidate */ |
381 | 381 | { |
382 | /* FramebufferUpdateRequest */ | |
383 | init_stream(s, 8192); | |
384 | out_uint8(s, 3); | |
385 | out_uint8(s, 0); | |
386 | x = (param1 >> 16) & 0xffff; | |
387 | out_uint16_be(s, x); | |
388 | y = param1 & 0xffff; | |
389 | out_uint16_be(s, y); | |
390 | cx = (param2 >> 16) & 0xffff; | |
391 | out_uint16_be(s, cx); | |
392 | cy = param2 & 0xffff; | |
393 | out_uint16_be(s, cy); | |
394 | s_mark_end(s); | |
395 | error = lib_send_copy(v, s); | |
382 | if (v->suppress_output == 0) | |
383 | { | |
384 | /* FramebufferUpdateRequest */ | |
385 | init_stream(s, 8192); | |
386 | out_uint8(s, 3); | |
387 | out_uint8(s, 0); | |
388 | x = (param1 >> 16) & 0xffff; | |
389 | out_uint16_be(s, x); | |
390 | y = param1 & 0xffff; | |
391 | out_uint16_be(s, y); | |
392 | cx = (param2 >> 16) & 0xffff; | |
393 | out_uint16_be(s, cx); | |
394 | cy = param2 & 0xffff; | |
395 | out_uint16_be(s, cy); | |
396 | s_mark_end(s); | |
397 | error = lib_send_copy(v, s); | |
398 | } | |
396 | 399 | } |
397 | 400 | |
398 | 401 | free_stream(s); |
741 | 744 | |
742 | 745 | if (error == 0) |
743 | 746 | { |
744 | /* FramebufferUpdateRequest */ | |
745 | init_stream(s, 8192); | |
746 | out_uint8(s, 3); | |
747 | out_uint8(s, 1); | |
748 | out_uint16_be(s, 0); | |
749 | out_uint16_be(s, 0); | |
750 | out_uint16_be(s, v->mod_width); | |
751 | out_uint16_be(s, v->mod_height); | |
752 | s_mark_end(s); | |
753 | error = lib_send_copy(v, s); | |
747 | if (v->suppress_output == 0) | |
748 | { | |
749 | /* FramebufferUpdateRequest */ | |
750 | init_stream(s, 8192); | |
751 | out_uint8(s, 3); | |
752 | out_uint8(s, 1); | |
753 | out_uint16_be(s, 0); | |
754 | out_uint16_be(s, 0); | |
755 | out_uint16_be(s, v->mod_width); | |
756 | out_uint16_be(s, v->mod_height); | |
757 | s_mark_end(s); | |
758 | error = lib_send_copy(v, s); | |
759 | } | |
754 | 760 | } |
755 | 761 | |
756 | 762 | free_stream(s); |
915 | 921 | } |
916 | 922 | else |
917 | 923 | { |
918 | g_sprintf(text, "VNC unknown in lib_mod_signal %d", type); | |
924 | g_sprintf(text, "VNC unknown in lib_mod_process_message %d", type); | |
919 | 925 | v->server_msg(v, text, 1); |
920 | 926 | } |
921 | 927 | } |
1339 | 1345 | |
1340 | 1346 | if (error == 0) |
1341 | 1347 | { |
1342 | /* FramebufferUpdateRequest */ | |
1343 | init_stream(s, 8192); | |
1344 | out_uint8(s, 3); | |
1345 | out_uint8(s, 0); | |
1346 | out_uint16_be(s, 0); | |
1347 | out_uint16_be(s, 0); | |
1348 | out_uint16_be(s, v->mod_width); | |
1349 | out_uint16_be(s, v->mod_height); | |
1350 | v->server_msg(v, "VNC sending framebuffer update request", 0); | |
1351 | s_mark_end(s); | |
1352 | error = trans_force_write_s(v->trans, s); | |
1348 | if (v->suppress_output == 0) | |
1349 | { | |
1350 | /* FramebufferUpdateRequest */ | |
1351 | init_stream(s, 8192); | |
1352 | out_uint8(s, 3); | |
1353 | out_uint8(s, 0); | |
1354 | out_uint16_be(s, 0); | |
1355 | out_uint16_be(s, 0); | |
1356 | out_uint16_be(s, v->mod_width); | |
1357 | out_uint16_be(s, v->mod_height); | |
1358 | v->server_msg(v, "VNC sending framebuffer update request", 0); | |
1359 | s_mark_end(s); | |
1360 | error = trans_force_write_s(v->trans, s); | |
1361 | } | |
1353 | 1362 | } |
1354 | 1363 | |
1355 | 1364 | if (error == 0) |
1489 | 1498 | } |
1490 | 1499 | } |
1491 | 1500 | return rv; |
1501 | } | |
1502 | ||
1503 | /******************************************************************************/ | |
1504 | /* return error */ | |
1505 | int | |
1506 | lib_mod_frame_ack(struct vnc* v, int flags, int frame_id) | |
1507 | { | |
1508 | return 0; | |
1509 | } | |
1510 | ||
1511 | /******************************************************************************/ | |
1512 | /* return error */ | |
1513 | int | |
1514 | lib_mod_suppress_output(struct vnc* v, int suppress, | |
1515 | int left, int top, int right, int bottom) | |
1516 | { | |
1517 | int error; | |
1518 | struct stream *s; | |
1519 | ||
1520 | error = 0; | |
1521 | v->suppress_output = suppress; | |
1522 | if (suppress == 0) | |
1523 | { | |
1524 | /* FramebufferUpdateRequest */ | |
1525 | make_stream(s); | |
1526 | init_stream(s, 8192); | |
1527 | out_uint8(s, 3); | |
1528 | out_uint8(s, 0); | |
1529 | out_uint16_be(s, 0); | |
1530 | out_uint16_be(s, 0); | |
1531 | out_uint16_be(s, v->mod_width); | |
1532 | out_uint16_be(s, v->mod_height); | |
1533 | s_mark_end(s); | |
1534 | error = lib_send_copy(v, s); | |
1535 | free_stream(s); | |
1536 | } | |
1537 | return error; | |
1492 | 1538 | } |
1493 | 1539 | |
1494 | 1540 | /******************************************************************************/ |
1510 | 1556 | v->mod_set_param = lib_mod_set_param; |
1511 | 1557 | v->mod_get_wait_objs = lib_mod_get_wait_objs; |
1512 | 1558 | v->mod_check_wait_objs = lib_mod_check_wait_objs; |
1559 | v->mod_frame_ack = lib_mod_frame_ack; | |
1560 | v->mod_suppress_output = lib_mod_suppress_output; | |
1513 | 1561 | return (tintptr) v; |
1514 | 1562 | } |
1515 | 1563 |
23 | 23 | #include "os_calls.h" |
24 | 24 | #include "defines.h" |
25 | 25 | |
26 | #define CURRENT_MOD_VER 3 | |
26 | #define CURRENT_MOD_VER 4 | |
27 | 27 | |
28 | 28 | struct vnc |
29 | 29 | { |
41 | 41 | int (*mod_get_wait_objs)(struct vnc* v, tbus* read_objs, int* rcount, |
42 | 42 | tbus* write_objs, int* wcount, int* timeout); |
43 | 43 | int (*mod_check_wait_objs)(struct vnc* v); |
44 | tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod | |
45 | functions above */ | |
44 | int (*mod_frame_ack)(struct vnc* v, int flags, int frame_id); | |
45 | int (*mod_suppress_output)(struct vnc* v, int suppress, | |
46 | int left, int top, int right, int bottom); | |
47 | tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod | |
48 | functions above */ | |
46 | 49 | /* server functions */ |
47 | 50 | int (*server_begin_update)(struct vnc* v); |
48 | 51 | int (*server_end_update)(struct vnc* v); |
115 | 118 | struct trans *trans; |
116 | 119 | int got_guid; |
117 | 120 | tui8 guid[16]; |
121 | int suppress_output; | |
118 | 122 | }; |
163 | 163 | } |
164 | 164 | |
165 | 165 | /*****************************************************************************/ |
166 | void | |
167 | xrdp_hang_up(int sig) | |
168 | { | |
169 | log_message(LOG_LEVEL_INFO, "caught SIGHUP, noop..."); | |
170 | } | |
171 | ||
172 | /*****************************************************************************/ | |
166 | 173 | /* called in child just after fork */ |
167 | 174 | int |
168 | 175 | xrdp_child_fork(void) |
574 | 581 | |
575 | 582 | if (!no_daemon) |
576 | 583 | { |
584 | /* if can't listen, exit with failure status */ | |
585 | if (xrdp_listen_test(startup_params) != 0) | |
586 | { | |
587 | log_message(LOG_LEVEL_ERROR, "Failed to start xrdp daemon, " | |
588 | "possibly address already in use."); | |
589 | g_deinit(); | |
590 | /* must exit with failure status, | |
591 | or systemd cannot detect xrdp daemon couldn't start properly */ | |
592 | g_exit(1); | |
593 | } | |
577 | 594 | /* start of daemonizing code */ |
578 | 595 | pid = g_fork(); |
579 | 596 | |
586 | 603 | |
587 | 604 | if (0 != pid) |
588 | 605 | { |
589 | /* if can't listen, exit with failure status */ | |
590 | if (xrdp_listen_test() != 0) | |
591 | { | |
592 | log_message(LOG_LEVEL_ERROR, "Failed to start xrdp daemon, " | |
593 | "possibly address already in use."); | |
594 | g_deinit(); | |
595 | /* must exit with failure status, | |
596 | or systemd cannot detect xrdp daemon couldn't start properly */ | |
597 | g_exit(1); | |
598 | } | |
599 | 606 | g_writeln("daemon process %d started ok", pid); |
600 | 607 | /* exit, this is the main process */ |
601 | 608 | g_deinit(); |
643 | 650 | g_threadid = tc_get_threadid(); |
644 | 651 | g_listen = xrdp_listen_create(); |
645 | 652 | g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ |
646 | g_signal_pipe(pipe_sig); /* SIGPIPE */ | |
647 | g_signal_terminate(xrdp_shutdown); /* SIGTERM */ | |
648 | g_signal_child_stop(xrdp_child); /* SIGCHLD */ | |
653 | g_signal_pipe(pipe_sig); /* SIGPIPE */ | |
654 | g_signal_terminate(xrdp_shutdown); /* SIGTERM */ | |
655 | g_signal_child_stop(xrdp_child); /* SIGCHLD */ | |
656 | g_signal_hang_up(xrdp_hang_up); /* SIGHUP */ | |
649 | 657 | g_sync_mutex = tc_mutex_create(); |
650 | 658 | g_sync1_mutex = tc_mutex_create(); |
651 | 659 | pid = g_getpid(); |
169 | 169 | int |
170 | 170 | xrdp_listen_main_loop(struct xrdp_listen* self); |
171 | 171 | int |
172 | xrdp_listen_test(void); | |
172 | xrdp_listen_test(struct xrdp_startup_params *startup_params); | |
173 | 173 | |
174 | 174 | /* xrdp_region.c */ |
175 | 175 | struct xrdp_region* |
370 | 370 | /* xrdp_mm.c */ |
371 | 371 | int |
372 | 372 | xrdp_mm_drdynvc_up(struct xrdp_mm* self); |
373 | int | |
374 | xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress, | |
375 | int left, int top, int right, int bottom); | |
373 | 376 | struct xrdp_mm* |
374 | 377 | xrdp_mm_create(struct xrdp_wm* owner); |
375 | 378 | void |
3 | 3 | |
4 | 4 | ; fork a new process for each incoming connection |
5 | 5 | fork=true |
6 | ; tcp port to listen | |
6 | ||
7 | ; ports to listen on, number alone means listen on all interfaces | |
8 | ; 0.0.0.0 or :: if ipv6 is configured | |
9 | ; space between multiple occurrences | |
10 | ; | |
11 | ; Examples: | |
12 | ; port=3389 | |
13 | ; port=unix://./tmp/xrdp.socket | |
14 | ; port=tcp://.:3389 127.0.0.1:3389 | |
15 | ; port=tcp://:3389 *:3389 | |
16 | ; port=tcp://<any ipv4 format addr>:3389 192.168.1.1:3389 | |
17 | ; port=tcp6://.:3389 ::1:3389 | |
18 | ; port=tcp6://:3389 *:3389 | |
19 | ; port=tcp6://{<any ipv6 format addr>}:3389 {FC00:0:0:0:0:0:0:1}:3389 | |
20 | ; port=vsock://<cid>:<port> | |
7 | 21 | port=3389 |
22 | ||
8 | 23 | ; 'port' above should be connected to with vsock instead of tcp |
24 | ; use this only with number alone in port above | |
25 | ; prefer use vsock://<cid>:<port> above | |
9 | 26 | use_vsock=false |
27 | ||
10 | 28 | ; regulate if the listening socket use socket option tcp_nodelay |
11 | 29 | ; no buffering will be performed in the TCP stack |
12 | 30 | tcp_nodelay=true |
31 | ||
13 | 32 | ; regulate if the listening socket use socket option keepalive |
14 | 33 | ; if the network connection disappear without close messages the connection will be closed |
15 | 34 | tcp_keepalive=true |
35 | ||
36 | ; set tcp send/recv buffer (for experts) | |
16 | 37 | #tcp_send_buffer_bytes=32768 |
17 | 38 | #tcp_recv_buffer_bytes=32768 |
18 | 39 | |
19 | 40 | ; security layer can be 'tls', 'rdp' or 'negotiate' |
20 | 41 | ; for client compatible layer |
21 | 42 | security_layer=negotiate |
22 | ; minimum security level allowed for client | |
43 | ||
44 | ; minimum security level allowed for client for classic RDP encryption | |
45 | ; use tls_ciphers to configure TLS encryption | |
23 | 46 | ; can be 'none', 'low', 'medium', 'high', 'fips' |
24 | 47 | crypt_level=high |
48 | ||
25 | 49 | ; X.509 certificate and private key |
26 | 50 | ; openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 |
27 | 51 | certificate= |
28 | 52 | key_file= |
53 | ||
29 | 54 | ; set SSL protocols |
30 | 55 | ; can be comma separated list of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3' |
31 | 56 | ssl_protocols=TLSv1.2, TLSv1.3 |
58 | 58 | [default_rdp_layouts] |
59 | 59 | rdp_layout_us=0x00000409 |
60 | 60 | rdp_layout_us_dvorak=0x00010409 |
61 | rdp_layout_dk=0x00000406 | |
61 | 62 | rdp_layout_de=0x00000407 |
62 | 63 | rdp_layout_es=0x0000040A |
63 | 64 | rdp_layout_fi=0x0000040B |
83 | 84 | [default_layouts_map] |
84 | 85 | rdp_layout_us=us |
85 | 86 | rdp_layout_us_dvorak=dvorak |
87 | rdp_layout_dk=dk | |
86 | 88 | rdp_layout_de=de |
87 | 89 | rdp_layout_es=es |
88 | 90 | rdp_layout_fi=fi |
119 | 121 | [rdp_layouts_map_mac] |
120 | 122 | rdp_layout_us=us |
121 | 123 | rdp_layout_us_dvorak=dvorak |
124 | rdp_layout_dk=dk | |
122 | 125 | rdp_layout_de=de |
123 | 126 | rdp_layout_es=es |
124 | 127 | rdp_layout_fi=fi |
29 | 29 | static tbus g_process_sem = 0; |
30 | 30 | static struct xrdp_process *g_process = 0; |
31 | 31 | |
32 | int | |
33 | xrdp_listen_conn_in(struct trans *self, struct trans *new_self); | |
34 | ||
32 | 35 | /*****************************************************************************/ |
33 | 36 | static int |
34 | 37 | xrdp_listen_create_pro_done(struct xrdp_listen *self) |
56 | 59 | |
57 | 60 | self = (struct xrdp_listen *)g_malloc(sizeof(struct xrdp_listen), 1); |
58 | 61 | xrdp_listen_create_pro_done(self); |
62 | self->trans_list = list_create(); | |
59 | 63 | self->process_list = list_create(); |
64 | self->fork_list = list_create(); | |
60 | 65 | |
61 | 66 | if (g_process_sem == 0) |
62 | 67 | { |
63 | 68 | g_process_sem = tc_sem_create(0); |
64 | 69 | } |
65 | ||
66 | /* setting TCP mode now, may change later */ | |
67 | self->listen_trans = trans_create(TRANS_MODE_TCP, 16, 16); | |
68 | ||
69 | if (self->listen_trans == 0) | |
70 | { | |
71 | log_message(LOG_LEVEL_ERROR,"xrdp_listen_create: trans_create failed"); | |
72 | } | |
73 | else | |
74 | { | |
75 | self->listen_trans->is_term = g_is_term; | |
76 | } | |
77 | ||
78 | 70 | return self; |
79 | 71 | } |
80 | 72 | |
82 | 74 | void |
83 | 75 | xrdp_listen_delete(struct xrdp_listen *self) |
84 | 76 | { |
85 | if (self->listen_trans != 0) | |
86 | { | |
87 | trans_delete(self->listen_trans); | |
77 | int index; | |
78 | struct trans *ltrans; | |
79 | ||
80 | if (self == NULL) | |
81 | { | |
82 | return; | |
83 | } | |
84 | if (self->trans_list != NULL) | |
85 | { | |
86 | for (index = 0; index < self->trans_list->count; index++) | |
87 | { | |
88 | ltrans = (struct trans *) list_get_item(self->trans_list, index); | |
89 | trans_delete(ltrans); | |
90 | } | |
91 | list_delete(self->trans_list); | |
88 | 92 | } |
89 | 93 | |
90 | 94 | if (g_process_sem != 0) |
95 | 99 | |
96 | 100 | g_delete_wait_obj(self->pro_done_event); |
97 | 101 | list_delete(self->process_list); |
102 | list_delete(self->fork_list); | |
98 | 103 | g_free(self); |
99 | 104 | } |
100 | 105 | |
149 | 154 | |
150 | 155 | /*****************************************************************************/ |
151 | 156 | static int |
152 | xrdp_listen_get_port_address(char *port, int port_bytes, | |
153 | char *address, int address_bytes, | |
154 | int *tcp_nodelay, int *tcp_keepalive, | |
155 | int *mode, | |
156 | struct xrdp_startup_params *startup_param) | |
157 | xrdp_listen_get_startup_params(struct xrdp_listen *self) | |
157 | 158 | { |
158 | 159 | int fd; |
159 | int error; | |
160 | 160 | int index; |
161 | int port_override; | |
162 | int fork_override; | |
161 | 163 | char *val; |
162 | 164 | struct list *names; |
163 | 165 | struct list *values; |
164 | 166 | char cfg_file[256]; |
165 | ||
166 | /* default to port 3389 */ | |
167 | g_strncpy(port, "3389", port_bytes - 1); | |
168 | /* Default to all */ | |
169 | g_strncpy(address, "0.0.0.0", address_bytes - 1); | |
170 | /* see if port or address is in xrdp.ini file */ | |
167 | struct xrdp_startup_params *startup_params; | |
168 | ||
169 | startup_params = self->startup_params; | |
170 | port_override = startup_params->port[0] != 0; | |
171 | fork_override = startup_params->fork; | |
171 | 172 | g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); |
172 | 173 | fd = g_file_open(cfg_file); |
173 | *mode = TRANS_MODE_TCP; | |
174 | *tcp_nodelay = 0 ; | |
175 | *tcp_keepalive = 0 ; | |
176 | ||
177 | 174 | if (fd != -1) |
178 | 175 | { |
179 | 176 | names = list_create(); |
180 | 177 | names->auto_free = 1; |
181 | 178 | values = list_create(); |
182 | 179 | values->auto_free = 1; |
183 | ||
184 | 180 | if (file_read_section(fd, "globals", names, values) == 0) |
185 | 181 | { |
186 | 182 | for (index = 0; index < names->count; index++) |
187 | 183 | { |
188 | 184 | val = (char *)list_get_item(names, index); |
189 | ||
190 | 185 | if (val != 0) |
191 | 186 | { |
192 | 187 | if (g_strcasecmp(val, "port") == 0) |
193 | 188 | { |
194 | val = (char *)list_get_item(values, index); | |
195 | if (val[0] == '/') | |
189 | if (port_override == 0) | |
196 | 190 | { |
197 | g_strncpy(port, val, port_bytes - 1); | |
198 | } | |
199 | else | |
200 | { | |
201 | error = g_atoi(val); | |
202 | if ((error > 0) && (error < 65000)) | |
203 | { | |
204 | g_strncpy(port, val, port_bytes - 1); | |
205 | } | |
191 | val = (char *) list_get_item(values, index); | |
192 | g_strncpy(startup_params->port, val, | |
193 | sizeof(startup_params->port) - 1); | |
206 | 194 | } |
207 | 195 | } |
196 | if (g_strcasecmp(val, "fork") == 0) | |
197 | { | |
198 | if (fork_override == 0) | |
199 | { | |
200 | val = (char *) list_get_item(values, index); | |
201 | startup_params->fork = g_text2bool(val); | |
202 | } | |
203 | } | |
204 | ||
205 | if (g_strcasecmp(val, "tcp_nodelay") == 0) | |
206 | { | |
207 | val = (char *)list_get_item(values, index); | |
208 | startup_params->tcp_nodelay = g_text2bool(val); | |
209 | } | |
210 | ||
211 | if (g_strcasecmp(val, "tcp_keepalive") == 0) | |
212 | { | |
213 | val = (char *)list_get_item(values, index); | |
214 | startup_params->tcp_keepalive = g_text2bool(val); | |
215 | } | |
216 | ||
217 | if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0) | |
218 | { | |
219 | val = (char *)list_get_item(values, index); | |
220 | startup_params->tcp_send_buffer_bytes = g_atoi(val); | |
221 | } | |
222 | ||
223 | if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0) | |
224 | { | |
225 | val = (char *)list_get_item(values, index); | |
226 | startup_params->tcp_recv_buffer_bytes = g_atoi(val); | |
227 | } | |
228 | ||
208 | 229 | if (g_strcasecmp(val, "use_vsock") == 0) |
209 | 230 | { |
210 | 231 | val = (char *)list_get_item(values, index); |
211 | if (g_text2bool(val) == 1) | |
212 | { | |
213 | *mode = TRANS_MODE_VSOCK; | |
214 | } | |
215 | } | |
216 | if (g_strcasecmp(val, "address") == 0) | |
217 | { | |
218 | val = (char *)list_get_item(values, index); | |
219 | g_strncpy(address, val, address_bytes - 1); | |
220 | } | |
221 | ||
222 | if (g_strcasecmp(val, "fork") == 0) | |
223 | { | |
224 | val = (char *)list_get_item(values, index); | |
225 | startup_param->fork = g_text2bool(val); | |
226 | } | |
227 | ||
228 | if (g_strcasecmp(val, "tcp_nodelay") == 0) | |
229 | { | |
230 | val = (char *)list_get_item(values, index); | |
231 | *tcp_nodelay = g_text2bool(val); | |
232 | } | |
233 | ||
234 | if (g_strcasecmp(val, "tcp_keepalive") == 0) | |
235 | { | |
236 | val = (char *)list_get_item(values, index); | |
237 | *tcp_keepalive = g_text2bool(val); | |
238 | } | |
239 | ||
240 | if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0) | |
241 | { | |
242 | val = (char *)list_get_item(values, index); | |
243 | startup_param->send_buffer_bytes = g_atoi(val); | |
244 | } | |
245 | ||
246 | if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0) | |
247 | { | |
248 | val = (char *)list_get_item(values, index); | |
249 | startup_param->recv_buffer_bytes = g_atoi(val); | |
232 | startup_params->use_vsock = g_text2bool(val); | |
250 | 233 | } |
251 | 234 | } |
252 | 235 | } |
254 | 237 | |
255 | 238 | list_delete(names); |
256 | 239 | list_delete(values); |
257 | } | |
258 | ||
259 | if (fd != -1) | |
260 | 240 | g_file_close(fd); |
261 | ||
262 | /* startup_param overrides */ | |
263 | if (startup_param->port[0] != 0) | |
264 | { | |
265 | g_strncpy(port, startup_param->port, port_bytes - 1); | |
266 | } | |
267 | ||
241 | } | |
242 | return 0; | |
243 | } | |
244 | ||
245 | /*****************************************************************************/ | |
246 | static int | |
247 | xrdp_listen_stop_all_listen(struct xrdp_listen *self) | |
248 | { | |
249 | int index; | |
250 | struct trans *ltrans; | |
251 | ||
252 | if (self->trans_list == NULL) | |
253 | { | |
254 | return 0; | |
255 | } | |
256 | for (index = 0; index < self->trans_list->count; index++) | |
257 | { | |
258 | ltrans = (struct trans *) | |
259 | list_get_item(self->trans_list, index); | |
260 | trans_delete(ltrans); | |
261 | } | |
262 | list_clear(self->trans_list); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | /*****************************************************************************/ | |
267 | static int | |
268 | xrdp_listen_parse_filename(char *strout, int strout_max, | |
269 | const char *strin, int strin_max) | |
270 | { | |
271 | int count; | |
272 | int in; | |
273 | int strin_index; | |
274 | int strout_index; | |
275 | ||
276 | strin_index = 0; | |
277 | strout_index = 0; | |
278 | in = 0; | |
279 | count = 0; | |
280 | while ((strin_index < strin_max) && (strout_index < strout_max)) | |
281 | { | |
282 | if (in) | |
283 | { | |
284 | if ((strin[strin_index] > ' ') && (strin[strin_index] != ',')) | |
285 | { | |
286 | strout[strout_index++] = strin[strin_index++]; | |
287 | count++; | |
288 | continue; | |
289 | } | |
290 | else | |
291 | { | |
292 | break; | |
293 | } | |
294 | } | |
295 | else | |
296 | { | |
297 | if ((strin[strin_index] > ' ') && (strin[strin_index] != ',')) | |
298 | { | |
299 | in = 1; | |
300 | strout[strout_index++] = strin[strin_index++]; | |
301 | count++; | |
302 | continue; | |
303 | } | |
304 | } | |
305 | strin_index++; | |
306 | count++; | |
307 | } | |
308 | strout[strout_index] = 0; | |
309 | return count; | |
310 | } | |
311 | ||
312 | /*****************************************************************************/ | |
313 | static int | |
314 | xrdp_listen_parse_integer(char *strout, int strout_max, | |
315 | const char *strin, int strin_max) | |
316 | { | |
317 | int count; | |
318 | int in; | |
319 | int strin_index; | |
320 | int strout_index; | |
321 | ||
322 | strin_index = 0; | |
323 | strout_index = 0; | |
324 | in = 0; | |
325 | count = 0; | |
326 | while ((strin_index < strin_max) && (strout_index < strout_max)) | |
327 | { | |
328 | if (in) | |
329 | { | |
330 | if ((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) | |
331 | { | |
332 | strout[strout_index++] = strin[strin_index++]; | |
333 | count++; | |
334 | continue; | |
335 | } | |
336 | else | |
337 | { | |
338 | break; | |
339 | } | |
340 | } | |
341 | else | |
342 | { | |
343 | if ((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) | |
344 | { | |
345 | in = 1; | |
346 | strout[strout_index++] = strin[strin_index++]; | |
347 | count++; | |
348 | continue; | |
349 | } | |
350 | } | |
351 | strin_index++; | |
352 | count++; | |
353 | } | |
354 | strout[strout_index] = 0; | |
355 | return count; | |
356 | } | |
357 | ||
358 | /*****************************************************************************/ | |
359 | static int | |
360 | xrdp_listen_parse_vsock(char *strout, int strout_max, | |
361 | const char *strin, int strin_max) | |
362 | { | |
363 | int count; | |
364 | int in; | |
365 | int strin_index; | |
366 | int strout_index; | |
367 | ||
368 | strin_index = 0; | |
369 | strout_index = 0; | |
370 | in = 0; | |
371 | count = 0; | |
372 | while ((strin_index < strin_max) && (strout_index < strout_max)) | |
373 | { | |
374 | if (in) | |
375 | { | |
376 | if ((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) | |
377 | { | |
378 | strout[strout_index++] = strin[strin_index++]; | |
379 | count++; | |
380 | continue; | |
381 | } | |
382 | else | |
383 | { | |
384 | break; | |
385 | } | |
386 | } | |
387 | else | |
388 | { | |
389 | if (((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) || | |
390 | (strin[strin_index] == '-')) | |
391 | { | |
392 | in = 1; | |
393 | strout[strout_index++] = strin[strin_index++]; | |
394 | count++; | |
395 | continue; | |
396 | } | |
397 | } | |
398 | strin_index++; | |
399 | count++; | |
400 | } | |
401 | strout[strout_index] = 0; | |
402 | return count; | |
403 | } | |
404 | ||
405 | /*****************************************************************************/ | |
406 | static int | |
407 | xrdp_listen_parse_ipv4(char *strout, int strout_max, | |
408 | const char *strin, int strin_max) | |
409 | { | |
410 | int count; | |
411 | int in; | |
412 | int strin_index; | |
413 | int strout_index; | |
414 | ||
415 | strin_index = 0; | |
416 | strout_index = 0; | |
417 | in = 0; | |
418 | count = 0; | |
419 | while ((strin_index < strin_max) && (strout_index < strout_max)) | |
420 | { | |
421 | if (in) | |
422 | { | |
423 | if (((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) || | |
424 | (strin[strin_index] == '.')) | |
425 | { | |
426 | strout[strout_index++] = strin[strin_index++]; | |
427 | count++; | |
428 | continue; | |
429 | } | |
430 | else | |
431 | { | |
432 | break; | |
433 | } | |
434 | } | |
435 | else | |
436 | { | |
437 | if ((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) | |
438 | { | |
439 | in = 1; | |
440 | strout[strout_index++] = strin[strin_index++]; | |
441 | count++; | |
442 | continue; | |
443 | } | |
444 | } | |
445 | strin_index++; | |
446 | count++; | |
447 | } | |
448 | strout[strout_index] = 0; | |
449 | return count; | |
450 | } | |
451 | ||
452 | /*****************************************************************************/ | |
453 | static int | |
454 | xrdp_listen_parse_ipv6(char *strout, int strout_max, | |
455 | const char *strin, int strin_max) | |
456 | { | |
457 | int count; | |
458 | int in; | |
459 | int strin_index; | |
460 | int strout_index; | |
461 | ||
462 | strin_index = 0; | |
463 | strout_index = 0; | |
464 | in = 0; | |
465 | count = 0; | |
466 | while ((strin_index < strin_max) && (strout_index < strout_max)) | |
467 | { | |
468 | if (in) | |
469 | { | |
470 | if (strin[strin_index] != '}') | |
471 | { | |
472 | strout[strout_index++] = strin[strin_index++]; | |
473 | count++; | |
474 | continue; | |
475 | } | |
476 | else | |
477 | { | |
478 | break; | |
479 | } | |
480 | } | |
481 | else | |
482 | { | |
483 | if (strin[strin_index] == '{') | |
484 | { | |
485 | in = 1; | |
486 | strin_index++; | |
487 | count++; | |
488 | continue; | |
489 | } | |
490 | } | |
491 | strin_index++; | |
492 | count++; | |
493 | } | |
494 | strout[strout_index] = 0; | |
495 | return count; | |
496 | } | |
497 | ||
498 | /*****************************************************************************/ | |
499 | /* address and port are assumed 128 bytes */ | |
500 | static int | |
501 | xrdp_listen_pp(struct xrdp_listen *self, int *index, | |
502 | char *address, char *port, int *mode) | |
503 | { | |
504 | struct xrdp_startup_params *startup_params; | |
505 | const char *str; | |
506 | const char *str_end; | |
507 | int lindex; | |
508 | int bytes; | |
509 | ||
510 | startup_params = self->startup_params; | |
511 | lindex = *index; | |
512 | str = startup_params->port + lindex; | |
513 | str_end = startup_params->port + g_strlen(startup_params->port); | |
514 | while (str < str_end) | |
515 | { | |
516 | if (g_strncmp(str, "unix://.", 8) == 0) | |
517 | { | |
518 | str += 8; | |
519 | lindex += 8; | |
520 | address[0] = 0; | |
521 | bytes = xrdp_listen_parse_filename(port, 128, str, str_end - str); | |
522 | str += bytes; | |
523 | lindex += bytes; | |
524 | *mode = TRANS_MODE_UNIX; | |
525 | *index = lindex; | |
526 | return 0; | |
527 | } | |
528 | else if (g_strncmp(str, "tcp://.:", 8) == 0) | |
529 | { | |
530 | str += 8; | |
531 | lindex += 8; | |
532 | g_strncpy(address, "127.0.0.1", 127); | |
533 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
534 | str += bytes; | |
535 | lindex += bytes; | |
536 | *mode = TRANS_MODE_TCP4; | |
537 | *index = lindex; | |
538 | return 0; | |
539 | } | |
540 | else if (g_strncmp(str, "tcp://:", 7) == 0) | |
541 | { | |
542 | str += 7; | |
543 | lindex += 7; | |
544 | g_strncpy(address, "0.0.0.0", 127); | |
545 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
546 | str += bytes; | |
547 | lindex += bytes; | |
548 | *mode = TRANS_MODE_TCP4; | |
549 | *index = lindex; | |
550 | return 0; | |
551 | } | |
552 | else if (g_strncmp(str, "tcp://", 6) == 0) | |
553 | { | |
554 | str += 6; | |
555 | lindex += 6; | |
556 | bytes = xrdp_listen_parse_ipv4(address, 128, str, str_end - str); | |
557 | str += bytes; | |
558 | lindex += bytes; | |
559 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
560 | str += bytes; | |
561 | lindex += bytes; | |
562 | *mode = TRANS_MODE_TCP4; | |
563 | *index = lindex; | |
564 | return 0; | |
565 | } | |
566 | else if (g_strncmp(str, "tcp6://.:", 9) == 0) | |
567 | { | |
568 | str += 9; | |
569 | lindex += 9; | |
570 | g_strncpy(address, "::1", 127); | |
571 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
572 | str += bytes; | |
573 | lindex += bytes; | |
574 | *mode = TRANS_MODE_TCP6; | |
575 | *index = lindex; | |
576 | return 0; | |
577 | } | |
578 | else if (g_strncmp(str, "tcp6://:", 8) == 0) | |
579 | { | |
580 | str += 8; | |
581 | lindex += 8; | |
582 | g_strncpy(address, "::", 127); | |
583 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
584 | str += bytes; | |
585 | lindex += bytes; | |
586 | *mode = TRANS_MODE_TCP6; | |
587 | *index = lindex; | |
588 | return 0; | |
589 | } | |
590 | else if (g_strncmp(str, "tcp6://", 7) == 0) | |
591 | { | |
592 | str += 7; | |
593 | lindex += 7; | |
594 | bytes = xrdp_listen_parse_ipv6(address, 128, str, str_end - str); | |
595 | str += bytes; | |
596 | lindex += bytes; | |
597 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
598 | str += bytes; | |
599 | lindex += bytes; | |
600 | *mode = TRANS_MODE_TCP6; | |
601 | *index = lindex; | |
602 | return 0; | |
603 | } | |
604 | else if (g_strncmp(str, "vsock://", 8) == 0) | |
605 | { | |
606 | str += 8; | |
607 | lindex += 8; | |
608 | bytes = xrdp_listen_parse_vsock(address, 128, str, str_end - str); | |
609 | str += bytes; | |
610 | lindex += bytes; | |
611 | bytes = xrdp_listen_parse_vsock(port, 128, str, str_end - str); | |
612 | str += bytes; | |
613 | lindex += bytes; | |
614 | *mode = TRANS_MODE_VSOCK; | |
615 | *index = lindex; | |
616 | return 0; | |
617 | } | |
618 | else if ((str[0] >= '0') && (str[0] <= '9')) | |
619 | { | |
620 | g_strncpy(address, "0.0.0.0", 127); | |
621 | bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str); | |
622 | str += bytes; | |
623 | lindex += bytes; | |
624 | if (startup_params->use_vsock) | |
625 | { | |
626 | *mode = TRANS_MODE_VSOCK; | |
627 | } | |
628 | else | |
629 | { | |
630 | *mode = TRANS_MODE_TCP; | |
631 | } | |
632 | *index = lindex; | |
633 | return 0; | |
634 | } | |
635 | else | |
636 | { | |
637 | str++; | |
638 | lindex++; | |
639 | } | |
640 | } | |
641 | if (lindex == *index) | |
642 | { | |
643 | return 1; | |
644 | } | |
645 | if (str >= str_end) | |
646 | { | |
647 | return 1; | |
648 | } | |
649 | *index = lindex; | |
650 | return 0; | |
651 | } | |
652 | ||
653 | /*****************************************************************************/ | |
654 | static int | |
655 | xrdp_listen_process_startup_params(struct xrdp_listen *self) | |
656 | { | |
657 | int mode; /* TRANS_MODE_TCP*, TRANS_MODE_UNIX, TRANS_MODE_VSOCK */ | |
658 | int error; | |
659 | int cont; | |
660 | int bytes; | |
661 | int index; | |
662 | struct trans *ltrans; | |
663 | char address[128]; | |
664 | char port[128]; | |
665 | struct xrdp_startup_params *startup_params; | |
666 | ||
667 | startup_params = self->startup_params; | |
668 | index = 0; | |
669 | cont = 1; | |
670 | while (cont) | |
671 | { | |
672 | if (xrdp_listen_pp(self, &index, address, port, &mode) != 0) | |
673 | { | |
674 | log_message(LOG_LEVEL_INFO, "xrdp_listen_pp done"); | |
675 | cont = 0; | |
676 | break; | |
677 | } | |
678 | log_message(LOG_LEVEL_INFO, "address [%s] port [%s] mode %d", | |
679 | address, port, mode); | |
680 | ltrans = trans_create(mode, 16, 16); | |
681 | if (ltrans == NULL) | |
682 | { | |
683 | log_message(LOG_LEVEL_ERROR, "trans_create failed"); | |
684 | xrdp_listen_stop_all_listen(self); | |
685 | return 1; | |
686 | } | |
687 | log_message(LOG_LEVEL_INFO, "listening to port %s on %s", | |
688 | port, address); | |
689 | error = trans_listen_address(ltrans, port, address); | |
690 | if (error != 0) | |
691 | { | |
692 | log_message(LOG_LEVEL_ERROR, "trans_listen_address failed"); | |
693 | trans_delete(ltrans); | |
694 | xrdp_listen_stop_all_listen(self); | |
695 | return 1; | |
696 | } | |
697 | if ((mode == TRANS_MODE_TCP) || | |
698 | (mode == TRANS_MODE_TCP4) || | |
699 | (mode == TRANS_MODE_TCP6)) | |
700 | { | |
701 | if (startup_params->tcp_nodelay) | |
702 | { | |
703 | if (g_tcp_set_no_delay(ltrans->sck)) | |
704 | { | |
705 | log_message(LOG_LEVEL_ERROR, "Error setting tcp_nodelay"); | |
706 | } | |
707 | } | |
708 | if (startup_params->tcp_keepalive) | |
709 | { | |
710 | if (g_tcp_set_keepalive(ltrans->sck)) | |
711 | { | |
712 | log_message(LOG_LEVEL_ERROR, "Error setting " | |
713 | "tcp_keepalive"); | |
714 | } | |
715 | } | |
716 | if (startup_params->tcp_send_buffer_bytes > 0) | |
717 | { | |
718 | bytes = startup_params->tcp_send_buffer_bytes; | |
719 | log_message(LOG_LEVEL_INFO, "setting send buffer to %d bytes", | |
720 | bytes); | |
721 | if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0) | |
722 | { | |
723 | log_message(LOG_LEVEL_ERROR, "error setting send buffer"); | |
724 | } | |
725 | else | |
726 | { | |
727 | if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0) | |
728 | { | |
729 | log_message(LOG_LEVEL_ERROR, "error getting send " | |
730 | "buffer"); | |
731 | } | |
732 | else | |
733 | { | |
734 | log_message(LOG_LEVEL_INFO, "send buffer set to %d " | |
735 | "bytes", bytes); | |
736 | } | |
737 | } | |
738 | } | |
739 | if (startup_params->tcp_recv_buffer_bytes > 0) | |
740 | { | |
741 | bytes = startup_params->tcp_recv_buffer_bytes; | |
742 | log_message(LOG_LEVEL_INFO, "setting recv buffer to %d bytes", | |
743 | bytes); | |
744 | if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0) | |
745 | { | |
746 | log_message(LOG_LEVEL_ERROR, "error setting recv buffer"); | |
747 | } | |
748 | else | |
749 | { | |
750 | if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0) | |
751 | { | |
752 | log_message(LOG_LEVEL_ERROR, "error getting recv " | |
753 | "buffer"); | |
754 | } | |
755 | else | |
756 | { | |
757 | log_message(LOG_LEVEL_INFO, "recv buffer set to %d " | |
758 | "bytes", bytes); | |
759 | } | |
760 | } | |
761 | } | |
762 | } | |
763 | ltrans->trans_conn_in = xrdp_listen_conn_in; | |
764 | ltrans->callback_data = self; | |
765 | list_add_item(self->trans_list, (intptr_t) ltrans); | |
766 | } | |
268 | 767 | return 0; |
269 | 768 | } |
270 | 769 | |
273 | 772 | xrdp_listen_fork(struct xrdp_listen *self, struct trans *server_trans) |
274 | 773 | { |
275 | 774 | int pid; |
775 | int index; | |
276 | 776 | struct xrdp_process *process; |
777 | struct trans *ltrans; | |
277 | 778 | |
278 | 779 | pid = g_fork(); |
279 | 780 | |
287 | 788 | g_close_wait_obj(self->pro_done_event); |
288 | 789 | xrdp_listen_create_pro_done(self); |
289 | 790 | /* delete listener, child need not listen */ |
290 | trans_delete_from_child(self->listen_trans); | |
291 | self->listen_trans = 0; | |
791 | for (index = 0; index < self->trans_list->count; index++) | |
792 | { | |
793 | ltrans = (struct trans *) list_get_item(self->trans_list, index); | |
794 | trans_delete_from_child(ltrans); | |
795 | } | |
796 | list_delete(self->trans_list); | |
797 | self->trans_list = NULL; | |
292 | 798 | /* new connect instance */ |
293 | 799 | process = xrdp_process_create(self, 0); |
294 | 800 | process->server_trans = server_trans; |
295 | 801 | g_process = process; |
296 | 802 | xrdp_process_run(0); |
803 | tc_sem_dec(g_process_sem); | |
297 | 804 | xrdp_process_delete(process); |
298 | 805 | /* mark this process to exit */ |
299 | 806 | g_set_term(1); |
300 | return 0; | |
807 | return 1; | |
301 | 808 | } |
302 | 809 | |
303 | 810 | /* parent */ |
317 | 824 | |
318 | 825 | if (lis->startup_params->fork) |
319 | 826 | { |
320 | return xrdp_listen_fork(lis, new_self); | |
827 | list_add_item(lis->fork_list, (intptr_t) new_self); | |
828 | return 0; | |
321 | 829 | } |
322 | 830 | |
323 | 831 | process = xrdp_process_create(lis, lis->pro_done_event); |
344 | 852 | int |
345 | 853 | xrdp_listen_main_loop(struct xrdp_listen *self) |
346 | 854 | { |
347 | int error; | |
348 | 855 | int robjs_count; |
349 | 856 | int cont; |
350 | int timeout = 0; | |
351 | char port[128]; | |
352 | char address[256]; | |
353 | tbus robjs[8]; | |
354 | tbus term_obj; | |
355 | tbus sync_obj; | |
356 | tbus done_obj; | |
357 | int tcp_nodelay; | |
358 | int tcp_keepalive; | |
359 | int bytes; | |
857 | int index; | |
858 | int timeout; | |
859 | intptr_t robjs[32]; | |
860 | intptr_t term_obj; | |
861 | intptr_t sync_obj; | |
862 | intptr_t done_obj; | |
863 | struct trans *ltrans; | |
360 | 864 | |
361 | 865 | self->status = 1; |
362 | ||
363 | if (xrdp_listen_get_port_address(port, sizeof(port), | |
364 | address, sizeof(address), | |
365 | &tcp_nodelay, &tcp_keepalive, | |
366 | &self->listen_trans->mode, | |
367 | self->startup_params) != 0) | |
866 | if (xrdp_listen_get_startup_params(self) != 0) | |
368 | 867 | { |
369 | 868 | log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed"); |
370 | 869 | self->status = -1; |
371 | 870 | return 1; |
372 | 871 | } |
373 | ||
374 | if (port[0] == '/') | |
375 | { | |
376 | /* set UDS mode */ | |
377 | self->listen_trans->mode = TRANS_MODE_UNIX; | |
378 | /* not valid with UDS */ | |
379 | tcp_nodelay = 0; | |
380 | } | |
381 | else if (self->listen_trans->mode == TRANS_MODE_VSOCK) | |
382 | { | |
383 | /* not valid with VSOCK */ | |
384 | tcp_nodelay = 0; | |
385 | } | |
386 | ||
387 | /* Create socket */ | |
388 | error = trans_listen_address(self->listen_trans, port, address); | |
389 | if (port[0] == '/') | |
390 | { | |
391 | g_chmod_hex(port, 0x0666); | |
392 | } | |
393 | ||
394 | if (error == 0) | |
395 | { | |
396 | log_message(LOG_LEVEL_INFO, "listening to port %s on %s", | |
397 | port, address); | |
398 | if (tcp_nodelay) | |
399 | { | |
400 | if (g_tcp_set_no_delay(self->listen_trans->sck)) | |
401 | { | |
402 | log_message(LOG_LEVEL_ERROR,"Error setting tcp_nodelay"); | |
403 | } | |
404 | } | |
405 | ||
406 | if (tcp_keepalive) | |
407 | { | |
408 | if (g_tcp_set_keepalive(self->listen_trans->sck)) | |
409 | { | |
410 | log_message(LOG_LEVEL_ERROR,"Error setting tcp_keepalive"); | |
411 | } | |
412 | } | |
413 | ||
414 | if (self->startup_params->send_buffer_bytes > 0) | |
415 | { | |
416 | bytes = self->startup_params->send_buffer_bytes; | |
417 | log_message(LOG_LEVEL_INFO, "setting send buffer to %d bytes", | |
418 | bytes); | |
419 | if (g_sck_set_send_buffer_bytes(self->listen_trans->sck, | |
420 | bytes) != 0) | |
421 | { | |
422 | log_message(LOG_LEVEL_ERROR, "error setting send buffer"); | |
423 | } | |
424 | else | |
425 | { | |
426 | if (g_sck_get_send_buffer_bytes(self->listen_trans->sck, | |
427 | &bytes) != 0) | |
428 | { | |
429 | log_message(LOG_LEVEL_ERROR, "error getting send buffer"); | |
430 | } | |
431 | else | |
432 | { | |
433 | log_message(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes); | |
434 | } | |
435 | } | |
436 | } | |
437 | ||
438 | if (self->startup_params->recv_buffer_bytes > 0) | |
439 | { | |
440 | bytes = self->startup_params->recv_buffer_bytes; | |
441 | log_message(LOG_LEVEL_INFO, "setting recv buffer to %d bytes", | |
442 | bytes); | |
443 | if (g_sck_set_recv_buffer_bytes(self->listen_trans->sck, | |
444 | bytes) != 0) | |
445 | { | |
446 | log_message(LOG_LEVEL_ERROR, "error setting recv buffer"); | |
447 | } | |
448 | else | |
449 | { | |
450 | if (g_sck_get_recv_buffer_bytes(self->listen_trans->sck, | |
451 | &bytes) != 0) | |
452 | { | |
453 | log_message(LOG_LEVEL_ERROR, "error getting recv buffer"); | |
454 | } | |
455 | else | |
456 | { | |
457 | log_message(LOG_LEVEL_INFO, "recv buffer set to %d bytes", bytes); | |
458 | } | |
459 | } | |
460 | } | |
461 | ||
462 | self->listen_trans->trans_conn_in = xrdp_listen_conn_in; | |
463 | self->listen_trans->callback_data = self; | |
464 | term_obj = g_get_term_event(); /*Global termination event */ | |
465 | sync_obj = g_get_sync_event(); | |
466 | done_obj = self->pro_done_event; | |
467 | cont = 1; | |
468 | ||
469 | while (cont) | |
470 | { | |
471 | /* build the wait obj list */ | |
472 | robjs_count = 0; | |
473 | robjs[robjs_count++] = term_obj; | |
474 | robjs[robjs_count++] = sync_obj; | |
475 | robjs[robjs_count++] = done_obj; | |
476 | timeout = -1; | |
477 | ||
478 | if (trans_get_wait_objs(self->listen_trans, robjs, | |
479 | &robjs_count) != 0) | |
480 | { | |
872 | if (xrdp_listen_process_startup_params(self) != 0) | |
873 | { | |
874 | log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed"); | |
875 | self->status = -1; | |
876 | return 1; | |
877 | } | |
878 | term_obj = g_get_term_event(); /*Global termination event */ | |
879 | sync_obj = g_get_sync_event(); | |
880 | done_obj = self->pro_done_event; | |
881 | cont = 1; | |
882 | while (cont) | |
883 | { | |
884 | /* build the wait obj list */ | |
885 | robjs_count = 0; | |
886 | robjs[robjs_count++] = term_obj; | |
887 | robjs[robjs_count++] = sync_obj; | |
888 | robjs[robjs_count++] = done_obj; | |
889 | timeout = -1; | |
890 | ||
891 | for (index = 0; index < self->trans_list->count; index++) | |
892 | { | |
893 | ltrans = (struct trans *) | |
894 | list_get_item(self->trans_list, index); | |
895 | if (trans_get_wait_objs(ltrans, robjs, &robjs_count) != 0) | |
896 | { | |
897 | cont = 0; | |
481 | 898 | break; |
482 | 899 | } |
483 | ||
484 | /* wait - timeout -1 means wait indefinitely*/ | |
485 | if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) | |
486 | { | |
487 | /* error, should not get here */ | |
488 | g_sleep(100); | |
489 | } | |
490 | ||
491 | if (g_is_wait_obj_set(term_obj)) /* termination called */ | |
492 | { | |
900 | } | |
901 | if (cont == 0) | |
902 | { | |
903 | break; | |
904 | } | |
905 | ||
906 | /* wait - timeout -1 means wait indefinitely*/ | |
907 | if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) | |
908 | { | |
909 | /* error, should not get here */ | |
910 | g_sleep(100); | |
911 | } | |
912 | ||
913 | if (g_is_wait_obj_set(term_obj)) /* termination called */ | |
914 | { | |
915 | break; | |
916 | } | |
917 | ||
918 | /* some function must be processed by this thread */ | |
919 | if (g_is_wait_obj_set(sync_obj)) | |
920 | { | |
921 | g_reset_wait_obj(sync_obj); | |
922 | g_process_waiting_function(); /* run the function */ | |
923 | } | |
924 | ||
925 | if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ | |
926 | { | |
927 | g_reset_wait_obj(done_obj); | |
928 | /* a process has died remove it from lists*/ | |
929 | xrdp_listen_delete_done_pro(self); | |
930 | } | |
931 | ||
932 | /* Run the callback when accept() returns a new socket*/ | |
933 | for (index = 0; index < self->trans_list->count; index++) | |
934 | { | |
935 | ltrans = (struct trans *) | |
936 | list_get_item(self->trans_list, index); | |
937 | if (trans_check_wait_objs(ltrans) != 0) | |
938 | { | |
939 | cont = 0; | |
493 | 940 | break; |
494 | 941 | } |
495 | ||
496 | /* some function must be processed by this thread */ | |
497 | if (g_is_wait_obj_set(sync_obj)) | |
498 | { | |
499 | g_reset_wait_obj(sync_obj); | |
500 | g_process_waiting_function(); /* run the function */ | |
501 | } | |
502 | ||
503 | if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ | |
504 | { | |
505 | g_reset_wait_obj(done_obj); | |
506 | /* a process has died remove it from lists*/ | |
507 | xrdp_listen_delete_done_pro(self); | |
508 | } | |
509 | ||
510 | /* Run the callback when accept() returns a new socket*/ | |
511 | if (trans_check_wait_objs(self->listen_trans) != 0) | |
512 | { | |
942 | } | |
943 | if (cont == 0) | |
944 | { | |
945 | break; | |
946 | } | |
947 | while (self->fork_list->count > 0) | |
948 | { | |
949 | ltrans = (struct trans *) list_get_item(self->fork_list, 0); | |
950 | list_remove_item(self->fork_list, 0); | |
951 | if (xrdp_listen_fork(self, ltrans) != 0) | |
952 | { | |
953 | cont = 0; | |
513 | 954 | break; |
514 | 955 | } |
515 | 956 | } |
516 | ||
517 | /* stop listening */ | |
518 | trans_delete(self->listen_trans); | |
519 | self->listen_trans = 0; | |
520 | /* second loop to wait for all process threads to close */ | |
521 | cont = 1; | |
522 | ||
523 | while (cont) | |
524 | { | |
525 | if (self->process_list->count == 0) | |
526 | { | |
527 | break; | |
528 | } | |
529 | ||
530 | timeout = -1; | |
531 | /* build the wait obj list */ | |
532 | robjs_count = 0; | |
533 | robjs[robjs_count++] = sync_obj; | |
534 | robjs[robjs_count++] = done_obj; | |
535 | ||
536 | /* wait - timeout -1 means wait indefinitely*/ | |
537 | if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) | |
538 | { | |
539 | /* error, should not get here */ | |
540 | g_sleep(100); | |
541 | } | |
542 | ||
543 | /* some function must be processed by this thread */ | |
544 | if (g_is_wait_obj_set(sync_obj)) | |
545 | { | |
546 | g_reset_wait_obj(sync_obj); | |
547 | g_process_waiting_function(); /* run the function that is waiting*/ | |
548 | } | |
549 | ||
550 | if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ | |
551 | { | |
552 | g_reset_wait_obj(done_obj); | |
553 | xrdp_listen_delete_done_pro(self); | |
554 | } | |
555 | } | |
556 | } | |
557 | else | |
558 | { | |
559 | log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, possible port " | |
560 | "already in use"); | |
561 | #if !defined(XRDP_ENABLE_VSOCK) | |
562 | if (self->listen_trans->mode == TRANS_MODE_VSOCK) | |
563 | { | |
564 | log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, " | |
565 | "vsock support not compiled and config requested"); | |
566 | } | |
567 | #endif | |
957 | if (cont == 0) | |
958 | { | |
959 | break; | |
960 | } | |
961 | } | |
962 | ||
963 | /* stop listening */ | |
964 | xrdp_listen_stop_all_listen(self); | |
965 | ||
966 | /* second loop to wait for all process threads to close */ | |
967 | cont = 1; | |
968 | ||
969 | while (cont) | |
970 | { | |
971 | if (self->process_list->count == 0) | |
972 | { | |
973 | break; | |
974 | } | |
975 | ||
976 | timeout = -1; | |
977 | /* build the wait obj list */ | |
978 | robjs_count = 0; | |
979 | robjs[robjs_count++] = sync_obj; | |
980 | robjs[robjs_count++] = done_obj; | |
981 | ||
982 | /* wait - timeout -1 means wait indefinitely*/ | |
983 | if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) | |
984 | { | |
985 | /* error, should not get here */ | |
986 | g_sleep(100); | |
987 | } | |
988 | ||
989 | /* some function must be processed by this thread */ | |
990 | if (g_is_wait_obj_set(sync_obj)) | |
991 | { | |
992 | g_reset_wait_obj(sync_obj); | |
993 | g_process_waiting_function(); /* run the function that is waiting*/ | |
994 | } | |
995 | ||
996 | if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ | |
997 | { | |
998 | g_reset_wait_obj(done_obj); | |
999 | xrdp_listen_delete_done_pro(self); | |
1000 | } | |
568 | 1001 | } |
569 | 1002 | |
570 | 1003 | self->status = -1; |
571 | return error; | |
1004 | return 0; | |
572 | 1005 | } |
573 | 1006 | |
574 | 1007 | /*****************************************************************************/ |
575 | 1008 | /* returns 0 if xrdp can listen |
576 | 1009 | returns 1 if xrdp cannot listen */ |
577 | 1010 | int |
578 | xrdp_listen_test(void) | |
579 | { | |
580 | int rv = 0; | |
581 | char port[128]; | |
582 | int mode; | |
583 | char address[256]; | |
584 | int tcp_nodelay; | |
585 | int tcp_keepalive; | |
1011 | xrdp_listen_test(struct xrdp_startup_params *startup_params) | |
1012 | { | |
586 | 1013 | struct xrdp_listen *xrdp_listen; |
587 | struct xrdp_startup_params *startup_params; | |
588 | ||
589 | ||
590 | startup_params = (struct xrdp_startup_params *) | |
591 | g_malloc(sizeof(struct xrdp_startup_params), 1); | |
1014 | ||
592 | 1015 | xrdp_listen = xrdp_listen_create(); |
593 | 1016 | xrdp_listen->startup_params = startup_params; |
594 | ||
595 | ||
596 | if (xrdp_listen_get_port_address(port, sizeof(port), | |
597 | address, sizeof(address), | |
598 | &tcp_nodelay, &tcp_keepalive, | |
599 | &mode, | |
600 | xrdp_listen->startup_params) != 0) | |
601 | { | |
602 | log_message(LOG_LEVEL_DEBUG, "xrdp_listen_test: " | |
603 | "xrdp_listen_get_port_address failed"); | |
604 | rv = 1; | |
605 | goto done; | |
606 | } | |
607 | ||
608 | /* try to listen */ | |
609 | log_message(LOG_LEVEL_DEBUG, "Testing if xrdp can listen on %s port %s.", | |
610 | address, port); | |
611 | rv = trans_listen_address(xrdp_listen->listen_trans, port, address); | |
612 | if (rv == 0) | |
613 | { | |
614 | /* if listen succeeded, stop listen immediately */ | |
615 | trans_delete(xrdp_listen->listen_trans); | |
616 | xrdp_listen->listen_trans = 0; | |
617 | } | |
618 | ||
619 | goto done; | |
620 | ||
621 | done: | |
1017 | if (xrdp_listen_get_startup_params(xrdp_listen) != 0) | |
1018 | { | |
1019 | xrdp_listen_delete(xrdp_listen); | |
1020 | return 1; | |
1021 | } | |
1022 | if (xrdp_listen_process_startup_params(xrdp_listen) != 0) | |
1023 | { | |
1024 | xrdp_listen_delete(xrdp_listen); | |
1025 | return 1; | |
1026 | } | |
622 | 1027 | xrdp_listen_delete(xrdp_listen); |
623 | g_free(startup_params); | |
624 | return rv; | |
625 | } | |
1028 | return 0; | |
1029 | } |
998 | 998 | return 0; |
999 | 999 | } |
1000 | 1000 | |
1001 | /******************************************************************************/ | |
1002 | int | |
1003 | xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress, | |
1004 | int left, int top, int right, int bottom) | |
1005 | { | |
1006 | LLOGLN(0, ("xrdp_mm_suppress_output: suppress %d " | |
1007 | "left %d top %d right %d bottom %d", | |
1008 | suppress, left, top, right, bottom)); | |
1009 | if (self->mod != NULL) | |
1010 | { | |
1011 | if (self->mod->mod_suppress_output != NULL) | |
1012 | { | |
1013 | self->mod->mod_suppress_output(self->mod, suppress, | |
1014 | left, top, right, bottom); | |
1015 | } | |
1016 | } | |
1017 | return 0; | |
1018 | } | |
1019 | ||
1001 | 1020 | /*****************************************************************************/ |
1002 | 1021 | /* open response from client going to channel server */ |
1003 | 1022 | static int |
1410 | 1429 | |
1411 | 1430 | self->usechansrv = 1; |
1412 | 1431 | |
1432 | if (self->wm->client_info->channels_allowed == 0) | |
1433 | { | |
1434 | log_message(LOG_LEVEL_DEBUG, "%s: " | |
1435 | "skip connecting to chansrv because all channels are disabled", | |
1436 | __func__); | |
1437 | return 0; | |
1438 | } | |
1439 | ||
1413 | 1440 | /* connect channel redir */ |
1414 | 1441 | if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) |
1415 | 1442 | { |
1439 | 1466 | self->chan_trans_up = 1; |
1440 | 1467 | break; |
1441 | 1468 | } |
1442 | ||
1469 | if (g_is_term()) | |
1470 | { | |
1471 | break; | |
1472 | } | |
1443 | 1473 | g_sleep(1000); |
1444 | 1474 | log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: connect failed " |
1445 | 1475 | "trying again..."); |
2274 | 2304 | ok = 1; |
2275 | 2305 | break; |
2276 | 2306 | } |
2277 | ||
2307 | if (g_is_term()) | |
2308 | { | |
2309 | break; | |
2310 | } | |
2278 | 2311 | g_sleep(1000); |
2279 | 2312 | g_writeln("xrdp_mm_connect: connect failed " |
2280 | 2313 | "trying again..."); |
47 | 47 | tbus* write_objs, int* wcount, int* timeout); |
48 | 48 | int (*mod_check_wait_objs)(struct xrdp_mod* v); |
49 | 49 | int (*mod_frame_ack)(struct xrdp_mod* v, int flags, int frame_id); |
50 | tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod | |
50 | int (*mod_suppress_output)(struct xrdp_mod* v, int suppress, | |
51 | int left, int top, int right, int bottom); | |
52 | tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod | |
51 | 53 | functions above */ |
52 | 54 | /* server functions */ |
53 | 55 | int (*server_begin_update)(struct xrdp_mod* v); |
402 | 404 | struct xrdp_listen |
403 | 405 | { |
404 | 406 | int status; |
405 | struct trans* listen_trans; /* in tcp listen mode */ | |
406 | struct list* process_list; | |
407 | struct list *trans_list; /* list of struct trans* */ | |
408 | struct list *process_list; | |
409 | struct list *fork_list; | |
407 | 410 | tbus pro_done_event; |
408 | 411 | struct xrdp_startup_params* startup_params; |
409 | 412 | }; |
524 | 527 | |
525 | 528 | struct xrdp_startup_params |
526 | 529 | { |
527 | char port[128]; | |
530 | char port[1024]; | |
528 | 531 | int kill; |
529 | 532 | int no_daemon; |
530 | 533 | int help; |
531 | 534 | int version; |
532 | 535 | int fork; |
533 | int send_buffer_bytes; | |
534 | int recv_buffer_bytes; | |
536 | int tcp_send_buffer_bytes; | |
537 | int tcp_recv_buffer_bytes; | |
538 | int tcp_nodelay; | |
539 | int tcp_keepalive; | |
540 | int use_vsock; | |
535 | 541 | }; |
536 | 542 | |
537 | 543 | /* |
1915 | 1915 | case 0x5558: |
1916 | 1916 | xrdp_mm_drdynvc_up(wm->mm); |
1917 | 1917 | break; |
1918 | case 0x5559: | |
1919 | xrdp_mm_suppress_output(wm->mm, param1, | |
1920 | LOWORD(param2), HIWORD(param2), | |
1921 | LOWORD(param3), HIWORD(param3)); | |
1922 | break; | |
1918 | 1923 | } |
1919 | 1924 | return rv; |
1920 | 1925 | } |
350 | 350 | g_writeln("%s", ""); |
351 | 351 | g_writeln("xrdp: A Remote Desktop Protocol server."); |
352 | 352 | g_writeln("Copyright (C) Jay Sorg 2004-2011"); |
353 | g_writeln("See http://xrdp.sourceforge.net for more information."); | |
353 | g_writeln("See http://www.xrdp.org for more information."); | |
354 | 354 | g_writeln("%s", ""); |
355 | 355 | g_writeln("Usage: xrdp [options]"); |
356 | 356 | g_writeln(" -h: show help"); |
505 | 505 | g_writeln("%s", ""); |
506 | 506 | g_writeln("xrdp: A Remote Desktop Protocol server."); |
507 | 507 | g_writeln("Copyright (C) Jay Sorg 2004-2011"); |
508 | g_writeln("See http://xrdp.sourceforge.net for more information."); | |
508 | g_writeln("See http://www.xrdp.org for more information."); | |
509 | 509 | g_writeln("%s", ""); |
510 | 510 | g_writeln("Usage: xrdp [options]"); |
511 | 511 | g_writeln(" -h: show help"); |
520 | 520 | g_writeln("%s", ""); |
521 | 521 | g_writeln("xrdp: A Remote Desktop Protocol server."); |
522 | 522 | g_writeln("Copyright (C) Jay Sorg 2004-2011"); |
523 | g_writeln("See http://xrdp.sourceforge.net for more information."); | |
523 | g_writeln("See http://www.xrdp.org for more information."); | |
524 | 524 | g_writeln("Version %s", PACKAGE_VERSION); |
525 | 525 | g_writeln("%s", ""); |
526 | 526 | g_exit(0); |
225 | 225 | break; |
226 | 226 | } |
227 | 227 | |
228 | if (mod->server_is_term(mod)) | |
229 | { | |
230 | break; | |
231 | } | |
232 | ||
228 | 233 | i++; |
229 | 234 | |
230 | 235 | if (i >= 60) |
1105 | 1110 | amod->screen_shmem_id_mapped = 1; |
1106 | 1111 | } |
1107 | 1112 | } |
1113 | else if (amod->screen_shmem_id != shmem_id) | |
1114 | { | |
1115 | amod->screen_shmem_id = shmem_id; | |
1116 | g_shmdt(amod->screen_shmem_pixels); | |
1117 | amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); | |
1118 | if (amod->screen_shmem_pixels == (void*)-1) | |
1119 | { | |
1120 | /* failed */ | |
1121 | amod->screen_shmem_id = 0; | |
1122 | amod->screen_shmem_pixels = 0; | |
1123 | amod->screen_shmem_id_mapped = 0; | |
1124 | } | |
1125 | } | |
1108 | 1126 | if (amod->screen_shmem_pixels != 0) |
1109 | 1127 | { |
1110 | 1128 | bmpdata = amod->screen_shmem_pixels + shmem_offset; |
1145 | 1163 | /******************************************************************************/ |
1146 | 1164 | /* return error */ |
1147 | 1165 | static int |
1166 | send_suppress_output(struct mod *mod, int suppress, | |
1167 | int left, int top, int right, int bottom) | |
1168 | { | |
1169 | int len; | |
1170 | struct stream *s; | |
1171 | ||
1172 | make_stream(s); | |
1173 | init_stream(s, 8192); | |
1174 | s_push_layer(s, iso_hdr, 4); | |
1175 | out_uint16_le(s, 108); | |
1176 | out_uint32_le(s, suppress); | |
1177 | out_uint32_le(s, left); | |
1178 | out_uint32_le(s, top); | |
1179 | out_uint32_le(s, right); | |
1180 | out_uint32_le(s, bottom); | |
1181 | s_mark_end(s); | |
1182 | len = (int)(s->end - s->data); | |
1183 | s_pop_layer(s, iso_hdr); | |
1184 | out_uint32_le(s, len); | |
1185 | lib_send_copy(mod, s); | |
1186 | free_stream(s); | |
1187 | return 0; | |
1188 | } | |
1189 | ||
1190 | /******************************************************************************/ | |
1191 | /* return error */ | |
1192 | static int | |
1148 | 1193 | process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) |
1149 | 1194 | { |
1150 | 1195 | int num_drects; |
1214 | 1259 | else |
1215 | 1260 | { |
1216 | 1261 | amod->screen_shmem_id_mapped = 1; |
1262 | } | |
1263 | } | |
1264 | else if (amod->screen_shmem_id != shmem_id) | |
1265 | { | |
1266 | amod->screen_shmem_id = shmem_id; | |
1267 | g_shmdt(amod->screen_shmem_pixels); | |
1268 | amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); | |
1269 | if (amod->screen_shmem_pixels == (void*)-1) | |
1270 | { | |
1271 | /* failed */ | |
1272 | amod->screen_shmem_id = 0; | |
1273 | amod->screen_shmem_pixels = 0; | |
1274 | amod->screen_shmem_id_mapped = 0; | |
1217 | 1275 | } |
1218 | 1276 | } |
1219 | 1277 | if (amod->screen_shmem_pixels != 0) |
1556 | 1614 | } |
1557 | 1615 | |
1558 | 1616 | /******************************************************************************/ |
1617 | /* return error */ | |
1618 | int | |
1619 | lib_mod_suppress_output(struct mod *amod, int suppress, | |
1620 | int left, int top, int right, int bottom) | |
1621 | { | |
1622 | LLOGLN(10, ("lib_mod_suppress_output: suppress 0x%8.8x left %d top %d " | |
1623 | "right %d bottom %d", suppress, left, top, right, bottom)); | |
1624 | send_suppress_output(amod, suppress, left, top, right, bottom); | |
1625 | return 0; | |
1626 | } | |
1627 | ||
1628 | /******************************************************************************/ | |
1559 | 1629 | tintptr EXPORT_CC |
1560 | 1630 | mod_init(void) |
1561 | 1631 | { |
1574 | 1644 | mod->mod_get_wait_objs = lib_mod_get_wait_objs; |
1575 | 1645 | mod->mod_check_wait_objs = lib_mod_check_wait_objs; |
1576 | 1646 | mod->mod_frame_ack = lib_mod_frame_ack; |
1647 | mod->mod_suppress_output = lib_mod_suppress_output; | |
1577 | 1648 | return (tintptr) mod; |
1578 | 1649 | } |
1579 | 1650 |
25 | 25 | #include "xrdp_client_info.h" |
26 | 26 | #include "xrdp_rail.h" |
27 | 27 | |
28 | #define CURRENT_MOD_VER 3 | |
28 | #define CURRENT_MOD_VER 4 | |
29 | 29 | |
30 | 30 | struct mod |
31 | 31 | { |
44 | 44 | tbus* write_objs, int* wcount, int* timeout); |
45 | 45 | int (*mod_check_wait_objs)(struct mod* v); |
46 | 46 | int (*mod_frame_ack)(struct mod* v, int flags, int frame_id); |
47 | tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod | |
47 | int (*mod_suppress_output)(struct mod* v, int suppress, | |
48 | int left, int top, int right, int bottom); | |
49 | tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod | |
48 | 50 | functions above */ |
49 | 51 | /* server functions */ |
50 | 52 | int (*server_begin_update)(struct mod* v); |