Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2014
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/smb/smb_common.h"
22 : #include "libcli/smb/smb2_negotiate_context.h"
23 :
24 264515 : static size_t smb2_negotiate_context_padding(uint32_t offset, size_t n)
25 : {
26 264515 : if ((offset & (n-1)) == 0) return 0;
27 217123 : return n - (offset & (n-1));
28 : }
29 :
30 : /*
31 : parse a set of SMB2 create contexts
32 : */
33 45807 : NTSTATUS smb2_negotiate_context_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
34 : uint16_t expected_count,
35 : struct smb2_negotiate_contexts *contexts)
36 : {
37 45807 : const uint8_t *data = buffer.data;
38 45807 : uint32_t remaining = buffer.length;
39 1366 : uint16_t idx;
40 :
41 174550 : for (idx = 0; idx < expected_count; idx++) {
42 4803 : uint16_t data_length;
43 4803 : uint16_t type;
44 4803 : NTSTATUS status;
45 4803 : size_t pad;
46 4803 : uint32_t next_offset;
47 :
48 174550 : if (remaining < 8) {
49 0 : return NT_STATUS_INVALID_PARAMETER;
50 : }
51 174550 : type = SVAL(data, 0x00);
52 174550 : data_length = SVAL(data, 0x02);
53 : #if 0
54 : reserved = IVAL(data, 0x04);
55 : #endif
56 :
57 174550 : next_offset = 0x08 + data_length;
58 174550 : if (remaining < next_offset) {
59 0 : return NT_STATUS_INVALID_PARAMETER;
60 : }
61 :
62 174550 : status = smb2_negotiate_context_add(
63 : mem_ctx, contexts, type, data+0x08, data_length);
64 174550 : if (!NT_STATUS_IS_OK(status)) {
65 0 : return status;
66 : }
67 :
68 174550 : if (contexts->num_contexts == expected_count) {
69 44441 : break;
70 : }
71 :
72 128743 : remaining -= next_offset;
73 128743 : data += next_offset;
74 :
75 128743 : if (remaining == 0) {
76 0 : break;
77 : }
78 :
79 128743 : pad = smb2_negotiate_context_padding(next_offset, 8);
80 128743 : if (remaining < pad) {
81 0 : return NT_STATUS_INVALID_PARAMETER;
82 : }
83 128743 : remaining -= pad;
84 128743 : data += pad;
85 : }
86 :
87 45807 : if (contexts->num_contexts != expected_count) {
88 0 : return NT_STATUS_INVALID_PARAMETER;
89 : }
90 :
91 45807 : return NT_STATUS_OK;
92 : }
93 :
94 : /*
95 : add a context to a smb2_negotiate attribute context
96 : */
97 184250 : static NTSTATUS smb2_negotiate_context_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
98 : const struct smb2_negotiate_context *context,
99 : bool last)
100 : {
101 184250 : uint32_t ofs = buffer->length;
102 184250 : size_t next_offset = 0;
103 184250 : size_t next_pad = 0;
104 4759 : bool ok;
105 :
106 184250 : if (context->data.length > UINT16_MAX) {
107 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
108 : }
109 :
110 184250 : next_offset = 0x08 + context->data.length;
111 184250 : if (!last) {
112 135772 : next_pad = smb2_negotiate_context_padding(next_offset, 8);
113 : }
114 :
115 189009 : ok = data_blob_realloc(mem_ctx, buffer,
116 184250 : buffer->length + next_offset + next_pad);
117 184250 : if (!ok) {
118 0 : return NT_STATUS_NO_MEMORY;
119 : }
120 :
121 184250 : SSVAL(buffer->data, ofs+0x00, context->type);
122 184250 : SIVAL(buffer->data, ofs+0x02, context->data.length);
123 184250 : SIVAL(buffer->data, ofs+0x04, 0);
124 184250 : memcpy(buffer->data+ofs+0x08, context->data.data, context->data.length);
125 184250 : if (next_pad > 0) {
126 111240 : memset(buffer->data+ofs+next_offset, 0, next_pad);
127 : }
128 :
129 184250 : return NT_STATUS_OK;
130 : }
131 :
132 : /*
133 : create a buffer of a set of create contexts
134 : */
135 48478 : NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
136 : const struct smb2_negotiate_contexts contexts)
137 : {
138 1366 : uint32_t i;
139 1366 : NTSTATUS status;
140 :
141 48478 : *buffer = data_blob(NULL, 0);
142 234094 : for (i=0; i < contexts.num_contexts; i++) {
143 184250 : bool last = false;
144 4759 : const struct smb2_negotiate_context *c;
145 :
146 184250 : if ((i + 1) == contexts.num_contexts) {
147 48478 : last = true;
148 : }
149 :
150 184250 : c = &contexts.contexts[i];
151 184250 : status = smb2_negotiate_context_push_one(mem_ctx, buffer, c, last);
152 184250 : if (!NT_STATUS_IS_OK(status)) {
153 0 : return status;
154 : }
155 : }
156 48478 : return NT_STATUS_OK;
157 : }
158 :
159 370969 : NTSTATUS smb2_negotiate_context_add(TALLOC_CTX *mem_ctx,
160 : struct smb2_negotiate_contexts *c,
161 : uint16_t type,
162 : const uint8_t *buf,
163 : size_t buflen)
164 : {
165 9562 : struct smb2_negotiate_context *array;
166 :
167 370969 : array = talloc_realloc(mem_ctx, c->contexts,
168 : struct smb2_negotiate_context,
169 : c->num_contexts + 1);
170 370969 : NT_STATUS_HAVE_NO_MEMORY(array);
171 370969 : c->contexts = array;
172 :
173 370969 : c->contexts[c->num_contexts].type = type;
174 :
175 370969 : if (buf != NULL) {
176 370969 : c->contexts[c->num_contexts].data = data_blob_talloc(
177 : c->contexts, buf, buflen);
178 370969 : NT_STATUS_HAVE_NO_MEMORY(c->contexts[c->num_contexts].data.data);
179 : } else {
180 0 : c->contexts[c->num_contexts].data = data_blob_null;
181 : }
182 :
183 370969 : c->num_contexts += 1;
184 :
185 370969 : return NT_STATUS_OK;
186 : }
187 :
188 : /*
189 : * return the first blob with the given tag
190 : */
191 225596 : struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *c,
192 : uint16_t type)
193 : {
194 6073 : uint32_t i;
195 :
196 461878 : for (i=0; i < c->num_contexts; i++) {
197 384787 : if (c->contexts[i].type == type) {
198 148505 : return &c->contexts[i];
199 : }
200 : }
201 :
202 75116 : return NULL;
203 : }
|