/src/samba/libcli/smb/smb2_create_blob.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | SMB2 Create Context Blob handling |
5 | | |
6 | | Copyright (C) Andrew Tridgell 2005 |
7 | | Copyright (C) Stefan Metzmacher 2008-2009 |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "includes.h" |
24 | | #include "../libcli/smb/smb_common.h" |
25 | | |
26 | | static size_t smb2_create_blob_padding(uint32_t offset, size_t n) |
27 | 0 | { |
28 | 0 | if ((offset & (n-1)) == 0) return 0; |
29 | 0 | return n - (offset & (n-1)); |
30 | 0 | } |
31 | | |
32 | | /* |
33 | | parse a set of SMB2 create blobs |
34 | | */ |
35 | | NTSTATUS smb2_create_blob_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer, |
36 | | struct smb2_create_blobs *blobs) |
37 | 0 | { |
38 | 0 | const uint8_t *data = buffer.data; |
39 | 0 | uint32_t remaining = buffer.length; |
40 | |
|
41 | 0 | while (remaining > 0) { |
42 | 0 | uint32_t next; |
43 | 0 | uint32_t name_offset, name_length; |
44 | 0 | uint32_t data_offset; |
45 | 0 | uint32_t data_length; |
46 | 0 | char *tag; |
47 | 0 | DATA_BLOB b; |
48 | 0 | NTSTATUS status; |
49 | |
|
50 | 0 | if (remaining < 16) { |
51 | 0 | return NT_STATUS_INVALID_PARAMETER; |
52 | 0 | } |
53 | 0 | next = IVAL(data, 0); |
54 | 0 | name_offset = SVAL(data, 4); |
55 | 0 | name_length = SVAL(data, 6); |
56 | | #if 0 |
57 | | reserved = SVAL(data, 8); |
58 | | #endif |
59 | 0 | data_offset = SVAL(data, 10); |
60 | 0 | data_length = IVAL(data, 12); |
61 | |
|
62 | 0 | if ((next & 0x7) != 0 || |
63 | 0 | next > remaining || |
64 | 0 | name_offset != 16 || |
65 | 0 | name_length < 4 || |
66 | 0 | name_offset + name_length > remaining || |
67 | 0 | (data_offset & 0x7) != 0 || |
68 | 0 | (data_offset && (data_offset < name_offset + name_length)) || |
69 | 0 | (data_offset > remaining) || |
70 | 0 | (data_offset + (uint64_t)data_length > remaining)) { |
71 | 0 | return NT_STATUS_INVALID_PARAMETER; |
72 | 0 | } |
73 | | |
74 | 0 | tag = talloc_strndup(mem_ctx, (const char *)data + name_offset, name_length); |
75 | 0 | if (tag == NULL) { |
76 | 0 | return NT_STATUS_NO_MEMORY; |
77 | 0 | } |
78 | | |
79 | 0 | b = data_blob_const(data+data_offset, data_length); |
80 | 0 | status = smb2_create_blob_add(mem_ctx, blobs, tag, b); |
81 | 0 | if (!NT_STATUS_IS_OK(status)) { |
82 | 0 | return status; |
83 | 0 | } |
84 | | |
85 | 0 | talloc_free(tag); |
86 | |
|
87 | 0 | if (next == 0) break; |
88 | | |
89 | 0 | remaining -= next; |
90 | 0 | data += next; |
91 | |
|
92 | 0 | if (remaining < 16) { |
93 | 0 | return NT_STATUS_INVALID_PARAMETER; |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | 0 | return NT_STATUS_OK; |
98 | 0 | } |
99 | | |
100 | | |
101 | | /* |
102 | | add a blob to a smb2_create attribute blob |
103 | | */ |
104 | | static NTSTATUS smb2_create_blob_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer, |
105 | | const struct smb2_create_blob *blob, |
106 | | bool last) |
107 | 0 | { |
108 | 0 | uint32_t ofs = buffer->length; |
109 | 0 | size_t tag_length = strlen(blob->tag); |
110 | 0 | size_t blob_offset = 0; |
111 | 0 | size_t blob_pad = 0; |
112 | 0 | size_t next_offset = 0; |
113 | 0 | size_t next_pad = 0; |
114 | 0 | bool ok; |
115 | |
|
116 | 0 | blob_offset = 0x10 + tag_length; |
117 | 0 | blob_pad = smb2_create_blob_padding(blob_offset, 8); |
118 | 0 | next_offset = blob_offset + blob_pad + blob->data.length; |
119 | 0 | if (!last) { |
120 | 0 | next_pad = smb2_create_blob_padding(next_offset, 8); |
121 | 0 | } |
122 | |
|
123 | 0 | ok = data_blob_realloc(mem_ctx, buffer, |
124 | 0 | buffer->length + next_offset + next_pad); |
125 | 0 | if (!ok) { |
126 | 0 | return NT_STATUS_NO_MEMORY; |
127 | 0 | } |
128 | | |
129 | 0 | if (last) { |
130 | 0 | SIVAL(buffer->data, ofs+0x00, 0); |
131 | 0 | } else { |
132 | 0 | SIVAL(buffer->data, ofs+0x00, next_offset + next_pad); |
133 | 0 | } |
134 | 0 | SSVAL(buffer->data, ofs+0x04, 0x10); /* offset of tag */ |
135 | 0 | SIVAL(buffer->data, ofs+0x06, tag_length); /* tag length */ |
136 | 0 | SSVAL(buffer->data, ofs+0x0A, blob_offset + blob_pad); /* offset of data */ |
137 | 0 | SIVAL(buffer->data, ofs+0x0C, blob->data.length); |
138 | 0 | memcpy(buffer->data+ofs+0x10, blob->tag, tag_length); |
139 | 0 | if (blob_pad > 0) { |
140 | 0 | memset(buffer->data+ofs+blob_offset, 0, blob_pad); |
141 | 0 | blob_offset += blob_pad; |
142 | 0 | } |
143 | 0 | memcpy(buffer->data+ofs+blob_offset, blob->data.data, blob->data.length); |
144 | 0 | if (next_pad > 0) { |
145 | 0 | memset(buffer->data+ofs+next_offset, 0, next_pad); |
146 | 0 | } |
147 | |
|
148 | 0 | return NT_STATUS_OK; |
149 | 0 | } |
150 | | |
151 | | |
152 | | /* |
153 | | create a buffer of a set of create blobs |
154 | | */ |
155 | | NTSTATUS smb2_create_blob_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer, |
156 | | const struct smb2_create_blobs blobs) |
157 | 0 | { |
158 | 0 | uint32_t i; |
159 | 0 | NTSTATUS status; |
160 | |
|
161 | 0 | *buffer = (DATA_BLOB) { 0 }; |
162 | 0 | for (i=0; i < blobs.num_blobs; i++) { |
163 | 0 | bool last = false; |
164 | 0 | const struct smb2_create_blob *c; |
165 | |
|
166 | 0 | if ((i + 1) == blobs.num_blobs) { |
167 | 0 | last = true; |
168 | 0 | } |
169 | |
|
170 | 0 | c = &blobs.blobs[i]; |
171 | 0 | status = smb2_create_blob_push_one(mem_ctx, buffer, c, last); |
172 | 0 | if (!NT_STATUS_IS_OK(status)) { |
173 | 0 | return status; |
174 | 0 | } |
175 | 0 | } |
176 | 0 | return NT_STATUS_OK; |
177 | 0 | } |
178 | | |
179 | | |
180 | | NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b, |
181 | | const char *tag, DATA_BLOB data) |
182 | 0 | { |
183 | 0 | struct smb2_create_blob *array; |
184 | |
|
185 | 0 | array = talloc_realloc(mem_ctx, b->blobs, |
186 | 0 | struct smb2_create_blob, |
187 | 0 | b->num_blobs + 1); |
188 | 0 | NT_STATUS_HAVE_NO_MEMORY(array); |
189 | 0 | b->blobs = array; |
190 | |
|
191 | 0 | b->blobs[b->num_blobs].tag = talloc_strdup(b->blobs, tag); |
192 | 0 | NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].tag); |
193 | | |
194 | 0 | if (data.data) { |
195 | 0 | b->blobs[b->num_blobs].data = data_blob_talloc(b->blobs, |
196 | 0 | data.data, |
197 | 0 | data.length); |
198 | 0 | NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].data.data); |
199 | 0 | } else { |
200 | 0 | b->blobs[b->num_blobs].data = data_blob_null; |
201 | 0 | } |
202 | | |
203 | 0 | b->num_blobs += 1; |
204 | |
|
205 | 0 | return NT_STATUS_OK; |
206 | 0 | } |
207 | | |
208 | | /* |
209 | | * return the first blob with the given tag |
210 | | */ |
211 | | struct smb2_create_blob *smb2_create_blob_find(const struct smb2_create_blobs *b, |
212 | | const char *tag) |
213 | 0 | { |
214 | 0 | uint32_t i; |
215 | |
|
216 | 0 | if (b == NULL) { |
217 | 0 | return NULL; |
218 | 0 | } |
219 | | |
220 | 0 | for (i=0; i < b->num_blobs; i++) { |
221 | 0 | if (strcmp(b->blobs[i].tag, tag) == 0) { |
222 | 0 | return &b->blobs[i]; |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | 0 | return NULL; |
227 | 0 | } |