manpage: document the mount.cifs vers= option
[jlayton/cifs-utils.git] / data_blob.c
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 <string.h>
22
23 #include "replace.h"
24 #include "data_blob.h"
25
26 const DATA_BLOB data_blob_null = { NULL, 0 };
27
28 /**
29  * @file
30  * @brief Manipulation of arbitrary data blobs
31  **/
32
33 /**
34  construct a data blob, must be freed with data_blob_free()
35  you can pass NULL for p and get a blank data blob
36 **/
37 _PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
38 {
39         DATA_BLOB ret;
40
41         if (p == NULL && length == 0) {
42                 ZERO_STRUCT(ret);
43                 return ret;
44         }
45
46         if (p) {
47                 ret.data = (uint8_t *)talloc_memdup(NULL, p, length);
48         } else {
49                 ret.data = talloc_array(NULL, uint8_t, length);
50         }
51         if (ret.data == NULL) {
52                 ret.length = 0;
53                 return ret;
54         }
55         talloc_set_name_const(ret.data, name);
56         ret.length = length;
57         return ret;
58 }
59
60 /**
61  construct a data blob, using supplied TALLOC_CTX
62 **/
63 _PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
64 {
65         DATA_BLOB ret = data_blob_named(p, length, name);
66
67         if (ret.data) {
68                 talloc_steal(mem_ctx, ret.data);
69         }
70         return ret;
71 }
72
73 /**
74  construct a zero data blob, using supplied TALLOC_CTX. 
75  use this sparingly as it initialises data - better to initialise
76  yourself if you want specific data in the blob
77 **/
78 _PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
79 {
80         DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
81         data_blob_clear(&blob);
82         return blob;
83 }
84
85 /**
86 free a data blob
87 **/
88 _PUBLIC_ void data_blob_free(DATA_BLOB *d)
89 {
90         if (d) {
91                 talloc_free(d->data);
92                 d->data = NULL;
93                 d->length = 0;
94         }
95 }
96
97 /**
98 clear a DATA_BLOB's contents
99 **/
100 _PUBLIC_ void data_blob_clear(DATA_BLOB *d)
101 {
102         if (d->data) {
103                 memset(d->data, 0, d->length);
104         }
105 }
106
107 /**
108 free a data blob and clear its contents
109 **/
110 _PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
111 {
112         data_blob_clear(d);
113         data_blob_free(d);
114 }
115
116
117 /**
118 check if two data blobs are equal
119 **/
120 _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
121 {
122         int ret;
123         if (d1->data == NULL && d2->data != NULL) {
124                 return -1;
125         }
126         if (d1->data != NULL && d2->data == NULL) {
127                 return 1;
128         }
129         if (d1->data == d2->data) {
130                 return d1->length - d2->length;
131         }
132         ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
133         if (ret == 0) {
134                 return d1->length - d2->length;
135         }
136         return ret;
137 }
138
139 /**
140 print the data_blob as hex string
141 **/
142 _PUBLIC_ char *data_blob_hex_string_lower(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
143 {
144         unsigned int i;
145         char *hex_string;
146
147         hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
148         if (!hex_string) {
149                 return NULL;
150         }
151
152         /* this must be lowercase or w2k8 cannot join a samba domain,
153            as this routine is used to encode extended DNs and windows
154            only accepts lowercase hexadecimal numbers */
155         for (i = 0; i < blob->length; i++)
156                 slprintf(&hex_string[i*2], 3, "%02x", blob->data[i]);
157
158         hex_string[(blob->length*2)] = '\0';
159         return hex_string;
160 }
161
162 _PUBLIC_ char *data_blob_hex_string_upper(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
163 {
164         unsigned int i;
165         char *hex_string;
166
167         hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
168         if (!hex_string) {
169                 return NULL;
170         }
171
172         for (i = 0; i < blob->length; i++)
173                 slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
174
175         hex_string[(blob->length*2)] = '\0';
176         return hex_string;
177 }
178
179 /**
180   useful for constructing data blobs in test suites, while
181   avoiding const warnings
182 **/
183 _PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
184 {
185         DATA_BLOB blob;
186         blob.data = discard_const_p(uint8_t, str);
187         blob.length = str ? strlen(str) : 0;
188         return blob;
189 }
190
191 /**
192   useful for constructing data blobs in test suites, while
193   avoiding const warnings
194 **/
195 _PUBLIC_ DATA_BLOB data_blob_string_const_null(const char *str)
196 {
197         DATA_BLOB blob;
198         blob.data = discard_const_p(uint8_t, str);
199         blob.length = str ? strlen(str)+1 : 0;
200         return blob;
201 }
202
203 /**
204  * Create a new data blob from const data 
205  */
206
207 _PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
208 {
209         DATA_BLOB blob;
210         blob.data = discard_const_p(uint8_t, p);
211         blob.length = length;
212         return blob;
213 }
214
215
216 /**
217   realloc a data_blob
218 **/
219 _PUBLIC_ bool data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
220 {
221         blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, length);
222         if (blob->data == NULL)
223                 return false;
224         blob->length = length;
225         return true;
226 }
227
228
229 /**
230   append some data to a data blob
231 **/
232 _PUBLIC_ bool data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
233                                    const void *p, size_t length)
234 {
235         size_t old_len = blob->length;
236         size_t new_len = old_len + length;
237         if (new_len < length || new_len < old_len) {
238                 return false;
239         }
240
241         if ((const uint8_t *)p + length < (const uint8_t *)p) {
242                 return false;
243         }
244         
245         if (!data_blob_realloc(mem_ctx, blob, new_len)) {
246                 return false;
247         }
248
249         memcpy(blob->data + old_len, p, length);
250         return true;
251 }
252