CVE-2022-3437 third_party/heimdal: Don't pass NULL pointers to memcpy() in DES unwrap
[Samba.git] / source3 / libsmb / clisymlink.c
blob35a9c4069687c2762eb5763d0968c757327390dc
1 /*
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/>.
20 #include "includes.h"
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"
26 #include "trans2.h"
27 #include "libcli/security/secdesc.h"
28 #include "libcli/security/security.h"
29 #include "../libcli/smb/smbXcli_base.h"
30 #include "libcli/smb/reparse_symlink.h"
32 struct cli_symlink_state {
33 struct tevent_context *ev;
34 struct cli_state *cli;
35 const char *link_target;
36 const char *newpath;
37 uint32_t flags;
39 uint16_t fnum;
40 DATA_BLOB in;
42 NTSTATUS set_reparse_status;
45 static void cli_symlink_create_done(struct tevent_req *subreq);
46 static void cli_symlink_set_reparse_done(struct tevent_req *subreq);
47 static void cli_symlink_delete_on_close_done(struct tevent_req *subreq);
48 static void cli_symlink_close_done(struct tevent_req *subreq);
50 struct tevent_req *cli_symlink_send(TALLOC_CTX *mem_ctx,
51 struct tevent_context *ev,
52 struct cli_state *cli,
53 const char *link_target,
54 const char *newpath,
55 uint32_t flags)
57 struct tevent_req *req, *subreq;
58 struct cli_symlink_state *state;
60 req = tevent_req_create(mem_ctx, &state, struct cli_symlink_state);
61 if (req == NULL) {
62 return NULL;
64 state->ev = ev;
65 state->cli = cli;
66 state->link_target = link_target;
67 state->newpath = newpath;
68 state->flags = flags;
70 subreq = cli_ntcreate_send(
71 state, ev, cli, state->newpath, 0,
72 SYNCHRONIZE_ACCESS|DELETE_ACCESS|
73 FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
74 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_CREATE,
75 FILE_OPEN_REPARSE_POINT|FILE_SYNCHRONOUS_IO_NONALERT|
76 FILE_NON_DIRECTORY_FILE,
77 SMB2_IMPERSONATION_IMPERSONATION, 0);
78 if (tevent_req_nomem(subreq, req)) {
79 return tevent_req_post(req, ev);
81 tevent_req_set_callback(subreq, cli_symlink_create_done, req);
82 return req;
85 static void cli_symlink_create_done(struct tevent_req *subreq)
87 struct tevent_req *req = tevent_req_callback_data(
88 subreq, struct tevent_req);
89 struct cli_symlink_state *state = tevent_req_data(
90 req, struct cli_symlink_state);
91 NTSTATUS status;
93 status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
94 TALLOC_FREE(subreq);
95 if (tevent_req_nterror(req, status)) {
96 return;
99 if (!symlink_reparse_buffer_marshall(
100 state->link_target, NULL, state->flags, state,
101 &state->in.data, &state->in.length)) {
102 tevent_req_oom(req);
103 return;
106 subreq = cli_fsctl_send(
107 state,
108 state->ev,
109 state->cli,
110 state->fnum,
111 FSCTL_SET_REPARSE_POINT,
112 &state->in,
114 if (tevent_req_nomem(subreq, req)) {
115 return;
117 tevent_req_set_callback(subreq, cli_symlink_set_reparse_done, req);
120 static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
122 struct tevent_req *req = tevent_req_callback_data(
123 subreq, struct tevent_req);
124 struct cli_symlink_state *state = tevent_req_data(
125 req, struct cli_symlink_state);
127 state->set_reparse_status = cli_fsctl_recv(subreq, NULL, NULL);
128 TALLOC_FREE(subreq);
130 if (NT_STATUS_IS_OK(state->set_reparse_status)) {
131 subreq = cli_close_send(state, state->ev, state->cli,
132 state->fnum);
133 if (tevent_req_nomem(subreq, req)) {
134 return;
136 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
137 return;
139 subreq = cli_nt_delete_on_close_send(
140 state, state->ev, state->cli, state->fnum, true);
141 if (tevent_req_nomem(subreq, req)) {
142 return;
144 tevent_req_set_callback(subreq, cli_symlink_delete_on_close_done, req);
147 static void cli_symlink_delete_on_close_done(struct tevent_req *subreq)
149 struct tevent_req *req = tevent_req_callback_data(
150 subreq, struct tevent_req);
151 struct cli_symlink_state *state = tevent_req_data(
152 req, struct cli_symlink_state);
155 * Ignore status, we can't do much anyway in case of failure
158 (void)cli_nt_delete_on_close_recv(subreq);
159 TALLOC_FREE(subreq);
161 subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
162 if (tevent_req_nomem(subreq, req)) {
163 return;
165 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
168 static void cli_symlink_close_done(struct tevent_req *subreq)
170 struct tevent_req *req = tevent_req_callback_data(
171 subreq, struct tevent_req);
172 struct cli_symlink_state *state = tevent_req_data(
173 req, struct cli_symlink_state);
174 NTSTATUS status;
176 status = cli_close_recv(subreq);
177 TALLOC_FREE(subreq);
179 if (tevent_req_nterror(req, status)) {
180 return;
182 if (tevent_req_nterror(req, state->set_reparse_status)) {
183 return;
185 tevent_req_done(req);
188 NTSTATUS cli_symlink_recv(struct tevent_req *req)
190 return tevent_req_simple_recv_ntstatus(req);
193 NTSTATUS cli_symlink(struct cli_state *cli, const char *link_target,
194 const char *newname, uint32_t flags)
196 TALLOC_CTX *frame = talloc_stackframe();
197 struct tevent_context *ev;
198 struct tevent_req *req;
199 NTSTATUS status = NT_STATUS_NO_MEMORY;
201 if (smbXcli_conn_has_async_calls(cli->conn)) {
202 status = NT_STATUS_INVALID_PARAMETER;
203 goto fail;
205 ev = samba_tevent_context_init(frame);
206 if (ev == NULL) {
207 goto fail;
209 req = cli_symlink_send(frame, ev, cli, link_target, newname, flags);
210 if (req == NULL) {
211 goto fail;
213 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
214 goto fail;
216 status = cli_symlink_recv(req);
217 fail:
218 TALLOC_FREE(frame);
219 return status;
222 struct cli_readlink_state {
223 struct tevent_context *ev;
224 struct cli_state *cli;
225 uint16_t fnum;
227 uint16_t setup[4];
228 NTSTATUS get_reparse_status;
229 uint8_t *data;
230 uint32_t num_data;
233 static void cli_readlink_opened(struct tevent_req *subreq);
234 static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
235 static void cli_readlink_closed(struct tevent_req *subreq);
237 struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
238 struct tevent_context *ev,
239 struct cli_state *cli,
240 const char *fname)
242 struct tevent_req *req, *subreq;
243 struct cli_readlink_state *state;
245 req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
246 if (req == NULL) {
247 return NULL;
249 state->ev = ev;
250 state->cli = cli;
252 subreq = cli_ntcreate_send(
253 state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
254 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
255 FILE_OPEN, FILE_OPEN_REPARSE_POINT,
256 SMB2_IMPERSONATION_IMPERSONATION, 0);
257 if (tevent_req_nomem(subreq, req)) {
258 return tevent_req_post(req, ev);
260 tevent_req_set_callback(subreq, cli_readlink_opened, req);
261 return req;
264 static void cli_readlink_opened(struct tevent_req *subreq)
266 struct tevent_req *req = tevent_req_callback_data(
267 subreq, struct tevent_req);
268 struct cli_readlink_state *state = tevent_req_data(
269 req, struct cli_readlink_state);
270 NTSTATUS status;
272 status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
273 TALLOC_FREE(subreq);
274 if (tevent_req_nterror(req, status)) {
275 return;
278 subreq = cli_fsctl_send(
279 state,
280 state->ev,
281 state->cli,
282 state->fnum,
283 FSCTL_GET_REPARSE_POINT,
284 NULL,
285 65536);
287 if (tevent_req_nomem(subreq, req)) {
288 return;
290 tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
293 static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
295 struct tevent_req *req = tevent_req_callback_data(
296 subreq, struct tevent_req);
297 struct cli_readlink_state *state = tevent_req_data(
298 req, struct cli_readlink_state);
299 DATA_BLOB out = { .data = NULL, };
301 state->get_reparse_status = cli_fsctl_recv(subreq, state, &out);
302 TALLOC_FREE(subreq);
304 if (NT_STATUS_IS_OK(state->get_reparse_status)) {
305 state->data = out.data;
306 state->num_data = out.length;
309 subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
310 if (tevent_req_nomem(subreq, req)) {
311 return;
313 tevent_req_set_callback(subreq, cli_readlink_closed, req);
316 static void cli_readlink_closed(struct tevent_req *subreq)
318 struct tevent_req *req = tevent_req_callback_data(
319 subreq, struct tevent_req);
320 struct cli_readlink_state *state = tevent_req_data(
321 req, struct cli_readlink_state);
322 NTSTATUS status;
324 status = cli_close_recv(subreq);
325 TALLOC_FREE(subreq);
326 if (tevent_req_nterror(req, status)) {
327 return;
329 if (tevent_req_nterror(req, state->get_reparse_status)) {
330 return;
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,
337 uint32_t *pflags)
339 struct cli_readlink_state *state = tevent_req_data(
340 req, struct cli_readlink_state);
341 struct symlink_reparse_struct *symlink = NULL;
342 NTSTATUS status;
344 if (tevent_req_is_nterror(req, &status)) {
345 return status;
348 symlink = symlink_reparse_buffer_parse(
349 talloc_tos(), state->data, state->num_data);
350 if (symlink == NULL) {
351 return NT_STATUS_INVALID_NETWORK_RESPONSE;
354 if (psubstitute_name != NULL) {
355 *psubstitute_name = talloc_move(
356 mem_ctx, &symlink->substitute_name);
359 if (pprint_name != NULL) {
360 *pprint_name = talloc_move(mem_ctx, &symlink->print_name);
363 if (pflags != NULL) {
364 *pflags = symlink->flags;
367 TALLOC_FREE(symlink);
369 return NT_STATUS_OK;
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 tevent_context *ev;
378 struct tevent_req *req;
379 NTSTATUS status = NT_STATUS_NO_MEMORY;
381 if (smbXcli_conn_has_async_calls(cli->conn)) {
382 status = NT_STATUS_INVALID_PARAMETER;
383 goto fail;
385 ev = samba_tevent_context_init(frame);
386 if (ev == NULL) {
387 goto fail;
389 req = cli_readlink_send(frame, ev, cli, fname);
390 if (req == NULL) {
391 goto fail;
393 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
394 goto fail;
396 status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
397 pprint_name, pflags);
398 fail:
399 TALLOC_FREE(frame);
400 return status;