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