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 6745 : size_t ea_list_size(unsigned int num_eas, struct ea_struct *eas)
30 : {
31 6745 : unsigned int total = 4;
32 1022 : int i;
33 15635 : for (i=0;i<num_eas;i++) {
34 8890 : total += 4 + strlen(eas[i].name.s)+1 + eas[i].value.length;
35 : }
36 6745 : return total;
37 : }
38 :
39 : /*
40 : work out how many bytes on the wire a ea name list will consume.
41 : */
42 165 : static unsigned int ea_name_list_size(unsigned int num_names, struct ea_name *eas)
43 : {
44 165 : unsigned int total = 4;
45 28 : int i;
46 344 : for (i=0;i<num_names;i++) {
47 179 : total += 1 + strlen(eas[i].name.s) + 1;
48 : }
49 165 : 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 261 : size_t ea_list_size_chained(unsigned int num_eas, struct ea_struct *eas, unsigned alignment)
58 : {
59 261 : unsigned int total = 0;
60 3 : int i;
61 774 : for (i=0;i<num_eas;i++) {
62 513 : unsigned int len = 8 + strlen(eas[i].name.s)+1 + eas[i].value.length;
63 513 : len = (len + (alignment-1)) & ~(alignment-1);
64 513 : total += len;
65 : }
66 261 : 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 3372 : void ea_put_list(uint8_t *data, unsigned int num_eas, struct ea_struct *eas)
74 : {
75 511 : int i;
76 511 : uint32_t ea_size;
77 :
78 3372 : ea_size = ea_list_size(num_eas, eas);
79 :
80 3372 : SIVAL(data, 0, ea_size);
81 3372 : data += 4;
82 :
83 7816 : for (i=0;i<num_eas;i++) {
84 4444 : unsigned int nlen = strlen(eas[i].name.s);
85 4444 : SCVAL(data, 0, eas[i].flags);
86 4444 : SCVAL(data, 1, nlen);
87 4444 : SSVAL(data, 2, eas[i].value.length);
88 4444 : memcpy(data+4, eas[i].name.s, nlen+1);
89 4444 : if (eas[i].value.length > 0) {
90 3949 : memcpy(data + 4 + nlen + 1,
91 3380 : eas[i].value.data,
92 3023 : eas[i].value.length);
93 : }
94 4444 : data += 4+nlen+1+eas[i].value.length;
95 : }
96 3372 : }
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 259 : void ea_put_list_chained(uint8_t *data, unsigned int num_eas, struct ea_struct *eas,
104 : unsigned alignment)
105 : {
106 3 : int i;
107 :
108 772 : for (i=0;i<num_eas;i++) {
109 513 : unsigned int nlen = strlen(eas[i].name.s);
110 513 : uint32_t len = 8+nlen+1+eas[i].value.length;
111 513 : unsigned int pad = ((len + (alignment-1)) & ~(alignment-1)) - len;
112 513 : if (i == num_eas-1) {
113 257 : SIVAL(data, 0, 0);
114 : } else {
115 256 : SIVAL(data, 0, len+pad);
116 : }
117 513 : SCVAL(data, 4, eas[i].flags);
118 513 : SCVAL(data, 5, nlen);
119 513 : SSVAL(data, 6, eas[i].value.length);
120 513 : memcpy(data+8, eas[i].name.s, nlen+1);
121 513 : memcpy(data+8+nlen+1, eas[i].value.data, eas[i].value.length);
122 513 : memset(data+len, 0, pad);
123 513 : data += len + pad;
124 : }
125 259 : }
126 :
127 :
128 : /*
129 : pull a ea_struct from a buffer. Return the number of bytes consumed
130 : */
131 869 : unsigned int ea_pull_struct(const DATA_BLOB *blob,
132 : TALLOC_CTX *mem_ctx,
133 : struct ea_struct *ea)
134 : {
135 28 : uint8_t nlen;
136 28 : uint16_t vlen;
137 :
138 869 : ZERO_STRUCTP(ea);
139 :
140 869 : if (blob->length < 6) {
141 0 : return 0;
142 : }
143 :
144 869 : ea->flags = CVAL(blob->data, 0);
145 869 : nlen = CVAL(blob->data, 1);
146 869 : vlen = SVAL(blob->data, 2);
147 :
148 869 : if (nlen+1+vlen > blob->length-4) {
149 0 : return 0;
150 : }
151 :
152 869 : ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+4), nlen);
153 869 : ea->name.private_length = nlen;
154 869 : ea->value = data_blob_talloc(mem_ctx, NULL, vlen+1);
155 869 : if (!ea->value.data) return 0;
156 869 : if (vlen) {
157 794 : memcpy(ea->value.data, blob->data+4+nlen+1, vlen);
158 : }
159 869 : ea->value.data[vlen] = 0;
160 869 : ea->value.length--;
161 :
162 869 : return 4 + nlen+1 + vlen;
163 : }
164 :
165 :
166 : /*
167 : pull a ea_list from a buffer
168 : */
169 495 : NTSTATUS ea_pull_list(const DATA_BLOB *blob,
170 : TALLOC_CTX *mem_ctx,
171 : unsigned int *num_eas, struct ea_struct **eas)
172 : {
173 28 : int n;
174 28 : uint32_t ea_size, ofs;
175 :
176 495 : if (blob->length < 4) {
177 4 : return NT_STATUS_INFO_LENGTH_MISMATCH;
178 : }
179 :
180 491 : ea_size = IVAL(blob->data, 0);
181 491 : if (ea_size > blob->length) {
182 0 : return NT_STATUS_INVALID_PARAMETER;
183 : }
184 :
185 491 : ofs = 4;
186 491 : n = 0;
187 491 : *num_eas = 0;
188 491 : *eas = NULL;
189 :
190 1318 : while (ofs < ea_size) {
191 28 : unsigned int len;
192 28 : DATA_BLOB blob2;
193 :
194 827 : blob2.data = blob->data + ofs;
195 827 : blob2.length = ea_size - ofs;
196 :
197 827 : *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
198 827 : if (! *eas) return NT_STATUS_NO_MEMORY;
199 :
200 827 : len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
201 827 : if (len == 0) {
202 0 : return NT_STATUS_INVALID_PARAMETER;
203 : }
204 :
205 827 : ofs += len;
206 827 : n++;
207 : }
208 :
209 491 : *num_eas = n;
210 :
211 491 : return NT_STATUS_OK;
212 : }
213 :
214 :
215 : /*
216 : pull a chained ea_list from a buffer
217 : */
218 23 : 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 0 : int n;
223 0 : uint32_t ofs;
224 :
225 23 : if (blob->length < 4) {
226 0 : return NT_STATUS_INFO_LENGTH_MISMATCH;
227 : }
228 :
229 23 : ofs = 0;
230 23 : n = 0;
231 23 : *num_eas = 0;
232 23 : *eas = NULL;
233 :
234 42 : while (ofs < blob->length) {
235 0 : unsigned int len;
236 0 : DATA_BLOB blob2;
237 42 : uint32_t next_ofs = IVAL(blob->data, ofs);
238 :
239 42 : blob2.data = blob->data + ofs + 4;
240 42 : blob2.length = blob->length - (ofs + 4);
241 :
242 42 : *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1);
243 42 : if (! *eas) return NT_STATUS_NO_MEMORY;
244 :
245 42 : len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
246 42 : if (len == 0) {
247 0 : return NT_STATUS_INVALID_PARAMETER;
248 : }
249 :
250 42 : if (ofs + next_ofs < ofs) {
251 0 : return NT_STATUS_INVALID_PARAMETER;
252 : }
253 :
254 42 : ofs += next_ofs;
255 42 : if (ofs+4 > blob->length || ofs+4 < ofs) {
256 0 : return NT_STATUS_INVALID_PARAMETER;
257 : }
258 42 : n++;
259 42 : if (next_ofs == 0) break;
260 : }
261 :
262 23 : *num_eas = n;
263 :
264 23 : 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 0 : 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 0 : int n;
302 0 : 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 20 : while (ofs < ea_size) {
319 0 : unsigned int len;
320 0 : 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 165 : bool ea_push_name_list(TALLOC_CTX *mem_ctx,
347 : DATA_BLOB *data, unsigned int num_names, struct ea_name *eas)
348 : {
349 28 : int i;
350 28 : uint32_t ea_size;
351 28 : uint32_t off;
352 :
353 165 : ea_size = ea_name_list_size(num_names, eas);
354 :
355 165 : *data = data_blob_talloc(mem_ctx, NULL, ea_size);
356 165 : if (data->data == NULL) {
357 0 : return false;
358 : }
359 :
360 165 : SIVAL(data->data, 0, ea_size);
361 165 : off = 4;
362 :
363 344 : for (i=0;i<num_names;i++) {
364 179 : unsigned int nlen = strlen(eas[i].name.s);
365 179 : SCVAL(data->data, off, nlen);
366 179 : memcpy(data->data+off+1, eas[i].name.s, nlen+1);
367 179 : off += 1+nlen+1;
368 : }
369 :
370 137 : return true;
371 : }
|