1 /*
2    rdesktop: A Remote Desktop Protocol client.
3    Parsing primitives
4    Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
5 
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <errno.h>
21 #include <iconv.h>
22 #include <stdlib.h>
23 
24 #include "rdesktop.h"
25 
26 extern char g_codepage[16];
27 
28 STREAM
s_alloc(unsigned int size)29 s_alloc(unsigned int size)
30 {
31 	STREAM s;
32 
33 	s = xmalloc(sizeof(struct stream));
34 	memset(s, 0, sizeof(struct stream));
35 	s_realloc(s, size);
36 
37 	return s;
38 }
39 
40 STREAM
s_inherit(unsigned char * data,unsigned int size)41 s_inherit(unsigned char *data, unsigned int size)
42 {
43 	STREAM s;
44 
45 	s = xmalloc(sizeof(struct stream));
46 	memset(s, 0, sizeof(struct stream));
47 	s->p = s->data = data;
48 	s->size = size;
49 
50 	return s;
51 }
52 
53 void
s_realloc(STREAM s,unsigned int size)54 s_realloc(STREAM s, unsigned int size)
55 {
56 	unsigned char *data;
57 
58 	if (s->size >= size)
59 		return;
60 
61 	data = s->data;
62 	s->size = size;
63 	s->data = xrealloc(data, size);
64 	s->p = s->data + (s->p - data);
65 	s->end = s->data + (s->end - data);
66 	s->iso_hdr = s->data + (s->iso_hdr - data);
67 	s->mcs_hdr = s->data + (s->mcs_hdr - data);
68 	s->sec_hdr = s->data + (s->sec_hdr - data);
69 	s->rdp_hdr = s->data + (s->rdp_hdr - data);
70 	s->channel_hdr = s->data + (s->channel_hdr - data);
71 }
72 
73 void
s_reset(STREAM s)74 s_reset(STREAM s)
75 {
76 	struct stream tmp;
77 	tmp = *s;
78 	memset(s, 0, sizeof(struct stream));
79 	s->size = tmp.size;
80 	s->end = s->p = s->data = tmp.data;
81 }
82 
83 
84 void
s_free(STREAM s)85 s_free(STREAM s)
86 {
87 	if (s == NULL)
88 		return;
89 	free(s->data);
90 	free(s);
91 }
92 
93 static iconv_t
local_to_utf16()94 local_to_utf16()
95 {
96 	iconv_t icv;
97 	icv = iconv_open(WINDOWS_CODEPAGE, g_codepage);
98 	if (icv == (iconv_t) - 1)
99 	{
100 		logger(Core, Error, "locale_to_utf16(), iconv_open[%s -> %s] fail %p",
101 		       g_codepage, WINDOWS_CODEPAGE, icv);
102 		abort();
103 	}
104 	return icv;
105 }
106 
107 /* Writes a utf16 encoded string into stream excluding null termination.
108    This function assumes that input is ASCII compatible, such as UTF-8.
109  */
110 static inline size_t
_out_utf16s(STREAM s,size_t maxlength,const char * string)111 _out_utf16s(STREAM s, size_t maxlength, const char *string)
112 {
113 	static iconv_t icv_local_to_utf16;
114 	size_t bl, ibl, obl;
115 	const char *pin;
116 	char *pout;
117 
118 	if (string == NULL)
119 		return 0;
120 
121 	if (!icv_local_to_utf16)
122 	{
123 		icv_local_to_utf16 = local_to_utf16();
124 	}
125 
126 	ibl = strlen(string);
127 	obl = maxlength ? maxlength : (size_t) s_left(s);
128 	pin = string;
129 	pout = (char *) s->p;
130 
131 	if (iconv(icv_local_to_utf16, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
132 	{
133 		logger(Protocol, Error, "out_utf16s(), iconv(2) fail, errno %d", errno);
134 		abort();
135 	}
136 
137 	bl = (unsigned char *) pout - s->p;
138 
139 	s->p = (unsigned char *) pout;
140 
141 	return bl;
142 }
143 
144 /* Writes a utf16 encoded string into stream including a null
145    termination. The length is fixed and defined by width. If result is
146    longer than specified width, the string is truncated. pad,
147    specifies a character to pad with.
148 */
149 void
out_utf16s_padded(STREAM s,const char * string,size_t length,unsigned char pad)150 out_utf16s_padded(STREAM s, const char *string, size_t length, unsigned char pad)
151 {
152 	size_t i, bl;
153 	bl = _out_utf16s(s, length - 2, string);
154 
155 	// append utf16 null termination
156 	out_uint16(s, 0);
157 	bl += 2;
158 
159 	for (i = 0; i < (length - bl); i++)
160 		out_uint8(s, pad);
161 }
162 
163 /* Writes a utf16 encoded string into stream including a null
164    termination.
165 */
166 void
out_utf16s(STREAM s,const char * string)167 out_utf16s(STREAM s, const char *string)
168 {
169 	_out_utf16s(s, 0, string);
170 
171 	// append utf16 null termination
172 	out_uint16(s, 0);
173 }
174 
175 
176 /* Writes a utf16 encoded string into stream excluding null
177    termination. */
178 void
out_utf16s_no_eos(STREAM s,const char * string)179 out_utf16s_no_eos(STREAM s, const char *string)
180 {
181 	_out_utf16s(s, 0, string);
182 }
183 
184 /* Read bytes from STREAM s into *string until a null terminator is
185    found, or len bytes are read from the stream. Returns the number of
186    bytes read. */
187 size_t
in_ansi_string(STREAM s,char * string,size_t len)188 in_ansi_string(STREAM s, char *string, size_t len)
189 {
190 	char *ps;
191 	size_t left;
192 	ps = string;
193 
194 	left = len;
195 	while (left--)
196 	{
197 		if (left == 0)
198 			break;
199 
200 		in_uint8(s, *ps);
201 
202 		if (*ps == '\0')
203 			break;
204 
205 		ps++;
206 	}
207 
208 	return len - left;
209 }
210