Line data Source code
1 : /*
2 : Unix SMB/Netbios implementation.
3 : SMB client library implementation
4 : Copyright (C) Andrew Tridgell 1998
5 : Copyright (C) Richard Sharpe 2000, 2002
6 : Copyright (C) John Terpstra 2000
7 : Copyright (C) Tom Jansen (Ninja ISD) 2002
8 : Copyright (C) Derrell Lipman 2003-2008
9 : Copyright (C) Jeremy Allison 2007, 2008
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "includes.h"
26 : #include "libsmb/namequery.h"
27 : #include "libsmb/libsmb.h"
28 : #include "libsmbclient.h"
29 : #include "libsmb_internal.h"
30 : #include "rpc_client/cli_pipe.h"
31 : #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
32 : #include "libsmb/nmblib.h"
33 : #include "../libcli/smb/smbXcli_base.h"
34 : #include "../libcli/security/security.h"
35 : #include "lib/util/tevent_ntstatus.h"
36 : #include "lib/util/time_basic.h"
37 : #include "lib/util/string_wrappers.h"
38 :
39 : /*
40 : * Routine to open a directory
41 : * We accept the URL syntax explained in SMBC_parse_path(), above.
42 : */
43 :
44 58 : static void remove_dirplus(SMBCFILE *dir)
45 : {
46 58 : struct smbc_dirplus_list *d = NULL;
47 :
48 58 : d = dir->dirplus_list;
49 1584 : while (d != NULL) {
50 1526 : struct smbc_dirplus_list *f = d;
51 1526 : d = d->next;
52 :
53 1526 : SAFE_FREE(f->smb_finfo->short_name);
54 1526 : SAFE_FREE(f->smb_finfo->name);
55 1526 : SAFE_FREE(f->smb_finfo);
56 1526 : SAFE_FREE(f);
57 : }
58 :
59 58 : dir->dirplus_list = NULL;
60 58 : dir->dirplus_end = NULL;
61 58 : dir->dirplus_next = NULL;
62 58 : }
63 :
64 : static void
65 58 : remove_dir(SMBCFILE *dir)
66 : {
67 0 : struct smbc_dir_list *d,*f;
68 :
69 58 : d = dir->dir_list;
70 2226 : while (d) {
71 :
72 2168 : f = d; d = d->next;
73 :
74 2168 : SAFE_FREE(f->dirent);
75 2168 : SAFE_FREE(f);
76 :
77 : }
78 :
79 58 : dir->dir_list = dir->dir_end = dir->dir_next = NULL;
80 :
81 58 : }
82 :
83 : static int
84 2168 : add_dirent(SMBCFILE *dir,
85 : const char *name,
86 : const char *comment,
87 : uint32_t type)
88 : {
89 0 : struct smbc_dirent *dirent;
90 0 : int size;
91 2168 : int name_length = (name == NULL ? 0 : strlen(name));
92 2168 : int comment_len = (comment == NULL ? 0 : strlen(comment));
93 :
94 : /*
95 : * Allocate space for the dirent, which must be increased by the
96 : * size of the name and the comment and 1 each for the null terminator.
97 : */
98 :
99 2168 : size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
100 :
101 2168 : dirent = (struct smbc_dirent *)SMB_MALLOC(size);
102 :
103 2168 : if (!dirent) {
104 :
105 0 : dir->dir_error = ENOMEM;
106 0 : return -1;
107 :
108 : }
109 :
110 2168 : ZERO_STRUCTP(dirent);
111 :
112 2168 : if (dir->dir_list == NULL) {
113 :
114 55 : dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
115 55 : if (!dir->dir_list) {
116 :
117 0 : SAFE_FREE(dirent);
118 0 : dir->dir_error = ENOMEM;
119 0 : return -1;
120 :
121 : }
122 55 : ZERO_STRUCTP(dir->dir_list);
123 :
124 55 : dir->dir_end = dir->dir_next = dir->dir_list;
125 : }
126 : else {
127 :
128 2113 : dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
129 :
130 2113 : if (!dir->dir_end->next) {
131 :
132 0 : SAFE_FREE(dirent);
133 0 : dir->dir_error = ENOMEM;
134 0 : return -1;
135 :
136 : }
137 2113 : ZERO_STRUCTP(dir->dir_end->next);
138 :
139 2113 : dir->dir_end = dir->dir_end->next;
140 : }
141 :
142 2168 : dir->dir_end->next = NULL;
143 2168 : dir->dir_end->dirent = dirent;
144 :
145 2168 : dirent->smbc_type = type;
146 2168 : dirent->namelen = name_length;
147 2168 : dirent->commentlen = comment_len;
148 2168 : dirent->dirlen = size;
149 :
150 : /*
151 : * dirent->namelen + 1 includes the null (no null termination needed)
152 : * Ditto for dirent->commentlen.
153 : * The space for the two null bytes was allocated.
154 : */
155 2168 : strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
156 2168 : dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
157 2168 : strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
158 :
159 2168 : return 0;
160 :
161 : }
162 :
163 1526 : static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
164 : {
165 1526 : struct smbc_dirplus_list *new_entry = NULL;
166 1526 : struct libsmb_file_info *info = NULL;
167 :
168 1526 : new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
169 1526 : if (new_entry == NULL) {
170 0 : dir->dir_error = ENOMEM;
171 0 : return -1;
172 : }
173 1526 : ZERO_STRUCTP(new_entry);
174 1526 : new_entry->ino = finfo->ino;
175 :
176 1526 : info = SMB_MALLOC_P(struct libsmb_file_info);
177 1526 : if (info == NULL) {
178 0 : SAFE_FREE(new_entry);
179 0 : dir->dir_error = ENOMEM;
180 0 : return -1;
181 : }
182 :
183 1526 : ZERO_STRUCTP(info);
184 :
185 1526 : info->btime_ts = finfo->btime_ts;
186 1526 : info->atime_ts = finfo->atime_ts;
187 1526 : info->ctime_ts = finfo->ctime_ts;
188 1526 : info->mtime_ts = finfo->mtime_ts;
189 1526 : info->gid = finfo->gid;
190 1526 : info->attrs = finfo->attr;
191 1526 : info->size = finfo->size;
192 1526 : info->uid = finfo->uid;
193 1526 : info->name = SMB_STRDUP(finfo->name);
194 1526 : if (info->name == NULL) {
195 0 : SAFE_FREE(info);
196 0 : SAFE_FREE(new_entry);
197 0 : dir->dir_error = ENOMEM;
198 0 : return -1;
199 : }
200 :
201 1526 : if (finfo->short_name) {
202 1042 : info->short_name = SMB_STRDUP(finfo->short_name);
203 : } else {
204 484 : info->short_name = SMB_STRDUP("");
205 : }
206 :
207 1526 : if (info->short_name == NULL) {
208 0 : SAFE_FREE(info->name);
209 0 : SAFE_FREE(info);
210 0 : SAFE_FREE(new_entry);
211 0 : dir->dir_error = ENOMEM;
212 0 : return -1;
213 : }
214 1526 : new_entry->smb_finfo = info;
215 :
216 : /* Now add to the list. */
217 1526 : if (dir->dirplus_list == NULL) {
218 : /* Empty list - point everything at new_entry. */
219 48 : dir->dirplus_list = new_entry;
220 48 : dir->dirplus_end = new_entry;
221 48 : dir->dirplus_next = new_entry;
222 : } else {
223 : /* Append to list but leave the ->next cursor alone. */
224 1478 : dir->dirplus_end->next = new_entry;
225 1478 : dir->dirplus_end = new_entry;
226 : }
227 :
228 1526 : return 0;
229 : }
230 :
231 : static void
232 4 : list_unique_wg_fn(const char *name,
233 : uint32_t type,
234 : const char *comment,
235 : void *state)
236 : {
237 4 : SMBCFILE *dir = (SMBCFILE *)state;
238 0 : struct smbc_dir_list *dir_list;
239 0 : struct smbc_dirent *dirent;
240 0 : int dirent_type;
241 4 : int do_remove = 0;
242 :
243 4 : dirent_type = dir->dir_type;
244 :
245 4 : if (add_dirent(dir, name, comment, dirent_type) < 0) {
246 : /* An error occurred, what do we do? */
247 : /* FIXME: Add some code here */
248 : /* Change cli_NetServerEnum to take a fn
249 : returning NTSTATUS... JRA. */
250 0 : }
251 :
252 : /* Point to the one just added */
253 4 : dirent = dir->dir_end->dirent;
254 :
255 : /* See if this was a duplicate */
256 4 : for (dir_list = dir->dir_list;
257 10 : dir_list != dir->dir_end;
258 6 : dir_list = dir_list->next) {
259 6 : if (! do_remove &&
260 6 : strcmp(dir_list->dirent->name, dirent->name) == 0) {
261 : /* Duplicate. End end of list need to be removed. */
262 0 : do_remove = 1;
263 : }
264 :
265 6 : if (do_remove && dir_list->next == dir->dir_end) {
266 : /* Found the end of the list. Remove it. */
267 0 : dir->dir_end = dir_list;
268 0 : free(dir_list->next);
269 0 : free(dirent);
270 0 : dir_list->next = NULL;
271 0 : break;
272 : }
273 : }
274 4 : }
275 :
276 : static void
277 638 : list_fn(const char *name,
278 : uint32_t type,
279 : const char *comment,
280 : void *state)
281 : {
282 638 : SMBCFILE *dir = (SMBCFILE *)state;
283 0 : int dirent_type;
284 :
285 : /*
286 : * We need to process the type a little ...
287 : *
288 : * Disk share = 0x00000000
289 : * Print share = 0x00000001
290 : * Comms share = 0x00000002 (obsolete?)
291 : * IPC$ share = 0x00000003
292 : *
293 : * administrative shares:
294 : * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
295 : */
296 :
297 638 : if (dir->dir_type == SMBC_FILE_SHARE) {
298 636 : switch (type) {
299 612 : case 0 | 0x80000000:
300 : case 0:
301 612 : dirent_type = SMBC_FILE_SHARE;
302 612 : break;
303 :
304 20 : case 1:
305 20 : dirent_type = SMBC_PRINTER_SHARE;
306 20 : break;
307 :
308 0 : case 2:
309 0 : dirent_type = SMBC_COMMS_SHARE;
310 0 : break;
311 :
312 4 : case 3 | 0x80000000:
313 : case 3:
314 4 : dirent_type = SMBC_IPC_SHARE;
315 4 : break;
316 :
317 0 : default:
318 0 : dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
319 0 : break;
320 : }
321 : }
322 : else {
323 2 : dirent_type = dir->dir_type;
324 : }
325 :
326 638 : if (add_dirent(dir, name, comment, dirent_type) < 0) {
327 : /* An error occurred, what do we do? */
328 : /* FIXME: Add some code here */
329 : /* Change cli_NetServerEnum to take a fn
330 : returning NTSTATUS... JRA. */
331 0 : }
332 638 : }
333 :
334 : static NTSTATUS
335 1526 : dir_list_fn(struct file_info *finfo,
336 : const char *mask,
337 : void *state)
338 : {
339 1526 : SMBCFILE *dirp = (SMBCFILE *)state;
340 0 : int ret;
341 :
342 1526 : if (add_dirent((SMBCFILE *)state, finfo->name, "",
343 1526 : (finfo->attr&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
344 0 : SMBCFILE *dir = (SMBCFILE *)state;
345 0 : return map_nt_error_from_unix(dir->dir_error);
346 : }
347 1526 : ret = add_dirplus(dirp, finfo);
348 1526 : if (ret < 0) {
349 0 : return map_nt_error_from_unix(dirp->dir_error);
350 : }
351 1526 : return NT_STATUS_OK;
352 : }
353 :
354 : static NTSTATUS
355 4 : net_share_enum_rpc(struct cli_state *cli,
356 : void (*fn)(const char *name,
357 : uint32_t type,
358 : const char *comment,
359 : void *state),
360 : void *state)
361 : {
362 0 : uint32_t i;
363 0 : WERROR result;
364 4 : uint32_t preferred_len = 0xffffffff;
365 0 : uint32_t type;
366 0 : struct srvsvc_NetShareInfoCtr info_ctr;
367 0 : struct srvsvc_NetShareCtr1 ctr1;
368 4 : fstring name = "";
369 4 : fstring comment = "";
370 4 : struct rpc_pipe_client *pipe_hnd = NULL;
371 0 : NTSTATUS nt_status;
372 4 : uint32_t resume_handle = 0;
373 4 : uint32_t total_entries = 0;
374 0 : struct dcerpc_binding_handle *b;
375 :
376 : /* Open the server service pipe */
377 4 : nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
378 : &pipe_hnd);
379 4 : if (!NT_STATUS_IS_OK(nt_status)) {
380 0 : DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
381 0 : goto done;
382 : }
383 :
384 4 : ZERO_STRUCT(info_ctr);
385 4 : ZERO_STRUCT(ctr1);
386 :
387 4 : info_ctr.level = 1;
388 4 : info_ctr.ctr.ctr1 = &ctr1;
389 :
390 4 : b = pipe_hnd->binding_handle;
391 :
392 : /* Issue the NetShareEnum RPC call and retrieve the response */
393 4 : nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
394 4 : pipe_hnd->desthost,
395 : &info_ctr,
396 : preferred_len,
397 : &total_entries,
398 : &resume_handle,
399 : &result);
400 :
401 : /* Was it successful? */
402 4 : if (!NT_STATUS_IS_OK(nt_status)) {
403 : /* Nope. Go clean up. */
404 0 : goto done;
405 : }
406 :
407 4 : if (!W_ERROR_IS_OK(result)) {
408 : /* Nope. Go clean up. */
409 0 : nt_status = werror_to_ntstatus(result);
410 0 : goto done;
411 : }
412 :
413 4 : if (total_entries == 0) {
414 : /* Nope. Go clean up. */
415 0 : nt_status = NT_STATUS_NOT_FOUND;
416 0 : goto done;
417 : }
418 :
419 : /* For each returned entry... */
420 640 : for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
421 :
422 : /* pull out the share name */
423 636 : fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
424 :
425 : /* pull out the share's comment */
426 636 : fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
427 :
428 : /* Get the type value */
429 636 : type = info_ctr.ctr.ctr1->array[i].type;
430 :
431 : /* Add this share to the list */
432 636 : (*fn)(name, type, comment, state);
433 : }
434 :
435 4 : done:
436 : /* Close the server service pipe */
437 4 : TALLOC_FREE(pipe_hnd);
438 :
439 : /* Tell 'em if it worked */
440 4 : return nt_status;
441 : }
442 :
443 :
444 : /*
445 : * Verify that the options specified in a URL are valid
446 : */
447 : int
448 68 : SMBC_check_options(char *server,
449 : char *share,
450 : char *path,
451 : char *options)
452 : {
453 68 : DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
454 : "path='%s' options='%s'\n",
455 : server, share, path, options));
456 :
457 : /* No options at all is always ok */
458 68 : if (! *options) return 0;
459 :
460 : /* Currently, we don't support any options. */
461 0 : return -1;
462 : }
463 :
464 :
465 : SMBCFILE *
466 120 : SMBC_opendir_ctx(SMBCCTX *context,
467 : const char *fname)
468 : {
469 120 : char *server = NULL;
470 120 : char *share = NULL;
471 120 : char *user = NULL;
472 120 : char *password = NULL;
473 120 : char *options = NULL;
474 120 : char *workgroup = NULL;
475 120 : char *path = NULL;
476 120 : size_t path_len = 0;
477 120 : uint16_t port = 0;
478 120 : SMBCSRV *srv = NULL;
479 120 : SMBCFILE *dir = NULL;
480 0 : struct sockaddr_storage rem_ss;
481 120 : TALLOC_CTX *frame = talloc_stackframe();
482 :
483 120 : if (!context || !context->internal->initialized) {
484 0 : DEBUG(4, ("no valid context\n"));
485 0 : TALLOC_FREE(frame);
486 0 : errno = EINVAL + 8192;
487 0 : return NULL;
488 :
489 : }
490 :
491 120 : if (!fname) {
492 4 : DEBUG(4, ("no valid fname\n"));
493 4 : TALLOC_FREE(frame);
494 4 : errno = EINVAL + 8193;
495 4 : return NULL;
496 : }
497 :
498 116 : if (SMBC_parse_path(frame,
499 : context,
500 : fname,
501 : &workgroup,
502 : &server,
503 : &port,
504 : &share,
505 : &path,
506 : &user,
507 : &password,
508 : &options)) {
509 48 : DEBUG(4, ("no valid path\n"));
510 48 : TALLOC_FREE(frame);
511 48 : errno = EINVAL + 8194;
512 48 : return NULL;
513 : }
514 :
515 68 : DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
516 : "path='%s' options='%s'\n",
517 : fname, server, share, path, options));
518 :
519 : /* Ensure the options are valid */
520 68 : if (SMBC_check_options(server, share, path, options)) {
521 0 : DEBUG(4, ("unacceptable options (%s)\n", options));
522 0 : TALLOC_FREE(frame);
523 0 : errno = EINVAL + 8195;
524 0 : return NULL;
525 : }
526 :
527 68 : if (!user || user[0] == (char)0) {
528 46 : user = talloc_strdup(frame, smbc_getUser(context));
529 46 : if (!user) {
530 0 : TALLOC_FREE(frame);
531 0 : errno = ENOMEM;
532 0 : return NULL;
533 : }
534 : }
535 :
536 68 : dir = SMB_MALLOC_P(SMBCFILE);
537 :
538 68 : if (!dir) {
539 0 : TALLOC_FREE(frame);
540 0 : errno = ENOMEM;
541 0 : return NULL;
542 : }
543 :
544 68 : ZERO_STRUCTP(dir);
545 :
546 68 : dir->cli_fd = 0;
547 68 : dir->fname = SMB_STRDUP(fname);
548 68 : if (dir->fname == NULL) {
549 0 : SAFE_FREE(dir);
550 0 : TALLOC_FREE(frame);
551 0 : errno = ENOMEM;
552 0 : return NULL;
553 : }
554 68 : dir->srv = NULL;
555 68 : dir->offset = 0;
556 68 : dir->file = False;
557 68 : dir->dir_list = dir->dir_next = dir->dir_end = NULL;
558 :
559 68 : if (server[0] == (char)0) {
560 :
561 0 : size_t i;
562 4 : size_t count = 0;
563 0 : size_t max_lmb_count;
564 0 : struct sockaddr_storage *ip_list;
565 0 : struct sockaddr_storage server_addr;
566 4 : struct cli_credentials *creds = NULL;
567 0 : NTSTATUS status;
568 :
569 4 : if (share[0] != (char)0 || path[0] != (char)0) {
570 :
571 0 : if (dir) {
572 0 : SAFE_FREE(dir->fname);
573 0 : SAFE_FREE(dir);
574 : }
575 0 : TALLOC_FREE(frame);
576 0 : errno = EINVAL + 8196;
577 0 : return NULL;
578 : }
579 :
580 : /* Determine how many local master browsers to query */
581 4 : max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
582 : ? INT_MAX
583 4 : : smbc_getOptionBrowseMaxLmbCount(context));
584 :
585 4 : creds = cli_credentials_init(frame);
586 4 : if (creds == NULL) {
587 0 : if (dir) {
588 0 : SAFE_FREE(dir->fname);
589 0 : SAFE_FREE(dir);
590 : }
591 0 : TALLOC_FREE(frame);
592 0 : errno = ENOMEM;
593 0 : return NULL;
594 : }
595 :
596 4 : (void)cli_credentials_set_username(creds, user, CRED_SPECIFIED);
597 4 : (void)cli_credentials_set_password(creds, password, CRED_SPECIFIED);
598 :
599 : /*
600 : * We have server and share and path empty but options
601 : * requesting that we scan all master browsers for their list
602 : * of workgroups/domains. This implies that we must first try
603 : * broadcast queries to find all master browsers, and if that
604 : * doesn't work, then try our other methods which return only
605 : * a single master browser.
606 : */
607 :
608 4 : ip_list = NULL;
609 4 : status = name_resolve_bcast(talloc_tos(),
610 : MSBROWSE,
611 : 1,
612 : &ip_list,
613 : &count);
614 4 : if (!NT_STATUS_IS_OK(status))
615 : {
616 :
617 0 : TALLOC_FREE(ip_list);
618 :
619 0 : if (!find_master_ip(workgroup, &server_addr)) {
620 :
621 0 : if (dir) {
622 0 : SAFE_FREE(dir->fname);
623 0 : SAFE_FREE(dir);
624 : }
625 0 : TALLOC_FREE(frame);
626 0 : errno = ENOENT;
627 0 : return NULL;
628 : }
629 :
630 0 : ip_list = (struct sockaddr_storage *)talloc_memdup(
631 : talloc_tos(), &server_addr,
632 : sizeof(server_addr));
633 0 : if (ip_list == NULL) {
634 0 : if (dir) {
635 0 : SAFE_FREE(dir->fname);
636 0 : SAFE_FREE(dir);
637 : }
638 0 : TALLOC_FREE(frame);
639 0 : errno = ENOMEM;
640 0 : return NULL;
641 : }
642 0 : count = 1;
643 : }
644 :
645 16 : for (i = 0; i < count && i < max_lmb_count; i++) {
646 0 : char addr[INET6_ADDRSTRLEN];
647 12 : char *wg_ptr = NULL;
648 12 : struct cli_state *cli = NULL;
649 :
650 12 : print_sockaddr(addr, sizeof(addr), &ip_list[i]);
651 12 : DEBUG(99, ("Found master browser %zu of %zu: %s\n",
652 : i+1, MAX(count, max_lmb_count),
653 : addr));
654 :
655 12 : cli = get_ipc_connect_master_ip(talloc_tos(),
656 12 : &ip_list[i],
657 : creds,
658 : &wg_ptr);
659 : /* cli == NULL is the master browser refused to talk or
660 : could not be found */
661 12 : if (!cli) {
662 11 : continue;
663 : }
664 :
665 2 : workgroup = talloc_strdup(frame, wg_ptr);
666 2 : server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
667 :
668 2 : cli_shutdown(cli);
669 :
670 2 : if (!workgroup || !server) {
671 0 : if (dir) {
672 0 : SAFE_FREE(dir->fname);
673 0 : SAFE_FREE(dir);
674 : }
675 0 : TALLOC_FREE(frame);
676 0 : errno = ENOMEM;
677 0 : return NULL;
678 : }
679 :
680 2 : DEBUG(4, ("using workgroup %s %s\n",
681 : workgroup, server));
682 :
683 : /*
684 : * For each returned master browser IP address, get a
685 : * connection to IPC$ on the server if we do not
686 : * already have one, and determine the
687 : * workgroups/domains that it knows about.
688 : */
689 :
690 2 : srv = SMBC_server(frame, context, True, server, port, "IPC$",
691 : &workgroup, &user, &password);
692 2 : if (!srv) {
693 0 : continue;
694 : }
695 :
696 2 : if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
697 1 : continue;
698 : }
699 :
700 1 : dir->srv = srv;
701 1 : dir->dir_type = SMBC_WORKGROUP;
702 :
703 : /* Now, list the stuff ... */
704 :
705 1 : if (!cli_NetServerEnum(srv->cli,
706 : workgroup,
707 : SV_TYPE_DOMAIN_ENUM,
708 : list_unique_wg_fn,
709 : (void *)dir)) {
710 0 : continue;
711 : }
712 : }
713 :
714 4 : TALLOC_FREE(ip_list);
715 : } else {
716 : /*
717 : * Server not an empty string ... Check the rest and see what
718 : * gives
719 : */
720 64 : if (*share == '\0') {
721 16 : if (*path != '\0') {
722 :
723 : /* Should not have empty share with path */
724 0 : if (dir) {
725 0 : SAFE_FREE(dir->fname);
726 0 : SAFE_FREE(dir);
727 : }
728 0 : TALLOC_FREE(frame);
729 0 : errno = EINVAL + 8197;
730 0 : return NULL;
731 :
732 : }
733 :
734 : /*
735 : * We don't know if <server> is really a server name
736 : * or is a workgroup/domain name. If we already have
737 : * a server structure for it, we'll use it.
738 : * Otherwise, check to see if <server><1D>,
739 : * <server><1B>, or <server><20> translates. We check
740 : * to see if <server> is an IP address first.
741 : */
742 :
743 : /*
744 : * See if we have an existing server. Do not
745 : * establish a connection if one does not already
746 : * exist.
747 : */
748 16 : srv = SMBC_server(frame, context, False,
749 : server, port, "IPC$",
750 : &workgroup, &user, &password);
751 :
752 : /*
753 : * If no existing server and not an IP addr, look for
754 : * LMB or DMB
755 : */
756 16 : if (!srv &&
757 32 : !is_ipaddress(server) &&
758 20 : (resolve_name(server, &rem_ss, 0x1d, false) || /* LMB */
759 6 : resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
760 : /*
761 : * "server" is actually a workgroup name,
762 : * not a server. Make this clear.
763 : */
764 12 : char *wgroup = server;
765 0 : fstring buserver;
766 :
767 12 : dir->dir_type = SMBC_SERVER;
768 :
769 : /*
770 : * Get the backup list ...
771 : */
772 12 : if (!name_status_find(wgroup, 0, 0,
773 : &rem_ss, buserver)) {
774 0 : char addr[INET6_ADDRSTRLEN];
775 :
776 0 : print_sockaddr(addr, sizeof(addr), &rem_ss);
777 0 : DEBUG(0,("Could not get name of "
778 : "local/domain master browser "
779 : "for workgroup %s from "
780 : "address %s\n",
781 : wgroup,
782 : addr));
783 0 : if (dir) {
784 0 : SAFE_FREE(dir->fname);
785 0 : SAFE_FREE(dir);
786 : }
787 0 : TALLOC_FREE(frame);
788 0 : errno = EPERM;
789 0 : return NULL;
790 :
791 : }
792 :
793 : /*
794 : * Get a connection to IPC$ on the server if
795 : * we do not already have one
796 : */
797 12 : srv = SMBC_server(frame, context, True,
798 : buserver, port, "IPC$",
799 : &workgroup,
800 : &user, &password);
801 12 : if (!srv) {
802 4 : DEBUG(0, ("got no contact to IPC$\n"));
803 4 : if (dir) {
804 4 : SAFE_FREE(dir->fname);
805 4 : SAFE_FREE(dir);
806 : }
807 4 : TALLOC_FREE(frame);
808 4 : return NULL;
809 :
810 : }
811 :
812 8 : dir->srv = srv;
813 :
814 8 : if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
815 6 : if (dir) {
816 6 : SAFE_FREE(dir->fname);
817 6 : SAFE_FREE(dir);
818 : }
819 6 : TALLOC_FREE(frame);
820 6 : return NULL;
821 : }
822 :
823 : /* Now, list the servers ... */
824 2 : if (!cli_NetServerEnum(srv->cli, wgroup,
825 : 0x0000FFFE, list_fn,
826 : (void *)dir)) {
827 :
828 0 : if (dir) {
829 0 : SAFE_FREE(dir->fname);
830 0 : SAFE_FREE(dir);
831 : }
832 0 : TALLOC_FREE(frame);
833 0 : return NULL;
834 : }
835 8 : } else if (srv ||
836 8 : (resolve_name(server, &rem_ss, 0x20, false))) {
837 0 : NTSTATUS status;
838 :
839 : /*
840 : * If we hadn't found the server, get one now
841 : */
842 4 : if (!srv) {
843 4 : srv = SMBC_server(frame, context, True,
844 : server, port, "IPC$",
845 : &workgroup,
846 : &user, &password);
847 : }
848 :
849 4 : if (!srv) {
850 0 : if (dir) {
851 0 : SAFE_FREE(dir->fname);
852 0 : SAFE_FREE(dir);
853 : }
854 0 : TALLOC_FREE(frame);
855 0 : return NULL;
856 :
857 : }
858 :
859 4 : dir->dir_type = SMBC_FILE_SHARE;
860 4 : dir->srv = srv;
861 :
862 : /* List the shares ... */
863 :
864 4 : status = net_share_enum_rpc(srv->cli,
865 : list_fn,
866 : (void *)dir);
867 4 : if (!NT_STATUS_IS_OK(status) &&
868 0 : smbXcli_conn_protocol(srv->cli->conn) <=
869 : PROTOCOL_NT1) {
870 : /*
871 : * Only call cli_RNetShareEnum()
872 : * on SMB1 connections, not SMB2+.
873 : */
874 0 : int rc = cli_RNetShareEnum(srv->cli,
875 : list_fn,
876 : (void *)dir);
877 0 : if (rc != 0) {
878 0 : status = cli_nt_error(srv->cli);
879 : } else {
880 0 : status = NT_STATUS_OK;
881 : }
882 : }
883 4 : if (!NT_STATUS_IS_OK(status)) {
884 : /*
885 : * Set cli->raw_status so SMBC_errno()
886 : * will correctly return the error.
887 : */
888 0 : srv->cli->raw_status = status;
889 0 : if (dir != NULL) {
890 0 : SAFE_FREE(dir->fname);
891 0 : SAFE_FREE(dir);
892 : }
893 0 : TALLOC_FREE(frame);
894 0 : errno = map_errno_from_nt_status(
895 : status);
896 0 : return NULL;
897 : }
898 : } else {
899 : /* Neither the workgroup nor server exists */
900 0 : errno = ECONNREFUSED;
901 0 : if (dir) {
902 0 : SAFE_FREE(dir->fname);
903 0 : SAFE_FREE(dir);
904 : }
905 0 : TALLOC_FREE(frame);
906 0 : return NULL;
907 : }
908 :
909 : }
910 : else {
911 : /*
912 : * The server and share are specified ... work from
913 : * there ...
914 : */
915 0 : char *targetpath;
916 0 : struct cli_state *targetcli;
917 48 : struct cli_credentials *creds = NULL;
918 0 : NTSTATUS status;
919 :
920 : /* We connect to the server and list the directory */
921 48 : dir->dir_type = SMBC_FILE_SHARE;
922 :
923 48 : srv = SMBC_server(frame, context, True, server, port, share,
924 : &workgroup, &user, &password);
925 :
926 48 : if (!srv) {
927 0 : if (dir) {
928 0 : SAFE_FREE(dir->fname);
929 0 : SAFE_FREE(dir);
930 : }
931 0 : TALLOC_FREE(frame);
932 0 : return NULL;
933 : }
934 :
935 48 : dir->srv = srv;
936 :
937 : /* Now, list the files ... */
938 :
939 48 : path_len = strlen(path);
940 48 : path = talloc_asprintf_append(path, "\\*");
941 48 : if (!path) {
942 0 : if (dir) {
943 0 : SAFE_FREE(dir->fname);
944 0 : SAFE_FREE(dir);
945 : }
946 0 : TALLOC_FREE(frame);
947 0 : return NULL;
948 : }
949 :
950 48 : creds = context->internal->creds;
951 :
952 48 : status = cli_resolve_path(
953 : frame, "",
954 : creds,
955 : srv->cli, path, &targetcli, &targetpath);
956 48 : if (!NT_STATUS_IS_OK(status)) {
957 0 : d_printf("Could not resolve %s\n", path);
958 0 : if (dir) {
959 0 : SAFE_FREE(dir->fname);
960 0 : SAFE_FREE(dir);
961 : }
962 0 : TALLOC_FREE(frame);
963 0 : return NULL;
964 : }
965 :
966 48 : status = cli_list(targetcli, targetpath,
967 : FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
968 : dir_list_fn, (void *)dir);
969 48 : if (!NT_STATUS_IS_OK(status)) {
970 0 : int saved_errno;
971 0 : if (dir) {
972 0 : SAFE_FREE(dir->fname);
973 0 : SAFE_FREE(dir);
974 : }
975 0 : saved_errno = cli_status_to_errno(status);
976 :
977 0 : if (saved_errno == EINVAL) {
978 0 : struct stat sb = {0};
979 : /*
980 : * See if they asked to opendir
981 : * something other than a directory.
982 : * If so, the converted error value we
983 : * got would have been EINVAL rather
984 : * than ENOTDIR.
985 : */
986 0 : path[path_len] = '\0'; /* restore original path */
987 :
988 0 : status = SMBC_getatr(
989 : context,
990 : srv,
991 : path,
992 : &sb);
993 0 : if (NT_STATUS_IS_OK(status) &&
994 0 : !S_ISDIR(sb.st_mode)) {
995 :
996 : /* It is. Correct the error value */
997 0 : saved_errno = ENOTDIR;
998 : }
999 : }
1000 :
1001 : /*
1002 : * If there was an error and the server is no
1003 : * good any more...
1004 : */
1005 0 : if (cli_is_error(targetcli) &&
1006 0 : smbc_getFunctionCheckServer(context)(context, srv)) {
1007 :
1008 : /* ... then remove it. */
1009 0 : if (smbc_getFunctionRemoveUnusedServer(context)(context,
1010 : srv)) {
1011 : /*
1012 : * We could not remove the
1013 : * server completely, remove
1014 : * it from the cache so we
1015 : * will not get it again. It
1016 : * will be removed when the
1017 : * last file/dir is closed.
1018 : */
1019 0 : smbc_getFunctionRemoveCachedServer(context)(context, srv);
1020 : }
1021 : }
1022 :
1023 0 : TALLOC_FREE(frame);
1024 0 : errno = saved_errno;
1025 0 : return NULL;
1026 : }
1027 : }
1028 :
1029 : }
1030 :
1031 58 : DLIST_ADD(context->internal->files, dir);
1032 58 : TALLOC_FREE(frame);
1033 58 : return dir;
1034 :
1035 : }
1036 :
1037 : /*
1038 : * Routine to close a directory
1039 : */
1040 :
1041 : int
1042 58 : SMBC_closedir_ctx(SMBCCTX *context,
1043 : SMBCFILE *dir)
1044 : {
1045 58 : TALLOC_CTX *frame = NULL;
1046 :
1047 58 : if (!context || !context->internal->initialized) {
1048 0 : errno = EINVAL;
1049 0 : return -1;
1050 : }
1051 :
1052 58 : if (dir == NULL) {
1053 0 : return 0;
1054 : }
1055 :
1056 58 : frame = talloc_stackframe();
1057 :
1058 58 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1059 0 : errno = EBADF;
1060 0 : TALLOC_FREE(frame);
1061 0 : return -1;
1062 : }
1063 :
1064 58 : remove_dir(dir); /* Clean it up */
1065 58 : remove_dirplus(dir);
1066 :
1067 58 : DLIST_REMOVE(context->internal->files, dir);
1068 :
1069 58 : SAFE_FREE(dir->fname);
1070 58 : SAFE_FREE(dir); /* Free the space too */
1071 :
1072 58 : TALLOC_FREE(frame);
1073 58 : return 0;
1074 :
1075 : }
1076 :
1077 : static int
1078 1270 : smbc_readdir_internal(SMBCCTX * context,
1079 : struct smbc_dirent *dest,
1080 : struct smbc_dirent *src,
1081 : int max_namebuf_len)
1082 : {
1083 1270 : if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
1084 0 : int remaining_len;
1085 :
1086 : /* url-encode the name. get back remaining buffer space */
1087 0 : remaining_len =
1088 0 : smbc_urlencode(dest->name, src->name, max_namebuf_len);
1089 :
1090 : /* -1 means no null termination. */
1091 0 : if (remaining_len < 0) {
1092 0 : return -1;
1093 : }
1094 :
1095 : /* We now know the name length */
1096 0 : dest->namelen = strlen(dest->name);
1097 :
1098 0 : if (dest->namelen + 1 < 1) {
1099 : /* Integer wrap. */
1100 0 : return -1;
1101 : }
1102 :
1103 0 : if (dest->namelen + 1 >= max_namebuf_len) {
1104 : /* Out of space for comment. */
1105 0 : return -1;
1106 : }
1107 :
1108 : /* Save the pointer to the beginning of the comment */
1109 0 : dest->comment = dest->name + dest->namelen + 1;
1110 :
1111 0 : if (remaining_len < 1) {
1112 : /* No room for comment null termination. */
1113 0 : return -1;
1114 : }
1115 :
1116 : /* Copy the comment */
1117 0 : strlcpy(dest->comment, src->comment, remaining_len);
1118 :
1119 : /* Save other fields */
1120 0 : dest->smbc_type = src->smbc_type;
1121 0 : dest->commentlen = strlen(dest->comment);
1122 0 : dest->dirlen = ((dest->comment + dest->commentlen + 1) -
1123 : (char *) dest);
1124 : } else {
1125 :
1126 : /* No encoding. Just copy the entry as is. */
1127 1270 : if (src->dirlen > max_namebuf_len) {
1128 0 : return -1;
1129 : }
1130 1270 : memcpy(dest, src, src->dirlen);
1131 1270 : if (src->namelen + 1 < 1) {
1132 : /* Integer wrap */
1133 0 : return -1;
1134 : }
1135 1270 : if (src->namelen + 1 >= max_namebuf_len) {
1136 : /* Comment off the end. */
1137 0 : return -1;
1138 : }
1139 1270 : dest->comment = (char *)(&dest->name + src->namelen + 1);
1140 : }
1141 1270 : return 0;
1142 : }
1143 :
1144 : /*
1145 : * Routine to get a directory entry
1146 : */
1147 :
1148 : struct smbc_dirent *
1149 1154 : SMBC_readdir_ctx(SMBCCTX *context,
1150 : SMBCFILE *dir)
1151 : {
1152 0 : int maxlen;
1153 0 : int ret;
1154 0 : struct smbc_dirent *dirp, *dirent;
1155 1154 : TALLOC_CTX *frame = talloc_stackframe();
1156 :
1157 : /* Check that all is ok first ... */
1158 :
1159 1154 : if (!context || !context->internal->initialized) {
1160 :
1161 0 : errno = EINVAL;
1162 0 : DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
1163 0 : TALLOC_FREE(frame);
1164 0 : return NULL;
1165 :
1166 : }
1167 :
1168 1154 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1169 :
1170 0 : errno = EBADF;
1171 0 : DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
1172 0 : TALLOC_FREE(frame);
1173 0 : return NULL;
1174 :
1175 : }
1176 :
1177 1154 : if (dir->file != False) { /* FIXME, should be dir, perhaps */
1178 :
1179 0 : errno = ENOTDIR;
1180 0 : DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
1181 0 : TALLOC_FREE(frame);
1182 0 : return NULL;
1183 :
1184 : }
1185 :
1186 1154 : if (!dir->dir_next) {
1187 40 : TALLOC_FREE(frame);
1188 40 : return NULL;
1189 : }
1190 :
1191 1114 : dirent = dir->dir_next->dirent;
1192 1114 : if (!dirent) {
1193 :
1194 0 : errno = ENOENT;
1195 0 : TALLOC_FREE(frame);
1196 0 : return NULL;
1197 :
1198 : }
1199 :
1200 1114 : dirp = &context->internal->dirent;
1201 1114 : maxlen = sizeof(context->internal->_dirent_name);
1202 :
1203 1114 : ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
1204 1114 : if (ret == -1) {
1205 0 : errno = EINVAL;
1206 0 : TALLOC_FREE(frame);
1207 0 : return NULL;
1208 : }
1209 :
1210 1114 : dir->dir_next = dir->dir_next->next;
1211 :
1212 : /*
1213 : * If we are returning file entries, we
1214 : * have a duplicate list in dirplus.
1215 : *
1216 : * Update dirplus_next also so readdir and
1217 : * readdirplus are kept in sync.
1218 : */
1219 1114 : if (dir->dirplus_list != NULL) {
1220 478 : dir->dirplus_next = dir->dirplus_next->next;
1221 : }
1222 :
1223 1114 : TALLOC_FREE(frame);
1224 1114 : return dirp;
1225 : }
1226 :
1227 : /*
1228 : * Routine to get a directory entry with all attributes
1229 : */
1230 :
1231 : const struct libsmb_file_info *
1232 743 : SMBC_readdirplus_ctx(SMBCCTX *context,
1233 : SMBCFILE *dir)
1234 : {
1235 743 : struct libsmb_file_info *smb_finfo = NULL;
1236 743 : TALLOC_CTX *frame = talloc_stackframe();
1237 :
1238 : /* Check that all is ok first ... */
1239 :
1240 743 : if (context == NULL || !context->internal->initialized) {
1241 0 : DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
1242 0 : TALLOC_FREE(frame);
1243 0 : errno = EINVAL;
1244 0 : return NULL;
1245 : }
1246 :
1247 743 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1248 0 : DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
1249 0 : TALLOC_FREE(frame);
1250 0 : errno = EBADF;
1251 0 : return NULL;
1252 : }
1253 :
1254 743 : if (dir->dirplus_next == NULL) {
1255 0 : TALLOC_FREE(frame);
1256 0 : return NULL;
1257 : }
1258 :
1259 743 : smb_finfo = dir->dirplus_next->smb_finfo;
1260 743 : if (smb_finfo == NULL) {
1261 0 : TALLOC_FREE(frame);
1262 0 : errno = ENOENT;
1263 0 : return NULL;
1264 : }
1265 743 : dir->dirplus_next = dir->dirplus_next->next;
1266 :
1267 : /*
1268 : * If we are returning file entries, we
1269 : * have a duplicate list in dir_list
1270 : *
1271 : * Update dir_next also so readdir and
1272 : * readdirplus are kept in sync.
1273 : */
1274 743 : if (dir->dir_list) {
1275 743 : dir->dir_next = dir->dir_next->next;
1276 : }
1277 :
1278 743 : TALLOC_FREE(frame);
1279 743 : return smb_finfo;
1280 : }
1281 :
1282 : /*
1283 : * Routine to get a directory entry plus a filled in stat structure if
1284 : * requested.
1285 : */
1286 :
1287 131 : const struct libsmb_file_info *SMBC_readdirplus2_ctx(SMBCCTX *context,
1288 : SMBCFILE *dir,
1289 : struct stat *st)
1290 : {
1291 131 : struct libsmb_file_info *smb_finfo = NULL;
1292 131 : struct smbc_dirplus_list *dp_list = NULL;
1293 0 : ino_t ino;
1294 131 : char *full_pathname = NULL;
1295 131 : char *workgroup = NULL;
1296 131 : char *server = NULL;
1297 131 : uint16_t port = 0;
1298 131 : char *share = NULL;
1299 131 : char *path = NULL;
1300 131 : char *user = NULL;
1301 131 : char *password = NULL;
1302 131 : char *options = NULL;
1303 0 : int rc;
1304 131 : TALLOC_CTX *frame = NULL;
1305 :
1306 : /*
1307 : * Allow caller to pass in NULL for stat pointer if
1308 : * required. This makes this call identical to
1309 : * smbc_readdirplus().
1310 : */
1311 :
1312 131 : if (st == NULL) {
1313 0 : return SMBC_readdirplus_ctx(context, dir);
1314 : }
1315 :
1316 131 : frame = talloc_stackframe();
1317 :
1318 : /* Check that all is ok first ... */
1319 131 : if (context == NULL || !context->internal->initialized) {
1320 0 : DBG_ERR("Invalid context in SMBC_readdirplus2_ctx()\n");
1321 0 : TALLOC_FREE(frame);
1322 0 : errno = EINVAL;
1323 0 : return NULL;
1324 : }
1325 :
1326 131 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1327 0 : DBG_ERR("Invalid dir in SMBC_readdirplus2_ctx()\n");
1328 0 : TALLOC_FREE(frame);
1329 0 : errno = EBADF;
1330 0 : return NULL;
1331 : }
1332 :
1333 131 : dp_list = dir->dirplus_next;
1334 131 : if (dp_list == NULL) {
1335 0 : TALLOC_FREE(frame);
1336 0 : return NULL;
1337 : }
1338 :
1339 131 : ino = (ino_t)dp_list->ino;
1340 :
1341 131 : smb_finfo = dp_list->smb_finfo;
1342 131 : if (smb_finfo == NULL) {
1343 0 : TALLOC_FREE(frame);
1344 0 : errno = ENOENT;
1345 0 : return NULL;
1346 : }
1347 :
1348 131 : full_pathname = talloc_asprintf(frame,
1349 : "%s/%s",
1350 : dir->fname,
1351 : smb_finfo->name);
1352 131 : if (full_pathname == NULL) {
1353 0 : TALLOC_FREE(frame);
1354 0 : errno = ENOENT;
1355 0 : return NULL;
1356 : }
1357 :
1358 131 : rc = SMBC_parse_path(frame,
1359 : context,
1360 : full_pathname,
1361 : &workgroup,
1362 : &server,
1363 : &port,
1364 : &share,
1365 : &path,
1366 : &user,
1367 : &password,
1368 : &options);
1369 131 : if (rc != 0) {
1370 0 : TALLOC_FREE(frame);
1371 0 : errno = ENOENT;
1372 0 : return NULL;
1373 : }
1374 :
1375 131 : setup_stat(st,
1376 : path,
1377 131 : smb_finfo->size,
1378 131 : smb_finfo->attrs,
1379 : ino,
1380 131 : dir->srv->dev,
1381 : smb_finfo->atime_ts,
1382 : smb_finfo->ctime_ts,
1383 : smb_finfo->mtime_ts);
1384 :
1385 131 : TALLOC_FREE(full_pathname);
1386 :
1387 131 : dir->dirplus_next = dir->dirplus_next->next;
1388 :
1389 : /*
1390 : * If we are returning file entries, we
1391 : * have a duplicate list in dir_list
1392 : *
1393 : * Update dir_next also so readdir and
1394 : * readdirplus are kept in sync.
1395 : */
1396 131 : if (dir->dir_list) {
1397 131 : dir->dir_next = dir->dir_next->next;
1398 : }
1399 :
1400 131 : TALLOC_FREE(frame);
1401 131 : return smb_finfo;
1402 : }
1403 :
1404 : /*
1405 : * Routine to get directory entries
1406 : */
1407 :
1408 : int
1409 8 : SMBC_getdents_ctx(SMBCCTX *context,
1410 : SMBCFILE *dir,
1411 : struct smbc_dirent *dirp,
1412 : int count)
1413 : {
1414 8 : int rem = count;
1415 0 : int reqd;
1416 0 : int maxlen;
1417 8 : char *ndir = (char *)dirp;
1418 0 : struct smbc_dir_list *dirlist;
1419 8 : TALLOC_CTX *frame = talloc_stackframe();
1420 :
1421 : /* Check that all is ok first ... */
1422 :
1423 8 : if (!context || !context->internal->initialized) {
1424 :
1425 0 : errno = EINVAL;
1426 0 : TALLOC_FREE(frame);
1427 0 : return -1;
1428 :
1429 : }
1430 :
1431 8 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1432 :
1433 0 : errno = EBADF;
1434 0 : TALLOC_FREE(frame);
1435 0 : return -1;
1436 :
1437 : }
1438 :
1439 8 : if (dir->file != False) { /* FIXME, should be dir, perhaps */
1440 :
1441 0 : errno = ENOTDIR;
1442 0 : TALLOC_FREE(frame);
1443 0 : return -1;
1444 :
1445 : }
1446 :
1447 : /*
1448 : * Now, retrieve the number of entries that will fit in what was passed
1449 : * We have to figure out if the info is in the list, or we need to
1450 : * send a request to the server to get the info.
1451 : */
1452 :
1453 156 : while ((dirlist = dir->dir_next)) {
1454 0 : int ret;
1455 0 : struct smbc_dirent *dirent;
1456 156 : struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
1457 :
1458 156 : if (!dirlist->dirent) {
1459 :
1460 0 : errno = ENOENT; /* Bad error */
1461 0 : TALLOC_FREE(frame);
1462 0 : return -1;
1463 :
1464 : }
1465 :
1466 : /* Do urlencoding of next entry, if so selected */
1467 156 : dirent = &context->internal->dirent;
1468 156 : maxlen = sizeof(context->internal->_dirent_name);
1469 156 : ret = smbc_readdir_internal(context, dirent,
1470 : dirlist->dirent, maxlen);
1471 156 : if (ret == -1) {
1472 0 : errno = EINVAL;
1473 0 : TALLOC_FREE(frame);
1474 0 : return -1;
1475 : }
1476 :
1477 156 : reqd = dirent->dirlen;
1478 :
1479 156 : if (rem < reqd) {
1480 :
1481 8 : if (rem < count) { /* We managed to copy something */
1482 :
1483 8 : errno = 0;
1484 8 : TALLOC_FREE(frame);
1485 8 : return count - rem;
1486 :
1487 : }
1488 : else { /* Nothing copied ... */
1489 :
1490 0 : errno = EINVAL; /* Not enough space ... */
1491 0 : TALLOC_FREE(frame);
1492 0 : return -1;
1493 :
1494 : }
1495 :
1496 : }
1497 :
1498 148 : memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
1499 :
1500 148 : currentEntry->comment = ¤tEntry->name[0] +
1501 148 : dirent->namelen + 1;
1502 :
1503 148 : ndir += reqd;
1504 148 : rem -= reqd;
1505 :
1506 : /* Try and align the struct for the next entry
1507 : on a valid pointer boundary by appending zeros */
1508 1080 : while((rem > 0) && ((uintptr_t)ndir & (sizeof(void*) - 1))) {
1509 932 : *ndir = '\0';
1510 932 : rem--;
1511 932 : ndir++;
1512 932 : currentEntry->dirlen++;
1513 : }
1514 :
1515 148 : dir->dir_next = dirlist = dirlist -> next;
1516 :
1517 : /*
1518 : * If we are returning file entries, we
1519 : * have a duplicate list in dirplus.
1520 : *
1521 : * Update dirplus_next also so readdir and
1522 : * readdirplus are kept in sync.
1523 : */
1524 148 : if (dir->dirplus_list != NULL) {
1525 148 : dir->dirplus_next = dir->dirplus_next->next;
1526 : }
1527 : }
1528 :
1529 0 : TALLOC_FREE(frame);
1530 :
1531 0 : if (rem == count)
1532 0 : return 0;
1533 : else
1534 0 : return count - rem;
1535 :
1536 : }
1537 :
1538 : /*
1539 : * Routine to create a directory ...
1540 : */
1541 :
1542 : int
1543 4 : SMBC_mkdir_ctx(SMBCCTX *context,
1544 : const char *fname,
1545 : mode_t mode)
1546 : {
1547 4 : SMBCSRV *srv = NULL;
1548 4 : char *server = NULL;
1549 4 : char *share = NULL;
1550 4 : char *user = NULL;
1551 4 : char *password = NULL;
1552 4 : char *workgroup = NULL;
1553 4 : char *path = NULL;
1554 4 : char *targetpath = NULL;
1555 4 : uint16_t port = 0;
1556 4 : struct cli_state *targetcli = NULL;
1557 4 : struct cli_credentials *creds = NULL;
1558 4 : TALLOC_CTX *frame = talloc_stackframe();
1559 0 : NTSTATUS status;
1560 :
1561 4 : if (!context || !context->internal->initialized) {
1562 0 : errno = EINVAL;
1563 0 : TALLOC_FREE(frame);
1564 0 : return -1;
1565 : }
1566 :
1567 4 : if (!fname) {
1568 0 : errno = EINVAL;
1569 0 : TALLOC_FREE(frame);
1570 0 : return -1;
1571 : }
1572 :
1573 4 : DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1574 :
1575 4 : if (SMBC_parse_path(frame,
1576 : context,
1577 : fname,
1578 : &workgroup,
1579 : &server,
1580 : &port,
1581 : &share,
1582 : &path,
1583 : &user,
1584 : &password,
1585 : NULL)) {
1586 0 : errno = EINVAL;
1587 0 : TALLOC_FREE(frame);
1588 0 : return -1;
1589 : }
1590 :
1591 4 : if (!user || user[0] == (char)0) {
1592 0 : user = talloc_strdup(frame, smbc_getUser(context));
1593 0 : if (!user) {
1594 0 : errno = ENOMEM;
1595 0 : TALLOC_FREE(frame);
1596 0 : return -1;
1597 : }
1598 : }
1599 :
1600 4 : srv = SMBC_server(frame, context, True,
1601 : server, port, share, &workgroup, &user, &password);
1602 :
1603 4 : if (!srv) {
1604 :
1605 0 : TALLOC_FREE(frame);
1606 0 : return -1; /* errno set by SMBC_server */
1607 :
1608 : }
1609 :
1610 4 : creds = context->internal->creds;
1611 :
1612 : /*d_printf(">>>mkdir: resolving %s\n", path);*/
1613 4 : status = cli_resolve_path(frame, "",
1614 : creds,
1615 : srv->cli, path, &targetcli, &targetpath);
1616 4 : if (!NT_STATUS_IS_OK(status)) {
1617 0 : d_printf("Could not resolve %s\n", path);
1618 0 : errno = ENOENT;
1619 0 : TALLOC_FREE(frame);
1620 0 : return -1;
1621 : }
1622 : /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1623 :
1624 4 : status = cli_mkdir(targetcli, targetpath);
1625 4 : if (!NT_STATUS_IS_OK(status)) {
1626 0 : TALLOC_FREE(frame);
1627 0 : errno = cli_status_to_errno(status);
1628 0 : return -1;
1629 :
1630 : }
1631 :
1632 4 : TALLOC_FREE(frame);
1633 4 : return 0;
1634 :
1635 : }
1636 :
1637 : /*
1638 : * Our list function simply checks to see if a directory is not empty
1639 : */
1640 :
1641 : static NTSTATUS
1642 0 : rmdir_list_fn(struct file_info *finfo,
1643 : const char *mask,
1644 : void *state)
1645 : {
1646 0 : if (strncmp(finfo->name, ".", 1) != 0 &&
1647 0 : strncmp(finfo->name, "..", 2) != 0) {
1648 0 : bool *smbc_rmdir_dirempty = (bool *)state;
1649 0 : *smbc_rmdir_dirempty = false;
1650 : }
1651 0 : return NT_STATUS_OK;
1652 : }
1653 :
1654 : /*
1655 : * Routine to remove a directory
1656 : */
1657 :
1658 : int
1659 8 : SMBC_rmdir_ctx(SMBCCTX *context,
1660 : const char *fname)
1661 : {
1662 8 : SMBCSRV *srv = NULL;
1663 8 : char *server = NULL;
1664 8 : char *share = NULL;
1665 8 : char *user = NULL;
1666 8 : char *password = NULL;
1667 8 : char *workgroup = NULL;
1668 8 : char *path = NULL;
1669 8 : char *targetpath = NULL;
1670 8 : uint16_t port = 0;
1671 8 : struct cli_state *targetcli = NULL;
1672 8 : struct cli_credentials *creds = NULL;
1673 8 : TALLOC_CTX *frame = talloc_stackframe();
1674 0 : NTSTATUS status;
1675 :
1676 8 : if (!context || !context->internal->initialized) {
1677 0 : errno = EINVAL;
1678 0 : TALLOC_FREE(frame);
1679 0 : return -1;
1680 : }
1681 :
1682 8 : if (!fname) {
1683 0 : errno = EINVAL;
1684 0 : TALLOC_FREE(frame);
1685 0 : return -1;
1686 : }
1687 :
1688 8 : DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1689 :
1690 8 : if (SMBC_parse_path(frame,
1691 : context,
1692 : fname,
1693 : &workgroup,
1694 : &server,
1695 : &port,
1696 : &share,
1697 : &path,
1698 : &user,
1699 : &password,
1700 : NULL)) {
1701 0 : errno = EINVAL;
1702 0 : TALLOC_FREE(frame);
1703 0 : return -1;
1704 : }
1705 :
1706 8 : if (!user || user[0] == (char)0) {
1707 0 : user = talloc_strdup(frame, smbc_getUser(context));
1708 0 : if (!user) {
1709 0 : errno = ENOMEM;
1710 0 : TALLOC_FREE(frame);
1711 0 : return -1;
1712 : }
1713 : }
1714 :
1715 8 : srv = SMBC_server(frame, context, True,
1716 : server, port, share, &workgroup, &user, &password);
1717 :
1718 8 : if (!srv) {
1719 :
1720 0 : TALLOC_FREE(frame);
1721 0 : return -1; /* errno set by SMBC_server */
1722 :
1723 : }
1724 :
1725 8 : creds = context->internal->creds;
1726 :
1727 : /*d_printf(">>>rmdir: resolving %s\n", path);*/
1728 8 : status = cli_resolve_path(frame, "",
1729 : creds,
1730 : srv->cli, path, &targetcli, &targetpath);
1731 8 : if (!NT_STATUS_IS_OK(status)) {
1732 0 : d_printf("Could not resolve %s\n", path);
1733 0 : errno = ENOENT;
1734 0 : TALLOC_FREE(frame);
1735 0 : return -1;
1736 : }
1737 : /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1738 :
1739 8 : status = cli_rmdir(targetcli, targetpath);
1740 :
1741 8 : if (!NT_STATUS_IS_OK(status)) {
1742 :
1743 4 : errno = cli_status_to_errno(status);
1744 :
1745 4 : if (errno == EACCES) { /* Check if the dir empty or not */
1746 :
1747 : /* Local storage to avoid buffer overflows */
1748 0 : char *lpath;
1749 0 : bool smbc_rmdir_dirempty = true;
1750 :
1751 0 : lpath = talloc_asprintf(frame, "%s\\*",
1752 : targetpath);
1753 0 : if (!lpath) {
1754 0 : errno = ENOMEM;
1755 0 : TALLOC_FREE(frame);
1756 0 : return -1;
1757 : }
1758 :
1759 0 : status = cli_list(targetcli, lpath,
1760 : FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
1761 : rmdir_list_fn,
1762 : &smbc_rmdir_dirempty);
1763 :
1764 0 : if (!NT_STATUS_IS_OK(status)) {
1765 : /* Fix errno to ignore latest error ... */
1766 0 : DBG_INFO("cli_list returned an error: %s\n",
1767 : nt_errstr(status));
1768 0 : errno = EACCES;
1769 :
1770 : }
1771 :
1772 0 : if (smbc_rmdir_dirempty)
1773 0 : errno = EACCES;
1774 : else
1775 0 : errno = ENOTEMPTY;
1776 :
1777 : }
1778 :
1779 4 : TALLOC_FREE(frame);
1780 4 : return -1;
1781 :
1782 : }
1783 :
1784 4 : TALLOC_FREE(frame);
1785 4 : return 0;
1786 :
1787 : }
1788 :
1789 : /*
1790 : * Routine to return the current directory position
1791 : */
1792 :
1793 : off_t
1794 8 : SMBC_telldir_ctx(SMBCCTX *context,
1795 : SMBCFILE *dir)
1796 : {
1797 8 : TALLOC_CTX *frame = talloc_stackframe();
1798 :
1799 8 : if (!context || !context->internal->initialized) {
1800 :
1801 0 : errno = EINVAL;
1802 0 : TALLOC_FREE(frame);
1803 0 : return -1;
1804 :
1805 : }
1806 :
1807 8 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
1808 :
1809 0 : errno = EBADF;
1810 0 : TALLOC_FREE(frame);
1811 0 : return -1;
1812 :
1813 : }
1814 :
1815 8 : if (dir->file != False) { /* FIXME, should be dir, perhaps */
1816 :
1817 0 : errno = ENOTDIR;
1818 0 : TALLOC_FREE(frame);
1819 0 : return -1;
1820 :
1821 : }
1822 :
1823 : /* See if we're already at the end. */
1824 8 : if (dir->dir_next == NULL) {
1825 : /* We are. */
1826 0 : TALLOC_FREE(frame);
1827 0 : return -1;
1828 : }
1829 :
1830 : /*
1831 : * We return the pointer here as the offset
1832 : */
1833 8 : TALLOC_FREE(frame);
1834 8 : return (off_t)(long)dir->dir_next->dirent;
1835 : }
1836 :
1837 : /*
1838 : * A routine to run down the list and see if the entry is OK
1839 : * Modifies the dir list and the dirplus list (if it exists)
1840 : * to point at the correct next entry on success.
1841 : */
1842 :
1843 16 : static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
1844 : {
1845 16 : struct smbc_dir_list *tmp_dir = dir->dir_list;
1846 16 : struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
1847 :
1848 : /*
1849 : * Run down the list looking for what we want.
1850 : * If we're enumerating files both dir_list
1851 : * and dirplus_list contain the same entry
1852 : * list, as they were seeded from the same
1853 : * cli_list callback.
1854 : *
1855 : * If we're enumerating servers then
1856 : * dirplus_list will be NULL, so don't
1857 : * update in that case.
1858 : */
1859 :
1860 448 : while (tmp_dir != NULL) {
1861 448 : if (tmp_dir->dirent == dirent) {
1862 16 : dir->dir_next = tmp_dir;
1863 16 : if (tmp_dirplus != NULL) {
1864 16 : dir->dirplus_next = tmp_dirplus;
1865 : }
1866 16 : return true;
1867 : }
1868 432 : tmp_dir = tmp_dir->next;
1869 432 : if (tmp_dirplus != NULL) {
1870 432 : tmp_dirplus = tmp_dirplus->next;
1871 : }
1872 : }
1873 0 : return false;
1874 : }
1875 :
1876 : /*
1877 : * Routine to seek on a directory
1878 : */
1879 :
1880 : int
1881 20 : SMBC_lseekdir_ctx(SMBCCTX *context,
1882 : SMBCFILE *dir,
1883 : off_t offset)
1884 : {
1885 20 : long int l_offset = offset; /* Handle problems of size */
1886 20 : struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
1887 20 : TALLOC_CTX *frame = talloc_stackframe();
1888 0 : bool ok;
1889 :
1890 20 : if (!context || !context->internal->initialized) {
1891 :
1892 0 : errno = EINVAL;
1893 0 : TALLOC_FREE(frame);
1894 0 : return -1;
1895 :
1896 : }
1897 :
1898 20 : if (dir->file != False) { /* FIXME, should be dir, perhaps */
1899 :
1900 0 : errno = ENOTDIR;
1901 0 : TALLOC_FREE(frame);
1902 0 : return -1;
1903 :
1904 : }
1905 :
1906 : /* Now, check what we were passed and see if it is OK ... */
1907 :
1908 20 : if (dirent == NULL) { /* Seek to the beginning of the list */
1909 :
1910 4 : dir->dir_next = dir->dir_list;
1911 :
1912 : /* Do the same for dirplus. */
1913 4 : dir->dirplus_next = dir->dirplus_list;
1914 :
1915 4 : TALLOC_FREE(frame);
1916 4 : return 0;
1917 :
1918 : }
1919 :
1920 16 : if (offset == -1) { /* Seek to the end of the list */
1921 0 : dir->dir_next = NULL;
1922 :
1923 : /* Do the same for dirplus. */
1924 0 : dir->dirplus_next = NULL;
1925 :
1926 0 : TALLOC_FREE(frame);
1927 0 : return 0;
1928 : }
1929 :
1930 : /*
1931 : * Run down the list and make sure that the entry is OK.
1932 : * Update the position of both dir and dirplus lists.
1933 : */
1934 :
1935 16 : ok = update_dir_ents(dir, dirent);
1936 16 : if (!ok) {
1937 0 : errno = EINVAL; /* Bad entry */
1938 0 : TALLOC_FREE(frame);
1939 0 : return -1;
1940 : }
1941 :
1942 16 : TALLOC_FREE(frame);
1943 16 : return 0;
1944 : }
1945 :
1946 : /*
1947 : * Routine to fstat a dir
1948 : */
1949 :
1950 : int
1951 0 : SMBC_fstatdir_ctx(SMBCCTX *context,
1952 : SMBCFILE *dir,
1953 : struct stat *st)
1954 : {
1955 :
1956 0 : if (!context || !context->internal->initialized) {
1957 :
1958 0 : errno = EINVAL;
1959 0 : return -1;
1960 : }
1961 :
1962 : /* No code yet ... */
1963 0 : return 0;
1964 : }
1965 :
1966 : int
1967 0 : SMBC_chmod_ctx(SMBCCTX *context,
1968 : const char *fname,
1969 : mode_t newmode)
1970 : {
1971 0 : SMBCSRV *srv = NULL;
1972 0 : char *server = NULL;
1973 0 : char *share = NULL;
1974 0 : char *user = NULL;
1975 0 : char *password = NULL;
1976 0 : char *workgroup = NULL;
1977 0 : char *targetpath = NULL;
1978 0 : struct cli_state *targetcli = NULL;
1979 0 : char *path = NULL;
1980 0 : uint32_t attr;
1981 0 : uint16_t port = 0;
1982 0 : struct cli_credentials *creds = NULL;
1983 0 : TALLOC_CTX *frame = talloc_stackframe();
1984 0 : NTSTATUS status;
1985 :
1986 0 : if (!context || !context->internal->initialized) {
1987 :
1988 0 : errno = EINVAL; /* Best I can think of ... */
1989 0 : TALLOC_FREE(frame);
1990 0 : return -1;
1991 : }
1992 :
1993 0 : if (!fname) {
1994 0 : errno = EINVAL;
1995 0 : TALLOC_FREE(frame);
1996 0 : return -1;
1997 : }
1998 :
1999 0 : DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
2000 :
2001 0 : if (SMBC_parse_path(frame,
2002 : context,
2003 : fname,
2004 : &workgroup,
2005 : &server,
2006 : &port,
2007 : &share,
2008 : &path,
2009 : &user,
2010 : &password,
2011 : NULL)) {
2012 0 : errno = EINVAL;
2013 0 : TALLOC_FREE(frame);
2014 0 : return -1;
2015 : }
2016 :
2017 0 : if (!user || user[0] == (char)0) {
2018 0 : user = talloc_strdup(frame, smbc_getUser(context));
2019 0 : if (!user) {
2020 0 : errno = ENOMEM;
2021 0 : TALLOC_FREE(frame);
2022 0 : return -1;
2023 : }
2024 : }
2025 :
2026 0 : srv = SMBC_server(frame, context, True,
2027 : server, port, share, &workgroup, &user, &password);
2028 :
2029 0 : if (!srv) {
2030 0 : TALLOC_FREE(frame);
2031 0 : return -1; /* errno set by SMBC_server */
2032 : }
2033 :
2034 0 : creds = context->internal->creds;
2035 :
2036 : /*d_printf(">>>unlink: resolving %s\n", path);*/
2037 0 : status = cli_resolve_path(frame, "",
2038 : creds,
2039 : srv->cli, path, &targetcli, &targetpath);
2040 0 : if (!NT_STATUS_IS_OK(status)) {
2041 0 : d_printf("Could not resolve %s\n", path);
2042 0 : errno = ENOENT;
2043 0 : TALLOC_FREE(frame);
2044 0 : return -1;
2045 : }
2046 :
2047 0 : attr = 0;
2048 :
2049 0 : if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) attr |= FILE_ATTRIBUTE_READONLY;
2050 0 : if ((newmode & S_IXUSR) && lp_map_archive(-1)) attr |= FILE_ATTRIBUTE_ARCHIVE;
2051 0 : if ((newmode & S_IXGRP) && lp_map_system(-1)) attr |= FILE_ATTRIBUTE_SYSTEM;
2052 0 : if ((newmode & S_IXOTH) && lp_map_hidden(-1)) attr |= FILE_ATTRIBUTE_HIDDEN;
2053 :
2054 0 : status = cli_setatr(targetcli, targetpath, attr, 0);
2055 0 : if (!NT_STATUS_IS_OK(status)) {
2056 0 : TALLOC_FREE(frame);
2057 0 : errno = cli_status_to_errno(status);
2058 0 : return -1;
2059 : }
2060 :
2061 0 : TALLOC_FREE(frame);
2062 0 : return 0;
2063 : }
2064 :
2065 : int
2066 4 : SMBC_utimes_ctx(SMBCCTX *context,
2067 : const char *fname,
2068 : struct timeval *tbuf)
2069 : {
2070 4 : SMBCSRV *srv = NULL;
2071 4 : char *server = NULL;
2072 4 : char *share = NULL;
2073 4 : char *user = NULL;
2074 4 : char *password = NULL;
2075 4 : char *workgroup = NULL;
2076 4 : char *path = NULL;
2077 0 : struct timespec access_time, write_time;
2078 4 : uint16_t port = 0;
2079 4 : TALLOC_CTX *frame = talloc_stackframe();
2080 0 : bool ok;
2081 :
2082 4 : if (!context || !context->internal->initialized) {
2083 :
2084 0 : errno = EINVAL; /* Best I can think of ... */
2085 0 : TALLOC_FREE(frame);
2086 0 : return -1;
2087 : }
2088 :
2089 4 : if (!fname) {
2090 0 : errno = EINVAL;
2091 0 : TALLOC_FREE(frame);
2092 0 : return -1;
2093 : }
2094 :
2095 4 : if (tbuf == NULL) {
2096 0 : access_time = write_time = timespec_current();
2097 : } else {
2098 4 : access_time = convert_timeval_to_timespec(tbuf[0]);
2099 4 : write_time = convert_timeval_to_timespec(tbuf[1]);
2100 : }
2101 :
2102 4 : if (DEBUGLVL(4)) {
2103 0 : struct timeval_buf abuf, wbuf;
2104 :
2105 0 : dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
2106 : fname,
2107 : timespec_string_buf(&access_time, false, &abuf),
2108 : timespec_string_buf(&write_time, false, &wbuf));
2109 : }
2110 :
2111 4 : if (SMBC_parse_path(frame,
2112 : context,
2113 : fname,
2114 : &workgroup,
2115 : &server,
2116 : &port,
2117 : &share,
2118 : &path,
2119 : &user,
2120 : &password,
2121 : NULL)) {
2122 0 : errno = EINVAL;
2123 0 : TALLOC_FREE(frame);
2124 0 : return -1;
2125 : }
2126 :
2127 4 : if (!user || user[0] == (char)0) {
2128 0 : user = talloc_strdup(frame, smbc_getUser(context));
2129 0 : if (!user) {
2130 0 : errno = ENOMEM;
2131 0 : TALLOC_FREE(frame);
2132 0 : return -1;
2133 : }
2134 : }
2135 :
2136 4 : srv = SMBC_server(frame, context, True,
2137 : server, port, share, &workgroup, &user, &password);
2138 :
2139 4 : if (!srv) {
2140 0 : TALLOC_FREE(frame);
2141 0 : return -1; /* errno set by SMBC_server */
2142 : }
2143 :
2144 4 : ok = SMBC_setatr(
2145 : context,
2146 : srv,
2147 : path,
2148 4 : (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
2149 : access_time,
2150 : write_time,
2151 4 : (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
2152 : 0);
2153 4 : if (!ok) {
2154 0 : TALLOC_FREE(frame);
2155 0 : return -1; /* errno set by SMBC_setatr */
2156 : }
2157 :
2158 4 : TALLOC_FREE(frame);
2159 4 : return 0;
2160 : }
2161 :
2162 : /*
2163 : * Routine to unlink() a file
2164 : */
2165 :
2166 : int
2167 848 : SMBC_unlink_ctx(SMBCCTX *context,
2168 : const char *fname)
2169 : {
2170 848 : char *server = NULL;
2171 848 : char *share = NULL;
2172 848 : char *user = NULL;
2173 848 : char *password = NULL;
2174 848 : char *workgroup = NULL;
2175 848 : char *path = NULL;
2176 848 : char *targetpath = NULL;
2177 848 : uint16_t port = 0;
2178 848 : struct cli_state *targetcli = NULL;
2179 848 : SMBCSRV *srv = NULL;
2180 848 : struct cli_credentials *creds = NULL;
2181 848 : TALLOC_CTX *frame = talloc_stackframe();
2182 0 : NTSTATUS status;
2183 :
2184 848 : if (!context || !context->internal->initialized) {
2185 :
2186 0 : errno = EINVAL; /* Best I can think of ... */
2187 0 : TALLOC_FREE(frame);
2188 0 : return -1;
2189 :
2190 : }
2191 :
2192 848 : if (!fname) {
2193 0 : errno = EINVAL;
2194 0 : TALLOC_FREE(frame);
2195 0 : return -1;
2196 :
2197 : }
2198 :
2199 848 : if (SMBC_parse_path(frame,
2200 : context,
2201 : fname,
2202 : &workgroup,
2203 : &server,
2204 : &port,
2205 : &share,
2206 : &path,
2207 : &user,
2208 : &password,
2209 : NULL)) {
2210 0 : errno = EINVAL;
2211 0 : TALLOC_FREE(frame);
2212 0 : return -1;
2213 : }
2214 :
2215 848 : if (!user || user[0] == (char)0) {
2216 0 : user = talloc_strdup(frame, smbc_getUser(context));
2217 0 : if (!user) {
2218 0 : errno = ENOMEM;
2219 0 : TALLOC_FREE(frame);
2220 0 : return -1;
2221 : }
2222 : }
2223 :
2224 848 : srv = SMBC_server(frame, context, True,
2225 : server, port, share, &workgroup, &user, &password);
2226 :
2227 848 : if (!srv) {
2228 0 : TALLOC_FREE(frame);
2229 0 : return -1; /* SMBC_server sets errno */
2230 :
2231 : }
2232 :
2233 848 : creds = context->internal->creds;
2234 :
2235 : /*d_printf(">>>unlink: resolving %s\n", path);*/
2236 848 : status = cli_resolve_path(frame, "",
2237 : creds,
2238 : srv->cli, path, &targetcli, &targetpath);
2239 848 : if (!NT_STATUS_IS_OK(status)) {
2240 0 : d_printf("Could not resolve %s\n", path);
2241 0 : errno = ENOENT;
2242 0 : TALLOC_FREE(frame);
2243 0 : return -1;
2244 : }
2245 : /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
2246 :
2247 848 : status = cli_unlink(
2248 : targetcli,
2249 : targetpath,
2250 : FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2251 :
2252 848 : if (!NT_STATUS_IS_OK(status)) {
2253 :
2254 428 : errno = cli_status_to_errno(status);
2255 :
2256 428 : if (errno == EACCES) { /* Check if the file is a directory */
2257 :
2258 0 : int saverr = errno;
2259 0 : struct stat sb = {0};
2260 :
2261 0 : status = SMBC_getatr(context, srv, path, &sb);
2262 0 : if (!NT_STATUS_IS_OK(status)) {
2263 : /* Hmmm, bad error ... What? */
2264 :
2265 0 : TALLOC_FREE(frame);
2266 0 : errno = cli_status_to_errno(status);
2267 0 : return -1;
2268 :
2269 : }
2270 : else {
2271 :
2272 0 : if (S_ISDIR(sb.st_mode))
2273 0 : errno = EISDIR;
2274 : else
2275 0 : errno = saverr; /* Restore this */
2276 :
2277 : }
2278 : }
2279 :
2280 428 : TALLOC_FREE(frame);
2281 428 : return -1;
2282 :
2283 : }
2284 :
2285 420 : TALLOC_FREE(frame);
2286 420 : return 0; /* Success ... */
2287 :
2288 : }
2289 :
2290 : /*
2291 : * Routine to rename() a file
2292 : */
2293 :
2294 : int
2295 4 : SMBC_rename_ctx(SMBCCTX *ocontext,
2296 : const char *oname,
2297 : SMBCCTX *ncontext,
2298 : const char *nname)
2299 : {
2300 4 : char *server1 = NULL;
2301 4 : char *share1 = NULL;
2302 4 : char *server2 = NULL;
2303 4 : char *share2 = NULL;
2304 4 : char *user1 = NULL;
2305 4 : char *user2 = NULL;
2306 4 : char *password1 = NULL;
2307 4 : char *password2 = NULL;
2308 4 : char *workgroup = NULL;
2309 4 : char *path1 = NULL;
2310 4 : char *path2 = NULL;
2311 4 : char *targetpath1 = NULL;
2312 4 : char *targetpath2 = NULL;
2313 4 : struct cli_state *targetcli1 = NULL;
2314 4 : struct cli_state *targetcli2 = NULL;
2315 4 : SMBCSRV *srv = NULL;
2316 4 : uint16_t port1 = 0;
2317 4 : uint16_t port2 = 0;
2318 4 : struct cli_credentials *ocreds = NULL;
2319 4 : struct cli_credentials *ncreds = NULL;
2320 4 : TALLOC_CTX *frame = talloc_stackframe();
2321 0 : NTSTATUS status;
2322 :
2323 4 : if (!ocontext || !ncontext ||
2324 4 : !ocontext->internal->initialized ||
2325 4 : !ncontext->internal->initialized) {
2326 :
2327 0 : errno = EINVAL; /* Best I can think of ... */
2328 0 : TALLOC_FREE(frame);
2329 0 : return -1;
2330 : }
2331 :
2332 4 : if (!oname || !nname) {
2333 0 : errno = EINVAL;
2334 0 : TALLOC_FREE(frame);
2335 0 : return -1;
2336 : }
2337 :
2338 4 : DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
2339 :
2340 4 : if (SMBC_parse_path(frame,
2341 : ocontext,
2342 : oname,
2343 : &workgroup,
2344 : &server1,
2345 : &port1,
2346 : &share1,
2347 : &path1,
2348 : &user1,
2349 : &password1,
2350 : NULL)) {
2351 0 : errno = EINVAL;
2352 0 : TALLOC_FREE(frame);
2353 0 : return -1;
2354 : }
2355 :
2356 4 : if (!user1 || user1[0] == (char)0) {
2357 0 : user1 = talloc_strdup(frame, smbc_getUser(ocontext));
2358 0 : if (!user1) {
2359 0 : errno = ENOMEM;
2360 0 : TALLOC_FREE(frame);
2361 0 : return -1;
2362 : }
2363 : }
2364 :
2365 4 : if (SMBC_parse_path(frame,
2366 : ncontext,
2367 : nname,
2368 : NULL,
2369 : &server2,
2370 : &port2,
2371 : &share2,
2372 : &path2,
2373 : &user2,
2374 : &password2,
2375 : NULL)) {
2376 0 : errno = EINVAL;
2377 0 : TALLOC_FREE(frame);
2378 0 : return -1;
2379 : }
2380 :
2381 4 : if (!user2 || user2[0] == (char)0) {
2382 0 : user2 = talloc_strdup(frame, smbc_getUser(ncontext));
2383 0 : if (!user2) {
2384 0 : errno = ENOMEM;
2385 0 : TALLOC_FREE(frame);
2386 0 : return -1;
2387 : }
2388 : }
2389 :
2390 4 : if (strcmp(server1, server2) || strcmp(share1, share2) ||
2391 4 : strcmp(user1, user2)) {
2392 : /* Can't rename across file systems, or users?? */
2393 0 : errno = EXDEV;
2394 0 : TALLOC_FREE(frame);
2395 0 : return -1;
2396 : }
2397 :
2398 4 : srv = SMBC_server(frame, ocontext, True,
2399 : server1, port1, share1, &workgroup, &user1, &password1);
2400 4 : if (!srv) {
2401 0 : TALLOC_FREE(frame);
2402 0 : return -1;
2403 :
2404 : }
2405 :
2406 : /* set the credentials to make DFS work */
2407 4 : smbc_set_credentials_with_fallback(ocontext,
2408 : workgroup,
2409 : user1,
2410 : password1);
2411 :
2412 : /*d_printf(">>>rename: resolving %s\n", path1);*/
2413 4 : ocreds = ocontext->internal->creds;
2414 :
2415 4 : status = cli_resolve_path(frame, "",
2416 : ocreds,
2417 : srv->cli, path1, &targetcli1, &targetpath1);
2418 4 : if (!NT_STATUS_IS_OK(status)) {
2419 0 : d_printf("Could not resolve %s\n", path1);
2420 0 : errno = ENOENT;
2421 0 : TALLOC_FREE(frame);
2422 0 : return -1;
2423 : }
2424 :
2425 : /* set the credentials to make DFS work */
2426 4 : smbc_set_credentials_with_fallback(ncontext,
2427 : workgroup,
2428 : user2,
2429 : password2);
2430 :
2431 : /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
2432 : /*d_printf(">>>rename: resolving %s\n", path2);*/
2433 4 : ncreds = ncontext->internal->creds;
2434 :
2435 4 : status = cli_resolve_path(frame, "",
2436 : ncreds,
2437 : srv->cli, path2, &targetcli2, &targetpath2);
2438 4 : if (!NT_STATUS_IS_OK(status)) {
2439 0 : d_printf("Could not resolve %s\n", path2);
2440 0 : errno = ENOENT;
2441 0 : TALLOC_FREE(frame);
2442 0 : return -1;
2443 : }
2444 : /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
2445 :
2446 4 : if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
2447 4 : strcmp(targetcli1->share, targetcli2->share))
2448 : {
2449 : /* can't rename across file systems */
2450 0 : errno = EXDEV;
2451 0 : TALLOC_FREE(frame);
2452 0 : return -1;
2453 : }
2454 :
2455 4 : status = cli_rename(targetcli1, targetpath1, targetpath2, false);
2456 4 : if (!NT_STATUS_IS_OK(status)) {
2457 4 : int eno = cli_status_to_errno(status);
2458 :
2459 4 : if (eno != EEXIST ||
2460 4 : !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
2461 : FILE_ATTRIBUTE_SYSTEM |
2462 4 : FILE_ATTRIBUTE_HIDDEN)) ||
2463 4 : !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
2464 : targetpath2, false))) {
2465 :
2466 0 : errno = eno;
2467 0 : TALLOC_FREE(frame);
2468 0 : return -1;
2469 :
2470 : }
2471 : }
2472 :
2473 4 : TALLOC_FREE(frame);
2474 4 : return 0; /* Success */
2475 : }
2476 :
2477 : struct smbc_notify_cb_state {
2478 : struct tevent_context *ev;
2479 : struct cli_state *cli;
2480 : uint16_t fnum;
2481 : bool recursive;
2482 : uint32_t completion_filter;
2483 : unsigned callback_timeout_ms;
2484 : smbc_notify_callback_fn cb;
2485 : void *private_data;
2486 : };
2487 :
2488 : static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
2489 : static void smbc_notify_cb_timedout(struct tevent_req *subreq);
2490 :
2491 0 : static struct tevent_req *smbc_notify_cb_send(
2492 : TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
2493 : uint16_t fnum, bool recursive, uint32_t completion_filter,
2494 : unsigned callback_timeout_ms,
2495 : smbc_notify_callback_fn cb, void *private_data)
2496 : {
2497 0 : struct tevent_req *req, *subreq;
2498 0 : struct smbc_notify_cb_state *state;
2499 :
2500 0 : req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
2501 0 : if (req == NULL) {
2502 0 : return NULL;
2503 : }
2504 0 : state->ev = ev;
2505 0 : state->cli = cli;
2506 0 : state->fnum = fnum;
2507 0 : state->recursive = recursive;
2508 0 : state->completion_filter = completion_filter;
2509 0 : state->callback_timeout_ms = callback_timeout_ms;
2510 0 : state->cb = cb;
2511 0 : state->private_data = private_data;
2512 :
2513 0 : subreq = cli_notify_send(
2514 0 : state, state->ev, state->cli, state->fnum, 1000,
2515 0 : state->completion_filter, state->recursive);
2516 0 : if (tevent_req_nomem(subreq, req)) {
2517 0 : return tevent_req_post(req, ev);
2518 : }
2519 0 : tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2520 :
2521 0 : if (state->callback_timeout_ms == 0) {
2522 0 : return req;
2523 : }
2524 :
2525 0 : subreq = tevent_wakeup_send(
2526 0 : state, state->ev,
2527 0 : tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2528 0 : state->callback_timeout_ms*1000));
2529 0 : if (tevent_req_nomem(subreq, req)) {
2530 0 : return tevent_req_post(req, ev);
2531 : }
2532 0 : tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2533 :
2534 0 : return req;
2535 : }
2536 :
2537 0 : static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
2538 : {
2539 0 : struct tevent_req *req = tevent_req_callback_data(
2540 : subreq, struct tevent_req);
2541 0 : struct smbc_notify_cb_state *state = tevent_req_data(
2542 : req, struct smbc_notify_cb_state);
2543 0 : uint32_t num_changes;
2544 0 : struct notify_change *changes;
2545 0 : NTSTATUS status;
2546 0 : int cb_ret;
2547 :
2548 0 : status = cli_notify_recv(subreq, state, &num_changes, &changes);
2549 0 : TALLOC_FREE(subreq);
2550 0 : if (tevent_req_nterror(req, status)) {
2551 0 : return;
2552 : }
2553 :
2554 0 : {
2555 0 : struct smbc_notify_callback_action actions[num_changes];
2556 0 : uint32_t i;
2557 :
2558 0 : for (i=0; i<num_changes; i++) {
2559 0 : actions[i].action = changes[i].action;
2560 0 : actions[i].filename = changes[i].name;
2561 : }
2562 :
2563 0 : cb_ret = state->cb(actions, num_changes, state->private_data);
2564 : }
2565 :
2566 0 : TALLOC_FREE(changes);
2567 :
2568 0 : if (cb_ret != 0) {
2569 0 : tevent_req_done(req);
2570 0 : return;
2571 : }
2572 :
2573 0 : subreq = cli_notify_send(
2574 0 : state, state->ev, state->cli, state->fnum, 1000,
2575 0 : state->completion_filter, state->recursive);
2576 0 : if (tevent_req_nomem(subreq, req)) {
2577 0 : return;
2578 : }
2579 0 : tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2580 : }
2581 :
2582 0 : static void smbc_notify_cb_timedout(struct tevent_req *subreq)
2583 : {
2584 0 : struct tevent_req *req = tevent_req_callback_data(
2585 : subreq, struct tevent_req);
2586 0 : struct smbc_notify_cb_state *state = tevent_req_data(
2587 : req, struct smbc_notify_cb_state);
2588 0 : int cb_ret;
2589 0 : bool ok;
2590 :
2591 0 : ok = tevent_wakeup_recv(subreq);
2592 0 : TALLOC_FREE(subreq);
2593 0 : if (!ok) {
2594 0 : tevent_req_oom(req);
2595 0 : return;
2596 : }
2597 :
2598 0 : cb_ret = state->cb(NULL, 0, state->private_data);
2599 0 : if (cb_ret != 0) {
2600 0 : tevent_req_done(req);
2601 0 : return;
2602 : }
2603 :
2604 0 : subreq = tevent_wakeup_send(
2605 : state, state->ev,
2606 0 : tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2607 0 : state->callback_timeout_ms*1000));
2608 0 : if (tevent_req_nomem(subreq, req)) {
2609 0 : return;
2610 : }
2611 0 : tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2612 : }
2613 :
2614 0 : static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
2615 : {
2616 0 : return tevent_req_simple_recv_ntstatus(req);
2617 : }
2618 :
2619 0 : static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
2620 : bool recursive, uint32_t completion_filter,
2621 : unsigned callback_timeout_ms,
2622 : smbc_notify_callback_fn cb, void *private_data)
2623 : {
2624 0 : TALLOC_CTX *frame = talloc_stackframe();
2625 0 : struct tevent_context *ev;
2626 0 : struct tevent_req *req;
2627 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
2628 :
2629 0 : ev = samba_tevent_context_init(frame);
2630 0 : if (ev == NULL) {
2631 0 : goto fail;
2632 : }
2633 0 : req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
2634 : completion_filter,
2635 : callback_timeout_ms, cb, private_data);
2636 0 : if (req == NULL) {
2637 0 : goto fail;
2638 : }
2639 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2640 0 : goto fail;
2641 : }
2642 0 : status = smbc_notify_cb_recv(req);
2643 0 : TALLOC_FREE(req);
2644 0 : fail:
2645 0 : TALLOC_FREE(frame);
2646 0 : return status;
2647 : }
2648 :
2649 : int
2650 0 : SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
2651 : uint32_t completion_filter, unsigned callback_timeout_ms,
2652 : smbc_notify_callback_fn cb, void *private_data)
2653 : {
2654 0 : TALLOC_CTX *frame = talloc_stackframe();
2655 0 : struct cli_state *cli;
2656 0 : char *server = NULL;
2657 0 : char *share = NULL;
2658 0 : char *user = NULL;
2659 0 : char *password = NULL;
2660 0 : char *options = NULL;
2661 0 : char *workgroup = NULL;
2662 0 : char *path = NULL;
2663 0 : uint16_t port;
2664 0 : NTSTATUS status;
2665 0 : uint16_t fnum;
2666 :
2667 0 : if ((context == NULL) || !context->internal->initialized) {
2668 0 : TALLOC_FREE(frame);
2669 0 : errno = EINVAL;
2670 0 : return -1;
2671 : }
2672 0 : if (!SMBC_dlist_contains(context->internal->files, dir)) {
2673 0 : TALLOC_FREE(frame);
2674 0 : errno = EBADF;
2675 0 : return -1;
2676 : }
2677 :
2678 0 : if (SMBC_parse_path(frame,
2679 : context,
2680 0 : dir->fname,
2681 : &workgroup,
2682 : &server,
2683 : &port,
2684 : &share,
2685 : &path,
2686 : &user,
2687 : &password,
2688 : &options)) {
2689 0 : DEBUG(4, ("no valid path\n"));
2690 0 : TALLOC_FREE(frame);
2691 0 : errno = EINVAL + 8194;
2692 0 : return -1;
2693 : }
2694 :
2695 0 : DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
2696 : "path='%s' options='%s'\n",
2697 : dir->fname, server, share, path, options));
2698 :
2699 0 : DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
2700 : (int)recursive, completion_filter));
2701 :
2702 0 : cli = dir->srv->cli;
2703 0 : status = cli_ntcreate(
2704 : cli, path, 0, FILE_READ_DATA, 0,
2705 : FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2706 : FILE_OPEN, 0, 0, &fnum, NULL);
2707 0 : if (!NT_STATUS_IS_OK(status)) {
2708 0 : TALLOC_FREE(frame);
2709 0 : errno = cli_status_to_errno(status);
2710 0 : return -1;
2711 : }
2712 :
2713 0 : status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
2714 : callback_timeout_ms, cb, private_data);
2715 0 : if (!NT_STATUS_IS_OK(status)) {
2716 0 : cli_close(cli, fnum);
2717 0 : TALLOC_FREE(frame);
2718 0 : errno = cli_status_to_errno(status);
2719 0 : return -1;
2720 : }
2721 :
2722 0 : cli_close(cli, fnum);
2723 :
2724 0 : TALLOC_FREE(frame);
2725 0 : return 0;
2726 : }
|