libsmb_dir.c 65.5 KB
Newer Older
1
/*
2
3
4
5
6
   Unix SMB/Netbios implementation.
   SMB client library implementation
   Copyright (C) Andrew Tridgell 1998
   Copyright (C) Richard Sharpe 2000, 2002
   Copyright (C) John Terpstra 2000
7
   Copyright (C) Tom Jansen (Ninja ISD) 2002
8
9
   Copyright (C) Derrell Lipman 2003-2008
   Copyright (C) Jeremy Allison 2007, 2008
10

11
12
13
14
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
15

16
17
18
19
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
20

21
22
23
24
25
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "includes.h"
VL's avatar
VL committed
26
#include "libsmb/namequery.h"
27
#include "libsmb/libsmb.h"
28
29
#include "libsmbclient.h"
#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"
VL's avatar
VL committed
34
35
#include "../libcli/security/security.h"
#include "lib/util/tevent_ntstatus.h"
36
#include "lib/util/time_basic.h"
37
#include "lib/util/string_wrappers.h"
38
39
40
41
42
43

/*
 * Routine to open a directory
 * We accept the URL syntax explained in SMBC_parse_path(), above.
 */

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static void remove_dirplus(SMBCFILE *dir)
{
	struct smbc_dirplus_list *d = NULL;

	d = dir->dirplus_list;
	while (d != NULL) {
		struct smbc_dirplus_list *f = d;
		d = d->next;

		SAFE_FREE(f->smb_finfo->short_name);
		SAFE_FREE(f->smb_finfo->name);
		SAFE_FREE(f->smb_finfo);
		SAFE_FREE(f);
	}

	dir->dirplus_list = NULL;
	dir->dirplus_end = NULL;
	dir->dirplus_next = NULL;
}

64
65
66
67
static void
remove_dir(SMBCFILE *dir)
{
	struct smbc_dir_list *d,*f;
68

69
70
	d = dir->dir_list;
	while (d) {
71

72
		f = d; d = d->next;
73

74
75
		SAFE_FREE(f->dirent);
		SAFE_FREE(f);
76

77
	}
78

79
	dir->dir_list = dir->dir_end = dir->dir_next = NULL;
80

81
82
83
84
85
86
}

static int
add_dirent(SMBCFILE *dir,
           const char *name,
           const char *comment,
87
           uint32_t type)
88
89
90
91
92
{
	struct smbc_dirent *dirent;
	int size;
        int name_length = (name == NULL ? 0 : strlen(name));
        int comment_len = (comment == NULL ? 0 : strlen(comment));
93

94
	/*
95
	 * Allocate space for the dirent, which must be increased by the
96
97
	 * size of the name and the comment and 1 each for the null terminator.
	 */
98

99
	size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
100

101
	dirent = (struct smbc_dirent *)SMB_MALLOC(size);
102

103
	if (!dirent) {
104

105
106
		dir->dir_error = ENOMEM;
		return -1;
107

108
	}
109

110
	ZERO_STRUCTP(dirent);
111

112
	if (dir->dir_list == NULL) {
113

114
115
		dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
		if (!dir->dir_list) {
116

117
118
119
			SAFE_FREE(dirent);
			dir->dir_error = ENOMEM;
			return -1;
120

121
122
		}
		ZERO_STRUCTP(dir->dir_list);
123

124
125
126
		dir->dir_end = dir->dir_next = dir->dir_list;
	}
	else {
127

128
		dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
129

130
		if (!dir->dir_end->next) {
131

132
133
134
			SAFE_FREE(dirent);
			dir->dir_error = ENOMEM;
			return -1;
135

136
137
		}
		ZERO_STRUCTP(dir->dir_end->next);
138

139
140
		dir->dir_end = dir->dir_end->next;
	}
141

142
143
	dir->dir_end->next = NULL;
	dir->dir_end->dirent = dirent;
144

145
146
147
148
	dirent->smbc_type = type;
	dirent->namelen = name_length;
	dirent->commentlen = comment_len;
	dirent->dirlen = size;
149

150
151
152
153
154
155
156
157
        /*
         * dirent->namelen + 1 includes the null (no null termination needed)
         * Ditto for dirent->commentlen.
         * The space for the two null bytes was allocated.
         */
	strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
	dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
	strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
158

159
	return 0;
160

161
162
}

