2 Unix SMB/Netbios implementation.
5 Winbind daemon connection manager
7 Copyright (C) Tim Potter 2001
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 We need to manage connections to domain controllers without having to
26 mess up the main winbindd code with other issues. The aim of the
27 connection manager is to:
29 - make connections to domain controllers and cache them
30 - re-establish connections when networks or servers go down
31 - centralise the policy on connection timeouts, domain controller
33 - manage re-entrancy for when winbindd becomes able to handle
34 multiple outstanding rpc requests
36 Why not have connection management as part of the rpc layer like tng?
37 Good question. This code may morph into libsmb/rpc_cache.c or something
38 like that but at the moment it's simply staying as part of winbind. I
39 think the TNG architecture of forcing every user of the rpc layer to use
40 the connection caching system is a bad idea. It should be an optional
41 method of using the routines. We actually cache policy handles - tng
42 caches connections to pipes.
44 The TNG design is quite good but I disagree with some aspects of the
52 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
53 moved down into another function.
55 - There needs to be a utility function in libsmb/namequery.c that does
58 - When closing down sam handles we need to close down user, group and
61 - Take care when destroying cli_structs as they can be shared between
68 /* We store lists of connections here */
71 SAM_PIPE_BASIC, /* A basic handle */
72 SAM_PIPE_DOM, /* A domain handle */
73 SAM_PIPE_USER, /* A handle on a user */
74 SAM_PIPE_GROUP /* A handle on a group */
77 struct winbindd_cm_conn {
78 struct winbindd_cm_conn *prev, *next;
82 struct cli_state *cli;
85 /* Specific pipe stuff - move into a union? */
87 enum sam_pipe_type sam_pipe_type; /* Domain, user, group etc */
88 uint32 user_rid, group_rid;
91 /* Global list of connections. Initially a DLIST but can become a hash
92 table or whatever later. */
94 struct winbindd_cm_conn *cm_conns = NULL;
96 /* Get a domain controller name */
98 BOOL cm_get_dc_name(char *domain, fstring srv_name)
100 struct in_addr *ip_list, dc_ip;
101 extern pstring global_myname;
104 /* Lookup domain controller name */
106 if (!get_dc_list(False, domain, &ip_list, &count))
109 /* Firstly choose a PDC/BDC who has the same network address as any
110 of our interfaces. */
112 for (i = 0; i < count; i++) {
113 if(is_local_net(ip_list[i]))
117 i = (sys_random() % count);
123 if (!lookup_pdc_name(global_myname, domain, &dc_ip, srv_name))
129 /* Open a new smb pipe connection to a DC on a given domain */
131 static BOOL cm_open_connection(char *domain, char *pipe_name,
132 struct winbindd_cm_conn *new_conn)
134 struct nmb_name calling, called;
135 extern pstring global_myname;
137 struct in_addr dest_ip;
139 struct ntuser_creds creds;
141 fstrcpy(new_conn->domain, domain);
142 fstrcpy(new_conn->pipe_name, pipe_name);
144 /* Look for a domain controller for this domain */
146 if (!cm_get_dc_name(domain, new_conn->controller))
149 /* Initialise SMB connection */
151 if (!(new_conn->cli = cli_initialise(NULL)))
154 if (!resolve_srv_name(new_conn->controller, dest_host, &dest_ip))
157 make_nmb_name(&called, dns_to_netbios_name(new_conn->controller),
159 make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
162 creds.pwd.null_pwd = 1;
164 cli_init_creds(new_conn->cli, &creds);
166 if (!cli_establish_connection(new_conn->cli, new_conn->controller,
167 &dest_ip, &calling, &called, "IPC$",
171 if (!cli_nt_session_open (new_conn->cli, pipe_name))
177 if (!result && new_conn->cli)
178 cli_shutdown(new_conn->cli);
183 /* Return true if a connection is still alive */
185 static BOOL connection_ok(struct winbindd_cm_conn *conn)
187 if (!conn->cli->initialised)
190 if (!conn->cli->fd == -1)
196 /* Return a LSA policy handle on a domain */
198 CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
200 struct winbindd_cm_conn *conn;
201 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
203 static CLI_POLICY_HND hnd;
205 /* Look for existing connections */
207 for (conn = cm_conns; conn; conn = conn->next) {
208 if (strequal(conn->domain, domain) &&
209 strequal(conn->pipe_name, PIPE_LSARPC)) {
211 if (!connection_ok(conn))
218 /* Create a new one */
220 if (!(conn = (struct winbindd_cm_conn *)
221 malloc(sizeof(struct winbindd_cm_conn))))
226 if (!cm_open_connection(domain, PIPE_LSARPC, conn)) {
227 DEBUG(3, ("Could not connect to a dc for domain %s\n",
232 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
233 des_access, &conn->pol);
235 if (!NT_STATUS_IS_OK(result))
240 DLIST_ADD(cm_conns, conn);
249 /* Return a SAM policy handle on a domain */
251 CLI_POLICY_HND *cm_get_sam_handle(char *domain)
253 struct winbindd_cm_conn *conn;
254 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
256 static CLI_POLICY_HND hnd;
258 /* Look for existing connections */
260 for (conn = cm_conns; conn; conn = conn->next) {
261 if (strequal(conn->domain, domain) &&
262 strequal(conn->pipe_name, PIPE_SAMR) &&
263 conn->sam_pipe_type == SAM_PIPE_BASIC) {
265 if (!connection_ok(conn))
272 /* Create a new one */
274 if (!(conn = (struct winbindd_cm_conn *)
275 malloc(sizeof(struct winbindd_cm_conn))))
280 if (!cm_open_connection(domain, PIPE_SAMR, conn)) {
281 DEBUG(3, ("Could not connect to a dc for domain %s\n",
286 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx, des_access,
289 if (!NT_STATUS_IS_OK(result))
294 DLIST_ADD(cm_conns, conn);
303 /* Return a SAM domain policy handle on a domain */
305 CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
307 struct winbindd_cm_conn *conn, *basic_conn = NULL;
308 static CLI_POLICY_HND hnd;
310 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
312 /* Look for existing connections */
314 for (conn = cm_conns; conn; conn = conn->next) {
315 if (strequal(conn->domain, domain) &&
316 strequal(conn->pipe_name, PIPE_SAMR) &&
317 conn->sam_pipe_type == SAM_PIPE_DOM) {
319 if (!connection_ok(conn))
326 /* Create a basic handle to open a domain handle from */
328 if (!cm_get_sam_handle(domain))
331 for (conn = cm_conns; conn; conn = conn->next) {
332 if (strequal(conn->domain, domain) &&
333 strequal(conn->pipe_name, PIPE_SAMR) &&
334 conn->sam_pipe_type == SAM_PIPE_BASIC)
338 if (!(conn = (struct winbindd_cm_conn *)
339 malloc(sizeof(struct winbindd_cm_conn))))
344 fstrcpy(conn->domain, basic_conn->domain);
345 fstrcpy(conn->controller, basic_conn->controller);
346 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
348 conn->sam_pipe_type = SAM_PIPE_DOM;
349 conn->cli = basic_conn->cli;
351 result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
352 &basic_conn->pol, des_access,
353 domain_sid, &conn->pol);
355 if (!NT_STATUS_IS_OK(result))
360 DLIST_ADD(cm_conns, conn);
369 /* Return a SAM policy handle on a domain user */
371 CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
374 struct winbindd_cm_conn *conn, *basic_conn = NULL;
375 static CLI_POLICY_HND hnd;
377 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
379 /* Look for existing connections */
381 for (conn = cm_conns; conn; conn = conn->next) {
382 if (strequal(conn->domain, domain) &&
383 strequal(conn->pipe_name, PIPE_SAMR) &&
384 conn->sam_pipe_type == SAM_PIPE_USER &&
385 conn->user_rid == user_rid) {
387 if (!connection_ok(conn))
394 /* Create a domain handle to open a user handle from */
396 if (!cm_get_sam_dom_handle(domain, domain_sid))
399 for (conn = cm_conns; conn; conn = conn->next) {
400 if (strequal(conn->domain, domain) &&
401 strequal(conn->pipe_name, PIPE_SAMR) &&
402 conn->sam_pipe_type == SAM_PIPE_DOM)
407 DEBUG(0, ("No domain sam handle was created!\n"));
411 if (!(conn = (struct winbindd_cm_conn *)
412 malloc(sizeof(struct winbindd_cm_conn))))
417 fstrcpy(conn->domain, basic_conn->domain);
418 fstrcpy(conn->controller, basic_conn->controller);
419 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
421 conn->sam_pipe_type = SAM_PIPE_USER;
422 conn->cli = basic_conn->cli;
423 conn->user_rid = user_rid;
425 result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
426 &basic_conn->pol, des_access, user_rid,
429 if (!NT_STATUS_IS_OK(result))
434 DLIST_ADD(cm_conns, conn);
443 /* Return a SAM policy handle on a domain group */
445 CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
448 struct winbindd_cm_conn *conn, *basic_conn = NULL;
449 static CLI_POLICY_HND hnd;
451 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
453 /* Look for existing connections */
455 for (conn = cm_conns; conn; conn = conn->next) {
456 if (strequal(conn->domain, domain) &&
457 strequal(conn->pipe_name, PIPE_SAMR) &&
458 conn->sam_pipe_type == SAM_PIPE_GROUP &&
459 conn->group_rid == group_rid) {
461 if (!connection_ok(conn))
468 /* Create a domain handle to open a user handle from */
470 if (!cm_get_sam_dom_handle(domain, domain_sid))
473 for (conn = cm_conns; conn; conn = conn->next) {
474 if (strequal(conn->domain, domain) &&
475 strequal(conn->pipe_name, PIPE_SAMR) &&
476 conn->sam_pipe_type == SAM_PIPE_DOM)
481 DEBUG(0, ("No domain sam handle was created!\n"));
485 if (!(conn = (struct winbindd_cm_conn *)
486 malloc(sizeof(struct winbindd_cm_conn))))
491 fstrcpy(conn->domain, basic_conn->domain);
492 fstrcpy(conn->controller, basic_conn->controller);
493 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
495 conn->sam_pipe_type = SAM_PIPE_GROUP;
496 conn->cli = basic_conn->cli;
497 conn->group_rid = group_rid;
499 result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
500 &basic_conn->pol, des_access, group_rid,
503 if (!NT_STATUS_IS_OK(result))
508 DLIST_ADD(cm_conns, conn);