Change our Domain controller lookup routines to more carefully seperate
[metze/samba/wip.git] / source3 / nsswitch / winbindd_cm.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon connection manager
5
6    Copyright (C) Tim Potter 2001
7    Copyright (C) Andrew Bartlett 2002
8    
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.
13    
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.
18    
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.
22 */
23
24 /*
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:
28   
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
32          selection etc
33        - manage re-entrancy for when winbindd becomes able to handle
34          multiple outstanding rpc requests
35   
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.
42
43    The TNG design is quite good but I disagree with some aspects of the
44    implementation. -tpot
45
46  */
47
48 /*
49    TODO:
50
51      - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be
52        moved down into another function.
53
54      - Take care when destroying cli_structs as they can be shared between
55        various sam handles.
56
57  */
58
59 #include "includes.h"
60 #include "winbindd.h"
61
62 #undef DBGC_CLASS
63 #define DBGC_CLASS DBGC_WINBIND
64
65 /* Global list of connections.  Initially a DLIST but can become a hash
66    table or whatever later. */
67
68 struct winbindd_cm_conn {
69         struct winbindd_cm_conn *prev, *next;
70         fstring domain;
71         fstring controller;
72         fstring pipe_name;
73         size_t mutex_ref_count;
74         struct cli_state *cli;
75         POLICY_HND pol;
76 };
77
78 static struct winbindd_cm_conn *cm_conns = NULL;
79
80
81 /* Choose between anonymous or authenticated connections.  We need to use
82    an authenticated connection if DCs have the RestrictAnonymous registry
83    entry set > 0, or the "Additional restrictions for anonymous
84    connections" set in the win2k Local Security Policy. 
85    
86    Caller to free() result in domain, username, password
87 */
88
89 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
90 {
91         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
92         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
93         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
94         
95         if (*username && **username) {
96
97                 if (!*domain || !**domain)
98                         *domain = smb_xstrdup(lp_workgroup());
99                 
100                 if (!*password || !**password)
101                         *password = smb_xstrdup("");
102
103                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
104                           *domain, *username));
105
106         } else {
107                 DEBUG(3, ("IPC$ connections done anonymously\n"));
108                 *username = smb_xstrdup("");
109                 *domain = smb_xstrdup("");
110                 *password = smb_xstrdup("");
111         }
112 }
113
114 /* Open a connction to the remote server, cache failures for 30 seconds */
115
116 static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const int pipe_index,
117                                    struct winbindd_cm_conn *new_conn)
118 {
119         NTSTATUS result;
120         char *machine_password; 
121         char *machine_krb5_principal, *ipc_username, *ipc_domain, *ipc_password;
122         struct in_addr dc_ip;
123         int i;
124         BOOL retry = True;
125
126         ZERO_STRUCT(dc_ip);
127
128         fstrcpy(new_conn->domain, domain->name);
129         
130         /* connection failure cache has been moved inside of get_dc_name
131            so we can deal with half dead DC's   --jerry */
132
133         if (!get_dc_name(domain->name, domain->alt_name[0] ? domain->alt_name : NULL, 
134                          new_conn->controller, &dc_ip)) {
135                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
136                 add_failed_connection_entry(domain->name, "", result);
137                 return result;
138         }
139                 
140         /* Initialise SMB connection */
141         fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
142
143 /* grab stored passwords */
144         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
145         
146         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
147                 SAFE_FREE(machine_password);
148                 return NT_STATUS_NO_MEMORY;
149         }
150
151         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
152
153         for (i = 0; retry && (i < 3); i++) {
154                 BOOL got_mutex;
155                 if (!(got_mutex = secrets_named_mutex(new_conn->controller, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
156                         DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn->controller));
157                         result = NT_STATUS_POSSIBLE_DEADLOCK;
158                         continue;
159                 }
160                 
161                 new_conn->cli = NULL;
162                 result = cli_start_connection(&new_conn->cli, global_myname(), 
163                                               new_conn->controller, 
164                                               &dc_ip, 0, Undefined, 
165                                               CLI_FULL_CONNECTION_USE_KERBEROS, 
166                                               &retry);
167
168                 if (NT_STATUS_IS_OK(result)) {
169
170                         /* reset the error code */
171                         result = NT_STATUS_UNSUCCESSFUL; 
172
173                         /* Krb5 session */
174                         
175                         if ((lp_security() == SEC_ADS) 
176                                 && (new_conn->cli->protocol >= PROTOCOL_NT1 && new_conn->cli->capabilities & CAP_EXTENDED_SECURITY)) {
177                                 new_conn->cli->use_kerberos = True;
178                                 DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n", 
179                                           new_conn->controller, global_myname(), machine_krb5_principal));
180
181                                 result = NT_STATUS_OK;
182
183                                 if (!NT_STATUS_IS_OK(result = cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, 
184                                                               machine_password, 
185                                                               domain->name))) {
186                                         DEBUG(4,("failed kerberos session setup with %s\n", nt_errstr(result)));
187                                 }
188                         }
189                         new_conn->cli->use_kerberos = False;
190                         
191                         /* only do this is we have a username/password for thr IPC$ connection */
192                         
193                         if ( !NT_STATUS_IS_OK(result) 
194                                 && new_conn->cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
195                                 && strlen(ipc_username) )
196                         {       
197                                 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n", 
198                                           new_conn->controller, global_myname(), ipc_domain, ipc_username));
199
200                                 result = NT_STATUS_OK;
201
202                                 if (!cli_session_setup(new_conn->cli, ipc_username, 
203                                                        ipc_password, strlen(ipc_password)+1, 
204                                                        ipc_password, strlen(ipc_password)+1, 
205                                                        domain->name)) {
206                                         result = cli_nt_error(new_conn->cli);
207                                         DEBUG(4,("failed authenticated session setup with %s\n", nt_errstr(result)));
208                                         if (NT_STATUS_IS_OK(result)) 
209                                                 result = NT_STATUS_UNSUCCESSFUL;
210                                 }
211                         }
212                         
213                         /* anonymous is all that is left if we get to here */
214                         
215                         if (!NT_STATUS_IS_OK(result)) { 
216                         
217                                 DEBUG(5, ("anonymous connection attempt to %s from %s\n", 
218                                           new_conn->controller, global_myname()));
219                                           
220                                 result = NT_STATUS_OK;
221
222                                 if (!cli_session_setup(new_conn->cli, "", NULL, 0, NULL, 0, "")) 
223                                 {
224                                         result = cli_nt_error(new_conn->cli);
225                                         DEBUG(4,("failed anonymous session setup with %s\n", nt_errstr(result)));
226                                         if (NT_STATUS_IS_OK(result)) 
227                                                 result = NT_STATUS_UNSUCCESSFUL;
228                                 } 
229                                 
230                         }
231
232                         if (NT_STATUS_IS_OK(result) && !cli_send_tconX(new_conn->cli, "IPC$", "IPC",
233                                                                        "", 0)) {
234                                 result = cli_nt_error(new_conn->cli);
235                                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
236                                 cli_shutdown(new_conn->cli);
237                                 if (NT_STATUS_IS_OK(result)) {
238                                         result = NT_STATUS_UNSUCCESSFUL;
239                                 }
240                         }
241                 }
242
243                 if (NT_STATUS_IS_OK(result)) {
244                         struct ntuser_creds creds;
245                         init_creds(&creds, ipc_username, ipc_domain, ipc_password);
246                         cli_init_creds(new_conn->cli, &creds);
247                 }
248
249                 if (got_mutex)
250                         secrets_named_mutex_release(new_conn->controller);
251
252                 if (NT_STATUS_IS_OK(result))
253                         break;
254         }
255
256         SAFE_FREE(ipc_username);
257         SAFE_FREE(ipc_domain);
258         SAFE_FREE(ipc_password);
259         SAFE_FREE(machine_password);
260
261         if (!NT_STATUS_IS_OK(result)) {
262                 add_failed_connection_entry(domain->name, new_conn->controller, result);
263                 return result;
264         }
265         
266         /* set the domain if empty; needed for schannel connections */
267         if ( !*new_conn->cli->domain )
268                 fstrcpy( new_conn->cli->domain, domain->name );
269                 
270         
271         if ( !cli_nt_session_open (new_conn->cli, pipe_index) ) {
272                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
273                 /* 
274                  * only cache a failure if we are not trying to open the 
275                  * **win2k** specific lsarpc UUID.  This could be an NT PDC 
276                  * and therefore a failure is normal.  This should probably
277                  * be abstracted to a check for 2k specific pipes and wondering
278                  * if the PDC is an NT4 box.   but since there is only one 2k 
279                  * specific UUID right now, i'm not going to bother.  --jerry
280                  */
281                 if ( !is_win2k_pipe(pipe_index) )
282                         add_failed_connection_entry(domain->name, new_conn->controller, result);
283                 cli_shutdown(new_conn->cli);
284                 return result;
285         }
286
287         return NT_STATUS_OK;
288 }
289
290 /************************************************************************
291  Wrapper around statuc cm_open_connection to retreive a freshly
292  setup cli_state struct
293 ************************************************************************/
294
295 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
296                                struct cli_state **cli)
297 {
298         NTSTATUS result;
299         struct winbindd_cm_conn conn;
300         
301         result = cm_open_connection( domain, pipe_index, &conn );
302         
303         if ( NT_STATUS_IS_OK(result) ) 
304                 *cli = conn.cli;
305
306         return result;
307 }
308
309 /* Return true if a connection is still alive */
310
311 static BOOL connection_ok(struct winbindd_cm_conn *conn)
312 {
313         if (!conn) {
314                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
315                 return False;
316         }
317
318         if (!conn->cli) {
319                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
320                           conn->controller, conn->domain, conn->pipe_name));
321                 return False;
322         }
323
324         if (!conn->cli->initialised) {
325                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
326                           conn->controller, conn->domain, conn->pipe_name));
327                 return False;
328         }
329
330         if (conn->cli->fd == -1) {
331                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
332                           conn->controller, conn->domain, conn->pipe_name));
333                 return False;
334         }
335         
336         return True;
337 }
338
339 /* Search the cache for a connection. If there is a broken one,
340    shut it down properly and return NULL. */
341
342 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
343                                struct winbindd_cm_conn **conn_out) 
344 {
345         struct winbindd_cm_conn *conn;
346
347         for (conn = cm_conns; conn; ) {
348                 if (strequal(conn->domain, domain->name) && 
349                     strequal(conn->pipe_name, pipe_name)) {
350                         if (!connection_ok(conn)) {
351                                 /* Dead connection - remove it. */
352                                 struct winbindd_cm_conn *conn_temp = conn->next;
353                                 if (conn->cli)
354                                         cli_shutdown(conn->cli);
355                                 DLIST_REMOVE(cm_conns, conn);
356                                 SAFE_FREE(conn);
357                                 conn = conn_temp;  /* Keep the loop moving */
358                                 continue;
359                         } else {
360                                 break;
361                         }
362                 }
363                 conn = conn->next;
364         }
365
366         *conn_out = conn;
367 }
368
369 /* Initialize a new connection up to the RPC BIND. */
370
371 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
372                                   struct winbindd_cm_conn **conn_out)
373 {
374         struct winbindd_cm_conn *conn;
375         NTSTATUS result;
376
377         if (!(conn = malloc(sizeof(*conn))))
378                 return NT_STATUS_NO_MEMORY;
379                 
380         ZERO_STRUCTP(conn);
381                 
382         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
383                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
384                           domain->name, pipe_name, nt_errstr(result)));
385                 SAFE_FREE(conn);
386                 return result;
387         }
388         DLIST_ADD(cm_conns, conn);
389
390         *conn_out = conn;
391         return NT_STATUS_OK;
392 }
393
394 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
395
396 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
397                                           struct winbindd_cm_conn **conn_out)
398 {
399         find_cm_connection(domain, pipe_name, conn_out);
400
401         if (*conn_out != NULL)
402                 return NT_STATUS_OK;
403
404         return new_cm_connection(domain, pipe_name, conn_out);
405 }
406
407 /**********************************************************************************
408 **********************************************************************************/
409
410 BOOL cm_check_for_native_mode_win2k( struct winbindd_domain *domain )
411 {
412         NTSTATUS                result;
413         struct winbindd_cm_conn conn;
414         DS_DOMINFO_CTR          ctr;
415         BOOL                    ret = False;
416         
417         ZERO_STRUCT( conn );
418         ZERO_STRUCT( ctr );
419         
420         
421         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
422                 DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
423                           domain->name, nt_errstr(result)));
424                 return False;
425         }
426         
427         if ( conn.cli ) {
428                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
429                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
430                         ret = False;
431                         goto done;
432                 }
433         }
434                                 
435         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
436                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
437                 ret = True;
438
439 done:
440
441         /* close the connection;  no other cals use this pipe and it is called only
442            on reestablishing the domain list   --jerry */
443
444         if ( conn.cli )
445                 cli_shutdown( conn.cli );
446         
447         return ret;
448 }
449
450
451
452 /* Return a LSA policy handle on a domain */
453
454 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
455 {
456         struct winbindd_cm_conn *conn;
457         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
458         NTSTATUS result;
459         static CLI_POLICY_HND hnd;
460
461         /* Look for existing connections */
462
463         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
464                 return result;
465
466         /* This *shitty* code needs scrapping ! JRA */
467         
468         if (policy_handle_is_valid(&conn->pol)) {
469                 hnd.pol = conn->pol;
470                 hnd.cli = conn->cli;
471                 *return_hnd = &hnd;
472
473                 return NT_STATUS_OK;
474         }
475         
476         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
477                                      des_access, &conn->pol);
478
479         if (!NT_STATUS_IS_OK(result)) {
480                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
481                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
482                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
483                                 return result;
484
485                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
486                                                      des_access, &conn->pol);
487                 }
488
489                 if (!NT_STATUS_IS_OK(result)) {
490                         cli_shutdown(conn->cli);
491                         DLIST_REMOVE(cm_conns, conn);
492                         SAFE_FREE(conn);
493                         return result;
494                 }
495         }       
496
497         hnd.pol = conn->pol;
498         hnd.cli = conn->cli;
499
500         *return_hnd = &hnd;
501
502         return NT_STATUS_OK;
503 }
504
505 /* Return a SAM policy handle on a domain */
506
507 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
508
509         struct winbindd_cm_conn *conn;
510         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
511         NTSTATUS result;
512         static CLI_POLICY_HND hnd;
513
514         /* Look for existing connections */
515
516         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
517                 return result;
518         
519         /* This *shitty* code needs scrapping ! JRA */
520         
521         if (policy_handle_is_valid(&conn->pol)) {
522                 hnd.pol = conn->pol;
523                 hnd.cli = conn->cli;
524                 
525                 *return_hnd = &hnd;
526
527                 return NT_STATUS_OK;
528         }
529         
530         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
531                                   des_access, &conn->pol);
532
533         if (!NT_STATUS_IS_OK(result)) {
534                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
535                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
536                 
537                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
538                                 return result;
539
540                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
541                                                   des_access, &conn->pol);
542                 }
543
544                 if (!NT_STATUS_IS_OK(result)) {
545                 
546                         cli_shutdown(conn->cli);
547                         DLIST_REMOVE(cm_conns, conn);
548                         SAFE_FREE(conn);
549                         
550                         return result;
551                 }
552         }       
553
554         hnd.pol = conn->pol;
555         hnd.cli = conn->cli;
556
557         *return_hnd = &hnd;
558
559         return NT_STATUS_OK;
560 }
561
562 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
563    netlogon pipe as no handle is returned. */
564
565 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
566                              const unsigned char *trust_passwd, 
567                              uint32 sec_channel_type,
568                              BOOL fresh,
569                              struct cli_state **cli)
570 {
571         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
572         struct winbindd_cm_conn *conn;
573         fstring lock_name;
574         BOOL got_mutex;
575
576         if (!cli)
577                 return NT_STATUS_INVALID_PARAMETER;
578
579         /* Open an initial conection - keep the mutex. */
580
581         find_cm_connection(domain, PIPE_NETLOGON, &conn);
582
583         if ( fresh && (conn != NULL) ) {
584                 cli_shutdown(conn->cli);
585                 conn->cli = NULL;
586
587                 conn = NULL;
588
589                 /* purge connection from cache */
590                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
591                 if (conn != NULL) {
592                         DEBUG(0,("Could not purge connection\n"));
593                         return NT_STATUS_UNSUCCESSFUL;
594                 }
595         }
596
597         if (conn != NULL) {
598                 *cli = conn->cli;
599                 return NT_STATUS_OK;
600         }
601
602         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
603
604         if (!NT_STATUS_IS_OK(result))
605                 return result;
606         
607         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
608
609         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
610                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
611         }
612         
613         if ( sec_channel_type == SEC_CHAN_DOMAIN )
614                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
615                         
616                 
617         fstrcpy( conn->cli->domain, domain->name);
618        
619         
620         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
621         
622         if (got_mutex)
623                 secrets_named_mutex_release(lock_name);
624                                 
625         if (!NT_STATUS_IS_OK(result)) {
626                 cli_shutdown(conn->cli);
627                 DLIST_REMOVE(cm_conns, conn);
628                 SAFE_FREE(conn);
629                 return result;
630         }
631
632         *cli = conn->cli;
633
634         return result;
635 }
636
637 /* Dump the current connection status */
638
639 static void dump_conn_list(void)
640 {
641         struct winbindd_cm_conn *con;
642
643         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
644
645         for(con = cm_conns; con; con = con->next) {
646                 char *msg;
647
648                 /* Display pipe info */
649                 
650                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
651                         DEBUG(0, ("Error: not enough memory!\n"));
652                 } else {
653                         DEBUG(0, ("%s\n", msg));
654                         SAFE_FREE(msg);
655                 }
656         }
657 }
658
659 void winbindd_cm_status(void)
660 {
661         /* List open connections */
662
663         DEBUG(0, ("winbindd connection manager status:\n"));
664
665         if (cm_conns)
666                 dump_conn_list();
667         else
668                 DEBUG(0, ("\tNo active connections\n"));
669 }
670
671 /* Close all cached connections */
672
673 void winbindd_cm_flush(void)
674 {
675         struct winbindd_cm_conn *conn, tmp;
676
677         /* Flush connection cache */
678
679         for (conn = cm_conns; conn; conn = conn->next) {
680
681                 if (!connection_ok(conn))
682                         continue;
683
684                 DEBUG(10, ("Closing connection to %s on %s\n",
685                         conn->pipe_name, conn->controller));
686
687                 if (conn->cli)
688                         cli_shutdown(conn->cli);
689
690                 tmp.next = conn->next;
691
692                 DLIST_REMOVE(cm_conns, conn);
693                 SAFE_FREE(conn);
694                 conn = &tmp;
695         }
696
697         /* Flush failed connection cache */
698
699         flush_negative_conn_cache();
700 }