163
164
165
166
167
168
169
170
171
172
173
static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
{
	struct smbc_dirplus_list *new_entry = NULL;
	struct libsmb_file_info *info = NULL;

	new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
	if (new_entry == NULL) {
		dir->dir_error = ENOMEM;
		return -1;
	}
	ZERO_STRUCTP(new_entry);
174
	new_entry->ino = finfo->ino;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

	info = SMB_MALLOC_P(struct libsmb_file_info);
	if (info == NULL) {
		SAFE_FREE(new_entry);
		dir->dir_error = ENOMEM;
		return -1;
	}

	ZERO_STRUCTP(info);

	info->btime_ts = finfo->btime_ts;
	info->atime_ts = finfo->atime_ts;
	info->ctime_ts = finfo->ctime_ts;
	info->mtime_ts = finfo->mtime_ts;
	info->gid = finfo->gid;
190
	info->attrs = finfo->attr;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
	info->size = finfo->size;
	info->uid = finfo->uid;
	info->name = SMB_STRDUP(finfo->name);
	if (info->name == NULL) {
		SAFE_FREE(info);
		SAFE_FREE(new_entry);
		dir->dir_error = ENOMEM;
		return -1;
	}

	if (finfo->short_name) {
		info->short_name = SMB_STRDUP(finfo->short_name);
	} else {
		info->short_name = SMB_STRDUP("");
	}

	if (info->short_name == NULL) {
		SAFE_FREE(info->name);
		SAFE_FREE(info);
		SAFE_FREE(new_entry);
		dir->dir_error = ENOMEM;
		return -1;
	}
	new_entry->smb_finfo = info;

	/* Now add to the list. */
	if (dir->dirplus_list == NULL) {
		/* Empty list - point everything at new_entry. */
		dir->dirplus_list = new_entry;
		dir->dirplus_end = new_entry;
		dir->dirplus_next = new_entry;
	} else {
		/* Append to list but leave the ->next cursor alone. */
		dir->dirplus_end->next = new_entry;
		dir->dirplus_end = new_entry;
	}

	return 0;
}

231
232
static void
list_unique_wg_fn(const char *name,
233
                  uint32_t type,
234
235
236
237
238
239
240
241
                  const char *comment,
                  void *state)
{
	SMBCFILE *dir = (SMBCFILE *)state;
        struct smbc_dir_list *dir_list;
        struct smbc_dirent *dirent;
	int dirent_type;
        int do_remove = 0;
242

243
	dirent_type = dir->dir_type;
244

245
246
247
	if (add_dirent(dir, name, comment, dirent_type) < 0) {
		/* An error occurred, what do we do? */
		/* FIXME: Add some code here */
248
249
		/* Change cli_NetServerEnum to take a fn
		   returning NTSTATUS... JRA. */
250
	}
251

252
253
        /* Point to the one just added */
        dirent = dir->dir_end->dirent;
254

255
256
257
258
259
260
261
262
263
        /* See if this was a duplicate */
        for (dir_list = dir->dir_list;
             dir_list != dir->dir_end;
             dir_list = dir_list->next) {
                if (! do_remove &&
                    strcmp(dir_list->dirent->name, dirent->name) == 0) {
                        /* Duplicate.  End end of list need to be removed. */
                        do_remove = 1;
                }
264

265
266
267
268
269
270
271
272
273
274
275
276
277
                if (do_remove && dir_list->next == dir->dir_end) {
                        /* Found the end of the list.  Remove it. */
                        dir->dir_end = dir_list;
                        free(dir_list->next);
                        free(dirent);
                        dir_list->next = NULL;
                        break;
                }
        }
}

