From 482a9ef278567a35d3bcad1c2048ee97d86bfb9c Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Fri, 5 Oct 2001 00:20:06 +0000 Subject: This is the start of a bit of a rewrite of winbindd's connection handling. I've wrapped up all the decisions about managing, making and closing connections into a connection manager in nsswitch/winbindd_cm.c. It's rather incomplete at the moment - only querying basic user info works at the moment (i.e finger -m DOMAIN/user) and everything else is broken. Jeremy, please take a look and I'll start moving across the rest of winbindd to this new system. (This used to be commit c369cf5af787ed9c642778d21f162716fbf0620e) --- source3/nsswitch/winbindd_cm.c | 245 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 source3/nsswitch/winbindd_cm.c (limited to 'source3/nsswitch/winbindd_cm.c') diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c new file mode 100644 index 0000000000..ec1db826dd --- /dev/null +++ b/source3/nsswitch/winbindd_cm.c @@ -0,0 +1,245 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + + Winbind daemon connection manager + + Copyright (C) Tim Potter 2001 + + 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. +*/ + +/* + We need to manage connections to domain controllers without having to + mess up the main winbindd code with other issues. The aim of the + connection manager is to: + + - make connections to domain controllers and cache them + - re-establish connections when networks or servers go down + - centralise the policy on connection timeouts, domain controller + selection etc + - manage re-entrancy for when winbindd becomes able to handle + multiple outstanding rpc requests + + We can also throw away the CLI_POLICY_HND stuff as all this information + will be stored within this module. + + Why not have connection management as part of the rpc layer like tng? + Good question. This code may morph into libsmb/rpc_cache.c or something + like that but at the moment it's simply staying as part of winbind. I + think the TNG architecture of forcing every user of the rpc layer to use + the connection caching system is a bad idea. It should be an optional + method of using the routines. + + The TNG design is quite good but I disagree with some aspects of the + implementation. -tpot + + */ + +/* + TODO: + + - I'm pretty annoyed by all the make_nmb_name() stuff. It should be + moved down into another function. + + - There needs to be a utility function in libsmb/namequery.c that does + get_any_dc_name() + + */ + +#include "winbindd.h" + +/* We store lists of connections here */ + +struct winbindd_cm_conn { + struct winbindd_cm_conn *prev, *next; + fstring domain; + fstring controller; + fstring pipe_name; + struct cli_state cli; + POLICY_HND pol; +}; + +/* Global list of connections. Initially a DLIST but can become a hash + table or whatever later. */ + +struct winbindd_cm_conn *cm_conns = NULL; + +/* Get a domain controller name */ + +BOOL cm_get_dc_name(char *domain, fstring srv_name) +{ + struct in_addr *ip_list, dc_ip; + extern pstring global_myname; + int count, i; + + /* Lookup domain controller name */ + + if (!get_dc_list(False, domain, &ip_list, &count)) + return False; + + /* Firstly choose a PDC/BDC who has the same network address as any + of our interfaces. */ + + for (i = 0; i < count; i++) { + if(!is_local_net(ip_list[i])) + goto got_ip; + } + + i = (sys_random() % count); + + got_ip: + dc_ip = ip_list[i]; + SAFE_FREE(ip_list); + + if (!lookup_pdc_name(global_myname, domain, &dc_ip, srv_name)) + return False; + + return True; +} + +/* Open a new smb pipe connection to a DC on a given domain */ + +static BOOL cm_open_connection(char *domain, char *pipe_name, + struct winbindd_cm_conn *new_conn) +{ + struct nmb_name calling, called; + extern pstring global_myname; + fstring dest_host; + struct in_addr dest_ip; + BOOL result = False; + struct ntuser_creds creds; + + ZERO_STRUCT(new_conn->cli); + + fstrcpy(new_conn->domain, domain); + fstrcpy(new_conn->pipe_name, pipe_name); + + /* Look for a domain controller for this domain */ + + if (!cm_get_dc_name(lp_workgroup(), new_conn->controller)) + goto done; + + /* Initialise SMB connection */ + + if (!cli_initialise(&new_conn->cli)) + goto done; + + if (!resolve_srv_name(new_conn->controller, dest_host, &dest_ip)) + goto done; + + make_nmb_name(&called, dns_to_netbios_name(new_conn->controller), + 0x20); + make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0); + + ZERO_STRUCT(creds); + creds.pwd.null_pwd = 1; + + cli_init_creds(&new_conn->cli, &creds); + + if (!cli_establish_connection(&new_conn->cli, new_conn->controller, + &dest_ip, &calling, &called, "IPC$", + "IPC", False, True)) + goto done; + + if (!cli_nt_session_open (&new_conn->cli, pipe_name)) + goto done; + + result = True; + + done: + if (!result) + cli_shutdown(&new_conn->cli); + + return result; +} + +/* Return a LSA policy handle on a domain */ + +CLI_POLICY_HND *cm_get_lsa_handle(char *domain) +{ + struct winbindd_cm_conn *conn; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + NTSTATUS result; + static CLI_POLICY_HND hnd; + + /* Look for existing connections */ + + for (conn = cm_conns; conn; conn = conn->next) { + if (strequal(conn->domain, domain) && + strequal(conn->pipe_name, PIPE_LSARPC)) + goto ok; + } + + /* Create a new one */ + + if (!(conn = (struct winbindd_cm_conn *) + malloc(sizeof(struct winbindd_cm_conn)))) + return NULL; + + if (!cm_open_connection(domain, PIPE_LSARPC, conn)) { + DEBUG(3, ("Could not connect to a dc for domain %s\n", + domain)); + return NULL; + } + + result = cli_lsa_open_policy(&conn->cli, conn->cli.mem_ctx, False, + des_access, &conn->pol); + + if (!NT_STATUS_IS_OK(result)) + return NULL; + + /* Add to list */ + + DLIST_ADD(cm_conns, conn); + + ok: + hnd.pol = conn->pol; + hnd.cli = &conn->cli; + + return &hnd; +} + +/* Return a SAM policy handle on a domain */ + +CLI_POLICY_HND *cm_get_sam_handle(char *domain) +{ + DEBUG(0, ("get_sam_handle(): not implemented\n")); + return NULL; +} + +/* Return a SAM domain policy handle on a domain */ + +CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain) +{ + DEBUG(0, ("get_sam_dom_handle(): not implemented\n")); + return NULL; +} + +/* Return a SAM policy handle on a domain user */ + +CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, char *user) +{ + DEBUG(0, ("get_sam_user_handle(): not implemented\n")); + return NULL; +} + +/* Return a SAM policy handle on a domain group */ + +CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, char *group) +{ + DEBUG(0, ("get_sam_group_handle(): not implemented\n")); + return NULL; +} -- cgit