python: models: rename argument ldb to samdb
[samba.git] / source3 / modules / util_reparse.c
blob6f47367a4b8cd2625365952272b3c249d5d1667a
1 /*
2 * Unix SMB/CIFS implementation.
3 * Utility functions for reparse points.
5 * Copyright (C) Jeremy Allison 2018
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "util_reparse.h"
23 #include "libcli/smb/reparse.h"
24 #include "source3/smbd/proto.h"
26 static NTSTATUS fsctl_get_reparse_point_reg(struct files_struct *fsp,
27 TALLOC_CTX *ctx,
28 uint8_t **_out_data,
29 uint32_t max_out_len,
30 uint32_t *_out_len)
32 uint8_t *val = NULL;
33 ssize_t sizeret;
34 NTSTATUS status;
37 * 64k+8 bytes is the maximum reparse point length
38 * possible
41 val = talloc_array(ctx, uint8_t, MIN(max_out_len, 65536 + 8));
42 if (val == NULL) {
43 return NT_STATUS_NO_MEMORY;
46 sizeret = SMB_VFS_FGETXATTR(fsp,
47 SAMBA_XATTR_REPARSE_ATTRIB,
48 val,
49 talloc_get_size(val));
51 if ((sizeret == -1) && (errno == ERANGE)) {
52 status = NT_STATUS_BUFFER_TOO_SMALL;
53 goto fail;
56 if ((sizeret == -1) && (errno == ENOATTR)) {
57 DBG_DEBUG(SAMBA_XATTR_REPARSE_ATTRIB " does not exist\n");
58 status = NT_STATUS_NOT_A_REPARSE_POINT;
59 goto fail;
62 if (sizeret == -1) {
63 status = map_nt_error_from_unix(errno);
64 DBG_DEBUG("SMB_VFS_FGETXATTR failed: %s\n", strerror(errno));
65 goto fail;
68 *_out_data = val;
69 *_out_len = sizeret;
70 return NT_STATUS_OK;
71 fail:
72 TALLOC_FREE(val);
73 return status;
76 NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
77 TALLOC_CTX *mem_ctx,
78 uint32_t *_reparse_tag,
79 uint8_t **_out_data,
80 uint32_t max_out_len,
81 uint32_t *_out_len)
83 uint32_t dos_mode;
84 uint8_t *out_data = NULL;
85 uint32_t out_len = 0;
86 uint32_t reparse_tag = 0;
87 const uint8_t *reparse_data = NULL;
88 size_t reparse_data_length;
89 NTSTATUS status = NT_STATUS_NOT_A_REPARSE_POINT;
91 dos_mode = fdos_mode(fsp);
92 if ((dos_mode & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
93 return NT_STATUS_NOT_A_REPARSE_POINT;
96 if (S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
97 DBG_DEBUG("%s is a regular file\n", fsp_str_dbg(fsp));
98 status = fsctl_get_reparse_point_reg(
99 fsp, mem_ctx, &out_data, max_out_len, &out_len);
102 if (!NT_STATUS_IS_OK(status)) {
103 return status;
106 status = reparse_buffer_check(out_data,
107 out_len,
108 &reparse_tag,
109 &reparse_data,
110 &reparse_data_length);
111 if (!NT_STATUS_IS_OK(status)) {
112 DBG_DEBUG("Invalid reparse data: %s\n", nt_errstr(status));
113 TALLOC_FREE(out_data);
114 return status;
117 *_reparse_tag = reparse_tag;
118 *_out_data = out_data;
119 *_out_len = out_len;
121 return NT_STATUS_OK;
124 NTSTATUS fsctl_set_reparse_point(struct files_struct *fsp,
125 TALLOC_CTX *mem_ctx,
126 const uint8_t *in_data,
127 uint32_t in_len)
129 uint32_t reparse_tag;
130 const uint8_t *reparse_data = NULL;
131 size_t reparse_data_length;
132 uint32_t existing_tag;
133 uint8_t *existing_data = NULL;
134 uint32_t existing_len;
135 NTSTATUS status;
136 uint32_t dos_mode;
137 int ret;
139 DBG_DEBUG("Called on %s\n", fsp_str_dbg(fsp));
141 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
142 DBG_DEBUG("Can only set reparse point for regular files\n");
143 return NT_STATUS_ACCESS_DENIED;
146 status = reparse_buffer_check(in_data,
147 in_len,
148 &reparse_tag,
149 &reparse_data,
150 &reparse_data_length);
151 if (!NT_STATUS_IS_OK(status)) {
152 DBG_DEBUG("check_reparse_data_buffer failed: %s\n",
153 nt_errstr(status));
154 return status;
157 DBG_DEBUG("reparse tag=%" PRIX32 ", length=%zu\n",
158 reparse_tag,
159 reparse_data_length);
161 status = fsctl_get_reparse_point(fsp,
162 talloc_tos(),
163 &existing_tag,
164 &existing_data,
165 UINT32_MAX,
166 &existing_len);
167 if (NT_STATUS_IS_OK(status)) {
169 TALLOC_FREE(existing_data);
171 if (existing_tag != reparse_tag) {
172 DBG_DEBUG("Can't overwrite tag %" PRIX32
173 " with tag %" PRIX32 "\n",
174 existing_tag,
175 reparse_tag);
176 return NT_STATUS_IO_REPARSE_TAG_MISMATCH;
180 /* Store the data */
181 ret = SMB_VFS_FSETXATTR(
182 fsp, SAMBA_XATTR_REPARSE_ATTRIB, in_data, in_len, 0);
183 if (ret == -1) {
184 status = map_nt_error_from_unix(errno);
185 DBG_DEBUG("setxattr fail on %s - %s\n",
186 fsp_str_dbg(fsp),
187 strerror(errno));
188 return status;
192 * Files with reparse points don't have the ATTR_NORMAL bit
193 * set
195 dos_mode = fdos_mode(fsp);
196 dos_mode &= ~FILE_ATTRIBUTE_NORMAL;
197 dos_mode |= FILE_ATTRIBUTE_REPARSE_POINT;
199 status = SMB_VFS_FSET_DOS_ATTRIBUTES(fsp->conn, fsp, dos_mode);
201 if (!NT_STATUS_IS_OK(status)) {
202 DBG_ERR("set reparse attr fail on %s - %s\n",
203 fsp_str_dbg(fsp),
204 nt_errstr(status));
205 return status;
208 return NT_STATUS_OK;
211 NTSTATUS fsctl_del_reparse_point(struct files_struct *fsp,
212 TALLOC_CTX *mem_ctx,
213 const uint8_t *in_data,
214 uint32_t in_len)
216 uint32_t existing_tag;
217 uint8_t *existing_data = NULL;
218 uint32_t existing_len;
219 uint32_t reparse_tag;
220 const uint8_t *reparse_data = NULL;
221 size_t reparse_data_length;
222 NTSTATUS status;
223 uint32_t dos_mode;
224 int ret;
226 status = fsctl_get_reparse_point(fsp,
227 talloc_tos(),
228 &existing_tag,
229 &existing_data,
230 UINT32_MAX,
231 &existing_len);
232 if (!NT_STATUS_IS_OK(status)) {
233 return status;
235 TALLOC_FREE(existing_data);
237 status = reparse_buffer_check(in_data,
238 in_len,
239 &reparse_tag,
240 &reparse_data,
241 &reparse_data_length);
242 if (!NT_STATUS_IS_OK(status)) {
243 return status;
245 if (reparse_data_length != 0) {
246 return NT_STATUS_IO_REPARSE_DATA_INVALID;
249 if (existing_tag != reparse_tag) {
250 DBG_DEBUG("Expect correct tag %" PRIX32 ", got tag %" PRIX32
251 "\n",
252 existing_tag,
253 reparse_tag);
254 return NT_STATUS_IO_REPARSE_TAG_MISMATCH;
257 ret = SMB_VFS_FREMOVEXATTR(fsp, SAMBA_XATTR_REPARSE_ATTRIB);
258 if (ret == -1) {
259 status = map_nt_error_from_unix(errno);
260 DBG_DEBUG("removexattr fail on %s - %s\n",
261 fsp_str_dbg(fsp),
262 strerror(errno));
263 return status;
267 * Files with reparse points don't have the ATTR_NORMAL bit
268 * set
270 dos_mode = fdos_mode(fsp);
271 dos_mode &= ~FILE_ATTRIBUTE_REPARSE_POINT;
273 status = SMB_VFS_FSET_DOS_ATTRIBUTES(fsp->conn, fsp, dos_mode);
275 if (!NT_STATUS_IS_OK(status)) {
276 DBG_ERR("set reparse attr fail on %s - %s\n",
277 fsp_str_dbg(fsp),
278 nt_errstr(status));
279 return status;
282 return NT_STATUS_OK;