static void
list_fn(const char *name,
278
        uint32_t type,
279
280
281
282
283
        const char *comment,
        void *state)
{
	SMBCFILE *dir = (SMBCFILE *)state;
	int dirent_type;
284

285
286
287
288
289
290
291
292
293
294
295
	/*
         * We need to process the type a little ...
         *
         * Disk share     = 0x00000000
         * Print share    = 0x00000001
         * Comms share    = 0x00000002 (obsolete?)
         * IPC$ share     = 0x00000003
         *
         * administrative shares:
         * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
         */
296

297
298
299
300
301
302
	if (dir->dir_type == SMBC_FILE_SHARE) {
		switch (type) {
                case 0 | 0x80000000:
		case 0:
			dirent_type = SMBC_FILE_SHARE;
			break;
303

304
305
306
		case 1:
			dirent_type = SMBC_PRINTER_SHARE;
			break;
307

308
309
310
		case 2:
			dirent_type = SMBC_COMMS_SHARE;
			break;
311

312
313
314
315
                case 3 | 0x80000000:
		case 3:
			dirent_type = SMBC_IPC_SHARE;
			break;
316

317
318
319
320
321
322
323
324
		default:
			dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
			break;
		}
	}
	else {
                dirent_type = dir->dir_type;
        }
325

326
327
328
	if (add_dirent(dir, name, comment, dirent_type) < 0) {
		/* An error occurred, what do we do? */
		/* FIXME: Add some code here */
329
330
		/* Change cli_NetServerEnum to take a fn
		   returning NTSTATUS... JRA. */
331
332
333
	}
}

334
static NTSTATUS
335
dir_list_fn(struct file_info *finfo,
336
337
338
            const char *mask,
            void *state)
{
339
340
	SMBCFILE *dirp = (SMBCFILE *)state;
	int ret;
341
342

	if (add_dirent((SMBCFILE *)state, finfo->name, "",
343
		       (finfo->attr&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
344
345
		SMBCFILE *dir = (SMBCFILE *)state;
		return map_nt_error_from_unix(dir->dir_error);
346
	}
347
348
349
350
	ret = add_dirplus(dirp, finfo);
	if (ret < 0) {
		return map_nt_error_from_unix(dirp->dir_error);
	}
351
	return NT_STATUS_OK;
352
353
}

354
static NTSTATUS
355
356
net_share_enum_rpc(struct cli_state *cli,
                   void (*fn)(const char *name,
357
                              uint32_t type,
358
359
360
361
                              const char *comment,
                              void *state),
                   void *state)
{
362
        uint32_t i;
363
	WERROR result;
364
365
	uint32_t preferred_len = 0xffffffff;
        uint32_t type;
366
367
	struct srvsvc_NetShareInfoCtr info_ctr;
	struct srvsvc_NetShareCtr1 ctr1;
368
369
	fstring name = "";
        fstring comment = "";
370
	struct rpc_pipe_client *pipe_hnd = NULL;
371
        NTSTATUS nt_status;
372
373
	uint32_t resume_handle = 0;
	uint32_t total_entries = 0;
374
	struct dcerpc_binding_handle *b;
375

376
        /* Open the server service pipe */
377
        nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
378
379
					     &pipe_hnd);
        if (!NT_STATUS_IS_OK(nt_status)) {
380
                DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
381
		goto done;
382
        }
383

384
385
386
387
388
389
	ZERO_STRUCT(info_ctr);
	ZERO_STRUCT(ctr1);

	info_ctr.level = 1;
	info_ctr.ctr.ctr1 = &ctr1;

390
391
	b = pipe_hnd->binding_handle;

392
        /* Issue the NetShareEnum RPC call and retrieve the response */
393
	nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
VL's avatar
VL committed
394
						  pipe_hnd->desthost,
395
396
397
398
399
						  &info_ctr,
						  preferred_len,
						  &total_entries,
						  &resume_handle,
						  &result);
400

401
        /* Was it successful? */
402
403
404
405
406
407
	if (!NT_STATUS_IS_OK(nt_status)) {
                /*  Nope.  Go clean up. */
		goto done;
	}

	if (!W_ERROR_IS_OK(result)) {
408
                /*  Nope.  Go clean up. */
409
		nt_status = werror_to_ntstatus(result);
410
411
		goto done;
        }
412

413
414
	if (total_entries == 0) {
                /*  Nope.  Go clean up. */
415
		nt_status = NT_STATUS_NOT_FOUND;
416
417
418
		goto done;
	}

419
        /* For each returned entry... */
420
        for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
421

422
                /* pull out the share name */
423
		fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
424

425
                /* pull out the share's comment */
426
		fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
427

428
                /* Get the type value */
429
                type = info_ctr.ctr.ctr1->array[i].type;
430

431
432
433
                /* Add this share to the list */
                (*fn)(name, type, comment, state);
        }
