e2f109e9eb2a6cf13f3bcd1247326e4a52024619
[kai/samba.git] / source3 / utils / smbtree.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Network neighbourhood browser.
4    
5    Copyright (C) Tim Potter      2000
6    Copyright (C) Jelmer Vernooij 2003
7    
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.
12    
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.
17    
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/>.
20 */
21
22 #include "includes.h"
23 #include "popt_common.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/clirap.h"
28
29 static int use_bcast;
30
31 /* How low can we go? */
32
33 enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE};
34 static enum tree_level level = LEV_SHARE;
35
36 /* Holds a list of workgroups or servers */
37
38 struct smb_name_list {
39         struct smb_name_list *prev, *next;
40         char *name, *comment;
41         uint32 server_type;
42 };
43
44 static struct smb_name_list *workgroups, *servers, *shares;
45
46 static void free_name_list(struct smb_name_list *list)
47 {
48         while(list)
49                 DLIST_REMOVE(list, list);
50 }
51
52 static void add_name(const char *machine_name, uint32 server_type,
53                      const char *comment, void *state)
54 {
55         struct smb_name_list **name_list = (struct smb_name_list **)state;
56         struct smb_name_list *new_name;
57
58         new_name = SMB_MALLOC_P(struct smb_name_list);
59
60         if (!new_name)
61                 return;
62
63         ZERO_STRUCTP(new_name);
64
65         new_name->name = SMB_STRDUP(machine_name);
66         new_name->comment = SMB_STRDUP(comment);
67         new_name->server_type = server_type;
68
69         if (!new_name->name || !new_name->comment) {
70                 SAFE_FREE(new_name->name);
71                 SAFE_FREE(new_name->comment);
72                 SAFE_FREE(new_name);
73                 return;
74         }
75
76         DLIST_ADD(*name_list, new_name);
77 }
78
79 /****************************************************************************
80   display tree of smb workgroups, servers and shares
81 ****************************************************************************/
82 static bool get_workgroups(struct user_auth_info *user_info)
83 {
84         struct cli_state *cli;
85         struct sockaddr_storage server_ss;
86         TALLOC_CTX *ctx = talloc_tos();
87         char *master_workgroup = NULL;
88
89         /* Try to connect to a #1d name of our current workgroup.  If that
90            doesn't work broadcast for a master browser and then jump off
91            that workgroup. */
92
93         master_workgroup = talloc_strdup(ctx, lp_workgroup());
94         if (!master_workgroup) {
95                 return false;
96         }
97
98         if (!use_bcast && !find_master_ip(lp_workgroup(), &server_ss)) {
99                 DEBUG(4,("Unable to find master browser for workgroup %s, "
100                          "falling back to broadcast\n",
101                          master_workgroup));
102                 use_bcast = true;
103         }
104
105         if (!use_bcast) {
106                 char addr[INET6_ADDRSTRLEN];
107
108                 print_sockaddr(addr, sizeof(addr), &server_ss);
109
110                 cli = get_ipc_connect(addr, &server_ss, user_info);
111                 if (cli == NULL) {
112                         return false;
113                 }
114         } else {
115                 cli = get_ipc_connect_master_ip_bcast(talloc_tos(),
116                                                       user_info,
117                                                       &master_workgroup);
118                 if (cli == NULL) {
119                         DEBUG(4, ("Unable to find master browser by "
120                                   "broadcast\n"));
121                         return false;
122                 }
123         }
124
125         if (!cli_NetServerEnum(cli, master_workgroup,
126                                SV_TYPE_DOMAIN_ENUM, add_name, &workgroups))
127                 return False;
128
129         return True;
130 }
131
132 /* Retrieve the list of servers for a given workgroup */
133
134 static bool get_servers(char *workgroup, struct user_auth_info *user_info)
135 {
136         struct cli_state *cli;
137         struct sockaddr_storage server_ss;
138         char addr[INET6_ADDRSTRLEN];
139
140         /* Open an IPC$ connection to the master browser for the workgroup */
141
142         if (!find_master_ip(workgroup, &server_ss)) {
143                 DEBUG(4, ("Cannot find master browser for workgroup %s\n",
144                           workgroup));
145                 return False;
146         }
147
148         print_sockaddr(addr, sizeof(addr), &server_ss);
149         if (!(cli = get_ipc_connect(addr, &server_ss, user_info)))
150                 return False;
151
152         if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name,
153                                &servers))
154                 return False;
155
156         return True;
157 }
158
159 static bool get_rpc_shares(struct cli_state *cli,
160                            void (*fn)(const char *, uint32, const char *, void *),
161                            void *state)
162 {
163         NTSTATUS status;
164         struct rpc_pipe_client *pipe_hnd = NULL;
165         TALLOC_CTX *mem_ctx;
166         WERROR werr;
167         struct srvsvc_NetShareInfoCtr info_ctr;
168         struct srvsvc_NetShareCtr1 ctr1;
169         int i;
170         uint32_t resume_handle = 0;
171         uint32_t total_entries = 0;
172         struct dcerpc_binding_handle *b;
173
174         mem_ctx = talloc_new(NULL);
175         if (mem_ctx == NULL) {
176                 DEBUG(0, ("talloc_new failed\n"));
177                 return False;
178         }
179
180         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
181                                           &pipe_hnd);
182
183         if (!NT_STATUS_IS_OK(status)) {
184                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
185                            nt_errstr(status)));
186                 TALLOC_FREE(mem_ctx);
187                 return False;
188         }
189
190         b = pipe_hnd->binding_handle;
191
192         ZERO_STRUCT(info_ctr);
193         ZERO_STRUCT(ctr1);
194
195         info_ctr.level = 1;
196         info_ctr.ctr.ctr1 = &ctr1;
197
198         status = dcerpc_srvsvc_NetShareEnumAll(b, mem_ctx,
199                                                pipe_hnd->desthost,
200                                                &info_ctr,
201                                                0xffffffff,
202                                                &total_entries,
203                                                &resume_handle,
204                                                &werr);
205
206         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
207                 TALLOC_FREE(mem_ctx);
208                 TALLOC_FREE(pipe_hnd);
209                 return False;
210         }
211
212         for (i=0; i<total_entries; i++) {
213                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
214                 fn(info.name, info.type, info.comment, state);
215         }
216
217         TALLOC_FREE(mem_ctx);
218         TALLOC_FREE(pipe_hnd);
219         return True;
220 }
221
222
223 static bool get_shares(char *server_name, struct user_auth_info *user_info)
224 {
225         struct cli_state *cli;
226
227         if (!(cli = get_ipc_connect(server_name, NULL, user_info)))
228                 return False;
229
230         if (get_rpc_shares(cli, add_name, &shares))
231                 return True;
232
233         if (!cli_RNetShareEnum(cli, add_name, &shares))
234                 return False;
235
236         return True;
237 }
238
239 static bool print_tree(struct user_auth_info *user_info)
240 {
241         struct smb_name_list *wg, *sv, *sh;
242
243         /* List workgroups */
244
245         if (!get_workgroups(user_info))
246                 return False;
247
248         for (wg = workgroups; wg; wg = wg->next) {
249
250                 printf("%s\n", wg->name);
251
252                 /* List servers */
253
254                 free_name_list(servers);
255                 servers = NULL;
256
257                 if (level == LEV_WORKGROUP || 
258                     !get_servers(wg->name, user_info))
259                         continue;
260
261                 for (sv = servers; sv; sv = sv->next) {
262
263                         printf("\t\\\\%-15s\t\t%s\n", 
264                                sv->name, sv->comment);
265
266                         /* List shares */
267
268                         free_name_list(shares);
269                         shares = NULL;
270
271                         if (level == LEV_SERVER ||
272                             !get_shares(sv->name, user_info))
273                                 continue;
274
275                         for (sh = shares; sh; sh = sh->next) {
276                                 printf("\t\t\\\\%s\\%-15s\t%s\n", 
277                                        sv->name, sh->name, sh->comment);
278                         }
279                 }
280         }
281
282         return True;
283 }
284
285 /****************************************************************************
286   main program
287 ****************************************************************************/
288  int main(int argc,char *argv[])
289 {
290         TALLOC_CTX *frame = talloc_stackframe();
291         struct user_auth_info *auth_info;
292         struct poptOption long_options[] = {
293                 POPT_AUTOHELP
294                 { "broadcast", 'b', POPT_ARG_VAL, &use_bcast, True, "Use broadcast instead of using the master browser" },
295                 { "domains", 'D', POPT_ARG_VAL, &level, LEV_WORKGROUP, "List only domains (workgroups) of tree" },
296                 { "servers", 'S', POPT_ARG_VAL, &level, LEV_SERVER, "List domains(workgroups) and servers of tree" },
297                 POPT_COMMON_SAMBA
298                 POPT_COMMON_CREDENTIALS
299                 POPT_TABLEEND
300         };
301         poptContext pc;
302
303         /* Initialise samba stuff */
304         load_case_tables();
305
306         setlinebuf(stdout);
307
308         setup_logging(argv[0], DEBUG_STDERR);
309
310         auth_info = user_auth_info_init(frame);
311         if (auth_info == NULL) {
312                 exit(1);
313         }
314         popt_common_set_auth_info(auth_info);
315
316         pc = poptGetContext("smbtree", argc, (const char **)argv, long_options,
317                                                 POPT_CONTEXT_KEEP_FIRST);
318         while(poptGetNextOpt(pc) != -1);
319         poptFreeContext(pc);
320
321         lp_load_global(get_dyn_CONFIGFILE());
322         load_interfaces();
323
324         /* Parse command line args */
325
326         if (get_cmdline_auth_info_use_machine_account(auth_info) &&
327             !set_cmdline_auth_info_machine_account_creds(auth_info)) {
328                 TALLOC_FREE(frame);
329                 return 1;
330         }
331
332         set_cmdline_auth_info_getpass(auth_info);
333
334         /* Now do our stuff */
335
336         if (!print_tree(auth_info)) {
337                 TALLOC_FREE(frame);
338                 return 1;
339         }
340
341         TALLOC_FREE(frame);
342         return 0;
343 }