ctdb-tests: Avoid a race
[samba.git] / libcli / smb / reparse_symlink.c
blobc06195f324c0666d22f8d4a918983a7934c668f8
1 /*
2 * Unix SMB/CIFS implementation.
4 * Implementation of
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/>.
23 #include "replace.h"
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 bool symlink_reparse_buffer_marshall(
32 const char *substitute, const char *printname, uint32_t flags,
33 TALLOC_CTX *mem_ctx, uint8_t **pdst, size_t *pdstlen)
35 uint8_t *dst = NULL;
36 size_t dst_len;
37 uint8_t *subst_utf16 = NULL;
38 uint8_t *print_utf16 = NULL;
39 size_t subst_len = 0;
40 size_t print_len = 0;
41 bool ret = false;
42 bool ok;
44 if (substitute == NULL) {
45 return false;
47 if (printname == NULL) {
48 printname = substitute;
51 ok = convert_string_talloc(
52 mem_ctx,
53 CH_UNIX,
54 CH_UTF16,
55 substitute,
56 strlen(substitute),
57 &subst_utf16,
58 &subst_len);
59 if (!ok) {
60 goto fail;
63 ok = convert_string_talloc(
64 mem_ctx,
65 CH_UNIX,
66 CH_UTF16,
67 printname,
68 strlen(printname),
69 &print_utf16,
70 &print_len);
71 if (!ok) {
72 goto fail;
75 dst_len = subst_len + 20;
76 if (dst_len < 20) {
77 goto fail;
79 dst_len += print_len;
80 if (dst_len < print_len) {
81 goto fail;
83 dst = talloc_array(mem_ctx, uint8_t, dst_len);
84 if (dst == NULL) {
85 goto fail;
88 SIVAL(dst, 0, IO_REPARSE_TAG_SYMLINK); /* ReparseTag */
89 SSVAL(dst, 4, 12 + subst_len + print_len); /* ReparseDataLength */
90 SSVAL(dst, 6, 0); /* Reserved */
91 SSVAL(dst, 8, 0); /* SubstituteNameOffset */
92 SSVAL(dst, 10, subst_len); /* SubstituteNameLength */
93 SSVAL(dst, 12, subst_len); /* PrintNameOffset */
94 SSVAL(dst, 14, print_len); /* PrintNameLength */
95 SIVAL(dst, 16, flags); /* Flags */
97 if ((subst_utf16 != NULL) && (subst_len != 0)) {
98 memcpy(dst + 20, subst_utf16, subst_len);
101 if ((print_utf16 != NULL) && (print_len != 0)) {
102 memcpy(dst + 20 + subst_len, print_utf16, print_len);
105 *pdst = dst;
106 *pdstlen = dst_len;
107 ret = true;
109 fail:
110 TALLOC_FREE(subst_utf16);
111 TALLOC_FREE(print_utf16);
112 return ret;
115 struct symlink_reparse_struct *symlink_reparse_buffer_parse(
116 TALLOC_CTX *mem_ctx, const uint8_t *src, size_t srclen)
118 struct symlink_reparse_struct *result = NULL;
119 uint16_t reparse_data_length;
120 uint16_t substitute_name_offset, substitute_name_length;
121 uint16_t print_name_offset, print_name_length;
122 bool ok;
124 if (srclen < 20) {
125 DEBUG(10, ("srclen = %d, expected >= 20\n", (int)srclen));
126 goto fail;
128 if (IVAL(src, 0) != IO_REPARSE_TAG_SYMLINK) {
129 DEBUG(10, ("Got ReparseTag %8.8x, expected %8.8x\n",
130 IVAL(src, 0), IO_REPARSE_TAG_SYMLINK));
131 goto fail;
134 reparse_data_length = SVAL(src, 4);
135 substitute_name_offset = SVAL(src, 8);
136 substitute_name_length = SVAL(src, 10);
137 print_name_offset = SVAL(src, 12);
138 print_name_length = SVAL(src, 14);
140 if (reparse_data_length < 12) {
141 DEBUG(10, ("reparse_data_length = %d, expected >= 12\n",
142 (int)reparse_data_length));
143 goto fail;
145 if (smb_buffer_oob(srclen - 8, reparse_data_length, 0)) {
146 DEBUG(10, ("reparse_data_length (%d) too large for "
147 "src_len (%d)\n", (int)reparse_data_length,
148 (int)srclen));
149 goto fail;
151 if (smb_buffer_oob(reparse_data_length - 12, substitute_name_offset,
152 substitute_name_length)) {
153 DEBUG(10, ("substitute_name (%d/%d) does not fit in "
154 "reparse_data_length (%d)\n",
155 (int)substitute_name_offset,
156 (int)substitute_name_length,
157 (int)reparse_data_length - 12));
158 goto fail;
160 if (smb_buffer_oob(reparse_data_length - 12, print_name_offset,
161 print_name_length)) {
162 DEBUG(10, ("print_name (%d/%d) does not fit in "
163 "reparse_data_length (%d)\n",
164 (int)print_name_offset,
165 (int)print_name_length,
166 (int)reparse_data_length - 12));
167 goto fail;
170 result = talloc_zero(mem_ctx, struct symlink_reparse_struct);
171 if (result == NULL) {
172 DBG_DEBUG("talloc failed\n");
173 goto fail;
176 ok = convert_string_talloc(
177 result,
178 CH_UTF16,
179 CH_UNIX,
180 src + 20 + substitute_name_offset,
181 substitute_name_length,
182 &result->substitute_name,
183 NULL);
184 if (!ok) {
185 DEBUG(10, ("convert_string_talloc for substitute_name "
186 "failed\n"));
187 goto fail;
190 ok = convert_string_talloc(
191 result,
192 CH_UTF16,
193 CH_UNIX,
194 src + 20 + print_name_offset,
195 print_name_length,
196 &result->print_name,
197 NULL);
198 if (!ok) {
199 DEBUG(10, ("convert_string_talloc for print_name "
200 "failed\n"));
201 goto fail;
204 result->unparsed_path_length = SVAL(src, 6);
205 result->flags = IVAL(src, 16);
207 return result;
208 fail:
209 TALLOC_FREE(result);
210 return NULL;