434

435
436
done:
        /* Close the server service pipe */
437
        TALLOC_FREE(pipe_hnd);
438

439
        /* Tell 'em if it worked */
440
        return nt_status;
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
}


/*
 * Verify that the options specified in a URL are valid
 */
int
SMBC_check_options(char *server,
                   char *share,
                   char *path,
                   char *options)
{
        DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
                  "path='%s' options='%s'\n",
                  server, share, path, options));
456

457
458
        /* No options at all is always ok */
        if (! *options) return 0;
459

460
461
462
463
464
465
466
467
468
        /* Currently, we don't support any options. */
        return -1;
}


SMBCFILE *
SMBC_opendir_ctx(SMBCCTX *context,
                 const char *fname)
{
469
470
471
472
473
	char *server = NULL;
        char *share = NULL;
        char *user = NULL;
        char *password = NULL;
        char *options = NULL;
474
475
	char *workgroup = NULL;
	char *path = NULL;
476
	size_t path_len = 0;
477
	uint16_t port = 0;
478
479
480
481
	SMBCSRV *srv  = NULL;
	SMBCFILE *dir = NULL;
	struct sockaddr_storage rem_ss;
	TALLOC_CTX *frame = talloc_stackframe();
482

483
	if (!context || !context->internal->initialized) {
484
485
	        DEBUG(4, ("no valid context\n"));
		TALLOC_FREE(frame);
486
		errno = EINVAL + 8192;
487
		return NULL;
488

489
	}
490

491
492
493
	if (!fname) {
		DEBUG(4, ("no valid fname\n"));
		TALLOC_FREE(frame);
494
		errno = EINVAL + 8193;
495
496
		return NULL;
	}
497

498
	if (SMBC_parse_path(frame,
499
500
501
502
                            context,
                            fname,
                            &workgroup,
                            &server,
503
                            &port,
504
505
506
507
508
                            &share,
                            &path,
                            &user,
                            &password,
                            &options)) {
509
510
	        DEBUG(4, ("no valid path\n"));
		TALLOC_FREE(frame);
511
		errno = EINVAL + 8194;
512
513
		return NULL;
	}
514

515
516
517
	DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
                  "path='%s' options='%s'\n",
                  fname, server, share, path, options));
518

519
520
521
522
        /* Ensure the options are valid */
        if (SMBC_check_options(server, share, path, options)) {
                DEBUG(4, ("unacceptable options (%s)\n", options));
		TALLOC_FREE(frame);
523
                errno = EINVAL + 8195;
524
525
                return NULL;
        }
526

527
	if (!user || user[0] == (char)0) {
528
		user = talloc_strdup(frame, smbc_getUser(context));
529
530
		if (!user) {
			TALLOC_FREE(frame);
531
			errno = ENOMEM;
532
533
534
			return NULL;
		}
	}
535

536
	dir = SMB_MALLOC_P(SMBCFILE);
537

538
539
	if (!dir) {
		TALLOC_FREE(frame);
540
		errno = ENOMEM;
541
542
		return NULL;
	}
543

544
	ZERO_STRUCTP(dir);
545

546
547
	dir->cli_fd   = 0;
	dir->fname    = SMB_STRDUP(fname);
VL's avatar
VL committed
548
549
550
551
552
553
	if (dir->fname == NULL) {
		SAFE_FREE(dir);
		TALLOC_FREE(frame);
		errno = ENOMEM;
		return NULL;
	}
554
555
556
557
	dir->srv      = NULL;
	dir->offset   = 0;
	dir->file     = False;
	dir->dir_list = dir->dir_next = dir->dir_end = NULL;
558

559
	if (server[0] == (char)0) {
560

561
562
563
                size_t i;
                size_t count = 0;
                size_t max_lmb_count;
564
565
                struct sockaddr_storage *ip_list;
                struct sockaddr_storage server_addr;
566
		struct cli_credentials *creds = NULL;
567
		NTSTATUS status;
568

569
		if (share[0] != (char)0 || path[0] != (char)0) {
570

571
572
573
574
575
			if (dir) {
				SAFE_FREE(dir->fname);
				SAFE_FREE(dir);
			}
			TALLOC_FREE(frame);
576
			errno = EINVAL + 8196;
577
578
			return NULL;
		}
579

580
                /* Determine how many local master browsers to query */
581
                max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
582
                                 ? INT_MAX
583
                                 : smbc_getOptionBrowseMaxLmbCount(context));
