Coverage Report

Created: 2026-02-14 07:07

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