c9aef2905f254bdee3f3768d719647b7d4050cf6
[tprouty/samba.git] / source / 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         struct cli_state *cli;
74         POLICY_HND pol;
75 };
76
77 static struct winbindd_cm_conn *cm_conns = NULL;
78
79 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
80                                           const char *pipe_name,
81                                           struct winbindd_cm_conn **conn_out);
82
83 /* Choose between anonymous or authenticated connections.  We need to use
84    an authenticated connection if DCs have the RestrictAnonymous registry
85    entry set > 0, or the "Additional restrictions for anonymous
86    connections" set in the win2k Local Security Policy. 
87    
88    Caller to free() result in domain, username, password
89 */
90
91 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
92 {
93         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
94         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
95         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
96         
97         if (*username && **username) {
98
99                 if (!*domain || !**domain)
100                         *domain = smb_xstrdup(lp_workgroup());
101                 
102                 if (!*password || !**password)
103                         *password = smb_xstrdup("");
104
105                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
106                           *domain, *username));
107
108         } else {
109                 DEBUG(3, ("IPC$ connections done anonymously\n"));
110                 *username = smb_xstrdup("");
111                 *domain = smb_xstrdup("");
112                 *password = smb_xstrdup("");
113         }
114 }
115
116 /*
117   setup for schannel on any pipes opened on this connection
118 */
119 static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
120 {
121         NTSTATUS ret;
122         uchar trust_password[16];
123         uint32 sec_channel_type;
124         DOM_SID sid;
125         time_t lct;
126
127         /* use the domain trust password if we're on a DC 
128            and this is not our domain */
129         
130         if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
131                 char *pass = NULL;
132                 
133                 if ( !secrets_fetch_trusted_domain_password( domain, 
134                         &pass, &sid, &lct) )
135                 {
136                         return NT_STATUS_UNSUCCESSFUL;
137                 }       
138
139                 sec_channel_type = SEC_CHAN_DOMAIN;
140                 E_md4hash(pass, trust_password);
141                 SAFE_FREE( pass );
142                 
143         } else {
144                 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145                         trust_password, NULL, &sec_channel_type)) 
146                 {
147                         return NT_STATUS_UNSUCCESSFUL;
148                 }
149         }
150
151         ret = cli_nt_setup_netsec(cli, sec_channel_type, 
152                 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
153
154         return ret;
155 }
156
157 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
158                                      fstring dcname, struct in_addr *dc_ip)
159 {
160         struct winbindd_domain *our_domain;
161         NTSTATUS result;
162         struct winbindd_cm_conn *conn;
163         TALLOC_CTX *mem_ctx;
164
165         fstring tmp;
166         char *p;
167
168         if (IS_DC)
169                 return False;
170
171         if (domain->primary)
172                 return False;
173
174         if ((our_domain = find_our_domain()) == NULL)
175                 return False;
176
177         result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
178         if (!NT_STATUS_IS_OK(result))
179                 return False;
180
181         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
182                 return False;
183
184         result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
185
186         talloc_destroy(mem_ctx);
187
188         if (!NT_STATUS_IS_OK(result))
189                 return False;
190
191         /* cli_netlogon_getdcname gives us a name with \\ */
192         p = tmp;
193         if (*p == '\\') p+=1;
194         if (*p == '\\') p+=1;
195
196         fstrcpy(dcname, p);
197
198         if (!resolve_name(dcname, dc_ip, 0x20))
199                 return False;
200
201         return True;
202 }
203
204 /************************************************************************
205  Given a fd with a just-connected TCP connection to a DC, open a connection
206  to the pipe.
207 ************************************************************************/
208
209 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
210                                       const int sockfd,
211                                       const int pipe_index,
212                                       const char *controller,
213                                       struct cli_state **cli,
214                                       BOOL *retry)
215 {
216         char *machine_password, *machine_krb5_principal;
217         char *ipc_username, *ipc_domain, *ipc_password;
218         struct ntuser_creds creds;
219
220         BOOL got_mutex;
221         BOOL add_failed_connection = True;
222
223         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
224
225         struct sockaddr peeraddr;
226         socklen_t peeraddr_len;
227
228         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
229
230         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
231                                                           NULL);
232         
233         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
234                      lp_realm()) == -1) {
235                 SAFE_FREE(machine_password);
236                 return NT_STATUS_NO_MEMORY;
237         }
238
239         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
240
241         *retry = True;
242
243         got_mutex = secrets_named_mutex(controller,
244                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
245
246         if (!got_mutex) {
247                 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248                          controller));
249                 result = NT_STATUS_POSSIBLE_DEADLOCK;
250                 goto done;
251         }
252
253         if ((*cli = cli_initialise(NULL)) == NULL) {
254                 DEBUG(1, ("Could not cli_initialize\n"));
255                 result = NT_STATUS_NO_MEMORY;
256                 goto done;
257         }
258
259         (*cli)->timeout = 10000;        /* 10 seconds */
260         (*cli)->fd = sockfd;
261         fstrcpy((*cli)->desthost, controller);
262         (*cli)->use_kerberos = True;
263
264         peeraddr_len = sizeof(peeraddr);
265
266         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
267             (peeraddr_len != sizeof(struct sockaddr_in)) ||
268             (peeraddr_in->sin_family != PF_INET))
269                 goto done;
270
271         if (ntohs(peeraddr_in->sin_port) == 139) {
272                 struct nmb_name calling;
273                 struct nmb_name called;
274
275                 make_nmb_name(&calling, global_myname(), 0x0);
276                 make_nmb_name(&called, "*SMBSERVER", 0x20);
277
278                 if (!cli_session_request(*cli, &calling, &called)) {
279                         DEBUG(8, ("cli_session_request failed for %s\n",
280                                   controller));
281                         goto done;
282                 }
283         }
284
285         cli_setup_signing_state(*cli, Undefined);
286
287         if (!cli_negprot(*cli)) {
288                 DEBUG(1, ("cli_negprot failed\n"));
289                 cli_shutdown(*cli);
290                 goto done;
291         }
292
293         /* Krb5 session */
294                         
295         if ((lp_security() == SEC_ADS) 
296             && ((*cli)->protocol >= PROTOCOL_NT1 &&
297                 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
298
299                 ADS_STATUS ads_status;
300                 (*cli)->use_kerberos = True;
301                 DEBUG(5, ("connecting to %s from %s with kerberos principal "
302                           "[%s]\n", controller, global_myname(),
303                           machine_krb5_principal));
304
305                 ads_status = cli_session_setup_spnego(*cli,
306                                                       machine_krb5_principal, 
307                                                       machine_password, 
308                                                       lp_workgroup());
309
310                 if (!ADS_ERR_OK(ads_status))
311                         DEBUG(4,("failed kerberos session setup with %s\n",
312                                  ads_errstr(ads_status)));
313
314                 result = ads_ntstatus(ads_status);
315         }
316
317         if (NT_STATUS_IS_OK(result))
318                 goto session_setup_done;
319
320         /* Fall back to non-kerberos session setup */
321
322         (*cli)->use_kerberos = False;
323
324         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
325             (strlen(ipc_username) > 0)) {
326
327                 /* Only try authenticated if we have a username */
328
329                 DEBUG(5, ("connecting to %s from %s with username "
330                           "[%s]\\[%s]\n",  controller, global_myname(),
331                           ipc_domain, ipc_username));
332
333                 if (cli_session_setup(*cli, ipc_username,
334                                       ipc_password, strlen(ipc_password)+1,
335                                       ipc_password, strlen(ipc_password)+1,
336                                       ipc_domain)) {
337                         DEBUG(5, ("authenticated session setup failed\n"));
338                         goto session_setup_done;
339                 }
340         }
341
342         /* Fall back to anonymous connection, this might fail later */
343
344         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
345                 DEBUG(5, ("Connected anonymously\n"));
346                 goto session_setup_done;
347         }
348
349         result = cli_nt_error(*cli);
350
351         if (NT_STATUS_IS_OK(result))
352                 result = NT_STATUS_UNSUCCESSFUL;
353
354         /* We can't session setup */
355
356         goto done;
357
358  session_setup_done:
359
360         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
361
362                 result = cli_nt_error(*cli);
363
364                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
365
366                 if (NT_STATUS_IS_OK(result))
367                         result = NT_STATUS_UNSUCCESSFUL;
368
369                 cli_shutdown(*cli);
370                 goto done;
371         }
372
373         init_creds(&creds, ipc_username, ipc_domain, ipc_password);
374         cli_init_creds(*cli, &creds);
375
376         secrets_named_mutex_release(controller);
377         got_mutex = False;
378         *retry = False;
379
380         if (domain->primary || IS_DC) {
381                 NTSTATUS status = setup_schannel( *cli, domain->name );
382                 if (!NT_STATUS_IS_OK(status)) {
383                         DEBUG(3,("schannel refused - continuing without "
384                                  "schannel (%s)\n", nt_errstr(status)));
385                 }
386         }
387
388         /* set the domain if empty; needed for schannel connections */
389         if ( !*(*cli)->domain )
390                 fstrcpy( (*cli)->domain, domain->name );
391
392         if ( !cli_nt_session_open (*cli, pipe_index) ) {
393
394                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
395
396                 /* This might be a NT4 DC */
397                 if ( is_win2k_pipe(pipe_index) )
398                         add_failed_connection = False;
399
400                 cli_shutdown(*cli);
401                 goto done;
402         }
403
404         result = NT_STATUS_OK;
405         add_failed_connection = False;
406
407  done:
408         if (got_mutex)
409                 secrets_named_mutex_release(controller);
410
411         SAFE_FREE(machine_password);
412         SAFE_FREE(machine_krb5_principal);
413         SAFE_FREE(ipc_username);
414         SAFE_FREE(ipc_domain);
415         SAFE_FREE(ipc_password);
416
417         if (add_failed_connection)
418                 add_failed_connection_entry(domain->name, controller, result);
419
420         return result;
421 }
422
423 struct dc_name_ip {
424         fstring name;
425         struct in_addr ip;
426 };
427
428 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
429                               const char *dcname, struct in_addr ip,
430                               struct dc_name_ip **dcs, int *num)
431 {
432         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
433                 return False;
434
435         *dcs = talloc_realloc(mem_ctx, *dcs, ((*num)+1) * sizeof(**dcs));
436
437         if (*dcs == NULL)
438                 return False;
439
440         fstrcpy((*dcs)[*num].name, dcname);
441         (*dcs)[*num].ip = ip;
442         *num += 1;
443         return True;
444 }
445
446 static BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
447                                 const char *str, char ***array, int *num)
448 {
449         char *dup_str = talloc_strdup(mem_ctx, str);
450
451         *array = talloc_realloc(mem_ctx, *array, ((*num)+1) * sizeof(**array));
452
453         if ((*array == NULL) || (dup_str == NULL))
454                 return False;
455
456         (*array)[*num] = dup_str;
457         *num += 1;
458         return True;
459 }
460
461 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
462                                   struct in_addr ip, uint16 port,
463                                   struct sockaddr_in **addrs, int *num)
464 {
465         *addrs = talloc_realloc(mem_ctx, *addrs, ((*num)+1) * sizeof(**addrs));
466
467         if (*addrs == NULL)
468                 return False;
469
470         (*addrs)[*num].sin_family = PF_INET;
471         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
472         (*addrs)[*num].sin_port = htons(port);
473
474         *num += 1;
475         return True;
476 }
477
478 static BOOL get_dcs_1c(TALLOC_CTX *mem_ctx,
479                        const struct winbindd_domain *domain,
480                        struct dc_name_ip **dcs, int *num_dcs)
481 {
482         struct ip_service *iplist = NULL;
483         int i, num = 0;
484
485         if (!internal_resolve_name(domain->name, 0x1c, &iplist, &num,
486                                    lp_name_resolve_order()))
487                 return False;
488
489         /* Now try to find the server names of at least one IP address, hosts
490          * not replying are cached as such */
491
492         for (i=0; i<num; i++) {
493
494                 fstring dcname;
495
496                 if (!name_status_find(domain->name, 0x1c, 0x20, iplist[i].ip,
497                                       dcname))
498                         continue;
499
500                 if (add_one_dc_unique(mem_ctx, domain->name, dcname,
501                                       iplist[i].ip, dcs, num_dcs)) {
502                         /* One DC responded, so we assume that he will also
503                            work on 139/445 */
504                         break;
505                 }
506         }
507
508         return True;
509 }
510
511 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
512                     struct dc_name_ip **dcs, int *num_dcs)
513 {
514         fstring dcname;
515         struct in_addr ip;
516         BOOL is_our_domain;
517
518         const char *p;
519
520         is_our_domain = strequal(domain->name, lp_workgroup());
521
522         if (!is_our_domain && get_dc_name_via_netlogon(domain, dcname, &ip) &&
523             add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs))
524                         return True;
525
526         if (!is_our_domain) {
527                 /* NETLOGON to our own domain could not give us a DC name
528                  * (which is an error), fall back to looking up domain#1c */
529                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
530         }
531
532         if (must_use_pdc(domain->name) && get_pdc_ip(domain->name, &ip)) {
533
534                 if (!name_status_find(domain->name, 0x1b, 0x20, ip, dcname))
535                         return False;
536
537                 if (add_one_dc_unique(mem_ctx, domain->name,
538                                       dcname, ip, dcs, num_dcs))
539                         return True;
540         }
541
542         p = lp_passwordserver();
543
544         if (*p == 0)
545                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
546
547         while (next_token(&p, dcname, LIST_SEP, sizeof(dcname))) {
548
549                 if (strequal(dcname, "*")) {
550                         get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
551                         continue;
552                 }
553
554                 if (!resolve_name(dcname, &ip, 0x20))
555                         continue;
556
557                 add_one_dc_unique(mem_ctx, domain->name, dcname, ip,
558                                   dcs, num_dcs);
559         }
560
561         return True;
562 }
563
564 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
565                         const struct winbindd_domain *domain,
566                         fstring dcname, struct sockaddr_in *addr, int *fd)
567 {
568         struct dc_name_ip *dcs = NULL;
569         int num_dcs = 0;
570
571         char **dcnames = NULL;
572         int num_dcnames = 0;
573
574         struct sockaddr_in *addrs = NULL;
575         int num_addrs = 0;
576
577         int i, fd_index;
578
579         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
580                 return False;
581
582         for (i=0; i<num_dcs; i++) {
583
584                 add_string_to_array(mem_ctx, dcs[i].name,
585                                     &dcnames, &num_dcnames);
586                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
587                                       &addrs, &num_addrs);
588
589                 add_string_to_array(mem_ctx, dcs[i].name,
590                                     &dcnames, &num_dcnames);
591                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
592                                       &addrs, &num_addrs);
593         }
594
595         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
596                 return False;
597
598         if (!open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd)) {
599                 for (i=0; i<num_dcs; i++) {
600                         add_failed_connection_entry(domain->name,
601                                                     dcs[i].name,
602                                                     NT_STATUS_UNSUCCESSFUL);
603                 }
604                 return False;
605         }
606
607         fstrcpy(dcname, dcnames[fd_index]);
608         *addr = addrs[fd_index];
609
610         return True;
611 }
612
613 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
614                                    const int pipe_index,
615                                    struct winbindd_cm_conn *new_conn)
616 {
617         TALLOC_CTX *mem_ctx;
618         NTSTATUS result;
619
620         int retries;
621
622         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
623                 return NT_STATUS_NO_MEMORY;
624
625         for (retries = 0; retries < 3; retries++) {
626
627                 int fd = -1;
628                 BOOL retry;
629
630                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
631
632                 if ((strlen(domain->dcname) > 0) &&
633                     NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
634                                                               domain->dcname))) {
635                         int dummy;
636                         if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
637                                                  &dummy, &fd)) {
638                                 fd = -1;
639                         }
640                 }
641
642                 if ((fd == -1) &&
643                     !find_new_dc(mem_ctx, domain, domain->dcname,
644                                  &domain->dcaddr, &fd))
645                         break;
646
647                 new_conn->cli = NULL;
648
649                 result = cm_prepare_connection(domain, fd, pipe_index,
650                                                domain->dcname,
651                                                &new_conn->cli, &retry);
652
653                 if (NT_STATUS_IS_OK(result)) {
654                         fstrcpy(new_conn->domain, domain->name);
655                         /* Initialise SMB connection */
656                         fstrcpy(new_conn->pipe_name,
657                                 get_pipe_name_from_index(pipe_index));
658                         break;
659                 }
660
661                 if (!retry)
662                         break;
663         }
664
665         talloc_destroy(mem_ctx);
666         return result;
667 }
668
669 /************************************************************************
670  Wrapper around statuc cm_open_connection to retreive a freshly
671  setup cli_state struct
672 ************************************************************************/
673
674 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
675                                struct cli_state **cli)
676 {
677         NTSTATUS result;
678         struct winbindd_cm_conn conn;
679         
680         result = cm_open_connection( domain, pipe_index, &conn );
681         
682         if ( NT_STATUS_IS_OK(result) ) 
683                 *cli = conn.cli;
684
685         return result;
686 }
687
688 /* Return true if a connection is still alive */
689
690 static BOOL connection_ok(struct winbindd_cm_conn *conn)
691 {
692         if (!conn) {
693                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
694                 return False;
695         }
696
697         if (!conn->cli) {
698                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
699                           conn->controller, conn->domain, conn->pipe_name));
700                 return False;
701         }
702
703         if (!conn->cli->initialised) {
704                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
705                           conn->controller, conn->domain, conn->pipe_name));
706                 return False;
707         }
708
709         if (conn->cli->fd == -1) {
710                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
711                           conn->controller, conn->domain, conn->pipe_name));
712                 return False;
713         }
714         
715         return True;
716 }
717
718 /* Search the cache for a connection. If there is a broken one,
719    shut it down properly and return NULL. */
720
721 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
722                                struct winbindd_cm_conn **conn_out) 
723 {
724         struct winbindd_cm_conn *conn;
725
726         for (conn = cm_conns; conn; ) {
727                 if (strequal(conn->domain, domain->name) && 
728                     strequal(conn->pipe_name, pipe_name)) {
729                         if (!connection_ok(conn)) {
730                                 /* Dead connection - remove it. */
731                                 struct winbindd_cm_conn *conn_temp = conn->next;
732                                 if (conn->cli)
733                                         cli_shutdown(conn->cli);
734                                 DLIST_REMOVE(cm_conns, conn);
735                                 SAFE_FREE(conn);
736                                 conn = conn_temp;  /* Keep the loop moving */
737                                 continue;
738                         } else {
739                                 break;
740                         }
741                 }
742                 conn = conn->next;
743         }
744
745         *conn_out = conn;
746 }
747
748 /* Initialize a new connection up to the RPC BIND. */
749
750 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
751                                   struct winbindd_cm_conn **conn_out)
752 {
753         struct winbindd_cm_conn *conn;
754         NTSTATUS result;
755
756         if (!(conn = malloc(sizeof(*conn))))
757                 return NT_STATUS_NO_MEMORY;
758                 
759         ZERO_STRUCTP(conn);
760                 
761         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
762                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
763                           domain->name, pipe_name, nt_errstr(result)));
764                 SAFE_FREE(conn);
765                 return result;
766         }
767         DLIST_ADD(cm_conns, conn);
768
769         *conn_out = conn;
770         return NT_STATUS_OK;
771 }
772
773 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
774
775 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
776                                           struct winbindd_cm_conn **conn_out)
777 {
778         find_cm_connection(domain, pipe_name, conn_out);
779
780         if (*conn_out != NULL)
781                 return NT_STATUS_OK;
782
783         return new_cm_connection(domain, pipe_name, conn_out);
784 }
785
786 /**********************************************************************************
787  We can 'sense' certain things about the DC by it's replies to certain questions.
788
789  This tells us if this particular remote server is Active Directory, and if it is
790  native mode.
791 **********************************************************************************/
792
793 void set_dc_type_and_flags( struct winbindd_domain *domain )
794 {
795         NTSTATUS                result;
796         struct winbindd_cm_conn conn;
797         DS_DOMINFO_CTR          ctr;
798         TALLOC_CTX              *mem_ctx = NULL;
799         
800         ZERO_STRUCT( conn );
801         ZERO_STRUCT( ctr );
802         
803         domain->native_mode = False;
804         domain->active_directory = False;
805
806         if (domain->internal) {
807                 domain->initialized = True;
808                 return;
809         }
810         
811         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
812                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
813                           domain->name, nt_errstr(result)));
814                 domain->initialized = True;
815                 return;
816         }
817         
818         if ( conn.cli ) {
819                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
820                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
821                         goto done;
822                 }
823         }
824                                 
825         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
826                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
827                 domain->native_mode = True;
828
829         /* Cheat - shut down the DS pipe, and open LSA */
830
831         cli_nt_session_close(conn.cli);
832
833         if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
834                 char *domain_name = NULL;
835                 char *dns_name = NULL;
836                 DOM_SID *dom_sid = NULL;
837
838                 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
839                 if (!mem_ctx) {
840                         DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
841                         return;
842                 }
843
844                 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
845                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
846                                               &conn.pol);
847                 
848                 if (NT_STATUS_IS_OK(result)) {
849                         /* This particular query is exactly what Win2k clients use 
850                            to determine that the DC is active directory */
851                         result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
852                                                             &conn.pol,
853                                                             12, &domain_name,
854                                                             &dns_name, NULL,
855                                                             NULL, &dom_sid);
856                 }
857
858                 if (NT_STATUS_IS_OK(result)) {
859                         if (domain_name)
860                                 fstrcpy(domain->name, domain_name);
861                         
862                         if (dns_name)
863                                 fstrcpy(domain->alt_name, dns_name);
864
865                         if (dom_sid) 
866                                 sid_copy(&domain->sid, dom_sid);
867
868                         domain->active_directory = True;
869                 } else {
870                         
871                         result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
872                                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
873                                                      &conn.pol);
874                         
875                         if (!NT_STATUS_IS_OK(result))
876                                 goto done;
877                         
878                         result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
879                                                            &conn.pol, 5, &domain_name, 
880                                                            &dom_sid);
881                         
882                         if (NT_STATUS_IS_OK(result)) {
883                                 if (domain_name)
884                                         fstrcpy(domain->name, domain_name);
885                                 
886                                 if (dom_sid) 
887                                         sid_copy(&domain->sid, dom_sid);
888                         }
889                 }
890         }
891         
892 done:
893         
894         /* close the connection;  no other calls use this pipe and it is called only
895            on reestablishing the domain list   --jerry */
896         
897         if ( conn.cli )
898                 cli_shutdown( conn.cli );
899         
900         talloc_destroy(mem_ctx);
901
902         domain->initialized = True;
903         
904         return;
905 }
906
907
908
909 /* Return a LSA policy handle on a domain */
910
911 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
912 {
913         struct winbindd_cm_conn *conn;
914         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
915         NTSTATUS result;
916         static CLI_POLICY_HND hnd;
917
918         /* Look for existing connections */
919
920         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
921                 return result;
922
923         /* This *shitty* code needs scrapping ! JRA */
924         
925         if (policy_handle_is_valid(&conn->pol)) {
926                 hnd.pol = conn->pol;
927                 hnd.cli = conn->cli;
928                 *return_hnd = &hnd;
929
930                 return NT_STATUS_OK;
931         }
932         
933         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
934                                      des_access, &conn->pol);
935
936         if (!NT_STATUS_IS_OK(result)) {
937                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
938                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
939                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
940                                 return result;
941
942                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
943                                                      des_access, &conn->pol);
944                 }
945
946                 if (!NT_STATUS_IS_OK(result)) {
947                         cli_shutdown(conn->cli);
948                         DLIST_REMOVE(cm_conns, conn);
949                         SAFE_FREE(conn);
950                         return result;
951                 }
952         }       
953
954         hnd.pol = conn->pol;
955         hnd.cli = conn->cli;
956
957         *return_hnd = &hnd;
958
959         return NT_STATUS_OK;
960 }
961
962 /* Return a SAM policy handle on a domain */
963
964 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
965
966         struct winbindd_cm_conn *conn;
967         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
968         NTSTATUS result;
969         static CLI_POLICY_HND hnd;
970
971         /* Look for existing connections */
972
973         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
974                 return result;
975         
976         /* This *shitty* code needs scrapping ! JRA */
977         
978         if (policy_handle_is_valid(&conn->pol)) {
979                 hnd.pol = conn->pol;
980                 hnd.cli = conn->cli;
981                 
982                 *return_hnd = &hnd;
983
984                 return NT_STATUS_OK;
985         }
986         
987         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
988                                   des_access, &conn->pol);
989
990         if (!NT_STATUS_IS_OK(result)) {
991                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
992                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
993                 
994                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
995                                 return result;
996
997                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
998                                                   des_access, &conn->pol);
999                 }
1000
1001                 if (!NT_STATUS_IS_OK(result)) {
1002                 
1003                         cli_shutdown(conn->cli);
1004                         DLIST_REMOVE(cm_conns, conn);
1005                         SAFE_FREE(conn);
1006                         
1007                         return result;
1008                 }
1009         }       
1010
1011         hnd.pol = conn->pol;
1012         hnd.cli = conn->cli;
1013
1014         *return_hnd = &hnd;
1015
1016         return NT_STATUS_OK;
1017 }
1018
1019 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
1020    netlogon pipe as no handle is returned. */
1021
1022 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
1023                              const unsigned char *trust_passwd, 
1024                              uint32 sec_channel_type,
1025                              BOOL fresh,
1026                              struct cli_state **cli)
1027 {
1028         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1029         struct winbindd_cm_conn *conn;
1030         fstring lock_name;
1031         BOOL got_mutex;
1032
1033         if (!cli)
1034                 return NT_STATUS_INVALID_PARAMETER;
1035
1036         /* Open an initial conection - keep the mutex. */
1037
1038         find_cm_connection(domain, PIPE_NETLOGON, &conn);
1039
1040         if ( fresh && (conn != NULL) ) {
1041                 cli_shutdown(conn->cli);
1042                 conn->cli = NULL;
1043
1044                 conn = NULL;
1045
1046                 /* purge connection from cache */
1047                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1048                 if (conn != NULL) {
1049                         DEBUG(0,("Could not purge connection\n"));
1050                         return NT_STATUS_UNSUCCESSFUL;
1051                 }
1052         }
1053
1054         if (conn != NULL) {
1055                 *cli = conn->cli;
1056                 return NT_STATUS_OK;
1057         }
1058
1059         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1060
1061         if (!NT_STATUS_IS_OK(result))
1062                 return result;
1063         
1064         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1065
1066         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1067                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1068         }
1069         
1070         if ( sec_channel_type == SEC_CHAN_DOMAIN )
1071                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1072                         
1073         /* This must be the remote domain (not ours) for schannel */
1074
1075         fstrcpy( conn->cli->domain, domain->name);
1076         
1077         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1078         
1079         if (got_mutex)
1080                 secrets_named_mutex_release(lock_name);
1081                                 
1082         if (!NT_STATUS_IS_OK(result)) {
1083                 cli_shutdown(conn->cli);
1084                 DLIST_REMOVE(cm_conns, conn);
1085                 SAFE_FREE(conn);
1086                 return result;
1087         }
1088
1089         *cli = conn->cli;
1090
1091         return result;
1092 }
1093
1094 /* Dump the current connection status */
1095
1096 static void dump_conn_list(void)
1097 {
1098         struct winbindd_cm_conn *con;
1099
1100         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
1101
1102         for(con = cm_conns; con; con = con->next) {
1103                 char *msg;
1104
1105                 /* Display pipe info */
1106                 
1107                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1108                         DEBUG(0, ("Error: not enough memory!\n"));
1109                 } else {
1110                         DEBUG(0, ("%s\n", msg));
1111                         SAFE_FREE(msg);
1112                 }
1113         }
1114 }
1115
1116 void winbindd_cm_status(void)
1117 {
1118         /* List open connections */
1119
1120         DEBUG(0, ("winbindd connection manager status:\n"));
1121
1122         if (cm_conns)
1123                 dump_conn_list();
1124         else
1125                 DEBUG(0, ("\tNo active connections\n"));
1126 }
1127
1128 /* Close all cached connections */
1129
1130 void winbindd_cm_flush(void)
1131 {
1132         struct winbindd_cm_conn *conn, tmp;
1133
1134         /* Flush connection cache */
1135
1136         for (conn = cm_conns; conn; conn = conn->next) {
1137
1138                 if (!connection_ok(conn))
1139                         continue;
1140
1141                 DEBUG(10, ("Closing connection to %s on %s\n",
1142                         conn->pipe_name, conn->controller));
1143
1144                 if (conn->cli)
1145                         cli_shutdown(conn->cli);
1146
1147                 tmp.next = conn->next;
1148
1149                 DLIST_REMOVE(cm_conns, conn);
1150                 SAFE_FREE(conn);
1151                 conn = &tmp;
1152         }
1153
1154         /* Flush failed connection cache */
1155
1156         flush_negative_conn_cache();
1157 }