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