diff options
Diffstat (limited to 'source3/utils/smbtree.c')
-rw-r--r-- | source3/utils/smbtree.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c new file mode 100644 index 0000000000..b80a27eb37 --- /dev/null +++ b/source3/utils/smbtree.c @@ -0,0 +1,423 @@ +/* + Unix SMB/CIFS implementation. + Network neighbourhood browser. + + Copyright (C) Tim Potter 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static BOOL use_bcast; + +struct user_auth_info { + pstring username; + pstring password; + pstring workgroup; +}; + +/* How low can we go? */ + +enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE}; +enum tree_level level = LEV_SHARE; + +static void usage(void) +{ + printf( +"Usage: smbtree [options]\n\ +\n\ +\t-d debuglevel set debug output level\n\ +\t-U username user to autheticate as\n\ +\t-W workgroup workgroup of user to authenticate as\n\ +\t-D list only domains (workgroups) of tree\n\ +\t-S list domains and servers of tree\n\ +\t-b use bcast instead of using the master browser\n\ +\n\ +The username can be of the form username%%password or\n\ +workgroup\\username%%password.\n\n\ +"); +} + +/* Holds a list of workgroups or servers */ + +struct name_list { + struct name_list *prev, *next; + pstring name, comment; + uint32 server_type; +}; + +static struct name_list *workgroups, *servers, *shares; + +static void free_name_list(struct name_list *list) +{ + while(list) + DLIST_REMOVE(list, list); +} + +static void add_name(const char *machine_name, uint32 server_type, + const char *comment, void *state) +{ + struct name_list **name_list = (struct name_list **)state; + struct name_list *new_name; + + new_name = (struct name_list *)malloc(sizeof(struct name_list)); + + if (!new_name) + return; + + ZERO_STRUCTP(new_name); + + pstrcpy(new_name->name, machine_name); + pstrcpy(new_name->comment, comment); + new_name->server_type = server_type; + + DLIST_ADD(*name_list, new_name); +} + +/* Return a cli_state pointing at the IPC$ share for the given workgroup */ + +static struct cli_state *get_ipc_connect(char *server, + struct user_auth_info *user_info) +{ + struct nmb_name calling, called; + struct in_addr server_ip; + struct cli_state *cli; + pstring myname; + + zero_ip(&server_ip); + + get_myname(myname); + + make_nmb_name(&called, myname, 0x0); + make_nmb_name(&calling, server, 0x20); + + if (is_ipaddress(server)) + if (!resolve_name(server, &server_ip, 0x20)) + return False; + + again: + if (!(cli = cli_initialise(NULL))) { + DEBUG(4, ("Unable to initialise cli structure\n")); + goto error; + } + + if (!cli_connect(cli, server, &server_ip)) { + DEBUG(4, ("Unable to connect to %s\n", server)); + goto error; + } + + if (!cli_session_request(cli, &calling, &called)) { + cli_shutdown(cli); + if (!strequal(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } + DEBUG(4, ("Session request failed to %s\n", called.name)); + goto error; + } + + if (!cli_negprot(cli)) { + DEBUG(4, ("Negprot failed\n")); + goto error; + } + + if (!cli_session_setup(cli, user_info->username, user_info->password, + strlen(user_info->password), + user_info->password, + strlen(user_info->password), server) && + /* try an anonymous login if it failed */ + !cli_session_setup(cli, "", "", 1,"", 0, server)) { + DEBUG(4, ("Session setup failed\n")); + goto error; + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(cli, "IPC$", "?????", + user_info->password, + strlen(user_info->password)+1)) { + DEBUG(4, ("Tconx failed\n")); + goto error; + } + + return cli; + + /* Clean up after error */ + + error: + if (cli && cli->initialised) + cli_shutdown(cli); + + return NULL; +} + +/* Return the IP address and workgroup of a master browser on the + network. */ + +static BOOL find_master_ip_bcast(pstring workgroup, struct in_addr *server_ip) +{ + struct in_addr *ip_list; + int i, count; + + /* Go looking for workgroups by broadcasting on the local network */ + + if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + return False; + } + + for (i = 0; i < count; i++) { + static fstring name; + + if (!name_status_find("*", 0, 0x1d, ip_list[i], name)) + continue; + + if (!find_master_ip(name, server_ip)) + continue; + + pstrcpy(workgroup, name); + + DEBUG(4, ("found master browser %s, %s\n", + name, inet_ntoa(ip_list[i]))); + + return True; + } + + return False; +} + +/**************************************************************************** + display tree of smb workgroups, servers and shares +****************************************************************************/ +static BOOL get_workgroups(struct user_auth_info *user_info) +{ + struct cli_state *cli; + struct in_addr server_ip; + pstring master_workgroup; + + /* Try to connect to a #1d name of our current workgroup. If that + doesn't work broadcast for a master browser and then jump off + that workgroup. */ + + pstrcpy(master_workgroup, lp_workgroup()); + + if (use_bcast || !find_master_ip(lp_workgroup(), &server_ip)) { + DEBUG(4, ("Unable to find master browser for workgroup %s\n", + master_workgroup)); + if (!find_master_ip_bcast(master_workgroup, &server_ip)) { + DEBUG(4, ("Unable to find master browser by " + "broadcast\n")); + return False; + } + } + + if (!(cli = get_ipc_connect(inet_ntoa(server_ip), user_info))) + return False; + + if (!cli_NetServerEnum(cli, master_workgroup, + SV_TYPE_DOMAIN_ENUM, add_name, &workgroups)) + return False; + + return True; +} + +/* Retrieve the list of servers for a given workgroup */ + +static BOOL get_servers(char *workgroup, struct user_auth_info *user_info) +{ + struct cli_state *cli; + struct in_addr server_ip; + + /* Open an IPC$ connection to the master browser for the workgroup */ + + if (!find_master_ip(workgroup, &server_ip)) { + DEBUG(4, ("Cannot find master browser for workgroup %s\n", + workgroup)); + return False; + } + + if (!(cli = get_ipc_connect(inet_ntoa(server_ip), user_info))) + return False; + + if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name, + &servers)) + return False; + + return True; +} + +static BOOL get_shares(char *server_name, struct user_auth_info *user_info) +{ + struct cli_state *cli; + + if (!(cli = get_ipc_connect(server_name, user_info))) + return False; + + if (!cli_RNetShareEnum(cli, add_name, &shares)) + return False; + + return True; +} + +static BOOL print_tree(struct user_auth_info *user_info) +{ + struct name_list *wg, *sv, *sh; + + /* List workgroups */ + + if (!get_workgroups(user_info)) + return False; + + for (wg = workgroups; wg; wg = wg->next) { + + printf("%s\n", wg->name); + + /* List servers */ + + free_name_list(servers); + servers = NULL; + + if (level == LEV_WORKGROUP || + !get_servers(wg->name, user_info)) + continue; + + for (sv = servers; sv; sv = sv->next) { + + printf("\t\\\\%-15s\t\t%s\n", + sv->name, sv->comment); + + /* List shares */ + + free_name_list(shares); + shares = NULL; + + if (level == LEV_SERVER || + !get_shares(sv->name, user_info)) + continue; + + for (sh = shares; sh; sh = sh->next) { + printf("\t\t\\\\%s\\%-15s\t%s\n", + sv->name, sh->name, sh->comment); + } + } + } + + return True; +} + +/**************************************************************************** + main program +****************************************************************************/ + int main(int argc,char *argv[]) +{ + extern char *optarg; + extern int optind; + int opt; + char *p; + struct user_auth_info user_info; + BOOL got_pass = False; + + /* Initialise samba stuff */ + + setlinebuf(stdout); + + dbf = x_stderr; + + setup_logging(argv[0],True); + + lp_load(dyn_CONFIGFILE,True,False,False); + load_interfaces(); + + if (getenv("USER")) { + pstrcpy(user_info.username, getenv("USER")); + + if ((p=strchr(user_info.username, '%'))) { + *p = 0; + pstrcpy(user_info.password, p+1); + got_pass = True; + memset(strchr(getenv("USER"), '%') + 1, 'X', + strlen(user_info.password)); + } + } + + pstrcpy(user_info.workgroup, lp_workgroup()); + + /* Parse command line args */ + + while ((opt = getopt(argc, argv, "U:hd:W:DSb")) != EOF) { + switch (opt) { + case 'U': + pstrcpy(user_info.username,optarg); + p = strchr(user_info.username,'%'); + if (p) { + *p = 0; + pstrcpy(user_info.password, p+1); + got_pass = 1; + } + break; + + case 'b': + use_bcast = True; + break; + + case 'h': + usage(); + exit(1); + + case 'd': + DEBUGLEVEL = atoi(optarg); + break; + + case 'W': + pstrcpy(user_info.workgroup, optarg); + break; + + case 'D': + level = LEV_WORKGROUP; + break; + + case 'S': + level = LEV_SERVER; + break; + + default: + printf("Unknown option %c (%d)\n", (char)opt, opt); + exit(1); + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (!got_pass) { + char *pass = getpass("Password: "); + if (pass) { + pstrcpy(user_info.password, pass); + } + got_pass = True; + } + + /* Now do our stuff */ + + if (!print_tree(&user_info)) + return 1; + + return 0; +} |