Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/data_blob.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Easy management of byte-length data
4
   Copyright (C) Andrew Tridgell 2001
5
   Copyright (C) Andrew Bartlett 2001
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
#include "replace.h"
22
#include "attr.h"
23
#include "data_blob.h"
24
#include "lib/util/samba_util.h"
25
#include "lib/util/tsort.h"
26
27
const DATA_BLOB data_blob_null = { NULL, 0 };
28
29
/**
30
 * @file
31
 * @brief Manipulation of arbitrary data blobs
32
 **/
33
34
/**
35
 construct a data blob, must be freed with data_blob_free()
36
 you can pass NULL for p and get a blank data blob
37
**/
38
_PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
39
1.09k
{
40
1.09k
  return data_blob_talloc_named(NULL, p, length, name);
41
1.09k
}
42
43
/**
44
 construct a data blob, using supplied TALLOC_CTX
45
**/
46
_PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
47
2.80M
{
48
2.80M
  DATA_BLOB ret;
49
50
2.80M
  if (p == NULL && length == 0) {
51
36.9k
    ZERO_STRUCT(ret);
52
36.9k
    return ret;
53
36.9k
  }
54
55
2.76M
  if (p) {
56
2.68M
    ret.data = (uint8_t *)talloc_memdup(mem_ctx, p, length);
57
2.68M
  } else {
58
81.3k
    ret.data = talloc_array(mem_ctx, uint8_t, length);
59
81.3k
  }
60
2.76M
  if (ret.data == NULL) {
61
0
    ret.length = 0;
62
0
    return ret;
63
0
  }
64
2.76M
  talloc_set_name_const(ret.data, name);
65
2.76M
  ret.length = length;
66
2.76M
  return ret;
67
2.76M
}
68
69
/**
70
 construct a zero data blob, using supplied TALLOC_CTX.
71
 use this sparingly as it initialises data - better to initialise
72
 yourself if you want specific data in the blob
73
**/
74
_PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
75
62.3k
{
76
62.3k
  DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
77
62.3k
  data_blob_clear(&blob);
78
62.3k
  return blob;
79
62.3k
}
80
81
/**
82
free a data blob
83
**/
84
_PUBLIC_ void data_blob_free(DATA_BLOB *d)
85
8.57k
{
86
8.57k
  if (d) {
87
8.57k
    TALLOC_FREE(d->data);
88
8.57k
    d->length = 0;
89
8.57k
  }
90
8.57k
}
91
92
/**
93
clear a DATA_BLOB's contents
94
**/
95
_PUBLIC_ void data_blob_clear(DATA_BLOB *d)
96
62.3k
{
97
62.3k
  if (d->data) {
98
26.3k
    ZERO_ARRAY_LEN(d->data, d->length);
99
26.3k
  }
100
62.3k
}
101
102
/**
103
free a data blob and clear its contents
104
**/
105
_PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
106
0
{
107
0
  data_blob_clear(d);
108
0
  data_blob_free(d);
109
0
}
110
111
112
/**
113
check if two data blobs are equal
114
**/
115
_PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
116
62.4k
{
117
62.4k
  int ret;
118
62.4k
  if (d1->data == NULL && d2->data != NULL) {
119
6.42k
    return -1;
120
6.42k
  }
121
56.0k
  if (d1->data != NULL && d2->data == NULL) {
122
5.41k
    return 1;
123
5.41k
  }
124
50.5k
  if (d1->data == d2->data) {
125
6.72k
    return NUMERIC_CMP(d1->length, d2->length);
126
6.72k
  }
127
43.8k
  ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
128
43.8k
  if (ret == 0) {
129
    /* Note this ordering is used in conditional aces */
130
31.7k
    return NUMERIC_CMP(d1->length, d2->length);
131
31.7k
  }
132
12.1k
  return ret;
133
43.8k
}
134
135
/**
136
check if two data blobs are equal, where the time taken should not depend on the
137
contents of either blob.
138
**/
139
_PUBLIC_ bool data_blob_equal_const_time(const DATA_BLOB *d1, const DATA_BLOB *d2)
140
0
{
141
0
  bool ret;
142
0
  if (d1->data == NULL && d2->data != NULL) {
143
0
    return false;
144
0
  }
145
0
  if (d1->data != NULL && d2->data == NULL) {
146
0
    return false;
147
0
  }
148
0
  if (d1->length != d2->length) {
149
0
    return false;
150
0
  }
151
0
  if (d1->data == d2->data) {
152
0
    return true;
153
0
  }
154
0
  ret = mem_equal_const_time(d1->data, d2->data, d1->length);
155
0
  return ret;
156
0
}
157
158
/**
159
print the data_blob as hex string
160
**/
161
_PUBLIC_ char *data_blob_hex_string_lower(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
162
0
{
163
0
  size_t i;
164
0
  char *hex_string;
165
166
0
  hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
167
0
  if (!hex_string) {
168
0
    return NULL;
169
0
  }
170
171
  /* this must be lowercase or w2k8 cannot join a samba domain,
172
     as this routine is used to encode extended DNs and windows
173
     only accepts lowercase hexadecimal numbers */
174
0
  for (i = 0; i < blob->length; i++) {
175
0
    hex_string[i * 2] = nybble_to_hex_lower(blob->data[i] >> 4);
176
0
    hex_string[i * 2 + 1] = nybble_to_hex_lower(blob->data[i]);
177
0
  }
178
179
0
  hex_string[(blob->length*2)] = '\0';
180
0
  return hex_string;
181
0
}
182
183
_PUBLIC_ char *data_blob_hex_string_upper(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
184
80.4k
{
185
80.4k
  size_t i;
186
80.4k
  char *hex_string;
187
188
80.4k
  hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
189
80.4k
  if (!hex_string) {
190
0
    return NULL;
191
0
  }
192
193
863k
  for (i = 0; i < blob->length; i++) {
194
782k
    hex_string[i * 2] = nybble_to_hex_upper(blob->data[i] >> 4);
195
782k
    hex_string[i * 2 + 1] = nybble_to_hex_upper(blob->data[i]);
196
782k
  }
197
198
80.4k
  hex_string[(blob->length*2)] = '\0';
199
80.4k
  return hex_string;
200
80.4k
}
201
202
/**
203
  useful for constructing data blobs in test suites, while
204
  avoiding const warnings
205
**/
206
_PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
207
113k
{
208
113k
  DATA_BLOB blob;
209
113k
  blob.data = discard_const_p(uint8_t, str);
210
113k
  blob.length = str ? strlen(str) : 0;
211
113k
  return blob;
212
113k
}
213
214
/**
215
  useful for constructing data blobs in test suites, while
216
  avoiding const warnings
217
**/
218
_PUBLIC_ DATA_BLOB data_blob_string_const_null(const char *str)
219
0
{
220
0
  DATA_BLOB blob;
221
0
  blob.data = discard_const_p(uint8_t, str);
222
0
  blob.length = str ? strlen(str)+1 : 0;
223
0
  return blob;
224
0
}
225
226
/**
227
 * Create a new data blob from const data
228
 */
229
230
_PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
231
1.87M
{
232
1.87M
  DATA_BLOB blob;
233
1.87M
  blob.data = discard_const_p(uint8_t, p);
234
1.87M
  blob.length = length;
235
1.87M
  return blob;
236
1.87M
}
237
238
239
/**
240
  realloc a data_blob
241
**/
242
_PUBLIC_ bool data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
243
0
{
244
0
  uint8_t *tmp = talloc_realloc(mem_ctx, blob->data, uint8_t, length);
245
0
  if (tmp == NULL) {
246
0
    return false;
247
0
  }
248
0
  blob->data = tmp;
249
0
  blob->length = length;
250
0
  return true;
251
0
}
252
253
254
/**
255
  append some data to a data blob
256
**/
257
_PUBLIC_ bool data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
258
           const void *p, size_t length)
259
0
{
260
0
  size_t old_len = blob->length;
261
0
  size_t new_len = old_len + length;
262
263
0
  if (length == 0) {
264
0
    return true;
265
0
  }
266
267
0
  if (new_len < length || new_len < old_len) {
268
0
    return false;
269
0
  }
270
271
0
  if ((const uint8_t *)p + length < (const uint8_t *)p) {
272
0
    return false;
273
0
  }
274
275
0
  if (!data_blob_realloc(mem_ctx, blob, new_len)) {
276
0
    return false;
277
0
  }
278
279
0
  memcpy(blob->data + old_len, p, length);
280
0
  return true;
281
0
}
282
283
/**
284
  pad the length of a data blob to a multiple of
285
  'pad'. 'pad' must be a power of two.
286
**/
287
_PUBLIC_ bool data_blob_pad(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
288
          size_t pad)
289
0
{
290
0
  size_t old_len = blob->length;
291
0
  size_t new_len = (old_len + pad - 1) & ~(pad - 1);
292
293
0
  if (new_len < old_len || (pad & (pad - 1)) != 0) {
294
0
    return false;
295
0
  }
296
297
0
  if (!data_blob_realloc(mem_ctx, blob, new_len)) {
298
0
    return false;
299
0
  }
300
301
0
  memset(blob->data + old_len, 0, new_len - old_len);
302
  return true;
303
0
}