smbd: avoid a panic in close_directory()
[samba4-gss.git] / source3 / utils / smbtree.c
blob80dfa0a5944b7df9ca61741f15994c8d07d16052
1 /*
2 Unix SMB/CIFS implementation.
3 Network neighbourhood browser.
5 Copyright (C) Tim Potter 2000
6 Copyright (C) Jelmer Vernooij 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "lib/cmdline/cmdline.h"
24 #include "rpc_client/cli_pipe.h"
25 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
26 #include "libsmb/libsmb.h"
27 #include "libsmb/namequery.h"
28 #include "libsmb/clirap.h"
29 #include "../libcli/smb/smbXcli_base.h"
30 #include "nameserv.h"
31 #include "libsmbclient.h"
33 /* How low can we go? */
35 enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE};
36 static enum tree_level level = LEV_SHARE;
38 static void get_auth_data_with_context_fn(
39 SMBCCTX *context,
40 const char *server,
41 const char *share,
42 char *domain,
43 int domain_len,
44 char *user,
45 int user_len,
46 char *password,
47 int password_len)
49 struct cli_credentials *creds = samba_cmdline_get_creds();
50 size_t len;
52 len = strlcpy(domain, cli_credentials_get_domain(creds), domain_len);
53 if ((int)len >= domain_len) {
54 return;
56 len = strlcpy(
57 user, cli_credentials_get_username(creds), user_len);
58 if ((int)len >= user_len) {
59 return;
61 len = strlcpy(
62 password, cli_credentials_get_password(creds), password_len);
63 if ((int)len >= password_len) {
64 /* pointless, but what can you do... */
65 return;
69 /****************************************************************************
70 main program
71 ****************************************************************************/
72 int main(int argc, char *argv[])
74 TALLOC_CTX *frame = talloc_stackframe();
75 const char **argv_const = discard_const_p(const char *, argv);
76 struct poptOption long_options[] = {
77 POPT_AUTOHELP
79 .longName = "domains",
80 .shortName = 'D',
81 .argInfo = POPT_ARG_VAL,
82 .arg = &level,
83 .val = LEV_WORKGROUP,
84 .descrip = "List only domains (workgroups) of tree" ,
87 .longName = "servers",
88 .shortName = 'S',
89 .argInfo = POPT_ARG_VAL,
90 .arg = &level,
91 .val = LEV_SERVER,
92 .descrip = "List domains(workgroups) and servers of tree" ,
94 POPT_COMMON_SAMBA
95 POPT_COMMON_CREDENTIALS
96 POPT_COMMON_VERSION
97 POPT_TABLEEND
99 poptContext pc;
100 SMBCCTX *ctx = NULL;
101 SMBCFILE *workgroups = NULL;
102 struct smbc_dirent *dirent = NULL;
103 bool ok;
104 int ret, result = 1;
105 int opt;
106 int debuglevel;
108 /* Initialise samba stuff */
109 smb_init_locale();
111 setlinebuf(stdout);
113 ok = samba_cmdline_init(frame,
114 SAMBA_CMDLINE_CONFIG_CLIENT,
115 false /* require_smbconf */);
116 if (!ok) {
117 DBG_ERR("Failed to init cmdline parser!\n");
118 TALLOC_FREE(frame);
119 exit(1);
122 pc = samba_popt_get_context(getprogname(),
123 argc,
124 argv_const,
125 long_options,
126 POPT_CONTEXT_KEEP_FIRST);
127 if (pc == NULL) {
128 DBG_ERR("Failed to setup popt context!\n");
129 TALLOC_FREE(frame);
130 exit(1);
133 while((opt = poptGetNextOpt(pc)) != -1) {
134 switch (opt) {
135 case POPT_ERROR_BADOPT:
136 fprintf(stderr, "\nInvalid option %s: %s\n\n",
137 poptBadOption(pc, 0), poptStrerror(opt));
138 poptPrintUsage(pc, stderr, 0);
139 exit(1);
143 samba_cmdline_burn(argc, argv);
145 debuglevel = DEBUGLEVEL;
147 ctx = smbc_new_context();
148 if (ctx == NULL) {
149 perror("smbc_new_context");
150 goto fail;
152 ret = smbc_setConfiguration(ctx, get_dyn_CONFIGFILE());
153 if (ret == -1) {
154 perror("smbc_setConfiguration");
155 goto fail;
157 smbc_setDebug(ctx, debuglevel);
158 ok = smbc_setOptionProtocols(ctx, NULL, "NT1");
159 if (!ok) {
160 perror("smbc_setOptionProtocols");
161 goto fail;
163 smbc_setFunctionAuthDataWithContext(
164 ctx, get_auth_data_with_context_fn);
166 ok = smbc_init_context(ctx);
167 if (!ok) {
168 perror("smbc_init_context");
169 goto fail;
172 workgroups = smbc_getFunctionOpendir(ctx)(ctx, "smb://");
173 if (workgroups == NULL) {
174 DBG_ERR("This is utility doesn't work if netbios name "
175 "resolution is not configured.\n"
176 "If you are using SMB2 or SMB3, network browsing uses "
177 "WSD/LLMNR, which is not yet supported by Samba. SMB1 "
178 "is disabled by default on the latest Windows versions "
179 "for security reasons. It is still possible to access "
180 "the Samba resources directly via \\name or "
181 "\\ip.address.\n");
182 goto fail;
185 while ((dirent = smbc_getFunctionReaddir(ctx)(ctx, workgroups))
186 != NULL) {
187 char *url = NULL;
188 SMBCFILE *servers = NULL;
190 if (dirent->smbc_type != SMBC_WORKGROUP) {
191 continue;
194 printf("%s\n", dirent->name);
196 if (level == LEV_WORKGROUP) {
197 continue;
200 url = talloc_asprintf(
201 talloc_tos(), "smb://%s/", dirent->name);
202 if (url == NULL) {
203 perror("talloc_asprintf");
204 goto fail;
207 servers = smbc_getFunctionOpendir(ctx)(ctx, url);
208 if (servers == NULL) {
209 perror("smbc_opendir");
210 goto fail;
212 TALLOC_FREE(url);
214 while ((dirent = smbc_getFunctionReaddir(ctx)(ctx, servers))
215 != NULL) {
216 SMBCFILE *shares = NULL;
217 char *servername = NULL;
219 if (dirent->smbc_type != SMBC_SERVER) {
220 continue;
223 printf("\t\\\\%-15s\t\t%s\n",
224 dirent->name,
225 dirent->comment);
227 if (level == LEV_SERVER) {
228 continue;
232 * The subsequent readdir for shares will
233 * overwrite the "server" readdir
235 servername = talloc_strdup(talloc_tos(), dirent->name);
236 if (servername == NULL) {
237 continue;
240 url = talloc_asprintf(
241 talloc_tos(), "smb://%s/", servername);
242 if (url == NULL) {
243 perror("talloc_asprintf");
244 goto fail;
247 shares = smbc_getFunctionOpendir(ctx)(ctx, url);
248 if (shares == NULL) {
249 perror("smbc_opendir");
250 goto fail;
253 while ((dirent = smbc_getFunctionReaddir(
254 ctx)(ctx, shares))
255 != NULL) {
256 printf("\t\t\\\\%s\\%-15s\t%s\n",
257 servername,
258 dirent->name,
259 dirent->comment);
262 ret = smbc_getFunctionClosedir(ctx)(ctx, shares);
263 if (ret == -1) {
264 perror("smbc_closedir");
265 goto fail;
268 TALLOC_FREE(servername);
269 TALLOC_FREE(url);
272 ret = smbc_getFunctionClosedir(ctx)(ctx, servers);
273 if (ret == -1) {
274 perror("smbc_closedir");
275 goto fail;
279 ret = smbc_getFunctionClosedir(ctx)(ctx, workgroups);
280 if (ret == -1) {
281 perror("smbc_closedir");
282 goto fail;
285 result = 0;
286 fail:
287 if (ctx != NULL) {
288 smbc_free_context(ctx, 0);
289 ctx = NULL;
291 gfree_all();
292 poptFreeContext(pc);
293 TALLOC_FREE(frame);
294 return result;