| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 | client file operations
|
|---|
| 4 | Copyright (C) Andrew Tridgell 1994-1998
|
|---|
| 5 | Copyright (C) Jeremy Allison 2001-2009
|
|---|
| 6 |
|
|---|
| 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.
|
|---|
| 11 |
|
|---|
| 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.
|
|---|
| 16 |
|
|---|
| 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/>.
|
|---|
| 19 | */
|
|---|
| 20 |
|
|---|
| 21 | #include "includes.h"
|
|---|
| 22 |
|
|---|
| 23 | /***********************************************************
|
|---|
| 24 | Common function for pushing stings, used by smb_bytes_push_str()
|
|---|
| 25 | and trans_bytes_push_str(). Only difference is the align_odd
|
|---|
| 26 | parameter setting.
|
|---|
| 27 | ***********************************************************/
|
|---|
| 28 |
|
|---|
| 29 | static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
|
|---|
| 30 | const char *str, size_t str_len,
|
|---|
| 31 | bool align_odd,
|
|---|
| 32 | size_t *pconverted_size)
|
|---|
| 33 | {
|
|---|
| 34 | size_t buflen;
|
|---|
| 35 | char *converted;
|
|---|
| 36 | size_t converted_size;
|
|---|
| 37 |
|
|---|
| 38 | if (buf == NULL) {
|
|---|
| 39 | return NULL;
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | buflen = talloc_get_size(buf);
|
|---|
| 43 |
|
|---|
| 44 | if (align_odd && ucs2 && (buflen % 2 == 0)) {
|
|---|
| 45 | /*
|
|---|
| 46 | * We're pushing into an SMB buffer, align odd
|
|---|
| 47 | */
|
|---|
| 48 | buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
|
|---|
| 49 | if (buf == NULL) {
|
|---|
| 50 | return NULL;
|
|---|
| 51 | }
|
|---|
| 52 | buf[buflen] = '\0';
|
|---|
| 53 | buflen += 1;
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | if (!convert_string_talloc(talloc_tos(), CH_UNIX,
|
|---|
| 57 | ucs2 ? CH_UTF16LE : CH_DOS,
|
|---|
| 58 | str, str_len, &converted,
|
|---|
| 59 | &converted_size, true)) {
|
|---|
| 60 | return NULL;
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
|
|---|
| 64 | buflen + converted_size);
|
|---|
| 65 | if (buf == NULL) {
|
|---|
| 66 | TALLOC_FREE(converted);
|
|---|
| 67 | return NULL;
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | memcpy(buf + buflen, converted, converted_size);
|
|---|
| 71 |
|
|---|
| 72 | TALLOC_FREE(converted);
|
|---|
| 73 |
|
|---|
| 74 | if (pconverted_size) {
|
|---|
| 75 | *pconverted_size = converted_size;
|
|---|
| 76 | }
|
|---|
| 77 |
|
|---|
| 78 | return buf;
|
|---|
| 79 | }
|
|---|
| 80 |
|
|---|
| 81 | /***********************************************************
|
|---|
| 82 | Push a string into an SMB buffer, with odd byte alignment
|
|---|
| 83 | if it's a UCS2 string.
|
|---|
| 84 | ***********************************************************/
|
|---|
| 85 |
|
|---|
| 86 | uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
|
|---|
| 87 | const char *str, size_t str_len,
|
|---|
| 88 | size_t *pconverted_size)
|
|---|
| 89 | {
|
|---|
| 90 | return internal_bytes_push_str(buf, ucs2, str, str_len,
|
|---|
| 91 | true, pconverted_size);
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | /***********************************************************
|
|---|
| 95 | Same as smb_bytes_push_str(), but without the odd byte
|
|---|
| 96 | align for ucs2 (we're pushing into a param or data block).
|
|---|
| 97 | static for now, although this will probably change when
|
|---|
| 98 | other modules use async trans calls.
|
|---|
| 99 | ***********************************************************/
|
|---|
| 100 |
|
|---|
| 101 | static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
|
|---|
| 102 | const char *str, size_t str_len,
|
|---|
| 103 | size_t *pconverted_size)
|
|---|
| 104 | {
|
|---|
| 105 | return internal_bytes_push_str(buf, ucs2, str, str_len,
|
|---|
| 106 | false, pconverted_size);
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | /****************************************************************************
|
|---|
| 110 | Hard/Symlink a file (UNIX extensions).
|
|---|
| 111 | Creates new name (sym)linked to oldname.
|
|---|
| 112 | ****************************************************************************/
|
|---|
| 113 |
|
|---|
| 114 | struct link_state {
|
|---|
| 115 | uint16_t setup;
|
|---|
| 116 | uint8_t *param;
|
|---|
| 117 | uint8_t *data;
|
|---|
| 118 | };
|
|---|
| 119 |
|
|---|
| 120 | static void cli_posix_link_internal_done(struct tevent_req *subreq)
|
|---|
| 121 | {
|
|---|
| 122 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 123 | subreq, struct tevent_req);
|
|---|
| 124 | struct link_state *state = tevent_req_data(req, struct link_state);
|
|---|
| 125 | NTSTATUS status;
|
|---|
| 126 |
|
|---|
| 127 | status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
|
|---|
| 128 | TALLOC_FREE(subreq);
|
|---|
| 129 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 130 | tevent_req_nterror(req, status);
|
|---|
| 131 | return;
|
|---|
| 132 | }
|
|---|
| 133 | tevent_req_done(req);
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
|
|---|
| 137 | struct event_context *ev,
|
|---|
| 138 | struct cli_state *cli,
|
|---|
| 139 | const char *oldname,
|
|---|
| 140 | const char *newname,
|
|---|
| 141 | bool hardlink)
|
|---|
| 142 | {
|
|---|
| 143 | struct tevent_req *req = NULL, *subreq = NULL;
|
|---|
| 144 | struct link_state *state = NULL;
|
|---|
| 145 |
|
|---|
| 146 | req = tevent_req_create(mem_ctx, &state, struct link_state);
|
|---|
| 147 | if (req == NULL) {
|
|---|
| 148 | return NULL;
|
|---|
| 149 | }
|
|---|
| 150 |
|
|---|
| 151 | /* Setup setup word. */
|
|---|
| 152 | SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
|
|---|
| 153 |
|
|---|
| 154 | /* Setup param array. */
|
|---|
| 155 | state->param = talloc_array(state, uint8_t, 6);
|
|---|
| 156 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 157 | return tevent_req_post(req, ev);
|
|---|
| 158 | }
|
|---|
| 159 | memset(state->param, '\0', 6);
|
|---|
| 160 | SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
|
|---|
| 161 |
|
|---|
| 162 | state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
|
|---|
| 163 | strlen(newname)+1, NULL);
|
|---|
| 164 |
|
|---|
| 165 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 166 | return tevent_req_post(req, ev);
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | /* Setup data array. */
|
|---|
| 170 | state->data = talloc_array(state, uint8_t, 0);
|
|---|
| 171 | if (tevent_req_nomem(state->data, req)) {
|
|---|
| 172 | return tevent_req_post(req, ev);
|
|---|
| 173 | }
|
|---|
| 174 | state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
|
|---|
| 175 | strlen(oldname)+1, NULL);
|
|---|
| 176 |
|
|---|
| 177 | subreq = cli_trans_send(state, /* mem ctx. */
|
|---|
| 178 | ev, /* event ctx. */
|
|---|
| 179 | cli, /* cli_state. */
|
|---|
| 180 | SMBtrans2, /* cmd. */
|
|---|
| 181 | NULL, /* pipe name. */
|
|---|
| 182 | -1, /* fid. */
|
|---|
| 183 | 0, /* function. */
|
|---|
| 184 | 0, /* flags. */
|
|---|
| 185 | &state->setup, /* setup. */
|
|---|
| 186 | 1, /* num setup uint16_t words. */
|
|---|
| 187 | 0, /* max returned setup. */
|
|---|
| 188 | state->param, /* param. */
|
|---|
| 189 | talloc_get_size(state->param), /* num param. */
|
|---|
| 190 | 2, /* max returned param. */
|
|---|
| 191 | state->data, /* data. */
|
|---|
| 192 | talloc_get_size(state->data), /* num data. */
|
|---|
| 193 | 0); /* max returned data. */
|
|---|
| 194 |
|
|---|
| 195 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 196 | return tevent_req_post(req, ev);
|
|---|
| 197 | }
|
|---|
| 198 | tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
|
|---|
| 199 | return req;
|
|---|
| 200 | }
|
|---|
| 201 |
|
|---|
| 202 | /****************************************************************************
|
|---|
| 203 | Symlink a file (UNIX extensions).
|
|---|
| 204 | ****************************************************************************/
|
|---|
| 205 |
|
|---|
| 206 | struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
|
|---|
| 207 | struct event_context *ev,
|
|---|
| 208 | struct cli_state *cli,
|
|---|
| 209 | const char *oldname,
|
|---|
| 210 | const char *newname)
|
|---|
| 211 | {
|
|---|
| 212 | return cli_posix_link_internal_send(mem_ctx, ev, cli,
|
|---|
| 213 | oldname, newname, false);
|
|---|
| 214 | }
|
|---|
| 215 |
|
|---|
| 216 | NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
|
|---|
| 217 | {
|
|---|
| 218 | NTSTATUS status;
|
|---|
| 219 |
|
|---|
| 220 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 221 | return status;
|
|---|
| 222 | }
|
|---|
| 223 | return NT_STATUS_OK;
|
|---|
| 224 | }
|
|---|
| 225 |
|
|---|
| 226 | NTSTATUS cli_posix_symlink(struct cli_state *cli,
|
|---|
| 227 | const char *oldname,
|
|---|
| 228 | const char *newname)
|
|---|
| 229 | {
|
|---|
| 230 | TALLOC_CTX *frame = talloc_stackframe();
|
|---|
| 231 | struct event_context *ev = NULL;
|
|---|
| 232 | struct tevent_req *req = NULL;
|
|---|
| 233 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 234 |
|
|---|
| 235 | if (cli_has_async_calls(cli)) {
|
|---|
| 236 | /*
|
|---|
| 237 | * Can't use sync call while an async call is in flight
|
|---|
| 238 | */
|
|---|
| 239 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 240 | goto fail;
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | ev = event_context_init(frame);
|
|---|
| 244 | if (ev == NULL) {
|
|---|
| 245 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 246 | goto fail;
|
|---|
| 247 | }
|
|---|
| 248 |
|
|---|
| 249 | req = cli_posix_symlink_send(frame,
|
|---|
| 250 | ev,
|
|---|
| 251 | cli,
|
|---|
| 252 | oldname,
|
|---|
| 253 | newname);
|
|---|
| 254 | if (req == NULL) {
|
|---|
| 255 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 256 | goto fail;
|
|---|
| 257 | }
|
|---|
| 258 |
|
|---|
| 259 | if (!tevent_req_poll(req, ev)) {
|
|---|
| 260 | status = map_nt_error_from_unix(errno);
|
|---|
| 261 | goto fail;
|
|---|
| 262 | }
|
|---|
| 263 |
|
|---|
| 264 | status = cli_posix_symlink_recv(req);
|
|---|
| 265 |
|
|---|
| 266 | fail:
|
|---|
| 267 | TALLOC_FREE(frame);
|
|---|
| 268 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 269 | cli_set_error(cli, status);
|
|---|
| 270 | }
|
|---|
| 271 | return status;
|
|---|
| 272 | }
|
|---|
| 273 |
|
|---|
| 274 | /****************************************************************************
|
|---|
| 275 | Read a POSIX symlink.
|
|---|
| 276 | ****************************************************************************/
|
|---|
| 277 |
|
|---|
| 278 | struct readlink_state {
|
|---|
| 279 | uint16_t setup;
|
|---|
| 280 | uint8_t *param;
|
|---|
| 281 | uint8_t *data;
|
|---|
| 282 | uint32_t num_data;
|
|---|
| 283 | };
|
|---|
| 284 |
|
|---|
| 285 | static void cli_posix_readlink_done(struct tevent_req *subreq)
|
|---|
| 286 | {
|
|---|
| 287 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 288 | subreq, struct tevent_req);
|
|---|
| 289 | struct readlink_state *state = tevent_req_data(req, struct readlink_state);
|
|---|
| 290 | NTSTATUS status;
|
|---|
| 291 |
|
|---|
| 292 | status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
|
|---|
| 293 | &state->data, &state->num_data);
|
|---|
| 294 | TALLOC_FREE(subreq);
|
|---|
| 295 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 296 | tevent_req_nterror(req, status);
|
|---|
| 297 | return;
|
|---|
| 298 | }
|
|---|
| 299 | if (state->num_data == 0) {
|
|---|
| 300 | tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
|
|---|
| 301 | return;
|
|---|
| 302 | }
|
|---|
| 303 | if (state->data[state->num_data-1] != '\0') {
|
|---|
| 304 | tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
|
|---|
| 305 | return;
|
|---|
| 306 | }
|
|---|
| 307 | tevent_req_done(req);
|
|---|
| 308 | }
|
|---|
| 309 |
|
|---|
| 310 | struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
|
|---|
| 311 | struct event_context *ev,
|
|---|
| 312 | struct cli_state *cli,
|
|---|
| 313 | const char *fname,
|
|---|
| 314 | size_t len)
|
|---|
| 315 | {
|
|---|
| 316 | struct tevent_req *req = NULL, *subreq = NULL;
|
|---|
| 317 | struct readlink_state *state = NULL;
|
|---|
| 318 | uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
|
|---|
| 319 |
|
|---|
| 320 | if (maxbytelen < len) {
|
|---|
| 321 | return NULL;
|
|---|
| 322 | }
|
|---|
| 323 |
|
|---|
| 324 | req = tevent_req_create(mem_ctx, &state, struct readlink_state);
|
|---|
| 325 | if (req == NULL) {
|
|---|
| 326 | return NULL;
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | /* Setup setup word. */
|
|---|
| 330 | SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
|
|---|
| 331 |
|
|---|
| 332 | /* Setup param array. */
|
|---|
| 333 | state->param = talloc_array(state, uint8_t, 6);
|
|---|
| 334 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 335 | return tevent_req_post(req, ev);
|
|---|
| 336 | }
|
|---|
| 337 | memset(state->param, '\0', 6);
|
|---|
| 338 | SSVAL(state->param,0,SMB_QUERY_FILE_UNIX_LINK);
|
|---|
| 339 |
|
|---|
| 340 | state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
|
|---|
| 341 | strlen(fname)+1, NULL);
|
|---|
| 342 |
|
|---|
| 343 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 344 | return tevent_req_post(req, ev);
|
|---|
| 345 | }
|
|---|
| 346 |
|
|---|
| 347 | subreq = cli_trans_send(state, /* mem ctx. */
|
|---|
| 348 | ev, /* event ctx. */
|
|---|
| 349 | cli, /* cli_state. */
|
|---|
| 350 | SMBtrans2, /* cmd. */
|
|---|
| 351 | NULL, /* pipe name. */
|
|---|
| 352 | -1, /* fid. */
|
|---|
| 353 | 0, /* function. */
|
|---|
| 354 | 0, /* flags. */
|
|---|
| 355 | &state->setup, /* setup. */
|
|---|
| 356 | 1, /* num setup uint16_t words. */
|
|---|
| 357 | 0, /* max returned setup. */
|
|---|
| 358 | state->param, /* param. */
|
|---|
| 359 | talloc_get_size(state->param), /* num param. */
|
|---|
| 360 | 2, /* max returned param. */
|
|---|
| 361 | NULL, /* data. */
|
|---|
| 362 | 0, /* num data. */
|
|---|
| 363 | maxbytelen); /* max returned data. */
|
|---|
| 364 |
|
|---|
| 365 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 366 | return tevent_req_post(req, ev);
|
|---|
| 367 | }
|
|---|
| 368 | tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
|
|---|
| 369 | return req;
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
|
|---|
| 373 | char *retpath, size_t len)
|
|---|
| 374 | {
|
|---|
| 375 | NTSTATUS status;
|
|---|
| 376 | char *converted = NULL;
|
|---|
| 377 | size_t converted_size = 0;
|
|---|
| 378 | struct readlink_state *state = tevent_req_data(req, struct readlink_state);
|
|---|
| 379 |
|
|---|
| 380 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 381 | return status;
|
|---|
| 382 | }
|
|---|
| 383 | /* The returned data is a pushed string, not raw data. */
|
|---|
| 384 | if (!convert_string_talloc(state,
|
|---|
| 385 | cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
|
|---|
| 386 | CH_UNIX,
|
|---|
| 387 | state->data,
|
|---|
| 388 | state->num_data,
|
|---|
| 389 | &converted,
|
|---|
| 390 | &converted_size,
|
|---|
| 391 | true)) {
|
|---|
| 392 | return NT_STATUS_NO_MEMORY;
|
|---|
| 393 | }
|
|---|
| 394 |
|
|---|
| 395 | len = MIN(len,converted_size);
|
|---|
| 396 | if (len == 0) {
|
|---|
| 397 | return NT_STATUS_DATA_ERROR;
|
|---|
| 398 | }
|
|---|
| 399 | memcpy(retpath, converted, len);
|
|---|
| 400 | return NT_STATUS_OK;
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
|
|---|
| 404 | char *linkpath, size_t len)
|
|---|
| 405 | {
|
|---|
| 406 | TALLOC_CTX *frame = talloc_stackframe();
|
|---|
| 407 | struct event_context *ev = NULL;
|
|---|
| 408 | struct tevent_req *req = NULL;
|
|---|
| 409 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 410 |
|
|---|
| 411 | if (cli_has_async_calls(cli)) {
|
|---|
| 412 | /*
|
|---|
| 413 | * Can't use sync call while an async call is in flight
|
|---|
| 414 | */
|
|---|
| 415 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 416 | goto fail;
|
|---|
| 417 | }
|
|---|
| 418 |
|
|---|
| 419 | ev = event_context_init(frame);
|
|---|
| 420 | if (ev == NULL) {
|
|---|
| 421 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 422 | goto fail;
|
|---|
| 423 | }
|
|---|
| 424 |
|
|---|
| 425 | /* Len is in bytes, we need it in UCS2 units. */
|
|---|
| 426 | if (2*len < len) {
|
|---|
| 427 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 428 | goto fail;
|
|---|
| 429 | }
|
|---|
| 430 |
|
|---|
| 431 | req = cli_posix_readlink_send(frame,
|
|---|
| 432 | ev,
|
|---|
| 433 | cli,
|
|---|
| 434 | fname,
|
|---|
| 435 | len);
|
|---|
| 436 | if (req == NULL) {
|
|---|
| 437 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 438 | goto fail;
|
|---|
| 439 | }
|
|---|
| 440 |
|
|---|
| 441 | if (!tevent_req_poll(req, ev)) {
|
|---|
| 442 | status = map_nt_error_from_unix(errno);
|
|---|
| 443 | goto fail;
|
|---|
| 444 | }
|
|---|
| 445 |
|
|---|
| 446 | status = cli_posix_readlink_recv(req, cli, linkpath, len);
|
|---|
| 447 |
|
|---|
| 448 | fail:
|
|---|
| 449 | TALLOC_FREE(frame);
|
|---|
| 450 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 451 | cli_set_error(cli, status);
|
|---|
| 452 | }
|
|---|
| 453 | return status;
|
|---|
| 454 | }
|
|---|
| 455 |
|
|---|
| 456 | /****************************************************************************
|
|---|
| 457 | Hard link a file (UNIX extensions).
|
|---|
| 458 | ****************************************************************************/
|
|---|
| 459 |
|
|---|
| 460 | struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
|
|---|
| 461 | struct event_context *ev,
|
|---|
| 462 | struct cli_state *cli,
|
|---|
| 463 | const char *oldname,
|
|---|
| 464 | const char *newname)
|
|---|
| 465 | {
|
|---|
| 466 | return cli_posix_link_internal_send(mem_ctx, ev, cli,
|
|---|
| 467 | oldname, newname, true);
|
|---|
| 468 | }
|
|---|
| 469 |
|
|---|
| 470 | NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
|
|---|
| 471 | {
|
|---|
| 472 | NTSTATUS status;
|
|---|
| 473 |
|
|---|
| 474 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 475 | return status;
|
|---|
| 476 | }
|
|---|
| 477 | return NT_STATUS_OK;
|
|---|
| 478 | }
|
|---|
| 479 |
|
|---|
| 480 | NTSTATUS cli_posix_hardlink(struct cli_state *cli,
|
|---|
| 481 | const char *oldname,
|
|---|
| 482 | const char *newname)
|
|---|
| 483 | {
|
|---|
| 484 | TALLOC_CTX *frame = talloc_stackframe();
|
|---|
| 485 | struct event_context *ev = NULL;
|
|---|
| 486 | struct tevent_req *req = NULL;
|
|---|
| 487 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 488 |
|
|---|
| 489 | if (cli_has_async_calls(cli)) {
|
|---|
| 490 | /*
|
|---|
| 491 | * Can't use sync call while an async call is in flight
|
|---|
| 492 | */
|
|---|
| 493 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 494 | goto fail;
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | ev = event_context_init(frame);
|
|---|
| 498 | if (ev == NULL) {
|
|---|
| 499 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 500 | goto fail;
|
|---|
| 501 | }
|
|---|
| 502 |
|
|---|
| 503 | req = cli_posix_hardlink_send(frame,
|
|---|
| 504 | ev,
|
|---|
| 505 | cli,
|
|---|
| 506 | oldname,
|
|---|
| 507 | newname);
|
|---|
| 508 | if (req == NULL) {
|
|---|
| 509 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 510 | goto fail;
|
|---|
| 511 | }
|
|---|
| 512 |
|
|---|
| 513 | if (!tevent_req_poll(req, ev)) {
|
|---|
| 514 | status = map_nt_error_from_unix(errno);
|
|---|
| 515 | goto fail;
|
|---|
| 516 | }
|
|---|
| 517 |
|
|---|
| 518 | status = cli_posix_hardlink_recv(req);
|
|---|
| 519 |
|
|---|
| 520 | fail:
|
|---|
| 521 | TALLOC_FREE(frame);
|
|---|
| 522 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 523 | cli_set_error(cli, status);
|
|---|
| 524 | }
|
|---|
| 525 | return status;
|
|---|
| 526 | }
|
|---|
| 527 |
|
|---|
| 528 | /****************************************************************************
|
|---|
| 529 | Map standard UNIX permissions onto wire representations.
|
|---|
| 530 | ****************************************************************************/
|
|---|
| 531 |
|
|---|
| 532 | uint32_t unix_perms_to_wire(mode_t perms)
|
|---|
| 533 | {
|
|---|
| 534 | unsigned int ret = 0;
|
|---|
| 535 |
|
|---|
| 536 | ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
|
|---|
| 537 | ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
|
|---|
| 538 | ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
|
|---|
| 539 | ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
|
|---|
| 540 | ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
|
|---|
| 541 | ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
|
|---|
| 542 | ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
|
|---|
| 543 | ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
|
|---|
| 544 | ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
|
|---|
| 545 | #ifdef S_ISVTX
|
|---|
| 546 | ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
|
|---|
| 547 | #endif
|
|---|
| 548 | #ifdef S_ISGID
|
|---|
| 549 | ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
|
|---|
| 550 | #endif
|
|---|
| 551 | #ifdef S_ISUID
|
|---|
| 552 | ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
|
|---|
| 553 | #endif
|
|---|
| 554 | return ret;
|
|---|
| 555 | }
|
|---|
| 556 |
|
|---|
| 557 | /****************************************************************************
|
|---|
| 558 | Map wire permissions to standard UNIX.
|
|---|
| 559 | ****************************************************************************/
|
|---|
| 560 |
|
|---|
| 561 | mode_t wire_perms_to_unix(uint32_t perms)
|
|---|
| 562 | {
|
|---|
| 563 | mode_t ret = (mode_t)0;
|
|---|
| 564 |
|
|---|
| 565 | ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
|
|---|
| 566 | ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
|
|---|
| 567 | ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
|
|---|
| 568 | ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
|
|---|
| 569 | ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
|
|---|
| 570 | ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
|
|---|
| 571 | ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
|
|---|
| 572 | ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
|
|---|
| 573 | ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
|
|---|
| 574 | #ifdef S_ISVTX
|
|---|
| 575 | ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
|
|---|
| 576 | #endif
|
|---|
| 577 | #ifdef S_ISGID
|
|---|
| 578 | ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
|
|---|
| 579 | #endif
|
|---|
| 580 | #ifdef S_ISUID
|
|---|
| 581 | ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
|
|---|
| 582 | #endif
|
|---|
| 583 | return ret;
|
|---|
| 584 | }
|
|---|
| 585 |
|
|---|
| 586 | /****************************************************************************
|
|---|
| 587 | Return the file type from the wire filetype for UNIX extensions.
|
|---|
| 588 | ****************************************************************************/
|
|---|
| 589 |
|
|---|
| 590 | static mode_t unix_filetype_from_wire(uint32_t wire_type)
|
|---|
| 591 | {
|
|---|
| 592 | switch (wire_type) {
|
|---|
| 593 | case UNIX_TYPE_FILE:
|
|---|
| 594 | return S_IFREG;
|
|---|
| 595 | case UNIX_TYPE_DIR:
|
|---|
| 596 | return S_IFDIR;
|
|---|
| 597 | #ifdef S_IFLNK
|
|---|
| 598 | case UNIX_TYPE_SYMLINK:
|
|---|
| 599 | return S_IFLNK;
|
|---|
| 600 | #endif
|
|---|
| 601 | #ifdef S_IFCHR
|
|---|
| 602 | case UNIX_TYPE_CHARDEV:
|
|---|
| 603 | return S_IFCHR;
|
|---|
| 604 | #endif
|
|---|
| 605 | #ifdef S_IFBLK
|
|---|
| 606 | case UNIX_TYPE_BLKDEV:
|
|---|
| 607 | return S_IFBLK;
|
|---|
| 608 | #endif
|
|---|
| 609 | #ifdef S_IFIFO
|
|---|
| 610 | case UNIX_TYPE_FIFO:
|
|---|
| 611 | return S_IFIFO;
|
|---|
| 612 | #endif
|
|---|
| 613 | #ifdef S_IFSOCK
|
|---|
| 614 | case UNIX_TYPE_SOCKET:
|
|---|
| 615 | return S_IFSOCK;
|
|---|
| 616 | #endif
|
|---|
| 617 | default:
|
|---|
| 618 | return (mode_t)0;
|
|---|
| 619 | }
|
|---|
| 620 | }
|
|---|
| 621 |
|
|---|
| 622 | /****************************************************************************
|
|---|
| 623 | Do a POSIX getfacl (UNIX extensions).
|
|---|
| 624 | ****************************************************************************/
|
|---|
| 625 |
|
|---|
| 626 | struct getfacl_state {
|
|---|
| 627 | uint16_t setup;
|
|---|
| 628 | uint8_t *param;
|
|---|
| 629 | uint32_t num_data;
|
|---|
| 630 | uint8_t *data;
|
|---|
| 631 | };
|
|---|
| 632 |
|
|---|
| 633 | static void cli_posix_getfacl_done(struct tevent_req *subreq)
|
|---|
| 634 | {
|
|---|
| 635 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 636 | subreq, struct tevent_req);
|
|---|
| 637 | struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
|
|---|
| 638 | NTSTATUS status;
|
|---|
| 639 |
|
|---|
| 640 | status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
|
|---|
| 641 | &state->data, &state->num_data);
|
|---|
| 642 | TALLOC_FREE(subreq);
|
|---|
| 643 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 644 | tevent_req_nterror(req, status);
|
|---|
| 645 | return;
|
|---|
| 646 | }
|
|---|
| 647 | tevent_req_done(req);
|
|---|
| 648 | }
|
|---|
| 649 |
|
|---|
| 650 | struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
|
|---|
| 651 | struct event_context *ev,
|
|---|
| 652 | struct cli_state *cli,
|
|---|
| 653 | const char *fname)
|
|---|
| 654 | {
|
|---|
| 655 | struct tevent_req *req = NULL, *subreq = NULL;
|
|---|
| 656 | struct link_state *state = NULL;
|
|---|
| 657 |
|
|---|
| 658 | req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
|
|---|
| 659 | if (req == NULL) {
|
|---|
| 660 | return NULL;
|
|---|
| 661 | }
|
|---|
| 662 |
|
|---|
| 663 | /* Setup setup word. */
|
|---|
| 664 | SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
|
|---|
| 665 |
|
|---|
| 666 | /* Setup param array. */
|
|---|
| 667 | state->param = talloc_array(state, uint8_t, 6);
|
|---|
| 668 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 669 | return tevent_req_post(req, ev);
|
|---|
| 670 | }
|
|---|
| 671 | memset(state->param, '\0', 6);
|
|---|
| 672 | SSVAL(state->param, 0, SMB_QUERY_POSIX_ACL);
|
|---|
| 673 |
|
|---|
| 674 | state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
|
|---|
| 675 | strlen(fname)+1, NULL);
|
|---|
| 676 |
|
|---|
| 677 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 678 | return tevent_req_post(req, ev);
|
|---|
| 679 | }
|
|---|
| 680 |
|
|---|
| 681 | subreq = cli_trans_send(state, /* mem ctx. */
|
|---|
| 682 | ev, /* event ctx. */
|
|---|
| 683 | cli, /* cli_state. */
|
|---|
| 684 | SMBtrans2, /* cmd. */
|
|---|
| 685 | NULL, /* pipe name. */
|
|---|
| 686 | -1, /* fid. */
|
|---|
| 687 | 0, /* function. */
|
|---|
| 688 | 0, /* flags. */
|
|---|
| 689 | &state->setup, /* setup. */
|
|---|
|
|---|