2 * Unix SMB/CIFS implementation.
5 * http://msdn.microsoft.com/en-us/library/cc232006%28v=PROT.13%29.aspx
7 * Copyright (C) Volker Lendecke 2011
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.
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.
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/>.
24 #include "reparse_symlink.h"
25 #include "lib/util/charset/charset.h"
26 #include "lib/util/byteorder.h"
27 #include "libcli/smb/smb_constants.h"
28 #include "libcli/smb/smb_util.h"
29 #include "lib/util/debug.h"
31 ssize_t reparse_buffer_marshall(
34 const struct iovec *iov,
39 ssize_t reparse_data_length = iov_buflen(iov, iovlen);
42 if (reparse_data_length == -1) {
45 if (reparse_data_length > UINT16_MAX) {
49 needed = reparse_data_length + 8;
50 if (needed < reparse_data_length) {
54 if (buflen >= needed) {
55 PUSH_LE_U32(buf, 0, reparse_tag);
56 PUSH_LE_U16(buf, 4, reparse_data_length);
57 PUSH_LE_U16(buf, 6, reserved);
58 iov_buf(iov, iovlen, buf+8, buflen-8);
64 bool symlink_reparse_buffer_marshall(
65 const char *substitute,
66 const char *printname,
67 uint16_t unparsed_path_length,
77 uint8_t *subst_utf16 = NULL;
78 uint8_t *print_utf16 = NULL;
84 if (substitute == NULL) {
87 if (printname == NULL) {
88 printname = substitute;
91 iov[0] = (struct iovec) { .iov_base = sbuf, .iov_len = sizeof(sbuf), };
93 ok = convert_string_talloc(
104 if (subst_len > UINT16_MAX) {
107 iov[1] = (struct iovec) {
108 .iov_base = subst_utf16, .iov_len = subst_len,
111 ok = convert_string_talloc(
122 if (print_len > UINT16_MAX) {
125 iov[2] = (struct iovec) {
126 .iov_base = print_utf16, .iov_len = print_len,
129 PUSH_LE_U16(sbuf, 0, 0); /* SubstituteNameOffset */
130 PUSH_LE_U16(sbuf, 2, subst_len); /* SubstituteNameLength */
131 PUSH_LE_U16(sbuf, 4, subst_len); /* PrintNameOffset */
132 PUSH_LE_U16(sbuf, 6, print_len); /* PrintNameLength */
133 PUSH_LE_U32(sbuf, 8, flags); /* Flags */
135 dst_len = reparse_buffer_marshall(
136 IO_REPARSE_TAG_SYMLINK,
137 unparsed_path_length,
146 dst = talloc_array(mem_ctx, uint8_t, dst_len);
151 reparse_buffer_marshall(
152 IO_REPARSE_TAG_SYMLINK,
153 unparsed_path_length,
164 TALLOC_FREE(subst_utf16);
165 TALLOC_FREE(print_utf16);
169 struct symlink_reparse_struct *symlink_reparse_buffer_parse(
170 TALLOC_CTX *mem_ctx, const uint8_t *src, size_t srclen)
172 struct symlink_reparse_struct *result = NULL;
173 uint16_t reparse_data_length;
174 uint16_t substitute_name_offset, substitute_name_length;
175 uint16_t print_name_offset, print_name_length;
179 DBG_DEBUG("srclen = %zu, expected >= 20\n", srclen);
182 if (IVAL(src, 0) != IO_REPARSE_TAG_SYMLINK) {
183 DBG_DEBUG("Got ReparseTag %8.8x, expected %8.8x\n",
185 IO_REPARSE_TAG_SYMLINK);
189 reparse_data_length = SVAL(src, 4);
190 substitute_name_offset = SVAL(src, 8);
191 substitute_name_length = SVAL(src, 10);
192 print_name_offset = SVAL(src, 12);
193 print_name_length = SVAL(src, 14);
195 if (reparse_data_length < 12) {
196 DBG_DEBUG("reparse_data_length = %"PRIu16", expected >= 12\n",
197 reparse_data_length);
200 if (smb_buffer_oob(srclen - 8, reparse_data_length, 0)) {
201 DBG_DEBUG("reparse_data_length (%"PRIu16") too large for "
207 if (smb_buffer_oob(reparse_data_length - 12, substitute_name_offset,
208 substitute_name_length)) {
209 DBG_DEBUG("substitute_name (%"PRIu16"/%"PRIu16") does not fit "
210 "in reparse_data_length (%"PRIu16")\n",
211 substitute_name_offset,
212 substitute_name_length,
213 reparse_data_length - 12);
216 if (smb_buffer_oob(reparse_data_length - 12, print_name_offset,
217 print_name_length)) {
218 DBG_DEBUG("print_name (%"PRIu16"/%"PRIu16") does not fit in "
219 "reparse_data_length (%"PRIu16")\n",
222 reparse_data_length - 12);
226 result = talloc_zero(mem_ctx, struct symlink_reparse_struct);
227 if (result == NULL) {
228 DBG_DEBUG("talloc failed\n");
232 ok = convert_string_talloc(
236 src + 20 + substitute_name_offset,
237 substitute_name_length,
238 &result->substitute_name,
241 DBG_DEBUG("convert_string_talloc for substitute_name "
246 ok = convert_string_talloc(
250 src + 20 + print_name_offset,
255 DBG_DEBUG("convert_string_talloc for print_name failed\n");
259 result->unparsed_path_length = SVAL(src, 6);
260 result->flags = IVAL(src, 16);