2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2014
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.
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.
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/>.
21 #include "../libcli/smb/smb_common.h"
22 #include "libcli/smb/smb2_negotiate_context.h"
24 static size_t smb2_negotiate_context_padding(uint32_t offset
, size_t n
)
26 if ((offset
& (n
-1)) == 0) return 0;
27 return n
- (offset
& (n
-1));
31 parse a set of SMB2 create contexts
33 NTSTATUS
smb2_negotiate_context_parse(TALLOC_CTX
*mem_ctx
, const DATA_BLOB buffer
,
34 struct smb2_negotiate_contexts
*contexts
)
36 const uint8_t *data
= buffer
.data
;
37 uint32_t remaining
= buffer
.length
;
48 return NT_STATUS_INVALID_PARAMETER
;
50 type
= SVAL(data
, 0x00);
51 data_length
= SVAL(data
, 0x02);
53 reserved
= IVAL(data
, 0x04);
56 next_offset
= 0x08 + data_length
;
57 if (remaining
< next_offset
) {
58 return NT_STATUS_INVALID_PARAMETER
;
61 b
= data_blob_const(data
+0x08, data_length
);
62 status
= smb2_negotiate_context_add(mem_ctx
, contexts
, type
, b
);
63 if (!NT_STATUS_IS_OK(status
)) {
67 remaining
-= next_offset
;
74 pad
= smb2_negotiate_context_padding(next_offset
, 8);
75 if (remaining
< pad
) {
76 return NT_STATUS_INVALID_PARAMETER
;
86 add a context to a smb2_negotiate attribute context
88 static NTSTATUS
smb2_negotiate_context_push_one(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*buffer
,
89 const struct smb2_negotiate_context
*context
,
92 uint32_t ofs
= buffer
->length
;
93 size_t next_offset
= 0;
97 if (context
->data
.length
> UINT16_MAX
) {
98 return NT_STATUS_INVALID_PARAMETER_MIX
;
101 next_offset
= 0x08 + context
->data
.length
;
103 next_pad
= smb2_negotiate_context_padding(next_offset
, 8);
106 ok
= data_blob_realloc(mem_ctx
, buffer
,
107 buffer
->length
+ next_offset
+ next_pad
);
109 return NT_STATUS_NO_MEMORY
;
112 SSVAL(buffer
->data
, ofs
+0x00, context
->type
);
113 SIVAL(buffer
->data
, ofs
+0x02, context
->data
.length
);
114 SIVAL(buffer
->data
, ofs
+0x04, 0);
115 memcpy(buffer
->data
+ofs
+0x08, context
->data
.data
, context
->data
.length
);
117 memset(buffer
->data
+ofs
+next_offset
, 0, next_pad
);
118 next_offset
+= next_pad
;
125 create a buffer of a set of create contexts
127 NTSTATUS
smb2_negotiate_context_push(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*buffer
,
128 const struct smb2_negotiate_contexts contexts
)
133 *buffer
= data_blob(NULL
, 0);
134 for (i
=0; i
< contexts
.num_contexts
; i
++) {
136 const struct smb2_negotiate_context
*c
;
138 if ((i
+ 1) == contexts
.num_contexts
) {
142 c
= &contexts
.contexts
[i
];
143 status
= smb2_negotiate_context_push_one(mem_ctx
, buffer
, c
, last
);
144 if (!NT_STATUS_IS_OK(status
)) {
151 NTSTATUS
smb2_negotiate_context_add(TALLOC_CTX
*mem_ctx
, struct smb2_negotiate_contexts
*c
,
152 uint16_t type
, DATA_BLOB data
)
154 struct smb2_negotiate_context
*array
;
156 array
= talloc_realloc(mem_ctx
, c
->contexts
,
157 struct smb2_negotiate_context
,
158 c
->num_contexts
+ 1);
159 NT_STATUS_HAVE_NO_MEMORY(array
);
162 c
->contexts
[c
->num_contexts
].type
= type
;
165 c
->contexts
[c
->num_contexts
].data
= data_blob_talloc(c
->contexts
,
168 NT_STATUS_HAVE_NO_MEMORY(c
->contexts
[c
->num_contexts
].data
.data
);
170 c
->contexts
[c
->num_contexts
].data
= data_blob_null
;
173 c
->num_contexts
+= 1;
179 * return the first blob with the given tag
181 struct smb2_negotiate_context
*smb2_negotiate_context_find(const struct smb2_negotiate_contexts
*c
,
186 for (i
=0; i
< c
->num_contexts
; i
++) {
187 if (c
->contexts
[i
].type
== type
) {
188 return &c
->contexts
[i
];