Line data Source code
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 : */
29 663 : size_t ea_list_size(unsigned int num_eas, struct ea_struct *eas)
30 : {
31 663 : unsigned int total = 4;
32 : int i;
33 1979 : for (i=0;i<num_eas;i++) {
34 1316 : total += 4 + strlen(eas[i].name.s)+1 + eas[i].value.length;
35 : }
36 663 : return total;
37 : }
38 :
39 : /*
40 : work out how many bytes on the wire a ea name list will consume.
41 : */
42 9 : static unsigned int ea_name_list_size(unsigned int num_names, struct ea_name *eas)
43 : {
44 9 : unsigned int total = 4;
45 : int i;
46 20 : for (i=0;i<num_names;i++) {
47 11 : total += 1 + strlen(eas[i].name.s) + 1;
48 : }
49 9 : 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 : */
57 14 : size_t ea_list_size_chained(unsigned int num_eas, struct ea_struct *eas, unsigned alignment)
58 : {
59 14 : unsigned int total = 0;
60 : int i;
61 40 : for (i=0;i<num_eas;i++) {
62 26 : unsigned int len = 8 + strlen(eas[i].name.s)+1 + eas[i].value.length;
63 26 : len = (len + (alignment-1)) & ~(alignment-1);
64 26 : total += len;
65 : }
66 14 : 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 : */
73 331 : 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 331 : ea_size = ea_list_size(num_eas, eas);
79 :
80 331 : SIVAL(data, 0, ea_size);
81 331 : data += 4;
82 :
83 988 : for (i=0;i<num_eas;i++) {
84 657 : unsigned int nlen = strlen(eas[i].name.s);
85 657 : SCVAL(data, 0, eas[i].flags);
86 657 : SCVAL(data, 1, nlen);
87 657 : SSVAL(data, 2, eas[i].value.length);
88 657 : memcpy(data+4, eas[i].name.s, nlen+1);
89 657 : if (eas[i].value.length > 0) {
90 1306 : memcpy(data + 4 + nlen + 1,
91 653 : eas[i].value.data,
92 653 : eas[i].value.length);
93 : }
94 657 : data += 4+nlen+1+eas[i].value.length;
95 : }
96 331 : }
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 : */
103 14 : 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 40 : for (i=0;i<num_eas;i++) {
109 26 : unsigned int nlen = strlen(eas[i].name.s);
110 26 : uint32_t len = 8+nlen+1+eas[i].value.length;
111 26 : unsigned int pad = ((len + (alignment-1)) & ~(alignment-1)) - len;
112 26 : if (i == num_eas-1) {
113 14 : SIVAL(data, 0, 0);
114 : } else {
115 12 : SIVAL(data, 0, len+pad);
116 : }
117 26 : SCVAL(data, 4, eas[i].flags);
118 26 : SCVAL(data, 5, nlen);
119 26 : SSVAL(data, 6, eas[i].value.length);
120 26 : memcpy(data+8, eas[i].name.s, nlen+1);
121 26 : memcpy(data+8+nlen+1, eas[i].value.data, eas[i].value.length);
122 26 : memset(data+len, 0, pad);
123 26 : data += len + pad;
124 : }
125 14 : }
126 :
127 :
128 : /*
129 : pull a ea_struct from a buffer. Return the number of bytes consumed
130 : */
131 673 : 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 673 : ZERO_STRUCTP(ea);
139 :
140 673 : if (blob->length < 6) {
141 0 : return 0;
142 : }
143 :
144 673 : ea->flags = CVAL(blob->data, 0);
145 673 : nlen = CVAL(blob->data, 1);
146 673 : vlen = SVAL(blob->data, 2);
147 :
148 673 : if (nlen+1+vlen > blob->length-4) {
149 0 : return 0;
150 : }
151 :
152 673 : ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+4), nlen);
153 673 : ea->name.private_length = nlen;
154 673 : ea->value = data_blob_talloc(mem_ctx, NULL, vlen+1);
155 673 : if (!ea->value.data) return 0;
156 673 : if (vlen) {
157 667 : memcpy(ea->value.data, blob->data+4+nlen+1, vlen);
158 : }
159 673 : ea->value.data[vlen] = 0;
160 673 : ea->value.length--;
161 :
162 673 : return 4 + nlen+1 + vlen;
163 : }
164 :
165 :
166 : /*
167 : pull a ea_list from a buffer
168 : */
169 335 : 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 335 : if (blob->length < 4) {
177 4 : return NT_STATUS_INFO_LENGTH_MISMATCH;
178 : }
179 :
180 331 : ea_size = IVAL(blob->data, 0);
181 331 : if (ea_size > blob->length) {
182 0 : return NT_STATUS_INVALID_PARAMETER;
183 : }
184 :
185 331 : ofs = 4;
186 331 : n = 0;
187 331 : *num_eas = 0;
188 331 : *eas = NULL;
189 :
190 1309 : while (ofs < ea_size) {
191 : unsigned int len;
192 : DATA_BLOB blob2;
193 :
194 649 : blob2.data = blob->data + ofs;
195 649 : blob2.length = ea_size - ofs;
196 :
197 649 : *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
198 649 : if (! *eas) return NT_STATUS_NO_MEMORY;
199 :
200 649 : len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
201 649 : if (len == 0) {
202 0 : return NT_STATUS_INVALID_PARAMETER;
203 : }
204 :
205 649 : ofs += len;
206 649 : n++;
207 : }
208 :
209 331 : *num_eas = n;
210 :
211 331 : return NT_STATUS_OK;
212 : }
213 :
214 :
215 : /*
216 : pull a chained ea_list from a buffer
217 : */
218 13 : 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 13 : if (blob->length < 4) {
226 0 : return NT_STATUS_INFO_LENGTH_MISMATCH;
227 : }
228 :
229 13 : ofs = 0;
230 13 : n = 0;
231 13 : *num_eas = 0;
232 13 : *eas = NULL;
233 :
234 37 : while (ofs < blob->length) {
235 : unsigned int len;
236 : DATA_BLOB blob2;
237 24 : uint32_t next_ofs = IVAL(blob->data, ofs);
238 :
239 24 : blob2.data = blob->data + ofs + 4;
240 24 : blob2.length = blob->length - (ofs + 4);
241 :
242 24 : *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
243 24 : if (! *eas) return NT_STATUS_NO_MEMORY;
244 :
245 24 : len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
246 24 : if (len == 0) {
247 0 : return NT_STATUS_INVALID_PARAMETER;
248 : }
249 :
250 24 : if (ofs + next_ofs < ofs) {
251 0 : return NT_STATUS_INVALID_PARAMETER;
252 : }
253 :
254 24 : ofs += next_ofs;
255 24 : if (ofs+4 > blob->length || ofs+4 < ofs) {
256 0 : return NT_STATUS_INVALID_PARAMETER;
257 : }
258 24 : n++;
259 24 : if (next_ofs == 0) break;
260 : }
261 :
262 13 : *num_eas = n;
263 :
264 13 : return NT_STATUS_OK;
265 : }
266 :
267 :
268 : /*
269 : pull a ea_name from a buffer. Return the number of bytes consumed
270 : */
271 11 : 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 11 : if (blob->length < 2) {
278 0 : return 0;
279 : }
280 :
281 11 : nlen = CVAL(blob->data, 0);
282 :
283 11 : if (nlen+2 > blob->length) {
284 0 : return 0;
285 : }
286 :
287 11 : ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+1), nlen);
288 11 : ea->name.private_length = nlen;
289 :
290 11 : return nlen+2;
291 : }
292 :
293 :
294 : /*
295 : pull a ea_name list from a buffer
296 : */
297 15 : 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 15 : if (blob->length < 4) {
305 6 : return NT_STATUS_INFO_LENGTH_MISMATCH;
306 : }
307 :
308 9 : ea_size = IVAL(blob->data, 0);
309 9 : if (ea_size > blob->length) {
310 0 : return NT_STATUS_INVALID_PARAMETER;
311 : }
312 :
313 9 : ofs = 4;
314 9 : n = 0;
315 9 : *num_names = 0;
316 9 : *ea_names = NULL;
317 :
318 29 : while (ofs < ea_size) {
319 : unsigned int len;
320 : DATA_BLOB blob2;
321 :
322 11 : blob2.data = blob->data + ofs;
323 11 : blob2.length = ea_size - ofs;
324 :
325 11 : *ea_names = talloc_realloc(mem_ctx, *ea_names, struct ea_name, n+1);
326 11 : if (! *ea_names) return NT_STATUS_NO_MEMORY;
327 :
328 11 : len = ea_pull_name(&blob2, mem_ctx, &(*ea_names)[n]);
329 11 : if (len == 0) {
330 0 : return NT_STATUS_INVALID_PARAMETER;
331 : }
332 :
333 11 : ofs += len;
334 11 : n++;
335 : }
336 :
337 9 : *num_names = n;
338 :
339 9 : return NT_STATUS_OK;
340 : }
341 :
342 :
343 : /*
344 : put a ea_name list into a data blob
345 : */
346 9 : 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 9 : ea_size = ea_name_list_size(num_names, eas);
354 :
355 9 : *data = data_blob_talloc(mem_ctx, NULL, ea_size);
356 9 : if (data->data == NULL) {
357 0 : return false;
358 : }
359 :
360 9 : SIVAL(data->data, 0, ea_size);
361 9 : off = 4;
362 :
363 20 : for (i=0;i<num_names;i++) {
364 11 : unsigned int nlen = strlen(eas[i].name.s);
365 11 : SCVAL(data->data, off, nlen);
366 11 : memcpy(data->data+off+1, eas[i].name.s, nlen+1);
367 11 : off += 1+nlen+1;
368 : }
369 :
370 9 : return true;
371 : }
|