584

585
586
		creds = cli_credentials_init(frame);
		if (creds == NULL) {
587
588
589
590
591
592
			if (dir) {
				SAFE_FREE(dir->fname);
				SAFE_FREE(dir);
			}
			TALLOC_FREE(frame);
			errno = ENOMEM;
593
594
			return NULL;
		}
595

596
597
		(void)cli_credentials_set_username(creds, user, CRED_SPECIFIED);
		(void)cli_credentials_set_password(creds, password, CRED_SPECIFIED);
598

599
600
601
602
603
604
605
606
		/*
                 * We have server and share and path empty but options
                 * requesting that we scan all master browsers for their list
                 * of workgroups/domains.  This implies that we must first try
                 * broadcast queries to find all master browsers, and if that
                 * doesn't work, then try our other methods which return only
                 * a single master browser.
                 */
607

608
                ip_list = NULL;
609
610
611
612
613
		status = name_resolve_bcast(talloc_tos(),
					    MSBROWSE,
					    1,
					    &ip_list,
					    &count);
614
                if (!NT_STATUS_IS_OK(status))
615
		{
616

617
                        TALLOC_FREE(ip_list);
618

619
                        if (!find_master_ip(workgroup, &server_addr)) {
620

621
622
623
624
625
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
				TALLOC_FREE(frame);
626
                                errno = ENOENT;
627
628
                                return NULL;
                        }
629

630
631
632
			ip_list = (struct sockaddr_storage *)talloc_memdup(
				talloc_tos(), &server_addr,
				sizeof(server_addr));
633
			if (ip_list == NULL) {
VL's avatar
VL committed
634
635
636
637
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
638
				TALLOC_FREE(frame);
639
				errno = ENOMEM;
640
641
642
643
				return NULL;
			}
                        count = 1;
                }
644

645
646
647
648
                for (i = 0; i < count && i < max_lmb_count; i++) {
			char addr[INET6_ADDRSTRLEN];
			char *wg_ptr = NULL;
                	struct cli_state *cli = NULL;
649

650
			print_sockaddr(addr, sizeof(addr), &ip_list[i]);
651
                        DEBUG(99, ("Found master browser %zu of %zu: %s\n",
652
653
                                   i+1, MAX(count, max_lmb_count),
                                   addr));
654

655
                        cli = get_ipc_connect_master_ip(talloc_tos(),
656
							&ip_list[i],
657
							creds,
658
659
660
661
662
663
							&wg_ptr);
			/* cli == NULL is the master browser refused to talk or
			   could not be found */
			if (!cli) {
				continue;
			}
664

665
			workgroup = talloc_strdup(frame, wg_ptr);
666
			server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
667

668
                        cli_shutdown(cli);
669

670
			if (!workgroup || !server) {
VL's avatar
VL committed
671
672
673
674
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
675
				TALLOC_FREE(frame);
676
				errno = ENOMEM;
677
678
				return NULL;
			}
679

680
681
                        DEBUG(4, ("using workgroup %s %s\n",
                                  workgroup, server));
682

683
684
685
686
687
688
                        /*
                         * For each returned master browser IP address, get a
                         * connection to IPC$ on the server if we do not
                         * already have one, and determine the
                         * workgroups/domains that it knows about.
                         */
689

690
                        srv = SMBC_server(frame, context, True, server, port, "IPC$",
691
692
693
694
                                          &workgroup, &user, &password);
                        if (!srv) {
                                continue;
                        }
695

696
697
698
699
			if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
				continue;
			}

700
701
                        dir->srv = srv;
                        dir->dir_type = SMBC_WORKGROUP;
702

703
                        /* Now, list the stuff ... */
704

705
706
707
708
709
710
711
712
                        if (!cli_NetServerEnum(srv->cli,
                                               workgroup,
                                               SV_TYPE_DOMAIN_ENUM,
                                               list_unique_wg_fn,
                                               (void *)dir)) {
                                continue;
                        }
                }
713

714
                TALLOC_FREE(ip_list);
