source: vendor/current/source3/libsmb/clifile.c@ 587

Last change on this file since 587 was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 120.7 KB
Line 
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
29static 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
86uint8_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
101static 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
114struct link_state {
115 uint16_t setup;
116 uint8_t *param;
117 uint8_t *data;
118};
119
120static 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
136static 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
206struct 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
216NTSTATUS 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
226NTSTATUS 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
278struct readlink_state {
279 uint16_t setup;
280 uint8_t *param;
281 uint8_t *data;
282 uint32_t num_data;
283};
284
285static 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
310struct 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
372NTSTATUS 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
403NTSTATUS 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
460struct 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
470NTSTATUS 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
480NTSTATUS 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
532uint32_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
561mode_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
590static 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
626struct getfacl_state {
627 uint16_t setup;
628 uint8_t *param;
629 uint32_t num_data;
630 uint8_t *data;
631};
632
633static 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
650struct 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. */