1 /*
2    Unix SMB/CIFS implementation.
3    parsing of EA (extended attribute) lists
4    Copyright (C) Andrew Tridgell 2003
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 "includes.h"
21 #include "libcli/raw/libcliraw.h"
22 #include "libcli/raw/raw_proto.h"
23 
24 /*
25   work out how many bytes on the wire a ea list will consume.
26   This assumes the names are strict ascii, which should be a
27   reasonable assumption
28 */
ea_list_size(unsigned int num_eas,struct ea_struct * eas)29 size_t ea_list_size(unsigned int num_eas, struct ea_struct *eas)
30 {
31 	unsigned int total = 4;
32 	int i;
33 	for (i=0;i<num_eas;i++) {
34 		total += 4 + strlen(eas[i].name.s)+1 + eas[i].value.length;
35 	}
36 	return total;
37 }
38 
39 /*
40   work out how many bytes on the wire a ea name list will consume.
41 */
ea_name_list_size(unsigned int num_names,struct ea_name * eas)42 static unsigned int ea_name_list_size(unsigned int num_names, struct ea_name *eas)
43 {
44 	unsigned int total = 4;
45 	int i;
46 	for (i=0;i<num_names;i++) {
47 		total += 1 + strlen(eas[i].name.s) + 1;
48 	}
49 	return total;
50 }
51 
52 /*
53   work out how many bytes on the wire a chained ea list will consume.
54   This assumes the names are strict ascii, which should be a
55   reasonable assumption
56 */
ea_list_size_chained(unsigned int num_eas,struct ea_struct * eas,unsigned alignment)57 size_t ea_list_size_chained(unsigned int num_eas, struct ea_struct *eas, unsigned alignment)
58 {
59 	unsigned int total = 0;
60 	int i;
61 	for (i=0;i<num_eas;i++) {
62 		unsigned int len = 8 + strlen(eas[i].name.s)+1 + eas[i].value.length;
63 		len = (len + (alignment-1)) & ~(alignment-1);
64 		total += len;
65 	}
66 	return total;
67 }
68 
69 /*
70   put a ea_list into a pre-allocated buffer - buffer must be at least
71   of size ea_list_size()
72 */
ea_put_list(uint8_t * data,unsigned int num_eas,struct ea_struct * eas)73 void ea_put_list(uint8_t *data, unsigned int num_eas, struct ea_struct *eas)
74 {
75 	int i;
76 	uint32_t ea_size;
77 
78 	ea_size = ea_list_size(num_eas, eas);
79 
80 	SIVAL(data, 0, ea_size);
81 	data += 4;
82 
83 	for (i=0;i<num_eas;i++) {
84 		unsigned int nlen = strlen(eas[i].name.s);
85 		SCVAL(data, 0, eas[i].flags);
86 		SCVAL(data, 1, nlen);
87 		SSVAL(data, 2, eas[i].value.length);
88 		memcpy(data+4, eas[i].name.s, nlen+1);
89 		if (eas[i].value.length > 0) {
90 			memcpy(data + 4 + nlen + 1,
91 			       eas[i].value.data,
92 			       eas[i].value.length);
93 		}
94 		data += 4+nlen+1+eas[i].value.length;
95 	}
96 }
97 
98 
99 /*
100   put a chained ea_list into a pre-allocated buffer - buffer must be
101   at least of size ea_list_size()
102 */
ea_put_list_chained(uint8_t * data,unsigned int num_eas,struct ea_struct * eas,unsigned alignment)103 void ea_put_list_chained(uint8_t *data, unsigned int num_eas, struct ea_struct *eas,
104 			 unsigned alignment)
105 {
106 	int i;
107 
108 	for (i=0;i<num_eas;i++) {
109 		unsigned int nlen = strlen(eas[i].name.s);
110 		uint32_t len = 8+nlen+1+eas[i].value.length;
111 		unsigned int pad = ((len + (alignment-1)) & ~(alignment-1)) - len;
112 		if (i == num_eas-1) {
113 			SIVAL(data, 0, 0);
114 		} else {
115 			SIVAL(data, 0, len+pad);
116 		}
117 		SCVAL(data, 4, eas[i].flags);
118 		SCVAL(data, 5, nlen);
119 		SSVAL(data, 6, eas[i].value.length);
120 		memcpy(data+8, eas[i].name.s, nlen+1);
121 		memcpy(data+8+nlen+1, eas[i].value.data, eas[i].value.length);
122 		memset(data+len, 0, pad);
123 		data += len + pad;
124 	}
125 }
126 
127 
128 /*
129   pull a ea_struct from a buffer. Return the number of bytes consumed
130 */
ea_pull_struct(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,struct ea_struct * ea)131 unsigned int ea_pull_struct(const DATA_BLOB *blob,
132 		      TALLOC_CTX *mem_ctx,
133 		      struct ea_struct *ea)
134 {
135 	uint8_t nlen;
136 	uint16_t vlen;
137 
138 	ZERO_STRUCTP(ea);
139 
140 	if (blob->length < 6) {
141 		return 0;
142 	}
143 
144 	ea->flags = CVAL(blob->data, 0);
145 	nlen = CVAL(blob->data, 1);
146 	vlen = SVAL(blob->data, 2);
147 
148 	if (nlen+1+vlen > blob->length-4) {
149 		return 0;
150 	}
151 
152 	ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+4), nlen);
153 	ea->name.private_length = nlen;
154 	ea->value = data_blob_talloc(mem_ctx, NULL, vlen+1);
155 	if (!ea->value.data) return 0;
156 	if (vlen) {
157 		memcpy(ea->value.data, blob->data+4+nlen+1, vlen);
158 	}
159 	ea->value.data[vlen] = 0;
160 	ea->value.length--;
161 
162 	return 4 + nlen+1 + vlen;
163 }
164 
165 
166 /*
167   pull a ea_list from a buffer
168 */
ea_pull_list(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,unsigned int * num_eas,struct ea_struct ** eas)169 NTSTATUS ea_pull_list(const DATA_BLOB *blob,
170 		      TALLOC_CTX *mem_ctx,
171 		      unsigned int *num_eas, struct ea_struct **eas)
172 {
173 	int n;
174 	uint32_t ea_size, ofs;
175 
176 	if (blob->length < 4) {
177 		return NT_STATUS_INFO_LENGTH_MISMATCH;
178 	}
179 
180 	ea_size = IVAL(blob->data, 0);
181 	if (ea_size > blob->length) {
182 		return NT_STATUS_INVALID_PARAMETER;
183 	}
184 
185 	ofs = 4;
186 	n = 0;
187 	*num_eas = 0;
188 	*eas = NULL;
189 
190 	while (ofs < ea_size) {
191 		unsigned int len;
192 		DATA_BLOB blob2;
193 
194 		blob2.data = blob->data + ofs;
195 		blob2.length = ea_size - ofs;
196 
197 		*eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
198 		if (! *eas) return NT_STATUS_NO_MEMORY;
199 
200 		len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
201 		if (len == 0) {
202 			return NT_STATUS_INVALID_PARAMETER;
203 		}
204 
205 		ofs += len;
206 		n++;
207 	}
208 
209 	*num_eas = n;
210 
211 	return NT_STATUS_OK;
212 }
213 
214 
215 /*
216   pull a chained ea_list from a buffer
217 */
ea_pull_list_chained(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,unsigned int * num_eas,struct ea_struct ** eas)218 NTSTATUS ea_pull_list_chained(const DATA_BLOB *blob,
219 			      TALLOC_CTX *mem_ctx,
220 			      unsigned int *num_eas, struct ea_struct **eas)
221 {
222 	int n;
223 	uint32_t ofs;
224 
225 	if (blob->length < 4) {
226 		return NT_STATUS_INFO_LENGTH_MISMATCH;
227 	}
228 
229 	ofs = 0;
230 	n = 0;
231 	*num_eas = 0;
232 	*eas = NULL;
233 
234 	while (ofs < blob->length) {
235 		unsigned int len;
236 		DATA_BLOB blob2;
237 		uint32_t next_ofs = IVAL(blob->data, ofs);
238 
239 		blob2.data = blob->data + ofs + 4;
240 		blob2.length = blob->length - (ofs + 4);
241 
242 		*eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
243 		if (! *eas) return NT_STATUS_NO_MEMORY;
244 
245 		len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
246 		if (len == 0) {
247 			return NT_STATUS_INVALID_PARAMETER;
248 		}
249 
250 		if (ofs + next_ofs < ofs) {
251 			return NT_STATUS_INVALID_PARAMETER;
252 		}
253 
254 		ofs += next_ofs;
255 		if (ofs+4 > blob->length || ofs+4 < ofs) {
256 			return NT_STATUS_INVALID_PARAMETER;
257 		}
258 		n++;
259 		if (next_ofs == 0) break;
260 	}
261 
262 	*num_eas = n;
263 
264 	return NT_STATUS_OK;
265 }
266 
267 
268 /*
269   pull a ea_name from a buffer. Return the number of bytes consumed
270 */
ea_pull_name(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,struct ea_name * ea)271 static unsigned int ea_pull_name(const DATA_BLOB *blob,
272 			   TALLOC_CTX *mem_ctx,
273 			   struct ea_name *ea)
274 {
275 	uint8_t nlen;
276 
277 	if (blob->length < 2) {
278 		return 0;
279 	}
280 
281 	nlen = CVAL(blob->data, 0);
282 
283 	if (nlen+2 > blob->length) {
284 		return 0;
285 	}
286 
287 	ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+1), nlen);
288 	ea->name.private_length = nlen;
289 
290 	return nlen+2;
291 }
292 
293 
294 /*
295   pull a ea_name list from a buffer
296 */
ea_pull_name_list(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,unsigned int * num_names,struct ea_name ** ea_names)297 NTSTATUS ea_pull_name_list(const DATA_BLOB *blob,
298 			   TALLOC_CTX *mem_ctx,
299 			   unsigned int *num_names, struct ea_name **ea_names)
300 {
301 	int n;
302 	uint32_t ea_size, ofs;
303 
304 	if (blob->length < 4) {
305 		return NT_STATUS_INFO_LENGTH_MISMATCH;
306 	}
307 
308 	ea_size = IVAL(blob->data, 0);
309 	if (ea_size > blob->length) {
310 		return NT_STATUS_INVALID_PARAMETER;
311 	}
312 
313 	ofs = 4;
314 	n = 0;
315 	*num_names = 0;
316 	*ea_names = NULL;
317 
318 	while (ofs < ea_size) {
319 		unsigned int len;
320 		DATA_BLOB blob2;
321 
322 		blob2.data = blob->data + ofs;
323 		blob2.length = ea_size - ofs;
324 
325 		*ea_names = talloc_realloc(mem_ctx, *ea_names, struct ea_name, n+1);
326 		if (! *ea_names) return NT_STATUS_NO_MEMORY;
327 
328 		len = ea_pull_name(&blob2, mem_ctx, &(*ea_names)[n]);
329 		if (len == 0) {
330 			return NT_STATUS_INVALID_PARAMETER;
331 		}
332 
333 		ofs += len;
334 		n++;
335 	}
336 
337 	*num_names = n;
338 
339 	return NT_STATUS_OK;
340 }
341 
342 
343 /*
344   put a ea_name list into a data blob
345 */
ea_push_name_list(TALLOC_CTX * mem_ctx,DATA_BLOB * data,unsigned int num_names,struct ea_name * eas)346 bool ea_push_name_list(TALLOC_CTX *mem_ctx,
347 		       DATA_BLOB *data, unsigned int num_names, struct ea_name *eas)
348 {
349 	int i;
350 	uint32_t ea_size;
351 	uint32_t off;
352 
353 	ea_size = ea_name_list_size(num_names, eas);
354 
355 	*data = data_blob_talloc(mem_ctx, NULL, ea_size);
356 	if (data->data == NULL) {
357 		return false;
358 	}
359 
360 	SIVAL(data->data, 0, ea_size);
361 	off = 4;
362 
363 	for (i=0;i<num_names;i++) {
364 		unsigned int nlen = strlen(eas[i].name.s);
365 		SCVAL(data->data, off, nlen);
366 		memcpy(data->data+off+1, eas[i].name.s, nlen+1);
367 		off += 1+nlen+1;
368 	}
369 
370 	return true;
371 }
372