715
716
717
718
719
720
721
        } else {
                /*
                 * Server not an empty string ... Check the rest and see what
                 * gives
                 */
		if (*share == '\0') {
			if (*path != '\0') {
722

723
724
725
726
727
728
                                /* Should not have empty share with path */
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
				TALLOC_FREE(frame);
729
				errno = EINVAL + 8197;
730
				return NULL;
731

732
			}
733

734
735
736
737
738
739
740
741
			/*
                         * We don't know if <server> is really a server name
                         * or is a workgroup/domain name.  If we already have
                         * a server structure for it, we'll use it.
                         * Otherwise, check to see if <server><1D>,
                         * <server><1B>, or <server><20> translates.  We check
                         * to see if <server> is an IP address first.
                         */
742

743
744
745
746
747
                        /*
                         * See if we have an existing server.  Do not
                         * establish a connection if one does not already
                         * exist.
                         */
748
                        srv = SMBC_server(frame, context, False,
749
                                          server, port, "IPC$",
750
                                          &workgroup, &user, &password);
751

752
753
754
755
756
757
                        /*
                         * If no existing server and not an IP addr, look for
                         * LMB or DMB
                         */
			if (!srv &&
                            !is_ipaddress(server) &&
758
759
			    (resolve_name(server, &rem_ss, 0x1d, false) ||   /* LMB */
                             resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
760
761
762
763
764
				/*
				 * "server" is actually a workgroup name,
				 * not a server. Make this clear.
				 */
				char *wgroup = server;
765
				fstring buserver;
766

767
				dir->dir_type = SMBC_SERVER;
768

769
770
771
				/*
				 * Get the backup list ...
				 */
772
				if (!name_status_find(wgroup, 0, 0,
773
                                                      &rem_ss, buserver)) {
774
					char addr[INET6_ADDRSTRLEN];
775

776
					print_sockaddr(addr, sizeof(addr), &rem_ss);
777
                                        DEBUG(0,("Could not get name of "
778
779
780
781
782
                                                "local/domain master browser "
                                                "for workgroup %s from "
						"address %s\n",
						wgroup,
						addr));
783
784
785
786
787
					if (dir) {
						SAFE_FREE(dir->fname);
						SAFE_FREE(dir);
					}
					TALLOC_FREE(frame);
788
					errno = EPERM;
789
					return NULL;
790

791
				}
792

793
794
795
796
797
				/*
                                 * Get a connection to IPC$ on the server if
                                 * we do not already have one
                                 */
				srv = SMBC_server(frame, context, True,
798
                                                  buserver, port, "IPC$",
799
800
                                                  &workgroup,
                                                  &user, &password);
801
802
803
804
805
806
807
808
				if (!srv) {
				        DEBUG(0, ("got no contact to IPC$\n"));
					if (dir) {
						SAFE_FREE(dir->fname);
						SAFE_FREE(dir);
					}
					TALLOC_FREE(frame);
					return NULL;
809

810
				}
811

812
				dir->srv = srv;
813

814
815
816
817
818
819
820
821
822
				if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
					if (dir) {
						SAFE_FREE(dir->fname);
						SAFE_FREE(dir);
					}
					TALLOC_FREE(frame);
					return NULL;
				}

823
				/* Now, list the servers ... */
824
				if (!cli_NetServerEnum(srv->cli, wgroup,
825
826
                                                       0x0000FFFE, list_fn,
						       (void *)dir)) {
827

828
829
830
831
832
833
834
835
					if (dir) {
						SAFE_FREE(dir->fname);
						SAFE_FREE(dir);
					}
					TALLOC_FREE(frame);
					return NULL;
				}
			} else if (srv ||
836
                                   (resolve_name(server, &rem_ss, 0x20, false))) {
837
				NTSTATUS status;
838

839
840
841
                                /*
                                 * If we hadn't found the server, get one now
                                 */
842
843
                                if (!srv) {
                                        srv = SMBC_server(frame, context, True,
844
                                                          server, port, "IPC$",
845
846
847
                                                          &workgroup,
                                                          &user, &password);
                                }
848

849
850
851
852
853
854
855
                                if (!srv) {
                                        if (dir) {
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
                                        }
					TALLOC_FREE(frame);
                                        return NULL;
856

857
                                }
858

859
860
                                dir->dir_type = SMBC_FILE_SHARE;
                                dir->srv = srv;
861

862
                                /* List the shares ... */
863

864
				status = net_share_enum_rpc(srv->cli,
865
866
							list_fn,
							(void *)dir);
867
				if (!NT_STATUS_IS_OK(status) &&
868
869
870
871
872
873
				    smbXcli_conn_protocol(srv->cli->conn) <=
						PROTOCOL_NT1) {
					/*
					 * Only call cli_RNetShareEnum()
					 * on SMB1 connections, not SMB2+.
					 */
874
					int rc = cli_RNetShareEnum(srv->cli,
875
876
							       list_fn,
							       (void *)dir);
877
878
879
880
881
					if (rc != 0) {
						status = cli_nt_error(srv->cli);
					} else {
						status = NT_STATUS_OK;
					}
882
				}
883
884
885
886
887
888
				if (!NT_STATUS_IS_OK(status)) {
					/*
					 * Set cli->raw_status so SMBC_errno()
					 * will correctly return the error.
					 */
					srv->cli->raw_status = status;
889
890
891
892
					if (dir != NULL) {
						SAFE_FREE(dir->fname);
						SAFE_FREE(dir);
					}
893
					TALLOC_FREE(frame);
894
895
					errno = map_errno_from_nt_status(
								status);
896
897
					return NULL;
				}
898
899
900
901
902
903
904
905
906
907
                        } else {
                                /* Neither the workgroup nor server exists */
                                errno = ECONNREFUSED;
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
				TALLOC_FREE(frame);
                                return NULL;
			}
908

909
910
911
912
913
914
915
916
		}
		else {
                        /*
                         * The server and share are specified ... work from
                         * there ...
                         */
			char *targetpath;
			struct cli_state *targetcli;
917
			struct cli_credentials *creds = NULL;
VL's avatar
VL committed
918
			NTSTATUS status;
919

920
921
			/* We connect to the server and list the directory */
			dir->dir_type = SMBC_FILE_SHARE;
922

923
			srv = SMBC_server(frame, context, True, server, port, share,
924
                                          &workgroup, &user, &password);
925

926
927
928
929
930
931
932
933
			if (!srv) {
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
				TALLOC_FREE(frame);
				return NULL;
			}
934

935
			dir->srv = srv;
936

937
			/* Now, list the files ... */
938

939
                        path_len = strlen(path);
940
941
942
943
944
945
946
947
948
			path = talloc_asprintf_append(path, "\\*");
			if (!path) {
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
				TALLOC_FREE(frame);
				return NULL;
			}
949

950
			creds = context->internal->creds;
951

VL's avatar
VL committed
952
			status = cli_resolve_path(
953
954
				frame, "",
				creds,
VL's avatar
VL committed
955
956
				srv->cli, path, &targetcli, &targetpath);
			if (!NT_STATUS_IS_OK(status)) {
957
958
959
960
961
962
963
964
				d_printf("Could not resolve %s\n", path);
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
				TALLOC_FREE(frame);
				return NULL;
			}
965

VL's avatar
VL committed
966
			status = cli_list(targetcli, targetpath,
967
					  FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
VL's avatar
VL committed
968
969
					  dir_list_fn, (void *)dir);
			if (!NT_STATUS_IS_OK(status)) {
970
				int saved_errno;
971
972
973
974
				if (dir) {
					SAFE_FREE(dir->fname);
					SAFE_FREE(dir);
				}
VL's avatar
VL committed
975
				saved_errno = cli_status_to_errno(status);
976

977
                                if (saved_errno == EINVAL) {
978
					struct stat sb = {0};
979
980
981
982
983
984
985
                                        /*
                                         * See if they asked to opendir
                                         * something other than a directory.
                                         * If so, the converted error value we
                                         * got would have been EINVAL rather
                                         * than ENOTDIR.
                                         */
986
                                        path[path_len] = '\0'; /* restore original path */
987

VL's avatar
VL committed
988
989
990
991
992
993
					status = SMBC_getatr(
						context,
						srv,
						path,
						&sb);
					if (NT_STATUS_IS_OK(status) &&
994
                                            !S_ISDIR(sb.st_mode)) {
995

996
997
998
                                                /* It is.  Correct the error value */
                                                saved_errno = ENOTDIR;
                                        }
999
                                }
1000