s3-smbtree: prefer dcerpc_srvsvc_X functions.
[bbaumbach/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 "popt_common.h"
24 #include "../librpc/gen_ndr/ndr_srvsvc_c.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         struct dcerpc_binding_handle *b;
162
163         mem_ctx = talloc_new(NULL);
164         if (mem_ctx == NULL) {
165                 DEBUG(0, ("talloc_new failed\n"));
166                 return False;
167         }
168
169         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
170                                           &pipe_hnd);
171
172         if (!NT_STATUS_IS_OK(status)) {
173                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
174                            nt_errstr(status)));
175                 TALLOC_FREE(mem_ctx);
176                 return False;
177         }
178
179         b = pipe_hnd->binding_handle;
180
181         ZERO_STRUCT(info_ctr);
182         ZERO_STRUCT(ctr1);
183
184         info_ctr.level = 1;
185         info_ctr.ctr.ctr1 = &ctr1;
186
187         status = dcerpc_srvsvc_NetShareEnumAll(b, mem_ctx,
188                                                pipe_hnd->desthost,
189                                                &info_ctr,
190                                                0xffffffff,
191                                                &total_entries,
192                                                &resume_handle,
193                                                &werr);
194
195         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
196                 TALLOC_FREE(mem_ctx);
197                 TALLOC_FREE(pipe_hnd);
198                 return False;
199         }
200
201         for (i=0; i<total_entries; i++) {
202                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
203                 fn(info.name, info.type, info.comment, state);
204         }
205
206         TALLOC_FREE(mem_ctx);
207         TALLOC_FREE(pipe_hnd);
208         return True;
209 }
210
211
212 static bool get_shares(char *server_name, struct user_auth_info *user_info)
213 {
214         struct cli_state *cli;
215
216         if (!(cli = get_ipc_connect(server_name, NULL, user_info)))
217                 return False;
218
219         if (get_rpc_shares(cli, add_name, &shares))
220                 return True;
221
222         if (!cli_RNetShareEnum(cli, add_name, &shares))
223                 return False;
224
225         return True;
226 }
227
228 static bool print_tree(struct user_auth_info *user_info)
229 {
230         struct smb_name_list *wg, *sv, *sh;
231
232         /* List workgroups */
233
234         if (!get_workgroups(user_info))
235                 return False;
236
237         for (wg = workgroups; wg; wg = wg->next) {
238
239                 printf("%s\n", wg->name);
240
241                 /* List servers */
242
243                 free_name_list(servers);
244                 servers = NULL;
245
246                 if (level == LEV_WORKGROUP || 
247                     !get_servers(wg->name, user_info))
248                         continue;
249
250                 for (sv = servers; sv; sv = sv->next) {
251
252                         printf("\t\\\\%-15s\t\t%s\n", 
253                                sv->name, sv->comment);
254
255                         /* List shares */
256
257                         free_name_list(shares);
258                         shares = NULL;
259
260                         if (level == LEV_SERVER ||
261                             !get_shares(sv->name, user_info))
262                                 continue;
263
264                         for (sh = shares; sh; sh = sh->next) {
265                                 printf("\t\t\\\\%s\\%-15s\t%s\n", 
266                                        sv->name, sh->name, sh->comment);
267                         }
268                 }
269         }
270
271         return True;
272 }
273
274 /****************************************************************************
275   main program
276 ****************************************************************************/
277  int main(int argc,char *argv[])
278 {
279         TALLOC_CTX *frame = talloc_stackframe();
280         struct user_auth_info *auth_info;
281         struct poptOption long_options[] = {
282                 POPT_AUTOHELP
283                 { "broadcast", 'b', POPT_ARG_VAL, &use_bcast, True, "Use broadcast instead of using the master browser" },
284                 { "domains", 'D', POPT_ARG_VAL, &level, LEV_WORKGROUP, "List only domains (workgroups) of tree" },
285                 { "servers", 'S', POPT_ARG_VAL, &level, LEV_SERVER, "List domains(workgroups) and servers of tree" },
286                 POPT_COMMON_SAMBA
287                 POPT_COMMON_CREDENTIALS
288                 POPT_TABLEEND
289         };
290         poptContext pc;
291
292         /* Initialise samba stuff */
293         load_case_tables();
294
295         setlinebuf(stdout);
296
297         setup_logging(argv[0], DEBUG_STDERR);
298
299         auth_info = user_auth_info_init(frame);
300         if (auth_info == NULL) {
301                 exit(1);
302         }
303         popt_common_set_auth_info(auth_info);
304
305         pc = poptGetContext("smbtree", argc, (const char **)argv, long_options,
306                                                 POPT_CONTEXT_KEEP_FIRST);
307         while(poptGetNextOpt(pc) != -1);
308         poptFreeContext(pc);
309
310         lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
311         load_interfaces();
312
313         /* Parse command line args */
314
315         if (get_cmdline_auth_info_use_machine_account(auth_info) &&
316             !set_cmdline_auth_info_machine_account_creds(auth_info)) {
317                 TALLOC_FREE(frame);
318                 return 1;
319         }
320
321         set_cmdline_auth_info_getpass(auth_info);
322
323         /* Now do our stuff */
324
325         if (!print_tree(auth_info)) {
326                 TALLOC_FREE(frame);
327                 return 1;
328         }
329
330         TALLOC_FREE(frame);
331         return 0;
332 }