libsmbclient: Read the file type from the server with posix enabled
[Samba.git] / libcli / smb / smb2_negotiate_context.c
blob9ec20bc93d04d21ac76b84f9dbbafd2dda75f276
1 /*
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/>.
20 #include "includes.h"
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 uint16_t expected_count,
35 struct smb2_negotiate_contexts *contexts)
37 const uint8_t *data = buffer.data;
38 uint32_t remaining = buffer.length;
39 uint16_t idx;
41 for (idx = 0; idx < expected_count; idx++) {
42 uint16_t data_length;
43 uint16_t type;
44 NTSTATUS status;
45 size_t pad;
46 uint32_t next_offset;
48 if (remaining < 8) {
49 return NT_STATUS_INVALID_PARAMETER;
51 type = SVAL(data, 0x00);
52 data_length = SVAL(data, 0x02);
53 #if 0
54 reserved = IVAL(data, 0x04);
55 #endif
57 next_offset = 0x08 + data_length;
58 if (remaining < next_offset) {
59 return NT_STATUS_INVALID_PARAMETER;
62 status = smb2_negotiate_context_add(
63 mem_ctx, contexts, type, data+0x08, data_length);
64 if (!NT_STATUS_IS_OK(status)) {
65 return status;
68 if (contexts->num_contexts == expected_count) {
69 break;
72 remaining -= next_offset;
73 data += next_offset;
75 if (remaining == 0) {
76 break;
79 pad = smb2_negotiate_context_padding(next_offset, 8);
80 if (remaining < pad) {
81 return NT_STATUS_INVALID_PARAMETER;
83 remaining -= pad;
84 data += pad;
87 if (contexts->num_contexts != expected_count) {
88 return NT_STATUS_INVALID_PARAMETER;
91 return NT_STATUS_OK;
95 add a context to a smb2_negotiate attribute context
97 static NTSTATUS smb2_negotiate_context_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
98 const struct smb2_negotiate_context *context,
99 bool last)
101 uint32_t ofs = buffer->length;
102 size_t next_offset = 0;
103 size_t next_pad = 0;
104 bool ok;
106 if (context->data.length > UINT16_MAX) {
107 return NT_STATUS_INVALID_PARAMETER_MIX;
110 next_offset = 0x08 + context->data.length;
111 if (!last) {
112 next_pad = smb2_negotiate_context_padding(next_offset, 8);
115 ok = data_blob_realloc(mem_ctx, buffer,
116 buffer->length + next_offset + next_pad);
117 if (!ok) {
118 return NT_STATUS_NO_MEMORY;
121 SSVAL(buffer->data, ofs+0x00, context->type);
122 SIVAL(buffer->data, ofs+0x02, context->data.length);
123 SIVAL(buffer->data, ofs+0x04, 0);
124 memcpy(buffer->data+ofs+0x08, context->data.data, context->data.length);
125 if (next_pad > 0) {
126 memset(buffer->data+ofs+next_offset, 0, next_pad);
129 return NT_STATUS_OK;
133 create a buffer of a set of create contexts
135 NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
136 const struct smb2_negotiate_contexts contexts)
138 uint32_t i;
139 NTSTATUS status;
141 *buffer = data_blob(NULL, 0);
142 for (i=0; i < contexts.num_contexts; i++) {
143 bool last = false;
144 const struct smb2_negotiate_context *c;
146 if ((i + 1) == contexts.num_contexts) {
147 last = true;
150 c = &contexts.contexts[i];
151 status = smb2_negotiate_context_push_one(mem_ctx, buffer, c, last);
152 if (!NT_STATUS_IS_OK(status)) {
153 return status;
156 return NT_STATUS_OK;
159 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)
165 struct smb2_negotiate_context *array;
167 array = talloc_realloc(mem_ctx, c->contexts,
168 struct smb2_negotiate_context,
169 c->num_contexts + 1);
170 NT_STATUS_HAVE_NO_MEMORY(array);
171 c->contexts = array;
173 c->contexts[c->num_contexts].type = type;
175 if (buf != NULL) {
176 c->contexts[c->num_contexts].data = data_blob_talloc(
177 c->contexts, buf, buflen);
178 NT_STATUS_HAVE_NO_MEMORY(c->contexts[c->num_contexts].data.data);
179 } else {
180 c->contexts[c->num_contexts].data = data_blob_null;
183 c->num_contexts += 1;
185 return NT_STATUS_OK;
189 * return the first blob with the given tag
191 struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *c,
192 uint16_t type)
194 uint32_t i;
196 for (i=0; i < c->num_contexts; i++) {
197 if (c->contexts[i].type == type) {
198 return &c->contexts[i];
202 return NULL;