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