2 * Unix SMB/CIFS implementation.
3 * Client implementation of setting symlinks using reparse points
4 * Copyright (C) Volker Lendecke 2011
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 "system/filesys.h"
22 #include "libsmb/libsmb.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "async_smb.h"
25 #include "libsmb/clirap.h"
27 #include "libcli/security/secdesc.h"
28 #include "libcli/security/security.h"
30 struct cli_symlink_state
{
31 struct tevent_context
*ev
;
32 struct cli_state
*cli
;
40 NTSTATUS set_reparse_status
;
43 static void cli_symlink_create_done(struct tevent_req
*subreq
);
44 static void cli_symlink_set_reparse_done(struct tevent_req
*subreq
);
45 static void cli_symlink_delete_on_close_done(struct tevent_req
*subreq
);
46 static void cli_symlink_close_done(struct tevent_req
*subreq
);
48 struct tevent_req
*cli_symlink_send(TALLOC_CTX
*mem_ctx
,
49 struct tevent_context
*ev
,
50 struct cli_state
*cli
,
55 struct tevent_req
*req
, *subreq
;
56 struct cli_symlink_state
*state
;
58 req
= tevent_req_create(mem_ctx
, &state
, struct cli_symlink_state
);
64 state
->oldpath
= oldpath
;
65 state
->newpath
= newpath
;
68 subreq
= cli_ntcreate_send(
69 state
, ev
, cli
, state
->oldpath
, 0,
70 SYNCHRONIZE_ACCESS
|DELETE_ACCESS
|
71 FILE_READ_ATTRIBUTES
|FILE_WRITE_ATTRIBUTES
,
72 FILE_ATTRIBUTE_NORMAL
, FILE_SHARE_NONE
, FILE_CREATE
,
73 FILE_OPEN_REPARSE_POINT
|FILE_SYNCHRONOUS_IO_NONALERT
|
74 FILE_NON_DIRECTORY_FILE
, 0);
75 if (tevent_req_nomem(subreq
, req
)) {
76 return tevent_req_post(req
, ev
);
78 tevent_req_set_callback(subreq
, cli_symlink_create_done
, req
);
82 static void cli_symlink_create_done(struct tevent_req
*subreq
)
84 struct tevent_req
*req
= tevent_req_callback_data(
85 subreq
, struct tevent_req
);
86 struct cli_symlink_state
*state
= tevent_req_data(
87 req
, struct cli_symlink_state
);
92 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
94 if (tevent_req_nterror(req
, status
)) {
98 SIVAL(state
->setup
, 0, FSCTL_SET_REPARSE_POINT
);
99 SSVAL(state
->setup
, 4, state
->fnum
);
100 SCVAL(state
->setup
, 6, 1); /* IsFcntl */
101 SCVAL(state
->setup
, 7, 0); /* IsFlags */
103 if (!symlink_reparse_buffer_marshall(
104 state
->newpath
, NULL
, state
->flags
, state
,
110 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
, SMBnttrans
,
111 NULL
, -1, /* name, fid */
112 NT_TRANSACT_IOCTL
, 0,
113 state
->setup
, 4, 0, /* setup */
114 NULL
, 0, 0, /* param */
115 data
, data_len
, 0); /* data */
116 if (tevent_req_nomem(subreq
, req
)) {
119 tevent_req_set_callback(subreq
, cli_symlink_set_reparse_done
, req
);
122 static void cli_symlink_set_reparse_done(struct tevent_req
*subreq
)
124 struct tevent_req
*req
= tevent_req_callback_data(
125 subreq
, struct tevent_req
);
126 struct cli_symlink_state
*state
= tevent_req_data(
127 req
, struct cli_symlink_state
);
129 state
->set_reparse_status
= cli_trans_recv(
131 NULL
, 0, NULL
, /* rsetup */
132 NULL
, 0, NULL
, /* rparam */
133 NULL
, 0, NULL
); /* rdata */
136 if (NT_STATUS_IS_OK(state
->set_reparse_status
)) {
137 subreq
= cli_close_send(state
, state
->ev
, state
->cli
,
139 if (tevent_req_nomem(subreq
, req
)) {
142 tevent_req_set_callback(subreq
, cli_symlink_close_done
, req
);
145 subreq
= cli_nt_delete_on_close_send(
146 state
, state
->ev
, state
->cli
, state
->fnum
, true);
147 if (tevent_req_nomem(subreq
, req
)) {
150 tevent_req_set_callback(subreq
, cli_symlink_delete_on_close_done
, req
);
153 static void cli_symlink_delete_on_close_done(struct tevent_req
*subreq
)
155 struct tevent_req
*req
= tevent_req_callback_data(
156 subreq
, struct tevent_req
);
157 struct cli_symlink_state
*state
= tevent_req_data(
158 req
, struct cli_symlink_state
);
161 * Ignore status, we can't do much anyway in case of failure
164 (void)cli_nt_delete_on_close_recv(subreq
);
167 subreq
= cli_close_send(state
, state
->ev
, state
->cli
, state
->fnum
);
168 if (tevent_req_nomem(subreq
, req
)) {
171 tevent_req_set_callback(subreq
, cli_symlink_close_done
, req
);
174 static void cli_symlink_close_done(struct tevent_req
*subreq
)
176 struct tevent_req
*req
= tevent_req_callback_data(
177 subreq
, struct tevent_req
);
178 struct cli_symlink_state
*state
= tevent_req_data(
179 req
, struct cli_symlink_state
);
182 status
= cli_close_recv(subreq
);
185 if (tevent_req_nterror(req
, status
)) {
188 if (tevent_req_nterror(req
, state
->set_reparse_status
)) {
191 tevent_req_done(req
);
194 NTSTATUS
cli_symlink_recv(struct tevent_req
*req
)
196 return tevent_req_simple_recv_ntstatus(req
);
199 NTSTATUS
cli_symlink(struct cli_state
*cli
, const char *oldname
,
200 const char *newname
, uint32_t flags
)
202 TALLOC_CTX
*frame
= talloc_stackframe();
203 struct event_context
*ev
;
204 struct tevent_req
*req
;
205 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
207 if (cli_has_async_calls(cli
)) {
208 status
= NT_STATUS_INVALID_PARAMETER
;
211 ev
= event_context_init(frame
);
215 req
= cli_symlink_send(frame
, ev
, cli
, oldname
, newname
, flags
);
219 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
222 status
= cli_symlink_recv(req
);
228 struct cli_readlink_state
{
229 struct tevent_context
*ev
;
230 struct cli_state
*cli
;
234 NTSTATUS get_reparse_status
;
239 static void cli_readlink_opened(struct tevent_req
*subreq
);
240 static void cli_readlink_got_reparse_data(struct tevent_req
*subreq
);
241 static void cli_readlink_closed(struct tevent_req
*subreq
);
243 struct tevent_req
*cli_readlink_send(TALLOC_CTX
*mem_ctx
,
244 struct tevent_context
*ev
,
245 struct cli_state
*cli
,
248 struct tevent_req
*req
, *subreq
;
249 struct cli_readlink_state
*state
;
251 req
= tevent_req_create(mem_ctx
, &state
, struct cli_readlink_state
);
258 subreq
= cli_ntcreate_send(
259 state
, ev
, cli
, fname
, 0, FILE_READ_ATTRIBUTES
| FILE_READ_EA
,
260 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
261 FILE_OPEN
, FILE_OPEN_REPARSE_POINT
, 0);
262 if (tevent_req_nomem(subreq
, req
)) {
263 return tevent_req_post(req
, ev
);
265 tevent_req_set_callback(subreq
, cli_readlink_opened
, req
);
269 static void cli_readlink_opened(struct tevent_req
*subreq
)
271 struct tevent_req
*req
= tevent_req_callback_data(
272 subreq
, struct tevent_req
);
273 struct cli_readlink_state
*state
= tevent_req_data(
274 req
, struct cli_readlink_state
);
277 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
279 if (tevent_req_nterror(req
, status
)) {
283 SIVAL(state
->setup
, 0, FSCTL_GET_REPARSE_POINT
);
284 SSVAL(state
->setup
, 4, state
->fnum
);
285 SCVAL(state
->setup
, 6, 1); /* IsFcntl */
286 SCVAL(state
->setup
, 7, 0); /* IsFlags */
288 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
, SMBnttrans
,
289 NULL
, -1, /* name, fid */
290 NT_TRANSACT_IOCTL
, 0,
291 state
->setup
, 4, 0, /* setup */
292 NULL
, 0, 0, /* param */
293 NULL
, 0, 16384); /* data */
294 if (tevent_req_nomem(subreq
, req
)) {
297 tevent_req_set_callback(subreq
, cli_readlink_got_reparse_data
, req
);
300 static void cli_readlink_got_reparse_data(struct tevent_req
*subreq
)
302 struct tevent_req
*req
= tevent_req_callback_data(
303 subreq
, struct tevent_req
);
304 struct cli_readlink_state
*state
= tevent_req_data(
305 req
, struct cli_readlink_state
);
307 state
->get_reparse_status
= cli_trans_recv(
309 NULL
, 0, NULL
, /* rsetup */
310 NULL
, 0, NULL
, /* rparam */
311 &state
->data
, 20, &state
->num_data
); /* rdata */
314 subreq
= cli_close_send(state
, state
->ev
, state
->cli
, state
->fnum
);
315 if (tevent_req_nomem(subreq
, req
)) {
318 tevent_req_set_callback(subreq
, cli_readlink_closed
, req
);
321 static void cli_readlink_closed(struct tevent_req
*subreq
)
323 struct tevent_req
*req
= tevent_req_callback_data(
324 subreq
, struct tevent_req
);
327 status
= cli_close_recv(subreq
);
329 if (tevent_req_nterror(req
, status
)) {
332 tevent_req_done(req
);
335 NTSTATUS
cli_readlink_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
336 char **psubstitute_name
, char **pprint_name
,
339 struct cli_readlink_state
*state
= tevent_req_data(
340 req
, struct cli_readlink_state
);
342 char *substitute_name
;
346 if (tevent_req_is_nterror(req
, &status
)) {
350 if (!symlink_reparse_buffer_parse(state
->data
, state
->num_data
,
351 talloc_tos(), &substitute_name
,
352 &print_name
, &flags
)) {
353 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
356 if (psubstitute_name
!= NULL
) {
357 *psubstitute_name
= talloc_move(mem_ctx
, &substitute_name
);
359 TALLOC_FREE(substitute_name
);
361 if (pprint_name
!= NULL
) {
362 *pprint_name
= talloc_move(mem_ctx
, &print_name
);
364 TALLOC_FREE(print_name
);
366 if (pflags
!= NULL
) {
372 NTSTATUS
cli_readlink(struct cli_state
*cli
, const char *fname
,
373 TALLOC_CTX
*mem_ctx
, char **psubstitute_name
,
374 char **pprint_name
, uint32_t *pflags
)
376 TALLOC_CTX
*frame
= talloc_stackframe();
377 struct event_context
*ev
;
378 struct tevent_req
*req
;
379 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
381 if (cli_has_async_calls(cli
)) {
382 status
= NT_STATUS_INVALID_PARAMETER
;
385 ev
= event_context_init(frame
);
389 req
= cli_readlink_send(frame
, ev
, cli
, fname
);
393 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
396 status
= cli_readlink_recv(req
, mem_ctx
, psubstitute_name
,
397 pprint_name
, pflags
);